def test_r_named_tag(): styles = {"other style": SSAStyle(bold=True)} text = "Hello, {\\rother style\\i1}world!" assert parse_tags(text, styles=styles) == \ [("Hello, ", SSAStyle()), ("world!", SSAStyle(italic=True, bold=True))]
def test_import_styles(): red1 = SSAStyle() red2 = SSAStyle() green = SSAStyle() subs1 = SSAFile() subs2 = SSAFile() def prepare(): subs1.styles = {} subs2.styles = {} subs1.styles["green"] = green subs1.styles["red"] = red1 subs2.styles["red"] = red2 prepare() subs2.import_styles(subs1) assert subs2.styles["green"] is green assert subs2.styles["red"] is red1 prepare() subs2.import_styles(subs1, overwrite=False) assert subs2.styles["green"] is green assert subs2.styles["red"] is red2 with assert_raises(TypeError): subs2.import_styles({})
def test_rename_style(): subs = SSAFile() red = SSAStyle() green = SSAStyle() def prepare(): subs.events = [SSAEvent(style="red"), SSAEvent(style="unrelated")] subs.styles = dict(red=red, green=green) prepare() subs.rename_style("red", "blue") assert "red" not in subs.styles assert subs.styles["blue"] is red assert subs[0].style == "blue" assert subs[1].style == "unrelated" prepare() with assert_raises(ValueError): # cannot delete style via move subs.rename_style("red", "green") prepare() with assert_raises(ValueError): subs.rename_style("red", "illegal,name") with assert_raises(ValueError): subs.rename_style("red", "illegal\nname") with assert_raises(KeyError): subs.rename_style("nonexistent-style", "blue")
def build_ref(): subs = SSAFile() subs.info["My Custom Info"] = "Some: Test, String." subs.styles["left"] = SSAStyle(alignment=7, bold=True) subs.styles["topleft"] = SSAStyle(alignment=4) subs.append(SSAEvent(start=0, end=make_time(m=1), text="An, example, subtitle.")) subs.append(SSAEvent(start=0, end=make_time(m=1), type="Comment", text="You can't see this one.")) subs.append(SSAEvent(start=make_time(m=1), end=make_time(m=2), text="Subtitle number\\Ntwo.")) return subs
def test_repr_simple(): subs = SSAFile() subs.append(SSAEvent(start=make_time(m=5), end=make_time(m=6))) subs.append(SSAEvent(start=make_time(m=125), end=make_time(m=126))) subs.append(SSAEvent(start=make_time(m=15), end=make_time(m=16))) subs.styles["style1"] = SSAStyle() subs.styles["style2"] = SSAStyle() ref = "<SSAFile with 3 events and 3 styles, last timestamp 2:06:00>" assert repr(subs) == ref
def test_non_ascii_str_fields(): # see issue #12 STYLE_NAME = "my-style" FONT_NAME = b"NonAsciiString\xff" subs = SSAFile() line = SSAEvent(style=STYLE_NAME) subs.events.append(line) style = SSAStyle(fontname=FONT_NAME) subs.styles[STYLE_NAME] = style # in all Pythons, saving subtitles with non-unicode fields # fails when they are not in ASCII range with assert_raises(TypeError): subs.to_string("ass")
def create_ssa_file(): subs = SSAFile() subs.styles['top'] = SSAStyle(alignment=8) subs.styles['bottom'] = SSAStyle(alignment=2) subs.styles['left'] = SSAStyle(alignment=4) subs.styles['left_red'] = SSAStyle(alignment=4, primarycolor=Color(255, 0, 0, 0)) subs.styles['red'] = SSAStyle(primarycolor=Color(255, 0, 0, 0)) subs.styles['right'] = SSAStyle(alignment=6) return subs
def test_write_read(): subs = SSAFile() e1 = SSAEvent(text="Hello, world!") e2 = SSAEvent(text="The other subtitle.\\NWith two lines.", style="custom style") s1 = SSAStyle(italic=True, primarycolor=Color(r=255, g=0, b=0, a=0)) subs.append(e1) subs.append(e2) subs.styles["custom style"] = s1 json_text = subs.to_string("json") subs2 = SSAFile.from_string(json_text, "json") assert subs2.equals(subs)
def test_ascii_str_fields(): # see issue #12 STYLE_NAME = b"top-style" subs = SSAFile() line = SSAEvent(style=STYLE_NAME) subs.events.append(line) style = SSAStyle() subs.styles[STYLE_NAME] = style if sys.version_info.major == 2: # in Python 2, saving subtitles with non-unicode fields is tolerated # as long as they do not fall outside of ASCII range subs.to_string("ass") else: # in Python 3, we are strict and enforce Unicode with assert_raises(TypeError): subs.to_string("ass")
def test_writer_tags(): subs = SSAFile() subs.styles["italic_style"] = SSAStyle(italic=True) subs.events = [ SSAEvent(start=0, end=10, text=r"Plain."), SSAEvent(start=0, end=10, text=r"{\i1}Inline."), SSAEvent(start=0, end=10, text=r"Styled.", style="italic_style"), SSAEvent(start=0, end=10, text=r"{\i1}Also{\i0} {\ritalic_style}italic."), SSAEvent(start=0, end=10, text=r"Not {\i1}italic.") ] f = dedent("""\ {0}{0}1000 {0}{10}Plain. {0}{10}{Y:i}Inline. {0}{10}{Y:i}Styled. {0}{10}{Y:i}Also italic. {0}{10}Not italic. """) assert subs.to_string("microdvd", 1000) == f
import os import pysubs2 from pysubs2 import SSAStyle from zhconv import convert DEFAULT_STYLE = SSAStyle(fontname='STKaiti', fontsize=18, outline=1, shadow=1) OUTPUT_DIR = 'K:\\书包\\自制字幕' def main(): while (file := input('srt path: ')) != '': trans(file) def trans(file): try: subs = pysubs2.load(file) except UnicodeDecodeError: try: subs = pysubs2.load(file, 'gbk') except UnicodeDecodeError: subs = pysubs2.load(file, 'utf-16') subs.styles['Default'] = DEFAULT_STYLE subs.info['PlayResX'] = '384' subs.info['PlayResY'] = '288' subs.info['ScaledBorderAndShadow'] = 'no' for line in subs: line.text = convert(line.text, 'zh-cn') subs.save(output_file(file))
def test_r_tag(): text = "{\\i1}Hello, {\\r}world!" assert parse_tags(text) == [("", SSAStyle()), ("Hello, ", SSAStyle(italic=True)), ("world!", SSAStyle())]
def test_no_tags(): text = "Hello, world!" assert parse_tags(text) == [(text, SSAStyle())]
def test_repr_italic(): ev = SSAStyle(fontname="Calibri", fontsize=36, italic=True) ref = "<SSAStyle 36px italic 'Calibri'>" assert repr(ev) == ref
def test_repr_plain(): ev = SSAStyle(fontname="Calibri", fontsize=36) ref = "<SSAStyle 36px 'Calibri'>" assert repr(ev) == ref
def renderVideo(video, rendering_screen): global render_current_progress, render_max_progress, render_message t0 = datetime.datetime.now() clips = video.clips colour1 = getColour(video.colour1) colour2 = getColour(video.colour2) music_type = video.audio_cat subprocess._cleanup = lambda: None credits = [] streamers_in_cred = [] render_current_progress = 0 # see where render_current_progress += 1 amount = 0 for clip in clips: if clip.isUsed: amount += 1 render_max_progress = amount * 3 + 1 + 1 render_message = "Beginning Rendering" rendering_screen.render_progress.emit() current_date = datetime.datetime.today().strftime("%m-%d-%Y__%H-%M-%S") fClips = [] start_duration = 0 end_duration = 0 # render progress 1 for i, clip in enumerate(clips): if clip.isUsed: name = clip.streamer_name mp4 = clip.mp4 subs = SSAFile() if name is not None and name not in streamers_in_cred and not clip.isUpload: credits.append( f"Streamer: {clip.streamer_name} Channel: {clip.channel_url}" ) streamers_in_cred.append(clip.streamer_name) if clip.start_cut is None: clip.start_cut = 0 if clip.end_cut is None: clip.end_cut = 0 start_trim = round(clip.start_cut / 1000, 1) end_trim = round(clip.end_cut / 1000, 1) final_duration = round(clip.vid_duration - end_trim - start_trim, 1) audio = clip.audio if name is None: name = "" render_message = f"Adding text ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() subs.styles['vidText'] = SSAStyle(alignment=7, fontname='Gilroy-ExtraBold', fontsize=25, marginl=4, marginv=-2.5, marginr=0, outline=2, outlinecolor=colour2, primarycolor=colour1, shadow=0) if settings.includeStreamerName: subs.append( SSAEvent(start=make_time(s=0), end=make_time(s=60), style='vidText', text=f"{name}")) subs.save(f'subtitleFile.ass') render_current_progress += 1 render_message = f"Done Adding text ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() print(f"Adding text ({i + 1}/{len(clips)}) to video: {mp4}.mp4") render_message = f"Adding text to video ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() print( f"Rendering video ({i + 1}/{len(clips)}) to \"{settings.vid_finishedvids}\"/{mp4}_finished.mp4" ) mp4name = mp4 mp4path = f"{mp4}.mp4" if len(mp4.split("/")) > 2: name = len(mp4.split("/")) mp4name = mp4.split("/")[name - 1].replace(".mp4", "") mp4path = mp4[1:] if not clip.isInterval and not clip.isIntro: print("%s duration %s" % (mp4name, final_duration)) if end_trim == 0 and start_trim == 0: print("%s no trim" % mp4name) os.system( f"ffmpeg -y -fflags genpts -i \"{mp4path}\" -vf \"ass=subtitleFile.ass, scale=1920:1080\" \"{settings.vid_finishedvids}/{mp4name}_finished.mp4\"" ) elif end_trim > 0 and start_trim > 0: print("%s start trim %s and end trim %s" % (mp4name, start_trim, end_trim)) os.system( f"ffmpeg -y -fflags genpts -i \"{mp4path}\" -ss {start_trim} -t {final_duration} -vf \"ass=subtitleFile.ass, scale=1920:1080\" \"{settings.vid_finishedvids}/{mp4name}_finished.mp4\"" ) elif end_trim > 0 and start_trim == 0: print("%s end trim %s" % (mp4name, end_trim)) os.system( f"ffmpeg -y -fflags genpts -i \"{mp4path}\" -t {clip.vid_duration - end_trim} -vf \"ass=subtitleFile.ass, scale=1920:1080\" \"{settings.vid_finishedvids}/{mp4name}_finished.mp4\"" ) elif end_trim == 0 and start_trim > 0: print("%s start trim %s" % (mp4name, start_trim)) os.system( f"ffmpeg -y -fflags genpts -i \"{mp4path}\" -ss {start_trim} -vf \"ass=subtitleFile.ass, scale=1920:1080\" \"{settings.vid_finishedvids}/{mp4name}_finished.mp4\"" ) render_current_progress += 1 render_message = f"Done Adding text to video ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() render_message = f"Adding clip to list ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() if not clip.isInterval and not clip.isIntro: finish = VideoFileClip( f'{settings.vid_finishedvids}/{mp4name}_finished.mp4').fx( afx.volumex, audio) else: finish = VideoFileClip(f'{mp4path}').fx(afx.volumex, audio) end_duration += finish.duration fClips.append(finish) render_current_progress += 1 render_message = f"Done Adding clip to list ({i + 1}/{len(clips)})" rendering_screen.render_progress.emit() if i <= 2: start_duration += finish.duration musicFiles = getFileNames(f'{settings.asset_file_path}/Music') random.shuffle(musicFiles) print("done working out durations") final_concat = concatenate_videoclips(fClips) print("done combining clips") print(musicFiles) # render progress 2 render_message = "Creating audio loop" rendering_screen.render_progress.emit() #audio = AudioFileClip(f'{settings.asset_file_path}/Music/{musicFiles[0]}.mp3').fx(afx.volumex, float(video.background_volume)) print("Using music type %s" % music_type) musicFolders = (getFileNames("Assets/Music")) if not musicFolders: music_type = "None" print("No music folders, defaulting to no audio") if not music_type == "None": to_combine = [] music_combined_duration = 0 while music_combined_duration < end_duration: random_file = random.choice( os.listdir(f'{settings.asset_file_path}/Music/{music_type}')) sound1 = AudioSegment.from_wav( f"Assets/Music/{music_type}/{random_file}") music_combined_duration += sound1.duration_seconds to_combine.append(sound1) combined_sounds = sum(to_combine) combined_sounds.export(f"{settings.temp_path}/music-loop-uncut.wav", format="wav") audio_loop_without_pause = AudioSegment.from_wav( "%s/music-loop-uncut.wav" % settings.temp_path) new_audio = AudioSegment.silent( duration=(start_duration * 1000)) + audio_loop_without_pause new_audio.export( f"{settings.temp_path}/music-loop-uncut_with_pause.mp3", format="mp3") music_loop = afx.audio_loop(AudioFileClip( f"{settings.temp_path}/music-loop-uncut_with_pause.mp3"), duration=end_duration).fx( afx.volumex, float(video.background_volume)) #music_loop = afx.audio_loop(audio, duration=end_duration) music_loop.write_audiofile(f'{settings.temp_path}/music-loop.mp3') render_current_progress += 1 render_message = "Done Creating audio loop" rendering_screen.render_progress.emit() # render progress 3 render_message = "Writing final video" rendering_screen.render_progress.emit() if not music_type == "None": final_vid_with_music = final_concat.set_audio( CompositeAudioClip([ final_concat.audio, AudioFileClip(f'{settings.temp_path}/music-loop.mp3') ])) else: final_vid_with_music = final_concat.set_audio(final_concat.audio) sleep(5) final_vid_with_music.write_videofile( f'{settings.final_video_path}/TwitchMoments_{current_date}.mp4', fps=settings.fps, threads=16) render_current_progress += 1 t1 = datetime.datetime.now() total = t1 - t0 render_message = "Done writing final video (%s)" % total rendering_screen.render_progress.emit() f = open(f"{settings.final_video_path}/TwitchMoments_{current_date}.txt", "w+") f.write("A special thanks to the following: \n\n") for cred in credits: f.write(cred + "\n") f.close() sleep(10)
def merge(file1, file2, outfile): subs1 = pysubs2.load(file1, encoding=charset_detect(file1)) subs2 = pysubs2.load(file2, encoding=charset_detect(file2)) '''[V4+ Styles] 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,Arial, 16, &H00FFFFFF, &H00FFFFFF, &H00000000, &H00000000,-1, 0, 0, 0 ,100 ,100 ,0 ,0 ,1 ,3 ,0 ,2 ,10 ,10 ,10 ,0 Style: Top ,Arial ,16 ,&H00F9FFFF ,&H00FFFFFF ,&H00000000 ,&H00000000,-1 ,0 ,0 ,0 ,100 ,100 ,0 ,0 ,1 ,3 ,0 ,8 ,10 ,10 ,10 ,0 Style: Mid ,Arial ,16 ,&H0000FFFF ,&H00FFFFFF ,&H00000000 ,&H00000000,-1 ,0 ,0 ,0 ,100 ,100 ,0 ,0 ,1 ,3 ,0 ,5 ,10 ,10 ,10 ,0 Style: Bot ,Arial ,16 ,&H00F9FFF9 ,&H00FFFFFF ,&H00000000 ,&H00000000,-1 ,0 ,0 ,0 ,100 ,100 ,0 ,0 ,1 ,3 ,0 ,2 ,10 ,10 ,10 ,0 ''' style_top = SSAStyle() style_bot = SSAStyle() style_top.primarycolor = Color(249, 255, 255) style_bot.primarycolor = Color(249, 255, 249) style_bot.secondarycolor = Color(255, 255, 255) style_top.secondarycolor = Color(255, 255, 255) style_top.outline = 1.0 style_bot.outline = 1.0 style_top.shadow = 0.0 style_bot.shadow = 0.0 style_top.alignment = 8 style_bot.alignment = 2 # style_top.encoding # не знаю что значит, по умолчанию 1, в примере 0, оставлю 1 subs2.styles['bot'] = style_bot subs2.styles['top'] = style_top for line in subs2: line.style = 'bot' for line in subs1: line.style = 'top' subs2.append(line) subs2.styles["Default"].fontsize = 14.0 subs2.styles["Default"].shadow = 0.5 subs2.styles["Default"].outline = 1.0 subs2.save(outfile)
def test_i_tag(): text = "Hello, {\\i1}world{\\i0}!" assert parse_tags(text) == [("Hello, ", SSAStyle()), ("world", SSAStyle(italic=True)), ("!", SSAStyle())]
def test_repr_floatsize(): ev = SSAStyle(fontname="Calibri", fontsize=36.499) ref = "<SSAStyle 36.499px 'Calibri'>" assert repr(ev) == ref
def add_styles(subs, style_list=None): """ Add styles to the subtitle file based on the style strings in each individual subtitle """ if style_list is None: style_list = [] for style in style_list: new_style = SSAStyle() # Number for position refers to the number on a keypad if 'top_left' in style: new_style.alignment = 7 elif 'top_right' in style: new_style.alignment = 9 elif 'bottom_left' in style: new_style.alignment = 1 elif 'bottom_right' in style: new_style.alignment = 3 elif 'left' in style: new_style.alignment = 4 elif 'right' in style: new_style.alignment = 6 elif 'top' in style: new_style.alignment = 8 elif 'bottom' in style: new_style.alignment = 2 # Setting the RGB values for the text if 'pred' in style: new_style.primarycolor = Color(255, 0, 0, 0) elif 'pblue' in style: new_style.primarycolor = Color(0, 0, 255, 0) elif 'pgreen' in style: new_style.primarycolor = Color(0, 255, 0, 0) elif 'pwhite' in style: new_style.primarycolor = Color(255, 255, 255, 0) # Setting the RGB values for the text's background if 'bred' in style: new_style.backcolor = Color(255, 0, 0, 0) elif 'bblue' in style: new_style.backcolor = Color(0, 0, 255, 0) elif 'bgreen' in style: new_style.backcolor = Color(0, 255, 0, 0) elif 'bwhite' in style: new_style.backcolor = Color(255, 255, 255, 0) # Setting different font types if 'bold' in style: new_style.bold = True if 'italic' in style: new_style.italic = True subs.styles[style] = new_style return subs