karaoke-gen 0.61.1__tar.gz → 0.62.1__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.

Potentially problematic release.


This version of karaoke-gen might be problematic. Click here for more details.

Files changed (22) hide show
  1. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/PKG-INFO +3 -2
  2. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/config.py +37 -4
  3. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/karaoke_gen.py +23 -3
  4. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/utils/gen_cli.py +18 -0
  5. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/pyproject.toml +1 -1
  6. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/LICENSE +0 -0
  7. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/README.md +0 -0
  8. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/__init__.py +0 -0
  9. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/audio_processor.py +0 -0
  10. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/file_handler.py +0 -0
  11. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/karaoke_finalise/__init__.py +0 -0
  12. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/karaoke_finalise/karaoke_finalise.py +0 -0
  13. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/lyrics_processor.py +0 -0
  14. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/metadata.py +0 -0
  15. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/resources/AvenirNext-Bold.ttf +0 -0
  16. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/resources/Montserrat-Bold.ttf +0 -0
  17. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/resources/Oswald-Bold.ttf +0 -0
  18. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/resources/Oswald-SemiBold.ttf +0 -0
  19. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/resources/Zurich_Cn_BT_Bold.ttf +0 -0
  20. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/utils/__init__.py +0 -0
  21. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/utils/bulk_cli.py +0 -0
  22. {karaoke_gen-0.61.1 → karaoke_gen-0.62.1}/karaoke_gen/video_generator.py +0 -0
@@ -1,8 +1,9 @@
1
- Metadata-Version: 2.3
1
+ Metadata-Version: 2.4
2
2
  Name: karaoke-gen
3
- Version: 0.61.1
3
+ Version: 0.62.1
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
+ License-File: LICENSE
6
7
  Author: Andrew Beveridge
7
8
  Author-email: andrew@beveridge.uk
8
9
  Requires-Python: >=3.10,<3.14
@@ -46,15 +46,43 @@ DEFAULT_STYLE_PARAMS = {
46
46
  }
47
47
 
48
48
 
49
- def load_style_params(style_params_json, logger):
49
+ def apply_style_overrides(style_params, overrides, logger):
50
+ """Recursively applies overrides to the style parameters."""
51
+ for key, value in overrides.items():
52
+ keys = key.split('.')
53
+ current_level = style_params
54
+ for i, k in enumerate(keys):
55
+ if i == len(keys) - 1:
56
+ if k in current_level:
57
+ # Attempt to cast the value to the type of the existing value
58
+ try:
59
+ original_type = type(current_level[k])
60
+ if original_type == bool:
61
+ # Handle boolean conversion
62
+ value = value.lower() in ('true', '1', 't', 'y', 'yes')
63
+ else:
64
+ value = original_type(value)
65
+ except (ValueError, TypeError) as e:
66
+ logger.warning(f"Could not cast override value '{value}' for key '{key}' to original type. Using as string. Error: {e}")
67
+ current_level[k] = value
68
+ logger.info(f"Overrode style: {key} = {value}")
69
+ else:
70
+ logger.warning(f"Override key '{key}' not found in style parameters.")
71
+ elif k in current_level and isinstance(current_level[k], dict):
72
+ current_level = current_level[k]
73
+ else:
74
+ logger.warning(f"Override key part '{k}' not found or not a dictionary for key '{key}'.")
75
+ break
76
+
77
+
78
+ def load_style_params(style_params_json, style_overrides, logger):
50
79
  """Loads style parameters from a JSON file or uses defaults."""
80
+ style_params = {}
51
81
  if style_params_json:
52
82
  try:
53
83
  with open(style_params_json, "r") as f:
54
84
  style_params = json.loads(f.read())
55
85
  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
86
  except FileNotFoundError:
59
87
  logger.error(f"Style parameters configuration file not found: {style_params_json}")
60
88
  sys.exit(1)
@@ -66,7 +94,12 @@ def load_style_params(style_params_json, logger):
66
94
  sys.exit(1)
67
95
  else:
68
96
  logger.info("No style parameters JSON file provided. Using default styles.")
69
- return DEFAULT_STYLE_PARAMS
97
+ style_params = DEFAULT_STYLE_PARAMS
98
+
99
+ if style_overrides:
100
+ apply_style_overrides(style_params, style_overrides, logger)
101
+
102
+ return style_params
70
103
 
71
104
  def setup_title_format(style_params):
72
105
  """Sets up the title format dictionary from style parameters."""
@@ -67,6 +67,7 @@ class KaraokePrep:
67
67
  subtitle_offset_ms=0,
68
68
  # Style Configuration
69
69
  style_params_json=None,
70
+ style_overrides=None,
70
71
  # Add the new parameter
71
72
  skip_separation=False,
72
73
  # YouTube/Online Configuration
@@ -124,13 +125,23 @@ class KaraokePrep:
124
125
 
125
126
  # Style Config - Keep needed ones
126
127
  self.render_bounding_boxes = render_bounding_boxes # Passed to VideoGenerator
127
- self.style_params_json = style_params_json # Passed to LyricsProcessor
128
+ self.style_params_json = style_params_json
129
+ self.style_overrides = style_overrides
130
+ self.temp_style_file = None
128
131
 
129
132
  # YouTube/Online Config
130
133
  self.cookies_str = cookies_str # Passed to metadata extraction and file download
131
134
 
132
135
  # Load style parameters using the config module
133
- self.style_params = load_style_params(self.style_params_json, self.logger)
136
+ self.style_params = load_style_params(self.style_params_json, self.style_overrides, self.logger)
137
+
138
+ # If overrides were applied, write to a temp file and update the path
139
+ if self.style_overrides:
140
+ with tempfile.NamedTemporaryFile(mode='w', delete=False, suffix=".json") as temp_file:
141
+ json.dump(self.style_params, temp_file, indent=2)
142
+ self.temp_style_file = temp_file.name
143
+ self.style_params_json = self.temp_style_file
144
+ self.logger.info(f"Style overrides applied. Using temporary style file: {self.temp_style_file}")
134
145
 
135
146
  # Set up title and end formats using the config module
136
147
  self.title_format = setup_title_format(self.style_params)
@@ -199,6 +210,15 @@ class KaraokePrep:
199
210
  else:
200
211
  self.logger.debug(f"Overall output dir {self.output_dir} already exists")
201
212
 
213
+ def __del__(self):
214
+ # Cleanup the temporary style file if it was created
215
+ if self.temp_style_file and os.path.exists(self.temp_style_file):
216
+ try:
217
+ os.remove(self.temp_style_file)
218
+ self.logger.debug(f"Removed temporary style file: {self.temp_style_file}")
219
+ except OSError as e:
220
+ self.logger.warning(f"Error removing temporary style file {self.temp_style_file}: {e}")
221
+
202
222
  # Compatibility methods for tests - these call the new functions in metadata.py
203
223
  def extract_info_for_online_media(self, input_url=None, input_artist=None, input_title=None):
204
224
  """Compatibility method that calls the function in metadata.py"""
@@ -476,7 +496,7 @@ class KaraokePrep:
476
496
  # Check if separation_future was the placeholder or a real task
477
497
  # The result index in `results` depends on whether transcription_future existed
478
498
  separation_result_index = 1 if transcription_future else 0
479
- if separation_future is not None and not isinstance(separation_future, asyncio.Task) and len(results) > separation_result_index:
499
+ if separation_future is not None and isinstance(separation_future, asyncio.Task) and len(results) > separation_result_index:
480
500
  self.logger.info("Processing separation results...")
481
501
  try:
482
502
  separation_results = results[separation_result_index]
@@ -215,6 +215,11 @@ async def async_main():
215
215
  "--style_params_json",
216
216
  help="Optional: Path to JSON file containing style configuration. Example: --style_params_json='/path/to/style_params.json'",
217
217
  )
218
+ style_group.add_argument(
219
+ "--style_override",
220
+ action="append",
221
+ help="Optional: Override a style parameter. Can be used multiple times. Example: --style_override 'intro.background_image=/path/to/new_image.png'",
222
+ )
218
223
 
219
224
  # Finalisation Configuration
220
225
  finalise_group = parser.add_argument_group("Finalisation Configuration")
@@ -283,6 +288,17 @@ async def async_main():
283
288
 
284
289
  args = parser.parse_args()
285
290
 
291
+ # Process style overrides
292
+ style_overrides = {}
293
+ if args.style_override:
294
+ for override in args.style_override:
295
+ try:
296
+ key, value = override.split("=", 1)
297
+ style_overrides[key] = value
298
+ except ValueError:
299
+ logger.error(f"Invalid style override format: {override}. Must be in 'key=value' format.")
300
+ sys.exit(1)
301
+
286
302
  # Handle test email template case first
287
303
  if args.test_email_template:
288
304
  log_level = getattr(logging, args.log_level.upper())
@@ -354,6 +370,7 @@ async def async_main():
354
370
  skip_transcription_review=args.skip_transcription_review,
355
371
  subtitle_offset_ms=args.subtitle_offset_ms,
356
372
  style_params_json=args.style_params_json,
373
+ style_overrides=style_overrides,
357
374
  )
358
375
  # No await needed for constructor
359
376
  kprep = kprep_coroutine
@@ -671,6 +688,7 @@ async def async_main():
671
688
  skip_transcription_review=args.skip_transcription_review,
672
689
  subtitle_offset_ms=args.subtitle_offset_ms,
673
690
  style_params_json=args.style_params_json,
691
+ style_overrides=style_overrides,
674
692
  )
675
693
  # No await needed for constructor
676
694
  kprep = kprep_coroutine
@@ -1,6 +1,6 @@
1
1
  [tool.poetry]
2
2
  name = "karaoke-gen"
3
- version = "0.61.1"
3
+ version = "0.62.1"
4
4
  description = "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
  authors = ["Andrew Beveridge <andrew@beveridge.uk>"]
6
6
  license = "MIT"
File without changes
File without changes