Compare commits

..

40 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
Benexl
97f5bb9cb3 chore: bump 2025-08-16 19:45:25 +03:00
Benexl
b09fdbf69b chore: update deps 2025-08-16 19:44:49 +03:00
Benexl
071c46cad9 chore: bump version 2025-08-16 19:32:23 +03:00
Benexl
5d32503ff9 chore: update publish.yml 2025-08-16 19:31:28 +03:00
Benexl
e67532c496 chore: bump version 2025-08-16 19:19:32 +03:00
Benexl
819012897d Update README.md 2025-08-16 19:17:44 +03:00
Benexl
c4f78b12a4 revert 2025-08-16 19:16:11 +03:00
Benexl
8aacbcc35b Update README.md 2025-08-16 19:11:21 +03:00
Benexl
5976ab43b2 chore: correct package issues 2025-08-16 19:08:39 +03:00
Benexl
99c67a4bc0 fix: publish.yml 2025-08-16 19:00:44 +03:00
Benexl
34851fd3e4 chore: update publish.yml 2025-08-16 18:58:59 +03:00
Benexl
e74b5977bb chore: update workflow 2025-08-16 18:56:31 +03:00
Benexl
0650f45fba revert 2025-08-16 18:55:33 +03:00
Benexl
0c8f2a70ba chore: update project name 2025-08-16 18:50:42 +03:00
254 changed files with 3350 additions and 431 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)](https://pypi.org/project/viu/)
[![PyPI - Downloads](https://img.shields.io/pypi/dm/viu)](https://pypi.org/project/viu/)
[![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[standard]"
uv tool install "viu-media[standard]"
# Or, pick and choose the extras you need:
uv tool install viu # Core functionality only
uv tool install "viu[download]" # For advanced downloading with yt-dlp
uv tool install "viu[discord]" # For Discord Rich Presence
uv tool install "viu[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[notifications]" # For desktop notifications
#### Using pipx (for isolated environments)
```bash
pipx install "viu[standard]"
pipx install "viu-media[standard]"
```
#### Using pip
```bash
pip install "viu[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"
version = "3.1.0"
name = "viu-media"
version = "3.2.7"
description = "A browser anime site experience from the terminal"
license = "UNLICENSE"
readme = "README.md"
@@ -14,14 +14,16 @@ dependencies = [
]
[project.scripts]
viu = 'viu:Cli'
viu = 'viu_media:Cli'
[project.optional-dependencies]
standard = [
"thefuzz>=0.22.1",
"yt-dlp>=2025.7.21",
"pycryptodomex>=3.23.0",
"dbus-python>=1.4.0",
"pypiwin32; sys_platform == 'win32'", # For Windows-specific functionality
"pyobjc; sys_platform == 'darwin'", # For macOS-specific functionality
"dbus-python; sys_platform == 'linux'", # For Linux-specific functionality (e.g., notifications),
"plyer>=2.1.0",
"lxml>=6.0.0"
]

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.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.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.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.utils.completion import anime_titles_shell_complete
from viu.core.config import AppConfig
from viu.core.exceptions import ViuError
from viu.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.service.download.service import DownloadService
from viu.cli.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.cli.service.watch_history import WatchHistoryService
from viu.cli.utils.parser import parse_episode_range
from viu.libs.media_api.api import create_api_client
from viu.libs.media_api.params import MediaSearchParams
from viu.libs.provider.anime.provider import create_provider
from viu.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.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.service.feedback import FeedbackService
from viu.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.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.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.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.core.config import AppConfig
from viu.core.exceptions import ViuError
from viu.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.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.service.download.service import DownloadService
from viu.cli.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.cli.utils.parser import parse_episode_range
from viu.libs.media_api.params import MediaSearchParams
from viu.libs.media_api.api import create_api_client
from viu.libs.provider.anime.provider import create_provider
from viu.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.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.core.config import AppConfig
from viu.core.exceptions import ViuError
from viu.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.libs.media_api.types import (
)
@click.pass_obj
def add(config: AppConfig, **options):
from viu.cli.service.download import DownloadService
from viu.cli.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.cli.utils.parser import parse_episode_range
from viu.libs.media_api.api import create_api_client
from viu.libs.media_api.params import MediaSearchParams
from viu.libs.provider.anime.provider import create_provider
from viu.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.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.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.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.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.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.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.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.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.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.service.download.service import DownloadService
from viu.cli.service.feedback import FeedbackService
from viu.cli.service.registry import MediaRegistryService
from viu.libs.media_api.api import create_api_client
from viu.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.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.service.feedback.service import FeedbackService
from viu.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.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.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.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.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.service.auth import AuthService
from viu.cli.service.download.service import DownloadService
from viu.cli.service.feedback import FeedbackService
from viu.cli.service.notification.service import NotificationService
from viu.cli.service.registry.service import MediaRegistryService
from viu.cli.service.worker.service import BackgroundWorkerService
from viu.libs.media_api.api import create_api_client
from viu.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