easyrip 4.9.1__py3-none-any.whl → 4.11.0__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.
easyrip/easyrip_log.py CHANGED
@@ -397,8 +397,6 @@ class log:
397
397
  **fmt_kwargs,
398
398
  )
399
399
 
400
- warn = warning
401
-
402
400
  @classmethod
403
401
  def error(
404
402
  cls,
@@ -428,8 +426,6 @@ class log:
428
426
  **fmt_kwargs,
429
427
  )
430
428
 
431
- err = error
432
-
433
429
  @classmethod
434
430
  def send(
435
431
  cls,
easyrip/global_val.py CHANGED
@@ -3,7 +3,7 @@ import sys
3
3
  from pathlib import Path
4
4
 
5
5
  PROJECT_NAME = "Easy Rip"
6
- PROJECT_VERSION = "4.9.1"
6
+ PROJECT_VERSION = "4.11.0"
7
7
  PROJECT_TITLE = f"{PROJECT_NAME} v{PROJECT_VERSION}"
8
8
  PROJECT_URL = "https://github.com/op200/EasyRip"
9
9
  PROJECT_RELEASE_API = "https://api.github.com/repos/op200/EasyRip/releases/latest"
easyrip/ripper/ripper.py CHANGED
@@ -1081,6 +1081,8 @@ class Ripper:
1081
1081
  soft_sub_list = [Path(s) for s in soft_sub.split("?")]
1082
1082
 
1083
1083
  subset_folder = Path(self.output_dir) / f"subset_temp_{temp_name}"
1084
+ if not soft_sub_list:
1085
+ log.warning("-soft-sub is empty")
1084
1086
  log.info("-soft-sub list = {}", soft_sub_list)
1085
1087
 
1086
1088
  # 临时翻译
@@ -2,11 +2,13 @@ import enum
2
2
  import itertools
3
3
  import re
4
4
  from dataclasses import dataclass, field
5
+ from functools import total_ordering
5
6
  from pathlib import Path
7
+ from typing import Self
6
8
 
7
9
  from ...easyrip_log import log
8
10
  from ...easyrip_mlang import Mlang_exception
9
- from ...utils import read_text, uudecode_ssa, uuencode_ssa
11
+ from ...utils import read_text, time_str_to_sec, uudecode_ssa, uuencode_ssa
10
12
 
11
13
 
12
14
  class Style_fmt_it(enum.Enum):
@@ -63,7 +65,7 @@ class Script_info:
63
65
  class Style_data:
64
66
  Name: str
65
67
  Fontname: str
66
- Fontsize: int
68
+ Fontsize: float
67
69
  PrimaryColour: str
68
70
  SecondaryColour: str
69
71
  OutlineColour: str
@@ -212,7 +214,7 @@ class Styles:
212
214
  res = Style_data(
213
215
  Name=style_tuple[self.fmt_index[Style_fmt_it.Name]],
214
216
  Fontname=style_tuple[self.fmt_index[Style_fmt_it.Fontname]],
215
- Fontsize=int(style_tuple[self.fmt_index[Style_fmt_it.Fontsize]]),
217
+ Fontsize=float(style_tuple[self.fmt_index[Style_fmt_it.Fontsize]]),
216
218
  PrimaryColour=style_tuple[self.fmt_index[Style_fmt_it.PrimaryColour]],
217
219
  SecondaryColour=style_tuple[
218
220
  self.fmt_index[Style_fmt_it.SecondaryColour]
@@ -264,6 +266,75 @@ class Styles:
264
266
  )
265
267
 
266
268
 
269
+ @total_ordering
270
+ class Ass_time:
271
+ def __init__(
272
+ self,
273
+ h: int = 0,
274
+ m: int = 0,
275
+ s: int = 0,
276
+ ms: int = 0,
277
+ ) -> None:
278
+ self.h = h
279
+ self.m = m
280
+ self.s = s
281
+ self.ms = ms
282
+
283
+ def __str__(self) -> str:
284
+ return f"{self.h:02d}:{self.m:02d}:{self.s:02d}.{self.ms // 10:02d}"
285
+
286
+ def __hash__(self) -> int:
287
+ return hash((self.h, self.m, self.s, self.ms))
288
+
289
+ def __eq__(self, value: object) -> bool:
290
+ if isinstance(value, Ass_time):
291
+ return (self.h, self.m, self.s, self.ms) == (
292
+ value.h,
293
+ value.m,
294
+ value.s,
295
+ value.ms,
296
+ )
297
+ return NotImplemented
298
+
299
+ def __lt__(self, value: object) -> bool:
300
+ if isinstance(value, Ass_time):
301
+ return (self.h, self.m, self.s, self.ms) < (
302
+ value.h,
303
+ value.m,
304
+ value.s,
305
+ value.ms,
306
+ )
307
+ return NotImplemented
308
+
309
+ def __add__(self, other: object) -> Self:
310
+ if isinstance(other, Ass_time):
311
+ return self.__class__.from_ms(self.total_ms() + other.total_ms())
312
+ return NotImplemented
313
+
314
+ def __sub__(self, other: object) -> Self:
315
+ if isinstance(other, Ass_time):
316
+ return self.__class__.from_ms(self.total_ms() - other.total_ms())
317
+ return NotImplemented
318
+
319
+ @classmethod
320
+ def from_ms(cls, ms: int) -> Self:
321
+ return cls(
322
+ ms // 3_600_000,
323
+ (ms % 3_600_000) // 60_000,
324
+ (ms % 60_000) // 1000,
325
+ ms % 1000,
326
+ )
327
+
328
+ @classmethod
329
+ def from_str(cls, ass_time_str: str) -> Self:
330
+ return cls.from_ms(
331
+ round(time_str_to_sec(ass_time_str) * 1000),
332
+ )
333
+
334
+ def total_ms(self) -> int:
335
+ return self.h * 3_600_000 + self.m * 60_000 + self.s * 1000 + self.ms
336
+
337
+
267
338
  class Event_fmt_it(enum.Enum):
268
339
  Layer = "Layer"
269
340
  Start = "Start"
@@ -291,8 +362,8 @@ class Event_data:
291
362
  type: Event_type
292
363
 
293
364
  Layer: int
294
- Start: str
295
- End: str
365
+ Start: Ass_time
366
+ End: Ass_time
296
367
  Style: str
297
368
  Name: str
298
369
  MarginL: int
@@ -451,8 +522,12 @@ class Events:
451
522
  res = Event_data(
452
523
  type=event_type,
453
524
  Layer=int(event_tuple[self.fmt_index[Event_fmt_it.Layer]]),
454
- Start=event_tuple[self.fmt_index[Event_fmt_it.Start]],
455
- End=event_tuple[self.fmt_index[Event_fmt_it.End]],
525
+ Start=Ass_time.from_str(
526
+ event_tuple[self.fmt_index[Event_fmt_it.Start]],
527
+ ),
528
+ End=Ass_time.from_str(
529
+ event_tuple[self.fmt_index[Event_fmt_it.End]],
530
+ ),
456
531
  Style=event_tuple[self.fmt_index[Event_fmt_it.Style]],
457
532
  Name=event_tuple[self.fmt_index[Event_fmt_it.Name]],
458
533
  MarginL=int(event_tuple[self.fmt_index[Event_fmt_it.MarginL]]),
@@ -496,7 +571,11 @@ class Events:
496
571
  )
497
572
  for event in self.data
498
573
  if (drop_non_render is False)
499
- or (event.type != Event_type.Comment and event.Text)
574
+ or (
575
+ event.type != Event_type.Comment
576
+ and event.Text
577
+ and event.Start < event.End
578
+ )
500
579
  ),
501
580
  )
502
581
  )
@@ -613,143 +692,156 @@ class Ass:
613
692
  new_unknown_data: Unknown_data | None = None
614
693
 
615
694
  for line in filter(bool, map(str.strip, read_text(path).splitlines())):
616
- if line.startswith("[") and line.endswith("]"):
617
- if new_unknown_data is not None:
618
- self.unknown_data.append(new_unknown_data)
619
- new_unknown_data = None
620
-
621
- match head := line[1:-1]:
622
- case "Script Info":
623
- state = State.script_info
624
- case "V4+ Styles":
625
- state = State.styles
626
- case "Fonts":
627
- state = State.fonts
628
- case "Graphics":
629
- state = State.graphics
630
- case "Events":
631
- state = State.events
632
- case _:
633
- if bool(re.search(r"[a-z]", head)):
634
- state = State.unknown
635
- new_unknown_data = Unknown_data(head=head)
636
-
637
- elif line.startswith("Format:"):
638
- formats_tuple = tuple(map(str.strip, line[7:].split(",")))
639
- match state:
640
- case State.styles:
641
- format_order = tuple(map(Style_fmt_it, formats_tuple))
642
- if len(format_order) != 23:
643
- raise Ass_generate_error("Style Format len != 23")
644
-
645
- self.styles.fmt_order = format_order
646
-
647
- case State.events:
648
- try:
649
- format_order = tuple(
650
- map(Event_fmt_it.__getitem__, formats_tuple)
651
- )
652
- except ValueError as e:
653
- raise Ass_generate_error from e
695
+ try:
696
+ if line.startswith("[") and line.endswith("]"):
697
+ if new_unknown_data is not None:
698
+ self.unknown_data.append(new_unknown_data)
699
+ new_unknown_data = None
700
+
701
+ match head := line[1:-1]:
702
+ case "Script Info":
703
+ state = State.script_info
704
+ case "V4+ Styles":
705
+ state = State.styles
706
+ case "Fonts":
707
+ state = State.fonts
708
+ case "Graphics":
709
+ state = State.graphics
710
+ case "Events":
711
+ state = State.events
712
+ case _:
713
+ if bool(re.search(r"[a-z]", head)):
714
+ state = State.unknown
715
+ new_unknown_data = Unknown_data(head=head)
716
+
717
+ elif line.startswith("Format:"):
718
+ formats_tuple = tuple(map(str.strip, line[7:].split(",")))
719
+ match state:
720
+ case State.styles:
721
+ format_order = tuple(map(Style_fmt_it, formats_tuple))
722
+ if len(format_order) != 23:
723
+ raise Ass_generate_error("Style Format len != 23")
724
+
725
+ self.styles.fmt_order = format_order
726
+
727
+ case State.events:
728
+ try:
729
+ format_order = tuple(
730
+ map(Event_fmt_it.__getitem__, formats_tuple)
731
+ )
732
+ except ValueError as e:
733
+ raise Ass_generate_error from e
654
734
 
655
- if len(format_order) != 10:
656
- raise Ass_generate_error("Event Format len != 10")
735
+ if len(format_order) != 10:
736
+ raise Ass_generate_error("Event Format len != 10")
657
737
 
658
- if "Marked" in formats_tuple:
659
- log.error(
660
- "The ASS Events Format version too old: {}",
661
- "It used 'Marked' instead of 'Layer'. 'Marked' has been replaced with 'Layer', which will result in irreversible info loss",
662
- )
738
+ if "Marked" in formats_tuple:
739
+ log.error(
740
+ "The ASS Events Format version too old: {}",
741
+ "It used 'Marked' instead of 'Layer'. 'Marked' has been replaced with 'Layer', which will result in irreversible info loss",
742
+ )
663
743
 
664
- self.events.fmt_order = format_order
744
+ self.events.fmt_order = format_order
665
745
 
666
- else:
667
- match state:
668
- case State.script_info:
669
- self.script_info.data.append(Script_info_data(raw_str=line))
670
-
671
- case State.styles:
672
- if not line.startswith("Style:"):
673
- log.warning("Skip a Style line (illegal format): {}", line)
674
- continue
675
-
676
- style_tuple = tuple(map(str.strip, line[6:].split(",")))
677
- if len(style_tuple) != 23:
678
- log.warning(
679
- "Skip a Style line (Style Format len != 23): {}", line
680
- )
681
- continue
746
+ else:
747
+ match state:
748
+ case State.script_info:
749
+ self.script_info.data.append(Script_info_data(raw_str=line))
750
+
751
+ case State.styles:
752
+ if not line.startswith("Style:"):
753
+ log.warning(
754
+ "Skip a Style line (illegal format): {}", line
755
+ )
756
+ continue
757
+
758
+ style_tuple = tuple(map(str.strip, line[6:].split(",")))
759
+ if len(style_tuple) != 23:
760
+ log.warning(
761
+ "Skip a Style line (Style Format len != 23): {}",
762
+ line,
763
+ )
764
+ continue
682
765
 
683
- self.styles.data.append(self.styles.new_data(style_tuple))
766
+ self.styles.data.append(self.styles.new_data(style_tuple))
684
767
 
685
- case State.graphics:
686
- if line.startswith("filename:"):
687
- self.attachments.data.append(
688
- Attachment_data(
689
- type=Attach_type.Graphics,
690
- name=line[9:].strip(),
691
- data="",
768
+ case State.graphics:
769
+ if line.startswith("filename:"):
770
+ self.attachments.data.append(
771
+ Attachment_data(
772
+ type=Attach_type.Graphics,
773
+ name=line[9:].strip(),
774
+ data="",
775
+ )
776
+ )
777
+ else:
778
+ if self.attachments.data[-1].data is None:
779
+ log.error("Unknown error", deep=True)
780
+ continue
781
+ self.attachments.data[-1].data += line + "\n"
782
+
783
+ case State.fonts:
784
+ if line.startswith("fontname:"):
785
+ self.attachments.data.append(
786
+ Attachment_data(
787
+ type=Attach_type.Fonts,
788
+ name=line[9:].strip(),
789
+ data="",
790
+ )
791
+ )
792
+ else:
793
+ if self.attachments.data[-1].data is None:
794
+ log.error("Unknown error", deep=True)
795
+ continue
796
+ self.attachments.data[-1].data += line + "\n"
797
+
798
+ case State.events:
799
+ event_type: Event_type
800
+ if line.startswith("Dialogue:"):
801
+ event_type = Event_type.Dialogue
802
+ elif line.startswith("Comment:"):
803
+ event_type = Event_type.Comment
804
+ else:
805
+ log.warning(
806
+ "Skip a Event line (illegal format): {}", line
692
807
  )
693
- )
694
- else:
695
- if self.attachments.data[-1].data is None:
696
- log.error("Unknown error", deep=True)
697
808
  continue
698
- self.attachments.data[-1].data += line + "\n"
699
-
700
- case State.fonts:
701
- if line.startswith("fontname:"):
702
- self.attachments.data.append(
703
- Attachment_data(
704
- type=Attach_type.Fonts,
705
- name=line[9:].strip(),
706
- data="",
809
+
810
+ event_tuple = tuple(
811
+ map(
812
+ str.strip,
813
+ line.split(":", maxsplit=1)[1].split(
814
+ ",", maxsplit=9
815
+ ),
707
816
  )
708
817
  )
709
- else:
710
- if self.attachments.data[-1].data is None:
711
- log.error("Unknown error", deep=True)
818
+ if len(event_tuple) != 10:
819
+ log.warning(
820
+ "Skip a Event line (Event Format len != 10): {}",
821
+ line,
822
+ )
712
823
  continue
713
- self.attachments.data[-1].data += line + "\n"
714
-
715
- case State.events:
716
- event_type: Event_type
717
- if line.startswith("Dialogue:"):
718
- event_type = Event_type.Dialogue
719
- elif line.startswith("Comment:"):
720
- event_type = Event_type.Comment
721
- else:
722
- log.warning("Skip a Event line (illegal format): {}", line)
723
- continue
724
-
725
- event_tuple = tuple(
726
- map(
727
- str.strip,
728
- line.split(":", maxsplit=1)[1].split(",", maxsplit=9),
729
- )
730
- )
731
- if len(event_tuple) != 10:
732
- log.warning(
733
- "Skip a Event line (Event Format len != 10): {}", line
824
+
825
+ self.events.data.append(
826
+ self.events.new_data(event_tuple, event_type)
734
827
  )
735
- continue
736
828
 
737
- self.events.data.append(
738
- self.events.new_data(event_tuple, event_type)
739
- )
829
+ case State.unknown:
830
+ if new_unknown_data is None:
831
+ raise Ass_generate_error(
832
+ "Unknown error occurred when read line: {}", line
833
+ )
834
+ new_unknown_data.data.append(line)
740
835
 
741
- case State.unknown:
742
- if new_unknown_data is None:
743
- raise Ass_generate_error(
744
- "Unknown error occurred when read line: {}", line
745
- )
746
- new_unknown_data.data.append(line)
836
+ except Exception as e:
837
+ raise Ass_generate_error("Unkown error in line: {}", line) from e
747
838
 
748
839
  if new_unknown_data is not None:
749
840
  self.unknown_data.append(new_unknown_data)
750
841
 
751
842
  def __str__(
752
843
  self,
844
+ *,
753
845
  drop_non_render: bool = False,
754
846
  drop_unkow_data: bool = False,
755
847
  drop_fonts: bool = False,
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: easyrip
3
- Version: 4.9.1
3
+ Version: 4.11.0
4
4
  Author: op200
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Project-URL: Homepage, https://github.com/op200/EasyRip
@@ -1,10 +1,10 @@
1
1
  easyrip/__init__.py,sha256=PIvSPDgswsIkWL4dsCe87knnxKmtvcrWYzmqAwZix_M,765
2
2
  easyrip/__main__.py,sha256=bPVlHqJb3BG-qZOY4JlJdKj7MKeRb_3EfoMbfoNN-gU,4943
3
3
  easyrip/easyrip_command.py,sha256=X9_8t9Sxl1-gILpsQ5PueCwozTQgjgL2cImzOZ6pO7w,27837
4
- easyrip/easyrip_log.py,sha256=i5r3OPGQ55c3_zCN0fmriPXiWxibq-w35FbNT7VfuuM,15610
4
+ easyrip/easyrip_log.py,sha256=R-dM3CWUBFITtG7GSD1zy4X4MhZqxkoiBPjlIpI76cY,15573
5
5
  easyrip/easyrip_main.py,sha256=QgIrsonjXNin72nv7WWePTlpj9soGZCBVv1cwFNS4a4,44691
6
6
  easyrip/easyrip_prompt.py,sha256=A5S7ybeJSGFkCmwdJ9TCQ_-lde7NWgkbFytZ2KnvkWI,2145
7
- easyrip/global_val.py,sha256=8kU9EXFlb7UoXTfTdW6l038FqRbwAH1iUaWJRPSuLtg,773
7
+ easyrip/global_val.py,sha256=Z9Y8N7MpqegW-5LDs8bn1dhmqjSSbEB2P6Oeye_sJ-4,774
8
8
  easyrip/utils.py,sha256=N1rMF1MyoC-YFBgy10_u29cFoowfhR-5Viea93O7wQ4,8750
9
9
  easyrip/easyrip_config/config.py,sha256=aj6Vg1rJkvICSTZ0ZONznR_MkvVr5u5ngkX_zfZopvU,9859
10
10
  easyrip/easyrip_config/config_key.py,sha256=_jjdKOunskUoG7UUWOz3QZK-s4LF_x6hmM9MKttyS2Q,766
@@ -18,14 +18,14 @@ easyrip/easyrip_web/http_server.py,sha256=iyulCAFQrJlz86Lrr-Dm3fhOnNCf79Bp6fVHhr
18
18
  easyrip/easyrip_web/third_party_api.py,sha256=GhP6LmR1sVMeLLbnj82r-QYjoUdSnyaU9xp0LRnRLsw,4623
19
19
  easyrip/ripper/media_info.py,sha256=mQq_vbQ7S9fWpb39HLkoZlAL-pqNfwxewv6X776Nf50,5078
20
20
  easyrip/ripper/param.py,sha256=y1n2XaW55TJQ_r858pB4kYZVgT6TRpmS5vv9iMEIESc,11736
21
- easyrip/ripper/ripper.py,sha256=yrqVlLLe68RZI9BVVMAEJ4AplrwlvBDt8h0m3yLrO9o,50345
21
+ easyrip/ripper/ripper.py,sha256=xTwKpgkqqhh0x6J8DnE5fnXmEN_Q6ZZAdCPky68P-DE,50437
22
22
  easyrip/ripper/sub_and_font/__init__.py,sha256=cBT7mxL7RRFaJXFPXuZ7RT-YK6FbnanaU5v6U9BOquw,153
23
- easyrip/ripper/sub_and_font/ass.py,sha256=eGi1eIDWAV1Ti_BYIAcAMwrAlXJ5f_zGYte3nNu4PeE,25532
23
+ easyrip/ripper/sub_and_font/ass.py,sha256=hJhVN7CqehN9xW1W295gmkPnG-somqlxnwXzRidbA2M,28645
24
24
  easyrip/ripper/sub_and_font/font.py,sha256=X2dPcPzbwQf3fv_g_mxO-zY7puVAX9Nv-9QHn88q4oA,7745
25
25
  easyrip/ripper/sub_and_font/subset.py,sha256=qGH3H26nHnyGFfFwvktEIKncHpm086DqxYjVhNoVDdM,18654
26
- easyrip-4.9.1.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
27
- easyrip-4.9.1.dist-info/METADATA,sha256=M2A05LL_xR25O-Gx1AY0O0XproQkXhc2e6bfE-AU2F4,3506
28
- easyrip-4.9.1.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
- easyrip-4.9.1.dist-info/entry_points.txt,sha256=D6GBMMTzZ-apgX76KyZ6jxMmIFqGYwU9neeLLni_qKI,49
30
- easyrip-4.9.1.dist-info/top_level.txt,sha256=kuEteBXm-Gf90jRQgH3-fTo-Z-Q6czSuUEqY158H4Ww,8
31
- easyrip-4.9.1.dist-info/RECORD,,
26
+ easyrip-4.11.0.dist-info/licenses/LICENSE,sha256=hIahDEOTzuHCU5J2nd07LWwkLW7Hko4UFO__ffsvB-8,34523
27
+ easyrip-4.11.0.dist-info/METADATA,sha256=-5Cnc5K0zC8oUEFqgcomSavHeKGeejLu-h6-xhysxsA,3507
28
+ easyrip-4.11.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
29
+ easyrip-4.11.0.dist-info/entry_points.txt,sha256=D6GBMMTzZ-apgX76KyZ6jxMmIFqGYwU9neeLLni_qKI,49
30
+ easyrip-4.11.0.dist-info/top_level.txt,sha256=kuEteBXm-Gf90jRQgH3-fTo-Z-Q6czSuUEqY158H4Ww,8
31
+ easyrip-4.11.0.dist-info/RECORD,,