import json import os import subprocess import asstosrt import srt import webvtt from .utils import needs_change class SongPage: THUMBNAIL_GEOMETRY = '200x200' def __init__(self, path, root): self.name = path.name self.metadata = None self.original = None self.author = None self.path = path self.root = root self.video = None self.video_type = None self.vtt = None self.srt = None self.karaoke_ass = None self.ass = None self.cover = None self.thumbnail = None self.files = [] self.search_media() def search_media(self): for entry in self.path.iterdir(): if entry.name == 'metadata.json': with entry.open('r') as metadatafile: self.metadata = json.load(metadatafile) if 'name' in self.metadata: self.name = self.metadata['name'] if 'original' in self.metadata: self.original = self.metadata['original'] if 'author' in self.metadata: self.author = self.metadata['author'] elif entry.name.endswith('mp4'): self.video = entry self.video_type = 'video/mp4' self.files.append(entry) elif entry.name.endswith('webm'): self.video = entry self.video_type = 'video/webm' self.files.append(entry) elif entry.name.endswith('ogv'): self.video = entry self.video_type = 'video/ogg' self.files.append(entry) elif entry.name.endswith('vtt'): self.vtt = entry elif entry.name == "{}.srt".format(self.path.name): self.srt = entry self.files.append(entry) elif entry.name == "{}.karaoke.ass".format(self.path.name): self.karaoke_ass = entry self.files.append(entry) elif entry.name == "{}.ass".format(self.path.name): self.ass = entry self.files.append(entry) elif entry.name == 'thumb.jpg': self.thumbnail = entry elif entry.name == 'cover.jpg': self.cover = entry elif entry.name == 'index.html': continue else: self.files.append(entry) srt = self.path / "{}.srt".format(self.path.name) if needs_change(srt, (self.ass,)): self.srt = srt with self.ass.open('r') as assfile, self.srt.open('w') as srtfile: srtfile.write(asstosrt.convert(assfile)) self.files.append(self.srt) vtt = self.path / "{}.vtt".format(self.path.name) if needs_change(vtt, (self.srt,)): self.vtt = vtt webvtt.from_srt(str(self.srt.absolute())).save(str(self.vtt.absolute())) cover = self.path / "cover.jpg" if needs_change(cover, (self.video,)): self.cover = cover command = [ 'ffmpeg', '-loglevel', 'quiet', '-i', str(self.video.absolute()), '-vcodec', 'mjpeg', '-vframes', '1', '-an', '-f', 'rawvideo', '-ss', '2', '-y', str(self.cover.absolute()), ] subprocess.check_call(command) thumbnail = self.path / "thumb.jpg" if needs_change(thumbnail, (self.cover,)): self.thumbnail = thumbnail subprocess.check_call([ 'convert', str(self.cover.absolute()), '-resize', self.THUMBNAIL_GEOMETRY, str(self.thumbnail.absolute()), ]) @property def publish(self): has_subtitles = self.ass or self.srt or self.vtt has_video = self.video return has_video and has_subtitles def get_context_data(self): parsed_srt = None if self.srt: with self.srt.open('r') as srtfile: try: srt_str = srtfile.read().encode('utf-8').decode('utf-8-sig') parsed_srt = list(srt.parse(srt_str)) except Exception as e: print("{}: srt parse error: {}".format(self.path.name, e)) root_path = os.path.relpath(self.root, self.path) return { 'song': self, 'parsed_srt': parsed_srt, 'root_path': root_path, } def render(self, builder, context): ctx = self.get_context_data() ctx.update(context) builder.render('song.html', self.path, ctx) def load_songs(root_folder): songs = [] pending_songs = [] for entry in root_folder.iterdir(): if entry.name in ['static', 'playlist', 'home', 'todo']: continue if entry.is_dir(): print("building {}".format(entry.name)) try: songpage = SongPage(entry, root_folder) except Exception as e: raise e print("Error: {}".format(e)) continue if songpage.publish: songs.append(songpage) else: pending_songs.append(songpage) songs.sort(key=lambda a: a.name) return songs, pending_songs