From 387ea6d91db1b1328621dc1ac2937de607639a3b Mon Sep 17 00:00:00 2001 From: shagi Date: Sun, 16 Feb 2020 16:49:10 +0100 Subject: [PATCH] Primera prueba de gui --- gui/images/logo.png | Bin 0 -> 9850 bytes gui/karaoke.py | 178 ++++++++++++++++++++++++++++++++++++ gui/kv_templates/karaoke.kv | 69 ++++++++++++++ 3 files changed, 247 insertions(+) create mode 100644 gui/images/logo.png create mode 100644 gui/karaoke.py create mode 100644 gui/kv_templates/karaoke.kv diff --git a/gui/images/logo.png b/gui/images/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..1757ed1312cb4a34824d6ed9e07566418f00510d GIT binary patch literal 9850 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 YEqP@^4@3*$kQm~&yqa9G494&O0e9cQd;kCd literal 0 HcmV?d00001 diff --git a/gui/karaoke.py b/gui/karaoke.py new file mode 100644 index 0000000..4b44fbf --- /dev/null +++ b/gui/karaoke.py @@ -0,0 +1,178 @@ +import json +import subprocess +import sys +from pathlib import Path + +import kivy +kivy.require('1.11.1') + +from kivy.app import App +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.endswith('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_image.source = value.cover + + 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 + KaraokeApp(Path(sys.argv[1])).run() diff --git a/gui/kv_templates/karaoke.kv b/gui/kv_templates/karaoke.kv new file mode 100644 index 0000000..b7d80c8 --- /dev/null +++ b/gui/kv_templates/karaoke.kv @@ -0,0 +1,69 @@ +KaraokeGUI: + +: + size_hint: None, None + size: 200, 200 + orientation: 'vertical' + padding: 0 + spacing: 0 + + canvas.before: + Color: + rgb: 0.9, 0.9, 0.9 if self.active else 0.3, 0.3, 0.3 + Line: + rectangle: self.pos[0], self.pos[1], self.size[0], self.size[1] + + Image: + source: self.parent.thumbnail + size_hint: 1, 0.8 + Label: + canvas.before: + Color: + rgb: 0.3, 0.3, 0.3 + Rectangle: + pos: self.pos + size: self.size + size_hint: 1, 0.1 + text: self.parent.name + +: + orientation: 'vertical' + Image: + id: current_song_image + source: '' + Button: + text: '>' + on_press: root.play() + size_hint: 1, 0.1 + + BoxLayout: + orientation: 'horizontal' + height: 220 + size_hint: 1, None + + Button: + size_hint: None, None + size: 20, 220 + text: '<' + on_press: root.previous() + + ScrollView: + id: songs_scroll + do_scroll_x: True + do_scroll_y: False + size_hint: 1, None + height: 220 + + GridLayout: + id: song_container + rows: 1 + width: self.minimum_width + padding: 10 + spacing: 10 + size_hint: None, 1 + + Button: + size_hint: None, None + size: 20, 220 + text: '>' + on_press: root.next()