import json import subprocess import sys from pathlib import Path import kivy kivy.require('1.11.1') from kivy.app import App from kivy.config import Config from kivy.core.window import Window from kivy.properties import StringProperty, ObjectProperty, ListProperty, BooleanProperty from kivy.uix.boxlayout import BoxLayout from kivy.uix.button import Button from kivy.uix.widget import Widget class Song(BoxLayout): active = BooleanProperty(False) path = ObjectProperty('') def on_path(self, instance, value): self.search_media() def search_media(self): self.name = self.path.name self.original = None self.author = None self.video = None self.video_type = None self.vtt = None self.srt = None self.ass = None self.cover = None self.thumbnail = None self.files = [] 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 = str(entry) self.video_type = 'video/mp4' elif entry.name.endswith('webm'): self.video = str(entry) self.video_type = 'video/webm' elif entry.name.endswith('ogv'): self.video = str(entry) self.video_type = 'video/ogg' elif entry.name.endswith('vtt'): self.vtt = str(entry) elif entry.name == "{}.srt".format(self.path.name): self.srt = str(entry) elif entry.name.endswith('ass'): self.ass = str(entry) elif entry.name == 'thumb.jpg': self.thumbnail = str(entry) elif entry.name == 'cover.jpg': self.cover = str(entry) elif entry.name == 'index.html': continue @property def publish(self): return self.video and self.subtitle @property def subtitle(self): return self.ass or self.srt or self.vtt class KaraokeGUI(BoxLayout): active_song = ObjectProperty(None) songs = ListProperty([]) def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.keyboard = Window.request_keyboard( self.keyboard_closed, self, 'text', ) self.keyboard.bind(on_key_down=self.on_key_down) def on_key_down(self, keyboard, keycode, text, modifiers): if text == 'a': self.previous() return True elif text == 'd': self.next() return True elif text == 's': self.play() return True return False def keyboard_closed(self): pass def on_songs(self, instance, value): container = self.ids['song_container'] container.clear_widgets() for song in self.songs: container.add_widget(song) self.active_song = self.songs[0] def on_active_song(self, instance, value): for song in self.songs: song.active = False value.active = True current_song_image = self.ids['current_song_image'] current_song_title = self.ids['current_song_title'] current_song_image.source = value.cover current_song_title.text = value.name scrollview = self.ids['songs_scroll'] scrollview.scroll_to(value) def previous(self): idx = self.songs.index(self.active_song) if idx > 0: idx -= 1 else: idx = len(self.songs) - 1 self.active_song = self.songs[idx] def next(self): idx = self.songs.index(self.active_song) if idx < len(self.songs) - 1: idx += 1 else: idx = 0 self.active_song = self.songs[idx] def play(self): subprocess.call([ 'vlc', '--fullscreen', '--sub-file', self.active_song.subtitle, self.active_song.video, 'vlc://quit' ]) class KaraokeApp(App): kv_directory = 'kv_templates' def __init__(self, root_folder, **kwargs): super().__init__(**kwargs) self.root_folder = root_folder def build(self): super().build() songs = [] container = self.root.ids['song_container'] for entry in self.root_folder.iterdir(): if entry.is_dir(): song = Song( path=entry, ) if song.publish: songs.append(song) self.root.songs = songs return self.root if __name__ == '__main__': Window.fullscreen = True Config.set('graphics', 'font_name', 'CyrBit.ttf') Config.write() KaraokeApp(Path(sys.argv[1])).run()