videoconverter-worker 1.0.3__py3-none-any.whl → 1.0.4__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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: videoconverter-worker
3
- Version: 1.0.3
3
+ Version: 1.0.4
4
4
  Summary: VideoConverter Python Worker:从 queue 目录读取任务并执行切分/去字幕/合成
5
5
  License: MIT
6
6
  Keywords: videoconverter,ffmpeg,worker,video
@@ -0,0 +1,10 @@
1
+ ffmpeg_runner.py,sha256=2sYugXkKp-NKj3ahxbwbhAo4G49FDu-0oze-cdJvcY0,12218
2
+ metadata.py,sha256=32zQn7jJ6XTHhunwTn5Xv0qmpjHnap_pkPxY0XI8MBs,3116
3
+ schema.py,sha256=3ILdGl5qSQOSvKfiKWcnaxdyHwV4rDvGnRZIparVp3o,4361
4
+ task_queue.py,sha256=sYQelPRuTbP9g_sPs69xOR3n5SIxGBFxY4EI5ueQrQs,11822
5
+ worker.py,sha256=7sp3Wn6qf2xFtsQpJZEhUXrvb6m8uSmCNbcE4ssapQI,21117
6
+ videoconverter_worker-1.0.4.dist-info/METADATA,sha256=0bWYbcY5_HuBpnwNILPdmRb5LBeNPAiP_rQRfrf4tDM,5139
7
+ videoconverter_worker-1.0.4.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
+ videoconverter_worker-1.0.4.dist-info/entry_points.txt,sha256=qedJjjix02n9Hz8adBioDIpGHghm8S3fQZdFwM5LV1A,83
9
+ videoconverter_worker-1.0.4.dist-info/top_level.txt,sha256=iamWyiqUZ4X0_2UZx6GEk9gsPmiI9qhse_15HqtzUj8,48
10
+ videoconverter_worker-1.0.4.dist-info/RECORD,,
worker.py CHANGED
@@ -8,6 +8,7 @@ Python Worker:从 queue 目录读取任务并执行切分/去字幕/合成,
8
8
  import argparse
9
9
  import logging
10
10
  import sys
11
+ import threading
11
12
  import time
12
13
  from pathlib import Path
13
14
 
@@ -30,6 +31,19 @@ logging.basicConfig(
30
31
  logger = logging.getLogger("worker")
31
32
 
32
33
 
34
+ def _desub_spinner(stop_event: threading.Event) -> None:
35
+ """去字幕阶段同一行跑马灯,避免用户以为死机。"""
36
+ i = 0
37
+ while not stop_event.wait(0.25):
38
+ dots = "." * ((i % 3) + 1)
39
+ try:
40
+ sys.stderr.write("\r [INFO] worker: 去字幕中 " + dots + " ")
41
+ sys.stderr.flush()
42
+ except (OSError, UnicodeEncodeError):
43
+ break
44
+ i += 1
45
+
46
+
33
47
  def process_split_task(store: QueueStore, task: dict) -> None:
34
48
  task_id = task["task_id"]
35
49
  input_file = task["input_file"]
@@ -167,7 +181,7 @@ def _format_duration(sec: float) -> str:
167
181
 
168
182
 
169
183
  def _log_split_to_merge_duration(data: dict, task_id: str, store: QueueStore) -> None:
170
- """若 metadata 含 splitStartedAt,则计算并输出从切分到合成结束的总时长。"""
184
+ """若 metadata 含 splitStartedAt,则计算并输出从切分到合成结束的总时长与产能预估。"""
171
185
  s = data.get("splitStartedAt") or ""
172
186
  if not s:
173
187
  return
@@ -177,10 +191,16 @@ def _log_split_to_merge_duration(data: dict, task_id: str, store: QueueStore) ->
177
191
  if ts.tzinfo is None:
178
192
  ts = ts.replace(tzinfo=timezone.utc)
179
193
  duration_sec = (datetime.now(timezone.utc) - ts).total_seconds()
180
- if duration_sec >= 0:
181
- msg = f"从切分到合成结束总时长: {_format_duration(duration_sec)}"
182
- logger.info("videoId=%s %s", data.get("videoId", ""), msg)
183
- store.add_log(task_id, "INFO", msg)
194
+ if duration_sec < 0:
195
+ return
196
+ msg = f"从切分到合成结束总时长: {_format_duration(duration_sec)}"
197
+ processed = get_processed_chunks(data)
198
+ if processed and duration_sec > 0:
199
+ src_duration_sec = processed[-1]["endTime"] - processed[0]["startTime"]
200
+ capacity = (src_duration_sec / 3600.0) / (duration_sec / 3600.0)
201
+ msg += f",产能预估: 约 {capacity:.2f} 原视频小时/小时"
202
+ logger.info("videoId=%s %s", data.get("videoId", ""), msg)
203
+ store.add_log(task_id, "INFO", msg)
184
204
  except Exception:
185
205
  pass
186
206
 
@@ -332,27 +352,39 @@ def run_simple_compose(
332
352
  chunk_list = [c for c in (metadata.get("chunks") or []) if c.get("originalPath")]
333
353
  logger.info("切分完成: %d 块,开始去字幕", len(chunk_list))
334
354
 
335
- for ch in chunk_list:
336
- rel = ch.get("originalPath", "")
337
- if not rel:
338
- continue
339
- chunk_path = Path(output_dir) / rel
340
- if not chunk_path.exists():
341
- continue
342
- chunk_id = ch.get("chunkId", "")
343
- out_dir_v = Path(output_dir) / video_id
344
- out_dir_v.mkdir(parents=True, exist_ok=True)
345
- output_file = out_dir_v / (Path(chunk_path).stem + "_desub.mp4")
346
- cfg = dict(config)
347
- cfg["inputPath"] = str(chunk_path)
348
- cfg["outputPath"] = str(output_file)
349
- cfg["startTime"] = 0
350
- cfg["endTime"] = 0
351
- cfg["forceKeyframeAtStart"] = True
352
- run_desubtitle(cfg, str(chunk_path), str(output_file))
353
- meta_path = Path(output_dir) / video_id / "metadata.json"
354
- if meta_path.exists():
355
- update_chunk_processed(str(meta_path), chunk_id, str(output_file))
355
+ stop_spinner = threading.Event()
356
+ spinner = threading.Thread(target=_desub_spinner, args=(stop_spinner,), daemon=True)
357
+ spinner.start()
358
+ try:
359
+ for ch in chunk_list:
360
+ rel = ch.get("originalPath", "")
361
+ if not rel:
362
+ continue
363
+ chunk_path = Path(output_dir) / rel
364
+ if not chunk_path.exists():
365
+ continue
366
+ chunk_id = ch.get("chunkId", "")
367
+ out_dir_v = Path(output_dir) / video_id
368
+ out_dir_v.mkdir(parents=True, exist_ok=True)
369
+ output_file = out_dir_v / (Path(chunk_path).stem + "_desub.mp4")
370
+ cfg = dict(config)
371
+ cfg["inputPath"] = str(chunk_path)
372
+ cfg["outputPath"] = str(output_file)
373
+ cfg["startTime"] = 0
374
+ cfg["endTime"] = 0
375
+ cfg["forceKeyframeAtStart"] = True
376
+ run_desubtitle(cfg, str(chunk_path), str(output_file))
377
+ meta_path = Path(output_dir) / video_id / "metadata.json"
378
+ if meta_path.exists():
379
+ update_chunk_processed(str(meta_path), chunk_id, str(output_file))
380
+ finally:
381
+ stop_spinner.set()
382
+ spinner.join(timeout=1.0)
383
+ try:
384
+ sys.stderr.write("\n")
385
+ sys.stderr.flush()
386
+ except (OSError, UnicodeEncodeError):
387
+ pass
356
388
 
357
389
  data = load_metadata(str(Path(output_dir) / video_id / "metadata.json"))
358
390
  processed = get_processed_chunks(data)
@@ -363,7 +395,12 @@ def run_simple_compose(
363
395
  out_file = Path(output_dir) / f"{video_id}_merged.mp4"
364
396
  merge_chunks(data, start_t, end_t, str(out_file))
365
397
  elapsed = time.time() - t0
366
- logger.info("简易模式完成: %s,从切分到合成结束总时长: %s", out_file, _format_duration(elapsed))
398
+ src_duration_sec = end_sec - start_sec
399
+ capacity = (src_duration_sec / 3600.0) / (elapsed / 3600.0) if elapsed > 0 else 0
400
+ logger.info(
401
+ "简易模式完成: %s,从切分到合成结束总时长: %s,产能预估: 约 %.2f 原视频小时/小时",
402
+ out_file, _format_duration(elapsed), capacity,
403
+ )
367
404
  return str(out_file)
368
405
 
369
406
 
@@ -1,10 +0,0 @@
1
- ffmpeg_runner.py,sha256=2sYugXkKp-NKj3ahxbwbhAo4G49FDu-0oze-cdJvcY0,12218
2
- metadata.py,sha256=32zQn7jJ6XTHhunwTn5Xv0qmpjHnap_pkPxY0XI8MBs,3116
3
- schema.py,sha256=3ILdGl5qSQOSvKfiKWcnaxdyHwV4rDvGnRZIparVp3o,4361
4
- task_queue.py,sha256=sYQelPRuTbP9g_sPs69xOR3n5SIxGBFxY4EI5ueQrQs,11822
5
- worker.py,sha256=2t7mFIV2i_qJJxN55wNrU6ZmPbG4wT9YEjzECi04BR8,19664
6
- videoconverter_worker-1.0.3.dist-info/METADATA,sha256=8qyb44UnKGgChp4v3F8SuHkL4EpK6IepBhdMLJ7UWTQ,5139
7
- videoconverter_worker-1.0.3.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
8
- videoconverter_worker-1.0.3.dist-info/entry_points.txt,sha256=qedJjjix02n9Hz8adBioDIpGHghm8S3fQZdFwM5LV1A,83
9
- videoconverter_worker-1.0.3.dist-info/top_level.txt,sha256=iamWyiqUZ4X0_2UZx6GEk9gsPmiI9qhse_15HqtzUj8,48
10
- videoconverter_worker-1.0.3.dist-info/RECORD,,