Compare commits

...

26 Commits

Author SHA1 Message Date
Benexl
de8b6b7f2f chore: bump version 2025-08-18 01:15:00 +03:00
Benexl
54e0942233 chore: update uv.lock 2025-08-18 01:12:10 +03:00
Benexl
8ea0c121c2 chore: viu_media 2025-08-18 01:08:27 +03:00
Benexl
eddaad64e7 chore: viu media is better 2025-08-18 01:07:36 +03:00
Benexl
43be7a52cf chore(envrc): check if nix command is available 2025-08-18 00:31:05 +03:00
Benexl
b689760a25 Merge pull request #129 from s-weigand/fix-ci
🚇🩹 Fix test CI workflow
2025-08-17 20:25:55 +03:00
Benexl
e53246b79b feat(interactive-state): media api state should come second 2025-08-17 19:45:59 +03:00
Benexl
b0fc94cdc5 style: ruff format 2025-08-17 19:40:53 +03:00
Benexl
449f6c1e59 feat(interactive-state): create accessors that ensure values exist 2025-08-17 19:38:55 +03:00
Benexl
ab4734b79d fix(session): allow offline viewing by wrapping authenticate in try block 2025-08-17 17:49:38 +03:00
Benexl
93d0f6a1a5 refactor: fa to viu 2025-08-17 17:22:38 +03:00
Benexl
19c75c48b2 Merge pull request #128 from s-weigand/improve-title-matching
👌 Make finding best_match_title more robust
2025-08-17 16:49:32 +03:00
Benexl
5341b0a844 Update README.md 2025-08-17 16:40:26 +03:00
Benexl
24e7e6a16b Update README.md 2025-08-17 16:36:52 +03:00
s-weigand
4b310e60b8 Revert " Run on feature-branch"
This reverts commit c6b8cfc294.
2025-08-17 13:42:43 +02:00
s-weigand
4d50cffd86 🧹 Ignore blank except ruff rule 2025-08-17 13:14:32 +02:00
s-weigand
f6fedf0500 🧹 Remove unused TYPE_CHECKING import 2025-08-17 13:13:11 +02:00
s-weigand
7b431450fe 🩹 Relock uv.lock file due to changed package name 2025-08-17 13:09:52 +02:00
s-weigand
66b247330b 🚇🩹 Install libglib2.0-dev 2025-08-17 12:56:03 +02:00
s-weigand
c6b8cfc294 Run on feature-branch 2025-08-17 12:49:05 +02:00
s-weigand
6895426d67 🚇🩹 Install dbus-python build dependencies 2025-08-17 12:48:29 +02:00
s-weigand
cc69dc35f6 👌 Make finding best_match_title more robust 2025-08-17 12:34:25 +02:00
Benexl
ed81f37ae4 Merge pull request #126 from blob5/master
Build failure on nixOS. ModuleNotFoundError: No module named 'viu'
2025-08-16 23:47:43 +03:00
Senna
c6858b00c4 remove pythonImportsCheck 2025-08-16 22:08:06 +02:00
Benexl
a44034a5d4 chore: remove 2025-08-16 21:47:44 +03:00
Benexl
f768518721 Update README.md 2025-08-16 19:48:57 +03:00
254 changed files with 3347 additions and 430 deletions

4
.envrc
View File

@@ -1 +1,3 @@
use flake
if command -v nix >/dev/null;then
use flake
fi

15
.github/FUNDING.yml vendored
View File

@@ -1,15 +0,0 @@
# These are supported funding model platforms
github: benexl # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
patreon: # Replace with a single Patreon username
open_collective: # Replace with a single Open Collective username
ko_fi: benexl # Replace with a single Ko-fi username
tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
liberapay: # Replace with a single Liberapay username
issuehunt: # Replace with a single IssueHunt username
lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
polar: # Replace with a single Polar username
buy_me_a_coffee: # Replace with a single Buy Me a Coffee username
thanks_dev: # Replace with a single thanks.dev username
custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']

View File

@@ -22,6 +22,11 @@ jobs:
with:
python-version: ${{ matrix.python-version }}
- name: Install dbus-python build dependencies
run: |
sudo apt-get update
sudo apt-get -y install libdbus-1-dev libglib2.0-dev
- name: Install uv
uses: astral-sh/setup-uv@v3
with:

View File

@@ -1,3 +1,15 @@
>[!IMPORTANT]
> looking for a new project name
>
>if you have any that is not already being used by someone on pypi please share on discord
>
>and let me warn yah am not good at naming things so help before disaster strikes again lol
>
>i dont want it to end up like viu where i added cli lol since viu was taken
>
>
<p align="center">
<h1 align="center">Viu</h1>
</p>
@@ -8,8 +20,8 @@
</p>
<div align="center">
[![PyPI - Version](https://img.shields.io/pypi/v/viu_cli)](https://pypi.org/project/viu_cli/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/viu_cli)](https://pypi.org/project/viu_cli/)
[![PyPI - Version](https://img.shields.io/pypi/v/viu-media)](https://pypi.org/project/viu-media/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/viu-media)](https://pypi.org/project/viu-media/)
[![GitHub Actions Workflow Status](https://img.shields.io/github/actions/workflow/status/Benexl/Viu/test.yml?label=Tests)](https://github.com/Benexl/Viu/actions)
[![Discord](https://img.shields.io/discord/1250887070906323096?label=Discord&logo=discord)](https://discord.gg/HBEmAwvbHV)
[![GitHub Issues](https://img.shields.io/github/issues/Benexl/Viu)](https://github.com/Benexl/Viu/issues)
@@ -23,47 +35,6 @@
</a>
</p>
![viu](https://github.com/user-attachments/assets/9ab09f26-e4a8-4b70-a315-7def998cec63)
<details>
<summary>
<b>Screenshots</b>
</summary>
<b>Fzf:</b>
<img width="1346" height="710" alt="250815_13h29m15s_screenshot" src="https://github.com/user-attachments/assets/d8fb8473-a0fe-47b1-b112-5cd8bec51937" />
<img width="1346" height="710" alt="250815_13h29m43s_screenshot" src="https://github.com/user-attachments/assets/16a2555d-f81e-4044-9e65-e61205dfe899" />
<img width="1346" height="710" alt="250815_13h30m09s_screenshot" src="https://github.com/user-attachments/assets/f521670a-c04f-4f5e-a62a-6c849fbf49bd" />
<img width="1346" height="710" alt="250815_13h30m33s_screenshot" src="https://github.com/user-attachments/assets/27fd2ef9-ec1f-4677-b816-038eaaca1391" />
<img width="1346" height="710" alt="250815_13h31m07s_screenshot" src="https://github.com/user-attachments/assets/6a64aa99-507e-449a-9e4a-9daa4fe496a3" />
<img width="1346" height="710" alt="250815_13h31m44s_screenshot" src="https://github.com/user-attachments/assets/a2896d1f-0e23-4ff3-b0c6-121d21a9f99a" />
<b>Rofi:</b>
<img width="1366" height="729" alt="250815_13h23m12s_screenshot" src="https://github.com/user-attachments/assets/6d18d950-11e5-41fc-a7fe-1f9eaa481e46" />
<img width="1366" height="765" alt="250815_13h24m09s_screenshot" src="https://github.com/user-attachments/assets/af852fee-17bf-4f24-ada9-7cf0e6f3451c" />
<img width="1366" height="768" alt="250815_13h24m57s_screenshot" src="https://github.com/user-attachments/assets/d3b4e2ab-10bd-40ae-88ed-0720b57957c1" />
<img width="1366" height="735" alt="250815_13h26m47s_screenshot" src="https://github.com/user-attachments/assets/64682b09-c88e-4d4c-ae26-a3aa34dd08a1" />
<img width="1366" height="768" alt="250815_13h28m05s_screenshot" src="https://github.com/user-attachments/assets/d6cd6931-0113-462c-86bb-abe6f3e12d68" />
</details>
<details>
<summary>
<b>Riced Preview Examples</b>
</summary>
**Anilist Results Menu (FZF):**
![image](https://github.com/user-attachments/assets/240023a7-7e4e-47dd-80ff-017d65081ee1)
**Episodes Menu with Preview (FZF):**
![image](https://github.com/user-attachments/assets/580f86ef-326f-4ab3-9bd8-c1cb312fbfa6)
**No Image Preview Mode:**
![image](https://github.com/user-attachments/assets/e1248a85-438f-4758-ae34-b0e0b224addd)
**Desktop Notifications + Episodes Menu:**
![image](https://github.com/user-attachments/assets/b7802ef1-ca0d-45f5-a13a-e39c96a5d499)
</details>
## Core Features
@@ -98,13 +69,13 @@ The best way to install Viu is with [**uv**](https://github.com/astral-sh/uv), a
```bash
# Install with all optional features for the full experience
uv tool install "viu_cli[standard]"
uv tool install "viu-media[standard]"
# Or, pick and choose the extras you need:
uv tool install viu_cli # Core functionality only
uv tool install "viu_cli[download]" # For advanced downloading with yt-dlp
uv tool install "viu_cli[discord]" # For Discord Rich Presence
uv tool install "viu_cli[notifications]" # For desktop notifications
uv tool install viu-media # Core functionality only
uv tool install "viu-media[download]" # For advanced downloading with yt-dlp
uv tool install "viu-media[discord]" # For Discord Rich Presence
uv tool install "viu-media[notifications]" # For desktop notifications
```
### Other Installation Methods
@@ -129,12 +100,12 @@ uv tool install "viu_cli[notifications]" # For desktop notifications
#### Using pipx (for isolated environments)
```bash
pipx install "viu_cli[standard]"
pipx install "viu-media[standard]"
```
#### Using pip
```bash
pip install "viu_cli[standard]"
pip install "viu-media[standard]"
```
</details>

View File

@@ -67,8 +67,6 @@
# Needs to be adapted for the nix derivation build
doCheck = false;
pythonImportsCheck = [ "viu" ];
meta = {
description = "Your browser anime experience from the terminal";
homepage = "https://github.com/Benexl/Viu";

View File

@@ -1,6 +1,6 @@
[project]
name = "viu_cli"
version = "3.2.6"
name = "viu-media"
version = "3.2.7"
description = "A browser anime site experience from the terminal"
license = "UNLICENSE"
readme = "README.md"
@@ -14,7 +14,7 @@ dependencies = [
]
[project.scripts]
viu = 'viu_cli:Cli'
viu = 'viu_media:Cli'
[project.optional-dependencies]
standard = [

3057
uv.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -3,4 +3,4 @@ provider_type=$1
provider_name=$2
[ -z "$provider_type" ] && echo "Please specify provider type" && exit
[ -z "$provider_name" ] && echo "Please specify provider type" && exit
uv run python -m viu_cli.libs.provider.${provider_type}.${provider_name}.provider
uv run python -m viu_media.libs.provider.${provider_type}.${provider_name}.provider

View File

@@ -1,85 +0,0 @@
from enum import Enum
from typing import Dict, Optional, Union
from pydantic import BaseModel, ConfigDict, Field
from ...libs.media_api.params import MediaSearchParams, UserMediaListSearchParams
from ...libs.media_api.types import MediaItem, PageInfo
from ...libs.provider.anime.types import Anime, SearchResults, Server
# TODO: is internal directive a good name
class InternalDirective(Enum):
MAIN = "MAIN"
BACK = "BACK"
BACKX2 = "BACKX2"
BACKX3 = "BACKX3"
BACKX4 = "BACKX4"
EXIT = "EXIT"
CONFIG_EDIT = "CONFIG_EDIT"
RELOAD = "RELOAD"
class MenuName(Enum):
MAIN = "MAIN"
AUTH = "AUTH"
EPISODES = "EPISODES"
RESULTS = "RESULTS"
SERVERS = "SERVERS"
WATCH_HISTORY = "WATCH_HISTORY"
PROVIDER_SEARCH = "PROVIDER_SEARCH"
PLAYER_CONTROLS = "PLAYER_CONTROLS"
USER_MEDIA_LIST = "USER_MEDIA_LIST"
SESSION_MANAGEMENT = "SESSION_MANAGEMENT"
MEDIA_ACTIONS = "MEDIA_ACTIONS"
DOWNLOADS = "DOWNLOADS"
DYNAMIC_SEARCH = "DYNAMIC_SEARCH"
MEDIA_REVIEW = "MEDIA_REVIEW"
MEDIA_CHARACTERS = "MEDIA_CHARACTERS"
MEDIA_AIRING_SCHEDULE = "MEDIA_AIRING_SCHEDULE"
PLAY_DOWNLOADS = "PLAY_DOWNLOADS"
DOWNLOADS_PLAYER_CONTROLS = "DOWNLOADS_PLAYER_CONTROLS"
DOWNLOAD_EPISODES = "DOWNLOAD_EPISODES"
class StateModel(BaseModel):
model_config = ConfigDict(frozen=True)
class MediaApiState(StateModel):
search_result: Optional[Dict[int, MediaItem]] = None
search_params: Optional[Union[MediaSearchParams, UserMediaListSearchParams]] = None
page_info: Optional[PageInfo] = None
media_id: Optional[int] = None
@property
def media_item(self) -> Optional[MediaItem]:
if self.search_result and self.media_id:
return self.search_result[self.media_id]
class ProviderState(StateModel):
search_results: Optional[SearchResults] = None
anime: Optional[Anime] = None
episode: Optional[str] = None
servers: Optional[Dict[str, Server]] = None
server_name: Optional[str] = None
start_time: Optional[str] = None
@property
def server(self) -> Optional[Server]:
if self.servers and self.server_name:
return self.servers[self.server_name]
class State(StateModel):
menu_name: MenuName
provider: ProviderState = Field(default_factory=ProviderState)
media_api: MediaApiState = Field(default_factory=MediaApiState)

View File

Before

Width:  |  Height:  |  Size: 3.7 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

View File

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 276 KiB

View File

@@ -44,7 +44,7 @@ commands = {
@click.group(
cls=LazyGroup,
root="viu_cli.cli.commands",
root="viu_media.cli.commands",
invoke_without_command=True,
lazy_subcommands=commands,
context_settings=dict(auto_envvar_prefix=PROJECT_NAME),

View File

@@ -18,7 +18,7 @@ commands = {
@click.group(
cls=LazyGroup,
name="anilist",
root="viu_cli.cli.commands.anilist.commands",
root="viu_media.cli.commands.anilist.commands",
invoke_without_command=True,
help="A beautiful interface that gives you access to a commplete streaming experience",
short_help="Access all streaming options",

View File

@@ -45,7 +45,9 @@ def auth(config: AppConfig, status: bool, logout: bool):
open_success = webbrowser.open(ANILIST_AUTH, new=2)
if open_success:
feedback.info("Your browser has been opened to obtain an AniList token.")
feedback.info(f"or you can visit the site manually [magenta][link={ANILIST_AUTH}]here[/link][/magenta].")
feedback.info(
f"or you can visit the site manually [magenta][link={ANILIST_AUTH}]here[/link][/magenta]."
)
else:
feedback.warning(
f"Failed to open the browser. Please visit the site manually [magenta][link={ANILIST_AUTH}]here[/link][/magenta]."

View File

@@ -1,10 +1,10 @@
from typing import TYPE_CHECKING, Dict, List
import click
from viu_cli.cli.utils.completion import anime_titles_shell_complete
from viu_cli.core.config import AppConfig
from viu_cli.core.exceptions import ViuError
from viu_cli.libs.media_api.types import (
from viu_media.cli.utils.completion import anime_titles_shell_complete
from viu_media.core.config import AppConfig
from viu_media.core.exceptions import ViuError
from viu_media.libs.media_api.types import (
MediaFormat,
MediaGenre,
MediaItem,
@@ -112,15 +112,15 @@ if TYPE_CHECKING:
)
@click.pass_obj
def download(config: AppConfig, **options: "Unpack[DownloadOptions]"):
from viu_cli.cli.service.download.service import DownloadService
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.cli.service.watch_history import WatchHistoryService
from viu_cli.cli.utils.parser import parse_episode_range
from viu_cli.libs.media_api.api import create_api_client
from viu_cli.libs.media_api.params import MediaSearchParams
from viu_cli.libs.provider.anime.provider import create_provider
from viu_cli.libs.selectors import create_selector
from viu_media.cli.service.download.service import DownloadService
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.cli.service.watch_history import WatchHistoryService
from viu_media.cli.utils.parser import parse_episode_range
from viu_media.libs.media_api.api import create_api_client
from viu_media.libs.media_api.params import MediaSearchParams
from viu_media.libs.provider.anime.provider import create_provider
from viu_media.libs.selectors import create_selector
from rich.progress import Progress
feedback = FeedbackService(config)

View File

@@ -1,5 +1,4 @@
import json
from typing import TYPE_CHECKING
import click

View File

@@ -1,5 +1,5 @@
import click
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
from rich.console import Console
from rich.table import Table
@@ -11,8 +11,8 @@ def notifications(config: AppConfig):
Displays unread notifications from AniList.
Running this command will also mark the notifications as read on the AniList website.
"""
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.libs.media_api.api import create_api_client
from viu_media.cli.service.feedback import FeedbackService
from viu_media.libs.media_api.api import create_api_client
from ....service.auth import AuthService

View File

@@ -251,18 +251,14 @@ def search(config: AppConfig, **options: "Unpack[SearchOptions]"):
and start_date_lesser is not None
and start_date_greater > start_date_lesser
):
raise ViuError(
"Start date greater cannot be later than start date lesser"
)
raise ViuError("Start date greater cannot be later than start date lesser")
if (
end_date_greater is not None
and end_date_lesser is not None
and end_date_greater > end_date_lesser
):
raise ViuError(
"End date greater cannot be later than end date lesser"
)
raise ViuError("End date greater cannot be later than end date lesser")
# Build search parameters
search_params = MediaSearchParams(

View File

@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
import click
if TYPE_CHECKING:
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
@click.command(help="Print out your anilist stats")

View File

@@ -11,7 +11,7 @@ if TYPE_CHECKING:
from pathlib import Path
from typing import TypedDict
from viu_cli.cli.service.feedback.service import FeedbackService
from viu_media.cli.service.feedback.service import FeedbackService
from typing_extensions import Unpack
from ...libs.provider.anime.base import BaseAnimeProvider
@@ -103,7 +103,7 @@ if TYPE_CHECKING:
)
@click.pass_obj
def download(config: AppConfig, **options: "Unpack[Options]"):
from viu_cli.cli.service.feedback.service import FeedbackService
from viu_media.cli.service.feedback.service import FeedbackService
from ...core.exceptions import ViuError
from ...libs.provider.anime.params import (

View File

@@ -1,7 +1,7 @@
import click
from viu_cli.core.config import AppConfig
from viu_cli.core.exceptions import ViuError
from viu_cli.libs.media_api.types import (
from viu_media.core.config import AppConfig
from viu_media.core.exceptions import ViuError
from viu_media.libs.media_api.types import (
MediaFormat,
MediaGenre,
MediaItem,
@@ -33,8 +33,12 @@ from viu_cli.libs.media_api.types import (
@click.option(
"--genres-not", multiple=True, type=click.Choice([g.value for g in MediaGenre])
)
@click.option("--tags", "-T", multiple=True, type=click.Choice([t.value for t in MediaTag]))
@click.option("--tags-not", multiple=True, type=click.Choice([t.value for t in MediaTag]))
@click.option(
"--tags", "-T", multiple=True, type=click.Choice([t.value for t in MediaTag])
)
@click.option(
"--tags-not", multiple=True, type=click.Choice([t.value for t in MediaTag])
)
@click.option(
"--media-format",
"-f",
@@ -72,14 +76,14 @@ def queue(config: AppConfig, **options):
and queue the specified episode range for background download.
The background worker should be running to process the queue.
"""
from viu_cli.cli.service.download.service import DownloadService
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.cli.utils.parser import parse_episode_range
from viu_cli.libs.media_api.params import MediaSearchParams
from viu_cli.libs.media_api.api import create_api_client
from viu_cli.libs.provider.anime.provider import create_provider
from viu_cli.libs.selectors import create_selector
from viu_media.cli.service.download.service import DownloadService
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.cli.utils.parser import parse_episode_range
from viu_media.libs.media_api.params import MediaSearchParams
from viu_media.libs.media_api.api import create_api_client
from viu_media.libs.provider.anime.provider import create_provider
from viu_media.libs.selectors import create_selector
from rich.progress import Progress
feedback = FeedbackService(config)

View File

@@ -13,7 +13,7 @@ commands = {
@click.group(
cls=LazyGroup,
name="queue",
root="viu_cli.cli.commands.queue.commands",
root="viu_media.cli.commands.queue.commands",
invoke_without_command=False,
help="Manage the download queue (add, list, resume, clear).",
short_help="Manage the download queue.",

View File

@@ -1,7 +1,7 @@
import click
from viu_cli.core.config import AppConfig
from viu_cli.core.exceptions import ViuError
from viu_cli.libs.media_api.types import (
from viu_media.core.config import AppConfig
from viu_media.core.exceptions import ViuError
from viu_media.libs.media_api.types import (
MediaFormat,
MediaGenre,
MediaItem,
@@ -70,14 +70,14 @@ from viu_cli.libs.media_api.types import (
)
@click.pass_obj
def add(config: AppConfig, **options):
from viu_cli.cli.service.download import DownloadService
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.cli.utils.parser import parse_episode_range
from viu_cli.libs.media_api.api import create_api_client
from viu_cli.libs.media_api.params import MediaSearchParams
from viu_cli.libs.provider.anime.provider import create_provider
from viu_cli.libs.selectors import create_selector
from viu_media.cli.service.download import DownloadService
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.cli.utils.parser import parse_episode_range
from viu_media.libs.media_api.api import create_api_client
from viu_media.libs.media_api.params import MediaSearchParams
from viu_media.libs.provider.anime.provider import create_provider
from viu_media.libs.selectors import create_selector
from rich.progress import Progress
feedback = FeedbackService(config)
@@ -149,7 +149,7 @@ def add(config: AppConfig, **options):
}
preview_command = None
if config.general.preview != "none":
from viu_cli.cli.utils.preview import create_preview_context
from viu_media.cli.utils.preview import create_preview_context
with create_preview_context() as preview_ctx:
preview_command = preview_ctx.get_anime_preview(

View File

@@ -1,14 +1,17 @@
import click
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
@click.command(name="clear", help="Clear queued items from the registry (QUEUED -> NOT_DOWNLOADED).")
@click.command(
name="clear",
help="Clear queued items from the registry (QUEUED -> NOT_DOWNLOADED).",
)
@click.option("--force", is_flag=True, help="Do not prompt for confirmation.")
@click.pass_obj
def clear_cmd(config: AppConfig, force: bool):
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.cli.service.registry.models import DownloadStatus
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.cli.service.registry.models import DownloadStatus
feedback = FeedbackService(config)
registry = MediaRegistryService(config.general.media_api, config.media_registry)

View File

@@ -1,5 +1,5 @@
import click
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
@click.command(name="list", help="List items in the download queue and their statuses.")
@@ -10,9 +10,9 @@ from viu_cli.core.config import AppConfig
@click.option("--detailed", is_flag=True)
@click.pass_obj
def list_cmd(config: AppConfig, status: str | None, detailed: bool | None):
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.cli.service.registry.models import DownloadStatus
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.cli.service.registry.models import DownloadStatus
feedback = FeedbackService(config)
registry = MediaRegistryService(config.general.media_api, config.media_registry)

View File

@@ -1,15 +1,17 @@
import click
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
@click.command(name="resume", help="Submit any queued or in-progress downloads to the worker.")
@click.command(
name="resume", help="Submit any queued or in-progress downloads to the worker."
)
@click.pass_obj
def resume(config: AppConfig):
from viu_cli.cli.service.download.service import DownloadService
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.registry import MediaRegistryService
from viu_cli.libs.media_api.api import create_api_client
from viu_cli.libs.provider.anime.provider import create_provider
from viu_media.cli.service.download.service import DownloadService
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.registry import MediaRegistryService
from viu_media.libs.media_api.api import create_api_client
from viu_media.libs.provider.anime.provider import create_provider
feedback = FeedbackService(config)
media_api = create_api_client(config.general.media_api, config)

View File

@@ -19,7 +19,7 @@ commands = {
@click.group(
cls=LazyGroup,
name="registry",
root="viu_cli.cli.commands.registry.commands",
root="viu_media.cli.commands.registry.commands",
invoke_without_command=True,
help="Manage your local media registry - sync, search, backup and maintain your anime database",
short_help="Local media registry management",

View File

@@ -3,8 +3,8 @@ Registry sync command - synchronize local registry with remote media API
"""
import click
from viu_cli.cli.service.feedback.service import FeedbackService
from viu_cli.cli.service.registry.service import MediaRegistryService
from viu_media.cli.service.feedback.service import FeedbackService
from viu_media.cli.service.registry.service import MediaRegistryService
from .....core.config import AppConfig

View File

@@ -10,7 +10,7 @@ from . import examples
if TYPE_CHECKING:
from typing import TypedDict
from viu_cli.cli.service.feedback.service import FeedbackService
from viu_media.cli.service.feedback.service import FeedbackService
from typing_extensions import Unpack
from ...libs.provider.anime.base import BaseAnimeProvider
@@ -42,7 +42,7 @@ if TYPE_CHECKING:
)
@click.pass_obj
def search(config: AppConfig, **options: "Unpack[Options]"):
from viu_cli.cli.service.feedback.service import FeedbackService
from viu_media.cli.service.feedback.service import FeedbackService
from ...core.exceptions import ViuError
from ...libs.provider.anime.params import (
@@ -134,7 +134,7 @@ def stream_anime(
episode: str,
anime_title: str,
):
from viu_cli.cli.service.player.service import PlayerService
from viu_media.cli.service.player.service import PlayerService
from ...libs.player.params import PlayerParams
from ...libs.provider.anime.params import EpisodeStreamsParams

View File

@@ -1,5 +1,5 @@
import click
from viu_cli.core.config import AppConfig
from viu_media.core.config import AppConfig
@click.command(help="Run the background worker for notifications and downloads.")
@@ -11,14 +11,14 @@ def worker(config: AppConfig):
process any queued downloads. It's recommended to run this in the
background (e.g., 'viu worker &') or as a system service.
"""
from viu_cli.cli.service.auth import AuthService
from viu_cli.cli.service.download.service import DownloadService
from viu_cli.cli.service.feedback import FeedbackService
from viu_cli.cli.service.notification.service import NotificationService
from viu_cli.cli.service.registry.service import MediaRegistryService
from viu_cli.cli.service.worker.service import BackgroundWorkerService
from viu_cli.libs.media_api.api import create_api_client
from viu_cli.libs.provider.anime.provider import create_provider
from viu_media.cli.service.auth import AuthService
from viu_media.cli.service.download.service import DownloadService
from viu_media.cli.service.feedback import FeedbackService
from viu_media.cli.service.notification.service import NotificationService
from viu_media.cli.service.registry.service import MediaRegistryService
from viu_media.cli.service.worker.service import BackgroundWorkerService
from viu_media.libs.media_api.api import create_api_client
from viu_media.libs.provider.anime.provider import create_provider
feedback = FeedbackService(config)
if not config.worker.enabled:

View File

@@ -19,9 +19,7 @@ class InteractiveConfigEditor:
def run(self) -> AppConfig:
"""Starts the interactive configuration wizard."""
print(
"[bold cyan]Welcome to the Viu Interactive Configurator![/bold cyan]"
)
print("[bold cyan]Welcome to the Viu Interactive Configurator![/bold cyan]")
print("Let's set up your experience. Press Ctrl+C at any time to exit.")
print("Current values will be shown as defaults.")

View File

@@ -6,7 +6,7 @@ from ...state import InternalDirective, State
@session.menu
def download_episodes(ctx: Context, state: State) -> State | InternalDirective:
"""Menu to select and download episodes synchronously."""
from .....core.utils.fuzzy import fuzz
from viu_media.cli.utils.search import find_best_match_title
from .....core.utils.normalizer import normalize_title
from ....service.download.service import DownloadService
@@ -40,12 +40,8 @@ def download_episodes(ctx: Context, state: State) -> State | InternalDirective:
return InternalDirective.BACK
provider_results_map = {res.title: res for res in provider_search_results.results}
best_match_title = max(
provider_results_map.keys(),
key=lambda p_title: fuzz.ratio(
normalize_title(p_title, config.general.provider.value).lower(),
media_title.lower(),
),
best_match_title = find_best_match_title(
provider_results_map, config.general.provider, media_item
)
selected_provider_anime_ref = provider_results_map[best_match_title]

View File

@@ -72,6 +72,6 @@ def episodes(ctx: Context, state: State) -> State | InternalDirective:
menu_name=MenuName.SERVERS,
media_api=state.media_api,
provider=state.provider.model_copy(
update={"episode": chosen_episode, "start_time": start_time}
update={"episode_": chosen_episode, "start_time_": start_time}
),
)

Some files were not shown because too many files have changed in this diff Show More