lyrics-transcriber 0.30.0__py3-none-any.whl → 0.32.1__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 (88) hide show
  1. lyrics_transcriber/__init__.py +2 -1
  2. lyrics_transcriber/cli/{main.py → cli_main.py} +47 -14
  3. lyrics_transcriber/core/config.py +35 -0
  4. lyrics_transcriber/core/controller.py +164 -166
  5. lyrics_transcriber/correction/anchor_sequence.py +471 -0
  6. lyrics_transcriber/correction/corrector.py +256 -0
  7. lyrics_transcriber/correction/handlers/__init__.py +0 -0
  8. lyrics_transcriber/correction/handlers/base.py +30 -0
  9. lyrics_transcriber/correction/handlers/extend_anchor.py +91 -0
  10. lyrics_transcriber/correction/handlers/levenshtein.py +147 -0
  11. lyrics_transcriber/correction/handlers/no_space_punct_match.py +98 -0
  12. lyrics_transcriber/correction/handlers/relaxed_word_count_match.py +55 -0
  13. lyrics_transcriber/correction/handlers/repeat.py +71 -0
  14. lyrics_transcriber/correction/handlers/sound_alike.py +223 -0
  15. lyrics_transcriber/correction/handlers/syllables_match.py +182 -0
  16. lyrics_transcriber/correction/handlers/word_count_match.py +54 -0
  17. lyrics_transcriber/correction/handlers/word_operations.py +135 -0
  18. lyrics_transcriber/correction/phrase_analyzer.py +426 -0
  19. lyrics_transcriber/correction/text_utils.py +30 -0
  20. lyrics_transcriber/lyrics/base_lyrics_provider.py +125 -0
  21. lyrics_transcriber/lyrics/genius.py +73 -0
  22. lyrics_transcriber/lyrics/spotify.py +82 -0
  23. lyrics_transcriber/output/ass/__init__.py +21 -0
  24. lyrics_transcriber/output/{ass.py → ass/ass.py} +150 -690
  25. lyrics_transcriber/output/ass/ass_specs.txt +732 -0
  26. lyrics_transcriber/output/ass/config.py +37 -0
  27. lyrics_transcriber/output/ass/constants.py +23 -0
  28. lyrics_transcriber/output/ass/event.py +94 -0
  29. lyrics_transcriber/output/ass/formatters.py +132 -0
  30. lyrics_transcriber/output/ass/lyrics_line.py +219 -0
  31. lyrics_transcriber/output/ass/lyrics_screen.py +252 -0
  32. lyrics_transcriber/output/ass/section_detector.py +89 -0
  33. lyrics_transcriber/output/ass/section_screen.py +106 -0
  34. lyrics_transcriber/output/ass/style.py +187 -0
  35. lyrics_transcriber/output/cdg.py +503 -0
  36. lyrics_transcriber/output/cdgmaker/__init__.py +0 -0
  37. lyrics_transcriber/output/cdgmaker/cdg.py +262 -0
  38. lyrics_transcriber/output/cdgmaker/composer.py +1919 -0
  39. lyrics_transcriber/output/cdgmaker/config.py +151 -0
  40. lyrics_transcriber/output/cdgmaker/images/instrumental.png +0 -0
  41. lyrics_transcriber/output/cdgmaker/images/intro.png +0 -0
  42. lyrics_transcriber/output/cdgmaker/pack.py +507 -0
  43. lyrics_transcriber/output/cdgmaker/render.py +346 -0
  44. lyrics_transcriber/output/cdgmaker/transitions/centertexttoplogobottomtext.png +0 -0
  45. lyrics_transcriber/output/cdgmaker/transitions/circlein.png +0 -0
  46. lyrics_transcriber/output/cdgmaker/transitions/circleout.png +0 -0
  47. lyrics_transcriber/output/cdgmaker/transitions/fizzle.png +0 -0
  48. lyrics_transcriber/output/cdgmaker/transitions/largecentertexttoplogo.png +0 -0
  49. lyrics_transcriber/output/cdgmaker/transitions/rectangle.png +0 -0
  50. lyrics_transcriber/output/cdgmaker/transitions/spiral.png +0 -0
  51. lyrics_transcriber/output/cdgmaker/transitions/topleftmusicalnotes.png +0 -0
  52. lyrics_transcriber/output/cdgmaker/transitions/wipein.png +0 -0
  53. lyrics_transcriber/output/cdgmaker/transitions/wipeleft.png +0 -0
  54. lyrics_transcriber/output/cdgmaker/transitions/wipeout.png +0 -0
  55. lyrics_transcriber/output/cdgmaker/transitions/wiperight.png +0 -0
  56. lyrics_transcriber/output/cdgmaker/utils.py +132 -0
  57. lyrics_transcriber/output/fonts/AvenirNext-Bold.ttf +0 -0
  58. lyrics_transcriber/output/fonts/DMSans-VariableFont_opsz,wght.ttf +0 -0
  59. lyrics_transcriber/output/fonts/DMSerifDisplay-Regular.ttf +0 -0
  60. lyrics_transcriber/output/fonts/Oswald-SemiBold.ttf +0 -0
  61. lyrics_transcriber/output/fonts/Zurich_Cn_BT_Bold.ttf +0 -0
  62. lyrics_transcriber/output/fonts/arial.ttf +0 -0
  63. lyrics_transcriber/output/fonts/georgia.ttf +0 -0
  64. lyrics_transcriber/output/fonts/verdana.ttf +0 -0
  65. lyrics_transcriber/output/generator.py +140 -171
  66. lyrics_transcriber/output/lyrics_file.py +102 -0
  67. lyrics_transcriber/output/plain_text.py +91 -0
  68. lyrics_transcriber/output/segment_resizer.py +416 -0
  69. lyrics_transcriber/output/subtitles.py +328 -302
  70. lyrics_transcriber/output/video.py +219 -0
  71. lyrics_transcriber/review/__init__.py +1 -0
  72. lyrics_transcriber/review/server.py +138 -0
  73. lyrics_transcriber/storage/dropbox.py +110 -134
  74. lyrics_transcriber/transcribers/audioshake.py +171 -105
  75. lyrics_transcriber/transcribers/base_transcriber.py +149 -0
  76. lyrics_transcriber/transcribers/whisper.py +267 -133
  77. lyrics_transcriber/types.py +454 -0
  78. {lyrics_transcriber-0.30.0.dist-info → lyrics_transcriber-0.32.1.dist-info}/METADATA +14 -3
  79. lyrics_transcriber-0.32.1.dist-info/RECORD +86 -0
  80. {lyrics_transcriber-0.30.0.dist-info → lyrics_transcriber-0.32.1.dist-info}/WHEEL +1 -1
  81. lyrics_transcriber-0.32.1.dist-info/entry_points.txt +4 -0
  82. lyrics_transcriber/core/corrector.py +0 -56
  83. lyrics_transcriber/core/fetcher.py +0 -143
  84. lyrics_transcriber/storage/tokens.py +0 -116
  85. lyrics_transcriber/transcribers/base.py +0 -31
  86. lyrics_transcriber-0.30.0.dist-info/RECORD +0 -22
  87. lyrics_transcriber-0.30.0.dist-info/entry_points.txt +0 -3
  88. {lyrics_transcriber-0.30.0.dist-info → lyrics_transcriber-0.32.1.dist-info}/LICENSE +0 -0
@@ -1,423 +1,26 @@
1
1
  #!/usr/bin/env python
2
2
  import os, re, sys, functools, collections
3
+ from lyrics_transcriber.output.ass.event import Event
4
+ from lyrics_transcriber.output.ass.style import Style
5
+ from lyrics_transcriber.output.ass.formatters import Formatters
6
+ from lyrics_transcriber.output.ass.constants import (
7
+ ALIGN_BOTTOM_LEFT,
8
+ ALIGN_BOTTOM_CENTER,
9
+ ALIGN_BOTTOM_RIGHT,
10
+ ALIGN_MIDDLE_LEFT,
11
+ ALIGN_MIDDLE_CENTER,
12
+ ALIGN_MIDDLE_RIGHT,
13
+ ALIGN_TOP_LEFT,
14
+ ALIGN_TOP_CENTER,
15
+ ALIGN_TOP_RIGHT,
16
+ LEGACY_ALIGNMENT_TO_REGULAR,
17
+ )
3
18
 
4
19
  version_info = (1, 0, 4)
5
20
 
6
21
 
7
22
  # Advanced SubStation Alpha read/write/modification class
8
23
  class ASS:
9
- class Formatters:
10
- __re_color_format = re.compile(r"([a-fA-F0-9]{1,8})", re.U)
11
- __re_tag_number = re.compile(
12
- r"^\s*([\+\-]?(?:[0-9]+(?:\.[0-9]*)?|\.[0-9]+))", re.U
13
- )
14
-
15
- @classmethod
16
- def same(cls, val, *args):
17
- return val
18
-
19
- @classmethod
20
- def color_to_str(cls, val, *args):
21
- return "&H{0:02X}{1:02X}{2:02X}{3:02X}".format(
22
- 255 - val[3], val[2], val[1], val[0]
23
- )
24
-
25
- @classmethod
26
- def str_to_color(cls, val, *args):
27
- match = cls.__re_color_format.search(val)
28
- if match:
29
- hex_val = "{0:>08s}".format(match.group(1))
30
- return (
31
- int(hex_val[6:8], 16), # Red
32
- int(hex_val[4:6], 16), # Green
33
- int(hex_val[2:4], 16), # Blue
34
- 255 - int(hex_val[0:2], 16), # Alpha
35
- )
36
- else:
37
- return (255, 255, 255, 255)
38
-
39
- @classmethod
40
- def n1bool_to_str(cls, val, *args):
41
- if val:
42
- return "-1"
43
- return "0"
44
-
45
- @classmethod
46
- def str_to_n1bool(cls, val, *args):
47
- try:
48
- val = int(val, 10)
49
- except ValueError:
50
- return False
51
- return val != 0
52
-
53
- @classmethod
54
- def integer_to_str(cls, val, *args):
55
- return str(int(val))
56
-
57
- @classmethod
58
- def str_to_integer(cls, val, *args):
59
- try:
60
- return int(val, 10)
61
- except ValueError:
62
- return 0
63
-
64
- @classmethod
65
- def number_to_str(cls, val, *args):
66
- if int(val) == val:
67
- return str(int(val))
68
- # No decimal
69
- return str(val)
70
-
71
- @classmethod
72
- def str_to_number(cls, val, *args):
73
- try:
74
- return float(val)
75
- except ValueError:
76
- return 0.0
77
-
78
- @classmethod
79
- def timecode_to_str_generic(
80
- cls,
81
- timecode,
82
- decimal_length=2,
83
- seconds_length=2,
84
- minutes_length=2,
85
- hours_length=1,
86
- ):
87
- if decimal_length > 0:
88
- total_length = seconds_length + decimal_length + 1
89
- else:
90
- total_length = seconds_length
91
-
92
- tc_parts = [
93
- "{{0:0{0:d}d}}".format(hours_length).format(int(timecode // 3600)),
94
- "{{0:0{0:d}d}}".format(minutes_length).format(
95
- int((timecode // 60) % 60)
96
- ),
97
- "{{0:0{0:d}.{1:d}f}}".format(total_length, decimal_length).format(
98
- timecode % 60
99
- ),
100
- ]
101
- return ":".join(tc_parts)
102
-
103
- @classmethod
104
- def timecode_to_str(cls, val, *args):
105
- return cls.timecode_to_str_generic(val, 2)
106
-
107
- @classmethod
108
- def str_to_timecode(cls, val, *args):
109
- time = 0.0
110
- mult = 1
111
-
112
- for t in reversed(val.split(":")):
113
- time += float(t) * mult
114
- mult *= 60
115
-
116
- return time
117
-
118
- @classmethod
119
- def style_to_str(cls, val, *args):
120
- if val is None:
121
- return ""
122
- return val.Name
123
-
124
- @classmethod
125
- def str_to_style(cls, val, style_map, style_constructor, *args):
126
- if val in style_map:
127
- return style_map[val]
128
-
129
- # Create fake
130
- style = style_constructor()
131
- style.fake = True
132
- style.Name = val
133
-
134
- # Add to map (will not be included in global style list, but allows for duplicate "fake" styles to reference the same object)
135
- style_map[style.Name] = style
136
-
137
- # Return the new style
138
- return style
139
-
140
- @classmethod
141
- def tag_argument_to_number(cls, arg, default_value=None):
142
- match = cls.__re_tag_number.match(arg)
143
- if match is None:
144
- return default_value
145
- return float(match.group(1))
146
-
147
- class Style:
148
- aliases = {}
149
- formatters = None
150
- order = [
151
- "Name",
152
- "Fontname",
153
- "Fontsize",
154
- "PrimaryColour",
155
- "SecondaryColour",
156
- "OutlineColour",
157
- "BackColour",
158
- "Bold",
159
- "Italic",
160
- "Underline",
161
- "StrikeOut",
162
- "ScaleX",
163
- "ScaleY",
164
- "Spacing",
165
- "Angle",
166
- "BorderStyle",
167
- "Outline",
168
- "Shadow",
169
- "Alignment",
170
- "MarginL",
171
- "MarginR",
172
- "MarginV",
173
- "Encoding",
174
- ]
175
-
176
- # Constructor
177
- def __init__(self):
178
- self.type = None
179
- self.fake = False
180
-
181
- self.Name = ""
182
- self.Fontname = ""
183
- self.Fontsize = 1.0
184
- self.PrimaryColour = (255, 255, 255, 255)
185
- self.SecondaryColour = (255, 255, 255, 255)
186
- self.OutlineColour = (255, 255, 255, 255)
187
- self.BackColour = (255, 255, 255, 255)
188
- self.Bold = False
189
- self.Italic = False
190
- self.Underline = False
191
- self.StrikeOut = False
192
- self.ScaleX = 100
193
- self.ScaleY = 100
194
- self.Spacing = 0
195
- self.Angle = 0.0
196
- self.BorderStyle = 1
197
- self.Outline = 0
198
- self.Shadow = 0
199
- self.Alignment = ASS.ALIGN_BOTTOM_CENTER
200
- self.MarginL = 0
201
- self.MarginR = 0
202
- self.MarginV = 0
203
- self.Encoding = 0
204
-
205
- def set(self, attribute_name, value, *args):
206
- if hasattr(self, attribute_name):
207
- if not attribute_name[0].isupper():
208
- return
209
- elif attribute_name in self.aliases:
210
- attribute_name = self.aliases[attribute_name]
211
- else:
212
- return
213
-
214
- setattr(
215
- self, attribute_name, self.formatters[attribute_name][0](value, *args)
216
- )
217
-
218
- def get(self, attribute_name, *args):
219
- if hasattr(self, attribute_name):
220
- if not attribute_name[0].isupper():
221
- return None
222
- elif attribute_name in self.aliases:
223
- attribute_name = self.aliases[attribute_name]
224
- else:
225
- return None
226
-
227
- return self.formatters[attribute_name][1](
228
- getattr(self, attribute_name), *args
229
- )
230
-
231
- def copy(self, other=None):
232
- if other is None:
233
- other = self.__class__()
234
- obj1 = other
235
- obj2 = self
236
- else:
237
- obj1 = self
238
- obj2 = other
239
-
240
- obj1.type = obj2.type
241
-
242
- obj1.Name = obj2.Name
243
- obj1.Fontname = obj2.Fontname
244
- obj1.Fontsize = obj2.Fontsize
245
- obj1.PrimaryColour = obj2.PrimaryColour
246
- obj1.SecondaryColour = obj2.SecondaryColour
247
- obj1.OutlineColour = obj2.OutlineColour
248
- obj1.BackColour = obj2.BackColour
249
- obj1.Bold = obj2.Bold
250
- obj1.Italic = obj2.Italic
251
- obj1.Underline = obj2.Underline
252
- obj1.StrikeOut = obj2.StrikeOut
253
- obj1.ScaleX = obj2.ScaleX
254
- obj1.ScaleY = obj2.ScaleY
255
- obj1.Spacing = obj2.Spacing
256
- obj1.Angle = obj2.Angle
257
- obj1.BorderStyle = obj2.BorderStyle
258
- obj1.Outline = obj2.Outline
259
- obj1.Shadow = obj2.Shadow
260
- obj1.Alignment = obj2.Alignment
261
- obj1.MarginL = obj2.MarginL
262
- obj1.MarginR = obj2.MarginR
263
- obj1.MarginV = obj2.MarginV
264
- obj1.Encoding = obj2.Encoding
265
-
266
- return obj1
267
-
268
- def equals(self, other, names_can_differ=False):
269
- return (
270
- self.type == other.type
271
- and not self.fake
272
- and not other.fake
273
- and not other.fake
274
- and (names_can_differ or self.Name == other.Name)
275
- and self.Fontname == other.Fontname
276
- and self.Fontsize == other.Fontsize
277
- and self.PrimaryColour == other.PrimaryColour
278
- and self.SecondaryColour == other.SecondaryColour
279
- and self.OutlineColour == other.OutlineColour
280
- and self.BackColour == other.BackColour
281
- and self.Bold == other.Bold
282
- and self.Italic == other.Italic
283
- and self.Underline == other.Underline
284
- and self.StrikeOut == other.StrikeOut
285
- and self.ScaleX == other.ScaleX
286
- and self.ScaleY == other.ScaleY
287
- and self.Spacing == other.Spacing
288
- and self.Angle == other.Angle
289
- and self.BorderStyle == other.BorderStyle
290
- and self.Outline == other.Outline
291
- and self.Shadow == other.Shadow
292
- and self.Alignment == other.Alignment
293
- and self.MarginL == other.MarginL
294
- and self.MarginR == other.MarginR
295
- and self.MarginV == other.MarginV
296
- and self.Encoding == other.Encoding
297
- )
298
-
299
- Style.formatters = {
300
- "Name": (Formatters.same, Formatters.same),
301
- "Fontname": (Formatters.same, Formatters.same),
302
- "Fontsize": (Formatters.str_to_number, Formatters.number_to_str),
303
- "PrimaryColour": (Formatters.str_to_color, Formatters.color_to_str),
304
- "SecondaryColour": (Formatters.str_to_color, Formatters.color_to_str),
305
- "OutlineColour": (Formatters.str_to_color, Formatters.color_to_str),
306
- "BackColour": (Formatters.str_to_color, Formatters.color_to_str),
307
- "Bold": (Formatters.str_to_n1bool, Formatters.n1bool_to_str),
308
- "Italic": (Formatters.str_to_n1bool, Formatters.n1bool_to_str),
309
- "Underline": (Formatters.str_to_n1bool, Formatters.n1bool_to_str),
310
- "StrikeOut": (Formatters.str_to_n1bool, Formatters.n1bool_to_str),
311
- "ScaleX": (Formatters.str_to_integer, Formatters.integer_to_str),
312
- "ScaleY": (Formatters.str_to_integer, Formatters.integer_to_str),
313
- "Spacing": (Formatters.str_to_integer, Formatters.integer_to_str),
314
- "Angle": (Formatters.str_to_number, Formatters.number_to_str),
315
- "BorderStyle": (Formatters.str_to_integer, Formatters.integer_to_str),
316
- "Outline": (Formatters.str_to_integer, Formatters.integer_to_str),
317
- "Shadow": (Formatters.str_to_integer, Formatters.integer_to_str),
318
- "Alignment": (Formatters.str_to_integer, Formatters.integer_to_str),
319
- "MarginL": (Formatters.str_to_integer, Formatters.integer_to_str),
320
- "MarginR": (Formatters.str_to_integer, Formatters.integer_to_str),
321
- "MarginV": (Formatters.str_to_integer, Formatters.integer_to_str),
322
- "Encoding": (Formatters.str_to_integer, Formatters.integer_to_str),
323
- }
324
-
325
- class Event:
326
- aliases = {}
327
- formatters = None
328
- order = [
329
- "Layer",
330
- "Start",
331
- "End",
332
- "Style",
333
- "Name",
334
- "MarginL",
335
- "MarginR",
336
- "MarginV",
337
- "Effect",
338
- "Text",
339
- ]
340
-
341
- # Constructor
342
- def __init__(self):
343
- self.type = None
344
-
345
- self.Layer = 0
346
- self.Start = 0.0
347
- self.End = 0.0
348
- self.Style = None
349
- self.Name = ""
350
- self.MarginL = 0
351
- self.MarginR = 0
352
- self.MarginV = 0
353
- self.Effect = ""
354
- self.Text = ""
355
-
356
- def set(self, attribute_name, value, *args):
357
- if hasattr(self, attribute_name) and attribute_name[0].isupper():
358
- setattr(
359
- self,
360
- attribute_name,
361
- self.formatters[attribute_name][0](value, *args),
362
- )
363
-
364
- def get(self, attribute_name, *args):
365
- if hasattr(self, attribute_name) and attribute_name[0].isupper():
366
- return self.formatters[attribute_name][1](
367
- getattr(self, attribute_name), *args
368
- )
369
- return None
370
-
371
- def copy(self, other=None):
372
- if other is None:
373
- other = self.__class__()
374
- obj1 = other
375
- obj2 = self
376
- else:
377
- obj1 = self
378
- obj2 = other
379
-
380
- obj1.type = obj2.type
381
-
382
- obj1.Layer = obj2.Layer
383
- obj1.Start = obj2.Start
384
- obj1.End = obj2.End
385
- obj1.Style = obj2.Style
386
- obj1.Name = obj2.Name
387
- obj1.MarginL = obj2.MarginL
388
- obj1.MarginR = obj2.MarginR
389
- obj1.MarginV = obj2.MarginV
390
- obj1.Effect = obj2.Effect
391
- obj1.Text = obj2.Text
392
-
393
- return obj1
394
-
395
- def equals(self, other):
396
- return (
397
- self.type == other.type
398
- and self.Layer == other.Layer
399
- and self.Start == other.Start
400
- and self.End == other.End
401
- and self.Style is other.Style
402
- and self.Name == other.Name
403
- and self.MarginL == other.MarginL
404
- and self.MarginR == other.MarginR
405
- and self.MarginV == other.MarginV
406
- and self.Effect == other.Effect
407
- and self.Text == other.Text
408
- )
409
-
410
- def same_style(self, other):
411
- return (
412
- self.type == other.type
413
- and self.Layer == other.Layer
414
- and self.Style is other.Style
415
- and self.Name == other.Name
416
- and self.MarginL == other.MarginL
417
- and self.MarginR == other.MarginR
418
- and self.MarginV == other.MarginV
419
- and self.Effect == other.Effect
420
- )
421
24
 
422
25
  Event.formatters = {
423
26
  "Layer": (Formatters.str_to_integer, Formatters.integer_to_str),
@@ -438,16 +41,6 @@ class ASS:
438
41
  self.key = key
439
42
  self.value = value
440
43
 
441
- ALIGN_BOTTOM_LEFT = 1
442
- ALIGN_BOTTOM_CENTER = 2
443
- ALIGN_BOTTOM_RIGHT = 3
444
- ALIGN_MIDDLE_LEFT = 4
445
- ALIGN_MIDDLE_CENTER = 5
446
- ALIGN_MIDDLE_RIGHT = 6
447
- ALIGN_TOP_LEFT = 7
448
- ALIGN_TOP_CENTER = 8
449
- ALIGN_TOP_RIGHT = 9
450
-
451
44
  __re_ass_read_section_label = re.compile(r"^(?:\[(.+)\])$", re.U)
452
45
  __re_ass_read_key_value = re.compile(r"^([^:]+):\s?(.+)$", re.U)
453
46
  __re_tag_block = re.compile(r"(\{)(.*?)(\})", re.U)
@@ -525,17 +118,6 @@ class ASS:
525
118
  __re_draw_command_split = re.compile(r"\s+")
526
119
  __re_draw_commands_ord_min = ord("a")
527
120
  __re_draw_commands_ord_max = ord("z")
528
- __legacy_alignment_to_regular = {
529
- "1": ALIGN_BOTTOM_LEFT,
530
- "2": ALIGN_BOTTOM_CENTER,
531
- "3": ALIGN_BOTTOM_RIGHT,
532
- "5": ALIGN_TOP_LEFT,
533
- "6": ALIGN_TOP_CENTER,
534
- "7": ALIGN_TOP_RIGHT,
535
- "9": ALIGN_MIDDLE_LEFT,
536
- "10": ALIGN_MIDDLE_CENTER,
537
- "11": ALIGN_MIDDLE_RIGHT,
538
- }
539
121
 
540
122
  @classmethod
541
123
  def __split_line(cls, line, split_time, naive):
@@ -561,7 +143,7 @@ class ASS:
561
143
  return (before, after)
562
144
 
563
145
  @classmethod
564
- def __split_line3(cls, line, split_time, naive):
146
+ def __split_line3(cls, line, split_time, naive=False):
565
147
  if split_time < line.Start or split_time > line.End:
566
148
  return None
567
149
  # Nothing to split
@@ -628,9 +210,7 @@ class ASS:
628
210
  state = {
629
211
  "animations": 0,
630
212
  }
631
- cls.parse_text(
632
- text, modify_tag=lambda t: cls.__line_has_animations_modify_tag(state, t)
633
- )
213
+ cls.parse_text(text, modify_tag=lambda t: cls.__line_has_animations_modify_tag(state, t))
634
214
  return state["animations"] > 0
635
215
 
636
216
  @classmethod
@@ -710,13 +290,9 @@ class ASS:
710
290
  line = self.events[i]
711
291
  if filter_types is None or line.type in filter_types:
712
292
  if full_inclusion:
713
- perform = (start is None or line.Start >= start) and (
714
- end is None or line.End <= end
715
- )
293
+ perform = (start is None or line.Start >= start) and (end is None or line.End <= end)
716
294
  else:
717
- perform = (start is None or line.End > start) and (
718
- end is None or line.Start < end
719
- )
295
+ perform = (start is None or line.End > start) and (end is None or line.Start < end)
720
296
 
721
297
  if perform ^ inverse:
722
298
  # action should return None if the line should be removed, else it should return an Event object (likely the same one that was input)
@@ -791,7 +367,7 @@ class ASS:
791
367
 
792
368
  s = s.decode("utf-8")
793
369
  # Decode using UTF-8
794
- s = s.replace(u"\ufeff", "")
370
+ s = s.replace("\ufeff", "")
795
371
  # Replace any BOM
796
372
 
797
373
  # Target region
@@ -861,9 +437,7 @@ class ASS:
861
437
  instance.type = match.group(1)
862
438
 
863
439
  for i in range(len(values)):
864
- instance.set(
865
- target_format[i], values[i], *target_class_set_args
866
- )
440
+ instance.set(target_format[i], values[i], *target_class_set_args)
867
441
 
868
442
  target_list.append(instance)
869
443
  if target_map is not None:
@@ -875,7 +449,7 @@ class ASS:
875
449
  def write(self, filename, comments=None):
876
450
  # Generate source
877
451
  source = [
878
- u"[Script Info]\n",
452
+ "[Script Info]\n",
879
453
  ]
880
454
 
881
455
  # Comments
@@ -883,49 +457,45 @@ class ASS:
883
457
  # Default comment
884
458
  source.extend(
885
459
  [
886
- u"; Script generated by {0:s}\n".format(
887
- self.__re_filename_format[0].sub(
888
- self.__re_filename_format[1], os.path.split(__file__)[1]
889
- )
460
+ "; Script generated by {0:s}\n".format(
461
+ self.__re_filename_format[0].sub(self.__re_filename_format[1], os.path.split(__file__)[1])
890
462
  ),
891
463
  ]
892
464
  )
893
465
  else:
894
466
  # Custom comments
895
- source.extend([u"; {0:s}".format(c) for c in comments])
467
+ source.extend(["; {0:s}".format(c) for c in comments])
896
468
 
897
469
  # Script info
898
470
  for entry in self.script_info_ordered:
899
471
  if entry.key in self.script_info:
900
- source.append(u"{0:s}: {1:s}\n".format(entry.key, entry.value))
472
+ source.append("{0:s}: {1:s}\n".format(entry.key, entry.value))
901
473
 
902
- source.append(u"\n")
474
+ source.append("\n")
903
475
 
904
476
  # Styles
905
- source.append(u"[V4+ Styles]\n")
906
- source.append(u"Format: {0:s}\n".format(", ".join(self.styles_format)))
477
+ source.append("[V4+ Styles]\n")
478
+ source.append("Format: {0:s}\n".format(", ".join(self.styles_format)))
907
479
  for style in self.styles:
908
480
  style_list = []
909
481
  for key in self.styles_format:
910
482
  style_list.append(style.get(key))
911
- source.append(u"{0:s}: {1:s}\n".format(style.type, u",".join(style_list)))
912
- source.append(u"\n")
483
+ source.append("{0:s}: {1:s}\n".format(style.type, ",".join(style_list)))
484
+ source.append("\n")
913
485
 
914
486
  # Events
915
- source.append(u"[Events]\n")
916
- source.append(u"Format: {0:s}\n".format(u", ".join(self.events_format)))
487
+ source.append("[Events]\n")
488
+ source.append("Format: {0:s}\n".format(", ".join(self.events_format)))
917
489
  for event in self.events:
918
490
  if event.Start >= 0 and event.End >= 0:
919
491
  event_list = []
920
492
  for key in self.events_format:
921
493
  event_list.append(event.get(key))
922
- source.append(
923
- u"{0:s}: {1:s}\n".format(event.type, u",".join(event_list))
924
- )
494
+ source.append("{0:s}: {1:s}\n".format(event.type, ",".join(event_list)))
925
495
 
926
496
  # Write file
927
497
  f = open(filename, "wb")
928
- s = f.write((u"".join(source)).encode("utf-8"))
498
+ s = f.write(("".join(source)).encode("utf-8"))
929
499
  f.close()
930
500
 
931
501
  # Done
@@ -951,11 +521,7 @@ class ASS:
951
521
  sorted_events = []
952
522
  for i in range(len(self.events)):
953
523
  event = self.events[i]
954
- if (
955
- event.type == "Dialogue"
956
- and event.Start < event.End
957
- and event.Start >= 0
958
- ):
524
+ if event.type == "Dialogue" and event.Start < event.End and event.Start >= 0:
959
525
  meta_event = self.__WriteSRTMetaEvent(event, i)
960
526
  meta_event.format_text(self, newlines)
961
527
  if len(meta_event.text) > 0:
@@ -1017,18 +583,11 @@ class ASS:
1017
583
  block_end = event_data.event.End
1018
584
  for i in range(1, event_count):
1019
585
  event_data = sorted_events[i]
1020
- if (
1021
- event_data.start < block_start + self.__same_time_max_delta
1022
- ): # will set even if same
586
+ if event_data.start < block_start + self.__same_time_max_delta: # will set even if same
1023
587
  block_start = event_data.start
1024
- if (
1025
- event_data.event.End
1026
- <= block_end - self.__same_time_max_delta
1027
- ): # will set only if lower
588
+ if event_data.event.End <= block_end - self.__same_time_max_delta: # will set only if lower
1028
589
  block_end = event_data.event.End
1029
- elif (
1030
- event_data.start <= block_end - self.__same_time_max_delta
1031
- ): # will set only if lower
590
+ elif event_data.start <= block_end - self.__same_time_max_delta: # will set only if lower
1032
591
  block_end = event_data.start
1033
592
  assert block_start < block_end
1034
593
  # should never happen
@@ -1047,10 +606,7 @@ class ASS:
1047
606
  stack_lines_ordered.append(event_data)
1048
607
  else:
1049
608
  stack_lines_unordered.append(event_data)
1050
- if (
1051
- event_data.event.End
1052
- <= block_end + self.__same_time_max_delta
1053
- ):
609
+ if event_data.event.End <= block_end + self.__same_time_max_delta:
1054
610
  # Remove
1055
611
  sorted_events.pop(i)
1056
612
  event_count -= 1
@@ -1080,9 +636,7 @@ class ASS:
1080
636
  # Sort by vertical position; this is convenient for multiple lines appearing simultaneously; there are still cases ordering may be messed up
1081
637
  stack_lines_unordered = sorted(
1082
638
  stack_lines_unordered,
1083
- key=functools.cmp_to_key(
1084
- lambda e1, e2: self.__write_srt_sort_lines_compare(e1, e2)
1085
- ),
639
+ key=functools.cmp_to_key(lambda e1, e2: self.__write_srt_sort_lines_compare(e1, e2)),
1086
640
  )
1087
641
  stack_lines.extend(stack_lines_unordered)
1088
642
  for i in range(len(stack_lines)):
@@ -1114,22 +668,18 @@ class ASS:
1114
668
  for i in range(len(lines)):
1115
669
  line_start, line_end, line_text = lines[i]
1116
670
 
1117
- source.append(u"{0:d}\n".format(i + 1))
671
+ source.append("{0:d}\n".format(i + 1))
1118
672
  source.append(
1119
- u"{0:s} --> {1:s}\n".format(
1120
- self.Formatters.timecode_to_str_generic(
1121
- line_start, 3, 2, 2, 2
1122
- ).replace(".", ","),
1123
- self.Formatters.timecode_to_str_generic(
1124
- line_end, 3, 2, 2, 2
1125
- ).replace(".", ","),
673
+ "{0:s} --> {1:s}\n".format(
674
+ Formatters.timecode_to_str_generic(line_start, 3, 2, 2, 2).replace(".", ","),
675
+ Formatters.timecode_to_str_generic(line_end, 3, 2, 2, 2).replace(".", ","),
1126
676
  )
1127
677
  )
1128
- source.append(u"{0:s}\n\n".format(line_text))
678
+ source.append("{0:s}\n\n".format(line_text))
1129
679
 
1130
680
  # Write file
1131
681
  f = open(filename, "wb")
1132
- s = f.write((u"".join(source)).encode("utf-8"))
682
+ s = f.write(("".join(source)).encode("utf-8"))
1133
683
  f.close()
1134
684
 
1135
685
  # Done
@@ -1188,30 +738,22 @@ class ASS:
1188
738
  self.text = None
1189
739
 
1190
740
  def equals(self, other):
1191
- return (
1192
- self.text == other.text
1193
- and self.start == other.start
1194
- and self.event.End == other.event.End
1195
- )
741
+ return self.text == other.text and self.start == other.start and self.event.End == other.event.End
1196
742
 
1197
743
  def format_text(self, parent, newlines):
1198
744
  self.text = parent.parse_text(
1199
745
  self.event.Text,
1200
- modify_text=(
1201
- lambda t: self.__write_srt_format_text(parent, newlines, t)
1202
- ),
746
+ modify_text=(lambda t: self.__write_srt_format_text(parent, newlines, t)),
1203
747
  modify_tag_block=(lambda b: ""),
1204
748
  modify_geometry=(lambda g: ""),
1205
749
  )
1206
750
 
1207
751
  def __write_srt_format_text(self, parent, newlines, text):
1208
- return parent.replace_special(
1209
- text, (lambda c: self.__write_srt_format_text_space(newlines, c)), 1, 1
1210
- )
752
+ return parent.replace_special(text, (lambda c: self.__write_srt_format_text_space(newlines, c)), 1, 1)
1211
753
 
1212
754
  def __write_srt_format_text_space(self, newlines, character):
1213
755
  if character == "h":
1214
- return u"\u00A0"
756
+ return "\u00A0"
1215
757
  if newlines:
1216
758
  return "\n"
1217
759
  return " "
@@ -1259,38 +801,36 @@ class ASS:
1259
801
  if state[0] is None:
1260
802
  tag_name = tag[0]
1261
803
  if tag_name == "a":
1262
- state[0] = cls.__legacy_align_to_regular(
1263
- cls.Formatters.str_to_number(tag[1])
1264
- )
804
+ state[0] = cls.__legacy_align_to_regular(Formatters.str_to_number(tag[1]))
1265
805
  elif tag_name == "an":
1266
- state[0] = cls.Formatters.str_to_number(tag[1])
806
+ state[0] = Formatters.str_to_number(tag[1])
1267
807
 
1268
808
  # Done
1269
809
  return [tag]
1270
810
 
1271
811
  @classmethod
1272
812
  def get_xy_alignment(cls, align):
1273
- if align >= cls.ALIGN_TOP_LEFT and align <= cls.ALIGN_TOP_RIGHT:
813
+ if align >= ALIGN_TOP_LEFT and align <= ALIGN_TOP_RIGHT:
1274
814
  align_y = -1
1275
- if align == cls.ALIGN_TOP_LEFT:
815
+ if align == ALIGN_TOP_LEFT:
1276
816
  align_x = -1
1277
- elif align == cls.ALIGN_TOP_RIGHT:
817
+ elif align == ALIGN_TOP_RIGHT:
1278
818
  align_x = 1
1279
819
  else:
1280
820
  align_x = 0
1281
- elif align >= cls.ALIGN_MIDDLE_LEFT and align <= cls.ALIGN_MIDDLE_RIGHT:
821
+ elif align >= ALIGN_MIDDLE_LEFT and align <= ALIGN_MIDDLE_RIGHT:
1282
822
  align_y = 0
1283
- if align == cls.ALIGN_MIDDLE_LEFT:
823
+ if align == ALIGN_MIDDLE_LEFT:
1284
824
  align_x = -1
1285
- elif align == cls.ALIGN_MIDDLE_RIGHT:
825
+ elif align == ALIGN_MIDDLE_RIGHT:
1286
826
  align_x = 1
1287
827
  else:
1288
828
  align_x = 0
1289
- else: # if (align >= cls.ALIGN_BOTTOM_LEFT and align <= cls.ALIGN_BOTTOM_RIGHT):
829
+ else: # if (align >= ALIGN_BOTTOM_LEFT and align <= ALIGN_BOTTOM_RIGHT):
1290
830
  align_y = 1
1291
- if align == cls.ALIGN_BOTTOM_LEFT:
831
+ if align == ALIGN_BOTTOM_LEFT:
1292
832
  align_x = -1
1293
- elif align == cls.ALIGN_BOTTOM_RIGHT:
833
+ elif align == ALIGN_BOTTOM_RIGHT:
1294
834
  align_x = 1
1295
835
  else:
1296
836
  align_x = 0
@@ -1336,25 +876,25 @@ class ASS:
1336
876
  modify_geometry=None,
1337
877
  ):
1338
878
  """
1339
- modify_tag:
1340
- inputs:
1341
- tag_args - an array of the form:
1342
- [ tag_name , tag_arg1 , tag_arg2 , ... ]
1343
- where all tag_arg#'s are optional
1344
- return:
1345
- must return an array containing only "tag_args" and strings
1346
- - "tag_args" are auto-converted into strings
1347
- - strings are treated as comments, or pre-formatted tags
1348
-
1349
- <everything else>:
1350
- inputs:
1351
- the relevant string
1352
- return:
1353
- the relevant string, modified
1354
-
1355
- Note:
1356
- if modify_special is None, then "\\h", "\\n", and "\\N" will be treated part of text sections (i.e. they are not separated)
1357
- """
879
+ modify_tag:
880
+ inputs:
881
+ tag_args - an array of the form:
882
+ [ tag_name , tag_arg1 , tag_arg2 , ... ]
883
+ where all tag_arg#'s are optional
884
+ return:
885
+ must return an array containing only "tag_args" and strings
886
+ - "tag_args" are auto-converted into strings
887
+ - strings are treated as comments, or pre-formatted tags
888
+
889
+ <everything else>:
890
+ inputs:
891
+ the relevant string
892
+ return:
893
+ the relevant string, modified
894
+
895
+ Note:
896
+ if modify_special is None, then "\\h", "\\n", and "\\N" will be treated part of text sections (i.e. they are not separated)
897
+ """
1358
898
  text_new = []
1359
899
 
1360
900
  if modify_special is None:
@@ -1387,9 +927,7 @@ class ASS:
1387
927
  tag_new = [match.group(1)]
1388
928
 
1389
929
  # Parse individual tags
1390
- tag_text, next_geometry_scale = cls.parse_tags(
1391
- match.group(2), modify_tag, modify_comment, next_geometry_scale
1392
- )
930
+ tag_text, next_geometry_scale = cls.parse_tags(match.group(2), modify_tag, modify_comment, next_geometry_scale)
1393
931
  tag_text = match.group(1) + tag_text + match.group(3)
1394
932
 
1395
933
  if modify_tag_block is not None:
@@ -1416,26 +954,24 @@ class ASS:
1416
954
  return "".join(text_new)
1417
955
 
1418
956
  @classmethod
1419
- def parse_tags(
1420
- cls, text, modify_tag=None, modify_comment=None, next_geometry_scale=0
1421
- ):
957
+ def parse_tags(cls, text, modify_tag=None, modify_comment=None, next_geometry_scale=0):
958
+ """
959
+ modify_tag:
960
+ inputs:
961
+ tag_args - an array of the form:
962
+ [ tag_name , tag_arg1 , tag_arg2 , ... ]
963
+ where all tag_arg#'s are optional
964
+ return:
965
+ must return an array containing only "tag_args" and strings
966
+ - "tag_args" are auto-converted into strings
967
+ - strings are treated as comments, or pre-formatted tags
968
+
969
+ <everything else>:
970
+ inputs:
971
+ the relevant string
972
+ return:
973
+ the relevant string, modified
1422
974
  """
1423
- modify_tag:
1424
- inputs:
1425
- tag_args - an array of the form:
1426
- [ tag_name , tag_arg1 , tag_arg2 , ... ]
1427
- where all tag_arg#'s are optional
1428
- return:
1429
- must return an array containing only "tag_args" and strings
1430
- - "tag_args" are auto-converted into strings
1431
- - strings are treated as comments, or pre-formatted tags
1432
-
1433
- <everything else>:
1434
- inputs:
1435
- the relevant string
1436
- return:
1437
- the relevant string, modified
1438
- """
1439
975
  text_new = []
1440
976
  pos = 0
1441
977
  for match in cls.__re_tag.finditer(text):
@@ -1481,9 +1017,7 @@ class ASS:
1481
1017
  for tag_args in tag_args_array:
1482
1018
  if tag_args[0] == "p":
1483
1019
  # Drawing command
1484
- next_geometry_scale = cls.Formatters.tag_argument_to_number(
1485
- tag_args[1], 0
1486
- )
1020
+ next_geometry_scale = Formatters.tag_argument_to_number(tag_args[1], 0)
1487
1021
 
1488
1022
  text_new.append(tt)
1489
1023
 
@@ -1502,28 +1036,18 @@ class ASS:
1502
1036
 
1503
1037
  # Other parsing
1504
1038
  @classmethod
1505
- def replace_special(
1506
- cls, text, space=" ", min_whitespace_length=1, max_whitespace_length=1
1507
- ):
1039
+ def replace_special(cls, text, space=" ", min_whitespace_length=1, max_whitespace_length=1):
1508
1040
  return cls.__re_remove_special.sub(
1509
- (
1510
- lambda m: cls.__replace_special_replacer(
1511
- m, space, min_whitespace_length, max_whitespace_length
1512
- )
1513
- ),
1041
+ (lambda m: cls.__replace_special_replacer(m, space, min_whitespace_length, max_whitespace_length)),
1514
1042
  text,
1515
1043
  )
1516
1044
 
1517
1045
  @classmethod
1518
- def __replace_special_replacer(
1519
- cls, match, space, min_whitespace_length, max_whitespace_length
1520
- ):
1046
+ def __replace_special_replacer(cls, match, space, min_whitespace_length, max_whitespace_length):
1521
1047
  ws = match.group(1) + match.group(3)
1522
1048
  ws_len = len(ws)
1523
1049
 
1524
- if ws_len < min_whitespace_length or (
1525
- ws_len > max_whitespace_length and max_whitespace_length >= 0
1526
- ):
1050
+ if ws_len < min_whitespace_length or (ws_len > max_whitespace_length and max_whitespace_length >= 0):
1527
1051
  if hasattr(space, "__call__"):
1528
1052
  return space(match.group(2))
1529
1053
  return space
@@ -1713,17 +1237,13 @@ class ASS:
1713
1237
  # Done
1714
1238
  return self
1715
1239
 
1716
- def tidy_styles(
1717
- self, **kwargs
1718
- ): # Generate unique names, remove duplicates, and remove unused
1240
+ def tidy_styles(self, **kwargs): # Generate unique names, remove duplicates, and remove unused
1719
1241
  # Parse kwargs
1720
1242
  sort = self.__kwarg_default(kwargs, "sort", False)
1721
1243
  # if True, events are sorted by name
1722
1244
  join = self.__kwarg_default(kwargs, "join", False)
1723
1245
  # if True, duplicates are joined into a single style
1724
- join_if_names_differ = self.__kwarg_default(
1725
- kwargs, "join_if_names_differ", False
1726
- )
1246
+ join_if_names_differ = self.__kwarg_default(kwargs, "join_if_names_differ", False)
1727
1247
  # if True, styles are joined even if their names are different
1728
1248
  rename = self.__kwarg_default(kwargs, "rename", False)
1729
1249
  # if True, styles with identical names are renamed
@@ -1838,9 +1358,7 @@ class ASS:
1838
1358
  # (x,y) new total resolution
1839
1359
  geometry_scale = self.__kwarg_default(kwargs, "geometry_scale", None)
1840
1360
  # (x,y) factors by which to scale geometry
1841
- geometry_scale_origin = self.__kwarg_default(
1842
- kwargs, "geometry_scale_origin", (0.0, 0.0)
1843
- )
1361
+ geometry_scale_origin = self.__kwarg_default(kwargs, "geometry_scale_origin", (0.0, 0.0))
1844
1362
  # (x,y) geometry scaling origin
1845
1363
  geometry_offset = self.__kwarg_default(kwargs, "geometry_offset", (0.0, 0.0))
1846
1364
  # (x,y) geometry shifting offset
@@ -1973,23 +1491,13 @@ class ASS:
1973
1491
  line,
1974
1492
  ):
1975
1493
  # Modify
1976
- line.Start = (
1977
- (line.Start - time_scale_origin) * time_scale
1978
- + time_scale_origin
1979
- + time_offset
1980
- )
1981
- line.End = (
1982
- (line.End - time_scale_origin) * time_scale
1983
- + time_scale_origin
1984
- + time_offset
1985
- )
1494
+ line.Start = (line.Start - time_scale_origin) * time_scale + time_scale_origin + time_offset
1495
+ line.End = (line.End - time_scale_origin) * time_scale + time_scale_origin + time_offset
1986
1496
 
1987
1497
  # Modify timed tags
1988
1498
  line.Text = self.parse_text(
1989
1499
  line.Text,
1990
- modify_tag=(
1991
- lambda tag: self.__shiftscale_action_time_modify_tag(time_scale, tag)
1992
- ),
1500
+ modify_tag=(lambda tag: self.__shiftscale_action_time_modify_tag(time_scale, tag)),
1993
1501
  )
1994
1502
 
1995
1503
  # Clip
@@ -2017,23 +1525,23 @@ class ASS:
2017
1525
  tag_name = tag[0]
2018
1526
  if tag_name in ["k", "K", "kf", "ko"]:
2019
1527
  tag = list(tag)
2020
- tag[1] = str(int(self.Formatters.str_to_number(tag[1]) * time_scale))
1528
+ tag[1] = str(int(Formatters.str_to_number(tag[1]) * time_scale))
2021
1529
  elif tag_name == "move":
2022
1530
  if len(tag) == 7:
2023
1531
  tag = list(tag)
2024
- tag[5] = str(int(self.Formatters.str_to_number(tag[5]) * time_scale))
2025
- tag[6] = str(int(self.Formatters.str_to_number(tag[6]) * time_scale))
1532
+ tag[5] = str(int(Formatters.str_to_number(tag[5]) * time_scale))
1533
+ tag[6] = str(int(Formatters.str_to_number(tag[6]) * time_scale))
2026
1534
  elif tag_name == "fade":
2027
1535
  tag = list(tag)
2028
- tag[4] = str(int(self.Formatters.str_to_number(tag[4]) * time_scale))
2029
- tag[5] = str(int(self.Formatters.str_to_number(tag[5]) * time_scale))
2030
- tag[6] = str(int(self.Formatters.str_to_number(tag[6]) * time_scale))
2031
- tag[7] = str(int(self.Formatters.str_to_number(tag[7]) * time_scale))
1536
+ tag[4] = str(int(Formatters.str_to_number(tag[4]) * time_scale))
1537
+ tag[5] = str(int(Formatters.str_to_number(tag[5]) * time_scale))
1538
+ tag[6] = str(int(Formatters.str_to_number(tag[6]) * time_scale))
1539
+ tag[7] = str(int(Formatters.str_to_number(tag[7]) * time_scale))
2032
1540
  elif tag_name == "t":
2033
1541
  if len(tag) >= 4:
2034
1542
  tag = list(tag)
2035
- tag[1] = str(int(self.Formatters.str_to_number(tag[1]) * time_scale))
2036
- tag[2] = str(int(self.Formatters.str_to_number(tag[2]) * time_scale))
1543
+ tag[1] = str(int(Formatters.str_to_number(tag[1]) * time_scale))
1544
+ tag[2] = str(int(Formatters.str_to_number(tag[2]) * time_scale))
2037
1545
 
2038
1546
  return [tag]
2039
1547
 
@@ -2055,14 +1563,10 @@ class ASS:
2055
1563
  line.Text = self.parse_text(
2056
1564
  line.Text,
2057
1565
  modify_tag=(
2058
- lambda tag: self.__shiftscale_action_geometry_modify_tag(
2059
- state, geometry_scale, geometry_scale_origin, geometry_offset, tag
2060
- )
1566
+ lambda tag: self.__shiftscale_action_geometry_modify_tag(state, geometry_scale, geometry_scale_origin, geometry_offset, tag)
2061
1567
  ),
2062
1568
  modify_geometry=(
2063
- lambda geo: self.__shiftscale_action_geometry_modify_geometry(
2064
- geometry_scale, geometry_scale_origin, geometry_offset, geo
2065
- )
1569
+ lambda geo: self.__shiftscale_action_geometry_modify_geometry(geometry_scale, geometry_scale_origin, geometry_offset, geo)
2066
1570
  ),
2067
1571
  )
2068
1572
 
@@ -2090,44 +1594,34 @@ class ASS:
2090
1594
  # Done
2091
1595
  return line
2092
1596
 
2093
- def __shiftscale_action_geometry_modify_tag(
2094
- self, state, geometry_scale, geometry_scale_origin, geometry_offset, tag
2095
- ):
1597
+ def __shiftscale_action_geometry_modify_tag(self, state, geometry_scale, geometry_scale_origin, geometry_offset, tag):
2096
1598
  tag_name = tag[0]
2097
1599
  if tag_name in ["bord", "shad", "be", "blur", "fs"]:
2098
1600
  scale = (geometry_scale[0] + geometry_scale[1]) / 2.0
2099
1601
  tag = [
2100
1602
  tag_name,
2101
- self.Formatters.number_to_str(
2102
- self.Formatters.str_to_number(tag[1]) * scale
2103
- ),
1603
+ Formatters.number_to_str(Formatters.str_to_number(tag[1]) * scale),
2104
1604
  ]
2105
1605
  elif tag_name in ["xbord", "xshad", "fsp"]:
2106
1606
  tag = [
2107
1607
  tag_name,
2108
- self.Formatters.number_to_str(
2109
- self.Formatters.str_to_number(tag[1]) * geometry_scale[0]
2110
- ),
1608
+ Formatters.number_to_str(Formatters.str_to_number(tag[1]) * geometry_scale[0]),
2111
1609
  ]
2112
1610
  elif tag_name in ["ybord", "yshad"]:
2113
1611
  tag = [
2114
1612
  tag_name,
2115
- self.Formatters.number_to_str(
2116
- self.Formatters.str_to_number(tag[1]) * geometry_scale[1]
2117
- ),
1613
+ Formatters.number_to_str(Formatters.str_to_number(tag[1]) * geometry_scale[1]),
2118
1614
  ]
2119
1615
  elif tag_name in ["pos", "org"]:
2120
1616
  tag = [
2121
1617
  tag_name,
2122
- self.Formatters.number_to_str(
2123
- (self.Formatters.str_to_number(tag[1]) - geometry_scale_origin[0])
2124
- * geometry_scale[0]
1618
+ Formatters.number_to_str(
1619
+ (Formatters.str_to_number(tag[1]) - geometry_scale_origin[0]) * geometry_scale[0]
2125
1620
  + geometry_scale_origin[0]
2126
1621
  + geometry_offset[0]
2127
1622
  ),
2128
- self.Formatters.number_to_str(
2129
- (self.Formatters.str_to_number(tag[2]) - geometry_scale_origin[1])
2130
- * geometry_scale[1]
1623
+ Formatters.number_to_str(
1624
+ (Formatters.str_to_number(tag[2]) - geometry_scale_origin[1]) * geometry_scale[1]
2131
1625
  + geometry_scale_origin[1]
2132
1626
  + geometry_offset[1]
2133
1627
  ),
@@ -2138,34 +1632,24 @@ class ASS:
2138
1632
  tag = list(tag)
2139
1633
  for i in range(1, len(tag)):
2140
1634
  xy = (i + 1) % 2
2141
- val = self.Formatters.str_to_number(tag[i])
2142
- val = (
2143
- (val - geometry_scale_origin[xy]) * geometry_scale[xy]
2144
- + geometry_scale_origin[xy]
2145
- + geometry_offset[xy]
2146
- )
2147
- tag[i] = self.Formatters.number_to_str(val)
1635
+ val = Formatters.str_to_number(tag[i])
1636
+ val = (val - geometry_scale_origin[xy]) * geometry_scale[xy] + geometry_scale_origin[xy] + geometry_offset[xy]
1637
+ tag[i] = Formatters.number_to_str(val)
2148
1638
  else:
2149
1639
  # Draw command
2150
1640
  tag = list(tag)
2151
- tag[-1] = self.__shiftscale_action_geometry_modify_geometry(
2152
- geometry_scale, geometry_scale_origin, geometry_offset, tag[-1]
2153
- )
1641
+ tag[-1] = self.__shiftscale_action_geometry_modify_geometry(geometry_scale, geometry_scale_origin, geometry_offset, tag[-1])
2154
1642
  elif tag_name == "move":
2155
1643
  tag = list(tag)
2156
1644
  for i in range(1, len(tag)):
2157
1645
  xy = (i + 1) % 2
2158
- val = self.Formatters.str_to_number(tag[i])
2159
- val = (
2160
- (val - geometry_scale_origin[xy]) * geometry_scale[xy]
2161
- + geometry_scale_origin[xy]
2162
- + geometry_offset[xy]
2163
- )
2164
- tag[i] = self.Formatters.number_to_str(val)
1646
+ val = Formatters.str_to_number(tag[i])
1647
+ val = (val - geometry_scale_origin[xy]) * geometry_scale[xy] + geometry_scale_origin[xy] + geometry_offset[xy]
1648
+ tag[i] = Formatters.number_to_str(val)
2165
1649
  elif tag_name == "pbo":
2166
1650
  tag = [
2167
1651
  tag_name,
2168
- str(int(self.Formatters.str_to_number(tag[1]) * geometry_scale[1])),
1652
+ str(int(Formatters.str_to_number(tag[1]) * geometry_scale[1])),
2169
1653
  ]
2170
1654
  elif tag_name == "t":
2171
1655
  # Parse more tags
@@ -2183,11 +1667,9 @@ class ASS:
2183
1667
  )
2184
1668
  elif tag_name in ["a", "an"]:
2185
1669
  if tag_name == "a":
2186
- align = self.__legacy_align_to_regular(
2187
- self.Formatters.str_to_number(tag[1])
2188
- )
1670
+ align = self.__legacy_align_to_regular(Formatters.str_to_number(tag[1]))
2189
1671
  else: # if (tag_name == "an"):
2190
- align = self.Formatters.str_to_number(tag[1])
1672
+ align = Formatters.str_to_number(tag[1])
2191
1673
 
2192
1674
  # State update
2193
1675
  if state is not None and state["align"] is None:
@@ -2197,30 +1679,21 @@ class ASS:
2197
1679
 
2198
1680
  return [tag]
2199
1681
 
2200
- def __shiftscale_action_geometry_modify_geometry(
2201
- self, geometry_scale, geometry_scale_origin, geometry_offset, geo
2202
- ):
1682
+ def __shiftscale_action_geometry_modify_geometry(self, geometry_scale, geometry_scale_origin, geometry_offset, geo):
2203
1683
  points = self.__re_draw_command_split.split(geo.strip())
2204
1684
  xy = 0
2205
1685
  for i in range(len(points)):
2206
1686
  coord = points[i]
2207
1687
  if len(coord) == 1:
2208
1688
  coord_ord = ord(coord)
2209
- if (
2210
- coord_ord >= self.__re_draw_commands_ord_min
2211
- and coord_ord <= self.__re_draw_commands_ord_max
2212
- ):
1689
+ if coord_ord >= self.__re_draw_commands_ord_min and coord_ord <= self.__re_draw_commands_ord_max:
2213
1690
  # New command
2214
1691
  xy = 0
2215
1692
  continue
2216
1693
 
2217
1694
  # Value
2218
- val = self.Formatters.str_to_number(coord)
2219
- val = (
2220
- (val - geometry_scale_origin[xy]) * geometry_scale[xy]
2221
- + geometry_scale_origin[xy]
2222
- + geometry_offset[xy]
2223
- )
1695
+ val = Formatters.str_to_number(coord)
1696
+ val = (val - geometry_scale_origin[xy]) * geometry_scale[xy] + geometry_scale_origin[xy] + geometry_offset[xy]
2224
1697
  points[i] = str(int(val))
2225
1698
 
2226
1699
  # Next
@@ -2240,10 +1713,8 @@ class ASS:
2240
1713
  return (
2241
1714
  geometry_offset[0],
2242
1715
  geometry_offset[1],
2243
- (resolution_new[0] - resolution_old[0]) * geometry_scale[0]
2244
- + geometry_offset[0],
2245
- (resolution_new[1] - resolution_old[1]) * geometry_scale[1]
2246
- + geometry_offset[1],
1716
+ (resolution_new[0] - resolution_old[0]) * geometry_scale[0] + geometry_offset[0],
1717
+ (resolution_new[1] - resolution_old[1]) * geometry_scale[1] + geometry_offset[1],
2247
1718
  )
2248
1719
 
2249
1720
  def __shiftscale_action_get_new_margins(
@@ -2268,17 +1739,13 @@ class ASS:
2268
1739
  if margin_left != 0:
2269
1740
  margin_left = margin_left * geometry_scale[0] + bounds[0]
2270
1741
  if margin_right != 0:
2271
- margin_right = resolution_new[0] - (
2272
- bounds[2] - margin_right * geometry_scale[0]
2273
- )
1742
+ margin_right = resolution_new[0] - (bounds[2] - margin_right * geometry_scale[0])
2274
1743
  if margin_vertical != 0:
2275
1744
  align_xy = self.get_xy_alignment(align)
2276
1745
  if align_xy[1] < 0: # Top
2277
1746
  margin_vertical = margin_vertical * geometry_scale[1] + bounds[1]
2278
1747
  elif align_xy[1] > 0: # Bottom
2279
- margin_vertical = resolution_new[1] - (
2280
- bounds[3] - margin_vertical * geometry_scale[1]
2281
- )
1748
+ margin_vertical = resolution_new[1] - (bounds[3] - margin_vertical * geometry_scale[1])
2282
1749
  else: # if (align_xy[1] == 0): # Middle
2283
1750
  margin_vertical = margin_vertical * geometry_scale[1]
2284
1751
 
@@ -2394,9 +1861,7 @@ class ASS:
2394
1861
  length -= end - start
2395
1862
  # account for the self.extract call
2396
1863
  for line in self.events:
2397
- if (
2398
- filter_types is None or line.type in filter_types
2399
- ) and line.Start >= end:
1864
+ if (filter_types is None or line.type in filter_types) and line.Start >= end:
2400
1865
  line.Start += length
2401
1866
  line.End += length
2402
1867
 
@@ -2404,9 +1869,7 @@ class ASS:
2404
1869
  time_offset = 0.0
2405
1870
  while count >= 1:
2406
1871
  # Merge
2407
- self.merge(
2408
- other=temp, remove=False, filter_types=None, time_shift=time_offset
2409
- )
1872
+ self.merge(other=temp, remove=False, filter_types=None, time_shift=time_offset)
2410
1873
 
2411
1874
  # Shift for next
2412
1875
  time_offset += length_single
@@ -2415,9 +1878,7 @@ class ASS:
2415
1878
  # Cut
2416
1879
  temp.extract(start=start, end=start + length_single * count, inverse=True)
2417
1880
  # Add
2418
- self.merge(
2419
- other=temp, remove=True, filter_types=None, time_shift=time_offset
2420
- )
1881
+ self.merge(other=temp, remove=True, filter_types=None, time_shift=time_offset)
2421
1882
 
2422
1883
  # Done
2423
1884
  return self
@@ -2625,4 +2086,3 @@ class ASS:
2625
2086
  )
2626
2087
 
2627
2088
  return line
2628
-