karaoke-gen 0.57.0__py3-none-any.whl → 0.71.23__py3-none-any.whl

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.
Files changed (268) hide show
  1. karaoke_gen/audio_fetcher.py +461 -0
  2. karaoke_gen/audio_processor.py +407 -30
  3. karaoke_gen/config.py +62 -113
  4. karaoke_gen/file_handler.py +32 -59
  5. karaoke_gen/karaoke_finalise/karaoke_finalise.py +148 -67
  6. karaoke_gen/karaoke_gen.py +270 -61
  7. karaoke_gen/lyrics_processor.py +13 -1
  8. karaoke_gen/metadata.py +78 -73
  9. karaoke_gen/pipeline/__init__.py +87 -0
  10. karaoke_gen/pipeline/base.py +215 -0
  11. karaoke_gen/pipeline/context.py +230 -0
  12. karaoke_gen/pipeline/executors/__init__.py +21 -0
  13. karaoke_gen/pipeline/executors/local.py +159 -0
  14. karaoke_gen/pipeline/executors/remote.py +257 -0
  15. karaoke_gen/pipeline/stages/__init__.py +27 -0
  16. karaoke_gen/pipeline/stages/finalize.py +202 -0
  17. karaoke_gen/pipeline/stages/render.py +165 -0
  18. karaoke_gen/pipeline/stages/screens.py +139 -0
  19. karaoke_gen/pipeline/stages/separation.py +191 -0
  20. karaoke_gen/pipeline/stages/transcription.py +191 -0
  21. karaoke_gen/style_loader.py +531 -0
  22. karaoke_gen/utils/bulk_cli.py +6 -0
  23. karaoke_gen/utils/cli_args.py +424 -0
  24. karaoke_gen/utils/gen_cli.py +26 -261
  25. karaoke_gen/utils/remote_cli.py +1815 -0
  26. karaoke_gen/video_background_processor.py +351 -0
  27. karaoke_gen-0.71.23.dist-info/METADATA +610 -0
  28. karaoke_gen-0.71.23.dist-info/RECORD +275 -0
  29. {karaoke_gen-0.57.0.dist-info → karaoke_gen-0.71.23.dist-info}/WHEEL +1 -1
  30. {karaoke_gen-0.57.0.dist-info → karaoke_gen-0.71.23.dist-info}/entry_points.txt +1 -0
  31. lyrics_transcriber/__init__.py +10 -0
  32. lyrics_transcriber/cli/__init__.py +0 -0
  33. lyrics_transcriber/cli/cli_main.py +285 -0
  34. lyrics_transcriber/core/__init__.py +0 -0
  35. lyrics_transcriber/core/config.py +50 -0
  36. lyrics_transcriber/core/controller.py +520 -0
  37. lyrics_transcriber/correction/__init__.py +0 -0
  38. lyrics_transcriber/correction/agentic/__init__.py +9 -0
  39. lyrics_transcriber/correction/agentic/adapter.py +71 -0
  40. lyrics_transcriber/correction/agentic/agent.py +313 -0
  41. lyrics_transcriber/correction/agentic/feedback/aggregator.py +12 -0
  42. lyrics_transcriber/correction/agentic/feedback/collector.py +17 -0
  43. lyrics_transcriber/correction/agentic/feedback/retention.py +24 -0
  44. lyrics_transcriber/correction/agentic/feedback/store.py +76 -0
  45. lyrics_transcriber/correction/agentic/handlers/__init__.py +24 -0
  46. lyrics_transcriber/correction/agentic/handlers/ambiguous.py +44 -0
  47. lyrics_transcriber/correction/agentic/handlers/background_vocals.py +68 -0
  48. lyrics_transcriber/correction/agentic/handlers/base.py +51 -0
  49. lyrics_transcriber/correction/agentic/handlers/complex_multi_error.py +46 -0
  50. lyrics_transcriber/correction/agentic/handlers/extra_words.py +74 -0
  51. lyrics_transcriber/correction/agentic/handlers/no_error.py +42 -0
  52. lyrics_transcriber/correction/agentic/handlers/punctuation.py +44 -0
  53. lyrics_transcriber/correction/agentic/handlers/registry.py +60 -0
  54. lyrics_transcriber/correction/agentic/handlers/repeated_section.py +44 -0
  55. lyrics_transcriber/correction/agentic/handlers/sound_alike.py +126 -0
  56. lyrics_transcriber/correction/agentic/models/__init__.py +5 -0
  57. lyrics_transcriber/correction/agentic/models/ai_correction.py +31 -0
  58. lyrics_transcriber/correction/agentic/models/correction_session.py +30 -0
  59. lyrics_transcriber/correction/agentic/models/enums.py +38 -0
  60. lyrics_transcriber/correction/agentic/models/human_feedback.py +30 -0
  61. lyrics_transcriber/correction/agentic/models/learning_data.py +26 -0
  62. lyrics_transcriber/correction/agentic/models/observability_metrics.py +28 -0
  63. lyrics_transcriber/correction/agentic/models/schemas.py +46 -0
  64. lyrics_transcriber/correction/agentic/models/utils.py +19 -0
  65. lyrics_transcriber/correction/agentic/observability/__init__.py +5 -0
  66. lyrics_transcriber/correction/agentic/observability/langfuse_integration.py +35 -0
  67. lyrics_transcriber/correction/agentic/observability/metrics.py +46 -0
  68. lyrics_transcriber/correction/agentic/observability/performance.py +19 -0
  69. lyrics_transcriber/correction/agentic/prompts/__init__.py +2 -0
  70. lyrics_transcriber/correction/agentic/prompts/classifier.py +227 -0
  71. lyrics_transcriber/correction/agentic/providers/__init__.py +6 -0
  72. lyrics_transcriber/correction/agentic/providers/base.py +36 -0
  73. lyrics_transcriber/correction/agentic/providers/circuit_breaker.py +145 -0
  74. lyrics_transcriber/correction/agentic/providers/config.py +73 -0
  75. lyrics_transcriber/correction/agentic/providers/constants.py +24 -0
  76. lyrics_transcriber/correction/agentic/providers/health.py +28 -0
  77. lyrics_transcriber/correction/agentic/providers/langchain_bridge.py +212 -0
  78. lyrics_transcriber/correction/agentic/providers/model_factory.py +209 -0
  79. lyrics_transcriber/correction/agentic/providers/response_cache.py +218 -0
  80. lyrics_transcriber/correction/agentic/providers/response_parser.py +111 -0
  81. lyrics_transcriber/correction/agentic/providers/retry_executor.py +127 -0
  82. lyrics_transcriber/correction/agentic/router.py +35 -0
  83. lyrics_transcriber/correction/agentic/workflows/__init__.py +5 -0
  84. lyrics_transcriber/correction/agentic/workflows/consensus_workflow.py +24 -0
  85. lyrics_transcriber/correction/agentic/workflows/correction_graph.py +59 -0
  86. lyrics_transcriber/correction/agentic/workflows/feedback_workflow.py +24 -0
  87. lyrics_transcriber/correction/anchor_sequence.py +1043 -0
  88. lyrics_transcriber/correction/corrector.py +760 -0
  89. lyrics_transcriber/correction/feedback/__init__.py +2 -0
  90. lyrics_transcriber/correction/feedback/schemas.py +107 -0
  91. lyrics_transcriber/correction/feedback/store.py +236 -0
  92. lyrics_transcriber/correction/handlers/__init__.py +0 -0
  93. lyrics_transcriber/correction/handlers/base.py +52 -0
  94. lyrics_transcriber/correction/handlers/extend_anchor.py +149 -0
  95. lyrics_transcriber/correction/handlers/levenshtein.py +189 -0
  96. lyrics_transcriber/correction/handlers/llm.py +293 -0
  97. lyrics_transcriber/correction/handlers/llm_providers.py +60 -0
  98. lyrics_transcriber/correction/handlers/no_space_punct_match.py +154 -0
  99. lyrics_transcriber/correction/handlers/relaxed_word_count_match.py +85 -0
  100. lyrics_transcriber/correction/handlers/repeat.py +88 -0
  101. lyrics_transcriber/correction/handlers/sound_alike.py +259 -0
  102. lyrics_transcriber/correction/handlers/syllables_match.py +252 -0
  103. lyrics_transcriber/correction/handlers/word_count_match.py +80 -0
  104. lyrics_transcriber/correction/handlers/word_operations.py +187 -0
  105. lyrics_transcriber/correction/operations.py +352 -0
  106. lyrics_transcriber/correction/phrase_analyzer.py +435 -0
  107. lyrics_transcriber/correction/text_utils.py +30 -0
  108. lyrics_transcriber/frontend/.gitignore +23 -0
  109. lyrics_transcriber/frontend/.yarn/releases/yarn-4.7.0.cjs +935 -0
  110. lyrics_transcriber/frontend/.yarnrc.yml +3 -0
  111. lyrics_transcriber/frontend/README.md +50 -0
  112. lyrics_transcriber/frontend/REPLACE_ALL_FUNCTIONALITY.md +210 -0
  113. lyrics_transcriber/frontend/__init__.py +25 -0
  114. lyrics_transcriber/frontend/eslint.config.js +28 -0
  115. lyrics_transcriber/frontend/index.html +18 -0
  116. lyrics_transcriber/frontend/package.json +42 -0
  117. lyrics_transcriber/frontend/public/android-chrome-192x192.png +0 -0
  118. lyrics_transcriber/frontend/public/android-chrome-512x512.png +0 -0
  119. lyrics_transcriber/frontend/public/apple-touch-icon.png +0 -0
  120. lyrics_transcriber/frontend/public/favicon-16x16.png +0 -0
  121. lyrics_transcriber/frontend/public/favicon-32x32.png +0 -0
  122. lyrics_transcriber/frontend/public/favicon.ico +0 -0
  123. lyrics_transcriber/frontend/public/nomad-karaoke-logo.png +0 -0
  124. lyrics_transcriber/frontend/src/App.tsx +212 -0
  125. lyrics_transcriber/frontend/src/api.ts +239 -0
  126. lyrics_transcriber/frontend/src/components/AIFeedbackModal.tsx +77 -0
  127. lyrics_transcriber/frontend/src/components/AddLyricsModal.tsx +114 -0
  128. lyrics_transcriber/frontend/src/components/AgenticCorrectionMetrics.tsx +204 -0
  129. lyrics_transcriber/frontend/src/components/AudioPlayer.tsx +180 -0
  130. lyrics_transcriber/frontend/src/components/CorrectedWordWithActions.tsx +167 -0
  131. lyrics_transcriber/frontend/src/components/CorrectionAnnotationModal.tsx +359 -0
  132. lyrics_transcriber/frontend/src/components/CorrectionDetailCard.tsx +281 -0
  133. lyrics_transcriber/frontend/src/components/CorrectionMetrics.tsx +162 -0
  134. lyrics_transcriber/frontend/src/components/DurationTimelineView.tsx +257 -0
  135. lyrics_transcriber/frontend/src/components/EditActionBar.tsx +68 -0
  136. lyrics_transcriber/frontend/src/components/EditModal.tsx +702 -0
  137. lyrics_transcriber/frontend/src/components/EditTimelineSection.tsx +496 -0
  138. lyrics_transcriber/frontend/src/components/EditWordList.tsx +379 -0
  139. lyrics_transcriber/frontend/src/components/FileUpload.tsx +77 -0
  140. lyrics_transcriber/frontend/src/components/FindReplaceModal.tsx +467 -0
  141. lyrics_transcriber/frontend/src/components/Header.tsx +387 -0
  142. lyrics_transcriber/frontend/src/components/LyricsAnalyzer.tsx +1373 -0
  143. lyrics_transcriber/frontend/src/components/MetricsDashboard.tsx +51 -0
  144. lyrics_transcriber/frontend/src/components/ModeSelector.tsx +67 -0
  145. lyrics_transcriber/frontend/src/components/ModelSelector.tsx +23 -0
  146. lyrics_transcriber/frontend/src/components/PreviewVideoSection.tsx +144 -0
  147. lyrics_transcriber/frontend/src/components/ReferenceView.tsx +268 -0
  148. lyrics_transcriber/frontend/src/components/ReplaceAllLyricsModal.tsx +688 -0
  149. lyrics_transcriber/frontend/src/components/ReviewChangesModal.tsx +354 -0
  150. lyrics_transcriber/frontend/src/components/SegmentDetailsModal.tsx +64 -0
  151. lyrics_transcriber/frontend/src/components/TimelineEditor.tsx +376 -0
  152. lyrics_transcriber/frontend/src/components/TimingOffsetModal.tsx +131 -0
  153. lyrics_transcriber/frontend/src/components/TranscriptionView.tsx +256 -0
  154. lyrics_transcriber/frontend/src/components/WordDivider.tsx +187 -0
  155. lyrics_transcriber/frontend/src/components/shared/components/HighlightedText.tsx +379 -0
  156. lyrics_transcriber/frontend/src/components/shared/components/SourceSelector.tsx +56 -0
  157. lyrics_transcriber/frontend/src/components/shared/components/Word.tsx +87 -0
  158. lyrics_transcriber/frontend/src/components/shared/constants.ts +20 -0
  159. lyrics_transcriber/frontend/src/components/shared/hooks/useWordClick.ts +180 -0
  160. lyrics_transcriber/frontend/src/components/shared/styles.ts +13 -0
  161. lyrics_transcriber/frontend/src/components/shared/types.js +2 -0
  162. lyrics_transcriber/frontend/src/components/shared/types.ts +129 -0
  163. lyrics_transcriber/frontend/src/components/shared/utils/keyboardHandlers.ts +177 -0
  164. lyrics_transcriber/frontend/src/components/shared/utils/localStorage.ts +78 -0
  165. lyrics_transcriber/frontend/src/components/shared/utils/referenceLineCalculator.ts +75 -0
  166. lyrics_transcriber/frontend/src/components/shared/utils/segmentOperations.ts +360 -0
  167. lyrics_transcriber/frontend/src/components/shared/utils/timingUtils.ts +110 -0
  168. lyrics_transcriber/frontend/src/components/shared/utils/wordUtils.ts +22 -0
  169. lyrics_transcriber/frontend/src/hooks/useManualSync.ts +435 -0
  170. lyrics_transcriber/frontend/src/main.tsx +17 -0
  171. lyrics_transcriber/frontend/src/theme.ts +177 -0
  172. lyrics_transcriber/frontend/src/types/global.d.ts +9 -0
  173. lyrics_transcriber/frontend/src/types.js +2 -0
  174. lyrics_transcriber/frontend/src/types.ts +199 -0
  175. lyrics_transcriber/frontend/src/validation.ts +132 -0
  176. lyrics_transcriber/frontend/src/vite-env.d.ts +1 -0
  177. lyrics_transcriber/frontend/tsconfig.app.json +26 -0
  178. lyrics_transcriber/frontend/tsconfig.json +25 -0
  179. lyrics_transcriber/frontend/tsconfig.node.json +23 -0
  180. lyrics_transcriber/frontend/tsconfig.tsbuildinfo +1 -0
  181. lyrics_transcriber/frontend/update_version.js +11 -0
  182. lyrics_transcriber/frontend/vite.config.d.ts +2 -0
  183. lyrics_transcriber/frontend/vite.config.js +10 -0
  184. lyrics_transcriber/frontend/vite.config.ts +11 -0
  185. lyrics_transcriber/frontend/web_assets/android-chrome-192x192.png +0 -0
  186. lyrics_transcriber/frontend/web_assets/android-chrome-512x512.png +0 -0
  187. lyrics_transcriber/frontend/web_assets/apple-touch-icon.png +0 -0
  188. lyrics_transcriber/frontend/web_assets/assets/index-DdJTDWH3.js +42039 -0
  189. lyrics_transcriber/frontend/web_assets/assets/index-DdJTDWH3.js.map +1 -0
  190. lyrics_transcriber/frontend/web_assets/favicon-16x16.png +0 -0
  191. lyrics_transcriber/frontend/web_assets/favicon-32x32.png +0 -0
  192. lyrics_transcriber/frontend/web_assets/favicon.ico +0 -0
  193. lyrics_transcriber/frontend/web_assets/index.html +18 -0
  194. lyrics_transcriber/frontend/web_assets/nomad-karaoke-logo.png +0 -0
  195. lyrics_transcriber/frontend/yarn.lock +3752 -0
  196. lyrics_transcriber/lyrics/__init__.py +0 -0
  197. lyrics_transcriber/lyrics/base_lyrics_provider.py +211 -0
  198. lyrics_transcriber/lyrics/file_provider.py +95 -0
  199. lyrics_transcriber/lyrics/genius.py +384 -0
  200. lyrics_transcriber/lyrics/lrclib.py +231 -0
  201. lyrics_transcriber/lyrics/musixmatch.py +156 -0
  202. lyrics_transcriber/lyrics/spotify.py +290 -0
  203. lyrics_transcriber/lyrics/user_input_provider.py +44 -0
  204. lyrics_transcriber/output/__init__.py +0 -0
  205. lyrics_transcriber/output/ass/__init__.py +21 -0
  206. lyrics_transcriber/output/ass/ass.py +2088 -0
  207. lyrics_transcriber/output/ass/ass_specs.txt +732 -0
  208. lyrics_transcriber/output/ass/config.py +180 -0
  209. lyrics_transcriber/output/ass/constants.py +23 -0
  210. lyrics_transcriber/output/ass/event.py +94 -0
  211. lyrics_transcriber/output/ass/formatters.py +132 -0
  212. lyrics_transcriber/output/ass/lyrics_line.py +265 -0
  213. lyrics_transcriber/output/ass/lyrics_screen.py +252 -0
  214. lyrics_transcriber/output/ass/section_detector.py +89 -0
  215. lyrics_transcriber/output/ass/section_screen.py +106 -0
  216. lyrics_transcriber/output/ass/style.py +187 -0
  217. lyrics_transcriber/output/cdg.py +619 -0
  218. lyrics_transcriber/output/cdgmaker/__init__.py +0 -0
  219. lyrics_transcriber/output/cdgmaker/cdg.py +262 -0
  220. lyrics_transcriber/output/cdgmaker/composer.py +2260 -0
  221. lyrics_transcriber/output/cdgmaker/config.py +151 -0
  222. lyrics_transcriber/output/cdgmaker/images/instrumental.png +0 -0
  223. lyrics_transcriber/output/cdgmaker/images/intro.png +0 -0
  224. lyrics_transcriber/output/cdgmaker/pack.py +507 -0
  225. lyrics_transcriber/output/cdgmaker/render.py +346 -0
  226. lyrics_transcriber/output/cdgmaker/transitions/centertexttoplogobottomtext.png +0 -0
  227. lyrics_transcriber/output/cdgmaker/transitions/circlein.png +0 -0
  228. lyrics_transcriber/output/cdgmaker/transitions/circleout.png +0 -0
  229. lyrics_transcriber/output/cdgmaker/transitions/fizzle.png +0 -0
  230. lyrics_transcriber/output/cdgmaker/transitions/largecentertexttoplogo.png +0 -0
  231. lyrics_transcriber/output/cdgmaker/transitions/rectangle.png +0 -0
  232. lyrics_transcriber/output/cdgmaker/transitions/spiral.png +0 -0
  233. lyrics_transcriber/output/cdgmaker/transitions/topleftmusicalnotes.png +0 -0
  234. lyrics_transcriber/output/cdgmaker/transitions/wipein.png +0 -0
  235. lyrics_transcriber/output/cdgmaker/transitions/wipeleft.png +0 -0
  236. lyrics_transcriber/output/cdgmaker/transitions/wipeout.png +0 -0
  237. lyrics_transcriber/output/cdgmaker/transitions/wiperight.png +0 -0
  238. lyrics_transcriber/output/cdgmaker/utils.py +132 -0
  239. lyrics_transcriber/output/countdown_processor.py +267 -0
  240. lyrics_transcriber/output/fonts/AvenirNext-Bold.ttf +0 -0
  241. lyrics_transcriber/output/fonts/DMSans-VariableFont_opsz,wght.ttf +0 -0
  242. lyrics_transcriber/output/fonts/DMSerifDisplay-Regular.ttf +0 -0
  243. lyrics_transcriber/output/fonts/Oswald-SemiBold.ttf +0 -0
  244. lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf +0 -0
  245. lyrics_transcriber/output/fonts/arial.ttf +0 -0
  246. lyrics_transcriber/output/fonts/georgia.ttf +0 -0
  247. lyrics_transcriber/output/fonts/verdana.ttf +0 -0
  248. lyrics_transcriber/output/generator.py +257 -0
  249. lyrics_transcriber/output/lrc_to_cdg.py +61 -0
  250. lyrics_transcriber/output/lyrics_file.py +102 -0
  251. lyrics_transcriber/output/plain_text.py +96 -0
  252. lyrics_transcriber/output/segment_resizer.py +431 -0
  253. lyrics_transcriber/output/subtitles.py +397 -0
  254. lyrics_transcriber/output/video.py +544 -0
  255. lyrics_transcriber/review/__init__.py +0 -0
  256. lyrics_transcriber/review/server.py +676 -0
  257. lyrics_transcriber/storage/__init__.py +0 -0
  258. lyrics_transcriber/storage/dropbox.py +225 -0
  259. lyrics_transcriber/transcribers/__init__.py +0 -0
  260. lyrics_transcriber/transcribers/audioshake.py +290 -0
  261. lyrics_transcriber/transcribers/base_transcriber.py +157 -0
  262. lyrics_transcriber/transcribers/whisper.py +330 -0
  263. lyrics_transcriber/types.py +648 -0
  264. lyrics_transcriber/utils/__init__.py +0 -0
  265. lyrics_transcriber/utils/word_utils.py +27 -0
  266. karaoke_gen-0.57.0.dist-info/METADATA +0 -167
  267. karaoke_gen-0.57.0.dist-info/RECORD +0 -23
  268. {karaoke_gen-0.57.0.dist-info → karaoke_gen-0.71.23.dist-info/licenses}/LICENSE +0 -0
karaoke_gen/config.py CHANGED
@@ -1,130 +1,79 @@
1
+ """
2
+ Configuration utilities for karaoke generation.
3
+
4
+ This module provides configuration loading and setup functions.
5
+ Style loading is delegated to the unified style_loader module.
6
+ """
1
7
  import os
2
8
  import sys
3
- import json
4
9
  import logging
5
10
 
6
- # Default style parameters if no JSON file is provided or if it's invalid
7
- DEFAULT_STYLE_PARAMS = {
8
- "intro": {
9
- "video_duration": 5,
10
- "existing_image": None,
11
- "background_color": "#000000",
12
- "background_image": None,
13
- "font": "Montserrat-Bold.ttf",
14
- "artist_color": "#ffdf6b",
15
- "artist_gradient": None,
16
- "title_color": "#ffffff",
17
- "title_gradient": None,
18
- "title_region": "370, 200, 3100, 480",
19
- "artist_region": "370, 700, 3100, 480",
20
- "extra_text": None,
21
- "extra_text_color": "#ffffff",
22
- "extra_text_gradient": None,
23
- "extra_text_region": "370, 1200, 3100, 480",
24
- "title_text_transform": None, # none, uppercase, lowercase, propercase
25
- "artist_text_transform": None, # none, uppercase, lowercase, propercase
26
- },
27
- "end": {
28
- "video_duration": 5,
29
- "existing_image": None,
30
- "background_color": "#000000",
31
- "background_image": None,
32
- "font": "Montserrat-Bold.ttf",
33
- "artist_color": "#ffdf6b",
34
- "artist_gradient": None,
35
- "title_color": "#ffffff",
36
- "title_gradient": None,
37
- "title_region": None,
38
- "artist_region": None,
39
- "extra_text": "THANK YOU FOR SINGING!",
40
- "extra_text_color": "#ff7acc",
41
- "extra_text_gradient": None,
42
- "extra_text_region": None,
43
- "title_text_transform": None, # none, uppercase, lowercase, propercase
44
- "artist_text_transform": None, # none, uppercase, lowercase, propercase
45
- },
46
- }
11
+ # Import from the unified style loader module
12
+ from .style_loader import (
13
+ # Re-export defaults for backwards compatibility
14
+ DEFAULT_STYLE_PARAMS,
15
+ DEFAULT_INTRO_STYLE as _DEFAULT_INTRO,
16
+ DEFAULT_END_STYLE as _DEFAULT_END,
17
+ # Functions
18
+ load_style_params_from_file,
19
+ apply_style_overrides,
20
+ get_intro_format as _get_intro_format,
21
+ get_end_format as _get_end_format,
22
+ get_video_durations,
23
+ get_existing_images,
24
+ )
47
25
 
48
26
 
49
- def load_style_params(style_params_json, logger):
50
- """Loads style parameters from a JSON file or uses defaults."""
51
- if style_params_json:
52
- try:
53
- with open(style_params_json, "r") as f:
54
- style_params = json.loads(f.read())
55
- logger.info(f"Loaded style parameters from {style_params_json}")
56
- # You might want to add validation here to ensure the structure matches expectations
57
- return style_params
58
- except FileNotFoundError:
59
- logger.error(f"Style parameters configuration file not found: {style_params_json}")
60
- sys.exit(1)
61
- except json.JSONDecodeError as e:
62
- logger.error(f"Invalid JSON in style parameters configuration file: {e}")
63
- sys.exit(1)
64
- except Exception as e:
65
- logger.error(f"Error loading style parameters file {style_params_json}: {e}")
66
- sys.exit(1)
67
- else:
68
- logger.info("No style parameters JSON file provided. Using default styles.")
69
- return DEFAULT_STYLE_PARAMS
27
+ def load_style_params(style_params_json, style_overrides, logger):
28
+ """
29
+ Loads style parameters from a JSON file or uses defaults.
30
+
31
+ This is the main entry point for the local CLI to load styles.
32
+
33
+ Args:
34
+ style_params_json: Path to style JSON file, or None for defaults.
35
+ style_overrides: Dict of "section.key" -> value overrides.
36
+ logger: Logger for messages.
37
+
38
+ Returns:
39
+ Dictionary of style parameters.
40
+ """
41
+ style_params = load_style_params_from_file(
42
+ style_params_json,
43
+ logger=logger,
44
+ exit_on_error=True,
45
+ )
46
+
47
+ if style_overrides:
48
+ apply_style_overrides(style_params, style_overrides, logger)
49
+
50
+ return style_params
51
+
70
52
 
71
53
  def setup_title_format(style_params):
72
- """Sets up the title format dictionary from style parameters."""
73
- intro_params = style_params.get("intro", DEFAULT_STYLE_PARAMS["intro"])
74
- return {
75
- "background_color": intro_params.get("background_color", DEFAULT_STYLE_PARAMS["intro"]["background_color"]),
76
- "background_image": intro_params.get("background_image"),
77
- "font": intro_params.get("font", DEFAULT_STYLE_PARAMS["intro"]["font"]),
78
- "artist_color": intro_params.get("artist_color", DEFAULT_STYLE_PARAMS["intro"]["artist_color"]),
79
- "artist_gradient": intro_params.get("artist_gradient"),
80
- "title_color": intro_params.get("title_color", DEFAULT_STYLE_PARAMS["intro"]["title_color"]),
81
- "title_gradient": intro_params.get("title_gradient"),
82
- "extra_text": intro_params.get("extra_text"),
83
- "extra_text_color": intro_params.get("extra_text_color", DEFAULT_STYLE_PARAMS["intro"]["extra_text_color"]),
84
- "extra_text_gradient": intro_params.get("extra_text_gradient"),
85
- "extra_text_region": intro_params.get("extra_text_region", DEFAULT_STYLE_PARAMS["intro"]["extra_text_region"]),
86
- "title_region": intro_params.get("title_region", DEFAULT_STYLE_PARAMS["intro"]["title_region"]),
87
- "artist_region": intro_params.get("artist_region", DEFAULT_STYLE_PARAMS["intro"]["artist_region"]),
88
- "title_text_transform": intro_params.get("title_text_transform"),
89
- "artist_text_transform": intro_params.get("artist_text_transform"),
90
- }
54
+ """
55
+ Sets up the title format dictionary from style parameters.
56
+
57
+ This is a thin wrapper around style_loader.get_intro_format()
58
+ for backwards compatibility.
59
+ """
60
+ return _get_intro_format(style_params)
91
61
 
92
- def setup_end_format(style_params):
93
- """Sets up the end format dictionary from style parameters."""
94
- end_params = style_params.get("end", DEFAULT_STYLE_PARAMS["end"])
95
- return {
96
- "background_color": end_params.get("background_color", DEFAULT_STYLE_PARAMS["end"]["background_color"]),
97
- "background_image": end_params.get("background_image"),
98
- "font": end_params.get("font", DEFAULT_STYLE_PARAMS["end"]["font"]),
99
- "artist_color": end_params.get("artist_color", DEFAULT_STYLE_PARAMS["end"]["artist_color"]),
100
- "artist_gradient": end_params.get("artist_gradient"),
101
- "title_color": end_params.get("title_color", DEFAULT_STYLE_PARAMS["end"]["title_color"]),
102
- "title_gradient": end_params.get("title_gradient"),
103
- "extra_text": end_params.get("extra_text", DEFAULT_STYLE_PARAMS["end"]["extra_text"]),
104
- "extra_text_color": end_params.get("extra_text_color", DEFAULT_STYLE_PARAMS["end"]["extra_text_color"]),
105
- "extra_text_gradient": end_params.get("extra_text_gradient"),
106
- "extra_text_region": end_params.get("extra_text_region"),
107
- "title_region": end_params.get("title_region"),
108
- "artist_region": end_params.get("artist_region"),
109
- "title_text_transform": end_params.get("title_text_transform"),
110
- "artist_text_transform": end_params.get("artist_text_transform"),
111
- }
112
62
 
113
- def get_video_durations(style_params):
114
- """Gets intro and end video durations from style parameters."""
115
- intro_duration = style_params.get("intro", {}).get("video_duration", DEFAULT_STYLE_PARAMS["intro"]["video_duration"])
116
- end_duration = style_params.get("end", {}).get("video_duration", DEFAULT_STYLE_PARAMS["end"]["video_duration"])
117
- return intro_duration, end_duration
63
+ def setup_end_format(style_params):
64
+ """
65
+ Sets up the end format dictionary from style parameters.
66
+
67
+ This is a thin wrapper around style_loader.get_end_format()
68
+ for backwards compatibility.
69
+ """
70
+ return _get_end_format(style_params)
118
71
 
119
- def get_existing_images(style_params):
120
- """Gets existing title and end images from style parameters."""
121
- existing_title_image = style_params.get("intro", {}).get("existing_image")
122
- existing_end_image = style_params.get("end", {}).get("existing_image")
123
- return existing_title_image, existing_end_image
124
72
 
125
73
  def setup_ffmpeg_command(log_level):
126
74
  """Sets up the base ffmpeg command string based on log level."""
127
- # Path to the Windows PyInstaller frozen bundled ffmpeg.exe, or the system-installed FFmpeg binary on Mac/Linux
75
+ # Path to the Windows PyInstaller frozen bundled ffmpeg.exe,
76
+ # or the system-installed FFmpeg binary on Mac/Linux
128
77
  ffmpeg_path = os.path.join(sys._MEIPASS, "ffmpeg.exe") if getattr(sys, "frozen", False) else "ffmpeg"
129
78
  ffmpeg_base_command = f"{ffmpeg_path} -hide_banner -nostats"
130
79
  if log_level == logging.DEBUG:
@@ -3,7 +3,6 @@ import glob
3
3
  import logging
4
4
  import shutil
5
5
  import tempfile
6
- import yt_dlp.YoutubeDL as ydl
7
6
  from .utils import sanitize_filename
8
7
 
9
8
 
@@ -39,64 +38,38 @@ class FileHandler:
39
38
 
40
39
  return copied_file_name
41
40
 
42
- def download_video(self, url, output_filename_no_extension, cookies_str=None):
43
- self.logger.debug(f"Downloading media from URL {url} to filename {output_filename_no_extension} + (as yet) unknown extension")
44
-
45
- ydl_opts = {
46
- "quiet": True,
47
- "format": "bv*+ba/b", # if a combined video + audio format is better than the best video-only format use the combined format
48
- "outtmpl": f"{output_filename_no_extension}.%(ext)s",
49
- # Enhanced anti-detection options
50
- "user_agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
51
- "referer": "https://www.youtube.com/",
52
- "sleep_interval": 1,
53
- "max_sleep_interval": 3,
54
- "fragment_retries": 3,
55
- "extractor_retries": 3,
56
- "retries": 3,
57
- # Headers to appear more human
58
- "http_headers": {
59
- "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
60
- "Accept-Language": "en-us,en;q=0.5",
61
- "Accept-Encoding": "gzip, deflate",
62
- "DNT": "1",
63
- "Connection": "keep-alive",
64
- "Upgrade-Insecure-Requests": "1",
65
- },
66
- }
67
-
68
- # Add cookies if provided
69
- if cookies_str:
70
- self.logger.info("Using provided cookies for enhanced YouTube download access")
71
- # Save cookies to a temporary file
72
- import tempfile
73
- with tempfile.NamedTemporaryFile(mode='w', suffix='.txt', delete=False) as f:
74
- f.write(cookies_str)
75
- ydl_opts['cookiefile'] = f.name
76
- else:
77
- self.logger.info("No cookies provided for download - attempting standard download")
78
-
79
- try:
80
- with ydl(ydl_opts) as ydl_instance:
81
- ydl_instance.download([url])
82
-
83
- # Search for the file with any extension
84
- downloaded_files = glob.glob(f"{output_filename_no_extension}.*")
85
- if downloaded_files:
86
- downloaded_file_name = downloaded_files[0] # Assume the first match is the correct one
87
- self.logger.info(f"Download finished, returning downloaded filename: {downloaded_file_name}")
88
- return downloaded_file_name
89
- else:
90
- self.logger.error("No files found matching the download pattern.")
91
- return None
92
- finally:
93
- # Clean up temporary cookie file if it was created
94
- if cookies_str and 'cookiefile' in ydl_opts:
95
- try:
96
- import os
97
- os.unlink(ydl_opts['cookiefile'])
98
- except:
99
- pass
41
+ def download_audio_from_fetcher_result(self, filepath, output_filename_no_extension):
42
+ """
43
+ Handle audio that was downloaded via the AudioFetcher.
44
+
45
+ This method copies/moves the downloaded file to the expected location
46
+ and returns the path with the correct naming convention.
47
+
48
+ Args:
49
+ filepath: Path to the downloaded audio file from AudioFetcher
50
+ output_filename_no_extension: Desired output filename without extension
51
+
52
+ Returns:
53
+ Path to the renamed/copied audio file
54
+ """
55
+ if not os.path.isfile(filepath):
56
+ self.logger.error(f"Downloaded file not found: {filepath}")
57
+ return None
58
+
59
+ # Get the extension from the downloaded file
60
+ ext = os.path.splitext(filepath)[1]
61
+ target_path = f"{output_filename_no_extension}{ext}"
62
+
63
+ # If source and target are the same, no action needed
64
+ if os.path.abspath(filepath) == os.path.abspath(target_path):
65
+ self.logger.debug(f"Downloaded file already at target location: {target_path}")
66
+ return target_path
67
+
68
+ # Copy the file to the target location
69
+ self.logger.debug(f"Copying downloaded file from {filepath} to {target_path}")
70
+ shutil.copy2(filepath, target_path)
71
+
72
+ return target_path
100
73
 
101
74
  def extract_still_image_from_video(self, input_filename, output_filename_no_extension):
102
75
  output_filename = output_filename_no_extension + ".png"