karaoke-gen 0.71.29__tar.gz → 0.72.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/PKG-INFO +4 -1
- karaoke_gen-0.72.2/karaoke_gen/__init__.py +38 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/audio_fetcher.py +291 -34
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/audio_processor.py +11 -3
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/file_handler.py +192 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/__init__.py +45 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/analyzer.py +408 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/editor.py +322 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/models.py +171 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/server.py +423 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/static/index.html +1490 -0
- karaoke_gen-0.72.2/karaoke_gen/instrumental_review/waveform.py +409 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/karaoke_finalise/karaoke_finalise.py +62 -1
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/karaoke_gen.py +114 -1
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/lyrics_processor.py +81 -4
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/utils/bulk_cli.py +3 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/utils/cli_args.py +9 -2
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/utils/gen_cli.py +369 -2
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/utils/remote_cli.py +1040 -74
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/anchor_sequence.py +226 -350
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/package.json +1 -1
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/Header.tsx +38 -12
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +17 -3
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/LyricsSynchronizer/SyncControls.tsx +185 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/LyricsSynchronizer/TimelineCanvas.tsx +704 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/LyricsSynchronizer/UpcomingWordsBar.tsx +80 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/LyricsSynchronizer/index.tsx +905 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ModeSelectionModal.tsx +127 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +336 -0
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -0
- karaoke_gen-0.71.29/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/assets/index-DdJTDWH3.js → karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/assets/index-COYImAcx.js +1722 -489
- karaoke_gen-0.72.2/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/assets/index-COYImAcx.js.map +1 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/index.html +1 -1
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/review/server.py +5 -5
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/pyproject.toml +5 -1
- karaoke_gen-0.71.29/karaoke_gen/__init__.py +0 -7
- karaoke_gen-0.71.29/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +0 -688
- karaoke_gen-0.71.29/lyrics_transcriber_temp/lyrics_transcriber/frontend/tsconfig.tsbuildinfo +0 -1
- karaoke_gen-0.71.29/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/assets/index-DdJTDWH3.js.map +0 -1
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/LICENSE +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/README.md +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/config.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/karaoke_finalise/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/metadata.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/base.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/context.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/executors/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/executors/local.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/executors/remote.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/finalize.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/render.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/screens.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/separation.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/pipeline/stages/transcription.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/resources/AvenirNext-Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/resources/Montserrat-Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/resources/Oswald-Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/resources/Oswald-SemiBold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/resources/Zurich_Cn_BT_Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/style_loader.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/utils/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/video_background_processor.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/karaoke_gen/video_generator.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/cli/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/cli/cli_main.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/core/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/core/config.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/core/controller.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/adapter.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/agent.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/feedback/aggregator.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/feedback/collector.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/feedback/retention.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/feedback/store.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/ambiguous.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/background_vocals.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/base.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/complex_multi_error.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/extra_words.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/no_error.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/punctuation.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/registry.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/repeated_section.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/handlers/sound_alike.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/ai_correction.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/correction_session.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/enums.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/human_feedback.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/learning_data.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/observability_metrics.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/schemas.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/models/utils.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/observability/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/observability/langfuse_integration.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/observability/metrics.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/observability/performance.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/prompts/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/prompts/classifier.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/base.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/circuit_breaker.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/config.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/constants.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/health.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/model_factory.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/response_cache.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/response_parser.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/providers/retry_executor.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/router.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/workflows/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/workflows/consensus_workflow.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/workflows/correction_graph.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/agentic/workflows/feedback_workflow.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/corrector.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/feedback/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/feedback/schemas.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/feedback/store.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/base.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/extend_anchor.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/levenshtein.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/llm.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/llm_providers.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/no_space_punct_match.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/relaxed_word_count_match.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/repeat.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/sound_alike.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/syllables_match.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/word_count_match.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/handlers/word_operations.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/operations.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/phrase_analyzer.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/correction/text_utils.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/.gitignore +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/.yarnrc.yml +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/README.md +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/eslint.config.js +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/index.html +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/apple-touch-icon.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/favicon-16x16.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/favicon-32x32.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/favicon.ico +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/public/nomad-karaoke-logo.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/App.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/api.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/EditActionBar.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/EditModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/EditWordList.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/FileUpload.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ModeSelector.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ModelSelector.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ReferenceView.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/WordDivider.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/constants.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/styles.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/types.js +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/types.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/hooks/useManualSync.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/main.tsx +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/theme.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/types/global.d.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/types.js +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/types.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/validation.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/src/vite-env.d.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/tsconfig.app.json +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/tsconfig.json +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/tsconfig.node.json +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/update_version.js +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/vite.config.d.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/vite.config.js +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/vite.config.ts +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/frontend/yarn.lock +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/base_lyrics_provider.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/file_provider.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/genius.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/lrclib.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/musixmatch.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/spotify.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/lyrics/user_input_provider.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/ass.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/ass_specs.txt +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/config.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/constants.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/event.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/formatters.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/lyrics_line.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/lyrics_screen.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/section_detector.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/section_screen.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/ass/style.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdg.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/cdg.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/composer.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/config.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/images/instrumental.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/images/intro.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/pack.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/render.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/centertexttoplogobottomtext.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/circlein.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/circleout.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/fizzle.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/largecentertexttoplogo.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/rectangle.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/spiral.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/topleftmusicalnotes.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/wipein.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/wipeleft.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/wipeout.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/transitions/wiperight.png +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/cdgmaker/utils.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/countdown_processor.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/AvenirNext-Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/DMSans-VariableFont_opsz,wght.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/DMSerifDisplay-Regular.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/Oswald-SemiBold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/arial.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/georgia.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/fonts/verdana.ttf +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/generator.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/lrc_to_cdg.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/lyrics_file.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/plain_text.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/segment_resizer.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/subtitles.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/output/video.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/review/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/storage/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/storage/dropbox.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/transcribers/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/transcribers/audioshake.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/transcribers/base_transcriber.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/transcribers/whisper.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/types.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/utils/__init__.py +0 -0
- {karaoke_gen-0.71.29 → karaoke_gen-0.72.2}/lyrics_transcriber_temp/lyrics_transcriber/utils/word_utils.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: karaoke-gen
|
|
3
|
-
Version: 0.
|
|
3
|
+
Version: 0.72.2
|
|
4
4
|
Summary: Generate karaoke videos with synchronized lyrics. Handles the entire process from downloading audio and lyrics to creating the final video with title screens.
|
|
5
5
|
License: MIT
|
|
6
6
|
License-File: LICENSE
|
|
@@ -29,8 +29,10 @@ Requires-Dist: google-auth
|
|
|
29
29
|
Requires-Dist: google-auth-httplib2
|
|
30
30
|
Requires-Dist: google-auth-oauthlib
|
|
31
31
|
Requires-Dist: google-cloud-firestore (>=2.14.0)
|
|
32
|
+
Requires-Dist: google-cloud-run (>=0.10.0)
|
|
32
33
|
Requires-Dist: google-cloud-secret-manager (>=2.18.0)
|
|
33
34
|
Requires-Dist: google-cloud-storage (>=2.14.0)
|
|
35
|
+
Requires-Dist: google-cloud-tasks (>=2.16.0)
|
|
34
36
|
Requires-Dist: httpx (>=0.25.0)
|
|
35
37
|
Requires-Dist: jiwer (>=3.0.0)
|
|
36
38
|
Requires-Dist: karaoke-lyrics-processor (>=0.6)
|
|
@@ -82,6 +84,7 @@ Requires-Dist: torch (>=2.7)
|
|
|
82
84
|
Requires-Dist: tqdm (>=4.67)
|
|
83
85
|
Requires-Dist: transformers (>=4.47)
|
|
84
86
|
Requires-Dist: uvicorn[standard] (>=0.24.0)
|
|
87
|
+
Requires-Dist: yt-dlp (>=2024.0.0)
|
|
85
88
|
Project-URL: Documentation, https://github.com/nomadkaraoke/karaoke-gen/blob/main/README.md
|
|
86
89
|
Project-URL: Homepage, https://github.com/nomadkaraoke/karaoke-gen
|
|
87
90
|
Project-URL: Repository, https://github.com/nomadkaraoke/karaoke-gen
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import warnings
|
|
2
|
+
|
|
3
|
+
# Suppress specific SyntaxWarnings from third-party packages
|
|
4
|
+
warnings.filterwarnings("ignore", category=SyntaxWarning, module="pydub.*")
|
|
5
|
+
warnings.filterwarnings("ignore", category=SyntaxWarning, module="syrics.*")
|
|
6
|
+
|
|
7
|
+
# Lazy imports to avoid loading heavy dependencies when not needed.
|
|
8
|
+
# KaraokePrep has many dependencies (lyrics_transcriber, etc.) which may not
|
|
9
|
+
# be available in all contexts (e.g., backend which only needs audio_fetcher).
|
|
10
|
+
#
|
|
11
|
+
# Use explicit imports instead:
|
|
12
|
+
# from karaoke_gen.karaoke_gen import KaraokePrep
|
|
13
|
+
# from karaoke_gen.audio_fetcher import FlacFetcher, AudioSearchResult, ...
|
|
14
|
+
|
|
15
|
+
__all__ = [
|
|
16
|
+
"KaraokePrep",
|
|
17
|
+
# Audio fetcher
|
|
18
|
+
"FlacFetcher",
|
|
19
|
+
"AudioSearchResult",
|
|
20
|
+
"AudioFetchResult",
|
|
21
|
+
"AudioFetcherError",
|
|
22
|
+
"NoResultsError",
|
|
23
|
+
"DownloadError",
|
|
24
|
+
"UserCancelledError",
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def __getattr__(name):
|
|
29
|
+
"""Lazy import for heavy modules."""
|
|
30
|
+
if name == "KaraokePrep":
|
|
31
|
+
from .karaoke_gen import KaraokePrep
|
|
32
|
+
return KaraokePrep
|
|
33
|
+
elif name in ("FlacFetcher", "AudioSearchResult", "AudioFetchResult",
|
|
34
|
+
"AudioFetcherError", "NoResultsError", "DownloadError",
|
|
35
|
+
"UserCancelledError"):
|
|
36
|
+
from . import audio_fetcher
|
|
37
|
+
return getattr(audio_fetcher, name)
|
|
38
|
+
raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
|
|
@@ -7,15 +7,26 @@ using flacfetch, replacing the previous direct yt-dlp usage.
|
|
|
7
7
|
|
|
8
8
|
import logging
|
|
9
9
|
import os
|
|
10
|
+
import signal
|
|
11
|
+
import sys
|
|
10
12
|
import tempfile
|
|
13
|
+
import threading
|
|
11
14
|
from abc import ABC, abstractmethod
|
|
12
|
-
from
|
|
13
|
-
from
|
|
15
|
+
from concurrent.futures import ThreadPoolExecutor, TimeoutError as FuturesTimeoutError
|
|
16
|
+
from dataclasses import dataclass, asdict, field
|
|
17
|
+
from typing import List, Optional, Dict, Any
|
|
18
|
+
|
|
19
|
+
# Global flag to track if user requested cancellation via Ctrl+C
|
|
20
|
+
_interrupt_requested = False
|
|
14
21
|
|
|
15
22
|
|
|
16
23
|
@dataclass
|
|
17
24
|
class AudioSearchResult:
|
|
18
|
-
"""Represents a single search result for audio.
|
|
25
|
+
"""Represents a single search result for audio.
|
|
26
|
+
|
|
27
|
+
Used by both local CLI and cloud backend. Supports serialization
|
|
28
|
+
for Firestore storage via to_dict()/from_dict().
|
|
29
|
+
"""
|
|
19
30
|
|
|
20
31
|
title: str
|
|
21
32
|
artist: str
|
|
@@ -24,13 +35,49 @@ class AudioSearchResult:
|
|
|
24
35
|
duration: Optional[int] = None # Duration in seconds
|
|
25
36
|
quality: Optional[str] = None # e.g., "FLAC", "320kbps", etc.
|
|
26
37
|
source_id: Optional[str] = None # Unique ID from the source
|
|
27
|
-
|
|
28
|
-
|
|
38
|
+
index: int = 0 # Index in the results list (for API selection)
|
|
39
|
+
# Raw result object from the provider (for download) - not serialized
|
|
40
|
+
raw_result: Optional[object] = field(default=None, repr=False)
|
|
41
|
+
|
|
42
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
43
|
+
"""Convert to dict for JSON/Firestore serialization.
|
|
44
|
+
|
|
45
|
+
Note: raw_result is excluded as it's not serializable.
|
|
46
|
+
"""
|
|
47
|
+
return {
|
|
48
|
+
"title": self.title,
|
|
49
|
+
"artist": self.artist,
|
|
50
|
+
"url": self.url,
|
|
51
|
+
"provider": self.provider,
|
|
52
|
+
"duration": self.duration,
|
|
53
|
+
"quality": self.quality,
|
|
54
|
+
"source_id": self.source_id,
|
|
55
|
+
"index": self.index,
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
@classmethod
|
|
59
|
+
def from_dict(cls, data: Dict[str, Any]) -> "AudioSearchResult":
|
|
60
|
+
"""Create from dict (e.g., from Firestore)."""
|
|
61
|
+
return cls(
|
|
62
|
+
title=data.get("title", ""),
|
|
63
|
+
artist=data.get("artist", ""),
|
|
64
|
+
url=data.get("url", ""),
|
|
65
|
+
provider=data.get("provider", "Unknown"),
|
|
66
|
+
duration=data.get("duration"),
|
|
67
|
+
quality=data.get("quality"),
|
|
68
|
+
source_id=data.get("source_id"),
|
|
69
|
+
index=data.get("index", 0),
|
|
70
|
+
raw_result=None, # Not stored in serialized form
|
|
71
|
+
)
|
|
29
72
|
|
|
30
73
|
|
|
31
74
|
@dataclass
|
|
32
75
|
class AudioFetchResult:
|
|
33
|
-
"""Result of an audio fetch operation.
|
|
76
|
+
"""Result of an audio fetch operation.
|
|
77
|
+
|
|
78
|
+
Used by both local CLI and cloud backend. Supports serialization
|
|
79
|
+
for Firestore storage via to_dict()/from_dict().
|
|
80
|
+
"""
|
|
34
81
|
|
|
35
82
|
filepath: str
|
|
36
83
|
artist: str
|
|
@@ -38,6 +85,22 @@ class AudioFetchResult:
|
|
|
38
85
|
provider: str
|
|
39
86
|
duration: Optional[int] = None
|
|
40
87
|
quality: Optional[str] = None
|
|
88
|
+
|
|
89
|
+
def to_dict(self) -> Dict[str, Any]:
|
|
90
|
+
"""Convert to dict for JSON/Firestore serialization."""
|
|
91
|
+
return asdict(self)
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_dict(cls, data: Dict[str, Any]) -> "AudioFetchResult":
|
|
95
|
+
"""Create from dict (e.g., from Firestore)."""
|
|
96
|
+
return cls(
|
|
97
|
+
filepath=data.get("filepath", ""),
|
|
98
|
+
artist=data.get("artist", ""),
|
|
99
|
+
title=data.get("title", ""),
|
|
100
|
+
provider=data.get("provider", "Unknown"),
|
|
101
|
+
duration=data.get("duration"),
|
|
102
|
+
quality=data.get("quality"),
|
|
103
|
+
)
|
|
41
104
|
|
|
42
105
|
|
|
43
106
|
class AudioFetcherError(Exception):
|
|
@@ -58,6 +121,19 @@ class DownloadError(AudioFetcherError):
|
|
|
58
121
|
pass
|
|
59
122
|
|
|
60
123
|
|
|
124
|
+
class UserCancelledError(AudioFetcherError):
|
|
125
|
+
"""Raised when user explicitly cancels the operation (e.g., enters 0 or Ctrl+C)."""
|
|
126
|
+
|
|
127
|
+
pass
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
def _check_interrupt():
|
|
131
|
+
"""Check if interrupt was requested and raise UserCancelledError if so."""
|
|
132
|
+
global _interrupt_requested
|
|
133
|
+
if _interrupt_requested:
|
|
134
|
+
raise UserCancelledError("Operation cancelled by user")
|
|
135
|
+
|
|
136
|
+
|
|
61
137
|
class AudioFetcher(ABC):
|
|
62
138
|
"""Abstract base class for audio fetching implementations."""
|
|
63
139
|
|
|
@@ -140,6 +216,8 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
140
216
|
|
|
141
217
|
This provides access to multiple audio sources including private music trackers
|
|
142
218
|
and YouTube, with intelligent prioritization of high-quality sources.
|
|
219
|
+
|
|
220
|
+
Also exported as FlacFetcher for shorter name.
|
|
143
221
|
"""
|
|
144
222
|
|
|
145
223
|
def __init__(
|
|
@@ -169,25 +247,38 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
169
247
|
if self._manager is None:
|
|
170
248
|
# Import flacfetch here to avoid import errors if not installed
|
|
171
249
|
from flacfetch.core.manager import FetchManager
|
|
172
|
-
from flacfetch.providers.youtube import
|
|
250
|
+
from flacfetch.providers.youtube import YoutubeProvider
|
|
251
|
+
from flacfetch.downloaders.youtube import YoutubeDownloader
|
|
252
|
+
|
|
253
|
+
# Try to import TorrentDownloader (has optional dependencies)
|
|
254
|
+
try:
|
|
255
|
+
from flacfetch.downloaders.torrent import TorrentDownloader
|
|
256
|
+
except ImportError:
|
|
257
|
+
TorrentDownloader = None
|
|
258
|
+
self.logger.debug("TorrentDownloader not available (missing dependencies)")
|
|
173
259
|
|
|
174
260
|
self._manager = FetchManager()
|
|
175
261
|
|
|
176
|
-
# Add providers based on available API keys
|
|
262
|
+
# Add providers and downloaders based on available API keys
|
|
177
263
|
if self._redacted_api_key:
|
|
178
264
|
from flacfetch.providers.redacted import RedactedProvider
|
|
179
265
|
|
|
180
266
|
self._manager.add_provider(RedactedProvider(api_key=self._redacted_api_key))
|
|
267
|
+
if TorrentDownloader:
|
|
268
|
+
self._manager.register_downloader("Redacted", TorrentDownloader())
|
|
181
269
|
self.logger.debug("Added Redacted provider")
|
|
182
270
|
|
|
183
271
|
if self._ops_api_key:
|
|
184
272
|
from flacfetch.providers.ops import OPSProvider
|
|
185
273
|
|
|
186
274
|
self._manager.add_provider(OPSProvider(api_key=self._ops_api_key))
|
|
275
|
+
if TorrentDownloader:
|
|
276
|
+
self._manager.register_downloader("OPS", TorrentDownloader())
|
|
187
277
|
self.logger.debug("Added OPS provider")
|
|
188
278
|
|
|
189
|
-
# Always add YouTube as a fallback provider
|
|
190
|
-
self._manager.add_provider(
|
|
279
|
+
# Always add YouTube as a fallback provider with its downloader
|
|
280
|
+
self._manager.add_provider(YoutubeProvider())
|
|
281
|
+
self._manager.register_downloader("YouTube", YoutubeDownloader())
|
|
191
282
|
self.logger.debug("Added YouTube provider")
|
|
192
283
|
|
|
193
284
|
return self._manager
|
|
@@ -219,16 +310,21 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
219
310
|
|
|
220
311
|
# Convert to our AudioSearchResult format
|
|
221
312
|
search_results = []
|
|
222
|
-
for result in results:
|
|
313
|
+
for i, result in enumerate(results):
|
|
314
|
+
# Get quality as string if it's a Quality object
|
|
315
|
+
quality = getattr(result, "quality", None)
|
|
316
|
+
quality_str = str(quality) if quality else None
|
|
317
|
+
|
|
223
318
|
search_results.append(
|
|
224
319
|
AudioSearchResult(
|
|
225
320
|
title=getattr(result, "title", title),
|
|
226
321
|
artist=getattr(result, "artist", artist),
|
|
227
|
-
url=getattr(result, "
|
|
228
|
-
provider=getattr(result, "
|
|
229
|
-
duration=getattr(result, "
|
|
230
|
-
quality=
|
|
231
|
-
source_id=getattr(result, "
|
|
322
|
+
url=getattr(result, "download_url", "") or "",
|
|
323
|
+
provider=getattr(result, "source_name", "Unknown"),
|
|
324
|
+
duration=getattr(result, "duration_seconds", None),
|
|
325
|
+
quality=quality_str,
|
|
326
|
+
source_id=getattr(result, "info_hash", None),
|
|
327
|
+
index=i, # Set index for API selection
|
|
232
328
|
raw_result=result,
|
|
233
329
|
)
|
|
234
330
|
)
|
|
@@ -265,7 +361,7 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
265
361
|
if output_filename is None:
|
|
266
362
|
output_filename = f"{result.artist} - {result.title}"
|
|
267
363
|
|
|
268
|
-
self.logger.info(f"Downloading: {result.artist} - {result.title} from {result.provider}")
|
|
364
|
+
self.logger.info(f"Downloading: {result.artist} - {result.title} from {result.provider or 'Unknown'}")
|
|
269
365
|
|
|
270
366
|
try:
|
|
271
367
|
# Use flacfetch to download
|
|
@@ -292,6 +388,40 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
292
388
|
except Exception as e:
|
|
293
389
|
raise DownloadError(f"Failed to download {result.artist} - {result.title}: {e}") from e
|
|
294
390
|
|
|
391
|
+
def select_best(self, results: List[AudioSearchResult]) -> int:
|
|
392
|
+
"""
|
|
393
|
+
Select the best result from a list of search results.
|
|
394
|
+
|
|
395
|
+
Uses flacfetch's built-in quality ranking to determine the best source.
|
|
396
|
+
This is useful for automated/non-interactive usage.
|
|
397
|
+
|
|
398
|
+
Args:
|
|
399
|
+
results: List of AudioSearchResult objects from search()
|
|
400
|
+
|
|
401
|
+
Returns:
|
|
402
|
+
Index of the best result in the list
|
|
403
|
+
"""
|
|
404
|
+
if not results:
|
|
405
|
+
return 0
|
|
406
|
+
|
|
407
|
+
manager = self._get_manager()
|
|
408
|
+
|
|
409
|
+
# Get raw results that have raw_result set
|
|
410
|
+
raw_results = [r.raw_result for r in results if r.raw_result is not None]
|
|
411
|
+
|
|
412
|
+
if raw_results:
|
|
413
|
+
try:
|
|
414
|
+
best = manager.select_best(raw_results)
|
|
415
|
+
# Find index of best result
|
|
416
|
+
for i, r in enumerate(results):
|
|
417
|
+
if r.raw_result == best:
|
|
418
|
+
return i
|
|
419
|
+
except Exception as e:
|
|
420
|
+
self.logger.warning(f"select_best failed, using first result: {e}")
|
|
421
|
+
|
|
422
|
+
# Fallback: return first result
|
|
423
|
+
return 0
|
|
424
|
+
|
|
295
425
|
def search_and_download(
|
|
296
426
|
self,
|
|
297
427
|
artist: str,
|
|
@@ -319,6 +449,7 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
319
449
|
Raises:
|
|
320
450
|
NoResultsError: If no results are found
|
|
321
451
|
DownloadError: If download fails
|
|
452
|
+
UserCancelledError: If user cancels (Ctrl+C or enters 0)
|
|
322
453
|
"""
|
|
323
454
|
from flacfetch.core.models import TrackQuery
|
|
324
455
|
|
|
@@ -326,7 +457,9 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
326
457
|
query = TrackQuery(artist=artist, title=title)
|
|
327
458
|
|
|
328
459
|
self.logger.info(f"Searching for: {artist} - {title}")
|
|
329
|
-
|
|
460
|
+
|
|
461
|
+
# Run search in a thread so we can handle Ctrl+C
|
|
462
|
+
results = self._interruptible_search(manager, query)
|
|
330
463
|
|
|
331
464
|
if not results:
|
|
332
465
|
raise NoResultsError(f"No results found for: {artist} - {title}")
|
|
@@ -336,11 +469,13 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
336
469
|
if auto_select:
|
|
337
470
|
# Auto mode: select best result based on flacfetch's ranking
|
|
338
471
|
selected = manager.select_best(results)
|
|
339
|
-
self.logger.info(f"Auto-selected: {getattr(selected, 'title', title)} from {getattr(selected, '
|
|
472
|
+
self.logger.info(f"Auto-selected: {getattr(selected, 'title', title)} from {getattr(selected, 'source_name', 'Unknown')}")
|
|
340
473
|
else:
|
|
341
474
|
# Interactive mode: present options to user
|
|
342
475
|
selected = self._interactive_select(results, artist, title)
|
|
343
476
|
|
|
477
|
+
# Note: _interactive_select now raises UserCancelledError instead of returning None
|
|
478
|
+
# This check is kept as a safety net
|
|
344
479
|
if selected is None:
|
|
345
480
|
raise NoResultsError(f"No result selected for: {artist} - {title}")
|
|
346
481
|
|
|
@@ -351,7 +486,7 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
351
486
|
if output_filename is None:
|
|
352
487
|
output_filename = f"{artist} - {title}"
|
|
353
488
|
|
|
354
|
-
self.logger.info(f"Downloading from {getattr(selected, '
|
|
489
|
+
self.logger.info(f"Downloading from {getattr(selected, 'source_name', 'Unknown')}...")
|
|
355
490
|
|
|
356
491
|
try:
|
|
357
492
|
filepath = manager.download(
|
|
@@ -365,51 +500,169 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
365
500
|
|
|
366
501
|
self.logger.info(f"Downloaded to: {filepath}")
|
|
367
502
|
|
|
503
|
+
# Get quality as string if it's a Quality object
|
|
504
|
+
quality = getattr(selected, "quality", None)
|
|
505
|
+
quality_str = str(quality) if quality else None
|
|
506
|
+
|
|
368
507
|
return AudioFetchResult(
|
|
369
508
|
filepath=filepath,
|
|
370
509
|
artist=artist,
|
|
371
510
|
title=title,
|
|
372
|
-
provider=getattr(selected, "
|
|
373
|
-
duration=getattr(selected, "
|
|
374
|
-
quality=
|
|
511
|
+
provider=getattr(selected, "source_name", "Unknown"),
|
|
512
|
+
duration=getattr(selected, "duration_seconds", None),
|
|
513
|
+
quality=quality_str,
|
|
375
514
|
)
|
|
376
515
|
|
|
516
|
+
except (UserCancelledError, KeyboardInterrupt):
|
|
517
|
+
# Let cancellation exceptions propagate without wrapping
|
|
518
|
+
raise
|
|
377
519
|
except Exception as e:
|
|
378
520
|
raise DownloadError(f"Failed to download {artist} - {title}: {e}") from e
|
|
379
521
|
|
|
522
|
+
def _interruptible_search(self, manager, query) -> list:
|
|
523
|
+
"""
|
|
524
|
+
Run search in a way that can be interrupted by Ctrl+C.
|
|
525
|
+
|
|
526
|
+
The flacfetch search is a blocking network operation that doesn't
|
|
527
|
+
respond to SIGINT while running. This method runs it in a background
|
|
528
|
+
thread and periodically checks for interrupts.
|
|
529
|
+
|
|
530
|
+
Args:
|
|
531
|
+
manager: The FetchManager instance
|
|
532
|
+
query: The TrackQuery to search for
|
|
533
|
+
|
|
534
|
+
Returns:
|
|
535
|
+
List of search results
|
|
536
|
+
|
|
537
|
+
Raises:
|
|
538
|
+
UserCancelledError: If user presses Ctrl+C during search
|
|
539
|
+
"""
|
|
540
|
+
global _interrupt_requested
|
|
541
|
+
_interrupt_requested = False
|
|
542
|
+
result_container = {"results": None, "error": None}
|
|
543
|
+
|
|
544
|
+
def do_search():
|
|
545
|
+
try:
|
|
546
|
+
result_container["results"] = manager.search(query)
|
|
547
|
+
except Exception as e:
|
|
548
|
+
result_container["error"] = e
|
|
549
|
+
|
|
550
|
+
# Set up signal handler for immediate response to Ctrl+C
|
|
551
|
+
original_handler = signal.getsignal(signal.SIGINT)
|
|
552
|
+
|
|
553
|
+
def interrupt_handler(signum, frame):
|
|
554
|
+
global _interrupt_requested
|
|
555
|
+
_interrupt_requested = True
|
|
556
|
+
# Print immediately so user knows it was received
|
|
557
|
+
print("\nCancelling... please wait", file=sys.stderr)
|
|
558
|
+
|
|
559
|
+
signal.signal(signal.SIGINT, interrupt_handler)
|
|
560
|
+
|
|
561
|
+
try:
|
|
562
|
+
# Start search in background thread
|
|
563
|
+
search_thread = threading.Thread(target=do_search, daemon=True)
|
|
564
|
+
search_thread.start()
|
|
565
|
+
|
|
566
|
+
# Wait for completion with periodic interrupt checks
|
|
567
|
+
while search_thread.is_alive():
|
|
568
|
+
search_thread.join(timeout=0.1) # Check every 100ms
|
|
569
|
+
if _interrupt_requested:
|
|
570
|
+
# Don't wait for thread - it's a daemon and will be killed
|
|
571
|
+
raise UserCancelledError("Search cancelled by user (Ctrl+C)")
|
|
572
|
+
|
|
573
|
+
# Check for errors from the search
|
|
574
|
+
if result_container["error"] is not None:
|
|
575
|
+
raise result_container["error"]
|
|
576
|
+
|
|
577
|
+
return result_container["results"]
|
|
578
|
+
|
|
579
|
+
finally:
|
|
580
|
+
# Restore original signal handler
|
|
581
|
+
signal.signal(signal.SIGINT, original_handler)
|
|
582
|
+
_interrupt_requested = False
|
|
583
|
+
|
|
380
584
|
def _interactive_select(self, results: list, artist: str, title: str) -> object:
|
|
381
585
|
"""
|
|
382
586
|
Present search results to the user for interactive selection.
|
|
383
587
|
|
|
588
|
+
Uses flacfetch's built-in CLIHandler for rich, colorized output.
|
|
589
|
+
|
|
384
590
|
Args:
|
|
385
|
-
results: List of
|
|
591
|
+
results: List of Release objects from flacfetch
|
|
386
592
|
artist: The artist name being searched
|
|
387
593
|
title: The track title being searched
|
|
388
594
|
|
|
389
595
|
Returns:
|
|
390
|
-
The selected
|
|
596
|
+
The selected Release object
|
|
597
|
+
|
|
598
|
+
Raises:
|
|
599
|
+
UserCancelledError: If user cancels selection
|
|
600
|
+
"""
|
|
601
|
+
try:
|
|
602
|
+
# Use flacfetch's built-in CLIHandler for rich display
|
|
603
|
+
from flacfetch.interface.cli import CLIHandler
|
|
604
|
+
|
|
605
|
+
handler = CLIHandler(target_artist=artist)
|
|
606
|
+
result = handler.select_release(results)
|
|
607
|
+
if result is None:
|
|
608
|
+
# User selected 0 to cancel
|
|
609
|
+
raise UserCancelledError("Selection cancelled by user")
|
|
610
|
+
return result
|
|
611
|
+
except ImportError:
|
|
612
|
+
# Fallback to basic display if CLIHandler not available
|
|
613
|
+
return self._basic_interactive_select(results, artist, title)
|
|
614
|
+
except (KeyboardInterrupt, EOFError):
|
|
615
|
+
raise UserCancelledError("Selection cancelled by user (Ctrl+C)")
|
|
616
|
+
except (AttributeError, TypeError):
|
|
617
|
+
# Fallback if results aren't proper Release objects (e.g., in tests)
|
|
618
|
+
return self._basic_interactive_select(results, artist, title)
|
|
619
|
+
|
|
620
|
+
def _basic_interactive_select(self, results: list, artist: str, title: str) -> object:
|
|
621
|
+
"""
|
|
622
|
+
Basic fallback for interactive selection without rich formatting.
|
|
623
|
+
|
|
624
|
+
Args:
|
|
625
|
+
results: List of Release objects from flacfetch
|
|
626
|
+
artist: The artist name being searched
|
|
627
|
+
title: The track title being searched
|
|
628
|
+
|
|
629
|
+
Returns:
|
|
630
|
+
The selected Release object
|
|
631
|
+
|
|
632
|
+
Raises:
|
|
633
|
+
UserCancelledError: If user cancels selection
|
|
391
634
|
"""
|
|
392
635
|
print(f"\n{'=' * 60}")
|
|
393
636
|
print(f"Search Results for: {artist} - {title}")
|
|
394
637
|
print(f"{'=' * 60}\n")
|
|
395
638
|
|
|
396
639
|
for i, result in enumerate(results, 1):
|
|
397
|
-
|
|
640
|
+
# Use correct flacfetch attribute names
|
|
641
|
+
source_name = getattr(result, "source_name", "Unknown")
|
|
398
642
|
result_title = getattr(result, "title", "Unknown")
|
|
399
643
|
result_artist = getattr(result, "artist", "Unknown")
|
|
400
|
-
quality = getattr(result, "quality",
|
|
401
|
-
|
|
644
|
+
quality = getattr(result, "quality", None)
|
|
645
|
+
duration_seconds = getattr(result, "duration_seconds", None)
|
|
646
|
+
seeders = getattr(result, "seeders", None)
|
|
647
|
+
target_file = getattr(result, "target_file", None)
|
|
402
648
|
|
|
403
649
|
# Format duration if available
|
|
404
650
|
duration_str = ""
|
|
405
|
-
if
|
|
406
|
-
minutes =
|
|
407
|
-
seconds =
|
|
651
|
+
if duration_seconds:
|
|
652
|
+
minutes = duration_seconds // 60
|
|
653
|
+
seconds = duration_seconds % 60
|
|
408
654
|
duration_str = f" [{minutes}:{seconds:02d}]"
|
|
409
655
|
|
|
656
|
+
# Format quality - it's a Quality object with __str__
|
|
410
657
|
quality_str = f" ({quality})" if quality else ""
|
|
411
658
|
|
|
412
|
-
|
|
659
|
+
# Format seeders for torrent sources
|
|
660
|
+
seeders_str = f" Seeders: {seeders}" if seeders is not None else ""
|
|
661
|
+
|
|
662
|
+
# Format target file
|
|
663
|
+
file_str = f' "{target_file}"' if target_file else ""
|
|
664
|
+
|
|
665
|
+
print(f" {i}. [{source_name}] {result_artist} - {result_title}{quality_str}{duration_str}{seeders_str}{file_str}")
|
|
413
666
|
|
|
414
667
|
print()
|
|
415
668
|
print(" 0. Cancel")
|
|
@@ -421,7 +674,7 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
421
674
|
|
|
422
675
|
if choice == "0":
|
|
423
676
|
self.logger.info("User cancelled selection")
|
|
424
|
-
|
|
677
|
+
raise UserCancelledError("Selection cancelled by user")
|
|
425
678
|
|
|
426
679
|
choice_num = int(choice)
|
|
427
680
|
if 1 <= choice_num <= len(results):
|
|
@@ -435,7 +688,11 @@ class FlacFetchAudioFetcher(AudioFetcher):
|
|
|
435
688
|
print("Please enter a valid number")
|
|
436
689
|
except KeyboardInterrupt:
|
|
437
690
|
print("\nCancelled")
|
|
438
|
-
|
|
691
|
+
raise UserCancelledError("Selection cancelled by user (Ctrl+C)")
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
# Alias for shorter name - used by backend and other consumers
|
|
695
|
+
FlacFetcher = FlacFetchAudioFetcher
|
|
439
696
|
|
|
440
697
|
|
|
441
698
|
def create_audio_fetcher(
|
|
@@ -771,8 +771,16 @@ class AudioProcessor:
|
|
|
771
771
|
padded_result["other_stems"] = separation_result.get("other_stems", {})
|
|
772
772
|
padded_result["backing_vocals"] = separation_result.get("backing_vocals", {})
|
|
773
773
|
|
|
774
|
-
|
|
775
|
-
|
|
776
|
-
|
|
774
|
+
# Count actual padded files (don't assume clean instrumental was padded)
|
|
775
|
+
padded_count = (1 if padded_result["clean_instrumental"].get("instrumental") else 0) + len(padded_result["combined_instrumentals"])
|
|
776
|
+
|
|
777
|
+
if padded_count > 0:
|
|
778
|
+
self.logger.info(
|
|
779
|
+
f"✓ Countdown padding applied to {padded_count} instrumental file(s)"
|
|
780
|
+
)
|
|
781
|
+
else:
|
|
782
|
+
self.logger.warning(
|
|
783
|
+
"No instrumental files found to pad. Check that audio separation completed successfully."
|
|
784
|
+
)
|
|
777
785
|
|
|
778
786
|
return padded_result
|