def open_ass(file): try: with open(file, "r", encoding="gbk") as f: doc = ass.parse(f) return doc except: pass try: with open(file, "r", encoding="big5") as f: doc = ass.parse(f) return doc except: pass try: with open(file, "r", encoding="utf-8") as f: doc = ass.parse(f) return doc except: pass try: with open(file, 'rb') as f: input_bytes = f.read() result = chardet.detect(input_bytes) conf = result['confidence'] res_encoding = result['encoding'] if conf > 0.95: with open(file, "r", encoding=res_encoding) as f: doc = ass.parse(f) return doc except: pass return None
def test_parse_encoding(self): with self.test_ass.open("r", encoding='utf_8') as f: with self.assertRaises(ValueError): ass.parse(f) with self.test_ass.open("r", encoding='ascii') as f: with self.assertRaises(ValueError): ass.parse(f)
def test_dump_encoding(self): for encoding in ('utf_8_sig', 'utf-8-sig'): with self.test_ass.open("r", encoding=encoding) as f: doc = ass.parse(f) with self.test_ass.open("r", encoding=encoding.upper()) as f: doc = ass.parse(f) import tempfile with tempfile.TemporaryFile(mode='w', encoding='utf_8') as f: with pytest.warns(UserWarning): doc.dump_file(f)
def load_subs(subsfile): ''' Loads up and parses subtitles from subsfile and returns subsdigest object. ''' with open(subsfile, encoding='utf_8_sig') as f: subsdata = subdigest.Subtitles(ass.parse(f), subsfile) return subsdata
def loadSubsAss(self, file): with open(file, "r") as f: self.subs = ass.parse(f).events self.clear() g = 0 # for i in self.subs: # if i.style not in "ED,OP,staff": #*Default": # # self.insertItem(g, i.text.decode('utf_8')) # g = g + 1 for i in self.subs: self.insertItem(g, i.text.decode('utf_8')) g = g + 1 for i in xrange(self.count()): self.item(i).setFont(QFont('Meiryo', 16)) # MS Mincho i = self.subs[0] self.currentSubStart = i.start.total_seconds( ) * 1000 # + i.start.microseconds self.currentSubEnd = i.end.total_seconds( ) * 1000 # + i.end.microseconds self.currentRow = 0 i = self.subs[1] self.nextSubStart = i.start.total_seconds( ) * 1000 # + i.start.microseconds self.nextSubEnd = i.end.total_seconds() * 1000 # + i.end.microseconds
def read_dialogues(self): subs = ass.parse(self.contents.splitlines()) buffer = '' for quote in subs.events: if isinstance(quote, ass.document.Dialogue): buffer += quote.text + '\n' return unicode(buffer)
def edit_cn_ass_subtitle_style(subtitle_file): """ 为ass格式的中文字幕设置style :param subtitle_file: :return: """ with open(subtitle_file, "r") as f: subtitle = ass.parse(f) print(subtitle.styles) # subtitle.styles[0].fontname = '方正黑体_GBK' subtitle.styles[0].fontname = '黑体' subtitle.styles[0].fontsize = 21 subtitle.styles[0].primary_color = '&H00FFFFFF' subtitle.styles[0].secondary_color = '&HF0000000' subtitle.styles[0].outline_color = '&H006C3300' subtitle.styles[0].back_color = '&H00000000' subtitle.styles[0].bold = -1 subtitle.styles[0].border_style = 1 subtitle.styles[0].outline = 2 subtitle.styles[0].shadow = 1 subtitle.styles[0].alignment = 2 with open(subtitle_file, "w") as f: subtitle.dump_file(f) if os.path.exists(subtitle_file): return subtitle_file
def main(): file_path = sys.argv[1] with open(file_path, 'r') as fp: doc = ass.parse(fp) for i, event in enumerate(doc.events[:]): if event.TYPE == 'Dialogue' and event.effect == "fx": doc.events[i] = None # set to None to remove later continue if (event.TYPE == 'Comment' and event.effect == "karaoke" or event.TYPE == 'Dialogue' and not event.effect): if "Kanji" in event.style: comment_event = ass.document.Comment(**event.fields) comment_event.effect = "karaoke" new_event = ass.document.Dialogue(**event.fields) new_event.effect = "fx" # Cannot use str.join because tags might be inbetween text parts = re.split(r"(\{[^\}]*\})", new_event.text) parts = (f"{c}\\N" if not part.startswith("{") else c for part in parts for c in part) new_event.text = "".join(parts)[:-2] doc.events[i] = comment_event doc.events.append(new_event) # remove events flagged for deletion doc.events = filter(None, doc.events) with open(file_path + "_", 'w') as fp: doc.dump_file(fp)
def get_timestamps(dialogue): ''' Reads 'chptr' comments from dialogue subs to find timestamps of OP, ED and Eyecatch. Chapters must be named in the following format: Opening Part B Ending ... Returns a dict of timestamps and frame numbers. ''' op = ec = ed = opsync = ecsync = edsync = None with open(dialogue, encoding='utf_8_sig') as f: dialogue_data = ass.parse(f) for event in dialogue_data.events: if not isinstance(event, ass.line.Comment) and not event.name == 'chptr': continue if 'opening' in event.text.lower(): opsync = event.start op = math.ceil(opsync.total_seconds() * 23.976) if 'ending' in event.text.lower(): edsync = event.start ed = math.ceil(edsync.total_seconds() * 23.976) if 'part b' in event.text.lower(): # Part B / Eyecatch ecsync = event.start ec = math.ceil(ecsync.total_seconds() * 23.976) return {'op': op, 'ec': ec, 'ed': ed, 'opsync': opsync, 'ecsync': ecsync, 'edsync': edsync}
def test_dump_encoding(self): with self.test_ass.open("r", encoding='utf_8_sig') as f: doc = ass.parse(f) import tempfile with tempfile.TemporaryFile(mode='w', encoding='utf_8') as f: with self.assertWarns(UserWarning): doc.dump_file(f)
def test_parse_dump(self): with self.test_ass.open("r", encoding='utf_8_sig') as f: contents = f.read() doc = ass.parse(StringIO(contents)) out = StringIO() doc.dump_file(out) assert out.getvalue().strip() == contents.strip()
def test_parse_dump(self): with open("test.ass", "r") as f: contents = f.read() doc = ass.parse(StringIO(contents)) out = StringIO() doc.dump_file(out) self.assertEqual(out.getvalue().strip(), contents.strip())
def fix_ssa_start_end(basename): with open(f'{basename}.ssa') as f: d = ass.parse(f) prev = d.events[0] for i in d.events[1:]: i.start = prev.end + datetime.timedelta(seconds=2) prev = i with open(f'{basename}.ssa', 'w') as f: d.dump_file(f)
def main(): parser = argparse.ArgumentParser(description="Automatically merge fonts used in a Matroska file.") parser.add_argument('mkv', help=""" Video where the fonts will go. Must be a Matroska file. """) parser.add_argument('subtitles', nargs="+", help=""" Subtitles (can be several) containing fonts to be merged. Must be an ASS file. """) parser.add_argument('--mkvmerge', metavar="path", help=""" Path to mkvmerge.exe if not in variable environments. """) parser.add_argument('--fontfolder', metavar="path", help=""" Add a file with fonts to use. """) parser.add_argument('--output', '-o', metavar="path", help=""" Destination path of the Matroska merged file. """) args = parser.parse_args() if args.mkvmerge is None and not distutils.spawn.find_executable("mkvmerge.exe"): return print(Fore.RED + "fontmerge.py: error: mkvmerge in not in your environnements variable, add it or specify the path to mkvmerge.exe with --mkvmerge." + Fore.WHITE) if not is_mkv(args.mkv): return print(Fore.RED + "fontmerge.py: error: the file on mkv is not a Matroska file."+ Fore.WHITE) if not is_ass(args.subtitles): return print(Fore.RED + "fontmerge.py: error: the file on ass is not an ASS file." + Fore.WHITE) if not is_writable(args.mkv): return print(Fore.RED + "fontmerge.py: error: unable to create the Matroska file." + Fore.WHITE) if args.output is not None : if not is_dir(os.path.dirname(args.output)): return print(Fore.RED + "fontmerge.py: error: output path is not a valid folder." + Fore.WHITE) if args.fontfolder is not None : if not is_dir(args.fontfolder): return print(Fore.RED + "fontmerge.py: error: font path is not a directory." + Fore.WHITE) else: if not contains_fonts(args.fontfolder): print(Fore.RED + "fontmerge.py: error: font path does not contain any fonts." + Fore.WHITE) args.fontfolder = None fonts_path = [] installedFonts = get_installed_fonts(args.fontfolder) for assf in args.subtitles: with open(assf, 'r', encoding='utf_8_sig') as f: subtitles = [(os.path.basename(assf), ass.parse(f))] fonts_path.extend(get_used_font_path(subtitles, installedFonts)) if len(fonts_path) != len(dict.fromkeys(fonts_path)): print("Some fonts are duplicate. Removing.") fonts_path = list(dict.fromkeys(fonts_path)) merge(args.mkv, fonts_path, args.mkvmerge, args.output)
def main(): parser = argparse.ArgumentParser() for group in _filter_groups: arggroup = parser.add_argument_group(group.__name__) for name, member in inspect.getmembers(group): if getattr(member, '_filter', False): generate_argument(arggroup, member) parser.add_argument("-i", "--input", help="Specify input file (default: stdin)") parser.add_argument("-o", "--output", help="Specify output file (default: stdout)") parser.add_argument("--in-place", action="store_true", help="Perform operations in place") args = parser.parse_args() if args.input is None or args.input == '-': filename = None sub_obj = ass.parse(codecs.getreader('utf-8-sig')(sys.stdin.buffer)) else: filename = args.input with open(args.input, 'r', encoding='utf-8-sig') as f: sub_obj = ass.parse(f) sub_obj = Subtitles(sub_obj, filename) for func, filter_args in getattr(args, 'chain', []): filt = getattr(sub_obj, func) sub_obj = filt(*filter_args) if args.in_place and args.input is not None: args.output = args.input if args.output is None or args.output == '-': sys.stdout.buffer.write(str(sub_obj).encode('utf-8-sig')) else: with open(args.output, 'w', encoding="utf-8-sig") as f: f.write(str(sub_obj))
def tryOpen(f): """Open a .ass file with a bunch of encodings until one works.""" if not os.path.isfile(f): raise Exception('Invalid file: %s' % (f,)) lastException = None for encoding in ('utf-8', 'utf-16', 'utf-16-le'): try: return ass.parse(open(f, 'r', encoding=encoding).readlines()) except Exception as e: lastException = e raise Exception('Cannot find suitable encoding for file %s. Last error: %s' % (f, lastException))
def get_dialogues(self): if self.subs_format == 'ass': f = open(self.subs, 'r') subs = ass.parse(f) return [Dialogue(event.text, self.to_ms(event.start), self.to_ms(event.end)) for event in subs.events] elif self.subs_format == 'srt': subs = pysrt.open(self.subs) return [Dialogue(sub.text, self.to_ms_srt(sub.start), self.to_ms_srt(sub.end)) for sub in subs]
def get_dialogues(file_name): with open(file_name, "r") as rawFile: doc = ass.parse(rawFile) dialogues = [] for event in doc.events: dialogues.append({ "text": regex_process(event.text), "start": timedelta_to_ass(event.start), "end": timedelta_to_ass(event.end), "file": os.path.abspath(file_name)[:-4] }) return dialogues
def main(args): with open(args.filename, 'r') as f: doc = ass.parse(f) known = set(style.name for style in doc.styles) used = set(event.style for event in doc.events if event.text.strip() != '') unknown = used - known if unknown: raise LookupError('Some styles are not defined: {}'.format(unknown)) # remove unused styles doc.styles = [style for style in doc.styles if style.name in used] # rename styles to random names if args.rename: prefix = hex(random.getrandbits(128))[-8:] style_names = {} _new_names = set() for style in doc.styles: while True: new_name = hex(random.getrandbits(128))[-8:] if new_name not in _new_names: _new_names.add(new_name) break style_names[style.name] = '{}-{}'.format(prefix, new_name) for style in doc.styles: style.name = style_names[style.name] # clean up events and remove comments or empty texts. events = doc.events events = (clean_text(event, args.quotes) for event in events) events = (event for event in events if event.text != '' and event.TYPE.lower() == 'dialogue') doc.events = list(events) # rename the styles used in events. if args.rename: for event in doc.events: event.style = style_names[event.style] # remove all the third party tools headers (Aegisub etc.) fields = doc.fields.items() fields = ((k, v) for k, v in fields if k in desired_fields) doc.fields = dict(fields) if args.title is not None: doc.fields['Title'] = args.title # dump script with open(args.output, 'w') as f: doc.dump_file(f)
def gomen(subfile, times): if times < 0: print "Then why are you running this script?" sys.exit() print "Opening subtitle file..." with open(subfile, "r") as subf: subs = ass.parse(subf) try: subs.fields["Title"] = "Gomen" except: pass fullstr = "" indexes_to_replace = [] for dialogue_line in subs.events: if type(dialogue_line) is ass.document.Dialogue and dialogue_line.text.find("(") == -1: indexes_to_replace.append(subs.events.index(dialogue_line)) if dialogue_line.text.find("\N") != -1: for separ in dialogue_line.text.split("\N"): fullstr += separ + "*" fullstr += "^" else: fullstr += dialogue_line.text + "^" translations_to_perform = [lang_list[random.randint(0, len(lang_list) - 1)] for x in range(times)] en_to_mystery = translate(fullstr, "en", translations_to_perform[0]) if times > 1: for x in range(times - 1): en_to_mystery = translate(en_to_mystery, translations_to_perform[x], translations_to_perform[x + 1]) if "^" in en_to_mystery: translated_list = translate(en_to_mystery, translations_to_perform[times - 1], "en").split("^") else: print "Our string got messed up in translation." sys.exit() translated_parsed_list = [replace(item, "*", "\N") for item in translated_list] x = 0 try: for index in indexes_to_replace: subs.events[index].text = translated_parsed_list[x] x += 1 except: print "Indexes are messed up but whatever. That just makes it better, right?" if ( subs.events[0].text.count("\\x") > 2 or subs.events[1].text.count("\\x") > 2 or subs.events[2].text.count("\\x") > 2 or subs.events[3].text.count("\\x") > 2 ): print "Translation failed. Our string got screwed up. Trying again..." else: print "Finished. Writing to file." with open("subs_translated.ass", "w") as subs_out: subs.dump_file(subs_out)
def parse(file_path: str) -> Episode: with open(file_path, encoding='utf-8-sig') as file: serialized_ass = ass.parse(file) title = serialized_ass.fields.get('Title') production_code = int(serialized_ass.fields.get('Original Script')) episode = Episode(production_code, title=title) for event in serialized_ass.events: line = Line(production_code, event.start, event.end, event.name, event.text) episode.add_line(line) return episode
def parse(filename): segments = [] if filename.endswith(".ass"): with open(filename, "r") as f: doc = ass.parse(f) for event in doc.events: if ignore_ass_event(event): continue seg = Segment(event.start, event.end, event.tags_stripped()) segments.append(seg) else: raise Exception("Invalid file format") return segments
def tryOpen(f): """Open a .ass file with a bunch of encodings until one works.""" if not os.path.isfile(f): raise Exception('Invalid file: %s' % (f, )) lastException = None for encoding in ('utf-8', 'utf-16', 'utf-16-le'): try: return ass.parse(open(f, 'r', encoding=encoding).readlines()) except Exception as e: lastException = e raise Exception( 'Cannot find suitable encoding for file %s. Last error: %s' % (f, lastException))
def extractTextFromSubtitles(fileName): tracks = getSubtitleTracks(fileName) output = "" for track in tracks: srtName = exportSRT(fileName, track) lines = [] with open(srtName,"r") as f: doc = ass.parse(f) for event in doc.events: lines.append(cleanLine(event.text)) combined = "\n".join(lines) if "in" in combined or "to" in combined or "for" in combined: output += combined return output
def index_subtitle(index_writer, object_id, file, format): if format not in SUPPORTED_SUBTITLE_FORMATS: raise ESubtitleFormatNotSupported(format) try: if format == SRT: subtitles = srt.parse(file) _index_srt(index_writer, object_id, subtitles) else: doc = ass.parse(file) _index_ass(index_writer, object_id, doc.events) index_writer.commit() except Exception as e: index_writer.cancel() raise e
def main(): used_command = sys.argv.pop(0) doc_title = None rename_styles = False global_sync = 0 files = [] while sys.argv: arg = sys.argv.pop(0) if arg in ('-h', '--help'): usage(used_command) sys.exit(0) elif arg == '-r': rename_styles = True elif arg == '-t': doc_title = sys.argv.pop(0) elif arg == '-g': global_sync = int(sys.argv.pop(0)) * 1000 elif arg == '-s': file_sync = int(sys.argv.pop(0)) * 1000 filename = sys.argv.pop(0) files.append((file_sync, filename)) else: files.append((None, arg)) docs = [] for sync, filename in files: if sync is None: sync = global_sync print('', file=sys.stderr) print('File: {}'.format(filename), file=sys.stderr) print(' Sync: {}'.format(sync), file=sys.stderr) print('', file=sys.stderr) with open(filename, 'r') as f: doc = ass.parse(f) if sync != 0: doc = shift(doc, sync) docs.append(doc) merged_docs = merge(*docs, rename_styles=rename_styles) if doc_title is not None: merged_docs.fields['Title'] = doc_title merged_docs.dump_file(sys.stdout)
def main(path): path = path or "." for f in list_dir(path): if f and f.endswith('.ass'): if f == 'ok': continue print '' print f with open(f, 'r') as f_: doc = ass.parse(f_) print ' fn:', doc.styles[0].fontname print ' fs:', doc.styles[0].fontsize print ' bold:', doc.styles[0].bold print ' shadow:', doc.styles[0].shadow print ' border_style:', doc.styles[0].border_style print ' primary_color: ', doc.styles[0].primary_color for i in range(len(doc.styles)): doc.styles[i].fontname = 'Microsoft YaHei Light' doc.styles[i].fontsize = 13 doc.styles[i].bold = -1 doc.styles[i].shadow = 0 doc.styles[i].outline = 0 doc.styles[i].border_style = 0 doc.styles[i].primary_color = Color(r=0xff, g=0xff, b=0xff, a=0x30) ok_path = os.path.join(path, 'ok') if not os.path.exists(ok_path): os.mkdir(ok_path) new_path = f.replace(path, os.path.join(path, 'ok')) print new_path with open(new_path, 'w') as nf: doc.dump_file(nf) with open(new_path, 'r') as nf: txt = nf.read().replace(en_font_name, 'Microsoft YaHei Light').replace( en_font_size, 'fs11') with open(new_path, 'w') as nf: nf.write(txt)
def edit_two_lang_style(subtitle_file): """ 为ass格式的双语字幕设置style :param subtitle_file: :return: """ with open(subtitle_file, "r") as f: subtitle = ass.parse(f) print(subtitle.styles) # {\fn宋体\fs20\shad2\4a&H50&\3c&HFF8000&\4c&HFF8000&} # Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, # OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, # ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, # Alignment, MarginL, MarginR, MarginV, Encoding # Style: Default,方正黑体_GBK,21,&H00FFFFFF,&HF0000000,&H006C3300, # &H00000000,-1,0,0,0,100,100,0,0,1,2,1,2,5,5,5,134 # subtitle.styles[0].fontname = '方正黑体_GBK' subtitle.styles[0].fontname = '黑体' subtitle.styles[0].fontsize = 21 subtitle.styles[0].primary_color = '&H00FFFFFF' subtitle.styles[0].secondary_color = '&HF0000000' subtitle.styles[0].outline_color = '&H006C3300' subtitle.styles[0].back_color = '&H00000000' subtitle.styles[0].bold = -1 subtitle.styles[0].border_style = 1 subtitle.styles[0].outline = 2 subtitle.styles[0].shadow = 1 subtitle.styles[0].alignment = 2 for events in subtitle.events: utf8string = events.text.decode("utf-8") events.text = utf8string.replace( r'\N', r'\N{\fn黑体\fs14\b0\c&HFFFFFF&\3c&H2F2F2F&\4c&H000000&}' ) with open(subtitle_file, "w") as f: subtitle.dump_file(f) if os.path.exists(subtitle_file): return subtitle_file
def edit_two_lang_style(subtitle_file): """ 为ass格式的双语字幕设置style :param subtitle_file: :return: """ with open(subtitle_file, "r") as f: subtitle = ass.parse(f) print(subtitle.styles) # {\fn宋体\fs20\shad2\4a&H50&\3c&HFF8000&\4c&HFF8000&} # Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, # OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, # ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, # Alignment, MarginL, MarginR, MarginV, Encoding # Style: Default,方正黑体_GBK,21,&H00FFFFFF,&HF0000000,&H006C3300, # &H00000000,-1,0,0,0,100,100,0,0,1,2,1,2,5,5,5,134 # subtitle.styles[0].fontname = '方正黑体_GBK' subtitle.styles[0].fontname = '黑体' subtitle.styles[0].fontsize = 21 subtitle.styles[0].primary_color = '&H00FFFFFF' subtitle.styles[0].secondary_color = '&HF0000000' subtitle.styles[0].outline_color = '&H006C3300' subtitle.styles[0].back_color = '&H00000000' subtitle.styles[0].bold = -1 subtitle.styles[0].border_style = 1 subtitle.styles[0].outline = 2 subtitle.styles[0].shadow = 1 subtitle.styles[0].alignment = 2 for events in subtitle.events: utf8string = events.text.decode("utf-8") events.text = utf8string.replace( r'\N', r'\N{\fn黑体\fs14\b0\c&HFFFFFF&\3c&H2F2F2F&\4c&H000000&}') with open(subtitle_file, "w") as f: subtitle.dump_file(f) if os.path.exists(subtitle_file): return subtitle_file
def AssWeTran(SourceFileName): SourceFile = open(SourceFileName, 'rb') FileEnco = chardet.detect(SourceFile.read()).get('encoding') SourceFile.close() # 按文件编码重新打开文件 SourceFile = codecs.open(SourceFileName, 'rb', FileEnco) TargetFile = codecs.open(SourceFileName + '.srt', 'w', 'utf-8') AssFile = ass.parse(SourceFile) TimeDic = dict() for event in AssFile.events: if not re.match('//', event.text) and not event.text == '': StartTime = str(event.start) EndTime = str(event.end) StartTime = '0' + StartTime StartTime = StartTime[:-3] StartTime = re.sub(r'\.', ',', StartTime) EndTime = '0' + EndTime EndTime = EndTime[:-3] EndTime = re.sub(r'\.', ',', EndTime) Time = StartTime + ' --> ' + EndTime SubTitle = re.sub(r'{[^}]*}', '', event.text) SubTitle = re.sub(r'\\N', '\n', SubTitle) if not Time in TimeDic.keys(): TimeDic[Time] = SubTitle else: TimeDic[Time] = TimeDic[Time] + '\n' + SubTitle i = 1 for key, value in TimeDic.items(): TargetFile.write(str(i)) TargetFile.write('\n') TargetFile.write(key) TargetFile.write('\n') TargetFile.write(value) TargetFile.write('\n') TargetFile.write('\n') i = i + 1 TargetFile.close() return TargetFile.name
def merge_file( self, other_file: argparse.FileType(encoding='utf-8-sig')) -> Subtitles: """Append the styles and event lines from another file.""" f = ass.parse(other_file) self.sub_file.events.extend(f.events) existing_styles = { style.name: style.dump() for style in self.sub_file.styles } for style in f.styles: if style.name in existing_styles and style.dump( ) != existing_styles[style.name]: print( f"Warning: Ignoring style {style.name} from " f"{other_file.name}.", file=sys.stderr) continue self.sub_file.styles.append(style) return self
def _import_file(self, imp_definition, styles, events, fields): # strip extradata info fname = re.sub(r"^\{=\d+(,\d+)*\}", "", imp_definition.text) shifted = imp_definition.effect == 'import-shifted' self._ms_count += 1 self._ms_files[self._ms_count] = fname path = pathlib.Path(self.filename).parent / fname with path.open(encoding='utf-8-sig') as f: imp = ass.parse(f) if shifted: try: sync_line = next(line for line in imp.events if line.effect == 'sync') except StopIteration: raise ValueError(f"No sync line in {fname}") time_diff = imp_definition.start - sync_line.start for line in imp.events: line.start += time_diff line.end += time_diff for line in imp.events: line.layer += imp_definition.layer line.style = f"{self._ms_count}${line.style}" events.append(line) for style in imp.styles: style.name = f"{self._ms_count}${style.name}" styles[style.name] = style for field, value in imp.fields.items(): if field in fields and fields[field] != value: logging.warning( f"Ignoring conflicting value {value} for {field} from {fname}" ) else: fields[field] = value
def load_files(): subtitles = [] videos = [] for filename in os.listdir('.'): if filename.lower().endswith('.ass'): with open(filename, 'r') as f: subtitles.append(Ass(filename, ass.parse(f))) elif filename.lower().endswith(('.mkv', '.mp4')): proc = Popen( ['ffprobe', '-i', filename, '-v', 'quiet', '-print_format', 'json', '-show_streams'], stdout=PIPE, stderr=DEVNULL) out, err = proc.communicate() proc.wait() data = json.loads(out.decode('ascii')) videos.append(Video(filename, data)) videos.sort() subtitles.sort() videos = Collection(videos, 'Video files') subtitles = Collection(subtitles, 'ASS files') return subtitles, videos
def ass_parser(filename): f = codecs.open(filename, 'r', 'utf8') doc = ass.parse(f) f.close() print("length of event is: {}".format(len(doc.events))) doc.events.sort(key=lambda x:x.start) for event in doc.events: event.text = re.sub("{.*?}", "", event.text).replace("\\N", "\n") srtname = filename[:-3] + 'srt' f = codecs.open(srtname, 'w', 'utf8') for index, event in enumerate(doc.events): f.write("%d\n"%(index + 1)) f.write("%s --> %s\n" % (time_string(event.start), time_string(event.end))) f.write(event.text) f.write("\n\n") f.close()
def readAss(fname): if str(fname).endswith('.ass'): with open(fname, 'r', encoding='utf-8') as f: doc = ass.parse(f) dml = [] for evt in doc.events: dm = DanMu() dm.createByAss(evt, doc.play_res_x, doc.play_res_y) dml.append(dm) return doc.styles, dml elif str(fname).endswith(".xml"): tmpfile = fname + "_tmp.ass" print('请自行转换') raise #readAss('dm.ass')
def main(): parser = argparse.ArgumentParser( description="Automatically merge fonts used in a Matroska file.") parser.add_argument('subtitles', help=""" Subtitles containing fonts to be merged. Must be an ASS file. """) parser.add_argument('mkv', help=""" Video where the fonts will go. Must be a Matroska file. """) parser.add_argument('--mkvmerge', metavar="path", help=""" Path to mkvmerge.exe if not in variable environments. """) args = parser.parse_args() if not distutils.spawn.find_executable( "mkvmerge.exe") and args.mkvmerge is None: return print( "fontmerge.py: error: mkvmerge in not in your environnements variable, add it or specify the path to mkvmerge.exe with --mkvmerge." ) if not is_mkv(args.mkv): return print( "fontmerge.py: error: the file on -mkv is not a Matroska file.") if not is_ass(args.subtitles): return print("fontmerge.py: error: the file is not an Ass file.") if not is_writable(args.mkv): return print("fontmerge.py: error: unable to create the file.") with open(args.subtitles, 'r', encoding='utf_8_sig') as f: subtitles = [(os.path.basename(args.subtitles), ass.parse(f))] fonts_path = get_used_font_path(subtitles) merge(args.subtitles, args.mkv, fonts_path, args.mkvmerge) return print("Successfully merging subtitles and mkv")
def ssaProcessor(fname: str): if not os.path.isfile(fname): print(f'Missing file: {fname}') return with open(fname, encoding='utf_8_sig') as f: sub = ssa.parse(f) for s in sub.styles: transformColour(s.primary_color) transformColour(s.secondary_color) transformColour(s.outline_color) transformColour(s.back_color) for e in sub.events: transformEvent(e) output_fname = os.path.splitext(fname) output_fname = output_fname[0] + '.hdr.ass' with open(output_fname, 'w', encoding='utf_8_sig') as f: sub.dump_file(f) print(f'Wrote {output_fname}')
def sub_load(inp_fname): ''' input = ass subtitle file output = subtitle instance and dict with meta_data for easy access (for later) ''' subs_stl = {} #f = io.open(inp_fname, "rb") #doc = ass.parse(f) with open(inp_fname, "r", encoding='utf-8') as f: doc = ass.parse(f) subs = doc.events for i in doc.styles: stl_name = i.name r = i.primary_color.r g = i.primary_color.g b = i.primary_color.b a = i.primary_color.a font_name = i.fontname font_size = i.fontsize subs_stl.update({str(stl_name): {'r':r, 'g':g, 'b':b, 'a':a, 'font_name':font_name, 'font_size':font_size}}) return(subs, subs_stl)
def 字数漢字本ass(名): with open(名, 'r') as 本: 字幕 = (文.text for 文 in ass.parse(本).events) return 字数漢字(字幕)
import argparse import ass import datetime import io import os import re import sys parser = argparse.ArgumentParser() parser.add_argument('--file', help='Subtitle file to operate on.', required=True) parser.add_argument('--operation', help='"add" or "remove".', choices=('add', 'remove'), required=True) parser.add_argument('--begin', help='Interval begin timestamp as a stringified float (number of seconds).') parser.add_argument('--end', help='Interval end timestamp as a stringified float (number of seconds).') args = parser.parse_args() handle = open(args.file, 'r') doc = ass.parse(handle.readlines()) handle.close() begin = datetime.timedelta(seconds=float(args.begin)) end = datetime.timedelta(seconds=float(args.end)) duration = end - begin assert begin <= end if args.operation == 'add': for e in list(doc.events): if e.start > end: # \---int---/ e.start += duration # [---sub---]: Moved forward e.end += duration elif e.start >= begin and e.start <= end: # \-int-/ e.end += duration # [---sub---]: Extended by interval length
def parse(self, file_name, file_encoding): if file_encoding.lower() != "utf-8": file_name = get_utf_8_version(file_name, file_encoding) with open(file_name) as f: self._events = ass.parse(f).events