diff --git a/.vscode/settings.json b/.vscode/settings.json index acf6d3b..6760576 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,3 +1,3 @@ { - "python-envs.defaultEnvManager": "ms-python.python:system" + "python-envs.defaultEnvManager": "ms-python.python:venv" } diff --git a/README.md b/README.md index b7e889b..0263708 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# lrcfetch +# LRX-CLI A CLI tool for fetching LRC lyrics on Linux. Automatically detects the currently playing track via MPRIS/DBus and retrieves synced (or plain with all time tags set to `[00:00.00]` if failed to find any synced) lyrics from multiple sources. @@ -16,76 +16,76 @@ Lyrics are fetched using a fallback pipeline (first synced result wins): ## Usage -See `lrcfetch --help` for full command reference. Common use cases: +See `lrx --help` for full command reference. Common use cases: - Fetch lyrics for the currently playing track: ```bash - lrcfetch fetch + lrx fetch ``` using a specific player or source to fetch from: ```bash - lrcfetch --player mpd fetch --method lrclib-search + lrx --player mpd fetch --method lrclib-search ``` - Search by metadata (bypasses MPRIS): ```bash - lrcfetch search -t "My Love" -a "Westlife" - lrcfetch search --trackid "5p0ietGkLNEqx1Z7ijkw5g" + lrx search -t "My Love" -a "Westlife" + lrx search --trackid "5p0ietGkLNEqx1Z7ijkw5g" ``` or for a local file: ```bash - lrcfetch search --path "/path/to/Westlife - My Love.flac" + lrx search --path "/path/to/Westlife - My Love.flac" ``` - Export to sidecar `.lrc` file: ```bash - lrcfetch export + lrx export ``` or to a custom path: ```bash - lrcfetch export --output /path/to/lyrics.lrc + lrx export --output /path/to/lyrics.lrc ``` - Cache management: ```bash - lrcfetch cache stats # show cache statistics - lrcfetch cache query # query cache for current track - lrcfetch cache clear # clears cache of current track - lrcfetch cache clear --all # clears entire cache + lrx cache stats # show cache statistics + lrx cache query # query cache for current track + lrx cache clear # clears cache of current track + lrx cache clear --all # clears entire cache ``` ## Configuration Set credentials via environment variable or `.env` file: -- `~/.config/lrcfetch/.env` — user-level +- `~/.config/lrx/.env` — user-level - `.env` in working directory — project-local - Shell environment — highest priority ```env SPOTIFY_SP_DC=your_cookie_value QQ_MUSIC_API_URL=https://api.example.com -LRCFETCH_PLAYER=spotify +PREFERRED_PLAYER=spotify ``` - `SPOTIFY_SP_DC` — required for Spotify source. Defaults to empty (disabled Spotify source). - `QQ_MUSIC_API_URL` — required for QQ Music source. Defaults to empty (disabled QQ Music source). -- `LRCFETCH_PLAYER` — preferred MPRIS player when multiple are active. Defaults to `spotify`. Only used when no `--player` flag is given and more than one player (or none of them) is currently playing. +- `PREFERRED_PLAYER` — preferred MPRIS player when multiple are active. Defaults to `spotify`. Only used when no `--player` flag is given and more than one player (or none of them) is currently playing. Shell completion (zsh/fish/bash): ```bash -lrcfetch --install-completion +lrx --install-completion ``` ## Credits diff --git a/lrx/__pycache__/__init__.cpython-313.pyc b/lrx/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 1a3c3be..0000000 Binary files a/lrx/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/__init__.cpython-314.pyc b/lrx/__pycache__/__init__.cpython-314.pyc deleted file mode 100644 index 4ebce98..0000000 Binary files a/lrx/__pycache__/__init__.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/__main__.cpython-313.pyc b/lrx/__pycache__/__main__.cpython-313.pyc deleted file mode 100644 index 1c980ca..0000000 Binary files a/lrx/__pycache__/__main__.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/__main__.cpython-314.pyc b/lrx/__pycache__/__main__.cpython-314.pyc deleted file mode 100644 index e5908b0..0000000 Binary files a/lrx/__pycache__/__main__.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/cache.cpython-313.pyc b/lrx/__pycache__/cache.cpython-313.pyc deleted file mode 100644 index 670e768..0000000 Binary files a/lrx/__pycache__/cache.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/cache.cpython-314.pyc b/lrx/__pycache__/cache.cpython-314.pyc deleted file mode 100644 index 2f16fd4..0000000 Binary files a/lrx/__pycache__/cache.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/cli.cpython-313.pyc b/lrx/__pycache__/cli.cpython-313.pyc deleted file mode 100644 index 6e82c18..0000000 Binary files a/lrx/__pycache__/cli.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/cli.cpython-314.pyc b/lrx/__pycache__/cli.cpython-314.pyc deleted file mode 100644 index 9ac351b..0000000 Binary files a/lrx/__pycache__/cli.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/config.cpython-313.pyc b/lrx/__pycache__/config.cpython-313.pyc deleted file mode 100644 index 18c04b3..0000000 Binary files a/lrx/__pycache__/config.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/core.cpython-313.pyc b/lrx/__pycache__/core.cpython-313.pyc deleted file mode 100644 index a638a93..0000000 Binary files a/lrx/__pycache__/core.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/lrc.cpython-313.pyc b/lrx/__pycache__/lrc.cpython-313.pyc deleted file mode 100644 index 1d398ad..0000000 Binary files a/lrx/__pycache__/lrc.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/lrc.cpython-314.pyc b/lrx/__pycache__/lrc.cpython-314.pyc deleted file mode 100644 index 6864851..0000000 Binary files a/lrx/__pycache__/lrc.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/models.cpython-313.pyc b/lrx/__pycache__/models.cpython-313.pyc deleted file mode 100644 index af046de..0000000 Binary files a/lrx/__pycache__/models.cpython-313.pyc and /dev/null differ diff --git a/lrx/__pycache__/models.cpython-314.pyc b/lrx/__pycache__/models.cpython-314.pyc deleted file mode 100644 index 14d49aa..0000000 Binary files a/lrx/__pycache__/models.cpython-314.pyc and /dev/null differ diff --git a/lrx/__pycache__/mpris.cpython-313.pyc b/lrx/__pycache__/mpris.cpython-313.pyc deleted file mode 100644 index 5fb6c2f..0000000 Binary files a/lrx/__pycache__/mpris.cpython-313.pyc and /dev/null differ diff --git a/lrx/enrichers/__pycache__/__init__.cpython-313.pyc b/lrx/enrichers/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index bd522c1..0000000 Binary files a/lrx/enrichers/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/lrx/enrichers/__pycache__/audio_tag.cpython-313.pyc b/lrx/enrichers/__pycache__/audio_tag.cpython-313.pyc deleted file mode 100644 index c65ccca..0000000 Binary files a/lrx/enrichers/__pycache__/audio_tag.cpython-313.pyc and /dev/null differ diff --git a/lrx/enrichers/__pycache__/base.cpython-313.pyc b/lrx/enrichers/__pycache__/base.cpython-313.pyc deleted file mode 100644 index 8a88af1..0000000 Binary files a/lrx/enrichers/__pycache__/base.cpython-313.pyc and /dev/null differ diff --git a/lrx/enrichers/__pycache__/file_name.cpython-313.pyc b/lrx/enrichers/__pycache__/file_name.cpython-313.pyc deleted file mode 100644 index e514b4f..0000000 Binary files a/lrx/enrichers/__pycache__/file_name.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/__init__.cpython-313.pyc b/lrx/fetchers/__pycache__/__init__.cpython-313.pyc deleted file mode 100644 index 645408d..0000000 Binary files a/lrx/fetchers/__pycache__/__init__.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/base.cpython-313.pyc b/lrx/fetchers/__pycache__/base.cpython-313.pyc deleted file mode 100644 index 14e0222..0000000 Binary files a/lrx/fetchers/__pycache__/base.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/cache_search.cpython-313.pyc b/lrx/fetchers/__pycache__/cache_search.cpython-313.pyc deleted file mode 100644 index 8036956..0000000 Binary files a/lrx/fetchers/__pycache__/cache_search.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/local.cpython-313.pyc b/lrx/fetchers/__pycache__/local.cpython-313.pyc deleted file mode 100644 index 894ad14..0000000 Binary files a/lrx/fetchers/__pycache__/local.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/lrclib.cpython-313.pyc b/lrx/fetchers/__pycache__/lrclib.cpython-313.pyc deleted file mode 100644 index eda61f5..0000000 Binary files a/lrx/fetchers/__pycache__/lrclib.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/lrclib_search.cpython-313.pyc b/lrx/fetchers/__pycache__/lrclib_search.cpython-313.pyc deleted file mode 100644 index c01e5b0..0000000 Binary files a/lrx/fetchers/__pycache__/lrclib_search.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/musixmatch.cpython-313.pyc b/lrx/fetchers/__pycache__/musixmatch.cpython-313.pyc deleted file mode 100644 index 7c09c74..0000000 Binary files a/lrx/fetchers/__pycache__/musixmatch.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/netease.cpython-313.pyc b/lrx/fetchers/__pycache__/netease.cpython-313.pyc deleted file mode 100644 index 9fd6d53..0000000 Binary files a/lrx/fetchers/__pycache__/netease.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/qqmusic.cpython-313.pyc b/lrx/fetchers/__pycache__/qqmusic.cpython-313.pyc deleted file mode 100644 index a8b62e0..0000000 Binary files a/lrx/fetchers/__pycache__/qqmusic.cpython-313.pyc and /dev/null differ diff --git a/lrx/fetchers/__pycache__/spotify.cpython-313.pyc b/lrx/fetchers/__pycache__/spotify.cpython-313.pyc deleted file mode 100644 index 0b2c8bd..0000000 Binary files a/lrx/fetchers/__pycache__/spotify.cpython-313.pyc and /dev/null differ diff --git a/lrx/__init__.py b/lrx_cli/__init__.py similarity index 100% rename from lrx/__init__.py rename to lrx_cli/__init__.py diff --git a/lrx/__main__.py b/lrx_cli/__main__.py similarity index 57% rename from lrx/__main__.py rename to lrx_cli/__main__.py index 1407b6f..7f34de1 100644 --- a/lrx/__main__.py +++ b/lrx_cli/__main__.py @@ -1,4 +1,4 @@ -from lrx.cli import run +from lrx_cli.cli import run if __name__ == "__main__": run() diff --git a/lrx/cache.py b/lrx_cli/cache.py similarity index 100% rename from lrx/cache.py rename to lrx_cli/cache.py diff --git a/lrx/cli.py b/lrx_cli/cli.py similarity index 99% rename from lrx/cli.py rename to lrx_cli/cli.py index 48d7640..08a93b8 100644 --- a/lrx/cli.py +++ b/lrx_cli/cli.py @@ -22,7 +22,7 @@ from .lrc import get_sidecar_path app = cyclopts.App( - help="LRCFetch — Fetch line-synced lyrics for your music player.", + help="LRX-CLI — Fetch line-synced lyrics for your music player.", ) app.register_install_completion_command() diff --git a/lrx/config.py b/lrx_cli/config.py similarity index 91% rename from lrx/config.py rename to lrx_cli/config.py index 5f0f5b8..7706ed8 100644 --- a/lrx/config.py +++ b/lrx_cli/config.py @@ -13,7 +13,7 @@ from loguru import logger from importlib.metadata import version # Application -APP_NAME = "lrcfetch" +APP_NAME = "lrx-cli" APP_AUTHOR = "Uyanide" APP_VERSION = version(APP_NAME) @@ -23,7 +23,7 @@ DB_PATH = os.path.join(CACHE_DIR, "cache.db") # .env loading _config_env = Path(user_config_dir(APP_NAME, APP_AUTHOR)) / ".env" -load_dotenv(_config_env) # ~/.config/lrcfetch/.env +load_dotenv(_config_env) # ~/.config/lrx-cli/.env load_dotenv() # .env in cwd (does NOT override existing vars) # HTTP @@ -62,11 +62,11 @@ LRCLIB_SEARCH_URL = "https://lrclib.net/api/search" QQ_MUSIC_API_URL = os.environ.get("QQ_MUSIC_API_URL", "").rstrip("/") # Player preference (used when multiple MPRIS players are active) -PREFERRED_PLAYER = os.environ.get("LRCFETCH_PLAYER", "spotify") +PREFERRED_PLAYER = os.environ.get("PREFERRED_PLAYER", "spotify") # User-Agents UA_BROWSER = "Mozilla/5.0 (X11; Linux x86_64; rv:148.0) Gecko/20100101 Firefox/148.0" -UA_LRCFETCH = f"LRCFetch {APP_VERSION} (https://github.com/Uyanide/lrcfetch)" +UA_LRX = f"LRX-CLI {APP_VERSION} (https://github.com/Uyanide/lrx-cli)" os.makedirs(CACHE_DIR, exist_ok=True) diff --git a/lrx/core.py b/lrx_cli/core.py similarity index 100% rename from lrx/core.py rename to lrx_cli/core.py diff --git a/lrx/enrichers/__init__.py b/lrx_cli/enrichers/__init__.py similarity index 100% rename from lrx/enrichers/__init__.py rename to lrx_cli/enrichers/__init__.py diff --git a/lrx/enrichers/audio_tag.py b/lrx_cli/enrichers/audio_tag.py similarity index 100% rename from lrx/enrichers/audio_tag.py rename to lrx_cli/enrichers/audio_tag.py diff --git a/lrx/enrichers/base.py b/lrx_cli/enrichers/base.py similarity index 100% rename from lrx/enrichers/base.py rename to lrx_cli/enrichers/base.py diff --git a/lrx/enrichers/file_name.py b/lrx_cli/enrichers/file_name.py similarity index 100% rename from lrx/enrichers/file_name.py rename to lrx_cli/enrichers/file_name.py diff --git a/lrx/fetchers/__init__.py b/lrx_cli/fetchers/__init__.py similarity index 100% rename from lrx/fetchers/__init__.py rename to lrx_cli/fetchers/__init__.py diff --git a/lrx/fetchers/base.py b/lrx_cli/fetchers/base.py similarity index 100% rename from lrx/fetchers/base.py rename to lrx_cli/fetchers/base.py diff --git a/lrx/fetchers/cache_search.py b/lrx_cli/fetchers/cache_search.py similarity index 100% rename from lrx/fetchers/cache_search.py rename to lrx_cli/fetchers/cache_search.py diff --git a/lrx/fetchers/local.py b/lrx_cli/fetchers/local.py similarity index 100% rename from lrx/fetchers/local.py rename to lrx_cli/fetchers/local.py diff --git a/lrx/fetchers/lrclib.py b/lrx_cli/fetchers/lrclib.py similarity index 99% rename from lrx/fetchers/lrclib.py rename to lrx_cli/fetchers/lrclib.py index 94928d1..6c4eea6 100644 --- a/lrx/fetchers/lrclib.py +++ b/lrx_cli/fetchers/lrclib.py @@ -22,7 +22,7 @@ from ..config import ( TTL_NOT_FOUND, TTL_NETWORK_ERROR, LRCLIB_API_URL, - UA_LRCFETCH, + UA_LRX, ) @@ -54,7 +54,7 @@ class LrclibFetcher(BaseFetcher): try: with httpx.Client(timeout=HTTP_TIMEOUT) as client: - resp = client.get(url, headers={"User-Agent": UA_LRCFETCH}) + resp = client.get(url, headers={"User-Agent": UA_LRX}) if resp.status_code == 404: logger.debug(f"LRCLIB: not found for {track.display_name()}") diff --git a/lrx/fetchers/lrclib_search.py b/lrx_cli/fetchers/lrclib_search.py similarity index 99% rename from lrx/fetchers/lrclib_search.py rename to lrx_cli/fetchers/lrclib_search.py index 95f87c2..3cb18a5 100644 --- a/lrx/fetchers/lrclib_search.py +++ b/lrx_cli/fetchers/lrclib_search.py @@ -24,7 +24,7 @@ from ..config import ( TTL_NETWORK_ERROR, DURATION_TOLERANCE_MS, LRCLIB_SEARCH_URL, - UA_LRCFETCH, + UA_LRX, ) @@ -55,7 +55,7 @@ class LrclibSearchFetcher(BaseFetcher): try: with httpx.Client(timeout=HTTP_TIMEOUT) as client: - resp = client.get(url, headers={"User-Agent": UA_LRCFETCH}) + resp = client.get(url, headers={"User-Agent": UA_LRX}) if resp.status_code != 200: logger.error(f"LRCLIB-search: API returned {resp.status_code}") diff --git a/lrx/fetchers/netease.py b/lrx_cli/fetchers/netease.py similarity index 100% rename from lrx/fetchers/netease.py rename to lrx_cli/fetchers/netease.py diff --git a/lrx/fetchers/qqmusic.py b/lrx_cli/fetchers/qqmusic.py similarity index 100% rename from lrx/fetchers/qqmusic.py rename to lrx_cli/fetchers/qqmusic.py diff --git a/lrx/fetchers/spotify.py b/lrx_cli/fetchers/spotify.py similarity index 100% rename from lrx/fetchers/spotify.py rename to lrx_cli/fetchers/spotify.py diff --git a/lrx/lrc.py b/lrx_cli/lrc.py similarity index 100% rename from lrx/lrc.py rename to lrx_cli/lrc.py diff --git a/lrx/models.py b/lrx_cli/models.py similarity index 100% rename from lrx/models.py rename to lrx_cli/models.py diff --git a/lrx/mpris.py b/lrx_cli/mpris.py similarity index 96% rename from lrx/mpris.py rename to lrx_cli/mpris.py index c8a2c17..bf31348 100644 --- a/lrx/mpris.py +++ b/lrx_cli/mpris.py @@ -8,8 +8,8 @@ import asyncio from dbus_next.aio.message_bus import MessageBus from dbus_next.constants import BusType from dbus_next.message import Message -from lrx.models import TrackMeta -from lrx.config import PREFERRED_PLAYER +from lrx_cli.models import TrackMeta +from lrx_cli.config import PREFERRED_PLAYER from loguru import logger from typing import Optional, List, Any @@ -59,7 +59,7 @@ async def _select_player( When specific_player is given, filter by name match. Otherwise: prefer the currently playing player. If multiple are playing, - prefer the one matching LRCFETCH_PLAYER env var (default: spotify). + prefer the one matching PREFERRED_PLAYER env var (default: spotify). """ players = await _list_mpris_players(bus) if not players: @@ -82,7 +82,7 @@ async def _select_player( if len(candidates) == 1: return candidates[0] - # Multiple candidates: prefer LRCFETCH_PLAYER + # Multiple candidates: prefer PREFERRED_PLAYER preferred = PREFERRED_PLAYER.lower() if preferred: for p in candidates: diff --git a/main.py b/main.py index 1407b6f..7f34de1 100644 --- a/main.py +++ b/main.py @@ -1,4 +1,4 @@ -from lrx.cli import run +from lrx_cli.cli import run if __name__ == "__main__": run() diff --git a/pyproject.toml b/pyproject.toml index f61f550..ca37659 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -19,7 +19,7 @@ dependencies = [ ] [project.scripts] -lrx = "lrx.cli:run" +lrx = "lrx_cli.cli:run" [tool.ruff.lint] ignore = ["E402"] diff --git a/uv.lock b/uv.lock index 23596a2..5318acb 100644 --- a/uv.lock +++ b/uv.lock @@ -143,7 +143,7 @@ wheels = [ ] [[package]] -name = "lrcfetch" +name = "lrx-cli" version = "0.1.7" source = { editable = "." } dependencies = [