diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc3dc5f..e0f8a23 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -82,7 +82,8 @@ jobs: run: uv sync --frozen --all-extras - name: Run mypy - run: uv run mypy src/ || true + continue-on-error: true + run: uv run mypy src/ # Validate packaging scripts (syntax check only - real validation happens during build) packaging: diff --git a/packaging/tunecover.spec b/packaging/tunecover.spec index fdcbc85..17cbcff 100644 --- a/packaging/tunecover.spec +++ b/packaging/tunecover.spec @@ -8,7 +8,8 @@ Build command: Output: dist/TuneCover/ (folder with executable and dependencies) -Note: On Windows, you need chromaprint.dll in the system PATH or bundled. +Note: On Windows, fpcalc.exe must be placed in the packaging/ directory + (or project root) before building. CI downloads it automatically. Download from: https://acoustid.org/chromaprint """ @@ -59,25 +60,25 @@ hiddenimports = [ 'audioread.maddec', ] -# Platform-specific chromaprint binaries -# Users must ensure chromaprint is installed or bundled +# Bundle fpcalc binary on Windows so audio fingerprinting works out-of-the-box. +# CI downloads fpcalc.exe into packaging/ before running PyInstaller. binaries = [] -# On Windows, look for chromaprint.dll in common locations if sys.platform == 'win32': - chromaprint_paths = [ - os.path.join(os.environ.get('PROGRAMFILES', ''), 'Chromaprint', 'chromaprint.dll'), - os.path.join(os.environ.get('LOCALAPPDATA', ''), 'Chromaprint', 'chromaprint.dll'), - 'chromaprint.dll', # Current directory or PATH + fpcalc_search_paths = [ + os.path.join(SPECPATH, 'fpcalc.exe'), # CI places it here + os.path.join(SPECPATH, '..', 'fpcalc.exe'), # Project root + 'fpcalc.exe', # Current directory ] - chromaprint_found = False - for path in chromaprint_paths: + fpcalc_found = False + for path in fpcalc_search_paths: if os.path.exists(path): binaries.append((path, '.')) - chromaprint_found = True + fpcalc_found = True + print(f"INFO: Bundling fpcalc.exe from {os.path.abspath(path)}") break - if not chromaprint_found: - print("WARNING: chromaprint.dll not found. Audio fingerprinting will not work.") + if not fpcalc_found: + print("WARNING: fpcalc.exe not found. Audio fingerprinting will not work.") print(" Download from: https://acoustid.org/chromaprint") a = Analysis( @@ -182,7 +183,8 @@ exe = EXE( debug=False, bootloader_ignore_signals=False, strip=False, - upx=True, + # UPX disabled: compressing Qt DLLs causes runtime crashes on Windows. + upx=False, console=False, # GUI application, no console window disable_windowed_traceback=False, argv_emulation=False, @@ -199,7 +201,8 @@ coll = COLLECT( a.zipfiles, a.datas, strip=False, - upx=True, + # UPX disabled: compressing Qt DLLs causes runtime crashes on Windows. + upx=False, upx_exclude=[], name='TuneCover', ) diff --git a/pyproject.toml b/pyproject.toml index 0c42938..50b0275 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "tunecover" -version = "0.1.0" +version = "0.1.1" description = "A GUI application for fetching and embedding album artwork in music libraries" readme = "README.md" requires-python = ">=3.12" diff --git a/src/core/fingerprint.py b/src/core/fingerprint.py index cd5ed8f..73daa27 100644 --- a/src/core/fingerprint.py +++ b/src/core/fingerprint.py @@ -10,6 +10,7 @@ import platform import shutil import subprocess +import sys import threading from difflib import SequenceMatcher from pathlib import Path @@ -57,7 +58,8 @@ def _find_fpcalc_binary() -> str | None: 1. Custom path set via set_fpcalc_path() 2. FPCALC_COMMAND environment variable 3. System PATH (via shutil.which) - 4. Common installation paths for each platform + 4. PyInstaller bundle (frozen builds only) + 5. Common installation paths for each platform Returns: Path to fpcalc binary if found, None otherwise @@ -86,7 +88,29 @@ def _find_fpcalc_binary() -> str | None: _detected_fpcalc_path = which_path return which_path - # 4. Check platform-specific common locations + # 4. Check PyInstaller bundle (frozen builds only) + # In one-folder mode, fpcalc sits next to the executable. + # In one-file mode, it is extracted to sys._MEIPASS at runtime. + if getattr(sys, "frozen", False): + fpcalc_name = "fpcalc.exe" if platform.system() == "Windows" else "fpcalc" + # One-folder mode: next to the executable + candidate = Path(sys.executable).parent / fpcalc_name + if candidate.is_file(): + path_str = str(candidate) + logger.info(f"Found bundled fpcalc (one-folder): {path_str}") + _detected_fpcalc_path = path_str + return path_str + # One-file mode: extracted to temporary _MEIPASS directory + meipass = getattr(sys, "_MEIPASS", None) + if meipass: + candidate = Path(meipass) / fpcalc_name + if candidate.is_file(): + path_str = str(candidate) + logger.info(f"Found bundled fpcalc (one-file): {path_str}") + _detected_fpcalc_path = path_str + return path_str + + # 5. Check platform-specific common locations system = platform.system() common_paths: list[str] = [] diff --git a/src/i18n/locales/en/LC_MESSAGES/messages.po b/src/i18n/locales/en/LC_MESSAGES/messages.po index 31be853..cb7dad3 100644 --- a/src/i18n/locales/en/LC_MESSAGES/messages.po +++ b/src/i18n/locales/en/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: tunecover 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-01 18:16+0100\n" +"POT-Creation-Date: 2026-02-07 16:51+0100\n" "PO-Revision-Date: 2026-01-26 22:35+0100\n" "Last-Translator: TuneCover Team\n" "Language: en\n" @@ -525,7 +525,7 @@ msgstr "No cover available" msgid "Download error" msgstr "Download error" -#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:186 +#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:184 msgid "Cover applied" msgstr "Cover applied" @@ -571,10 +571,10 @@ msgstr "Processing in progress" #: src/ui/album_detail.py:350 src/ui/album_detail.py:619 #: src/ui/dialogs/acoustid_save_dialog.py:181 #: src/ui/dialogs/batch_acoustid_dialog.py:323 -#: src/ui/dialogs/batch_download_dialog.py:411 +#: src/ui/dialogs/batch_download_dialog.py:409 #: src/ui/dialogs/cover_comparison.py:364 src/ui/fingerprint_dialog.py:457 #: src/ui/main_window.py:866 src/ui/main_window.py:1521 -#: src/ui/preferences.py:82 src/ui/search_panel.py:1027 +#: src/ui/preferences.py:82 src/ui/search_panel.py:1031 msgid "Cancel" msgstr "Cancel" @@ -587,16 +587,16 @@ msgid "Information" msgstr "Information" #: src/ui/album_detail.py:441 src/ui/dialogs/acoustid_save_dialog.py:102 -#: src/ui/search_panel.py:813 +#: src/ui/search_panel.py:817 msgid "Artist:" msgstr "Artist:" #: src/ui/album_detail.py:444 src/ui/dialogs/acoustid_save_dialog.py:107 -#: src/ui/search_panel.py:821 +#: src/ui/search_panel.py:825 msgid "Album:" msgstr "Album:" -#: src/ui/album_detail.py:447 src/ui/search_panel.py:829 +#: src/ui/album_detail.py:447 src/ui/search_panel.py:833 msgid "Year:" msgstr "Year:" @@ -642,11 +642,11 @@ msgstr "Identify the album via audio fingerprint" msgid "AcoustID:" msgstr "AcoustID:" -#: src/ui/album_detail.py:512 src/ui/search_panel.py:851 +#: src/ui/album_detail.py:512 src/ui/search_panel.py:855 msgid "ISRC:" msgstr "ISRC:" -#: src/ui/album_detail.py:517 src/ui/search_panel.py:860 +#: src/ui/album_detail.py:517 src/ui/search_panel.py:864 msgid "Barcode:" msgstr "Barcode:" @@ -815,8 +815,8 @@ msgstr "Cover saved for {name} ({actions})" #: src/ui/album_detail.py:1926 src/ui/album_detail.py:2017 #: src/ui/dialogs/batch_acoustid_dialog.py:216 src/ui/main_window.py:1615 #: src/ui/main_window.py:2206 src/ui/preferences.py:680 -#: src/ui/preferences.py:693 src/ui/search_panel.py:1218 -#: src/ui/search_panel.py:1827 src/ui/search_panel.py:1869 +#: src/ui/preferences.py:693 src/ui/search_panel.py:1222 +#: src/ui/search_panel.py:1840 src/ui/search_panel.py:1882 msgid "Error" msgstr "Error" @@ -1752,11 +1752,11 @@ msgstr "" msgid "Auto download" msgstr "Auto download" -#: src/ui/main_window.py:1941 src/ui/search_panel.py:1206 +#: src/ui/main_window.py:1941 src/ui/search_panel.py:1210 msgid "Fingerprinting unavailable" msgstr "Fingerprinting unavailable" -#: src/ui/main_window.py:1943 src/ui/search_panel.py:1208 +#: src/ui/main_window.py:1943 src/ui/search_panel.py:1212 msgid "" "Audio fingerprinting requires chromaprint to be installed.\n" "\n" @@ -1865,7 +1865,7 @@ msgid "Cache" msgstr "Cache" #: src/ui/dialogs/cover_comparison.py:368 src/ui/preferences.py:86 -#: src/ui/search_panel.py:1031 +#: src/ui/search_panel.py:1035 msgid "Apply" msgstr "Apply" @@ -1901,7 +1901,7 @@ msgstr "Application language (requires restart)" msgid "Language:" msgstr "Language:" -#: src/ui/preferences.py:125 src/ui/search_panel.py:900 +#: src/ui/preferences.py:125 src/ui/search_panel.py:904 msgid "Search" msgstr "Search" @@ -2434,7 +2434,7 @@ msgstr "AcoustID lookup failed. Check your API key in Preferences." msgid "No matches found in AcoustID database" msgstr "No matches found in AcoustID database" -#: src/ui/search_panel.py:495 src/ui/search_panel.py:1226 +#: src/ui/search_panel.py:495 src/ui/search_panel.py:1230 msgid "Analyzing audio fingerprints..." msgstr "Analyzing audio fingerprints..." @@ -2447,16 +2447,16 @@ msgstr "[Cover]" msgid "Double-click to zoom" msgstr "Double-click to zoom" -#: src/ui/search_panel.py:745 +#: src/ui/search_panel.py:749 #, python-brace-format msgid "Cover search: {name}" msgstr "Cover search: {name}" -#: src/ui/search_panel.py:789 +#: src/ui/search_panel.py:793 msgid "Force text search" msgstr "Force text search" -#: src/ui/search_panel.py:792 +#: src/ui/search_panel.py:796 msgid "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." @@ -2464,43 +2464,43 @@ msgstr "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." -#: src/ui/search_panel.py:808 +#: src/ui/search_panel.py:812 msgid "Search criteria" msgstr "Search criteria" -#: src/ui/search_panel.py:816 +#: src/ui/search_panel.py:820 msgid "Artist name" msgstr "Artist name" -#: src/ui/search_panel.py:824 +#: src/ui/search_panel.py:828 msgid "Album title" msgstr "Album title" -#: src/ui/search_panel.py:832 +#: src/ui/search_panel.py:836 msgid "(optional)" msgstr "(optional)" -#: src/ui/search_panel.py:838 +#: src/ui/search_panel.py:842 msgid "Title:" msgstr "Title:" -#: src/ui/search_panel.py:841 +#: src/ui/search_panel.py:845 msgid "Track title" msgstr "Track title" -#: src/ui/search_panel.py:854 +#: src/ui/search_panel.py:858 msgid "ISRC" msgstr "ISRC" -#: src/ui/search_panel.py:863 +#: src/ui/search_panel.py:867 msgid "UPC/EAN" msgstr "UPC/EAN" -#: src/ui/search_panel.py:876 +#: src/ui/search_panel.py:880 msgid "AcoustID" msgstr "AcoustID" -#: src/ui/search_panel.py:879 +#: src/ui/search_panel.py:883 msgid "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." @@ -2508,7 +2508,7 @@ msgstr "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." -#: src/ui/search_panel.py:893 +#: src/ui/search_panel.py:897 msgid "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." @@ -2516,40 +2516,40 @@ msgstr "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." -#: src/ui/search_panel.py:896 +#: src/ui/search_panel.py:900 msgid "No audio file available for fingerprinting." msgstr "No audio file available for fingerprinting." -#: src/ui/search_panel.py:947 +#: src/ui/search_panel.py:951 msgid "Results" msgstr "Results" -#: src/ui/search_panel.py:962 +#: src/ui/search_panel.py:966 msgid "Stop" msgstr "Stop" -#: src/ui/search_panel.py:963 +#: src/ui/search_panel.py:967 msgid "Stop loading thumbnails" msgstr "Stop loading thumbnails" -#: src/ui/search_panel.py:984 +#: src/ui/search_panel.py:988 msgid "Start a search to find covers" msgstr "Start a search to find covers" -#: src/ui/search_panel.py:993 +#: src/ui/search_panel.py:997 msgid "Selection" msgstr "Selection" -#: src/ui/search_panel.py:1003 src/ui/search_panel.py:1599 +#: src/ui/search_panel.py:1007 src/ui/search_panel.py:1612 msgid "No selection" msgstr "No selection" -#: src/ui/search_panel.py:1078 +#: src/ui/search_panel.py:1082 #, python-brace-format msgid "Mode: MBID Lookup ({mbid}...)" msgstr "Mode: MBID Lookup ({mbid}...)" -#: src/ui/search_panel.py:1086 +#: src/ui/search_panel.py:1090 #, python-brace-format msgid "" "MusicBrainz Album ID: {mbid}\n" @@ -2562,11 +2562,11 @@ msgstr "" "Search uses the unique MusicBrainz identifier.\n" "This is the most reliable method (exact match)." -#: src/ui/search_panel.py:1092 +#: src/ui/search_panel.py:1096 msgid "Mode: Text search" msgstr "Mode: Text search" -#: src/ui/search_panel.py:1098 +#: src/ui/search_panel.py:1102 msgid "" "Search uses artist/album text.\n" "Results depend on text matching." @@ -2574,11 +2574,11 @@ msgstr "" "Search uses artist/album text.\n" "Results depend on text matching." -#: src/ui/search_panel.py:1218 +#: src/ui/search_panel.py:1222 msgid "No audio files available for fingerprinting." msgstr "No audio files available for fingerprinting." -#: src/ui/search_panel.py:1283 +#: src/ui/search_panel.py:1287 #, python-brace-format, python-format msgid "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" @@ -2587,16 +2587,16 @@ msgstr "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" "Click 'Search' to find covers." -#: src/ui/search_panel.py:1300 +#: src/ui/search_panel.py:1304 #, python-brace-format msgid "AcoustID error: {error}" msgstr "AcoustID error: {error}" -#: src/ui/search_panel.py:1305 +#: src/ui/search_panel.py:1309 msgid "Identification error" msgstr "Identification error" -#: src/ui/search_panel.py:1306 +#: src/ui/search_panel.py:1310 #, python-brace-format msgid "" "Could not identify via AcoustID:\n" @@ -2605,17 +2605,17 @@ msgstr "" "Could not identify via AcoustID:\n" "{error}" -#: src/ui/search_panel.py:1312 +#: src/ui/search_panel.py:1316 #, python-brace-format msgid "Analyzing track {current}/{total}: {name}" msgstr "Analyzing track {current}/{total}: {name}" -#: src/ui/search_panel.py:1327 +#: src/ui/search_panel.py:1331 #, python-brace-format msgid "No fingerprint matches found ({analyzed} tracks analyzed)." msgstr "No fingerprint matches found ({analyzed} tracks analyzed)." -#: src/ui/search_panel.py:1376 +#: src/ui/search_panel.py:1380 #, python-brace-format msgid "" "Selected: {artist} - {title} ({votes} tracks matched).\n" @@ -2624,11 +2624,11 @@ msgstr "" "Selected: {artist} - {title} ({votes} tracks matched).\n" "Click 'Search' to find covers." -#: src/ui/search_panel.py:1451 +#: src/ui/search_panel.py:1455 msgid "Scan error" msgstr "Scan error" -#: src/ui/search_panel.py:1452 +#: src/ui/search_panel.py:1456 #, python-brace-format msgid "" "Error scanning additional tracks:\n" @@ -2637,15 +2637,15 @@ msgstr "" "Error scanning additional tracks:\n" "{error}" -#: src/ui/search_panel.py:1483 +#: src/ui/search_panel.py:1487 msgid "No source available" msgstr "No source available" -#: src/ui/search_panel.py:1491 src/ui/widgets/source_selector.py:237 +#: src/ui/search_panel.py:1495 src/ui/widgets/source_selector.py:237 msgid "Configuration required" msgstr "Configuration required" -#: src/ui/search_panel.py:1493 +#: src/ui/search_panel.py:1497 #, python-brace-format msgid "" "Provider {name} requires an API key.\n" @@ -2658,53 +2658,53 @@ msgstr "" "Please configure the API key in preferences\n" "(Menu Edit -> Preferences)." -#: src/ui/search_panel.py:1520 +#: src/ui/search_panel.py:1524 msgid "Enter at least an artist or album" msgstr "Enter at least an artist or album" -#: src/ui/dialogs/batch_download_dialog.py:247 src/ui/search_panel.py:1539 +#: src/ui/dialogs/batch_download_dialog.py:245 src/ui/search_panel.py:1546 #, python-brace-format msgid "MBID lookup on {provider}..." msgstr "MBID lookup on {provider}..." -#: src/ui/search_panel.py:1546 +#: src/ui/search_panel.py:1553 #, python-brace-format msgid "artist='{artist}'" msgstr "artist='{artist}'" -#: src/ui/search_panel.py:1548 +#: src/ui/search_panel.py:1555 #, python-brace-format msgid "album='{album}'" msgstr "album='{album}'" -#: src/ui/search_panel.py:1550 +#: src/ui/search_panel.py:1557 #, python-brace-format msgid "year={year}" msgstr "year={year}" -#: src/ui/search_panel.py:1553 +#: src/ui/search_panel.py:1560 #, python-brace-format msgid "Searching on {provider}: {desc}..." msgstr "Searching on {provider}: {desc}..." -#: src/ui/search_panel.py:1617 +#: src/ui/search_panel.py:1630 #, python-brace-format msgid "No results found on {provider}" msgstr "No result found on {provider}" -#: src/ui/search_panel.py:1655 +#: src/ui/search_panel.py:1668 msgid "Connection error. Check your internet connection." msgstr "Connection error to server. Check your internet connection." -#: src/ui/search_panel.py:1657 +#: src/ui/search_panel.py:1670 msgid "Invalid or expired API key. Check your credentials in preferences." msgstr "Invalid or expired API key. Check your credentials in preferences." -#: src/ui/search_panel.py:1659 +#: src/ui/search_panel.py:1672 msgid "Too many requests. Please wait before trying again." msgstr "Too many requests. Please wait before retrying." -#: src/ui/search_panel.py:1661 +#: src/ui/search_panel.py:1674 #, python-brace-format msgid "" "API communication error:\n" @@ -2713,25 +2713,25 @@ msgstr "" "API communication error:\n" "{error}" -#: src/ui/search_panel.py:1667 +#: src/ui/search_panel.py:1680 msgid "Search error" msgstr "Search error" -#: src/ui/search_panel.py:1768 +#: src/ui/search_panel.py:1781 #, python-brace-format msgid "Year: {year} | Score: {score}%" msgstr "Year: {year} | Score: {score}%" -#: src/ui/search_panel.py:1776 +#: src/ui/search_panel.py:1789 #, python-brace-format msgid "Image: {info}" msgstr "Image: {info}" -#: src/ui/search_panel.py:1827 +#: src/ui/search_panel.py:1840 msgid "This cover is not available." msgstr "This cover is not available." -#: src/ui/search_panel.py:1869 +#: src/ui/search_panel.py:1882 #, python-brace-format msgid "" "Error downloading cover:\n" @@ -2800,7 +2800,7 @@ msgid "Albums to process: {count}" msgstr "Albums to process: {count}" #: src/ui/dialogs/batch_acoustid_dialog.py:103 -#: src/ui/dialogs/batch_download_dialog.py:134 +#: src/ui/dialogs/batch_download_dialog.py:132 msgid "Operation cancelled by user." msgstr "Operation cancelled by user." @@ -2813,12 +2813,12 @@ msgid "Already has AcoustID" msgstr "Already has AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:120 -#: src/ui/dialogs/batch_download_dialog.py:152 +#: src/ui/dialogs/batch_download_dialog.py:150 msgid "Skipped by user" msgstr "Skipped by user" #: src/ui/dialogs/batch_acoustid_dialog.py:122 -#: src/ui/dialogs/batch_download_dialog.py:154 +#: src/ui/dialogs/batch_download_dialog.py:152 msgid "Skipped" msgstr "Skipped" @@ -2851,7 +2851,7 @@ msgid "No match found in AcoustID" msgstr "No match found in AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:156 -#: src/ui/dialogs/batch_download_dialog.py:201 +#: src/ui/dialogs/batch_download_dialog.py:199 msgid "No match" msgstr "No match" @@ -2909,7 +2909,7 @@ msgid "If enabled, artist and album tags will be updated from AcoustID results" msgstr "If enabled, artist and album tags will be updated from AcoustID results" #: src/ui/dialogs/batch_acoustid_dialog.py:282 -#: src/ui/dialogs/batch_download_dialog.py:376 +#: src/ui/dialogs/batch_download_dialog.py:374 msgid "Progress" msgstr "Progress" @@ -2918,12 +2918,12 @@ msgid "Ready to start" msgstr "Ready to start" #: src/ui/dialogs/batch_acoustid_dialog.py:299 -#: src/ui/dialogs/batch_download_dialog.py:392 +#: src/ui/dialogs/batch_download_dialog.py:390 msgid "Log" msgstr "Log" #: src/ui/dialogs/batch_acoustid_dialog.py:312 -#: src/ui/dialogs/batch_download_dialog.py:406 +#: src/ui/dialogs/batch_download_dialog.py:404 msgid "Skip" msgstr "Skip" @@ -2937,7 +2937,7 @@ msgid "Processing {current}/{total}: {name}" msgstr "Processing {current}/{total}: {name}" #: src/ui/dialogs/batch_acoustid_dialog.py:387 -#: src/ui/dialogs/batch_download_dialog.py:415 +#: src/ui/dialogs/batch_download_dialog.py:413 #: src/ui/dialogs/cover_zoom_dialog.py:453 #: src/ui/dialogs/statistics_dialog.py:277 src/ui/widgets/toast.py:168 msgid "Close" @@ -2952,117 +2952,117 @@ msgstr "Complete" msgid "{count} albums identified via AcoustID" msgstr "{count} albums identified via AcoustID" -#: src/ui/dialogs/batch_download_dialog.py:115 +#: src/ui/dialogs/batch_download_dialog.py:113 msgid "No cover provider enabled." msgstr "No cover provider enabled." -#: src/ui/dialogs/batch_download_dialog.py:127 +#: src/ui/dialogs/batch_download_dialog.py:125 #, python-brace-format msgid "Enabled providers: {providers}" msgstr "Enabled providers: {providers}" -#: src/ui/dialogs/batch_download_dialog.py:129 +#: src/ui/dialogs/batch_download_dialog.py:127 #, python-brace-format msgid "Minimum score: {score}%" msgstr "Minimum score: {score}%" -#: src/ui/dialogs/batch_download_dialog.py:145 +#: src/ui/dialogs/batch_download_dialog.py:143 msgid "Skipped (already has cover)" msgstr "Skipped (already has cover)" -#: src/ui/dialogs/batch_download_dialog.py:147 +#: src/ui/dialogs/batch_download_dialog.py:145 msgid "Already has cover" msgstr "Already has cover" -#: src/ui/dialogs/batch_download_dialog.py:173 +#: src/ui/dialogs/batch_download_dialog.py:171 msgid "Error: invalid save configuration" msgstr "Error: invalid save configuration" -#: src/ui/dialogs/batch_download_dialog.py:182 +#: src/ui/dialogs/batch_download_dialog.py:180 #, python-brace-format msgid "Cover applied ({provider}, score: {score}%)" msgstr "Cover applied ({provider}, score: {score}%)" -#: src/ui/dialogs/batch_download_dialog.py:192 +#: src/ui/dialogs/batch_download_dialog.py:190 #, python-brace-format msgid "Error ({provider}): {error}" msgstr "Error ({provider}): {error}" -#: src/ui/dialogs/batch_download_dialog.py:199 +#: src/ui/dialogs/batch_download_dialog.py:197 msgid "No sufficient result found" msgstr "No sufficient result found" -#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:203 msgid "Summary:" msgstr "Summary:" -#: src/ui/dialogs/batch_download_dialog.py:207 -#: src/ui/dialogs/batch_download_dialog.py:487 +#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:485 #, python-brace-format msgid "Covers downloaded: {count}" msgstr "Covers downloaded: {count}" -#: src/ui/dialogs/batch_download_dialog.py:210 +#: src/ui/dialogs/batch_download_dialog.py:208 #, python-brace-format msgid "Skipped (no match): {count}" msgstr "Skipped (no match): {count}" -#: src/ui/dialogs/batch_download_dialog.py:214 +#: src/ui/dialogs/batch_download_dialog.py:212 #, python-brace-format msgid "Skipped (already have cover): {count}" msgstr "Skipped (already have cover): {count}" -#: src/ui/dialogs/batch_download_dialog.py:219 -#: src/ui/dialogs/batch_download_dialog.py:495 +#: src/ui/dialogs/batch_download_dialog.py:217 +#: src/ui/dialogs/batch_download_dialog.py:493 #, python-brace-format msgid "Errors: {count}" msgstr "Errors: {count}" -#: src/ui/dialogs/batch_download_dialog.py:258 +#: src/ui/dialogs/batch_download_dialog.py:256 #, python-brace-format msgid "Text search on {provider}..." msgstr "Text search on {provider}..." -#: src/ui/dialogs/batch_download_dialog.py:369 +#: src/ui/dialogs/batch_download_dialog.py:367 msgid "Automatic cover download" msgstr "Automatic cover download" -#: src/ui/dialogs/batch_download_dialog.py:379 +#: src/ui/dialogs/batch_download_dialog.py:377 msgid "Preparing..." msgstr "Preparing..." -#: src/ui/dialogs/batch_download_dialog.py:407 +#: src/ui/dialogs/batch_download_dialog.py:405 msgid "Skip to next album" msgstr "Skip to next album" -#: src/ui/dialogs/batch_download_dialog.py:442 +#: src/ui/dialogs/batch_download_dialog.py:440 #, python-brace-format msgid "Album {current}/{total}: {name}" msgstr "Album {current}/{total}: {name}" -#: src/ui/dialogs/batch_download_dialog.py:467 +#: src/ui/dialogs/batch_download_dialog.py:465 msgid "Finished" msgstr "Finished" -#: src/ui/dialogs/batch_download_dialog.py:482 +#: src/ui/dialogs/batch_download_dialog.py:480 msgid "Cancelling..." msgstr "Cancelling..." -#: src/ui/dialogs/batch_download_dialog.py:488 +#: src/ui/dialogs/batch_download_dialog.py:486 #, python-brace-format msgid "Albums skipped (no match): {count}" msgstr "Albums skipped (no match): {count}" -#: src/ui/dialogs/batch_download_dialog.py:489 +#: src/ui/dialogs/batch_download_dialog.py:487 #, python-brace-format msgid "Albums skipped (already have cover): {count}" msgstr "Albums skipped (already have cover): {count}" -#: src/ui/dialogs/batch_download_dialog.py:530 +#: src/ui/dialogs/batch_download_dialog.py:528 msgid "Cancel download" msgstr "Cancel download" -#: src/ui/dialogs/batch_download_dialog.py:531 +#: src/ui/dialogs/batch_download_dialog.py:529 msgid "A download is in progress. Do you want to cancel it?" msgstr "A download is in progress. Do you want to cancel it?" diff --git a/src/i18n/locales/es/LC_MESSAGES/messages.po b/src/i18n/locales/es/LC_MESSAGES/messages.po index e03ff85..080820b 100644 --- a/src/i18n/locales/es/LC_MESSAGES/messages.po +++ b/src/i18n/locales/es/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: tunecover 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-01 18:16+0100\n" +"POT-Creation-Date: 2026-02-07 16:51+0100\n" "PO-Revision-Date: 2026-01-26 22:35+0100\n" "Last-Translator: TuneCover Team\n" "Language: es\n" @@ -526,7 +526,7 @@ msgstr "Sin carátula disponible" msgid "Download error" msgstr "Error de descarga" -#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:186 +#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:184 msgid "Cover applied" msgstr "Carátula aplicada" @@ -572,10 +572,10 @@ msgstr "Procesamiento en curso" #: src/ui/album_detail.py:350 src/ui/album_detail.py:619 #: src/ui/dialogs/acoustid_save_dialog.py:181 #: src/ui/dialogs/batch_acoustid_dialog.py:323 -#: src/ui/dialogs/batch_download_dialog.py:411 +#: src/ui/dialogs/batch_download_dialog.py:409 #: src/ui/dialogs/cover_comparison.py:364 src/ui/fingerprint_dialog.py:457 #: src/ui/main_window.py:866 src/ui/main_window.py:1521 -#: src/ui/preferences.py:82 src/ui/search_panel.py:1027 +#: src/ui/preferences.py:82 src/ui/search_panel.py:1031 msgid "Cancel" msgstr "Cancelar" @@ -588,16 +588,16 @@ msgid "Information" msgstr "Información" #: src/ui/album_detail.py:441 src/ui/dialogs/acoustid_save_dialog.py:102 -#: src/ui/search_panel.py:813 +#: src/ui/search_panel.py:817 msgid "Artist:" msgstr "Artista:" #: src/ui/album_detail.py:444 src/ui/dialogs/acoustid_save_dialog.py:107 -#: src/ui/search_panel.py:821 +#: src/ui/search_panel.py:825 msgid "Album:" msgstr "Álbum:" -#: src/ui/album_detail.py:447 src/ui/search_panel.py:829 +#: src/ui/album_detail.py:447 src/ui/search_panel.py:833 msgid "Year:" msgstr "Año:" @@ -643,11 +643,11 @@ msgstr "Identificar el álbum mediante huella de audio" msgid "AcoustID:" msgstr "AcoustID:" -#: src/ui/album_detail.py:512 src/ui/search_panel.py:851 +#: src/ui/album_detail.py:512 src/ui/search_panel.py:855 msgid "ISRC:" msgstr "ISRC:" -#: src/ui/album_detail.py:517 src/ui/search_panel.py:860 +#: src/ui/album_detail.py:517 src/ui/search_panel.py:864 msgid "Barcode:" msgstr "Código de barras:" @@ -816,8 +816,8 @@ msgstr "Carátula guardada para {name} ({actions})" #: src/ui/album_detail.py:1926 src/ui/album_detail.py:2017 #: src/ui/dialogs/batch_acoustid_dialog.py:216 src/ui/main_window.py:1615 #: src/ui/main_window.py:2206 src/ui/preferences.py:680 -#: src/ui/preferences.py:693 src/ui/search_panel.py:1218 -#: src/ui/search_panel.py:1827 src/ui/search_panel.py:1869 +#: src/ui/preferences.py:693 src/ui/search_panel.py:1222 +#: src/ui/search_panel.py:1840 src/ui/search_panel.py:1882 msgid "Error" msgstr "Error" @@ -1768,11 +1768,11 @@ msgstr "" msgid "Auto download" msgstr "Descarga automática" -#: src/ui/main_window.py:1941 src/ui/search_panel.py:1206 +#: src/ui/main_window.py:1941 src/ui/search_panel.py:1210 msgid "Fingerprinting unavailable" msgstr "Identificación de audio no disponible" -#: src/ui/main_window.py:1943 src/ui/search_panel.py:1208 +#: src/ui/main_window.py:1943 src/ui/search_panel.py:1212 msgid "" "Audio fingerprinting requires chromaprint to be installed.\n" "\n" @@ -1882,7 +1882,7 @@ msgid "Cache" msgstr "Caché" #: src/ui/dialogs/cover_comparison.py:368 src/ui/preferences.py:86 -#: src/ui/search_panel.py:1031 +#: src/ui/search_panel.py:1035 msgid "Apply" msgstr "Aplicar" @@ -1918,7 +1918,7 @@ msgstr "Idioma de la aplicación (requiere reinicio)" msgid "Language:" msgstr "Idioma:" -#: src/ui/preferences.py:125 src/ui/search_panel.py:900 +#: src/ui/preferences.py:125 src/ui/search_panel.py:904 msgid "Search" msgstr "Buscar" @@ -2459,7 +2459,7 @@ msgstr "Búsqueda AcoustID fallida. Verifique su clave API en Preferencias." msgid "No matches found in AcoustID database" msgstr "No se encontraron coincidencias en la base de datos AcoustID" -#: src/ui/search_panel.py:495 src/ui/search_panel.py:1226 +#: src/ui/search_panel.py:495 src/ui/search_panel.py:1230 msgid "Analyzing audio fingerprints..." msgstr "Analizando huellas de audio..." @@ -2472,16 +2472,16 @@ msgstr "[Carátula]" msgid "Double-click to zoom" msgstr "Doble clic para ampliar" -#: src/ui/search_panel.py:745 +#: src/ui/search_panel.py:749 #, python-brace-format msgid "Cover search: {name}" msgstr "Búsqueda de carátula: {name}" -#: src/ui/search_panel.py:789 +#: src/ui/search_panel.py:793 msgid "Force text search" msgstr "Forzar búsqueda de texto" -#: src/ui/search_panel.py:792 +#: src/ui/search_panel.py:796 msgid "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." @@ -2489,43 +2489,43 @@ msgstr "" "Ignorar MBID y realizar búsqueda de texto.\n" "Útil si MBID no da resultados satisfactorios." -#: src/ui/search_panel.py:808 +#: src/ui/search_panel.py:812 msgid "Search criteria" msgstr "Criterios de búsqueda" -#: src/ui/search_panel.py:816 +#: src/ui/search_panel.py:820 msgid "Artist name" msgstr "Nombre del artista" -#: src/ui/search_panel.py:824 +#: src/ui/search_panel.py:828 msgid "Album title" msgstr "Título del álbum" -#: src/ui/search_panel.py:832 +#: src/ui/search_panel.py:836 msgid "(optional)" msgstr "(opcional)" -#: src/ui/search_panel.py:838 +#: src/ui/search_panel.py:842 msgid "Title:" msgstr "Título:" -#: src/ui/search_panel.py:841 +#: src/ui/search_panel.py:845 msgid "Track title" msgstr "Título de la pista" -#: src/ui/search_panel.py:854 +#: src/ui/search_panel.py:858 msgid "ISRC" msgstr "ISRC" -#: src/ui/search_panel.py:863 +#: src/ui/search_panel.py:867 msgid "UPC/EAN" msgstr "UPC/EAN" -#: src/ui/search_panel.py:876 +#: src/ui/search_panel.py:880 msgid "AcoustID" msgstr "AcoustID" -#: src/ui/search_panel.py:879 +#: src/ui/search_panel.py:883 msgid "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." @@ -2533,7 +2533,7 @@ msgstr "" "Usar huella digital de audio para identificar esta pista.\n" "Completa los campos artista/álbum desde la base de datos AcoustID." -#: src/ui/search_panel.py:893 +#: src/ui/search_panel.py:897 msgid "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." @@ -2541,40 +2541,40 @@ msgstr "" "Fingerprinting no disponible.\n" "Instala chromaprint/fpcalc y pyacoustid." -#: src/ui/search_panel.py:896 +#: src/ui/search_panel.py:900 msgid "No audio file available for fingerprinting." msgstr "No hay archivo de audio disponible para fingerprinting." -#: src/ui/search_panel.py:947 +#: src/ui/search_panel.py:951 msgid "Results" msgstr "Resultados" -#: src/ui/search_panel.py:962 +#: src/ui/search_panel.py:966 msgid "Stop" msgstr "Detener" -#: src/ui/search_panel.py:963 +#: src/ui/search_panel.py:967 msgid "Stop loading thumbnails" msgstr "Detener carga de miniaturas" -#: src/ui/search_panel.py:984 +#: src/ui/search_panel.py:988 msgid "Start a search to find covers" msgstr "Inicie una búsqueda para encontrar carátulas" -#: src/ui/search_panel.py:993 +#: src/ui/search_panel.py:997 msgid "Selection" msgstr "Selección" -#: src/ui/search_panel.py:1003 src/ui/search_panel.py:1599 +#: src/ui/search_panel.py:1007 src/ui/search_panel.py:1612 msgid "No selection" msgstr "Sin selección" -#: src/ui/search_panel.py:1078 +#: src/ui/search_panel.py:1082 #, python-brace-format msgid "Mode: MBID Lookup ({mbid}...)" msgstr "Modo: Búsqueda MBID ({mbid}...)" -#: src/ui/search_panel.py:1086 +#: src/ui/search_panel.py:1090 #, python-brace-format msgid "" "MusicBrainz Album ID: {mbid}\n" @@ -2587,11 +2587,11 @@ msgstr "" "La búsqueda usa el identificador único de MusicBrainz.\n" "Este es el método más fiable (coincidencia exacta)." -#: src/ui/search_panel.py:1092 +#: src/ui/search_panel.py:1096 msgid "Mode: Text search" msgstr "Modo: Búsqueda de texto" -#: src/ui/search_panel.py:1098 +#: src/ui/search_panel.py:1102 msgid "" "Search uses artist/album text.\n" "Results depend on text matching." @@ -2599,11 +2599,11 @@ msgstr "" "La búsqueda usa texto de artista/álbum.\n" "Los resultados dependen de la coincidencia de texto." -#: src/ui/search_panel.py:1218 +#: src/ui/search_panel.py:1222 msgid "No audio files available for fingerprinting." msgstr "No hay archivos de audio disponibles para fingerprinting." -#: src/ui/search_panel.py:1283 +#: src/ui/search_panel.py:1287 #, python-brace-format, python-format msgid "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" @@ -2613,16 +2613,16 @@ msgstr "" "\n" "Haga clic en 'Buscar' para encontrar carátulas." -#: src/ui/search_panel.py:1300 +#: src/ui/search_panel.py:1304 #, python-brace-format msgid "AcoustID error: {error}" msgstr "Error AcoustID: {error}" -#: src/ui/search_panel.py:1305 +#: src/ui/search_panel.py:1309 msgid "Identification error" msgstr "Error de identificación" -#: src/ui/search_panel.py:1306 +#: src/ui/search_panel.py:1310 #, python-brace-format msgid "" "Could not identify via AcoustID:\n" @@ -2631,17 +2631,17 @@ msgstr "" "No se pudo identificar mediante AcoustID:\n" "{error}" -#: src/ui/search_panel.py:1312 +#: src/ui/search_panel.py:1316 #, python-brace-format msgid "Analyzing track {current}/{total}: {name}" msgstr "Analizando pista {current}/{total}: {name}" -#: src/ui/search_panel.py:1327 +#: src/ui/search_panel.py:1331 #, python-brace-format msgid "No fingerprint matches found ({analyzed} tracks analyzed)." msgstr "No se encontraron coincidencias ({analyzed} pistas analizadas)." -#: src/ui/search_panel.py:1376 +#: src/ui/search_panel.py:1380 #, python-brace-format msgid "" "Selected: {artist} - {title} ({votes} tracks matched).\n" @@ -2650,11 +2650,11 @@ msgstr "" "Seleccionado: {artist} - {title} ({votes} pistas coincidentes).\n" "Haga clic en 'Buscar' para encontrar carátulas." -#: src/ui/search_panel.py:1451 +#: src/ui/search_panel.py:1455 msgid "Scan error" msgstr "Error de escaneo" -#: src/ui/search_panel.py:1452 +#: src/ui/search_panel.py:1456 #, python-brace-format msgid "" "Error scanning additional tracks:\n" @@ -2663,15 +2663,15 @@ msgstr "" "Error al escanear pistas adicionales:\n" "{error}" -#: src/ui/search_panel.py:1483 +#: src/ui/search_panel.py:1487 msgid "No source available" msgstr "Sin fuente disponible" -#: src/ui/search_panel.py:1491 src/ui/widgets/source_selector.py:237 +#: src/ui/search_panel.py:1495 src/ui/widgets/source_selector.py:237 msgid "Configuration required" msgstr "Configuración requerida" -#: src/ui/search_panel.py:1493 +#: src/ui/search_panel.py:1497 #, python-brace-format msgid "" "Provider {name} requires an API key.\n" @@ -2684,53 +2684,53 @@ msgstr "" "Configure la clave API en preferencias\n" "(Menú Editar -> Preferencias)." -#: src/ui/search_panel.py:1520 +#: src/ui/search_panel.py:1524 msgid "Enter at least an artist or album" msgstr "Ingrese al menos un artista o álbum" -#: src/ui/dialogs/batch_download_dialog.py:247 src/ui/search_panel.py:1539 +#: src/ui/dialogs/batch_download_dialog.py:245 src/ui/search_panel.py:1546 #, python-brace-format msgid "MBID lookup on {provider}..." msgstr "Búsqueda MBID en {provider}..." -#: src/ui/search_panel.py:1546 +#: src/ui/search_panel.py:1553 #, python-brace-format msgid "artist='{artist}'" msgstr "artista='{artist}'" -#: src/ui/search_panel.py:1548 +#: src/ui/search_panel.py:1555 #, python-brace-format msgid "album='{album}'" msgstr "álbum='{album}'" -#: src/ui/search_panel.py:1550 +#: src/ui/search_panel.py:1557 #, python-brace-format msgid "year={year}" msgstr "año={year}" -#: src/ui/search_panel.py:1553 +#: src/ui/search_panel.py:1560 #, python-brace-format msgid "Searching on {provider}: {desc}..." msgstr "Buscando en {provider}: {desc}..." -#: src/ui/search_panel.py:1617 +#: src/ui/search_panel.py:1630 #, python-brace-format msgid "No results found on {provider}" msgstr "Ningún resultado encontrado en {provider}" -#: src/ui/search_panel.py:1655 +#: src/ui/search_panel.py:1668 msgid "Connection error. Check your internet connection." msgstr "Error de conexión al servidor. Verifique su conexión a internet." -#: src/ui/search_panel.py:1657 +#: src/ui/search_panel.py:1670 msgid "Invalid or expired API key. Check your credentials in preferences." msgstr "Clave API inválida o expirada. Verifique sus credenciales en preferencias." -#: src/ui/search_panel.py:1659 +#: src/ui/search_panel.py:1672 msgid "Too many requests. Please wait before trying again." msgstr "Demasiadas solicitudes. Por favor espere antes de reintentar." -#: src/ui/search_panel.py:1661 +#: src/ui/search_panel.py:1674 #, python-brace-format msgid "" "API communication error:\n" @@ -2739,25 +2739,25 @@ msgstr "" "Error de comunicación API:\n" "{error}" -#: src/ui/search_panel.py:1667 +#: src/ui/search_panel.py:1680 msgid "Search error" msgstr "Error de búsqueda" -#: src/ui/search_panel.py:1768 +#: src/ui/search_panel.py:1781 #, python-brace-format msgid "Year: {year} | Score: {score}%" msgstr "Año: {year} | Puntuación: {score}%" -#: src/ui/search_panel.py:1776 +#: src/ui/search_panel.py:1789 #, python-brace-format msgid "Image: {info}" msgstr "Imagen: {info}" -#: src/ui/search_panel.py:1827 +#: src/ui/search_panel.py:1840 msgid "This cover is not available." msgstr "Esta carátula no está disponible." -#: src/ui/search_panel.py:1869 +#: src/ui/search_panel.py:1882 #, python-brace-format msgid "" "Error downloading cover:\n" @@ -2826,7 +2826,7 @@ msgid "Albums to process: {count}" msgstr "Álbumes a procesar: {count}" #: src/ui/dialogs/batch_acoustid_dialog.py:103 -#: src/ui/dialogs/batch_download_dialog.py:134 +#: src/ui/dialogs/batch_download_dialog.py:132 msgid "Operation cancelled by user." msgstr "Operación cancelada por el usuario." @@ -2839,12 +2839,12 @@ msgid "Already has AcoustID" msgstr "Ya tiene AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:120 -#: src/ui/dialogs/batch_download_dialog.py:152 +#: src/ui/dialogs/batch_download_dialog.py:150 msgid "Skipped by user" msgstr "Omitido por el usuario" #: src/ui/dialogs/batch_acoustid_dialog.py:122 -#: src/ui/dialogs/batch_download_dialog.py:154 +#: src/ui/dialogs/batch_download_dialog.py:152 msgid "Skipped" msgstr "Omitido" @@ -2877,7 +2877,7 @@ msgid "No match found in AcoustID" msgstr "No se encontró coincidencia en AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:156 -#: src/ui/dialogs/batch_download_dialog.py:201 +#: src/ui/dialogs/batch_download_dialog.py:199 msgid "No match" msgstr "Sin coincidencia" @@ -2938,7 +2938,7 @@ msgstr "" " y álbum se actualizarán desde los resultados de AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:282 -#: src/ui/dialogs/batch_download_dialog.py:376 +#: src/ui/dialogs/batch_download_dialog.py:374 msgid "Progress" msgstr "Progreso" @@ -2947,12 +2947,12 @@ msgid "Ready to start" msgstr "Listo para empezar" #: src/ui/dialogs/batch_acoustid_dialog.py:299 -#: src/ui/dialogs/batch_download_dialog.py:392 +#: src/ui/dialogs/batch_download_dialog.py:390 msgid "Log" msgstr "Registro" #: src/ui/dialogs/batch_acoustid_dialog.py:312 -#: src/ui/dialogs/batch_download_dialog.py:406 +#: src/ui/dialogs/batch_download_dialog.py:404 msgid "Skip" msgstr "Saltar" @@ -2966,7 +2966,7 @@ msgid "Processing {current}/{total}: {name}" msgstr "Procesando {current}/{total}: {name}" #: src/ui/dialogs/batch_acoustid_dialog.py:387 -#: src/ui/dialogs/batch_download_dialog.py:415 +#: src/ui/dialogs/batch_download_dialog.py:413 #: src/ui/dialogs/cover_zoom_dialog.py:453 #: src/ui/dialogs/statistics_dialog.py:277 src/ui/widgets/toast.py:168 msgid "Close" @@ -2981,117 +2981,117 @@ msgstr "Completado" msgid "{count} albums identified via AcoustID" msgstr "{count} álbumes identificados via AcoustID" -#: src/ui/dialogs/batch_download_dialog.py:115 +#: src/ui/dialogs/batch_download_dialog.py:113 msgid "No cover provider enabled." msgstr "Ningún proveedor de carátulas habilitado." -#: src/ui/dialogs/batch_download_dialog.py:127 +#: src/ui/dialogs/batch_download_dialog.py:125 #, python-brace-format msgid "Enabled providers: {providers}" msgstr "Proveedores habilitados: {providers}" -#: src/ui/dialogs/batch_download_dialog.py:129 +#: src/ui/dialogs/batch_download_dialog.py:127 #, python-brace-format msgid "Minimum score: {score}%" msgstr "Puntuación mínima: {score}%" -#: src/ui/dialogs/batch_download_dialog.py:145 +#: src/ui/dialogs/batch_download_dialog.py:143 msgid "Skipped (already has cover)" msgstr "Saltado (ya tiene carátula)" -#: src/ui/dialogs/batch_download_dialog.py:147 +#: src/ui/dialogs/batch_download_dialog.py:145 msgid "Already has cover" msgstr "Ya tiene carátula" -#: src/ui/dialogs/batch_download_dialog.py:173 +#: src/ui/dialogs/batch_download_dialog.py:171 msgid "Error: invalid save configuration" msgstr "Error: configuración de guardado inválida" -#: src/ui/dialogs/batch_download_dialog.py:182 +#: src/ui/dialogs/batch_download_dialog.py:180 #, python-brace-format msgid "Cover applied ({provider}, score: {score}%)" msgstr "Carátula aplicada ({provider}, puntuación: {score}%)" -#: src/ui/dialogs/batch_download_dialog.py:192 +#: src/ui/dialogs/batch_download_dialog.py:190 #, python-brace-format msgid "Error ({provider}): {error}" msgstr "Error ({provider}): {error}" -#: src/ui/dialogs/batch_download_dialog.py:199 +#: src/ui/dialogs/batch_download_dialog.py:197 msgid "No sufficient result found" msgstr "Ningún resultado suficiente encontrado" -#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:203 msgid "Summary:" msgstr "Resumen:" -#: src/ui/dialogs/batch_download_dialog.py:207 -#: src/ui/dialogs/batch_download_dialog.py:487 +#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:485 #, python-brace-format msgid "Covers downloaded: {count}" msgstr "Carátulas descargadas: {count}" -#: src/ui/dialogs/batch_download_dialog.py:210 +#: src/ui/dialogs/batch_download_dialog.py:208 #, python-brace-format msgid "Skipped (no match): {count}" msgstr "Saltados (sin coincidencia): {count}" -#: src/ui/dialogs/batch_download_dialog.py:214 +#: src/ui/dialogs/batch_download_dialog.py:212 #, python-brace-format msgid "Skipped (already have cover): {count}" msgstr "Saltados (ya tienen carátula): {count}" -#: src/ui/dialogs/batch_download_dialog.py:219 -#: src/ui/dialogs/batch_download_dialog.py:495 +#: src/ui/dialogs/batch_download_dialog.py:217 +#: src/ui/dialogs/batch_download_dialog.py:493 #, python-brace-format msgid "Errors: {count}" msgstr "Errores: {count}" -#: src/ui/dialogs/batch_download_dialog.py:258 +#: src/ui/dialogs/batch_download_dialog.py:256 #, python-brace-format msgid "Text search on {provider}..." msgstr "Búsqueda de texto en {provider}..." -#: src/ui/dialogs/batch_download_dialog.py:369 +#: src/ui/dialogs/batch_download_dialog.py:367 msgid "Automatic cover download" msgstr "Descarga automática de carátulas" -#: src/ui/dialogs/batch_download_dialog.py:379 +#: src/ui/dialogs/batch_download_dialog.py:377 msgid "Preparing..." msgstr "Preparando..." -#: src/ui/dialogs/batch_download_dialog.py:407 +#: src/ui/dialogs/batch_download_dialog.py:405 msgid "Skip to next album" msgstr "Saltar al siguiente álbum" -#: src/ui/dialogs/batch_download_dialog.py:442 +#: src/ui/dialogs/batch_download_dialog.py:440 #, python-brace-format msgid "Album {current}/{total}: {name}" msgstr "Álbum {current}/{total}: {name}" -#: src/ui/dialogs/batch_download_dialog.py:467 +#: src/ui/dialogs/batch_download_dialog.py:465 msgid "Finished" msgstr "Terminado" -#: src/ui/dialogs/batch_download_dialog.py:482 +#: src/ui/dialogs/batch_download_dialog.py:480 msgid "Cancelling..." msgstr "Cancelando..." -#: src/ui/dialogs/batch_download_dialog.py:488 +#: src/ui/dialogs/batch_download_dialog.py:486 #, python-brace-format msgid "Albums skipped (no match): {count}" msgstr "Álbumes saltados (sin coincidencia): {count}" -#: src/ui/dialogs/batch_download_dialog.py:489 +#: src/ui/dialogs/batch_download_dialog.py:487 #, python-brace-format msgid "Albums skipped (already have cover): {count}" msgstr "Álbumes saltados (ya tienen carátula): {count}" -#: src/ui/dialogs/batch_download_dialog.py:530 +#: src/ui/dialogs/batch_download_dialog.py:528 msgid "Cancel download" msgstr "Cancelar descarga" -#: src/ui/dialogs/batch_download_dialog.py:531 +#: src/ui/dialogs/batch_download_dialog.py:529 msgid "A download is in progress. Do you want to cancel it?" msgstr "Una descarga está en curso. ¿Desea cancelarla?" diff --git a/src/i18n/locales/fr/LC_MESSAGES/messages.po b/src/i18n/locales/fr/LC_MESSAGES/messages.po index 3e47160..f3fda1b 100644 --- a/src/i18n/locales/fr/LC_MESSAGES/messages.po +++ b/src/i18n/locales/fr/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: tunecover 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-01 18:16+0100\n" +"POT-Creation-Date: 2026-02-07 16:51+0100\n" "PO-Revision-Date: 2026-01-26 22:35+0100\n" "Last-Translator: TuneCover Team\n" "Language: fr\n" @@ -526,7 +526,7 @@ msgstr "Pas de pochette disponible" msgid "Download error" msgstr "Erreur de téléchargement" -#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:186 +#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:184 msgid "Cover applied" msgstr "Pochette appliquée" @@ -572,10 +572,10 @@ msgstr "Traitement en cours" #: src/ui/album_detail.py:350 src/ui/album_detail.py:619 #: src/ui/dialogs/acoustid_save_dialog.py:181 #: src/ui/dialogs/batch_acoustid_dialog.py:323 -#: src/ui/dialogs/batch_download_dialog.py:411 +#: src/ui/dialogs/batch_download_dialog.py:409 #: src/ui/dialogs/cover_comparison.py:364 src/ui/fingerprint_dialog.py:457 #: src/ui/main_window.py:866 src/ui/main_window.py:1521 -#: src/ui/preferences.py:82 src/ui/search_panel.py:1027 +#: src/ui/preferences.py:82 src/ui/search_panel.py:1031 msgid "Cancel" msgstr "Annuler" @@ -588,16 +588,16 @@ msgid "Information" msgstr "Informations" #: src/ui/album_detail.py:441 src/ui/dialogs/acoustid_save_dialog.py:102 -#: src/ui/search_panel.py:813 +#: src/ui/search_panel.py:817 msgid "Artist:" msgstr "Artiste:" #: src/ui/album_detail.py:444 src/ui/dialogs/acoustid_save_dialog.py:107 -#: src/ui/search_panel.py:821 +#: src/ui/search_panel.py:825 msgid "Album:" msgstr "Album:" -#: src/ui/album_detail.py:447 src/ui/search_panel.py:829 +#: src/ui/album_detail.py:447 src/ui/search_panel.py:833 msgid "Year:" msgstr "Année:" @@ -643,11 +643,11 @@ msgstr "Identifier l'album via empreinte audio" msgid "AcoustID:" msgstr "AcoustID :" -#: src/ui/album_detail.py:512 src/ui/search_panel.py:851 +#: src/ui/album_detail.py:512 src/ui/search_panel.py:855 msgid "ISRC:" msgstr "ISRC :" -#: src/ui/album_detail.py:517 src/ui/search_panel.py:860 +#: src/ui/album_detail.py:517 src/ui/search_panel.py:864 msgid "Barcode:" msgstr "Code-barres :" @@ -818,8 +818,8 @@ msgstr "Pochette enregistrée pour {name} ({actions})" #: src/ui/album_detail.py:1926 src/ui/album_detail.py:2017 #: src/ui/dialogs/batch_acoustid_dialog.py:216 src/ui/main_window.py:1615 #: src/ui/main_window.py:2206 src/ui/preferences.py:680 -#: src/ui/preferences.py:693 src/ui/search_panel.py:1218 -#: src/ui/search_panel.py:1827 src/ui/search_panel.py:1869 +#: src/ui/preferences.py:693 src/ui/search_panel.py:1222 +#: src/ui/search_panel.py:1840 src/ui/search_panel.py:1882 msgid "Error" msgstr "Erreur" @@ -1768,11 +1768,11 @@ msgstr "" msgid "Auto download" msgstr "Téléchargement automatique" -#: src/ui/main_window.py:1941 src/ui/search_panel.py:1206 +#: src/ui/main_window.py:1941 src/ui/search_panel.py:1210 msgid "Fingerprinting unavailable" msgstr "Identification audio indisponible" -#: src/ui/main_window.py:1943 src/ui/search_panel.py:1208 +#: src/ui/main_window.py:1943 src/ui/search_panel.py:1212 msgid "" "Audio fingerprinting requires chromaprint to be installed.\n" "\n" @@ -1882,7 +1882,7 @@ msgid "Cache" msgstr "Cache" #: src/ui/dialogs/cover_comparison.py:368 src/ui/preferences.py:86 -#: src/ui/search_panel.py:1031 +#: src/ui/search_panel.py:1035 msgid "Apply" msgstr "Appliquer" @@ -1918,7 +1918,7 @@ msgstr "Langue de l'application (nécessite redémarrage)" msgid "Language:" msgstr "Langue:" -#: src/ui/preferences.py:125 src/ui/search_panel.py:900 +#: src/ui/preferences.py:125 src/ui/search_panel.py:904 msgid "Search" msgstr "Rechercher" @@ -2461,7 +2461,7 @@ msgstr "" msgid "No matches found in AcoustID database" msgstr "Aucune correspondance trouvée dans la base AcoustID" -#: src/ui/search_panel.py:495 src/ui/search_panel.py:1226 +#: src/ui/search_panel.py:495 src/ui/search_panel.py:1230 msgid "Analyzing audio fingerprints..." msgstr "Analyse des empreintes audio..." @@ -2474,16 +2474,16 @@ msgstr "[Pochette]" msgid "Double-click to zoom" msgstr "Double-clic pour zoomer" -#: src/ui/search_panel.py:745 +#: src/ui/search_panel.py:749 #, python-brace-format msgid "Cover search: {name}" msgstr "Recherche pochette: {name}" -#: src/ui/search_panel.py:789 +#: src/ui/search_panel.py:793 msgid "Force text search" msgstr "Forcer recherche textuelle" -#: src/ui/search_panel.py:792 +#: src/ui/search_panel.py:796 msgid "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." @@ -2491,43 +2491,43 @@ msgstr "" "Ignorer le MBID et effectuer une recherche basée sur le texte.\n" "Utile si le MBID ne donne pas de résultats satisfaisants." -#: src/ui/search_panel.py:808 +#: src/ui/search_panel.py:812 msgid "Search criteria" msgstr "Critères de recherche" -#: src/ui/search_panel.py:816 +#: src/ui/search_panel.py:820 msgid "Artist name" msgstr "Nom de l'artiste" -#: src/ui/search_panel.py:824 +#: src/ui/search_panel.py:828 msgid "Album title" msgstr "Titre de l'album" -#: src/ui/search_panel.py:832 +#: src/ui/search_panel.py:836 msgid "(optional)" msgstr "(optionnel)" -#: src/ui/search_panel.py:838 +#: src/ui/search_panel.py:842 msgid "Title:" msgstr "Titre :" -#: src/ui/search_panel.py:841 +#: src/ui/search_panel.py:845 msgid "Track title" msgstr "Titre de la piste" -#: src/ui/search_panel.py:854 +#: src/ui/search_panel.py:858 msgid "ISRC" msgstr "ISRC" -#: src/ui/search_panel.py:863 +#: src/ui/search_panel.py:867 msgid "UPC/EAN" msgstr "UPC/EAN" -#: src/ui/search_panel.py:876 +#: src/ui/search_panel.py:880 msgid "AcoustID" msgstr "AcoustID" -#: src/ui/search_panel.py:879 +#: src/ui/search_panel.py:883 msgid "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." @@ -2535,7 +2535,7 @@ msgstr "" "Utiliser l'empreinte audio pour identifier ce morceau.\n" "Remplit les champs artiste/album depuis la base AcoustID." -#: src/ui/search_panel.py:893 +#: src/ui/search_panel.py:897 msgid "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." @@ -2543,40 +2543,40 @@ msgstr "" "Identification indisponible.\n" "Installez chromaprint/fpcalc et pyacoustid." -#: src/ui/search_panel.py:896 +#: src/ui/search_panel.py:900 msgid "No audio file available for fingerprinting." msgstr "Aucun fichier audio disponible pour l'identification." -#: src/ui/search_panel.py:947 +#: src/ui/search_panel.py:951 msgid "Results" msgstr "Résultats" -#: src/ui/search_panel.py:962 +#: src/ui/search_panel.py:966 msgid "Stop" msgstr "Arrêter" -#: src/ui/search_panel.py:963 +#: src/ui/search_panel.py:967 msgid "Stop loading thumbnails" msgstr "Arrêter le chargement des miniatures" -#: src/ui/search_panel.py:984 +#: src/ui/search_panel.py:988 msgid "Start a search to find covers" msgstr "Lancez une recherche pour trouver des pochettes" -#: src/ui/search_panel.py:993 +#: src/ui/search_panel.py:997 msgid "Selection" msgstr "Sélection" -#: src/ui/search_panel.py:1003 src/ui/search_panel.py:1599 +#: src/ui/search_panel.py:1007 src/ui/search_panel.py:1612 msgid "No selection" msgstr "Aucune sélection" -#: src/ui/search_panel.py:1078 +#: src/ui/search_panel.py:1082 #, python-brace-format msgid "Mode: MBID Lookup ({mbid}...)" msgstr "Mode: Recherche MBID ({mbid}...)" -#: src/ui/search_panel.py:1086 +#: src/ui/search_panel.py:1090 #, python-brace-format msgid "" "MusicBrainz Album ID: {mbid}\n" @@ -2589,11 +2589,11 @@ msgstr "" "La recherche utilise l'identifiant unique MusicBrainz.\n" "C'est la méthode la plus fiable (correspondance exacte)." -#: src/ui/search_panel.py:1092 +#: src/ui/search_panel.py:1096 msgid "Mode: Text search" msgstr "Mode: Recherche textuelle" -#: src/ui/search_panel.py:1098 +#: src/ui/search_panel.py:1102 msgid "" "Search uses artist/album text.\n" "Results depend on text matching." @@ -2601,11 +2601,11 @@ msgstr "" "La recherche utilise le texte artiste/album.\n" "Les résultats dépendent de la correspondance textuelle." -#: src/ui/search_panel.py:1218 +#: src/ui/search_panel.py:1222 msgid "No audio files available for fingerprinting." msgstr "Aucun fichier audio disponible pour l'identification." -#: src/ui/search_panel.py:1283 +#: src/ui/search_panel.py:1287 #, python-brace-format, python-format msgid "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" @@ -2614,16 +2614,16 @@ msgstr "" "Identifié via AcoustID : {artist} - {title} ({score}%% de confiance).\n" "Cliquez sur 'Rechercher' pour trouver les pochettes." -#: src/ui/search_panel.py:1300 +#: src/ui/search_panel.py:1304 #, python-brace-format msgid "AcoustID error: {error}" msgstr "Erreur AcoustID : {error}" -#: src/ui/search_panel.py:1305 +#: src/ui/search_panel.py:1309 msgid "Identification error" msgstr "Erreur d'identification" -#: src/ui/search_panel.py:1306 +#: src/ui/search_panel.py:1310 #, python-brace-format msgid "" "Could not identify via AcoustID:\n" @@ -2632,17 +2632,17 @@ msgstr "" "Impossible d'identifier via AcoustID :\n" "{error}" -#: src/ui/search_panel.py:1312 +#: src/ui/search_panel.py:1316 #, python-brace-format msgid "Analyzing track {current}/{total}: {name}" msgstr "Analyse de la piste {current}/{total} : {name}" -#: src/ui/search_panel.py:1327 +#: src/ui/search_panel.py:1331 #, python-brace-format msgid "No fingerprint matches found ({analyzed} tracks analyzed)." msgstr "Aucune correspondance trouvée ({analyzed} pistes analysées)." -#: src/ui/search_panel.py:1376 +#: src/ui/search_panel.py:1380 #, python-brace-format msgid "" "Selected: {artist} - {title} ({votes} tracks matched).\n" @@ -2651,11 +2651,11 @@ msgstr "" "Sélectionné : {artist} - {title} ({votes} pistes correspondantes).\n" "Cliquez sur 'Rechercher' pour trouver les pochettes." -#: src/ui/search_panel.py:1451 +#: src/ui/search_panel.py:1455 msgid "Scan error" msgstr "Erreur de scan" -#: src/ui/search_panel.py:1452 +#: src/ui/search_panel.py:1456 #, python-brace-format msgid "" "Error scanning additional tracks:\n" @@ -2664,15 +2664,15 @@ msgstr "" "Erreur lors du scan de pistes supplémentaires :\n" "{error}" -#: src/ui/search_panel.py:1483 +#: src/ui/search_panel.py:1487 msgid "No source available" msgstr "Aucune source disponible" -#: src/ui/search_panel.py:1491 src/ui/widgets/source_selector.py:237 +#: src/ui/search_panel.py:1495 src/ui/widgets/source_selector.py:237 msgid "Configuration required" msgstr "Configuration requise" -#: src/ui/search_panel.py:1493 +#: src/ui/search_panel.py:1497 #, python-brace-format msgid "" "Provider {name} requires an API key.\n" @@ -2685,56 +2685,56 @@ msgstr "" "Veuillez configurer la clé API dans les préférences\n" "(Menu Édition -> Préférences)." -#: src/ui/search_panel.py:1520 +#: src/ui/search_panel.py:1524 msgid "Enter at least an artist or album" msgstr "Entrez au moins un artiste ou un album" -#: src/ui/dialogs/batch_download_dialog.py:247 src/ui/search_panel.py:1539 +#: src/ui/dialogs/batch_download_dialog.py:245 src/ui/search_panel.py:1546 #, python-brace-format msgid "MBID lookup on {provider}..." msgstr "Recherche MBID sur {provider}..." -#: src/ui/search_panel.py:1546 +#: src/ui/search_panel.py:1553 #, python-brace-format msgid "artist='{artist}'" msgstr "artiste='{artist}'" -#: src/ui/search_panel.py:1548 +#: src/ui/search_panel.py:1555 #, python-brace-format msgid "album='{album}'" msgstr "album='{album}'" -#: src/ui/search_panel.py:1550 +#: src/ui/search_panel.py:1557 #, python-brace-format msgid "year={year}" msgstr "année={year}" -#: src/ui/search_panel.py:1553 +#: src/ui/search_panel.py:1560 #, python-brace-format msgid "Searching on {provider}: {desc}..." msgstr "Recherche sur {provider} : {desc}..." -#: src/ui/search_panel.py:1617 +#: src/ui/search_panel.py:1630 #, python-brace-format msgid "No results found on {provider}" msgstr "Aucun résultat trouvé sur {provider}" -#: src/ui/search_panel.py:1655 +#: src/ui/search_panel.py:1668 msgid "Connection error. Check your internet connection." msgstr "Erreur de connexion au serveur. Vérifiez votre connexion internet." -#: src/ui/search_panel.py:1657 +#: src/ui/search_panel.py:1670 msgid "Invalid or expired API key. Check your credentials in preferences." msgstr "" "Clé API invalide ou expirée. Vérifiez vos identifiants dans les " "préférences.Clé API invalide ou expirée. Vérifiez vos identifiants dans " "les préférences." -#: src/ui/search_panel.py:1659 +#: src/ui/search_panel.py:1672 msgid "Too many requests. Please wait before trying again." msgstr "Trop de requêtes. Veuillez patienter avant de réessayer." -#: src/ui/search_panel.py:1661 +#: src/ui/search_panel.py:1674 #, python-brace-format msgid "" "API communication error:\n" @@ -2743,25 +2743,25 @@ msgstr "" "Erreur de communication avec l'API:\n" "{error}" -#: src/ui/search_panel.py:1667 +#: src/ui/search_panel.py:1680 msgid "Search error" msgstr "Erreur de recherche" -#: src/ui/search_panel.py:1768 +#: src/ui/search_panel.py:1781 #, python-brace-format msgid "Year: {year} | Score: {score}%" msgstr "Année: {year} | Score: {score}%" -#: src/ui/search_panel.py:1776 +#: src/ui/search_panel.py:1789 #, python-brace-format msgid "Image: {info}" msgstr "Image: {info}" -#: src/ui/search_panel.py:1827 +#: src/ui/search_panel.py:1840 msgid "This cover is not available." msgstr "Cette pochette n'est pas disponible." -#: src/ui/search_panel.py:1869 +#: src/ui/search_panel.py:1882 #, python-brace-format msgid "" "Error downloading cover:\n" @@ -2830,7 +2830,7 @@ msgid "Albums to process: {count}" msgstr "Albums à traiter : {count}" #: src/ui/dialogs/batch_acoustid_dialog.py:103 -#: src/ui/dialogs/batch_download_dialog.py:134 +#: src/ui/dialogs/batch_download_dialog.py:132 msgid "Operation cancelled by user." msgstr "Opération annulée par l'utilisateur." @@ -2843,12 +2843,12 @@ msgid "Already has AcoustID" msgstr "A déjà un AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:120 -#: src/ui/dialogs/batch_download_dialog.py:152 +#: src/ui/dialogs/batch_download_dialog.py:150 msgid "Skipped by user" msgstr "Ignoré par l'utilisateur" #: src/ui/dialogs/batch_acoustid_dialog.py:122 -#: src/ui/dialogs/batch_download_dialog.py:154 +#: src/ui/dialogs/batch_download_dialog.py:152 msgid "Skipped" msgstr "Ignoré" @@ -2881,7 +2881,7 @@ msgid "No match found in AcoustID" msgstr "Aucune correspondance trouvée dans AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:156 -#: src/ui/dialogs/batch_download_dialog.py:201 +#: src/ui/dialogs/batch_download_dialog.py:199 msgid "No match" msgstr "Aucune correspondance" @@ -2942,7 +2942,7 @@ msgstr "" "depuis les résultats AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:282 -#: src/ui/dialogs/batch_download_dialog.py:376 +#: src/ui/dialogs/batch_download_dialog.py:374 msgid "Progress" msgstr "Progression" @@ -2951,12 +2951,12 @@ msgid "Ready to start" msgstr "Prêt à démarrer" #: src/ui/dialogs/batch_acoustid_dialog.py:299 -#: src/ui/dialogs/batch_download_dialog.py:392 +#: src/ui/dialogs/batch_download_dialog.py:390 msgid "Log" msgstr "Journal" #: src/ui/dialogs/batch_acoustid_dialog.py:312 -#: src/ui/dialogs/batch_download_dialog.py:406 +#: src/ui/dialogs/batch_download_dialog.py:404 msgid "Skip" msgstr "Passer" @@ -2970,7 +2970,7 @@ msgid "Processing {current}/{total}: {name}" msgstr "Traitement {current}/{total} : {name}" #: src/ui/dialogs/batch_acoustid_dialog.py:387 -#: src/ui/dialogs/batch_download_dialog.py:415 +#: src/ui/dialogs/batch_download_dialog.py:413 #: src/ui/dialogs/cover_zoom_dialog.py:453 #: src/ui/dialogs/statistics_dialog.py:277 src/ui/widgets/toast.py:168 msgid "Close" @@ -2985,117 +2985,117 @@ msgstr "Terminé" msgid "{count} albums identified via AcoustID" msgstr "{count} albums identifiés via AcoustID" -#: src/ui/dialogs/batch_download_dialog.py:115 +#: src/ui/dialogs/batch_download_dialog.py:113 msgid "No cover provider enabled." msgstr "Aucun fournisseur de pochettes activé." -#: src/ui/dialogs/batch_download_dialog.py:127 +#: src/ui/dialogs/batch_download_dialog.py:125 #, python-brace-format msgid "Enabled providers: {providers}" msgstr "Fournisseurs activés: {providers}" -#: src/ui/dialogs/batch_download_dialog.py:129 +#: src/ui/dialogs/batch_download_dialog.py:127 #, python-brace-format msgid "Minimum score: {score}%" msgstr "Score minimum: {score}%" -#: src/ui/dialogs/batch_download_dialog.py:145 +#: src/ui/dialogs/batch_download_dialog.py:143 msgid "Skipped (already has cover)" msgstr "Ignoré (a déjà une pochette)" -#: src/ui/dialogs/batch_download_dialog.py:147 +#: src/ui/dialogs/batch_download_dialog.py:145 msgid "Already has cover" msgstr "A déjà une pochette" -#: src/ui/dialogs/batch_download_dialog.py:173 +#: src/ui/dialogs/batch_download_dialog.py:171 msgid "Error: invalid save configuration" msgstr "Erreur: configuration de sauvegarde invalide" -#: src/ui/dialogs/batch_download_dialog.py:182 +#: src/ui/dialogs/batch_download_dialog.py:180 #, python-brace-format msgid "Cover applied ({provider}, score: {score}%)" msgstr "Pochette appliquée ({provider}, score: {score}%)" -#: src/ui/dialogs/batch_download_dialog.py:192 +#: src/ui/dialogs/batch_download_dialog.py:190 #, python-brace-format msgid "Error ({provider}): {error}" msgstr "Erreur ({provider}): {error}" -#: src/ui/dialogs/batch_download_dialog.py:199 +#: src/ui/dialogs/batch_download_dialog.py:197 msgid "No sufficient result found" msgstr "Aucun résultat suffisant trouvé" -#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:203 msgid "Summary:" msgstr "Résumé:" -#: src/ui/dialogs/batch_download_dialog.py:207 -#: src/ui/dialogs/batch_download_dialog.py:487 +#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:485 #, python-brace-format msgid "Covers downloaded: {count}" msgstr "Pochettes téléchargées: {count}" -#: src/ui/dialogs/batch_download_dialog.py:210 +#: src/ui/dialogs/batch_download_dialog.py:208 #, python-brace-format msgid "Skipped (no match): {count}" msgstr "Ignorés (pas de correspondance): {count}" -#: src/ui/dialogs/batch_download_dialog.py:214 +#: src/ui/dialogs/batch_download_dialog.py:212 #, python-brace-format msgid "Skipped (already have cover): {count}" msgstr "Ignorés (ont déjà une pochette): {count}" -#: src/ui/dialogs/batch_download_dialog.py:219 -#: src/ui/dialogs/batch_download_dialog.py:495 +#: src/ui/dialogs/batch_download_dialog.py:217 +#: src/ui/dialogs/batch_download_dialog.py:493 #, python-brace-format msgid "Errors: {count}" msgstr "Erreurs: {count}" -#: src/ui/dialogs/batch_download_dialog.py:258 +#: src/ui/dialogs/batch_download_dialog.py:256 #, python-brace-format msgid "Text search on {provider}..." msgstr "Recherche textuelle sur {provider}..." -#: src/ui/dialogs/batch_download_dialog.py:369 +#: src/ui/dialogs/batch_download_dialog.py:367 msgid "Automatic cover download" msgstr "Téléchargement automatique des pochettes" -#: src/ui/dialogs/batch_download_dialog.py:379 +#: src/ui/dialogs/batch_download_dialog.py:377 msgid "Preparing..." msgstr "Préparation..." -#: src/ui/dialogs/batch_download_dialog.py:407 +#: src/ui/dialogs/batch_download_dialog.py:405 msgid "Skip to next album" msgstr "Passer à l'album suivant" -#: src/ui/dialogs/batch_download_dialog.py:442 +#: src/ui/dialogs/batch_download_dialog.py:440 #, python-brace-format msgid "Album {current}/{total}: {name}" msgstr "Album {current}/{total} : {name}" -#: src/ui/dialogs/batch_download_dialog.py:467 +#: src/ui/dialogs/batch_download_dialog.py:465 msgid "Finished" msgstr "Terminé" -#: src/ui/dialogs/batch_download_dialog.py:482 +#: src/ui/dialogs/batch_download_dialog.py:480 msgid "Cancelling..." msgstr "Annulation..." -#: src/ui/dialogs/batch_download_dialog.py:488 +#: src/ui/dialogs/batch_download_dialog.py:486 #, python-brace-format msgid "Albums skipped (no match): {count}" msgstr "Albums ignorés (pas de correspondance): {count}" -#: src/ui/dialogs/batch_download_dialog.py:489 +#: src/ui/dialogs/batch_download_dialog.py:487 #, python-brace-format msgid "Albums skipped (already have cover): {count}" msgstr "Albums ignorés (ont déjà une pochette): {count}" -#: src/ui/dialogs/batch_download_dialog.py:530 +#: src/ui/dialogs/batch_download_dialog.py:528 msgid "Cancel download" msgstr "Annuler le téléchargement" -#: src/ui/dialogs/batch_download_dialog.py:531 +#: src/ui/dialogs/batch_download_dialog.py:529 msgid "A download is in progress. Do you want to cancel it?" msgstr "Un téléchargement est en cours. Voulez-vous l'annuler?" diff --git a/src/i18n/locales/it/LC_MESSAGES/messages.po b/src/i18n/locales/it/LC_MESSAGES/messages.po index fdf1d9d..3ab0816 100644 --- a/src/i18n/locales/it/LC_MESSAGES/messages.po +++ b/src/i18n/locales/it/LC_MESSAGES/messages.po @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: tunecover 0.0.1\n" "Report-Msgid-Bugs-To: \n" -"POT-Creation-Date: 2026-02-01 18:16+0100\n" +"POT-Creation-Date: 2026-02-07 16:51+0100\n" "PO-Revision-Date: 2026-01-26 22:35+0100\n" "Last-Translator: TuneCover Team\n" "Language: it\n" @@ -531,7 +531,7 @@ msgstr "Nessuna copertina disponibile" msgid "Download error" msgstr "Errore di scaricamento" -#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:186 +#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:184 msgid "Cover applied" msgstr "Copertina applicata" @@ -577,10 +577,10 @@ msgstr "Elaborazione in corso" #: src/ui/album_detail.py:350 src/ui/album_detail.py:619 #: src/ui/dialogs/acoustid_save_dialog.py:181 #: src/ui/dialogs/batch_acoustid_dialog.py:323 -#: src/ui/dialogs/batch_download_dialog.py:411 +#: src/ui/dialogs/batch_download_dialog.py:409 #: src/ui/dialogs/cover_comparison.py:364 src/ui/fingerprint_dialog.py:457 #: src/ui/main_window.py:866 src/ui/main_window.py:1521 -#: src/ui/preferences.py:82 src/ui/search_panel.py:1027 +#: src/ui/preferences.py:82 src/ui/search_panel.py:1031 msgid "Cancel" msgstr "Annulla" @@ -593,16 +593,16 @@ msgid "Information" msgstr "Informazioni" #: src/ui/album_detail.py:441 src/ui/dialogs/acoustid_save_dialog.py:102 -#: src/ui/search_panel.py:813 +#: src/ui/search_panel.py:817 msgid "Artist:" msgstr "Artista:" #: src/ui/album_detail.py:444 src/ui/dialogs/acoustid_save_dialog.py:107 -#: src/ui/search_panel.py:821 +#: src/ui/search_panel.py:825 msgid "Album:" msgstr "Album:" -#: src/ui/album_detail.py:447 src/ui/search_panel.py:829 +#: src/ui/album_detail.py:447 src/ui/search_panel.py:833 msgid "Year:" msgstr "Anno:" @@ -648,11 +648,11 @@ msgstr "Identifica l'album tramite impronta audio" msgid "AcoustID:" msgstr "AcoustID:" -#: src/ui/album_detail.py:512 src/ui/search_panel.py:851 +#: src/ui/album_detail.py:512 src/ui/search_panel.py:855 msgid "ISRC:" msgstr "ISRC:" -#: src/ui/album_detail.py:517 src/ui/search_panel.py:860 +#: src/ui/album_detail.py:517 src/ui/search_panel.py:864 msgid "Barcode:" msgstr "Codice a barre:" @@ -821,8 +821,8 @@ msgstr "Copertina salvata per {name} ({actions})" #: src/ui/album_detail.py:1926 src/ui/album_detail.py:2017 #: src/ui/dialogs/batch_acoustid_dialog.py:216 src/ui/main_window.py:1615 #: src/ui/main_window.py:2206 src/ui/preferences.py:680 -#: src/ui/preferences.py:693 src/ui/search_panel.py:1218 -#: src/ui/search_panel.py:1827 src/ui/search_panel.py:1869 +#: src/ui/preferences.py:693 src/ui/search_panel.py:1222 +#: src/ui/search_panel.py:1840 src/ui/search_panel.py:1882 msgid "Error" msgstr "Errore" @@ -1771,11 +1771,11 @@ msgstr "" msgid "Auto download" msgstr "Scaricamento automatico" -#: src/ui/main_window.py:1941 src/ui/search_panel.py:1206 +#: src/ui/main_window.py:1941 src/ui/search_panel.py:1210 msgid "Fingerprinting unavailable" msgstr "Identificazione audio non disponibile" -#: src/ui/main_window.py:1943 src/ui/search_panel.py:1208 +#: src/ui/main_window.py:1943 src/ui/search_panel.py:1212 msgid "" "Audio fingerprinting requires chromaprint to be installed.\n" "\n" @@ -1885,7 +1885,7 @@ msgid "Cache" msgstr "Cache" #: src/ui/dialogs/cover_comparison.py:368 src/ui/preferences.py:86 -#: src/ui/search_panel.py:1031 +#: src/ui/search_panel.py:1035 msgid "Apply" msgstr "Applica" @@ -1921,7 +1921,7 @@ msgstr "Lingua dell'applicazione (richiede riavvio)" msgid "Language:" msgstr "Lingua:" -#: src/ui/preferences.py:125 src/ui/search_panel.py:900 +#: src/ui/preferences.py:125 src/ui/search_panel.py:904 msgid "Search" msgstr "Cerca" @@ -2459,7 +2459,7 @@ msgstr "Ricerca AcoustID fallita. Controlla la tua chiave API nelle Preferenze." msgid "No matches found in AcoustID database" msgstr "Nessuna corrispondenza trovata nel database AcoustID" -#: src/ui/search_panel.py:495 src/ui/search_panel.py:1226 +#: src/ui/search_panel.py:495 src/ui/search_panel.py:1230 msgid "Analyzing audio fingerprints..." msgstr "Analisi delle impronte audio..." @@ -2472,16 +2472,16 @@ msgstr "[Copertina]" msgid "Double-click to zoom" msgstr "Doppio clic per ingrandire" -#: src/ui/search_panel.py:745 +#: src/ui/search_panel.py:749 #, python-brace-format msgid "Cover search: {name}" msgstr "Ricerca copertina: {name}" -#: src/ui/search_panel.py:789 +#: src/ui/search_panel.py:793 msgid "Force text search" msgstr "Forza ricerca testuale" -#: src/ui/search_panel.py:792 +#: src/ui/search_panel.py:796 msgid "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." @@ -2489,43 +2489,43 @@ msgstr "" "Ignora MBID ed esegui una ricerca testuale.\n" "Utile se MBID non dà risultati soddisfacenti." -#: src/ui/search_panel.py:808 +#: src/ui/search_panel.py:812 msgid "Search criteria" msgstr "Criteri di ricerca" -#: src/ui/search_panel.py:816 +#: src/ui/search_panel.py:820 msgid "Artist name" msgstr "Nome artista" -#: src/ui/search_panel.py:824 +#: src/ui/search_panel.py:828 msgid "Album title" msgstr "Titolo album" -#: src/ui/search_panel.py:832 +#: src/ui/search_panel.py:836 msgid "(optional)" msgstr "(opzionale)" -#: src/ui/search_panel.py:838 +#: src/ui/search_panel.py:842 msgid "Title:" msgstr "Titolo:" -#: src/ui/search_panel.py:841 +#: src/ui/search_panel.py:845 msgid "Track title" msgstr "Titolo della traccia" -#: src/ui/search_panel.py:854 +#: src/ui/search_panel.py:858 msgid "ISRC" msgstr "ISRC" -#: src/ui/search_panel.py:863 +#: src/ui/search_panel.py:867 msgid "UPC/EAN" msgstr "UPC/EAN" -#: src/ui/search_panel.py:876 +#: src/ui/search_panel.py:880 msgid "AcoustID" msgstr "AcoustID" -#: src/ui/search_panel.py:879 +#: src/ui/search_panel.py:883 msgid "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." @@ -2533,7 +2533,7 @@ msgstr "" "Usa il fingerprinting audio per identificare questa traccia.\n" "Compila i campi artista/album dal database AcoustID." -#: src/ui/search_panel.py:893 +#: src/ui/search_panel.py:897 msgid "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." @@ -2541,40 +2541,40 @@ msgstr "" "Fingerprinting non disponibile.\n" "Installa chromaprint/fpcalc e pyacoustid." -#: src/ui/search_panel.py:896 +#: src/ui/search_panel.py:900 msgid "No audio file available for fingerprinting." msgstr "Nessun file audio disponibile per il fingerprinting." -#: src/ui/search_panel.py:947 +#: src/ui/search_panel.py:951 msgid "Results" msgstr "Risultati" -#: src/ui/search_panel.py:962 +#: src/ui/search_panel.py:966 msgid "Stop" msgstr "Ferma" -#: src/ui/search_panel.py:963 +#: src/ui/search_panel.py:967 msgid "Stop loading thumbnails" msgstr "Ferma il caricamento delle miniature" -#: src/ui/search_panel.py:984 +#: src/ui/search_panel.py:988 msgid "Start a search to find covers" msgstr "Avvia una ricerca per trovare copertine" -#: src/ui/search_panel.py:993 +#: src/ui/search_panel.py:997 msgid "Selection" msgstr "Selezione" -#: src/ui/search_panel.py:1003 src/ui/search_panel.py:1599 +#: src/ui/search_panel.py:1007 src/ui/search_panel.py:1612 msgid "No selection" msgstr "Nessuna selezione" -#: src/ui/search_panel.py:1078 +#: src/ui/search_panel.py:1082 #, python-brace-format msgid "Mode: MBID Lookup ({mbid}...)" msgstr "Modalità: Ricerca MBID ({mbid}...)" -#: src/ui/search_panel.py:1086 +#: src/ui/search_panel.py:1090 #, python-brace-format msgid "" "MusicBrainz Album ID: {mbid}\n" @@ -2587,11 +2587,11 @@ msgstr "" "La ricerca usa l'identificatore unico MusicBrainz.\n" "Questo è il metodo più affidabile (corrispondenza esatta)." -#: src/ui/search_panel.py:1092 +#: src/ui/search_panel.py:1096 msgid "Mode: Text search" msgstr "Modalità: Ricerca testuale" -#: src/ui/search_panel.py:1098 +#: src/ui/search_panel.py:1102 msgid "" "Search uses artist/album text.\n" "Results depend on text matching." @@ -2599,11 +2599,11 @@ msgstr "" "La ricerca usa il testo artista/album.\n" "I risultati dipendono dalla corrispondenza testuale." -#: src/ui/search_panel.py:1218 +#: src/ui/search_panel.py:1222 msgid "No audio files available for fingerprinting." msgstr "Nessun file audio disponibile per il fingerprinting." -#: src/ui/search_panel.py:1283 +#: src/ui/search_panel.py:1287 #, python-brace-format, python-format msgid "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" @@ -2613,16 +2613,16 @@ msgstr "" "\n" "Clicca 'Cerca' per trovare le copertine." -#: src/ui/search_panel.py:1300 +#: src/ui/search_panel.py:1304 #, python-brace-format msgid "AcoustID error: {error}" msgstr "Errore AcoustID: {error}" -#: src/ui/search_panel.py:1305 +#: src/ui/search_panel.py:1309 msgid "Identification error" msgstr "Errore di identificazione" -#: src/ui/search_panel.py:1306 +#: src/ui/search_panel.py:1310 #, python-brace-format msgid "" "Could not identify via AcoustID:\n" @@ -2631,17 +2631,17 @@ msgstr "" "Impossibile identificare tramite AcoustID:\n" "{error}" -#: src/ui/search_panel.py:1312 +#: src/ui/search_panel.py:1316 #, python-brace-format msgid "Analyzing track {current}/{total}: {name}" msgstr "Analisi traccia {current}/{total}: {name}" -#: src/ui/search_panel.py:1327 +#: src/ui/search_panel.py:1331 #, python-brace-format msgid "No fingerprint matches found ({analyzed} tracks analyzed)." msgstr "Nessuna corrispondenza trovata ({analyzed} tracce analizzate)." -#: src/ui/search_panel.py:1376 +#: src/ui/search_panel.py:1380 #, python-brace-format msgid "" "Selected: {artist} - {title} ({votes} tracks matched).\n" @@ -2650,11 +2650,11 @@ msgstr "" "Selezionato: {artist} - {title} ({votes} tracce corrispondenti).\n" "Clicca 'Cerca' per trovare le copertine." -#: src/ui/search_panel.py:1451 +#: src/ui/search_panel.py:1455 msgid "Scan error" msgstr "Errore di scansione" -#: src/ui/search_panel.py:1452 +#: src/ui/search_panel.py:1456 #, python-brace-format msgid "" "Error scanning additional tracks:\n" @@ -2663,15 +2663,15 @@ msgstr "" "Errore nella scansione di tracce aggiuntive:\n" "{error}" -#: src/ui/search_panel.py:1483 +#: src/ui/search_panel.py:1487 msgid "No source available" msgstr "Nessuna fonte disponibile" -#: src/ui/search_panel.py:1491 src/ui/widgets/source_selector.py:237 +#: src/ui/search_panel.py:1495 src/ui/widgets/source_selector.py:237 msgid "Configuration required" msgstr "Configurazione richiesta" -#: src/ui/search_panel.py:1493 +#: src/ui/search_panel.py:1497 #, python-brace-format msgid "" "Provider {name} requires an API key.\n" @@ -2684,56 +2684,56 @@ msgstr "" "Configura la chiave API nelle preferenze\n" "(Menu Modifica -> Preferenze)." -#: src/ui/search_panel.py:1520 +#: src/ui/search_panel.py:1524 msgid "Enter at least an artist or album" msgstr "Inserisci almeno un artista o album" -#: src/ui/dialogs/batch_download_dialog.py:247 src/ui/search_panel.py:1539 +#: src/ui/dialogs/batch_download_dialog.py:245 src/ui/search_panel.py:1546 #, python-brace-format msgid "MBID lookup on {provider}..." msgstr "Ricerca MBID su {provider}..." -#: src/ui/search_panel.py:1546 +#: src/ui/search_panel.py:1553 #, python-brace-format msgid "artist='{artist}'" msgstr "artista='{artist}'" -#: src/ui/search_panel.py:1548 +#: src/ui/search_panel.py:1555 #, python-brace-format msgid "album='{album}'" msgstr "album='{album}'" -#: src/ui/search_panel.py:1550 +#: src/ui/search_panel.py:1557 #, python-brace-format msgid "year={year}" msgstr "anno={year}" -#: src/ui/search_panel.py:1553 +#: src/ui/search_panel.py:1560 #, python-brace-format msgid "Searching on {provider}: {desc}..." msgstr "Ricerca su {provider}: {desc}..." -#: src/ui/search_panel.py:1617 +#: src/ui/search_panel.py:1630 #, python-brace-format msgid "No results found on {provider}" msgstr "Nessun risultato trovato su {provider}" -#: src/ui/search_panel.py:1655 +#: src/ui/search_panel.py:1668 msgid "Connection error. Check your internet connection." msgstr "Errore di connessione al server. Controlla la tua connessione internet." -#: src/ui/search_panel.py:1657 +#: src/ui/search_panel.py:1670 msgid "Invalid or expired API key. Check your credentials in preferences." msgstr "" "Chiave API non valida o scaduta. Controlla le tue credenziali nelle " "preferenze.Chiave API non valida o scaduta. Controlla le tue credenziali " "nelle preferenze." -#: src/ui/search_panel.py:1659 +#: src/ui/search_panel.py:1672 msgid "Too many requests. Please wait before trying again." msgstr "Troppe richieste. Attendi prima di riprovare." -#: src/ui/search_panel.py:1661 +#: src/ui/search_panel.py:1674 #, python-brace-format msgid "" "API communication error:\n" @@ -2742,25 +2742,25 @@ msgstr "" "Errore di comunicazione API:\n" "{error}" -#: src/ui/search_panel.py:1667 +#: src/ui/search_panel.py:1680 msgid "Search error" msgstr "Errore di ricerca" -#: src/ui/search_panel.py:1768 +#: src/ui/search_panel.py:1781 #, python-brace-format msgid "Year: {year} | Score: {score}%" msgstr "Anno: {year} | Punteggio: {score}%" -#: src/ui/search_panel.py:1776 +#: src/ui/search_panel.py:1789 #, python-brace-format msgid "Image: {info}" msgstr "Immagine: {info}" -#: src/ui/search_panel.py:1827 +#: src/ui/search_panel.py:1840 msgid "This cover is not available." msgstr "Questa copertina non è disponibile." -#: src/ui/search_panel.py:1869 +#: src/ui/search_panel.py:1882 #, python-brace-format msgid "" "Error downloading cover:\n" @@ -2829,7 +2829,7 @@ msgid "Albums to process: {count}" msgstr "Album da elaborare: {count}" #: src/ui/dialogs/batch_acoustid_dialog.py:103 -#: src/ui/dialogs/batch_download_dialog.py:134 +#: src/ui/dialogs/batch_download_dialog.py:132 msgid "Operation cancelled by user." msgstr "Operazione annullata dall'utente." @@ -2842,12 +2842,12 @@ msgid "Already has AcoustID" msgstr "Ha già AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:120 -#: src/ui/dialogs/batch_download_dialog.py:152 +#: src/ui/dialogs/batch_download_dialog.py:150 msgid "Skipped by user" msgstr "Saltato dall'utente" #: src/ui/dialogs/batch_acoustid_dialog.py:122 -#: src/ui/dialogs/batch_download_dialog.py:154 +#: src/ui/dialogs/batch_download_dialog.py:152 msgid "Skipped" msgstr "Saltato" @@ -2880,7 +2880,7 @@ msgid "No match found in AcoustID" msgstr "Nessuna corrispondenza trovata in AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:156 -#: src/ui/dialogs/batch_download_dialog.py:201 +#: src/ui/dialogs/batch_download_dialog.py:199 msgid "No match" msgstr "Nessuna corrispondenza" @@ -2941,7 +2941,7 @@ msgstr "" "risultati AcoustID" #: src/ui/dialogs/batch_acoustid_dialog.py:282 -#: src/ui/dialogs/batch_download_dialog.py:376 +#: src/ui/dialogs/batch_download_dialog.py:374 msgid "Progress" msgstr "Progresso" @@ -2950,12 +2950,12 @@ msgid "Ready to start" msgstr "Pronto per iniziare" #: src/ui/dialogs/batch_acoustid_dialog.py:299 -#: src/ui/dialogs/batch_download_dialog.py:392 +#: src/ui/dialogs/batch_download_dialog.py:390 msgid "Log" msgstr "Log" #: src/ui/dialogs/batch_acoustid_dialog.py:312 -#: src/ui/dialogs/batch_download_dialog.py:406 +#: src/ui/dialogs/batch_download_dialog.py:404 msgid "Skip" msgstr "Salta" @@ -2969,7 +2969,7 @@ msgid "Processing {current}/{total}: {name}" msgstr "Elaborazione {current}/{total}: {name}" #: src/ui/dialogs/batch_acoustid_dialog.py:387 -#: src/ui/dialogs/batch_download_dialog.py:415 +#: src/ui/dialogs/batch_download_dialog.py:413 #: src/ui/dialogs/cover_zoom_dialog.py:453 #: src/ui/dialogs/statistics_dialog.py:277 src/ui/widgets/toast.py:168 msgid "Close" @@ -2984,117 +2984,117 @@ msgstr "Completato" msgid "{count} albums identified via AcoustID" msgstr "{count} album identificati via AcoustID" -#: src/ui/dialogs/batch_download_dialog.py:115 +#: src/ui/dialogs/batch_download_dialog.py:113 msgid "No cover provider enabled." msgstr "Nessun fornitore di copertine abilitato." -#: src/ui/dialogs/batch_download_dialog.py:127 +#: src/ui/dialogs/batch_download_dialog.py:125 #, python-brace-format msgid "Enabled providers: {providers}" msgstr "Fornitori abilitati: {providers}" -#: src/ui/dialogs/batch_download_dialog.py:129 +#: src/ui/dialogs/batch_download_dialog.py:127 #, python-brace-format msgid "Minimum score: {score}%" msgstr "Punteggio minimo: {score}%" -#: src/ui/dialogs/batch_download_dialog.py:145 +#: src/ui/dialogs/batch_download_dialog.py:143 msgid "Skipped (already has cover)" msgstr "Saltato (ha già una copertina)" -#: src/ui/dialogs/batch_download_dialog.py:147 +#: src/ui/dialogs/batch_download_dialog.py:145 msgid "Already has cover" msgstr "Ha già una copertina" -#: src/ui/dialogs/batch_download_dialog.py:173 +#: src/ui/dialogs/batch_download_dialog.py:171 msgid "Error: invalid save configuration" msgstr "Errore: configurazione di salvataggio non valida" -#: src/ui/dialogs/batch_download_dialog.py:182 +#: src/ui/dialogs/batch_download_dialog.py:180 #, python-brace-format msgid "Cover applied ({provider}, score: {score}%)" msgstr "Copertina applicata ({provider}, punteggio: {score}%)" -#: src/ui/dialogs/batch_download_dialog.py:192 +#: src/ui/dialogs/batch_download_dialog.py:190 #, python-brace-format msgid "Error ({provider}): {error}" msgstr "Errore ({provider}): {error}" -#: src/ui/dialogs/batch_download_dialog.py:199 +#: src/ui/dialogs/batch_download_dialog.py:197 msgid "No sufficient result found" msgstr "Nessun risultato sufficiente trovato" -#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:203 msgid "Summary:" msgstr "Riepilogo:" -#: src/ui/dialogs/batch_download_dialog.py:207 -#: src/ui/dialogs/batch_download_dialog.py:487 +#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:485 #, python-brace-format msgid "Covers downloaded: {count}" msgstr "Copertine scaricate: {count}" -#: src/ui/dialogs/batch_download_dialog.py:210 +#: src/ui/dialogs/batch_download_dialog.py:208 #, python-brace-format msgid "Skipped (no match): {count}" msgstr "Saltati (nessuna corrispondenza): {count}" -#: src/ui/dialogs/batch_download_dialog.py:214 +#: src/ui/dialogs/batch_download_dialog.py:212 #, python-brace-format msgid "Skipped (already have cover): {count}" msgstr "Saltati (hanno già copertina): {count}" -#: src/ui/dialogs/batch_download_dialog.py:219 -#: src/ui/dialogs/batch_download_dialog.py:495 +#: src/ui/dialogs/batch_download_dialog.py:217 +#: src/ui/dialogs/batch_download_dialog.py:493 #, python-brace-format msgid "Errors: {count}" msgstr "Errori: {count}" -#: src/ui/dialogs/batch_download_dialog.py:258 +#: src/ui/dialogs/batch_download_dialog.py:256 #, python-brace-format msgid "Text search on {provider}..." msgstr "Ricerca testuale su {provider}..." -#: src/ui/dialogs/batch_download_dialog.py:369 +#: src/ui/dialogs/batch_download_dialog.py:367 msgid "Automatic cover download" msgstr "Scaricamento automatico copertine" -#: src/ui/dialogs/batch_download_dialog.py:379 +#: src/ui/dialogs/batch_download_dialog.py:377 msgid "Preparing..." msgstr "Preparazione..." -#: src/ui/dialogs/batch_download_dialog.py:407 +#: src/ui/dialogs/batch_download_dialog.py:405 msgid "Skip to next album" msgstr "Passa al prossimo album" -#: src/ui/dialogs/batch_download_dialog.py:442 +#: src/ui/dialogs/batch_download_dialog.py:440 #, python-brace-format msgid "Album {current}/{total}: {name}" msgstr "Album {current}/{total}: {name}" -#: src/ui/dialogs/batch_download_dialog.py:467 +#: src/ui/dialogs/batch_download_dialog.py:465 msgid "Finished" msgstr "Completato" -#: src/ui/dialogs/batch_download_dialog.py:482 +#: src/ui/dialogs/batch_download_dialog.py:480 msgid "Cancelling..." msgstr "Annullamento..." -#: src/ui/dialogs/batch_download_dialog.py:488 +#: src/ui/dialogs/batch_download_dialog.py:486 #, python-brace-format msgid "Albums skipped (no match): {count}" msgstr "Album saltati (nessuna corrispondenza): {count}" -#: src/ui/dialogs/batch_download_dialog.py:489 +#: src/ui/dialogs/batch_download_dialog.py:487 #, python-brace-format msgid "Albums skipped (already have cover): {count}" msgstr "Album saltati (hanno già copertina): {count}" -#: src/ui/dialogs/batch_download_dialog.py:530 +#: src/ui/dialogs/batch_download_dialog.py:528 msgid "Cancel download" msgstr "Annulla scaricamento" -#: src/ui/dialogs/batch_download_dialog.py:531 +#: src/ui/dialogs/batch_download_dialog.py:529 msgid "A download is in progress. Do you want to cancel it?" msgstr "Uno scaricamento è in corso. Vuoi annullarlo?" diff --git a/src/i18n/locales/messages.pot b/src/i18n/locales/messages.pot index b987614..1dff7e4 100644 --- a/src/i18n/locales/messages.pot +++ b/src/i18n/locales/messages.pot @@ -6,9 +6,9 @@ #, fuzzy msgid "" msgstr "" -"Project-Id-Version: tunecover 0.0.1\n" +"Project-Id-Version: tunecover 0.1.1\n" "Report-Msgid-Bugs-To: EMAIL@ADDRESS\n" -"POT-Creation-Date: 2026-02-01 18:16+0100\n" +"POT-Creation-Date: 2026-02-07 16:51+0100\n" "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n" "Last-Translator: FULL NAME \n" "Language-Team: LANGUAGE \n" @@ -505,7 +505,7 @@ msgstr "" msgid "Download error" msgstr "" -#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:186 +#: src/ui/album_detail.py:212 src/ui/dialogs/batch_download_dialog.py:184 msgid "Cover applied" msgstr "" @@ -551,10 +551,10 @@ msgstr "" #: src/ui/album_detail.py:350 src/ui/album_detail.py:619 #: src/ui/dialogs/acoustid_save_dialog.py:181 #: src/ui/dialogs/batch_acoustid_dialog.py:323 -#: src/ui/dialogs/batch_download_dialog.py:411 +#: src/ui/dialogs/batch_download_dialog.py:409 #: src/ui/dialogs/cover_comparison.py:364 src/ui/fingerprint_dialog.py:457 #: src/ui/main_window.py:866 src/ui/main_window.py:1521 -#: src/ui/preferences.py:82 src/ui/search_panel.py:1027 +#: src/ui/preferences.py:82 src/ui/search_panel.py:1031 msgid "Cancel" msgstr "" @@ -567,16 +567,16 @@ msgid "Information" msgstr "" #: src/ui/album_detail.py:441 src/ui/dialogs/acoustid_save_dialog.py:102 -#: src/ui/search_panel.py:813 +#: src/ui/search_panel.py:817 msgid "Artist:" msgstr "" #: src/ui/album_detail.py:444 src/ui/dialogs/acoustid_save_dialog.py:107 -#: src/ui/search_panel.py:821 +#: src/ui/search_panel.py:825 msgid "Album:" msgstr "" -#: src/ui/album_detail.py:447 src/ui/search_panel.py:829 +#: src/ui/album_detail.py:447 src/ui/search_panel.py:833 msgid "Year:" msgstr "" @@ -622,11 +622,11 @@ msgstr "" msgid "AcoustID:" msgstr "" -#: src/ui/album_detail.py:512 src/ui/search_panel.py:851 +#: src/ui/album_detail.py:512 src/ui/search_panel.py:855 msgid "ISRC:" msgstr "" -#: src/ui/album_detail.py:517 src/ui/search_panel.py:860 +#: src/ui/album_detail.py:517 src/ui/search_panel.py:864 msgid "Barcode:" msgstr "" @@ -793,8 +793,8 @@ msgstr "" #: src/ui/album_detail.py:1926 src/ui/album_detail.py:2017 #: src/ui/dialogs/batch_acoustid_dialog.py:216 src/ui/main_window.py:1615 #: src/ui/main_window.py:2206 src/ui/preferences.py:680 -#: src/ui/preferences.py:693 src/ui/search_panel.py:1218 -#: src/ui/search_panel.py:1827 src/ui/search_panel.py:1869 +#: src/ui/preferences.py:693 src/ui/search_panel.py:1222 +#: src/ui/search_panel.py:1840 src/ui/search_panel.py:1882 msgid "Error" msgstr "" @@ -1683,11 +1683,11 @@ msgstr "" msgid "Auto download" msgstr "" -#: src/ui/main_window.py:1941 src/ui/search_panel.py:1206 +#: src/ui/main_window.py:1941 src/ui/search_panel.py:1210 msgid "Fingerprinting unavailable" msgstr "" -#: src/ui/main_window.py:1943 src/ui/search_panel.py:1208 +#: src/ui/main_window.py:1943 src/ui/search_panel.py:1212 msgid "" "Audio fingerprinting requires chromaprint to be installed.\n" "\n" @@ -1774,7 +1774,7 @@ msgid "Cache" msgstr "" #: src/ui/dialogs/cover_comparison.py:368 src/ui/preferences.py:86 -#: src/ui/search_panel.py:1031 +#: src/ui/search_panel.py:1035 msgid "Apply" msgstr "" @@ -1810,7 +1810,7 @@ msgstr "" msgid "Language:" msgstr "" -#: src/ui/preferences.py:125 src/ui/search_panel.py:900 +#: src/ui/preferences.py:125 src/ui/search_panel.py:904 msgid "Search" msgstr "" @@ -2308,7 +2308,7 @@ msgstr "" msgid "No matches found in AcoustID database" msgstr "" -#: src/ui/search_panel.py:495 src/ui/search_panel.py:1226 +#: src/ui/search_panel.py:495 src/ui/search_panel.py:1230 msgid "Analyzing audio fingerprints..." msgstr "" @@ -2321,103 +2321,103 @@ msgstr "" msgid "Double-click to zoom" msgstr "" -#: src/ui/search_panel.py:745 +#: src/ui/search_panel.py:749 #, python-brace-format msgid "Cover search: {name}" msgstr "" -#: src/ui/search_panel.py:789 +#: src/ui/search_panel.py:793 msgid "Force text search" msgstr "" -#: src/ui/search_panel.py:792 +#: src/ui/search_panel.py:796 msgid "" "Ignore MBID and perform text-based search.\n" "Useful if MBID doesn't give satisfactory results." msgstr "" -#: src/ui/search_panel.py:808 +#: src/ui/search_panel.py:812 msgid "Search criteria" msgstr "" -#: src/ui/search_panel.py:816 +#: src/ui/search_panel.py:820 msgid "Artist name" msgstr "" -#: src/ui/search_panel.py:824 +#: src/ui/search_panel.py:828 msgid "Album title" msgstr "" -#: src/ui/search_panel.py:832 +#: src/ui/search_panel.py:836 msgid "(optional)" msgstr "" -#: src/ui/search_panel.py:838 +#: src/ui/search_panel.py:842 msgid "Title:" msgstr "" -#: src/ui/search_panel.py:841 +#: src/ui/search_panel.py:845 msgid "Track title" msgstr "" -#: src/ui/search_panel.py:854 +#: src/ui/search_panel.py:858 msgid "ISRC" msgstr "" -#: src/ui/search_panel.py:863 +#: src/ui/search_panel.py:867 msgid "UPC/EAN" msgstr "" -#: src/ui/search_panel.py:876 +#: src/ui/search_panel.py:880 msgid "AcoustID" msgstr "" -#: src/ui/search_panel.py:879 +#: src/ui/search_panel.py:883 msgid "" "Use audio fingerprinting to identify this track.\n" "Fills in artist/album fields from AcoustID database." msgstr "" -#: src/ui/search_panel.py:893 +#: src/ui/search_panel.py:897 msgid "" "Fingerprinting unavailable.\n" "Install chromaprint/fpcalc and pyacoustid." msgstr "" -#: src/ui/search_panel.py:896 +#: src/ui/search_panel.py:900 msgid "No audio file available for fingerprinting." msgstr "" -#: src/ui/search_panel.py:947 +#: src/ui/search_panel.py:951 msgid "Results" msgstr "" -#: src/ui/search_panel.py:962 +#: src/ui/search_panel.py:966 msgid "Stop" msgstr "" -#: src/ui/search_panel.py:963 +#: src/ui/search_panel.py:967 msgid "Stop loading thumbnails" msgstr "" -#: src/ui/search_panel.py:984 +#: src/ui/search_panel.py:988 msgid "Start a search to find covers" msgstr "" -#: src/ui/search_panel.py:993 +#: src/ui/search_panel.py:997 msgid "Selection" msgstr "" -#: src/ui/search_panel.py:1003 src/ui/search_panel.py:1599 +#: src/ui/search_panel.py:1007 src/ui/search_panel.py:1612 msgid "No selection" msgstr "" -#: src/ui/search_panel.py:1078 +#: src/ui/search_panel.py:1082 #, python-brace-format msgid "Mode: MBID Lookup ({mbid}...)" msgstr "" -#: src/ui/search_panel.py:1086 +#: src/ui/search_panel.py:1090 #, python-brace-format msgid "" "MusicBrainz Album ID: {mbid}\n" @@ -2426,80 +2426,80 @@ msgid "" "This is the most reliable method (exact match)." msgstr "" -#: src/ui/search_panel.py:1092 +#: src/ui/search_panel.py:1096 msgid "Mode: Text search" msgstr "" -#: src/ui/search_panel.py:1098 +#: src/ui/search_panel.py:1102 msgid "" "Search uses artist/album text.\n" "Results depend on text matching." msgstr "" -#: src/ui/search_panel.py:1218 +#: src/ui/search_panel.py:1222 msgid "No audio files available for fingerprinting." msgstr "" -#: src/ui/search_panel.py:1283 +#: src/ui/search_panel.py:1287 #, python-brace-format, python-format msgid "" "Identified via AcoustID: {artist} - {title} ({score}%% confidence).\n" "Click 'Search' to find covers." msgstr "" -#: src/ui/search_panel.py:1300 +#: src/ui/search_panel.py:1304 #, python-brace-format msgid "AcoustID error: {error}" msgstr "" -#: src/ui/search_panel.py:1305 +#: src/ui/search_panel.py:1309 msgid "Identification error" msgstr "" -#: src/ui/search_panel.py:1306 +#: src/ui/search_panel.py:1310 #, python-brace-format msgid "" "Could not identify via AcoustID:\n" "{error}" msgstr "" -#: src/ui/search_panel.py:1312 +#: src/ui/search_panel.py:1316 #, python-brace-format msgid "Analyzing track {current}/{total}: {name}" msgstr "" -#: src/ui/search_panel.py:1327 +#: src/ui/search_panel.py:1331 #, python-brace-format msgid "No fingerprint matches found ({analyzed} tracks analyzed)." msgstr "" -#: src/ui/search_panel.py:1376 +#: src/ui/search_panel.py:1380 #, python-brace-format msgid "" "Selected: {artist} - {title} ({votes} tracks matched).\n" "Click 'Search' to find covers." msgstr "" -#: src/ui/search_panel.py:1451 +#: src/ui/search_panel.py:1455 msgid "Scan error" msgstr "" -#: src/ui/search_panel.py:1452 +#: src/ui/search_panel.py:1456 #, python-brace-format msgid "" "Error scanning additional tracks:\n" "{error}" msgstr "" -#: src/ui/search_panel.py:1483 +#: src/ui/search_panel.py:1487 msgid "No source available" msgstr "" -#: src/ui/search_panel.py:1491 src/ui/widgets/source_selector.py:237 +#: src/ui/search_panel.py:1495 src/ui/widgets/source_selector.py:237 msgid "Configuration required" msgstr "" -#: src/ui/search_panel.py:1493 +#: src/ui/search_panel.py:1497 #, python-brace-format msgid "" "Provider {name} requires an API key.\n" @@ -2508,78 +2508,78 @@ msgid "" "(Menu Edit -> Preferences)." msgstr "" -#: src/ui/search_panel.py:1520 +#: src/ui/search_panel.py:1524 msgid "Enter at least an artist or album" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:247 src/ui/search_panel.py:1539 +#: src/ui/dialogs/batch_download_dialog.py:245 src/ui/search_panel.py:1546 #, python-brace-format msgid "MBID lookup on {provider}..." msgstr "" -#: src/ui/search_panel.py:1546 +#: src/ui/search_panel.py:1553 #, python-brace-format msgid "artist='{artist}'" msgstr "" -#: src/ui/search_panel.py:1548 +#: src/ui/search_panel.py:1555 #, python-brace-format msgid "album='{album}'" msgstr "" -#: src/ui/search_panel.py:1550 +#: src/ui/search_panel.py:1557 #, python-brace-format msgid "year={year}" msgstr "" -#: src/ui/search_panel.py:1553 +#: src/ui/search_panel.py:1560 #, python-brace-format msgid "Searching on {provider}: {desc}..." msgstr "" -#: src/ui/search_panel.py:1617 +#: src/ui/search_panel.py:1630 #, python-brace-format msgid "No results found on {provider}" msgstr "" -#: src/ui/search_panel.py:1655 +#: src/ui/search_panel.py:1668 msgid "Connection error. Check your internet connection." msgstr "" -#: src/ui/search_panel.py:1657 +#: src/ui/search_panel.py:1670 msgid "Invalid or expired API key. Check your credentials in preferences." msgstr "" -#: src/ui/search_panel.py:1659 +#: src/ui/search_panel.py:1672 msgid "Too many requests. Please wait before trying again." msgstr "" -#: src/ui/search_panel.py:1661 +#: src/ui/search_panel.py:1674 #, python-brace-format msgid "" "API communication error:\n" "{error}" msgstr "" -#: src/ui/search_panel.py:1667 +#: src/ui/search_panel.py:1680 msgid "Search error" msgstr "" -#: src/ui/search_panel.py:1768 +#: src/ui/search_panel.py:1781 #, python-brace-format msgid "Year: {year} | Score: {score}%" msgstr "" -#: src/ui/search_panel.py:1776 +#: src/ui/search_panel.py:1789 #, python-brace-format msgid "Image: {info}" msgstr "" -#: src/ui/search_panel.py:1827 +#: src/ui/search_panel.py:1840 msgid "This cover is not available." msgstr "" -#: src/ui/search_panel.py:1869 +#: src/ui/search_panel.py:1882 #, python-brace-format msgid "" "Error downloading cover:\n" @@ -2646,7 +2646,7 @@ msgid "Albums to process: {count}" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:103 -#: src/ui/dialogs/batch_download_dialog.py:134 +#: src/ui/dialogs/batch_download_dialog.py:132 msgid "Operation cancelled by user." msgstr "" @@ -2659,12 +2659,12 @@ msgid "Already has AcoustID" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:120 -#: src/ui/dialogs/batch_download_dialog.py:152 +#: src/ui/dialogs/batch_download_dialog.py:150 msgid "Skipped by user" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:122 -#: src/ui/dialogs/batch_download_dialog.py:154 +#: src/ui/dialogs/batch_download_dialog.py:152 msgid "Skipped" msgstr "" @@ -2697,7 +2697,7 @@ msgid "No match found in AcoustID" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:156 -#: src/ui/dialogs/batch_download_dialog.py:201 +#: src/ui/dialogs/batch_download_dialog.py:199 msgid "No match" msgstr "" @@ -2753,7 +2753,7 @@ msgid "If enabled, artist and album tags will be updated from AcoustID results" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:282 -#: src/ui/dialogs/batch_download_dialog.py:376 +#: src/ui/dialogs/batch_download_dialog.py:374 msgid "Progress" msgstr "" @@ -2762,12 +2762,12 @@ msgid "Ready to start" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:299 -#: src/ui/dialogs/batch_download_dialog.py:392 +#: src/ui/dialogs/batch_download_dialog.py:390 msgid "Log" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:312 -#: src/ui/dialogs/batch_download_dialog.py:406 +#: src/ui/dialogs/batch_download_dialog.py:404 msgid "Skip" msgstr "" @@ -2781,7 +2781,7 @@ msgid "Processing {current}/{total}: {name}" msgstr "" #: src/ui/dialogs/batch_acoustid_dialog.py:387 -#: src/ui/dialogs/batch_download_dialog.py:415 +#: src/ui/dialogs/batch_download_dialog.py:413 #: src/ui/dialogs/cover_zoom_dialog.py:453 #: src/ui/dialogs/statistics_dialog.py:277 src/ui/widgets/toast.py:168 msgid "Close" @@ -2796,117 +2796,117 @@ msgstr "" msgid "{count} albums identified via AcoustID" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:115 +#: src/ui/dialogs/batch_download_dialog.py:113 msgid "No cover provider enabled." msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:127 +#: src/ui/dialogs/batch_download_dialog.py:125 #, python-brace-format msgid "Enabled providers: {providers}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:129 +#: src/ui/dialogs/batch_download_dialog.py:127 #, python-brace-format msgid "Minimum score: {score}%" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:145 +#: src/ui/dialogs/batch_download_dialog.py:143 msgid "Skipped (already has cover)" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:147 +#: src/ui/dialogs/batch_download_dialog.py:145 msgid "Already has cover" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:173 +#: src/ui/dialogs/batch_download_dialog.py:171 msgid "Error: invalid save configuration" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:182 +#: src/ui/dialogs/batch_download_dialog.py:180 #, python-brace-format msgid "Cover applied ({provider}, score: {score}%)" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:192 +#: src/ui/dialogs/batch_download_dialog.py:190 #, python-brace-format msgid "Error ({provider}): {error}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:199 +#: src/ui/dialogs/batch_download_dialog.py:197 msgid "No sufficient result found" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:203 msgid "Summary:" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:207 -#: src/ui/dialogs/batch_download_dialog.py:487 +#: src/ui/dialogs/batch_download_dialog.py:205 +#: src/ui/dialogs/batch_download_dialog.py:485 #, python-brace-format msgid "Covers downloaded: {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:210 +#: src/ui/dialogs/batch_download_dialog.py:208 #, python-brace-format msgid "Skipped (no match): {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:214 +#: src/ui/dialogs/batch_download_dialog.py:212 #, python-brace-format msgid "Skipped (already have cover): {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:219 -#: src/ui/dialogs/batch_download_dialog.py:495 +#: src/ui/dialogs/batch_download_dialog.py:217 +#: src/ui/dialogs/batch_download_dialog.py:493 #, python-brace-format msgid "Errors: {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:258 +#: src/ui/dialogs/batch_download_dialog.py:256 #, python-brace-format msgid "Text search on {provider}..." msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:369 +#: src/ui/dialogs/batch_download_dialog.py:367 msgid "Automatic cover download" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:379 +#: src/ui/dialogs/batch_download_dialog.py:377 msgid "Preparing..." msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:407 +#: src/ui/dialogs/batch_download_dialog.py:405 msgid "Skip to next album" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:442 +#: src/ui/dialogs/batch_download_dialog.py:440 #, python-brace-format msgid "Album {current}/{total}: {name}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:467 +#: src/ui/dialogs/batch_download_dialog.py:465 msgid "Finished" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:482 +#: src/ui/dialogs/batch_download_dialog.py:480 msgid "Cancelling..." msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:488 +#: src/ui/dialogs/batch_download_dialog.py:486 #, python-brace-format msgid "Albums skipped (no match): {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:489 +#: src/ui/dialogs/batch_download_dialog.py:487 #, python-brace-format msgid "Albums skipped (already have cover): {count}" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:530 +#: src/ui/dialogs/batch_download_dialog.py:528 msgid "Cancel download" msgstr "" -#: src/ui/dialogs/batch_download_dialog.py:531 +#: src/ui/dialogs/batch_download_dialog.py:529 msgid "A download is in progress. Do you want to cancel it?" msgstr "" diff --git a/tests/test_fingerprint.py b/tests/test_fingerprint.py index e0f6592..2d0a8a5 100644 --- a/tests/test_fingerprint.py +++ b/tests/test_fingerprint.py @@ -9,6 +9,7 @@ from src.core.fingerprint import ( AudioFingerprinter, + _find_fpcalc_binary, _fuzzy_match, calculate_match_score, extract_file_metadata, @@ -18,6 +19,118 @@ ) +class TestFindFpcalcBinary: + """Tests for _find_fpcalc_binary() PyInstaller bundle detection. + + Bug fix: Windows builds shipped without fpcalc.exe, making audio + fingerprinting completely broken. These tests verify that frozen + builds correctly locate the bundled fpcalc binary. + """ + + def test_frozen_windows_finds_fpcalc_exe(self, tmp_path): + """Frozen Windows build finds fpcalc.exe next to sys.executable.""" + exe_dir = tmp_path / "dist" + exe_dir.mkdir() + fpcalc = exe_dir / "fpcalc.exe" + fpcalc.write_bytes(b"fake") + fake_exe = str(exe_dir / "TuneCover.exe") + + with ( + patch("src.core.fingerprint._custom_fpcalc_path", None), + patch("src.core.fingerprint._detected_fpcalc_path", None), + patch.dict("os.environ", {}, clear=True), + patch("shutil.which", return_value=None), + patch("src.core.fingerprint.sys") as mock_sys, + patch("src.core.fingerprint.platform") as mock_platform, + ): + mock_sys.frozen = True + mock_sys.executable = fake_exe + mock_sys._MEIPASS = None + mock_platform.system.return_value = "Windows" + + result = _find_fpcalc_binary() + assert result == str(fpcalc) + + def test_frozen_linux_finds_fpcalc_no_extension(self, tmp_path): + """Frozen Linux build finds fpcalc (no .exe extension).""" + exe_dir = tmp_path / "dist" + exe_dir.mkdir() + fpcalc = exe_dir / "fpcalc" + fpcalc.write_bytes(b"fake") + fake_exe = str(exe_dir / "TuneCover") + + with ( + patch("src.core.fingerprint._custom_fpcalc_path", None), + patch("src.core.fingerprint._detected_fpcalc_path", None), + patch.dict("os.environ", {}, clear=True), + patch("shutil.which", return_value=None), + patch("src.core.fingerprint.sys") as mock_sys, + patch("src.core.fingerprint.platform") as mock_platform, + ): + mock_sys.frozen = True + mock_sys.executable = fake_exe + mock_sys._MEIPASS = None + mock_platform.system.return_value = "Linux" + + result = _find_fpcalc_binary() + assert result == str(fpcalc) + + def test_onefile_mode_finds_fpcalc_via_meipass(self, tmp_path): + """One-file mode finds fpcalc in sys._MEIPASS temp directory.""" + meipass_dir = tmp_path / "_MEI12345" + meipass_dir.mkdir() + fpcalc = meipass_dir / "fpcalc" + fpcalc.write_bytes(b"fake") + # exe_dir intentionally does NOT have fpcalc + exe_dir = tmp_path / "dist" + exe_dir.mkdir() + fake_exe = str(exe_dir / "TuneCover") + + with ( + patch("src.core.fingerprint._custom_fpcalc_path", None), + patch("src.core.fingerprint._detected_fpcalc_path", None), + patch.dict("os.environ", {}, clear=True), + patch("shutil.which", return_value=None), + patch("src.core.fingerprint.sys") as mock_sys, + patch("src.core.fingerprint.platform") as mock_platform, + ): + mock_sys.frozen = True + mock_sys.executable = fake_exe + mock_sys._MEIPASS = str(meipass_dir) + mock_platform.system.return_value = "Linux" + + result = _find_fpcalc_binary() + assert result == str(fpcalc) + + def test_non_frozen_skips_bundle_check(self, tmp_path): + """Non-frozen (development) mode skips the PyInstaller bundle check entirely.""" + # Place fpcalc next to a fake executable — it should NOT be found + # via the bundle check because we are not in a frozen build. + exe_dir = tmp_path / "dist" + exe_dir.mkdir() + bundled_fpcalc = exe_dir / "fpcalc" + bundled_fpcalc.write_bytes(b"fake") + + with ( + patch("src.core.fingerprint._custom_fpcalc_path", None), + patch("src.core.fingerprint._detected_fpcalc_path", None), + patch.dict("os.environ", {}, clear=True), + patch("shutil.which", return_value=None), + patch("src.core.fingerprint.sys") as mock_sys, + patch("src.core.fingerprint.platform") as mock_platform, + ): + # Not frozen — getattr(sys, "frozen", False) returns False + mock_sys.frozen = False + mock_sys.executable = str(exe_dir / "python") + # Use "FreeBSD" so step 5 has no common paths to check and + # doesn't call Path.home() (which crashes on Windows CI when + # os.environ is cleared). + mock_platform.system.return_value = "FreeBSD" + + result = _find_fpcalc_binary() + assert result is None + + class TestAudioFingerprinter: """Tests for AudioFingerprinter class.""" diff --git a/uv.lock b/uv.lock index 3387f73..428285a 100644 --- a/uv.lock +++ b/uv.lock @@ -894,7 +894,7 @@ wheels = [ [[package]] name = "tunecover" -version = "0.1.0" +version = "0.1.1" source = { editable = "." } dependencies = [ { name = "music-metadata-filter" },