diff --git a/config.txt b/config.txt index 8935c021..84707ed8 100644 --- a/config.txt +++ b/config.txt @@ -23,6 +23,7 @@ album.art = True auto.play = True long.press.time.ms = 700 poweroff = True +check.for.updates = False [logging] file.logging = False @@ -32,7 +33,7 @@ enable.stdout = True show.mouse.events = False [file.browser] -audio.file.extensions = mp3,wav,wv,flac,ape +audio.file.extensions = aac,ac3,aiff,ape,flac,m4a,mp3,mp4,ogg,opus,wav,wma,wv playlist.file.extensions = m3u,cue folder.images = folder.jpg,folder.png,cover.jpg,cover.png,front.jpg,front.png cover.art.folders = covers,artwork,scans,art @@ -40,6 +41,9 @@ auto.play.next.track = True cyclic.playback = True hide.folder.name = False folder.image.scale.ratio = 0.8 +rows = 3 +columns = 3 +alignment = center [web.server] http.port = 8000 @@ -58,6 +62,8 @@ audiobooks = True stream = False cd-player = False podcasts = True +airplay = False +spotify-connect = False [home.navigator] back = True @@ -79,11 +85,20 @@ spectrum = True lyrics = True random = True +[languages.menu] +English-USA = True +German = True +French = True +Italian = True +Spanish = True +Russian = True + [voice.assistant] type = Google Assistant credentials = c:\ga\credentials.json device.model.id = Peppy device.id = my_peppy +command.display.time = 1 [colors] color.web.bgr = 0,38,40 @@ -99,6 +114,14 @@ color.mute = 242,107,106 font.name = FiraSans.ttf [scripts] -startup.script.name = startup.py -shutdown.script.name = shutdown.py +startup.script.name = +shutdown.script.name = +[rotary.encoders] +gpio.volume.up = 16 +gpio.volume.down = 26 +gpio.mute = 13 +gpio.move.left = 6 +gpio.move.right = 12 +gpio.select = 5 +jitter.filter = 1 diff --git a/current.txt b/current.txt index 181e1a1b..4ee6c695 100644 --- a/current.txt +++ b/current.txt @@ -1,48 +1,47 @@ [current] -mode = -language = -stream = +mode = +language = +stream = equalizer = [player.settings] -volume = -mute = -pause = +volume = +mute = +pause = [file.playback] -file.playback.mode = -folder = -file.playlist = -file = -track.time = +file.playback.mode = +folder = +file.playlist = +file = +track.time = [cd.playback] -cd.drive.id = -cd.drive.name = -cd.track = -cd.track.time = +cd.drive.id = +cd.drive.name = +cd.track = +cd.track.time = [audiobooks] -site = -book.title = -book.url = -book.track.filename = -book.time = +site = +book.title = +book.url = +book.track.filename = +book.time = [podcasts] -podcast.url = -podcast.episode.name = -podcast.episode.url = -podcast.episode.time = +podcast.url = +podcast.episode.name = +podcast.episode.url = +podcast.episode.time = [screensaver] -name = -delay = +name = +delay = [timer] -sleep.time = -sleep = -poweroff = -wake.up.time = -wake.up = - +sleep.time = +sleep = +poweroff = +wake.up.time = +wake.up = diff --git a/event/dispatcher.py b/event/dispatcher.py index b254dc2f..ebeb2fcb 100644 --- a/event/dispatcher.py +++ b/event/dispatcher.py @@ -23,7 +23,8 @@ from ui.screen.station import StationScreen from ui.screen.fileplayer import FilePlayerScreen from util.config import USAGE, USE_LIRC, USE_ROTARY_ENCODERS, SCREEN_INFO, FRAME_RATE, SHOW_MOUSE_EVENTS, \ - FLIP_TOUCH_XY, WIDTH, HEIGHT, MULTI_TOUCH + FLIP_TOUCH_XY, WIDTH, HEIGHT, MULTI_TOUCH, ROTARY_ENCODERS, GPIO_VOLUME_UP, GPIO_VOLUME_DOWN, GPIO_MUTE, \ + GPIO_MOVE_LEFT, GPIO_MOVE_RIGHT, GPIO_SELECT, JITTER_FILTER from util.keys import kbd_keys, KEY_SUB_TYPE, SUB_TYPE_KEYBOARD, \ KEY_ACTION, KEY_KEYBOARD_KEY, KEY_VOLUME_UP, KEY_VOLUME_DOWN, USER_EVENT_TYPE, VOICE_EVENT_TYPE @@ -124,17 +125,21 @@ def init_lirc(self): def init_rotary_encoders(self): """ Rotary encoders (RE) initializer. - This is executed only if RE enabled in config.txt. Two REs are configured this way: - 1. Volume Control: GPIO16 - Volume Up, GPIO26 - Volume Down, GPIO13 - Mute - 2. Tuning: GPIO12 - Move Right, GPIO6 - Move Left, GPIO5 - Select - RE events will be wrapped into keyboard events with the following assignment: - Volume Up - '+' key on numeric keypad, Volume Down - '-' key on keypad, Mute - 'x' key + This is executed only if RE enabled in config.txt. + RE events will be wrapped into keyboard events. """ if not self.config[USAGE][USE_ROTARY_ENCODERS]: return from event.rotary import RotaryEncoder - RotaryEncoder(16, 26, 13, pygame.K_KP_PLUS, pygame.K_KP_MINUS, pygame.K_x) - RotaryEncoder(12, 6, 5, pygame.K_RIGHT, pygame.K_LEFT, pygame.K_RETURN) + volume_up = self.config[ROTARY_ENCODERS][GPIO_VOLUME_UP] + volume_down = self.config[ROTARY_ENCODERS][GPIO_VOLUME_DOWN] + mute = self.config[ROTARY_ENCODERS][GPIO_MUTE] + move_left = self.config[ROTARY_ENCODERS][GPIO_MOVE_LEFT] + move_right = self.config[ROTARY_ENCODERS][GPIO_MOVE_RIGHT] + select = self.config[ROTARY_ENCODERS][GPIO_SELECT] + jitter_filter = self.config[ROTARY_ENCODERS][JITTER_FILTER] + RotaryEncoder(volume_up, volume_down, mute, pygame.K_KP_PLUS, pygame.K_KP_MINUS, pygame.K_x, jitter_filter) + RotaryEncoder(move_right, move_left, select, pygame.K_RIGHT, pygame.K_LEFT, pygame.K_RETURN, jitter_filter) def handle_lirc_event(self, code): """ LIRC event handler. diff --git a/event/rotary.py b/event/rotary.py index f734343e..b0cdfeff 100644 --- a/event/rotary.py +++ b/event/rotary.py @@ -34,7 +34,6 @@ class RotaryEncoder(object): ANTICLOCKWISE=2 BUTTONDOWN=3 BUTTONUP=4 - ROTARY_JITTER_TOLERANCE = 2 KEY_DOWN_UP_INTERVAL = 0.1 rotary_a = 0 @@ -43,7 +42,7 @@ class RotaryEncoder(object): last_state = 0 direction = 0 - def __init__(self, pinA, pinB, button, key_increment, key_decrement, key_select): + def __init__(self, pinA, pinB, button, key_increment, key_decrement, key_select, jitter_filter): """ Initializer :param pinA: GPIO pin number to increment @@ -52,6 +51,7 @@ def __init__(self, pinA, pinB, button, key_increment, key_decrement, key_select) :param key_increment: keyboard key for increment event :param key_decrement: keyboard key for decrement event :param key_select: keyboard key for selection event + :param jitter_filter: jitter filter 0-no filter, 2 - two clicks before event """ self.lock = RLock() try: @@ -67,6 +67,7 @@ def __init__(self, pinA, pinB, button, key_increment, key_decrement, key_select) self.key_increment = key_increment self.key_decrement = key_decrement self.key_select = key_select + self.jitter_filter = jitter_filter self.gpio.setmode(self.gpio.BCM) self.gpio.setwarnings(False) self.gpio.setup(self.pinA, self.gpio.IN, pull_up_down=self.gpio.PUD_UP) @@ -144,7 +145,7 @@ def handle_event(self, event): if event == RotaryEncoder.CLOCKWISE: logging.debug("Clockwise") - if self.increment_counter == self.ROTARY_JITTER_TOLERANCE: + if self.increment_counter == self.jitter_filter: d[KEY_KEYBOARD_KEY] = self.key_increment self.increment_counter = 0 self.decrement_counter = 0 @@ -154,7 +155,7 @@ def handle_event(self, event): return elif event == RotaryEncoder.ANTICLOCKWISE: logging.debug("Anti-Clockwise") - if self.decrement_counter == self.ROTARY_JITTER_TOLERANCE: + if self.decrement_counter == self.jitter_filter: d[KEY_KEYBOARD_KEY] = self.key_decrement self.decrement_counter = 0 self.increment_counter = 0 diff --git a/icons/airplay.svg b/icons/airplay.svg new file mode 100644 index 00000000..514bbf2c --- /dev/null +++ b/icons/airplay.svg @@ -0,0 +1,966 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/icons/podcasts.svg b/icons/podcasts.svg index c691e8df..2db29319 100644 --- a/icons/podcasts.svg +++ b/icons/podcasts.svg @@ -1,8 +1,8 @@ - + width="40.763px" height="52.006px" viewBox="0 0 40.763 52.006" enable-background="new 0 0 40.763 52.006" xml:space="preserve"> + @@ -941,19 +941,19 @@ - + diff --git a/icons/spotify-connect.svg b/icons/spotify-connect.svg new file mode 100644 index 00000000..f5704e83 --- /dev/null +++ b/icons/spotify-connect.svg @@ -0,0 +1,976 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/languages/English-USA/labels.properties b/languages/English-USA/labels.properties index b5868eae..4a6e44da 100644 --- a/languages/English-USA/labels.properties +++ b/languages/English-USA/labels.properties @@ -1,5 +1,9 @@ about = About +add.station = Add Station +add.stream = Add Stream +airplay = AirPlay album.art = Album Art +alignment = Alignment animated = Animated audio.file.extensions = Audio File Extensions audio-files = Audio Files @@ -14,6 +18,8 @@ browser.stream.player = Browser Stream Player cd-player = CD Player cd.drives = CD Drives cd.track = Track +center = Center +check.for.updates = Check for Updates city = City city.label = City Label choose.author = Choose Author @@ -21,7 +27,11 @@ choose.genre = Choose Genre choose.track = Choose Track client.name = Client Name clock = Clock +colors = Colors +columns = Columns +command.display.time = Command Display Time configuration = Configuration +confirm.delete.image = Are you sure you want to delete image? confirm.reboot.message = The current playback will be stopped and the system will be rebooted. confirm.save.reboot.message = All current changes will be saved and player will be rebooted. confirm.save.shutdown.message = All current changes will be saved and player will be shutdown. @@ -32,7 +42,6 @@ confirm.save.shutdown.title = Would you like to save changes before shutdown? confirm.shutdown.title = Are you sure you want to shutdown? connected = Connected connecting = Connecting... -colors = Colors console.logging = Console Logging country = Country cover.art.folders = Cover Art Folders @@ -43,6 +52,7 @@ delay = Screensaver Delay delay.1 = 1 min delay.3 = 3 min delay.off = Off +delete.image = Delete Image depth = Depth device.id = Device ID device.model.id = Device Model ID @@ -50,7 +60,7 @@ disconnected = Disconnected disconnecting = Disconnecting... display = Display enable.stdout = Enable stdout -english = English +English-USA = English enter.password = Enter Password equalizer = Equalizer file.browser = File Browser @@ -62,8 +72,14 @@ font = Font font.name = Font Name frames.sec = frames/sec frame.rate = Frame Rate -french = French -german = German +French = French +German = German +gpio.mute = GPIO Mute +gpio.move.left = GPIO Move Left +gpio.move.right = GPIO Move Right +gpio.select = GPIO Select +gpio.volume.up = GPIO Volume Up +gpio.volume.down = GPIO Volume Down green = Green hdmi = HDMI headless = Headless @@ -74,7 +90,12 @@ home.menu = Home Menu home.navigator = Home Navigator http.port = HTTP Port https = HTTPS +Italian = Italian +jitter.filter = Jitter Filter language = Language +languages.menu = Languages +left = Left +link = Link lirc = LIRC loading = Loading... log.filename = Log Filename @@ -89,8 +110,10 @@ ms = ms multi.touch = Multi-touch music.folder.linux = Music Folder Linux music.folder.windows = Music Folder Windows +name = Name network = Network new.books = Audiobooks +new.version.released = New Version Released - {edition} no = No no.frame = No Frame nothing.save = Nothing to save @@ -108,6 +131,7 @@ pixels = pixels players = Players playlist.file.extensions = Playlist File Extensions player = Player +player.is.up.to.date = Player is up to date player.name = Player Name podcasts = Podcasts podcasts.folder = Podcasts Folder @@ -120,8 +144,10 @@ rebooting = Rebooting red = Red region = Region reset = Reset +right = Right rotary.encoders = Rotary Encoders -russian = Russian +rows = Rows +Russian = Russian save = Save saved.successfully = Saved successfully screen.samples = Screen Samples @@ -139,7 +165,9 @@ shutdown = Shutdown shutdown.script.name = Shutdown Script Name slides.folder = Slides Folder slideshow = Slideshow +Spanish = Spanish spectrum = Spectrum +spotify-connect = Spotify Connect startup.script.name = Startup Script Name stream = Stream stream.client.parameters = Stream Client Parameters @@ -155,7 +183,7 @@ update.period = Update Period usage = Usage use.logging = Use Logging vertical.size.percent = Vertical Size -voice.command = Voice command: +voice.command = Command: voice.assistant = Voice Assistant vu.meter = VU Meter waiting.for.command = Waiting for voice command... diff --git a/languages/English-USA/voice-commands.properties b/languages/English-USA/voice-commands.properties index 1f9506ed..20db2e8c 100644 --- a/languages/English-USA/voice-commands.properties +++ b/languages/English-USA/voice-commands.properties @@ -45,6 +45,8 @@ VA_GO_HOME = go home VA_SHUTDOWN = shut down VA_PLAY = play VA_PAUSE = pause +VA_PODCAST = podcast +VA_PODCASTS = podcasts VA_GENRE = genre VA_GO_GENRE = go genre VA_MUTE = mute @@ -67,6 +69,28 @@ VA_PREVIOUS = previous VA_NEW_BOOKS = new books VA_ABC = a b c VA_ALPHABET = alphabet +VA_SEARCH_BY_GENRE = search by genre +VA_SEARCH_BY_AUTHOR = search by author +VA_GO_TO_PAGE = go to page +VA_PAGE_NUMBER = page number +VA_STOP = stop +VA_EQUALIZER = equalizer +VA_TIMER = timer +VA_NETWORK = network +VA_FAVORITES = favorites +VA_REFRESH = refresh +VA_EJECT = eject +VA_MENU = menu +VA_SLEEP = sleep +VA_SLEEP_NOW = sleep now +VA_POWEROFF = poweroff +VA_WAKE_UP = wake up +VA_WI_FI_NETWORKS = wi-fi networks +VA_DISCONNECT_WI_FI = disconnect wi-fi +VA_SORT_NETWORKS = sort networks +VA_DELETE_PASSWORD = delete password +VA_SHOW_PASSWORD = show password +VA_HIDE_PASSWORD = hide password VA_0 = 0 VA_1 = 1 VA_2 = 2 @@ -77,18 +101,13 @@ VA_6 = 6 VA_7 = 7 VA_8 = 8 VA_9 = 9 -VA_ZERO = zero -VA_ONE = one -VA_TWO = two -VA_THREE = three -VA_FOUR = four -VA_FIVE = five -VA_SIX = six -VA_SEVEN = seven -VA_EIGHT = eight -VA_NINE = nine -VA_SEARCH_BY_GENRE = search by genre -VA_SEARCH_BY_AUTHOR = search by author -VA_GO_TO_PAGE = go to page -VA_PAGE_NUMBER = page number -VA_STOP = stop +VA_STR_0 = zero +VA_STR_1 = one +VA_STR_2 = two +VA_STR_3 = three +VA_STR_4 = four +VA_STR_5 = five +VA_STR_6 = six +VA_STR_7 = seven +VA_STR_8 = eight +VA_STR_9 = nine diff --git a/languages/English-USA/weather-config.txt b/languages/English-USA/weather-config.txt index 1e1914eb..cd3bad1d 100644 --- a/languages/English-USA/weather-config.txt +++ b/languages/English-USA/weather-config.txt @@ -6,7 +6,7 @@ frame.rate = 30 [weather.config] city = Washington -city.label = +city.label = Washington country = USA region = D.C. update.period = 10 @@ -30,13 +30,11 @@ wed = Wed thu = Thu fri = Fri sat = Sat - humidity = Humidity wind = Wind mph = mph sunrise = Sunrise sunset = Sunset - 0 = Tornado 1 = Tropical Storm 2 = Hurricane @@ -86,3 +84,4 @@ sunset = Sunset 46 = Snow Showers 47 = Isolated Thundershowers 3200 = Not Available + diff --git a/languages/French/labels.properties b/languages/French/labels.properties index 6585dd0f..284f9ac2 100644 --- a/languages/French/labels.properties +++ b/languages/French/labels.properties @@ -1,5 +1,9 @@ about = Environ +add.station = Ajouter Station +add.stream = Ajouter Courant +airplay = AirPlay album.art = Album d'art +alignment = Alignement animated = Animé audio.file.extensions = Extensions de fichiers audio audio-files = Fichiers Audio @@ -14,6 +18,8 @@ browser.stream.player = Navigateur Stream Player cd-player = Lecteur CD cd.drives = Lecteurs de CD cd.track = Piste +center = Centre +check.for.updates = Vérifier les mises à jour city = Ville city.label = Label de ville choose.author = Choisir l'auteur @@ -21,7 +27,11 @@ choose.genre = Choisir le genre choose.track = Choisir la voie client.name = Nom du client clock = Horloge +colors = Couleurs +columns = Colonnes +command.display.time = Heure d'affichage de la commande configuration = Configuration +confirm.delete.image = Êtes-vous sûr de vouloir supprimer une image? confirm.reboot.message = La lecture en cours sera arrêtée et le système redémarré. confirm.save.reboot.message = Toutes les modifications en cours seront enregistrées et le lecteur redémarré. confirm.save.shutdown.message = Toutes les modifications en cours seront sauvegardées et le lecteur sera arrêté. @@ -32,7 +42,6 @@ confirm.save.shutdown.title = Souhaitez-vous enregistrer les modifications avant confirm.shutdown.title = Êtes-vous sûr de vouloir arrêter? connected = Connecté connecting = De liaison... -colors = Couleurs console.logging = Consignation de la console country = Pays cover.art.folders = Dossiers d'art de couverture @@ -43,6 +52,7 @@ delay = Retard de Écran Veille delay.1 = 1 min delay.3 = 3 min delay.off = Éteindre +delete.image = Supprimer l'image depth = Profondeur device.id = Reference de l'appareil device.model.id = ID de modèle de périphérique @@ -50,7 +60,7 @@ disconnected = Débranché disconnecting = Déconnexion... display = Afficher enable.stdout = Activer la sortie standard -english = Anglais +English-USA = Anglais enter.password = Entrer le mot de passe equalizer = Égaliseur file.browser = Navigateur de fichiers @@ -62,8 +72,14 @@ font = Police de caractère font.name = Nom de la police frames.sec = img/sec frame.rate = Taux de trame -french = Français -german = Allemand +French = Français +German = Allemand +gpio.mute = GPIO Muet +gpio.move.left = GPIO À gauche +gpio.move.right = GPIO À droite +gpio.select = GPIO Sélectionnez +gpio.volume.up = GPIO Augmenter le volume +gpio.volume.down = GPIO Diminuer le volume green = Vert hdmi = HDMI headless = Headless @@ -74,7 +90,12 @@ home.menu = Menu d'accueil home.navigator = Navigateur d'accueil http.port = HTTP Port https = HTTPS +Italian = Italien +jitter.filter = Filtre de jitter language = Langue +languages.menu = Langues +left = Gauche +link = Lien lirc = LIRC loading = Chargement... log.filename = Nom du fichier journal @@ -89,8 +110,10 @@ ms = ms multi.touch = Multi-touch music.folder.linux = Dossier Musique Linux music.folder.windows = Dossier Musique Windows +name = Nom network = Réseau new.books = Livres Audio +new.version.released = Sortie d'une nouvelle version - {edition} no = Non no.frame = Pas de cadre nothing.save = Rien à sauver @@ -105,10 +128,11 @@ peppymeter = VU-mètre peppyweather = Météo percent = % pixels = pixels -players = Joueurs +players = Players playlist.file.extensions = Extensions de fichier de playlist -player = Joueur -player.name = Nom de joueur +player = Player +player.is.up.to.date = Le Player est à jour +player.name = Nom de Player podcasts = Podcasts podcasts.folder = Dossier Podcasts poweroff = Éteindre @@ -120,8 +144,10 @@ rebooting = Redémarrage red = Rouge region = Région reset = Réinitialiser +right = Droite rotary.encoders = Codeurs rotatifs -russian = Russe +rows = Lignes +Russian = Russe save = Sauvegarder saved.successfully = Enregistré avec succès screen.samples = Échantillons d'écran @@ -139,7 +165,9 @@ shutdown = Fermer shutdown.script.name = Nom du script d'arrêt slides.folder = Dossier Diaporama slideshow = Diaporama +Spanish = Espagnol spectrum = Spectre +spotify-connect = Spotify Connect startup.script.name = Nom du script de démarrage stream = Courant stream.client.parameters = Stream Client Parameters @@ -155,7 +183,7 @@ update.period = Période de mise à jour usage = Usage use.logging = Utiliser la journalisation vertical.size.percent = Taille verticale -voice.command = Commande vocale: +voice.command = Commande: voice.assistant = Assistant vocal vu.meter = VU mètre waiting.for.command = En attente de commande vocale... diff --git a/languages/French/voice-commands.properties b/languages/French/voice-commands.properties index 82afddaf..6ccf15cb 100644 --- a/languages/French/voice-commands.properties +++ b/languages/French/voice-commands.properties @@ -45,6 +45,8 @@ VA_GO_HOME = rentrer chez soi VA_SHUTDOWN = fermer VA_PLAY = jouer VA_PAUSE = pause +VA_PODCAST = podcast +VA_PODCASTS = podcasts VA_GENRE = genre VA_GO_GENRE = aller genre VA_MUTE = muet @@ -67,6 +69,28 @@ VA_PREVIOUS = précédent VA_NEW_BOOKS = nouveaux livres VA_ABC = a b c VA_ALPHABET = alphabet +VA_SEARCH_BY_GENRE = recherche par genre +VA_SEARCH_BY_AUTHOR = recherche par auteur +VA_GO_TO_PAGE = aller à la page +VA_PAGE_NUMBER = numéro de page +VA_STOP = arrête +VA_EQUALIZER = égaliseur +VA_TIMER = minuteur +VA_NETWORK = réseau +VA_FAVORITES = favoris +VA_REFRESH = rafraîchir +VA_EJECT = éjecter +VA_MENU = menu +VA_SLEEP = dormir +VA_SLEEP_NOW = dors maintenant +VA_POWEROFF = éteindre +VA_WAKE_UP = réveiller +VA_WI_FI_NETWORKS = réseaux wi-fi +VA_DISCONNECT_WI_FI = déconnexion wi-fi +VA_SORT_NETWORKS = réseaux de tri +VA_DELETE_PASSWORD = supprimer le mot de passe +VA_SHOW_PASSWORD = montrer le mot de passe +VA_HIDE_PASSWORD = cacher le mot de passe VA_0 = 0 VA_1 = 1 VA_2 = 2 @@ -77,18 +101,13 @@ VA_6 = 6 VA_7 = 7 VA_8 = 8 VA_9 = 9 -VA_ZERO = zéro -VA_ONE = un -VA_TWO = deux -VA_THREE = trois -VA_FOUR = quatre -VA_FIVE = cinq -VA_SIX = six -VA_SEVEN = sept -VA_EIGHT = huit -VA_NINE = neuf -VA_SEARCH_BY_GENRE = recherche par genre -VA_SEARCH_BY_AUTHOR = recherche par auteur -VA_GO_TO_PAGE = aller à la page -VA_PAGE_NUMBER = numéro de page -VA_STOP = arrête +VA_STR_0 = zéro +VA_STR_1 = un +VA_STR_2 = deux +VA_STR_3 = trois +VA_STR_4 = quatre +VA_STR_5 = cinq +VA_STR_6 = six +VA_STR_7 = sept +VA_STR_8 = huit +VA_STR_9 = neuf diff --git a/languages/German/labels.properties b/languages/German/labels.properties index af25f0a3..46e70e47 100644 --- a/languages/German/labels.properties +++ b/languages/German/labels.properties @@ -1,5 +1,9 @@ about = Über +add.station = Station hinzufügen +add.stream = Stream hinzufügen +airplay = AirPlay album.art = Album-Cover +alignment = Ausrichtung animated = Animiert audio.file.extensions = Audio-Dateiendungen audio-files = Audiodateien @@ -14,14 +18,20 @@ browser.stream.player = Browser Stream Player cd-player = CD-Spieler cd.drives = CD-Laufwerke cd.track = Titel +center = Center +check.for.updates = Auf Updates prüfen city = Stadt city.label = Stadt-Label choose.author = Autor auswählen choose.genre = Genre auswählen -choose.track = Spur auswählen +choose.track = Titel auswählen client.name = Kundenname clock = Uhr +colors = Farben +columns = Säulen +command.display.time = Befehlsanzeigezeit configuration = Aufbau +confirm.delete.image = Möchten Sie das Bild wirklich löschen? confirm.reboot.message = Die aktuelle Wiedergabe wird gestoppt und das System neu gestartet. confirm.save.reboot.message = Alle aktuellen Änderungen werden gespeichert und der Player wird neu gestartet. confirm.save.shutdown.message = Alle aktuellen Änderungen werden gespeichert und der Player wird heruntergefahren. @@ -32,7 +42,6 @@ confirm.save.shutdown.title = Möchten Sie die Änderungen vor dem Herunterfahre confirm.shutdown.title = Möchten Sie den Computer wirklich herunterfahren? connected = Verbunden connecting = Verbindung wird hergestellt... -colors = Farben console.logging = Konsolenprotokollierung country = Land cover.art.folders = Cover-Art-Ordner @@ -43,6 +52,7 @@ delay = Bildschirmschoner-Verzögerung delay.1 = 1 min delay.3 = 3 min delay.off = Ausschalten +delete.image = Lösche Bild depth = Tiefe device.id = Geräte-ID device.model.id = Gerätemodell-ID @@ -50,7 +60,7 @@ disconnected = Getrennt disconnecting = Verbindung wird getrennt... display = Anzeige enable.stdout = Standardausgabe aktivieren -english = Englisch +English-USA = Englisch enter.password = Passwort eingeben equalizer = Equalizer file.browser = Dateibrowser @@ -62,8 +72,14 @@ font = Schriftart font.name = Schriftartenname frames.sec = Bilder/sek frame.rate = Bildrate -french = Französisch -german = Deutsch +French = Französisch +German = Deutsche +gpio.mute = GPIO Stumm +gpio.move.left = GPIO Nach links +gpio.move.right = GPIO Nach rechts +gpio.select = GPIO Wählen +gpio.volume.up = GPIO Lautstärke erhöhen +gpio.volume.down = GPIO Lautstärke reduzieren green = Grün hdmi = HDMI headless = Headless @@ -74,7 +90,12 @@ home.menu = Hauptmenü home.navigator = Hauptnavigator http.port = HTTP-Port https = HTTPS +Italian = Italien +jitter.filter = Jitter-Filter language = Sprache +languages.menu = Sprachen +left = Links +link = Verknüpfung lirc = LIRC loading = Laden... log.filename = Protokoll-Dateiname @@ -89,8 +110,10 @@ ms = ms multi.touch = Multi-touch music.folder.linux = Musikordner Linux music.folder.windows = Musikordner Windows +name = Name network = Netzwerk new.books = Hörbücher +new.version.released = Neue Version freigegeben - {edition} no = Nein no.frame = Kein Rahmen nothing.save = Nichts zu speichern @@ -105,9 +128,10 @@ peppymeter = VU-Meter peppyweather = Wetter percent = % pixels = Pixel -players = Players +players = Player playlist.file.extensions = Playlist-Dateierweiterungen player = Player +player.is.up.to.date = Player ist aktuell player.name = Player Name podcasts = Podcasts podcasts.folder = Podcasts-Ordner @@ -115,13 +139,15 @@ poweroff = Ausschalten radio = Radio radio.playlists = Radio-Wiedergabelisten random = Zufällig -reboot = Rebooten -rebooting = Neustart +reboot = Neustart +rebooting = Neustart... red = Rot region = Region reset = Zurücksetzen +right = Recht rotary.encoders = Drehgeber -russian = Russisch +rows = Reihen +Russian = Russisch save = Speichern saved.successfully = Erfolgreich gespeichert screen.samples = Screen Samples @@ -139,7 +165,9 @@ shutdown = Ausschalten shutdown.script.name = Ausschalten Skriptname slides.folder = Folienordner slideshow = Slideshow +Spanish = Spanisch spectrum = Spektrum +spotify-connect = Spotify Connect startup.script.name = Anlaufen Skriptname stream = Stream stream.client.parameters = Stream Client-Parameter @@ -155,7 +183,7 @@ update.period = Aktualisierungszeitraum usage = Verwendungszweck use.logging = Protokollierung aktivieren vertical.size.percent = Vertikale Größe -voice.command = Sprachbefehl: +voice.command = Befehl: voice.assistant = Sprachassistent vu.meter = VU-Meter waiting.for.command = Warte auf Sprachbefehl... diff --git a/languages/German/radio-stations/Genre/Rock/Uturn Radio.png b/languages/German/radio-stations/Genre/Rock/Uturn Radio.png new file mode 100644 index 00000000..35963b18 Binary files /dev/null and b/languages/German/radio-stations/Genre/Rock/Uturn Radio.png differ diff --git a/languages/German/radio-stations/Genre/Rock/stations.m3u b/languages/German/radio-stations/Genre/Rock/stations.m3u index 7eb1e854..0ce0bf58 100644 --- a/languages/German/radio-stations/Genre/Rock/stations.m3u +++ b/languages/German/radio-stations/Genre/Rock/stations.m3u @@ -1,3 +1,5 @@ +#Uturn Radio +http://listen.uturnradio.com:80/classic_rock #FluxFM http://fluxfm.hoerradar.de/fluxfm-berlin #Absolut Radio @@ -63,24 +65,24 @@ http://regiocast.hoerradar.de/deltaradio-unplugged-mp3-hq #Delta Radio Der Beste Rockpop Reloaded http://regiocast.hoerradar.de/deltaradio-poprock-mp3-hq #Radio Bob! Livestream -https://sec-bob.hoerradar.de/radiobob-live-mp3-hq +https://bob.hoerradar.de/radiobob-live-mp3-hq #Radio Bob! BOBs Alternative Rock -https://sec-bob.hoerradar.de/radiobob-alternativerock-mp3-hq +https://bob.hoerradar.de/radiobob-alternativerock-mp3-hq #Radio Bob! BOBs Harte Saite -https://sec-bob.hoerradar.de/radiobob-hartesaite-mp3-hq +https://bob.hoerradar.de/radiobob-hartesaite-mp3-hq #Radio Bob! Classic Rock -https://sec-bob.hoerradar.de/radiobob-classicrock-mp3-hq +https://bob.hoerradar.de/radiobob-classicrock-mp3-hq #Radio Bob! ACDC -https://sec-bob.hoerradar.de/radiobob-acdc-mp3-hq +https://bob.hoerradar.de/radiobob-acdc-mp3-hq #Radio Bob! Deutschrock -https://sec-bob.hoerradar.de/radiobob-deutsch-mp3-hq +https://bob.hoerradar.de/radiobob-deutschrock-mp3-hq #Radio Bob! 80er Rock -https://sec-bob.hoerradar.de/radiobob-80srock-mp3-hq +https://bob.hoerradar.de/radiobob-80srock-mp3-hq #Radio Bob! 90er Rock -https://sec-bob.hoerradar.de/radiobob-90srock-mp3-hq +https://bob.hoerradar.de/radiobob-90srock-mp3-hq #Radio Bob! Best of Rock -https://sec-bob.hoerradar.de/radiobob-bestofrock-mp3-hq +https://bob.hoerradar.de/radiobob-bestofrock-mp3-hq #Radio Bob! Wacken -https://sec-bob.hoerradar.de/radiobob-wacken-mp3-hq +https://bob.hoerradar.de/radiobob-wacken-mp3-hq #Radio Bob! Rock Hits -https://sec-bob.hoerradar.de/radiobob-rockhits-mp3-hq +https://bob.hoerradar.de/radiobob-rockhits-mp3-hq diff --git a/languages/German/voice-commands.properties b/languages/German/voice-commands.properties index 4ae35f9f..7c5446dc 100644 --- a/languages/German/voice-commands.properties +++ b/languages/German/voice-commands.properties @@ -45,6 +45,8 @@ VA_GO_HOME = nach hause gehen VA_SHUTDOWN = schließen VA_PLAY = spiel VA_PAUSE = pause +VA_PODCAST = podcast +VA_PODCASTS = podcasts VA_GENRE = genre VA_GO_GENRE = genre gehen VA_MUTE = stumm @@ -67,6 +69,28 @@ VA_PREVIOUS = bisherige VA_NEW_BOOKS = neue bücher VA_ABC = a b c VA_ALPHABET = alphabet +VA_SEARCH_BY_GENRE = suche nach genre +VA_SEARCH_BY_AUTHOR = suche nach autor +VA_GO_TO_PAGE = gehe zur seite +VA_PAGE_NUMBER = seitennummer +VA_STOP = halt +VA_EQUALIZER = equalizer +VA_TIMER = timer +VA_NETWORK = netzwerk +VA_FAVORITES = favoriten +VA_REFRESH = aktualisierung +VA_EJECT = auswerfen +VA_MENU = menü +VA_SLEEP = schlafen +VA_SLEEP_NOW = schlaf jetzt +VA_POWEROFF = ausschalten +VA_WAKE_UP = aufwachen +VA_WI_FI_NETWORKS = wi-fi-netzwerke +VA_DISCONNECT_WI_FI = trennen sie wi-fi +VA_SORT_NETWORKS = netzwerke sortieren +VA_DELETE_PASSWORD = passwort löschen +VA_SHOW_PASSWORD = passwort anzeigen +VA_HIDE_PASSWORD = passwort verbergen VA_0 = 0 VA_1 = 1 VA_2 = 2 @@ -77,18 +101,13 @@ VA_6 = 6 VA_7 = 7 VA_8 = 8 VA_9 = 9 -VA_ZERO = null -VA_ONE = ein -VA_TWO = zwei -VA_THREE = drei -VA_FOUR = vier -VA_FIVE = fünf -VA_SIX = sechs -VA_SEVEN = sieben -VA_EIGHT = acht -VA_NINE = neun -VA_SEARCH_BY_GENRE = suche nach genre -VA_SEARCH_BY_AUTHOR = suche nach autor -VA_GO_TO_PAGE = gehe zur seite -VA_PAGE_NUMBER = seitennummer -VA_STOP = halt +VA_STR_0 = null +VA_STR_1 = ein +VA_STR_2 = zwei +VA_STR_3 = drei +VA_STR_4 = vier +VA_STR_5 = fünf +VA_STR_6 = sechs +VA_STR_7 = sieben +VA_STR_8 = acht +VA_STR_9 = neun diff --git a/languages/Italian/flag.png b/languages/Italian/flag.png new file mode 100644 index 00000000..ee838819 Binary files /dev/null and b/languages/Italian/flag.png differ diff --git a/languages/Italian/labels.properties b/languages/Italian/labels.properties new file mode 100644 index 00000000..4db76820 --- /dev/null +++ b/languages/Italian/labels.properties @@ -0,0 +1,194 @@ +about = Informazioni +add.station = Aggiungi stazione +add.stream = Aggiungi stream +airplay = AirPlay +album.art = Album Art +alignment = Allineamento +animated = Animato +audio.file.extensions = Estensioni file audio +audio-files = Audio Files +audiobooks = Audiolibri +authors = Autori +auto.play = Riproduzione automatica +auto.play.next.track = Riproduzione automatica della traccie +back = Indietro +bits = bits +blue = Blu +browser.stream.player = Browser Stream Player +cd-player = Lettore CD +cd.drives = Lettore CD +cd.track = Traccia +center = Centro +check.for.updates = Controlla gli aggiornamenti +city = Citta +city.label = Nome Citta +choose.author = Scegli l'autore +choose.genre = Scegli il genere +choose.track = Scegli la traccia +client.name = Client Nome +clock = Orologio +colors = Colori +columns = Colonne +command.display.time = Tempo visualizzazione comando +configuration = Configurazione +confirm.delete.image = Sei sicuro di voler eliminare l'immagine? +confirm.reboot.message = La lettura corrente verrà interrotta e il sistema verrà riavviato +confirm.save.reboot.message = Tutte le modifiche in sospeso verranno salvate e l'unità verrà riavviata.. +confirm.save.shutdown.message = Tutte le modifiche correnti verranno salvate e l'unità verrà arrestata.. +confirm.shutdown.message = Dopo l'arresto, il sistema non sarà disponibile +confirm.reboot.title = Sei sicuro di voler riavviare? +confirm.save.reboot.title = Vuoi salvare le modifiche prima di riavviare? +confirm.save.shutdown.title = Vuoi salvare le modifiche prima di interrompere? +confirm.shutdown.title = Sei sicuro di voler smettere? +connected = Connesso +connecting = Collegamento ... +console.logging = Registrazione della console +country = Nazione +cover.art.folders = Cartelle delle copertine +credentials = Credenziali +current.palette = Tavolozza corrente +cyclic.playback = Riproduzione ciclica +delay = Screensaver Ritardo +delay.1 = 1 min +delay.3 = 3 min +delay.off = Off +delete.image = Elimina immagine +depth = Profondità +device.id = Device ID +device.model.id = ID modello dispositivo +disconnected = Disconnesso +disconnecting = Disconnessione... +display = Mostra +enable.stdout = Abilita output standard +English-USA = Inglese +enter.password = Inserisci password +equalizer = Equalizzatore +file.browser = Browser file +file.logging = Salvataggio file +flip.touch.xy = Capovolgi Touch XYY +folder.image.scale.ratio = Rapporto di scala dell'immagine della cartella +folder.images = Cartella Immagini +font = Font +font.name = Nome del carattere +frames.sec = frames/sec +frame.rate = Frame Rate +French = Francese +German = Tedesco +gpio.mute = GPIO Muto +gpio.move.left = GPIO Sinistra +gpio.move.right = GPIO Destra +gpio.select = GPIO Scegliere +gpio.volume.up = GPIO Aumenta volume +gpio.volume.down = GPIO Volume basso +green = Verde +hdmi = HDMI +headless = Senza testa +height = Altezza +hide.folder.name = Nascondi il nome della cartella +home = Home +home.menu = Menu principale +home.navigator = Home principale +http.port = Porta HTTP +https = HTTPS +Italian = Italiano +jitter.filter = Filtro jitter +language = Lingua +languages.menu = Lingue +left = Sinistra +link = Collegamento +lirc = LIRC +loading = Caricamento in corso... +log.filename = Nome del file registro +logging = Registrazione +logo = Logo +long.press.time.ms = Tempo di pressione prolungato +lyrics = Parole +lyrics.not.found = Parole non trovate +military.time.format = Formato orario 24 ore +mouse = Mouse +ms = ms +multi.touch = Multi-touch +music.folder.linux = Cartella musicale Linux +music.folder.windows = Cartella musica di Windows +name = Nome +network = Rete +new.books = Audiolibri +new.version.released = Nuova versione rilasciata - {edition} +no = No +no.frame = Nessun frame +nothing.save = Niente da salvare +palette.original = Originale +palette.burgundy = Burgundy +palette.techno = Techno +palette.pinky = Pinky +palette.navy = Navy +palette.earth = Earth +palettes = Palettes +peppymeter = VU meter +peppyweather = Meteo +percent = % +pixels = pixels +players = Players +playlist.file.extensions = estensioni dei file della playlist +player = Player +player.is.up.to.date = Player è aggiornato +player.name = Player Nome +podcasts = Podcasts +podcasts.folder = Podcasts Folder +poweroff = Spegni +radio = Radio +radio.playlists = Radio Playlists +random = Casuale +reboot = Riavvia +rebooting = Riavvio +red = Rosso +region = Regione +reset = Ripristina +right = Destra +rotary.encoders = Encoder rotativi +rows = Righe +Russian = Russa +save = Salva +saved.successfully = Registrato correttamente +screen.samples = Esempi di schermate +screensaver = Screensaver +screensaver.menu = Screensaver Menu +screensavers = Screensavers +scripts = Scripts +sec = sec +see.you.later = A dopo +select.wifi = Seleziona la rete Wi-Fi +server.command = Comando server +server.folder = Cartella del server +show.mouse.events = Mostra eventi del mouse +shutdown = Spegni +shutdown.script.name = Nome dello script di spegnimento +slides.folder = Cartella presentazione +slideshow = Presentazione +Spanish = Spagnolo +spectrum = Spettro +spotify-connect = Spotify Connect +startup.script.name = Nome dello script di avvio +stream = Stream +stream.client.parameters = Stream Client Parameters +stream.server = Stream Server +stream.server.parameters = Stream Server Parametri +stream.server.port = Stream Server Porta +streams = Streams +timer = Timer +touchscreen = Touchscreen +type = Tipeo +unit = Unita +update.period = Periodo di aggiornamento +usage = Utilizzo +use.logging = Usa la registrazione +vertical.size.percent = Dimensione verticale +voice.command = Comando: +voice.assistant = Assistente vocale +vu.meter = VU Meter +waiting.for.command = In attesa di comando vocale ... +weather = Meteo +web = Web +web.server = Web Server +width = larghezza +yes = Si diff --git a/languages/Italian/radio-stations/Genre/Bambini/RAI Radio Kids.jpg b/languages/Italian/radio-stations/Genre/Bambini/RAI Radio Kids.jpg new file mode 100644 index 00000000..6dd99174 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Bambini/RAI Radio Kids.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Bambini/Radio Bimbo.png b/languages/Italian/radio-stations/Genre/Bambini/Radio Bimbo.png new file mode 100644 index 00000000..374f4665 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Bambini/Radio Bimbo.png differ diff --git a/languages/Italian/radio-stations/Genre/Bambini/Radio Magica.png b/languages/Italian/radio-stations/Genre/Bambini/Radio Magica.png new file mode 100644 index 00000000..eb636d2f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Bambini/Radio Magica.png differ diff --git a/languages/Italian/radio-stations/Genre/Bambini/folder-on.png b/languages/Italian/radio-stations/Genre/Bambini/folder-on.png new file mode 100644 index 00000000..08c04da7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Bambini/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Bambini/folder.png b/languages/Italian/radio-stations/Genre/Bambini/folder.png new file mode 100644 index 00000000..e962e7c6 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Bambini/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Bambini/stations.m3u b/languages/Italian/radio-stations/Genre/Bambini/stations.m3u new file mode 100644 index 00000000..3fce7ab5 --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Bambini/stations.m3u @@ -0,0 +1,6 @@ +#Radio Magica +http://nr6.newradio.it:9225/stream +#RAI Radio Kids +http://icestreaming.rai.it/11.mp3 +#Radio Bimbo +http://188.165.192.5:8450/;stream.mp3 diff --git a/languages/Italian/radio-stations/Genre/Classica/Bru Zane Classical Radio.png b/languages/Italian/radio-stations/Genre/Classica/Bru Zane Classical Radio.png new file mode 100644 index 00000000..97476cc1 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Bru Zane Classical Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Italy Classical Radio.png b/languages/Italian/radio-stations/Genre/Classica/Italy Classical Radio.png new file mode 100644 index 00000000..be687043 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Italy Classical Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/La Fenice Channel.png b/languages/Italian/radio-stations/Genre/Classica/La Fenice Channel.png new file mode 100644 index 00000000..6e86972c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/La Fenice Channel.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/RAI Radio Classica.jpg b/languages/Italian/radio-stations/Genre/Classica/RAI Radio Classica.jpg new file mode 100644 index 00000000..2bc47741 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/RAI Radio Classica.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Radio Classica Bresciana.png b/languages/Italian/radio-stations/Genre/Classica/Radio Classica Bresciana.png new file mode 100644 index 00000000..203aba4b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Radio Classica Bresciana.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Radio Classica.png b/languages/Italian/radio-stations/Genre/Classica/Radio Classica.png new file mode 100644 index 00000000..96aee918 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Radio Classica.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Radio Marconi 2 - Musica Classica.png b/languages/Italian/radio-stations/Genre/Classica/Radio Marconi 2 - Musica Classica.png new file mode 100644 index 00000000..ed8dbe19 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Radio Marconi 2 - Musica Classica.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Rete Toscana Classica.png b/languages/Italian/radio-stations/Genre/Classica/Rete Toscana Classica.png new file mode 100644 index 00000000..55c0e7ac Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Rete Toscana Classica.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Symphony Radio.png b/languages/Italian/radio-stations/Genre/Classica/Symphony Radio.png new file mode 100644 index 00000000..74a96c19 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Symphony Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/Venice Classic Radio.png b/languages/Italian/radio-stations/Genre/Classica/Venice Classic Radio.png new file mode 100644 index 00000000..fea14412 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/Venice Classic Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/folder-on.png b/languages/Italian/radio-stations/Genre/Classica/folder-on.png new file mode 100644 index 00000000..36482e26 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/folder.png b/languages/Italian/radio-stations/Genre/Classica/folder.png new file mode 100644 index 00000000..13fb01ab Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Classica/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Classica/stations.m3u b/languages/Italian/radio-stations/Genre/Classica/stations.m3u new file mode 100644 index 00000000..20245f4d --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Classica/stations.m3u @@ -0,0 +1,20 @@ +#RAI Radio Classica +http://icestreaming.rai.it/5.mp3 +#Italy Classical Radio +http://176.31.107.8:8204/; +#Bru Zane Classical Radio +http://109.123.116.202:7001/stream2 +#Radio Classica +http://onair15.xdevel.com:7096/;stream.mp3 +#Venice Classic Radio +http://109.123.116.202:8020/stream/1/ +#Radio Classica Bresciana +https://ice09.fluidstream.net/classicabresciana.mp3 +#La Fenice Channel +http://nr9.newradio.it:9690/stream.mp3 +#Symphony Radio +http://nr6.newradio.it:9146/; +#Rete Toscana Classica +http://193.200.241.170:8000/source +#Radio Marconi 2 - Musica Classica +http://onair22.streaming.xdevel.com:7598/;stream.mp3 diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Fly Radio TV.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Fly Radio TV.jpg new file mode 100644 index 00000000..6f8b58ec Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Fly Radio TV.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Ganga Radio.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Ganga Radio.jpg new file mode 100644 index 00000000..0fdc5b5e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Ganga Radio.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Italia Dance Music.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Italia Dance Music.jpg new file mode 100644 index 00000000..16b1e304 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Italia Dance Music.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Italian Dance Network.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Italian Dance Network.jpg new file mode 100644 index 00000000..eb2879ab Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Italian Dance Network.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/MC2.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/MC2.jpg new file mode 100644 index 00000000..c02928ca Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/MC2.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Mucca Radio.png b/languages/Italian/radio-stations/Genre/Contemporanea/Mucca Radio.png new file mode 100644 index 00000000..fb4d36aa Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Mucca Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/PaneBurroMarmellata.png b/languages/Italian/radio-stations/Genre/Contemporanea/PaneBurroMarmellata.png new file mode 100644 index 00000000..bb849088 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/PaneBurroMarmellata.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Passion Inside.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Passion Inside.jpg new file mode 100644 index 00000000..1e73def5 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Passion Inside.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/R101 Diretta.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/R101 Diretta.jpg new file mode 100644 index 00000000..6c2ef18a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/R101 Diretta.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/RAMPOWER.png b/languages/Italian/radio-stations/Genre/Contemporanea/RAMPOWER.png new file mode 100644 index 00000000..61ed0b55 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/RAMPOWER.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/RMC MCNIGHTS Story.png b/languages/Italian/radio-stations/Genre/Contemporanea/RMC MCNIGHTS Story.png new file mode 100644 index 00000000..6d88e6b0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/RMC MCNIGHTS Story.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/RTL Groove.png b/languages/Italian/radio-stations/Genre/Contemporanea/RTL Groove.png new file mode 100644 index 00000000..cc768f8b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/RTL Groove.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 HipHopRnB.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 HipHopRnB.png new file mode 100644 index 00000000..0f8d219f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 HipHopRnB.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Hits.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Hits.png new file mode 100644 index 00000000..4aab1ce7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Hits.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Rap Italia.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Rap Italia.png new file mode 100644 index 00000000..a081986e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio 105 Rap Italia.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Attivita.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Attivita.png new file mode 100644 index 00000000..acf9019a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Attivita.png differ diff --git "a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Citt\303\203 del Capo.png" "b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Citt\303\203 del Capo.png" new file mode 100644 index 00000000..d30fdd1c Binary files /dev/null and "b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Citt\303\203 del Capo.png" differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Cortina.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Cortina.png new file mode 100644 index 00000000..d7442212 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Cortina.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Fantastica.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Fantastica.jpg new file mode 100644 index 00000000..dd7a1350 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Fantastica.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Gelosa.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Gelosa.jpg new file mode 100644 index 00000000..072de781 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Gelosa.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Globo.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Globo.jpg new file mode 100644 index 00000000..451bbc41 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Globo.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Ibiza.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Ibiza.png new file mode 100644 index 00000000..5711577e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Ibiza.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Margherita Giovane.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Margherita Giovane.png new file mode 100644 index 00000000..d8afaa2f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Margherita Giovane.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Millennium.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Millennium.png new file mode 100644 index 00000000..306252f0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Millennium.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Parsifal.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Parsifal.png new file mode 100644 index 00000000..002b275e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Parsifal.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Punto Zero.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Punto Zero.png new file mode 100644 index 00000000..4f54539b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Punto Zero.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sintony.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sintony.png new file mode 100644 index 00000000..f571ec8c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sintony.png differ diff --git "a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Studio Pi\303\271.jpg" "b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Studio Pi\303\271.jpg" new file mode 100644 index 00000000..3413f021 Binary files /dev/null and "b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Studio Pi\303\271.jpg" differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Subasio Piu.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Subasio Piu.png new file mode 100644 index 00000000..220ae861 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Subasio Piu.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Suby.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Suby.jpg new file mode 100644 index 00000000..6484ae3b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Suby.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sunshine 95.4 FM.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sunshine 95.4 FM.png new file mode 100644 index 00000000..6b33726a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Sunshine 95.4 FM.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Villa Central.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Villa Central.jpg new file mode 100644 index 00000000..84b1c781 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Villa Central.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Radio Zeta.png b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Zeta.png new file mode 100644 index 00000000..58bd686c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Radio Zeta.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Duets.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Duets.jpg new file mode 100644 index 00000000..19079f82 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Duets.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Great Artists.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Great Artists.jpg new file mode 100644 index 00000000..7787ba56 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Great Artists.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Hits.png b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Hits.png new file mode 100644 index 00000000..4b34be9c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Hits.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Rmc KayKay.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc KayKay.jpg new file mode 100644 index 00000000..beb0b855 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc KayKay.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Love Songs.jpg b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Love Songs.jpg new file mode 100644 index 00000000..3da63541 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Rmc Love Songs.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/Viva FM.png b/languages/Italian/radio-stations/Genre/Contemporanea/Viva FM.png new file mode 100644 index 00000000..402d5d67 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/Viva FM.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/folder-on.png b/languages/Italian/radio-stations/Genre/Contemporanea/folder-on.png new file mode 100644 index 00000000..dda13741 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/folder.png b/languages/Italian/radio-stations/Genre/Contemporanea/folder.png new file mode 100644 index 00000000..98761ea6 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Contemporanea/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Contemporanea/stations.m3u b/languages/Italian/radio-stations/Genre/Contemporanea/stations.m3u new file mode 100644 index 00000000..2655a3c5 --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Contemporanea/stations.m3u @@ -0,0 +1,78 @@ +#R101 Diretta +http://icecast.unitedradio.it/r101 +#Radio 105 HipHopRnB +http://icy.unitedradio.it/105HipHopRnB.mp3 +#Radio 105 Hits +http://icy.unitedradio.it/105Hits.mp3 +#Radio 105 Rap Italia +http://icy.unitedradio.it/105RapItalia.mp3 +#RTL Groove +http://shoutcast.rtl.it:3040/ +#RMC MCNIGHTS Story +http://edge.radiomontecarlo.net/rmcweb012 +#Rmc KayKay +http://edge.radiomontecarlo.net/rmcweb004 +#Rmc Great Artists +http://edge.radiomontecarlo.net/rmcweb007 +#Rmc Duets +http://edge.radiomontecarlo.net/rmcweb003 +#Rmc Hits +http://edge.radiomontecarlo.net/rmcweb001 +#Rmc Love Songs +http://edge.radiomontecarlo.net/rmcweb006 +#Radio Margherita Giovane +http://onair20.xdevel.com:8018/ +#Passion Inside +http://ample-04.radiojar.com/wksgarp8w74tv +#Radio Ibiza +http://ice07.fluidstream.net:8080/Ibiza.mp3 +#Radio Globo +http://178.33.72.12/globorm128 +#Radio Studio Più +http://ice.studiopiu.net/rete.aac +#Radio Subasio Piu +http://icy.unitedradio.it/SubasioPiu.mp3 +#MC2 +https://edge.singsingmusic.net/MC2.mp3 +#Italia Dance Music +http://sr2.inmystream.info:8032/stream2 +#Italian Dance Network +http://radio.italiandancenetwork.com:8000/stream.mp3 +#Radio Millennium +http://sr7.inmystream.info:8068/;stream.mp3 +#PaneBurroMarmellata +http://2.234.55.237:443/paneburromarmellata +#Mucca Radio +http://nr9.newradio.it:9260/stream.mp3 +#Radio Città del Capo +http://stream2.netlit.eu/rcdc +#Radio Cortina +http://nr11.newradio.it:9114/stream +#Radio Gelosa +http://wma01.fluidstream.net/gelosa +#Radio Punto Zero +http://95.211.113.141:7100/stream.mp3 +#Radio Sintony +http://51.254.76.66:8000/stream +#Radio Sunshine 95.4 FM +http://195.201.227.227:8000/stream +#Viva FM +http://stream2.vivafm.it:8002/stream.mp3 +#Radio Attivita +http://178.250.66.145:8000/radioattivita +#RAMPOWER +http://icstream.rds.radio/ram_aac +#Radio Zeta +http://shoutcast.rtl.it:3030/1 +#Radio Fantastica +http://46.105.114.57:8006/stream2 +#Radio Suby +http://onair18.xdevel.com:8430/; +#Radio Parsifal +http://onair11.xdevel.com:10044/; +#Fly Radio TV +http://play.flyradiotv.net:9051/; +#Ganga Radio +http://dreamsiteradiocp3.com:8112/;stream.mp3 +#Radio Villa Central +http://nr11.newradio.it:9274/stream diff --git a/languages/Italian/radio-stations/Genre/Cultura/Controradio Firenze.png b/languages/Italian/radio-stations/Genre/Cultura/Controradio Firenze.png new file mode 100644 index 00000000..ef545fb8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Controradio Firenze.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Lady Radio.png b/languages/Italian/radio-stations/Genre/Cultura/Lady Radio.png new file mode 100644 index 00000000..35a44d5d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Lady Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO Live.jpg b/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO Live.jpg new file mode 100644 index 00000000..735bde27 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO Live.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO techete.jpg b/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO techete.jpg new file mode 100644 index 00000000..b72a1776 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/RAI RADIO techete.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/RAI RadioDue.jpg b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioDue.jpg new file mode 100644 index 00000000..dbed4c82 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioDue.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/RAI RadioTre.png b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioTre.png new file mode 100644 index 00000000..ac9f8fc5 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioTre.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/RAI RadioUno.png b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioUno.png new file mode 100644 index 00000000..4e44041a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/RAI RadioUno.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Colosseo.png b/languages/Italian/radio-stations/Genre/Cultura/Radio Colosseo.png new file mode 100644 index 00000000..d056b664 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Colosseo.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Day.jpg b/languages/Italian/radio-stations/Genre/Cultura/Radio Day.jpg new file mode 100644 index 00000000..3c9e0ab3 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Day.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Francigena.png b/languages/Italian/radio-stations/Genre/Cultura/Radio Francigena.png new file mode 100644 index 00000000..4e63ba27 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Francigena.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Linguaggio.png b/languages/Italian/radio-stations/Genre/Cultura/Radio Linguaggio.png new file mode 100644 index 00000000..dbaab3a8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Linguaggio.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Radio.png b/languages/Italian/radio-stations/Genre/Cultura/Radio Radio.png new file mode 100644 index 00000000..6577f07e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/Radio Senti Chi Parla.png b/languages/Italian/radio-stations/Genre/Cultura/Radio Senti Chi Parla.png new file mode 100644 index 00000000..04d5a33c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/Radio Senti Chi Parla.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/folder-on.png b/languages/Italian/radio-stations/Genre/Cultura/folder-on.png new file mode 100644 index 00000000..b30aeaa0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/folder.png b/languages/Italian/radio-stations/Genre/Cultura/folder.png new file mode 100644 index 00000000..240fd784 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Cultura/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Cultura/stations.m3u b/languages/Italian/radio-stations/Genre/Cultura/stations.m3u new file mode 100644 index 00000000..fc91037c --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Cultura/stations.m3u @@ -0,0 +1,26 @@ +#RAI RadioUno +http://icestreaming.rai.it/1.mp3 +#RAI RadioDue +http://icestreaming.rai.it/2.mp3 +#RAI RadioTre +http://icestreaming.rai.it/3.mp3 +#RAI RADIO Live +http://icestreaming.rai.it/10.mp3 +#RAI RADIO techete +http://icestreaming.rai.it/9.mp3 +#Radio Radio +http://mp3.radioradio.it:8102/;stream/ +#Radio Senti Chi Parla +http://18193.live.streamtheworld.com/SAM01AAC222_SC +#Radio Francigena +https://radiofrancigena.out.airtime.pro/radiofrancigena_b +#Radio Colosseo +http://nr6.newradio.it:9188/stream +#Radio Linguaggio +http://onair15.xdevel.com:8528/; +#Controradio Firenze +https://s4.yesstreaming.net:17199/stream +#Radio Day +http://audio1.meway.tv:8074/stream +#Lady Radio +http://onair15.xdevel.com:9126/;stream.mp3 diff --git a/languages/Italian/radio-stations/Genre/Jazz/MC2 Smooth Jazz.png b/languages/Italian/radio-stations/Genre/Jazz/MC2 Smooth Jazz.png new file mode 100644 index 00000000..9124e843 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/MC2 Smooth Jazz.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/Musica Jazz Radio.png b/languages/Italian/radio-stations/Genre/Jazz/Musica Jazz Radio.png new file mode 100644 index 00000000..2e9bd84a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/Musica Jazz Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/OnlyJazz.jpg b/languages/Italian/radio-stations/Genre/Jazz/OnlyJazz.jpg new file mode 100644 index 00000000..051aae14 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/OnlyJazz.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/RMC MC Nights Story.jpg b/languages/Italian/radio-stations/Genre/Jazz/RMC MC Nights Story.jpg new file mode 100644 index 00000000..f15c7c10 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/RMC MC Nights Story.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/Radio Iglesias Jazz'n'Soul.png b/languages/Italian/radio-stations/Genre/Jazz/Radio Iglesias Jazz'n'Soul.png new file mode 100644 index 00000000..16351d46 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/Radio Iglesias Jazz'n'Soul.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/Skyline Radio'n'Soul.png b/languages/Italian/radio-stations/Genre/Jazz/Skyline Radio'n'Soul.png new file mode 100644 index 00000000..17de4404 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/Skyline Radio'n'Soul.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/Spazio Radio.png b/languages/Italian/radio-stations/Genre/Jazz/Spazio Radio.png new file mode 100644 index 00000000..d329ace4 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/Spazio Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/Sweet'n'Sour-Radio.jpg b/languages/Italian/radio-stations/Genre/Jazz/Sweet'n'Sour-Radio.jpg new file mode 100644 index 00000000..148311a7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/Sweet'n'Sour-Radio.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/U-Fm Radio.png b/languages/Italian/radio-stations/Genre/Jazz/U-Fm Radio.png new file mode 100644 index 00000000..9de93d82 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/U-Fm Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/United Music Cool Jazz.png b/languages/Italian/radio-stations/Genre/Jazz/United Music Cool Jazz.png new file mode 100644 index 00000000..3466fbd6 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/United Music Cool Jazz.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/United Music Jazz Classics.png b/languages/Italian/radio-stations/Genre/Jazz/United Music Jazz Classics.png new file mode 100644 index 00000000..692d96c8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/United Music Jazz Classics.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/United Music Reggae.png b/languages/Italian/radio-stations/Genre/Jazz/United Music Reggae.png new file mode 100644 index 00000000..e72ab4e9 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/United Music Reggae.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/folder-on.png b/languages/Italian/radio-stations/Genre/Jazz/folder-on.png new file mode 100644 index 00000000..88837fe7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/folder.png b/languages/Italian/radio-stations/Genre/Jazz/folder.png new file mode 100644 index 00000000..62cebe29 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Jazz/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Jazz/stations.m3u b/languages/Italian/radio-stations/Genre/Jazz/stations.m3u new file mode 100644 index 00000000..0dfd8391 --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Jazz/stations.m3u @@ -0,0 +1,24 @@ +#Musica Jazz Radio +https://ice16.fluidstream.net/mjr.mp3 +#OnlyJazz +http://178.32.137.180:8873/; +#MC2 Smooth Jazz +https://edge.singsingmusic.net/singsingweb012 +#Skyline Radio'n'Soul +https://rblive.it/proxy/sky_mp3?mp=%2Fstream +#United Music Jazz Classics +https://icy.unitedradio.it/um053.mp3 +#United Music Cool Jazz +https://icy.unitedradio.it/um039.mp3 +#United Music Reggae +https://icy.unitedradio.it/um043.mp3 +#U-Fm Radio +http://94.23.66.114:8009/; +#Sweet'n'Sour-Radio +https://sweetnsour.stream.laut.fm/sweetnsour +#RMC MC Nights Story +http://edge.radiomontecarlo.net/rmcweb012 +#Radio Iglesias Jazz'n'Soul +http://95.211.113.141:8012/;651830639384452stream.nsv +#Spazio Radio +http://s6.mediastreaming.it:7190/; diff --git a/languages/Italian/radio-stations/Genre/News/AQRadio 99 Radio Infinito.png b/languages/Italian/radio-stations/Genre/News/AQRadio 99 Radio Infinito.png new file mode 100644 index 00000000..d1be5b52 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/AQRadio 99 Radio Infinito.png differ diff --git a/languages/Italian/radio-stations/Genre/News/FM Italia 92.8.png b/languages/Italian/radio-stations/Genre/News/FM Italia 92.8.png new file mode 100644 index 00000000..75956639 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/FM Italia 92.8.png differ diff --git a/languages/Italian/radio-stations/Genre/News/RAI GR Parlamento.png b/languages/Italian/radio-stations/Genre/News/RAI GR Parlamento.png new file mode 100644 index 00000000..2de7aebd Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/RAI GR Parlamento.png differ diff --git a/languages/Italian/radio-stations/Genre/News/RAI Isoradio.jpg b/languages/Italian/radio-stations/Genre/News/RAI Isoradio.jpg new file mode 100644 index 00000000..b6f34d6a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/RAI Isoradio.jpg differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio 24.jpg b/languages/Italian/radio-stations/Genre/News/Radio 24.jpg new file mode 100644 index 00000000..cc1faa50 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio 24.jpg differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio Ascoli.png b/languages/Italian/radio-stations/Genre/News/Radio Ascoli.png new file mode 100644 index 00000000..333c34d8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio Ascoli.png differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio BBSI.png b/languages/Italian/radio-stations/Genre/News/Radio BBSI.png new file mode 100644 index 00000000..cb60e245 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio BBSI.png differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio Gamma 5.jpg b/languages/Italian/radio-stations/Genre/News/Radio Gamma 5.jpg new file mode 100644 index 00000000..1209d8b3 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio Gamma 5.jpg differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio Radicale.png b/languages/Italian/radio-stations/Genre/News/Radio Radicale.png new file mode 100644 index 00000000..e912652e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio Radicale.png differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio Sportiva.png b/languages/Italian/radio-stations/Genre/News/Radio Sportiva.png new file mode 100644 index 00000000..979884b0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio Sportiva.png differ diff --git a/languages/Italian/radio-stations/Genre/News/Radio Vega.png b/languages/Italian/radio-stations/Genre/News/Radio Vega.png new file mode 100644 index 00000000..d640b728 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/Radio Vega.png differ diff --git a/languages/Italian/radio-stations/Genre/News/TMW Radio.png b/languages/Italian/radio-stations/Genre/News/TMW Radio.png new file mode 100644 index 00000000..81e8ae3b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/TMW Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/News/folder-on.png b/languages/Italian/radio-stations/Genre/News/folder-on.png new file mode 100644 index 00000000..031e4f90 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/News/folder.png b/languages/Italian/radio-stations/Genre/News/folder.png new file mode 100644 index 00000000..f36eb71c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/News/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/News/stations.m3u b/languages/Italian/radio-stations/Genre/News/stations.m3u new file mode 100644 index 00000000..994edc8f --- /dev/null +++ b/languages/Italian/radio-stations/Genre/News/stations.m3u @@ -0,0 +1,24 @@ +#RAI Isoradio +http://icestreaming.rai.it/6.mp3 +#RAI GR Parlamento +http://icestreaming.rai.it/7.mp3 +#Radio 24 +http://shoutcast.radio24.it:8000/ +#Radio Radicale +http://livemp3.radioradicale.it/live.mp3 +#TMW Radio +https://stream22.tmwradio.com/tmw.aac +#Radio Gamma 5 +http://ice05.fluidstream.net/fluid0510.mp3 +#AQRadio 99 Radio Infinito +http://99radioinfinito.ddns.net:33695/live +#Radio Ascoli +http://ice05.fluidstream.net/fluid0507.aac +#Radio Vega +http://188.165.192.5:8011/1 +#Radio BBSI +http://onair7.xdevel.com:8696/;stream.mp3 +#Radio Sportiva +http://46.105.114.57:8000/stream +#FM Italia 92.8 +http://onair7.xdevel.com:8700/; diff --git a/languages/Italian/radio-stations/Genre/Pop/Canale Italia.png b/languages/Italian/radio-stations/Genre/Pop/Canale Italia.png new file mode 100644 index 00000000..b943afba Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Canale Italia.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Centro Suono.png b/languages/Italian/radio-stations/Genre/Pop/Centro Suono.png new file mode 100644 index 00000000..eaf40731 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Centro Suono.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/CiaoComo Radio 89.4 FM.jpg b/languages/Italian/radio-stations/Genre/Pop/CiaoComo Radio 89.4 FM.jpg new file mode 100644 index 00000000..786a945b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/CiaoComo Radio 89.4 FM.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Discoradio.png b/languages/Italian/radio-stations/Genre/Pop/Discoradio.png new file mode 100644 index 00000000..157a0813 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Discoradio.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/FM Italia 92.8.png b/languages/Italian/radio-stations/Genre/Pop/FM Italia 92.8.png new file mode 100644 index 00000000..61a5e45e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/FM Italia 92.8.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/LatteMiele FM.png b/languages/Italian/radio-stations/Genre/Pop/LatteMiele FM.png new file mode 100644 index 00000000..9a852b32 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/LatteMiele FM.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Love FM.jpg b/languages/Italian/radio-stations/Genre/Pop/Love FM.jpg new file mode 100644 index 00000000..c83f9b15 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Love FM.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Primaradio Sicilia.png b/languages/Italian/radio-stations/Genre/Pop/Primaradio Sicilia.png new file mode 100644 index 00000000..32abd97d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Primaradio Sicilia.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/R101 Legend.jpg b/languages/Italian/radio-stations/Genre/Pop/R101 Legend.jpg new file mode 100644 index 00000000..75cf51b1 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/R101 Legend.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/R101 Made In Italy.jpg b/languages/Italian/radio-stations/Genre/Pop/R101 Made In Italy.jpg new file mode 100644 index 00000000..9b40d48d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/R101 Made In Italy.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/RADIO SANREMO.png b/languages/Italian/radio-stations/Genre/Pop/RADIO SANREMO.png new file mode 100644 index 00000000..cef5c863 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/RADIO SANREMO.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/RDS Relax.jpg b/languages/Italian/radio-stations/Genre/Pop/RDS Relax.jpg new file mode 100644 index 00000000..b719497a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/RDS Relax.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/ROL103.jpg b/languages/Italian/radio-stations/Genre/Pop/ROL103.jpg new file mode 100644 index 00000000..ff98ed6b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/ROL103.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/RTL 102.5.png b/languages/Italian/radio-stations/Genre/Pop/RTL 102.5.png new file mode 100644 index 00000000..f853a851 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/RTL 102.5.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio 105.png b/languages/Italian/radio-stations/Genre/Pop/Radio 105.png new file mode 100644 index 00000000..dec6ff96 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio 105.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio 3 Network.png b/languages/Italian/radio-stations/Genre/Pop/Radio 3 Network.png new file mode 100644 index 00000000..66ac69d5 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio 3 Network.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Aldebaran.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Aldebaran.jpg new file mode 100644 index 00000000..60ecce9d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Aldebaran.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Belluno.png b/languages/Italian/radio-stations/Genre/Pop/Radio Belluno.png new file mode 100644 index 00000000..88e4b10c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Belluno.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Bergamo.png b/languages/Italian/radio-stations/Genre/Pop/Radio Bergamo.png new file mode 100644 index 00000000..d25ea694 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Bergamo.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Bruno.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Bruno.jpg new file mode 100644 index 00000000..a33aa239 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Bruno.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Company Italiamo.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Company Italiamo.jpg new file mode 100644 index 00000000..4ac6165d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Company Italiamo.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Dolomiti.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Dolomiti.jpg new file mode 100644 index 00000000..85fa3979 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Dolomiti.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Flash.png b/languages/Italian/radio-stations/Genre/Pop/Radio Flash.png new file mode 100644 index 00000000..7b230674 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Flash.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Italianissima.png b/languages/Italian/radio-stations/Genre/Pop/Radio Italianissima.png new file mode 100644 index 00000000..803f4a4e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Italianissima.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Mania 88.2 FM.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Mania 88.2 FM.jpg new file mode 100644 index 00000000..9cb365c0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Mania 88.2 FM.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Marconi - Musica'n'Notizie.png b/languages/Italian/radio-stations/Genre/Pop/Radio Marconi - Musica'n'Notizie.png new file mode 100644 index 00000000..9633f4a9 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Marconi - Musica'n'Notizie.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Mi Piaci.png b/languages/Italian/radio-stations/Genre/Pop/Radio Mi Piaci.png new file mode 100644 index 00000000..12666691 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Mi Piaci.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Millenote.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Millenote.jpg new file mode 100644 index 00000000..9d5a7a71 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Millenote.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Monte Carlo Hits.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Monte Carlo Hits.jpg new file mode 100644 index 00000000..839d160f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Monte Carlo Hits.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Nettuno.png b/languages/Italian/radio-stations/Genre/Pop/Radio Nettuno.png new file mode 100644 index 00000000..5d45de78 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Nettuno.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Norba.png b/languages/Italian/radio-stations/Genre/Pop/Radio Norba.png new file mode 100644 index 00000000..e8b026e3 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Norba.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Number One.png b/languages/Italian/radio-stations/Genre/Pop/Radio Number One.png new file mode 100644 index 00000000..8a727460 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Number One.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Padova.png b/languages/Italian/radio-stations/Genre/Pop/Radio Padova.png new file mode 100644 index 00000000..3ec2a69b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Padova.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Pico Classic.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Pico Classic.jpg new file mode 100644 index 00000000..19c80571 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Pico Classic.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Pico.png b/languages/Italian/radio-stations/Genre/Pop/Radio Pico.png new file mode 100644 index 00000000..6e876053 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Pico.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Popolare.png b/languages/Italian/radio-stations/Genre/Pop/Radio Popolare.png new file mode 100644 index 00000000..ef379e6d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Popolare.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio RDF.png b/languages/Italian/radio-stations/Genre/Pop/Radio RDF.png new file mode 100644 index 00000000..dfa02ae8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio RDF.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Sabbia.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Sabbia.jpg new file mode 100644 index 00000000..009b181a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Sabbia.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Sound.png b/languages/Italian/radio-stations/Genre/Pop/Radio Sound.png new file mode 100644 index 00000000..8aa56479 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Sound.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Splash.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Splash.jpg new file mode 100644 index 00000000..8e1558a7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Splash.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Stella.png b/languages/Italian/radio-stations/Genre/Pop/Radio Stella.png new file mode 100644 index 00000000..a1192097 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Stella.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Studio Star.png b/languages/Italian/radio-stations/Genre/Pop/Radio Studio Star.png new file mode 100644 index 00000000..d467be16 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Studio Star.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Sud Orientale.jpg b/languages/Italian/radio-stations/Genre/Pop/Radio Sud Orientale.jpg new file mode 100644 index 00000000..54544fe1 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Sud Orientale.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Tour.png b/languages/Italian/radio-stations/Genre/Pop/Radio Tour.png new file mode 100644 index 00000000..6c976ce5 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Tour.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radio Touring Catania.png b/languages/Italian/radio-stations/Genre/Pop/Radio Touring Catania.png new file mode 100644 index 00000000..f59a272f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radio Touring Catania.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/RadioFly.jpg b/languages/Italian/radio-stations/Genre/Pop/RadioFly.jpg new file mode 100644 index 00000000..d70a4b2c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/RadioFly.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Radiolina.png b/languages/Italian/radio-stations/Genre/Pop/Radiolina.png new file mode 100644 index 00000000..83a12e80 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Radiolina.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Studioradio.png b/languages/Italian/radio-stations/Genre/Pop/Studioradio.png new file mode 100644 index 00000000..3f79afcf Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Studioradio.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/Tele Radio Stereo.jpg b/languages/Italian/radio-stations/Genre/Pop/Tele Radio Stereo.jpg new file mode 100644 index 00000000..c3943c9d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/Tele Radio Stereo.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Pop/folder-on.png b/languages/Italian/radio-stations/Genre/Pop/folder-on.png new file mode 100644 index 00000000..80e41a47 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/folder.png b/languages/Italian/radio-stations/Genre/Pop/folder.png new file mode 100644 index 00000000..b554d944 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Pop/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Pop/stations.m3u b/languages/Italian/radio-stations/Genre/Pop/stations.m3u new file mode 100644 index 00000000..14849908 --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Pop/stations.m3u @@ -0,0 +1,98 @@ +#R101 Legend +http://icy.unitedradio.it/101Legend.aac +#R101 Made In Italy +http://icy.unitedradio.it/R101MadeInItaly.aac +#RDS Relax +http://icstream.rds.radio/rdsrelax_aac +#Radio Mi Piaci +http://nr6.newradio.it:9182/stream +#RTL 102.5 +http://shoutcast.rtl.it:3010/1 +#Radio 105 +https://icecast.unitedradio.it/Radio105.mp3 +#Radio Norba +http://onair20.xdevel.com:8218/; +#Radiolina +http://145.239.128.64:8000/;listen +#Radio Sabbia +http://sr2.inmystream.info:8104/; +#Radio Stella +http://onair15.xdevel.com:9026/;stream.mp3 +#Love FM +https://ice02.fluidstream.net/lovefm.aac +#Radio Marconi - Musica'n'Notizie +http://onair15.xdevel.com:8922/;stream.mp3 +#Radio Millenote +http://ice12.fluidstream.net/millenote.aac +#Canale Italia +http://rci.canaleitalia.tv:8007/; +#Centro Suono +http://www.radiocentrosuono.it:8000/rcs +#Radio Italianissima +http://onair15.xdevel.com:9100/; +#Radio Company Italiamo +https://ice03.fluidstream.net/companyitalia.mp3 +#Radio Tour +http://shoutcast.streamingmedia.it:5004/;.mp3?_=1 +#Radio Monte Carlo Hits +https://icy.unitedradio.it/rmcweb001 +#CiaoComo Radio 89.4 FM +http://nr9.newradio.it:9383/stream +#Discoradio +https://icstream.rds.radio/disco +#FM Italia 92.8 +http://onair7.xdevel.com:8700/; +#LatteMiele FM +http://21253.live.streamtheworld.com/LATTEMIELE.mp3 +#Primaradio Sicilia +http://188.165.242.32:8126 +#Radio 3 Network +http://209.250.255.114:8000/listen +#Radio Aldebaran +https://nr11.newradio.it:19157/stream +#Radio Belluno +http://ice09.fluidstream.net/fluid0908.mp3 +#Radio Bergamo +http://ice12.fluidstream.net/bergamo.mp3 +#Radio Dolomiti +http://streaming.radiodolomiti.com:8068/stream +#Radio Flash +http://onair22.streaming.xdevel.com:8190/; +#Radio Mania 88.2 FM +http://wma03.fluidstream.net:8080/mania.aac +#Radio Nettuno +http://radionettunostreaming.besttool.it:8000/xstream +#Radio Number One +http://ice12.fluidstream.net/rn1.aac +#Radio Padova +https://ice04.fluidstream.net/rpd.mp3 +#Radio Pico +http://onair11.xdevel.com:8064/; +#Radio Pico Classic +http://onair11.xdevel.com:8014/; +#Radio Popolare +https://livex.radiopopolare.it/radiopop +#Radio RDF +http://onair22.streaming.xdevel.com:8244/; +#Radio Sound +http://onair15.xdevel.com:8094/; +#Radio Splash +http://51.254.76.66:8002/stream +#Radio Studio Star +http://nr5.newradio.it:8520/stream +#Radio Touring Catania +http://onair15.xdevel.com:8856/; +#ROL103 +http://ice04.fluidstream.net/fluid0409.mp3 +#Tele Radio Stereo +http://62.210.192.117:8016/live +#RADIO SANREMO +http://199.195.194.92:8055/;stream.nsv +#Radio Sud Orientale +http://nrf1.newradio.it:9750/; +#RadioFly +http://185.112.4.6:8000/radiofly +#Studioradio +http://91.121.38.216:8060/; +#Radio Bruno +http://onair7.xdevel.com:8752/; diff --git a/languages/Italian/radio-stations/Genre/Retro/Ciao Italia Radio.png b/languages/Italian/radio-stations/Genre/Retro/Ciao Italia Radio.png new file mode 100644 index 00000000..4b3c22fa Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Ciao Italia Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Easy Network.png b/languages/Italian/radio-stations/Genre/Retro/Easy Network.png new file mode 100644 index 00000000..2543d83c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Easy Network.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Funky Corner Radio.png b/languages/Italian/radio-stations/Genre/Retro/Funky Corner Radio.png new file mode 100644 index 00000000..53a601cd Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Funky Corner Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Lolli Radio Oldies.png b/languages/Italian/radio-stations/Genre/Retro/Lolli Radio Oldies.png new file mode 100644 index 00000000..d7094f7b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Lolli Radio Oldies.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/M100.png b/languages/Italian/radio-stations/Genre/Retro/M100.png new file mode 100644 index 00000000..88cdf622 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/M100.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/MC2 '80.png b/languages/Italian/radio-stations/Genre/Retro/MC2 '80.png new file mode 100644 index 00000000..51957289 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/MC2 '80.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Milano 1602 AM radio.png b/languages/Italian/radio-stations/Genre/Retro/Milano 1602 AM radio.png new file mode 100644 index 00000000..d3ef997f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Milano 1602 AM radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Nonsolosuoni.jpg b/languages/Italian/radio-stations/Genre/Retro/Nonsolosuoni.jpg new file mode 100644 index 00000000..0095d45e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Nonsolosuoni.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Otto FM.jpg b/languages/Italian/radio-stations/Genre/Retro/Otto FM.jpg new file mode 100644 index 00000000..e13e5b9b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Otto FM.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Retro/R101 00.png b/languages/Italian/radio-stations/Genre/Retro/R101 00.png new file mode 100644 index 00000000..b16bf7b4 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/R101 00.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/R101 70.png b/languages/Italian/radio-stations/Genre/Retro/R101 70.png new file mode 100644 index 00000000..e3b0a2ee Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/R101 70.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/R101 80.png b/languages/Italian/radio-stations/Genre/Retro/R101 80.png new file mode 100644 index 00000000..01606b62 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/R101 80.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/R101 90.png b/languages/Italian/radio-stations/Genre/Retro/R101 90.png new file mode 100644 index 00000000..3e2d9855 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/R101 90.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/RVM Vintage.png b/languages/Italian/radio-stations/Genre/Retro/RVM Vintage.png new file mode 100644 index 00000000..53e4486d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/RVM Vintage.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio 105 Classics.png b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Classics.png new file mode 100644 index 00000000..bedf1152 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Classics.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio 105 Dance 90.png b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Dance 90.png new file mode 100644 index 00000000..5ed6ae18 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Dance 90.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio 105 Story.png b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Story.png new file mode 100644 index 00000000..740ae1bf Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio 105 Story.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio 60 70 80 italy.png b/languages/Italian/radio-stations/Genre/Retro/Radio 60 70 80 italy.png new file mode 100644 index 00000000..ac1e2a42 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio 60 70 80 italy.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio 80 Forever Young.jpg b/languages/Italian/radio-stations/Genre/Retro/Radio 80 Forever Young.jpg new file mode 100644 index 00000000..002e1057 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio 80 Forever Young.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Amore I Migliori Anni.png b/languages/Italian/radio-stations/Genre/Retro/Radio Amore I Migliori Anni.png new file mode 100644 index 00000000..df64d04e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Amore I Migliori Anni.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Birikina.png b/languages/Italian/radio-stations/Genre/Retro/Radio Birikina.png new file mode 100644 index 00000000..620f8626 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Birikina.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio C1.png b/languages/Italian/radio-stations/Genre/Retro/Radio C1.png new file mode 100644 index 00000000..a39b449a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio C1.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Cafe.png b/languages/Italian/radio-stations/Genre/Retro/Radio Cafe.png new file mode 100644 index 00000000..ca9b87d6 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Cafe.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Caliente.png b/languages/Italian/radio-stations/Genre/Retro/Radio Caliente.png new file mode 100644 index 00000000..0f9812fc Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Caliente.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Clodia.png b/languages/Italian/radio-stations/Genre/Retro/Radio Clodia.png new file mode 100644 index 00000000..53ba2e98 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Clodia.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Digitalia Festival.png b/languages/Italian/radio-stations/Genre/Retro/Radio Digitalia Festival.png new file mode 100644 index 00000000..866a337f Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Digitalia Festival.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Energy Classic.png b/languages/Italian/radio-stations/Genre/Retro/Radio Energy Classic.png new file mode 100644 index 00000000..b99e485a Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Energy Classic.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Italia Anni 60.png b/languages/Italian/radio-stations/Genre/Retro/Radio Italia Anni 60.png new file mode 100644 index 00000000..bd807507 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Italia Anni 60.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Latina.jpg b/languages/Italian/radio-stations/Genre/Retro/Radio Latina.jpg new file mode 100644 index 00000000..69c7eb7b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Latina.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Mela.png b/languages/Italian/radio-stations/Genre/Retro/Radio Mela.png new file mode 100644 index 00000000..69485ae3 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Mela.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Milano International Classic.png b/languages/Italian/radio-stations/Genre/Retro/Radio Milano International Classic.png new file mode 100644 index 00000000..edab4062 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Milano International Classic.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Mitology.png b/languages/Italian/radio-stations/Genre/Retro/Radio Mitology.png new file mode 100644 index 00000000..040f8314 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Mitology.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 80.png b/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 80.png new file mode 100644 index 00000000..2e867272 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 80.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 90.png b/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 90.png new file mode 100644 index 00000000..7f49f969 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio Monte Carlo 90.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Radio SorRiso.png b/languages/Italian/radio-stations/Genre/Retro/Radio SorRiso.png new file mode 100644 index 00000000..e533625d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Radio SorRiso.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/Studio Dance.png b/languages/Italian/radio-stations/Genre/Retro/Studio Dance.png new file mode 100644 index 00000000..a04783c7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/Studio Dance.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Disco.png b/languages/Italian/radio-stations/Genre/Retro/United Music Disco.png new file mode 100644 index 00000000..3e804a6e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Disco.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Hits 60.png b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 60.png new file mode 100644 index 00000000..95a0d046 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 60.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Hits 70.png b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 70.png new file mode 100644 index 00000000..cb77f74b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 70.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Hits 90.png b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 90.png new file mode 100644 index 00000000..8a8b5eea Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Hits 90.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Italia 70.png b/languages/Italian/radio-stations/Genre/Retro/United Music Italia 70.png new file mode 100644 index 00000000..12c0c46b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Italia 70.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/United Music Motown 60.png b/languages/Italian/radio-stations/Genre/Retro/United Music Motown 60.png new file mode 100644 index 00000000..f358e96b Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/United Music Motown 60.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/VIVA LA RADIO.jpg b/languages/Italian/radio-stations/Genre/Retro/VIVA LA RADIO.jpg new file mode 100644 index 00000000..a368ee8e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/VIVA LA RADIO.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Retro/folder-on.png b/languages/Italian/radio-stations/Genre/Retro/folder-on.png new file mode 100644 index 00000000..20601a33 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/folder.png b/languages/Italian/radio-stations/Genre/Retro/folder.png new file mode 100644 index 00000000..e1aa6f5c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Retro/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Retro/stations.m3u b/languages/Italian/radio-stations/Genre/Retro/stations.m3u new file mode 100644 index 00000000..e8f66e8c --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Retro/stations.m3u @@ -0,0 +1,86 @@ +#R101 70 +http://icy.unitedradio.it/R10170.aac +#R101 80 +http://icy.unitedradio.it/R10180.aac +#R101 90 +http://icy.unitedradio.it/R10190.aac +#R101 00 +http://icy.unitedradio.it/R1012000.aac +#Radio Italia Anni 60 +http://str01.fluidstream.net:7130 +#Radio 60 70 80 italy +http://www.studiopiu.net:8005/ +#Radio Monte Carlo 80 +http://edge.radiomontecarlo.net/rmcweb008 +#Radio Monte Carlo 90 +http://edge.radiomontecarlo.net/rmcweb009 +#Radio 105 Story +http://icy.unitedradio.it/105Story.mp3 +#Radio 105 Dance 90 +http://icy.unitedradio.it/105Dance90.mp3 +#Radio 105 Classics +http://icy.unitedradio.it/105Classics.mp3 +#Radio Amore I Migliori Anni +http://onair15.xdevel.com:8838/; +#Ciao Italia Radio +http://31.220.4.253:8000/; +#Lolli Radio Oldies +https://oldies.lolliradio.net/stream +#United Music Motown 60 +https://icy.unitedradio.it/um024.mp3 +#United Music Hits 60 +https://icy.unitedradio.it/um054.mp3 +#United Music Hits 70 +https://icy.unitedradio.it/um070.mp3 +#United Music Italia 70 +https://icy.unitedradio.it/um020.mp3 +#United Music Hits 90 +https://icy.unitedradio.it/um045.mp3 +#United Music Disco +https://icy.unitedradio.it/um048.mp3 +#Otto FM +http://217.182.192.240:12041/; +#RVM Vintage +http://91.121.118.99:8181/; +#Radio Caliente +http://onair15.xdevel.com:7014/1 +#Radio Digitalia Festival +https://radiodigitalia-festival.stream.laut.fm/radiodigitalia-festival +#Radio 80 Forever Young +http://nr11.newradio.it:9208/; +#Radio Mitology +http://onair15.xdevel.com:9120/; +#M100 +http://94.23.65.199/m100-64 +#Easy Network +http://ice02.fluidstream.net/easy.aac +#Radio Latina +http://178.32.136.9:9097/; +#Funky Corner Radio +http://andromeda.shoutca.st:8411/stream +#Radio Milano International Classic +http://91.121.104.139:10101/; +#Studio Dance +https://studiodance.stream.laut.fm/studiodance +#Nonsolosuoni +http://95.110.226.198:8000/; +#Milano 1602 AM radio +http://91.121.104.139:1602/; +#Radio Energy Classic +http://178.32.62.163:8629/1 +#Radio Mela +http://91.121.38.216:8016/; +#MC2 '80 +https://edge.singsingmusic.net/singsingweb008 +#Radio Birikina +http://ice02.fluidstream.net/birikina +#Radio Cafe +http://onair18.xdevel.com:8218/; +#Radio Clodia +http://sr4.inmystream.info:8063/stream +#Radio SorRiso +http://wma01.fluidstream.net:8080/sorriso +#VIVA LA RADIO +http://stream.webradio.bz:8000/socialclub2 +#Radio C1 +http://intercast.max73.ovh:9030/stream diff --git a/languages/Italian/radio-stations/Genre/Rock/LifeGate Radio.png b/languages/Italian/radio-stations/Genre/Rock/LifeGate Radio.png new file mode 100644 index 00000000..37d6a532 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/LifeGate Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/MC2 Romantic Rock.png b/languages/Italian/radio-stations/Genre/Rock/MC2 Romantic Rock.png new file mode 100644 index 00000000..dc23c6c7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/MC2 Romantic Rock.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/MC2 Sensual Rock.png b/languages/Italian/radio-stations/Genre/Rock/MC2 Sensual Rock.png new file mode 100644 index 00000000..0e8a1297 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/MC2 Sensual Rock.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Milano XR.jpg b/languages/Italian/radio-stations/Genre/Rock/Milano XR.jpg new file mode 100644 index 00000000..68eedbb4 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Milano XR.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Coldplay.jpg b/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Coldplay.jpg new file mode 100644 index 00000000..e2094b8c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Coldplay.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Zucchero.jpg b/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Zucchero.jpg new file mode 100644 index 00000000..cbb9cd39 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/RMC Music Star Zucchero.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/RMC Romantic Rock.jpg b/languages/Italian/radio-stations/Genre/Rock/RMC Romantic Rock.jpg new file mode 100644 index 00000000..59191d9d Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/RMC Romantic Rock.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/RTL 102.5 - Rock.png b/languages/Italian/radio-stations/Genre/Rock/RTL 102.5 - Rock.png new file mode 100644 index 00000000..60afd886 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/RTL 102.5 - Rock.png differ diff --git "a/languages/Italian/radio-stations/Genre/Rock/Radio Citt\303\240 Futura.png" "b/languages/Italian/radio-stations/Genre/Rock/Radio Citt\303\240 Futura.png" new file mode 100644 index 00000000..8d0d3e00 Binary files /dev/null and "b/languages/Italian/radio-stations/Genre/Rock/Radio Citt\303\240 Futura.png" differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Company Rock.jpg b/languages/Italian/radio-stations/Genre/Rock/Radio Company Rock.jpg new file mode 100644 index 00000000..4f735e87 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Company Rock.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Elettrica.png b/languages/Italian/radio-stations/Genre/Rock/Radio Elettrica.png new file mode 100644 index 00000000..65a74e69 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Elettrica.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Freccia.png b/languages/Italian/radio-stations/Genre/Rock/Radio Freccia.png new file mode 100644 index 00000000..6d6d46e0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Freccia.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Gas.png b/languages/Italian/radio-stations/Genre/Rock/Radio Gas.png new file mode 100644 index 00000000..c6b7513e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Gas.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Kiss Kiss Rock.png b/languages/Italian/radio-stations/Genre/Rock/Radio Kiss Kiss Rock.png new file mode 100644 index 00000000..f580e3ac Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Kiss Kiss Rock.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Lupo Solitario 90.7 FM.png b/languages/Italian/radio-stations/Genre/Rock/Radio Lupo Solitario 90.7 FM.png new file mode 100644 index 00000000..944d18f7 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Lupo Solitario 90.7 FM.png differ diff --git "a/languages/Italian/radio-stations/Genre/Rock/Radio Maril\303\271.png" "b/languages/Italian/radio-stations/Genre/Rock/Radio Maril\303\271.png" new file mode 100644 index 00000000..cab6b705 Binary files /dev/null and "b/languages/Italian/radio-stations/Genre/Rock/Radio Maril\303\271.png" differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Rete 2000.png b/languages/Italian/radio-stations/Genre/Rock/Radio Rete 2000.png new file mode 100644 index 00000000..59565cd4 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Rete 2000.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Radio Rock 106.6.png b/languages/Italian/radio-stations/Genre/Rock/Radio Rock 106.6.png new file mode 100644 index 00000000..a837f6c4 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Radio Rock 106.6.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/United Music Rock 60.png b/languages/Italian/radio-stations/Genre/Rock/United Music Rock 60.png new file mode 100644 index 00000000..09b506fb Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/United Music Rock 60.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Classic Rock.jpg b/languages/Italian/radio-stations/Genre/Rock/Virgin Classic Rock.jpg new file mode 100644 index 00000000..00f5ceb6 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Classic Rock.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin HardRock Radio.png b/languages/Italian/radio-stations/Genre/Rock/Virgin HardRock Radio.png new file mode 100644 index 00000000..f17a3451 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin HardRock Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Pink Floyd.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Pink Floyd.png new file mode 100644 index 00000000..52feb95c Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Pink Floyd.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Queen.jpg b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Queen.jpg new file mode 100644 index 00000000..36a217b1 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Queen.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Rolling Stones.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Rolling Stones.png new file mode 100644 index 00000000..8e536d9e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Music Star Rolling Stones.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Rock Ballads.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Rock Ballads.png new file mode 100644 index 00000000..6746b812 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio Rock Ballads.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Radio.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio.png new file mode 100644 index 00000000..05d2cbf8 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Radio.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Rock Alternative.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock Alternative.png new file mode 100644 index 00000000..9117f405 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock Alternative.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Rock70.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock70.png new file mode 100644 index 00000000..7a2d8ae0 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock70.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Rock80.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock80.png new file mode 100644 index 00000000..6c51da36 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock80.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin Rock90.png b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock90.png new file mode 100644 index 00000000..46739652 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin Rock90.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin RockHits.png b/languages/Italian/radio-stations/Genre/Rock/Virgin RockHits.png new file mode 100644 index 00000000..81aa0f9e Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin RockHits.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/Virgin RockParty.jpg b/languages/Italian/radio-stations/Genre/Rock/Virgin RockParty.jpg new file mode 100644 index 00000000..fdd3b8c9 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/Virgin RockParty.jpg differ diff --git a/languages/Italian/radio-stations/Genre/Rock/folder-on.png b/languages/Italian/radio-stations/Genre/Rock/folder-on.png new file mode 100644 index 00000000..121a1d96 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/folder-on.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/folder.png b/languages/Italian/radio-stations/Genre/Rock/folder.png new file mode 100644 index 00000000..7e0a9437 Binary files /dev/null and b/languages/Italian/radio-stations/Genre/Rock/folder.png differ diff --git a/languages/Italian/radio-stations/Genre/Rock/stations.m3u b/languages/Italian/radio-stations/Genre/Rock/stations.m3u new file mode 100644 index 00000000..5a935122 --- /dev/null +++ b/languages/Italian/radio-stations/Genre/Rock/stations.m3u @@ -0,0 +1,64 @@ +#Radio Freccia +http://shoutcast.rtl.it:3060/stream +#Virgin Radio +http://icecast.unitedradio.it/Virgin.mp3 +#Virgin HardRock Radio +http://icy.unitedradio.it/VirginHardRock.mp3 +#Virgin Rock70 +http://icy.unitedradio.it/VirginRock70.mp3 +#Virgin Rock80 +http://icy.unitedradio.it/VirginRock80.mp3 +#Virgin Rock90 +https://icy.unitedradio.it/Virgin_03.mp3 +#Virgin Radio Rock Ballads +https://icy.unitedradio.it/Virgin_06.mp3 +#Virgin Classic Rock +http://icy.unitedradio.it/VirginRockClassics.mp3 +#Virgin RockHits +http://icy.unitedradio.it/VirginRockHits.mp3 +#Virgin RockParty +http://icy.unitedradio.it/VirginRockParty.mp3 +#Virgin Rock Alternative +http://icy.unitedradio.it/VirginRockAlternative.mp3 +#Virgin Radio Music Star Pink Floyd +https://icy.unitedradio.it/VirginRogerWaters.mp3 +#Virgin Radio Music Star Rolling Stones +https://icy.unitedradio.it/VirginSpecialEvent.mp3 +#Virgin Radio Music Star Queen +https://icy.unitedradio.it/Virgin_05.mp3 +#RMC Music Star Coldplay +http://icy.unitedradio.it/ColdPlay.mp3 +#RMC Music Star Zucchero +http://icy.unitedradio.it/Zucchero.mp3 +#RMC Romantic Rock +http://edge.radiomontecarlo.net/rmcweb015 +#United Music Rock 60 +https://icy.unitedradio.it/um064.mp3 +#Radio Marilù +http://wma01.fluidstream.net/marilu +#Radio Rock 106.6 +http://audio1.meway.tv:8050/; +#Radio Rete 2000 +http://212.83.150.15:8444/; +#Radio Lupo Solitario 90.7 FM +http://eu1.fastcast4u.com:3048/; +#RTL 102.5 - Rock +http://shoutcast.rtl.it:3060/stream/1/ +#MC2 Romantic Rock +https://edge.singsingmusic.net/singsingweb015 +#MC2 Sensual Rock +https://edge.singsingmusic.net/singsingweb016 +#Radio Kiss Kiss Rock +http://ice08.fluidstream.net/kk_rock.aac +#LifeGate Radio +http://onair15.xdevel.com:8254/; +#Radio Città Futura +http://nr11.newradio.it:9168/; +#Milano XR +http://mixr.100xr.com:8000/aac +#Radio Elettrica +http://178.32.136.9/proxy/apselett?mp=%2Fstream +#Radio Company Rock +https://ice03.fluidstream.net/companyrock.mp3 +#Radio Gas +http://nr5.newradio.it:8731/stream diff --git a/languages/Italian/voice-commands.properties b/languages/Italian/voice-commands.properties new file mode 100644 index 00000000..f26ccd70 --- /dev/null +++ b/languages/Italian/voice-commands.properties @@ -0,0 +1,113 @@ +VA_RADIO = radio +VA_GO_RADIO = vai alla radio +VA_FILES = cartelle +VA_GO_FILES = vai ai file +VA_AUDIO_FILES = file audio +VA_AUDIOBOOKS = audiolibro +VA_BOOKS = libro +VA_GO_BOOKS = vai a libro +VA_STREAM = stream +VA_GO_STREAM = vai a stream +VA_CD_PLAYER = lettore cd +VA_BACK = indietro +VA_GO_BACK = vai indietro +VA_SCREENSAVER = screensaver +VA_SAVER = salva +VA_LANGUAGE = lingua +VA_GO_LANGUAGE = passa alla lingua +VA_CHANGE_LANGUAGE = cambia lingua +VA_PLAYER = lettore +VA_GO_PLAYER = vai al lettore +VA_ABOUT = attiva +VA_GO_ABOUT = continua +VA_UP = in alto +VA_GO_UP = vai in alto +VA_DOWN = in basso +VA_GO_DOWN = vai in basso +VA_LEFT = a sinistra +VA_GO_LEFT = vai a sinistra +VA_RIGHT = a destra +VA_GO_RIGHT = vai a destra +VA_OK = ok +VA_OKAY = okay +VA_ENTER = invio +VA_SELECT = seleziona +VA_CLOCK = orologio +VA_LOGO = logo +VA_SLIDESHOW = presentazione +VA_INDICATOR = indicatore +VA_WEATHER = meteo +VA_ONE_MINUTE = un minuto +VA_THREE_MINUTES = 3 minuti +VA_OFF = chiudi +VA_HOME = menu +VA_GO_HOME = vai a menu +VA_SHUTDOWN = spegni +VA_PLAY = avvio +VA_PAUSE = pausa +VA_PODCAST = podcast +VA_PODCASTS = podcasts +VA_GENRE = genere +VA_GO_GENRE = vai a genere +VA_MUTE = muto +VA_VOLUME_UP = alza volume +VA_VOLUME_DOWN = abbassa volume +VA_PAGE_UP = pagina su +VA_PAGE_DOWN = pagina giu +VA_NEXT_PAGE = pagina avanti +VA_PREVIOUS_PAGE = pagina indietro +VA_MUSIC = musica +VA_USER_HOME = vai al menu +VA_ROOT = root +VA_PARENT = sali +VA_VOLUME = volume +VA_TIME = tempo +VA_TIME_UP = aumenta tempo +VA_TIME_DOWN = diminuisci tempo +VA_NEXT = successivo +VA_PREVIOUS = precedente +VA_NEW_BOOKS = nuovo libro +VA_ABC = a b c +VA_ALPHABET = alfabeto +VA_SEARCH_BY_GENRE = cerca per genere +VA_SEARCH_BY_AUTHOR = cerca per autore +VA_GO_TO_PAGE = vai alla pagina +VA_PAGE_NUMBER = pagina numero +VA_STOP = stop +VA_EQUALIZER = equalizzatore +VA_TIMER = timer +VA_NETWORK = rete +VA_FAVORITES = preferiti +VA_REFRESH = ricaricare +VA_EJECT = espellere +VA_MENU = menu +VA_SLEEP = dormire +VA_SLEEP_NOW = dormi ora +VA_POWEROFF = spegni +VA_WAKE_UP = svegliati +VA_WI_FI_NETWORKS = reti wi-fi +VA_DISCONNECT_WI_FI = disconnettere il wi-fi +VA_SORT_NETWORKS = ordina le reti +VA_DELETE_PASSWORD = elimina password +VA_SHOW_PASSWORD = mostra password +VA_HIDE_PASSWORD = nascondi password +VA_0 = 0 +VA_1 = 1 +VA_2 = 2 +VA_3 = 3 +VA_4 = 4 +VA_5 = 5 +VA_6 = 6 +VA_7 = 7 +VA_8 = 8 +VA_9 = 9 +VA_STR_0 = zero +VA_STR_1 = uno +VA_STR_2 = due +VA_STR_3 = tre +VA_STR_4 = quattro +VA_STR_5 = cinque +VA_STR_6 = sei +VA_STR_7 = sette +VA_STR_8 = otto +VA_STR_9 = nove diff --git a/languages/Italian/weather-config.txt b/languages/Italian/weather-config.txt new file mode 100644 index 00000000..f19d850b --- /dev/null +++ b/languages/Italian/weather-config.txt @@ -0,0 +1,88 @@ +[screen.info] +width = 480 +height = 320 +depth = 32 +frame.rate = 30 + +[weather.config] +city = Rome +city.label = Roma +country = Italy +region = +update.period = 10 +unit = c +military.time.format = True +use.logging = False + +[colors] +color.dark = 0,70,75 +color.dark.light = 20,90,100 +color.medium = 70,140,150 +color.bright = 160,190,210 +color.contrast = 255,190,120 +color.logo = 20,190,160 + +[labels] +sun = Dom +mon = Lun +tue = Mar +wed = Mer +thu = Gio +fri = Ven +sat = Sab + +humidity = Umidità +wind = Vento +mph = km/h +sunrise = Alba +sunset = Tramonto + +0 = Tornado +1 = Tempesta tropicale +2 = uragano +3 = Temporali gravi +4 = Temporali +5 = Pioggia e neve miste +6 = Pioggia mista e nevischio +7 = Neve mista e nevischio +8 = Pioggia congelata +9 = Grandine +10 = Pioggia gelata +11 = Piaggia +12 = Pioggia +13 = Accenni di neve +14 = Rovesci di neve leggera +15 = Neve che soffia +16 = Neve +17 = Nevischio +18 = Neve sciolta +19 = Polvere +20 = Nebbioso +21 = Smog +22 = Fumoso +23 = Tempesta +24 = Ventoso +25 = Freddo +26 = Nuvoloso +27 = Molto nuvoloso +28 = Molto nuvoloso +29 = Parzialmente nuvoloso +30 = Parzialmente nuvoloso +31 = Sereno e chiaro +32 = Soleggiato +33 = Per lo più chiaro +34 = Prevalentemente soleggiato +35 = Pioggia mista e grandine +36 = Caldo +37 = Temporali isolati +38 = Temporali sparsi +39 = Temporali sparsi +40 = Pioggie sparse +41 = Neve abbondante +42 = Rovesci di neve sparsi +43 = Neve pesante +44 = Parzialmente nuvoloso +45 = Temporali +46 = Rovesci di neve +47 = Temporali isolati +3200 = Non disponibile diff --git a/languages/Russian/labels.properties b/languages/Russian/labels.properties index 5096ce31..4225d0fa 100644 --- a/languages/Russian/labels.properties +++ b/languages/Russian/labels.properties @@ -1,5 +1,9 @@ about = Описание +add.station = Добавить станцию +add.stream = Добавить поток +airplay = AirPlay album.art = Обложки +alignment = Выравнивание animated = Анимация audio.file.extensions = Расширения аудио файлов audio-files = Аудио Файлы @@ -14,6 +18,8 @@ browser.stream.player = Броузерный проигрыватель пото cd-player = CD Плеер cd.drives = CD Плееры cd.track = Трек +center = Центр +check.for.updates = Проверка обновлений city = Город city.label = Название города choose.author = Выбор автора @@ -21,7 +27,11 @@ choose.genre = Выбор жанра choose.track = Выбор трека client.name = Название клиента clock = Часы +colors = Цвета +columns = Колонки +command.display.time = Время показа команды configuration = Конфигурация +confirm.delete.image = Вы уверены в том что вы хотите удалить картинку? confirm.reboot.message = Проигрывание будет остановлено и плеер перезагружен. confirm.save.reboot.message = Все текущие изменения будут сохранены и плеер перезагружен. confirm.save.shutdown.message = Все текущие изменения будут сохранены и плеер выключен. @@ -32,7 +42,6 @@ confirm.save.shutdown.title = Вы хотите сохранить измене confirm.shutdown.title = Вы уверены в том что вы хотите выключить плеер? connected = Подключен connecting = Подключение... -colors = Цвета console.logging = Вывод на консоль country = Страна cover.art.folders = Папка обложек @@ -43,6 +52,7 @@ delay = Пауза перед заставкой delay.1 = 1 мин delay.3 = 3 мин delay.off = Отключить +delete.image = Удалить картинку depth = Глубина device.id = Идентификатор устройства device.model.id = Идентификатор модели устройства @@ -50,7 +60,7 @@ disconnected = Отключен disconnecting = Отключение... display = Дисплей enable.stdout = Разрешить stdout -english = Английский +English-USA = Английский enter.password = Введите пароль equalizer = Эквалайзер file.browser = Броузер файлов @@ -62,8 +72,14 @@ font = Шрифт font.name = Название шрифта frames.sec = кадр/сек frame.rate = Частота кадров -french = Французский -german = Немецкий +French = Французский +German = Немецкий +gpio.mute = GPIO Без звука +gpio.move.left = GPIO Влево +gpio.move.right = GPIO Вправо +gpio.select = GPIO Выбрать +gpio.volume.up = GPIO Увеличение громкости +gpio.volume.down = GPIO Уменьшение громкости green = Зелёный hdmi = HDMI headless = Консольный @@ -74,7 +90,12 @@ home.menu = Главное меню home.navigator = Навигатор главного меню http.port = HTTP порт https = HTTPS +Italian = Итальянский +jitter.filter = Джиттер-фильтр language = Язык +languages.menu = Языки +left = Влево +link = Ссылка lirc = LIRC loading = Загрузка... log.filename = Имя файла записей @@ -89,8 +110,10 @@ ms = мс multi.touch = Мультитач music.folder.linux = Папка музыки Linux music.folder.windows = Папка музыки Windows +name = Имя network = Сеть new.books = Новинки +new.version.released = Выпущена новая версия - {edition} no = Нет no.frame = Без рамки nothing.save = Сохранять нечего @@ -108,6 +131,7 @@ pixels = пикселей players = Плееры playlist.file.extensions = Расширения файлов плейлистов player = Плеер +player.is.up.to.date = Плеер в последней версии player.name = Название плеера podcasts = Подкасты podcasts.folder = Папка подкастов @@ -120,8 +144,10 @@ rebooting = Перезагрузка red = Красный region = Область reset = Сбросить +right = Вправо rotary.encoders = Ротационные кодеры -russian = Русский +rows = Ряды +Russian = Русский save = Сохранить saved.successfully = Успешно сохранено screen.samples = Примеры экранов @@ -139,7 +165,9 @@ shutdown = Выключить shutdown.script.name = Имя скрипта выключения slides.folder = Папка слайдов slideshow = Слайд-шоу +Spanish = Испанский spectrum = Спектр +spotify-connect = Spotify Connect startup.script.name = Имя скрипта включения stream = Поток stream.client.parameters = Параметры клиента потока @@ -155,7 +183,7 @@ update.period = Период обновления usage = Использование use.logging = Использовать файл записей vertical.size.percent = Вертикальный размер -voice.command = Голосовая команда: +voice.command = Команда: voice.assistant = Голосовой помощник vu.meter = Индикатор waiting.for.command =Ожидаю голосовую команду... diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Bebop.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Bebop.png" deleted file mode 100644 index 4485cd53..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Bebop.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Blues.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Blues.png" deleted file mode 100644 index 83ce7b17..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Blues.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Classic Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Classic Jazz.png" deleted file mode 100644 index 304950a6..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Classic Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Contemporary Vocals.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Contemporary Vocals.png" deleted file mode 100644 index 8ba6d5ae..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Contemporary Vocals.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Current Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Current Jazz.png" deleted file mode 100644 index 04ca3b58..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Current Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Guitar Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Guitar Jazz.png" deleted file mode 100644 index 74adf77c..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Guitar Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Piano Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Piano Jazz.png" deleted file mode 100644 index b509e2a8..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Piano Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Saxophone Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Saxophone Jazz.png" deleted file mode 100644 index 5dbec0a2..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Saxophone Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Trumpet Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Trumpet Jazz.png" deleted file mode 100644 index 63ded8c6..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Trumpet Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vibraphone Jazz.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vibraphone Jazz.png" deleted file mode 100644 index fae303d0..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vibraphone Jazz.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vocal Legends.png" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vocal Legends.png" deleted file mode 100644 index c0487ce4..00000000 Binary files "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/Vocal Legends.png" and /dev/null differ diff --git "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/stations.m3u" "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/stations.m3u" index d579186b..8a741a2d 100644 --- "a/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/stations.m3u" +++ "b/languages/Russian/radio-stations/\320\226\320\260\320\275\321\200/\320\224\320\266\320\260\320\267/stations.m3u" @@ -1,25 +1,3 @@ -#Classic Jazz -http://radio.1jazz.ru:8110/radio -#Current Jazz -http://radio.1jazz.ru:8140/radio -#Blues -http://radio.1jazz.ru:8090/radio -#Bebop -http://radio.1jazz.ru:8070/radio -#Vocal Legends -http://radio.1jazz.ru:8310/radio -#Contemporary Vocals -http://radio.1jazz.ru:8120/radio -#Guitar Jazz -http://radio.1jazz.ru:8150/radio -#Piano Jazz -http://radio.1jazz.ru:8200/radio -#Saxophone Jazz -http://radio.1jazz.ru:8220/radio -#Trumpet Jazz -http://radio.1jazz.ru:8290/radio -#Vibraphone Jazz -http://radio.1jazz.ru:8300/radio #Эрмитаж http://91.190.127.185:8000/live_test #Около Джаза diff --git a/languages/Russian/voice-commands.properties b/languages/Russian/voice-commands.properties index 1f9506ed..12b79505 100644 --- a/languages/Russian/voice-commands.properties +++ b/languages/Russian/voice-commands.properties @@ -1,4 +1,4 @@ -VA_RADIO = radio +VA_RADIO = radio VA_GO_RADIO = go radio VA_FILES = files VA_GO_FILES = go files @@ -45,6 +45,8 @@ VA_GO_HOME = go home VA_SHUTDOWN = shut down VA_PLAY = play VA_PAUSE = pause +VA_PODCAST = podcast +VA_PODCASTS = podcasts VA_GENRE = genre VA_GO_GENRE = go genre VA_MUTE = mute @@ -67,6 +69,28 @@ VA_PREVIOUS = previous VA_NEW_BOOKS = new books VA_ABC = a b c VA_ALPHABET = alphabet +VA_SEARCH_BY_GENRE = search by genre +VA_SEARCH_BY_AUTHOR = search by author +VA_GO_TO_PAGE = go to page +VA_PAGE_NUMBER = page number +VA_STOP = stop +VA_EQUALIZER = equalizer +VA_TIMER = timer +VA_NETWORK = network +VA_FAVORITES = favorites +VA_REFRESH = refresh +VA_EJECT = eject +VA_MENU = menu +VA_SLEEP = sleep +VA_SLEEP_NOW = sleep now +VA_POWEROFF = poweroff +VA_WAKE_UP = wake up +VA_WI_FI_NETWORKS = wi-fi networks +VA_DISCONNECT_WI_FI = disconnect wi-fi +VA_SORT_NETWORKS = sort networks +VA_DELETE_PASSWORD = delete password +VA_SHOW_PASSWORD = show password +VA_HIDE_PASSWORD = hide password VA_0 = 0 VA_1 = 1 VA_2 = 2 @@ -77,18 +101,13 @@ VA_6 = 6 VA_7 = 7 VA_8 = 8 VA_9 = 9 -VA_ZERO = zero -VA_ONE = one -VA_TWO = two -VA_THREE = three -VA_FOUR = four -VA_FIVE = five -VA_SIX = six -VA_SEVEN = seven -VA_EIGHT = eight -VA_NINE = nine -VA_SEARCH_BY_GENRE = search by genre -VA_SEARCH_BY_AUTHOR = search by author -VA_GO_TO_PAGE = go to page -VA_PAGE_NUMBER = page number -VA_STOP = stop +VA_STR_0 = zero +VA_STR_1 = one +VA_STR_2 = two +VA_STR_3 = three +VA_STR_4 = four +VA_STR_5 = five +VA_STR_6 = six +VA_STR_7 = seven +VA_STR_8 = eight +VA_STR_9 = nine diff --git a/languages/Spanish/flag.png b/languages/Spanish/flag.png new file mode 100644 index 00000000..785461fc Binary files /dev/null and b/languages/Spanish/flag.png differ diff --git a/languages/Spanish/labels.properties b/languages/Spanish/labels.properties new file mode 100644 index 00000000..280669c4 --- /dev/null +++ b/languages/Spanish/labels.properties @@ -0,0 +1,194 @@ +about = Sobre +add.station = Agregar estación +add.stream = Añadir corriente +airplay = AirPlay +album.art = Portada del álbum +alignment = Alineación +animated = Animado +audio.file.extensions = Extensiones de archivos de audio +audio-files = Archivo de audio +audiobooks = Audiolibros +authors = Autores +auto.play = Auto-reproducción +auto.play.next.track = Reproducción automática Pista siguiente +back = Espalda +bits = bits +blue = Azul +browser.stream.player = Navegador Reproductor de Stream +cd-player = Lector de CD +cd.drives = Unidades de CD +cd.track = Pista +center = Centro +check.for.updates = Buscar actualizaciones +city = Ciudad +city.label = Etiqueta de la ciudad +choose.author = Seleccione Autor +choose.genre = Seleccione Género +choose.track = Seleccione Pista +client.name = Nombre del Cliente +clock = Reloj +colors = Colores +columns = Columnas +command.display.time = Tiempo de visualización de comandos +configuration = Configuración +confirm.delete.image = ¿Está seguro de que desea eliminar una imagen? +confirm.reboot.message = La reproducción actual se detendrá y el sistema se reiniciará. +confirm.save.reboot.message = Todos los cambios actuales se guardarán y el reproductor se reiniciará. +confirm.save.shutdown.message = Todos los cambios actuales se guardarán y el reproductor se apagará. +confirm.shutdown.message = Después del apagado, el sistema no estará disponible. +confirm.reboot.title = ¿Estás seguro de que quieres reiniciar? +confirm.save.reboot.title = ¿Desea guardar los cambios antes de reiniciar? +confirm.save.shutdown.title = ¿Desea guardar los cambios antes de apagar el equipo? +confirm.shutdown.title = ¿Estás seguro de que quieres cerrar? +connected = Conectado +connecting = Conectando... +console.logging = Registro de la consola +country = País +cover.art.folders = Carpetas de arte de portada +credentials = Credenciales +current.palette = Paleta actual +cyclic.playback = Reproducción cíclica +delay = Retardo del salvapantallas +delay.1 = 1 min +delay.3 = 3 min +delay.off = Apagado +delete.image = Eliminar imagen +depth = Profundidad +device.id = ID de dispositivo +device.model.id = ID de modelo de dispositivo +disconnected = Desconectado +disconnecting = Desconectando... +display = Pantalla +enable.stdout = Habilitar stdout +English-USA = Inglés +enter.password = Ingresar Contraseña +equalizer = Ecualizador +file.browser = Navegador de archivos +file.logging = Registro de archivos +flip.touch.xy = Flip Touch XY +folder.image.scale.ratio = Relación de escala de la imagen de la carpeta +folder.images = Imágenes de carpeta +font = Fuente +font.name = Nombre de la fuente +frames.sec = marcos/segundo +frame.rate = Velocidad de fotogramas +French = Francés +German = Alemán +gpio.mute = GPIO Silencio +gpio.move.left = GPIO Mover a la izquierda +gpio.move.right = GPIO Mover a la derecha +gpio.select = GPIO Seleccione +gpio.volume.up = GPIO Subir el volumen +gpio.volume.down = GPIO Bajar volumen +green = Verde +hdmi = HDMI +headless = Headless +height = Altura +hide.folder.name = Ocultar nombre de carpeta +home = Inicio +home.menu = Menú de inicio +home.navigator = Navegador inicio +http.port = HTTP Puerto +https = HTTPS +Italian = Italiano +jitter.filter = Filtro de fluctuaciones +language = Idioma +languages.menu = Idiomas +left = Izquierda +link = Enlace +lirc = LIRC +loading = Cargando... +log.filename = Nombre de archivo de registro +logging = Registro de archivos +logo = Logo +long.press.time.ms = Tiempo de pulsación prolongado +lyrics = Letra +lyrics.not.found = Letra no encontrada +military.time.format = Formato de hora militar +mouse = Ratón +ms = ms +multi.touch = Multitáctil +music.folder.linux = Carpeta de música Linux +music.folder.windows = Carpeta de música Windows +name = Nombre +network = Red +new.books = Audiolibros +new.version.released = Nueva Versión Lanzada - {edition} +no = No +no.frame = Sin marco +nothing.save = Nada que salvar +palette.original = Original +palette.burgundy = Borgoña +palette.techno = Tecno +palette.pinky = Meñique +palette.navy = Marina +palette.earth = Tierra +palettes = Paletas +peppymeter = Medidor VU +peppyweather = Tiempo +percent = % +pixels = píxeles +players = Reproductores +playlist.file.extensions = Extensiones de archivos de listas de reproducción +player = Reproductor +player.is.up.to.date = Reproductor está al día +player.name = Nombre de reproductor +podcasts = Podcasts +podcasts.folder = Carpeta de podcasts +poweroff = Poweroff +radio = Radio +radio.playlists = Listas de reproducción de radio +random = Aleatorio +reboot = Reiniciar +rebooting = Reinicio +red = Rojo +region = Región +reset = Reiniciar +right = Derecha +rotary.encoders = Codificadores rotativos +rows = Filas +Russian = Ruso +save = Guardar +saved.successfully = Guardado con éxito +screen.samples = Muestras de pantalla +screensaver = Salvapantallas +screensaver.menu = Menú Salvapantallas +screensavers = Salvapantallas +scripts = Guiones +sec = sec +see.you.later = Nos vemos luego +select.wifi = Seleccione Red Wi-Fi +server.command = Comando del servidor +server.folder = Carpeta del servidor +show.mouse.events = Mostrar eventos del ratón +shutdown = Apagado +shutdown.script.name = Nombre de guión de apagado +slides.folder = Carpeta de diapositivas +slideshow = Diapositivas +Spanish = Español +spectrum = Espectro +spotify-connect = Spotify Connect +startup.script.name = Nombre de guión de inicio +stream = Stream +stream.client.parameters = Parámetros del cliente de streaming +stream.server = Servidor de streaming +stream.server.parameters = Parámetros del servidor streaming +stream.server.port = Puerto de Servidor de Stream +streams = Streams +timer = Temporizador +touchscreen = Pantalla táctil +type = Tipo +unit = Unidad +update.period = Período de actualización +usage = Uso +use.logging = Usar Registro +vertical.size.percent = Tamaño vertical +voice.command = Comando: +voice.assistant = Asistente de voz +vu.meter = Medidor VU +waiting.for.command = Esperando el comando de voz... +weather = Tiempo +web = Web +web.server = Servidor web +width = Ancho +yes = Sí diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/Catalunya M\303\272sica.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/Catalunya M\303\272sica.png" new file mode 100644 index 00000000..ba7927d1 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/Catalunya M\303\272sica.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/RNE Radio Cl\303\241sica.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/RNE Radio Cl\303\241sica.png" new file mode 100644 index 00000000..dd10c69f Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/RNE Radio Cl\303\241sica.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder-on.png" new file mode 100644 index 00000000..36482e26 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder.png" new file mode 100644 index 00000000..13fb01ab Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/stations.m3u" new file mode 100644 index 00000000..09334565 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Cl\303\241sico/stations.m3u" @@ -0,0 +1,4 @@ +#RNE Radio Clásica +http://radioclasica.rtveradio.cires21.com/radioclasica_hc.mp3 +#Catalunya Música +http://catmusica.ccma.audioemotion.stream.flumotion.com/ccma/catmusica.mp3 diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Cadena Mix FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Cadena Mix FM.png" new file mode 100644 index 00000000..e7f8d405 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Cadena Mix FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Chocolate FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Chocolate FM.jpg" new file mode 100644 index 00000000..171bad5f Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Chocolate FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/DilemaRadio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/DilemaRadio.jpg" new file mode 100644 index 00000000..2c552160 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/DilemaRadio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Efecto Baile Radio Ibiza.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Efecto Baile Radio Ibiza.jpg" new file mode 100644 index 00000000..38b66390 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Efecto Baile Radio Ibiza.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Elixir FM 106.9.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Elixir FM 106.9.png" new file mode 100644 index 00000000..80549b79 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Elixir FM 106.9.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Fabulosa Fm.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Fabulosa Fm.jpg" new file mode 100644 index 00000000..56e25be0 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Fabulosa Fm.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Formula 30.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Formula 30.png" new file mode 100644 index 00000000..70aa639e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Formula 30.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Fresca FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Fresca FM.png" new file mode 100644 index 00000000..1aff39ce Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Fresca FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Isla FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Isla FM.png" new file mode 100644 index 00000000..b100498e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/La Isla FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Loca FM - Dance.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Loca FM - Dance.png" new file mode 100644 index 00000000..7832ed94 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Loca FM - Dance.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/M\303\241s Musica FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/M\303\241s Musica FM.jpg" new file mode 100644 index 00000000..1a4bcf2f Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/M\303\241s Musica FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/OM Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/OM Radio.png" new file mode 100644 index 00000000..6489a0a4 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/OM Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Pure Ibiza Radio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Pure Ibiza Radio.jpg" new file mode 100644 index 00000000..4131ab97 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Pure Ibiza Radio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/QD Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/QD Radio.png" new file mode 100644 index 00000000..11faf2df Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/QD Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Remember the Music FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Remember the Music FM.jpg" new file mode 100644 index 00000000..8b7ac675 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Remember the Music FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Sonica Club.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Sonica Club.png" new file mode 100644 index 00000000..925ebe46 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Sonica Club.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Top Dance FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Top Dance FM.jpg" new file mode 100644 index 00000000..9997299e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Top Dance FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Unika FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Unika FM.png" new file mode 100644 index 00000000..aa361c38 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Unika FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Zona Urbana.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Zona Urbana.jpg" new file mode 100644 index 00000000..f1f908f5 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/Zona Urbana.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder-on.png" new file mode 100644 index 00000000..dda13741 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder.png" new file mode 100644 index 00000000..98761ea6 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/stations.m3u" new file mode 100644 index 00000000..cf4ca834 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Contempor\303\241neo/stations.m3u" @@ -0,0 +1,38 @@ +#OM Radio +http://server9.emitironline.com:12488/radio +#Remember the Music FM +http://5.135.183.124:8434/live +#Elixir FM 106.9 +http://radioserver10.profesionalhosting.com:41004/stream/1/ +#La Fresca FM +http://stream.produccionesdale.com:8899/altacalidad +#Loca FM - Dance +http://5.39.66.128:8004/live +#Pure Ibiza Radio +http://192.99.1.139:9280/stream +#Cadena Mix FM +http://91.121.77.67:8000/; +#Sonica Club +http://s3.viastreaming.net:8032/; +#Efecto Baile Radio Ibiza +http://emisorasmusicales.es:8000/efectobaile.mp3 +#Unika FM +http://stream.unika.fm:8009/stream +#QD Radio +http://85.214.82.94:8026/; +#Top Dance FM +http://195.154.182.222:26846/live +#La Isla FM +http://streaming.laisla.fm:7000/32k-aac +#Formula 30 +http://stm1.emiteonline.com:8001/formula30 +#Zona Urbana +http://94.23.6.53:8372/; +#Más Musica FM +http://212.129.60.86:9994/; +#Fabulosa Fm +http://185.36.211.142:57320/fabulosa +#DilemaRadio +http://192.99.39.108:7649/STREAM +#Chocolate FM +http://streaming5.elitecomunicacion.es:8082/live.mp3 diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Buzz R\303\240dio Costa Brava.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Buzz R\303\240dio Costa Brava.jpg" new file mode 100644 index 00000000..8822ab4c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Buzz R\303\240dio Costa Brava.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Contrabanda 91.4.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Contrabanda 91.4.png" new file mode 100644 index 00000000..efa55214 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Contrabanda 91.4.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda 4.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda 4.jpg" new file mode 100644 index 00000000..9cb924fb Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda 4.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Cero Ciudad Rodrigo 89.1 FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Cero Ciudad Rodrigo 89.1 FM.jpg" new file mode 100644 index 00000000..8004552d Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Cero Ciudad Rodrigo 89.1 FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Layetana.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Layetana.png" new file mode 100644 index 00000000..6adb5bf2 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Onda Layetana.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/RTVA CanalSur Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/RTVA CanalSur Radio.png" new file mode 100644 index 00000000..70881451 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/RTVA CanalSur Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Radio Kanal Barcelona 106.9 FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Radio Kanal Barcelona 106.9 FM.png" new file mode 100644 index 00000000..c284243c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Radio Kanal Barcelona 106.9 FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/R\303\240dio Mussol.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/R\303\240dio Mussol.png" new file mode 100644 index 00000000..afd2f490 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/R\303\240dio Mussol.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/Vaughan Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Vaughan Radio.png" new file mode 100644 index 00000000..dc687bd2 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/Vaughan Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder-on.png" new file mode 100644 index 00000000..b30aeaa0 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder.png" new file mode 100644 index 00000000..240fd784 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/iCat FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/iCat FM.png" new file mode 100644 index 00000000..6e5da072 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/iCat FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Cultura/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/stations.m3u" new file mode 100644 index 00000000..e0a41667 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Cultura/stations.m3u" @@ -0,0 +1,20 @@ +#RTVA CanalSur Radio +http://195.10.10.206/rtva/canalsurradio_master.mp3 +#iCat FM +http://icatfm.ccma.audioemotion.stream.flumotion.com/ccma/icatfm.mp3 +#Onda Cero Ciudad Rodrigo 89.1 FM +http://94.23.87.98:9114/; +#Onda Layetana +http://stream.ondalayetana.es:4876/live +#Radio Kanal Barcelona 106.9 FM +http://5.135.71.2:31826/stream.mp3 +#Ràdio Mussol +http://78.129.193.82:6258/; +#Buzz Ràdio Costa Brava +http://130.185.144.199:38819/; +#Contrabanda 91.4 +http://www.contrabanda.org:8000/contrabanda +#Vaughan Radio +http://vaughanradioweb.streaming-pro.com:8057/; +#Onda 4 +http://cervera.eldialdigital.com:8028/;stream.mp3 diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/1 Jazz Radio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/1 Jazz Radio.jpg" new file mode 100644 index 00000000..ebaeb180 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/1 Jazz Radio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/89.8 FM Smooth FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/89.8 FM Smooth FM.jpg" new file mode 100644 index 00000000..0b64c216 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/89.8 FM Smooth FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Costa del Mar - Smooth Sax.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Costa del Mar - Smooth Sax.jpg" new file mode 100644 index 00000000..9a4d9a70 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Costa del Mar - Smooth Sax.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Qfm 94.3 FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Qfm 94.3 FM.jpg" new file mode 100644 index 00000000..1f13fa6c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Qfm 94.3 FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radio Radio Network 98.8 FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radio Radio Network 98.8 FM.jpg" new file mode 100644 index 00000000..86f93cdb Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radio Radio Network 98.8 FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radiowapa.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radiowapa.jpg" new file mode 100644 index 00000000..43d87251 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Radiowapa.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Rototom Sunsplash Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Rototom Sunsplash Radio.png" new file mode 100644 index 00000000..030637db Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Rototom Sunsplash Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/SmoothJazzRadio.es.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/SmoothJazzRadio.es.jpg" new file mode 100644 index 00000000..5b795a44 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/SmoothJazzRadio.es.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/Swing Latino FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Swing Latino FM.png" new file mode 100644 index 00000000..18482b1a Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/Swing Latino FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder-on.png" new file mode 100644 index 00000000..88837fe7 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder.png" new file mode 100644 index 00000000..62cebe29 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Jazz/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/stations.m3u" new file mode 100644 index 00000000..721a050b --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Jazz/stations.m3u" @@ -0,0 +1,18 @@ +#1 Jazz Radio +http://c4.auracast.net:8060/stream +#Qfm 94.3 FM +http://94.75.227.133:7420/; +#Swing Latino FM +http://37.59.121.120:9290/stream +#SmoothJazzRadio.es +http://streaming.radionomy.com/JamendoLounge +#Radiowapa +https://stream.radio.co/sb52bde625/listen +#Rototom Sunsplash Radio +http://broadcast-1.radiorototom.com/rototomsunsplash.mp3 +#Costa del Mar - Smooth Sax +http://stream.cdm-smoothsax.com:8024/stream-AAC-Smooth +#Radio Radio Network 98.8 FM +http://94.23.85.189:8000/listen.mp3 +#89.8 FM Smooth FM +http://37.59.28.208:8385/stream diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Babyradio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Babyradio.png" new file mode 100644 index 00000000..8f8b814c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Babyradio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Pequeradio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Pequeradio.png" new file mode 100644 index 00000000..03869365 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/Pequeradio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder-on.png" new file mode 100644 index 00000000..08c04da7 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder.png" new file mode 100644 index 00000000..e962e7c6 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/stations.m3u" new file mode 100644 index 00000000..3e0c0d77 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Ni\303\261os/stations.m3u" @@ -0,0 +1,4 @@ +#Babyradio +http://sd396babyradio1.lcinternet.com:8000/live +#Pequeradio +http://www.emisorasmusicales.es:8030/pequeradio.mp3 diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena COPE Sevilla.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena COPE Sevilla.png" new file mode 100644 index 00000000..45492ecc Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena COPE Sevilla.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena SER.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena SER.png" new file mode 100644 index 00000000..4302c590 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Cadena SER.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/Catalunya R\303\240dio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Catalunya R\303\240dio.jpg" new file mode 100644 index 00000000..1f291110 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Catalunya R\303\240dio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/EsRadio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/EsRadio.png" new file mode 100644 index 00000000..ac98a89f Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/EsRadio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/RAC 1.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/RAC 1.jpg" new file mode 100644 index 00000000..478be9f7 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/RAC 1.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/Radio Nervi\303\263n.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Radio Nervi\303\263n.png" new file mode 100644 index 00000000..d5611694 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/Radio Nervi\303\263n.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/VOXRadio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/VOXRadio.png" new file mode 100644 index 00000000..5bec5226 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/VOXRadio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder-on.png" new file mode 100644 index 00000000..031e4f90 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder.png" new file mode 100644 index 00000000..f36eb71c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Noticias/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/stations.m3u" new file mode 100644 index 00000000..8d249c55 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Noticias/stations.m3u" @@ -0,0 +1,14 @@ +#VOXRadio +http://www.voxradio.es:8000/emision.ogg +#EsRadio +http://livestreaming3.esradio.fm/stream64.mp3 +#Cadena SER +http://19993.live.streamtheworld.com/CADENASERAAC_SC +#RAC 1 +https://streaming.rac1.cat/ +#Cadena COPE Sevilla +http://wecast-b03-02.flumotion.com/copesedes/sevilla.mp3 +#Catalunya Ràdio +http://catradio.ccma.audioemotion.stream.flumotion.com/ccma/catradio.mp3 +#Radio Nervión +http://radionervion.streaming-pro.com:6017/nervionmobile diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/AyomtsRadio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/AyomtsRadio.png" new file mode 100644 index 00000000..70275148 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/AyomtsRadio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Cadena Elite.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Cadena Elite.png" new file mode 100644 index 00000000..506238c9 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Cadena Elite.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Central FM 98.6.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Central FM 98.6.png" new file mode 100644 index 00000000..bba4e991 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Central FM 98.6.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Chanquete FM M\303\241laga.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Chanquete FM M\303\241laga.jpg" new file mode 100644 index 00000000..85aca06e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Chanquete FM M\303\241laga.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/EiTB Gaztea.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/EiTB Gaztea.png" new file mode 100644 index 00000000..bfb3cd29 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/EiTB Gaztea.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Europa FM Gipuzkoa.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Europa FM Gipuzkoa.jpg" new file mode 100644 index 00000000..ab146070 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Europa FM Gipuzkoa.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Eurostereo.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Eurostereo.jpg" new file mode 100644 index 00000000..deb562f7 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Eurostereo.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Fiesta FM - Nacional.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Fiesta FM - Nacional.png" new file mode 100644 index 00000000..71e76dee Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Fiesta FM - Nacional.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Fly Radio Canarias.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Fly Radio Canarias.png" new file mode 100644 index 00000000..f4849e92 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Fly Radio Canarias.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Hit FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Hit FM.png" new file mode 100644 index 00000000..e1d30375 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Hit FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/HitPlus Spain.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/HitPlus Spain.png" new file mode 100644 index 00000000..a867fc15 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/HitPlus Spain.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Inca Radio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Inca Radio.jpg" new file mode 100644 index 00000000..90ce069e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Inca Radio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Kyoto FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Kyoto FM.png" new file mode 100644 index 00000000..a6d54a98 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Kyoto FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/LE Radio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/LE Radio.jpg" new file mode 100644 index 00000000..18e29f5d Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/LE Radio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Nayra Al Amanecer del Sol.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Nayra Al Amanecer del Sol.jpg" new file mode 100644 index 00000000..2d7f7769 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Nayra Al Amanecer del Sol.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Pepe Radio 89.3.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Pepe Radio 89.3.jpg" new file mode 100644 index 00000000..97ae779e Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Pepe Radio 89.3.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/RPA R\303\240dio Platja d'Aro.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/RPA R\303\240dio Platja d'Aro.png" new file mode 100644 index 00000000..8f68c954 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/RPA R\303\240dio Platja d'Aro.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Oro - M\303\241laga.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Oro - M\303\241laga.jpg" new file mode 100644 index 00000000..fdc27962 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Oro - M\303\241laga.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Pi Espa\303\261a.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Pi Espa\303\261a.jpg" new file mode 100644 index 00000000..76098ef9 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Pi Espa\303\261a.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Tentaci\303\263n.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Tentaci\303\263n.jpg" new file mode 100644 index 00000000..f30cd966 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Radio Tentaci\303\263n.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/Wradio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Wradio.png" new file mode 100644 index 00000000..134160c3 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/Wradio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/folder-on.png" new file mode 100644 index 00000000..80e41a47 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/folder.png" new file mode 100644 index 00000000..b554d944 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Pop/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Pop/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Pop/stations.m3u" new file mode 100644 index 00000000..a15b45d2 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Pop/stations.m3u" @@ -0,0 +1,42 @@ +#Europa FM Gipuzkoa +http://stream.irratia.net/1b +#EiTB Gaztea +http://mp3-eitb.stream.flumotion.com/eitb/gaztea.mp3 +#HitPlus Spain +http://media.xseu.net/HitPlus +#Radio Pi España +http://enlacederadio.ddns.net:8100/stream +#Cadena Elite +https://streaming2.elitecomunicacion.es:8000/stream +#LE Radio +http://104.167.4.67:8016/; +#Radio Oro - Málaga +http://www.portalradio.es:8002/; +#Central FM 98.6 +http://s29.myradiostream.com:4922/; +#Inca Radio +http://91.121.156.27:8000/stream +#Eurostereo +http://5.135.183.124:9280/stream +#Fly Radio Canarias +https://via.vulstream.com/radio/8430/radio.mp3 +#RPA Ràdio Platja d'Aro +http://stream.internetgirona.com:8008/onair +#Radio Tentación +http://88.26.228.190:8020/; +#Wradio +http://stream.wradio.es:7000/; +#Nayra Al Amanecer del Sol +http://209.141.39.242:8740/stream +#AyomtsRadio +http://ayomts.duckdns.org:8000/28mp3 +#Hit FM +http://hitfm.kissfmradio.cires21.com/hitfm.mp3 +#Chanquete FM Málaga +http://185.23.192.118:8008/; +#Pepe Radio 89.3 +http://server10.emitironline.com:8000/; +#Kyoto FM +http://148.251.83.173:9200/; +#Fiesta FM - Nacional +http://131.153.40.122:9314/;stream.mp3 diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/1000 Oldies.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/1000 Oldies.png" new file mode 100644 index 00000000..666d7db0 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/1000 Oldies.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/90FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/90FM.jpg" new file mode 100644 index 00000000..27c123ed Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/90FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Aire FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Aire FM.png" new file mode 100644 index 00000000..a0e7c13a Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Aire FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Amores Ocultos.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Amores Ocultos.jpg" new file mode 100644 index 00000000..4f5083a5 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Amores Ocultos.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Cadena Nostalgia.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Cadena Nostalgia.png" new file mode 100644 index 00000000..0c2cd1a8 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Cadena Nostalgia.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Decada FM 100.1.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Decada FM 100.1.jpg" new file mode 100644 index 00000000..c7e582be Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Decada FM 100.1.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/FM Calpe.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/FM Calpe.jpg" new file mode 100644 index 00000000..2c4aaff8 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/FM Calpe.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Factory Music.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Factory Music.jpg" new file mode 100644 index 00000000..20322ad9 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Factory Music.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Formula Disco.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Formula Disco.jpg" new file mode 100644 index 00000000..5f8ba2ae Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Formula Disco.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/IB3 Musica.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/IB3 Musica.png" new file mode 100644 index 00000000..df923236 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/IB3 Musica.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Inolvidable FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Inolvidable FM.png" new file mode 100644 index 00000000..bccab8cb Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Inolvidable FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/JAMMFM Radio Costa del Sol.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/JAMMFM Radio Costa del Sol.jpg" new file mode 100644 index 00000000..0eb30689 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/JAMMFM Radio Costa del Sol.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Kiss FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Kiss FM.jpg" new file mode 100644 index 00000000..dd9421c0 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Kiss FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Kustradion.fm.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Kustradion.fm.jpg" new file mode 100644 index 00000000..37cf5fee Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Kustradion.fm.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/LOS40 Classic.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/LOS40 Classic.png" new file mode 100644 index 00000000..dc49570a Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/LOS40 Classic.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Los 70 en Colmenares.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Los 70 en Colmenares.png" new file mode 100644 index 00000000..d435b44f Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Los 70 en Colmenares.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/MatkaRadio Fuengirola.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/MatkaRadio Fuengirola.jpg" new file mode 100644 index 00000000..90636ebf Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/MatkaRadio Fuengirola.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Melodia Para Dos.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Melodia Para Dos.png" new file mode 100644 index 00000000..23d08416 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Melodia Para Dos.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/ROCA FM Clasicos.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/ROCA FM Clasicos.png" new file mode 100644 index 00000000..8e2862cb Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/ROCA FM Clasicos.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Mi Amigo International.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Mi Amigo International.jpg" new file mode 100644 index 00000000..3316e34a Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Mi Amigo International.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Universal.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Universal.jpg" new file mode 100644 index 00000000..b9add751 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Radio Universal.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Styl Classics 95.2 FM.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Styl Classics 95.2 FM.jpg" new file mode 100644 index 00000000..48113d8a Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Styl Classics 95.2 FM.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/Stz Irratia.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Stz Irratia.png" new file mode 100644 index 00000000..c1bd79f3 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/Stz Irratia.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/X-Pat Radio Two.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/X-Pat Radio Two.jpg" new file mode 100644 index 00000000..ba1dbf42 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/X-Pat Radio Two.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/folder-on.png" new file mode 100644 index 00000000..20601a33 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/folder.png" new file mode 100644 index 00000000..e1aa6f5c Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Retro/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Retro/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Retro/stations.m3u" new file mode 100644 index 00000000..6732e8b2 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Retro/stations.m3u" @@ -0,0 +1,48 @@ +#1000 Oldies +http://c3.auracast.net:8010/stream +#ROCA FM Clasicos +https://xxdelgado.radioca.st/; +#Inolvidable FM +http://5.63.151.52:7008/stream +#Radio Mi Amigo International +http://195.154.217.103:8123/stream +#Factory Music +http://s1.utune.in:8696/stream +#Radio Universal +http://51.68.227.157:8005/stream +#X-Pat Radio Two +http://37.61.239.13:8000/xpr2 +#Kustradion.fm +http://198.178.123.2:8382/; +#Amores Ocultos +http://88.198.43.9:7030/; +#Los 70 en Colmenares +http://94.23.6.53:8709/; +#Formula Disco +http://51.68.227.157:8025/stream +#Stz Irratia +http://212.83.151.18:8296/; +#FM Calpe +http://canopus.dribbcast.com:8018/; +#MatkaRadio Fuengirola +https://streams.radio.co/sb31788003/listen +#LOS40 Classic +http://14923.live.streamtheworld.com/LOS40_CLASSIC_SC +#Aire FM +http://server.hablocomunicaciones.com:8020/; +#Decada FM 100.1 +http://streaming8.elitecomunicacion.es:8230/; +#90FM +http://www.portalradio.es:8010/; +#IB3 Musica +http://91.121.156.27:8023/live?type=.mp3 +#JAMMFM Radio Costa del Sol +http://stream.jammfmradio.com:8075/; +#Melodia Para Dos +http://195.154.56.114:7006/; +#Kiss FM +http://kissfm.kissfmradio.cires21.com/kissfm.mp3 +#Cadena Nostalgia +http://server.hablocomunicaciones.com:6002/oyentes128 +#Styl Classics 95.2 FM +http://149.56.155.73:8042/; diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/BeachRock Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/BeachRock Radio.png" new file mode 100644 index 00000000..9c0266dc Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/BeachRock Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Ciudad Rock Radio.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Ciudad Rock Radio.jpg" new file mode 100644 index 00000000..1823ae09 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Ciudad Rock Radio.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Free FM Rock.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Free FM Rock.jpg" new file mode 100644 index 00000000..cf50fc28 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Free FM Rock.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Holiday Gym Rock.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Holiday Gym Rock.png" new file mode 100644 index 00000000..6fda53b8 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Holiday Gym Rock.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Mariskal Rock.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Mariskal Rock.png" new file mode 100644 index 00000000..beb7b129 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Mariskal Rock.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/MuchoRock Radio.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/MuchoRock Radio.png" new file mode 100644 index 00000000..4d647fda Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/MuchoRock Radio.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Radio Carcoma 107.9 FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Radio Carcoma 107.9 FM.png" new file mode 100644 index 00000000..54b63343 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Radio Carcoma 107.9 FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Rock FM.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Rock FM.png" new file mode 100644 index 00000000..dc3075bb Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Rock FM.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/Spektra Fm.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Spektra Fm.jpg" new file mode 100644 index 00000000..7916df6b Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/Spektra Fm.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/TNT Radio Rock.jpg" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/TNT Radio Rock.jpg" new file mode 100644 index 00000000..0fc803c0 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/TNT Radio Rock.jpg" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/folder-on.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/folder-on.png" new file mode 100644 index 00000000..121a1d96 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/folder-on.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/folder.png" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/folder.png" new file mode 100644 index 00000000..7e0a9437 Binary files /dev/null and "b/languages/Spanish/radio-stations/G\303\251nero/Rock/folder.png" differ diff --git "a/languages/Spanish/radio-stations/G\303\251nero/Rock/stations.m3u" "b/languages/Spanish/radio-stations/G\303\251nero/Rock/stations.m3u" new file mode 100644 index 00000000..0aec85a4 --- /dev/null +++ "b/languages/Spanish/radio-stations/G\303\251nero/Rock/stations.m3u" @@ -0,0 +1,20 @@ +#Rock FM +http://flucast-b03-02.flumotion.com/cope/rockfm.mp3 +#MuchoRock Radio +http://5.135.183.124:8438/stream +#TNT Radio Rock +http://s2streamingradio.desafiohosting.com:8023/stream +#Mariskal Rock +http://radioserver9.profesionalhosting.com:8042/;stream +#Holiday Gym Rock +http://holidaygym.emitironline.com:9030/stream +#Free FM Rock +http://tachyon.shoutca.st:8298/; +#BeachRock Radio +http://stream.beachrockradio.com:7850/; +#Ciudad Rock Radio +http://01.solumedia.com.ar:7048/; +#Spektra Fm +http://stm1.emiteonline.com:8008/spektrafm +#Radio Carcoma 107.9 FM +http://www.radiocarcoma.com:8080/; diff --git a/languages/Spanish/voice-commands.properties b/languages/Spanish/voice-commands.properties new file mode 100644 index 00000000..53f1fb62 --- /dev/null +++ b/languages/Spanish/voice-commands.properties @@ -0,0 +1,113 @@ +VA_RADIO = radio +VA_GO_RADIO = ir radio +VA_FILES = archivos +VA_GO_FILES = ir archivos +VA_AUDIO_FILES = archivos de sonido +VA_AUDIOBOOKS = audiolibros +VA_BOOKS = libros +VA_GO_BOOKS = ir libros +VA_STREAM = corriente +VA_GO_STREAM = ir corriente +VA_CD_PLAYER = reproductor de cd +VA_BACK = atrás +VA_GO_BACK = regresa +VA_SCREENSAVER = salvapantallas +VA_SAVER = ahorrador +VA_LANGUAGE = idioma +VA_GO_LANGUAGE = ir idioma +VA_CHANGE_LANGUAGE = cambiar idioma +VA_PLAYER = reproductor +VA_GO_PLAYER = ir reproductor +VA_ABOUT = sobre +VA_GO_ABOUT = ir sobre +VA_UP = arriba +VA_GO_UP = subir +VA_DOWN = abajo +VA_GO_DOWN = bajar +VA_LEFT = izquierda +VA_GO_LEFT = ve a la izquierda +VA_RIGHT = derecho +VA_GO_RIGHT = ve a la derecha +VA_OK = ok +VA_OKAY = okay +VA_ENTER = entrar +VA_SELECT = seleccionar +VA_CLOCK = reloj +VA_LOGO = logo +VA_SLIDESHOW = diapositivas +VA_INDICATOR = indicador +VA_WEATHER = clima +VA_ONE_MINUTE = un minuto +VA_THREE_MINUTES = 3 minutos +VA_OFF = apagar +VA_HOME = casa +VA_GO_HOME = vete a casa +VA_SHUTDOWN = apagar +VA_PLAY = jugar +VA_PAUSE = pausa +VA_PODCAST = podcast +VA_PODCASTS = podcasts +VA_GENRE = género +VA_GO_GENRE = ir género +VA_MUTE = mudo +VA_VOLUME_UP = sube el volumen +VA_VOLUME_DOWN = bajar volumen +VA_PAGE_UP = página arriba +VA_PAGE_DOWN = página abajo +VA_NEXT_PAGE = siguiente página +VA_PREVIOUS_PAGE = pagina anterior +VA_MUSIC = música +VA_USER_HOME = casa de usuario +VA_ROOT = raíz +VA_PARENT = padre +VA_VOLUME = establecer volumen +VA_TIME = hora +VA_TIME_UP = aumentar el tiempo +VA_TIME_DOWN = disminuir el tiempo +VA_NEXT = próximo +VA_PREVIOUS = anterior +VA_NEW_BOOKS = libros nuevos +VA_ABC = a b c +VA_ALPHABET = alfabeto +VA_SEARCH_BY_GENRE = buscar por género +VA_SEARCH_BY_AUTHOR = buscar por autor +VA_GO_TO_PAGE = ir a la página +VA_PAGE_NUMBER = número de página +VA_STOP = detener +VA_EQUALIZER = ecualizador +VA_TIMER = temporizador +VA_NETWORK = red +VA_FAVORITES = favoritos +VA_REFRESH = actualizar +VA_EJECT = expulsar +VA_MENU = menú +VA_SLEEP = dormir +VA_SLEEP_NOW = duerme ahora +VA_POWEROFF = poweroff +VA_WAKE_UP = despierta +VA_WI_FI_NETWORKS = redes wi-fi +VA_DISCONNECT_WI_FI = desconectar wi-fi +VA_SORT_NETWORKS = ordenar redes +VA_DELETE_PASSWORD = eliminar contraseña +VA_SHOW_PASSWORD = mostrar contraseña +VA_HIDE_PASSWORD = contraseña oculta +VA_0 = 0 +VA_1 = 1 +VA_2 = 2 +VA_3 = 3 +VA_4 = 4 +VA_5 = 5 +VA_6 = 6 +VA_7 = 7 +VA_8 = 8 +VA_9 = 9 +VA_STR_0 = cero +VA_STR_1 = uno +VA_STR_2 = dos +VA_STR_3 = tres +VA_STR_4 = cuatro +VA_STR_5 = cinco +VA_STR_6 = seis +VA_STR_7 = siete +VA_STR_8 = ocho +VA_STR_9 = nueve diff --git a/languages/Spanish/weather-config.txt b/languages/Spanish/weather-config.txt new file mode 100644 index 00000000..812370b9 --- /dev/null +++ b/languages/Spanish/weather-config.txt @@ -0,0 +1,88 @@ +[screen.info] +width = 480 +height = 320 +depth = 32 +frame.rate = 30 + +[weather.config] +city = Madrid +city.label = +country = Spain +region = +update.period = 10 +unit = c +military.time.format = True +use.logging = False + +[colors] +color.dark = 0,70,75 +color.dark.light = 20,90,100 +color.medium = 70,140,150 +color.bright = 160,190,210 +color.contrast = 255,190,120 +color.logo = 20,190,160 + +[labels] +sun = Dom +mon = Lun +tue = Mar +wed = Mié +thu = Jue +fri = Vie +sat = Sáb + +humidity = Humedad +wind = Viento +mph = km/h +sunrise = Amanecer +sunset = Puesta de sol + +0 = Tornado +1 = Tormenta tropical +2 = Huracán +3 = Tormentas eléctricas severas +4 = Tormentas +5 = Lluvia Mixta y Nieve +6 = Lluvia Mixta y Aguanieve +7 = Mezcla de nieve y aguanieve +8 = Llovizna helada +9 = Llovizna +10 = Lluvia helada +11 = Lluvia +12 = Lluvia +13 = Copos de nieve +14 = Duchas de nieve liviana +15 = La nieve que sopla +16 = Nieve +17 = Granizo +18 = Aguanieve +19 = Polvo +20 = Brumoso +21 = Calina +22 = Humeante +23 = Tempestuoso +24 = Ventoso +25 = Frío +26 = Nublado +27 = Mayormente nublado +28 = Mayormente nublado +29 = Parcialmente nublado +30 = Parcialmente nublado +31 = Tiempo despejado +32 = soleado +33 = Mayormente claro +34 = Mayormente soleado +35 = Mezcla de lluvia y granizo +36 = Caliente +37 = Tormentas aisladas +38 = Tormentas eléctricas dispersas +39 = Tormentas eléctricas dispersas +40 = Chubascos dispersos +41 = Fuertes nevadas +42 = Chubascos de nieve dispersos +43 = Fuertes nevadas +44 = Parcialmente nublado +45 = Lluvias +46 = Duchas de nieve +47 = Aislado lluvias +3200 = No disponible diff --git a/languages/languages.txt b/languages/languages.txt index 7ada7e21..6d622564 100644 --- a/languages/languages.txt +++ b/languages/languages.txt @@ -2,22 +2,46 @@ English-USA = English-USA German = German French = French +Italian = Italian +Spanish = Spanish Russian = Russian [German] English-USA = Englisch-USA German = Deutsche French = Französisch +Italian = Italien +Spanish = Spanisch Russian = Russisch [French] English-USA = Anglais-USA German = Allemand French = Français +Italian = Italien +Spanish = Espagnol Russian = Russe +[Italian] +English-USA = Inglese-USA +German = Tedesco +French = Francese +Italian = Italiano +Spanish = Spagnolo +Russian = Russa + +[Spanish] +English-USA = Inglés-USA +German = Alemán +French = Francés +Italian = Italiano +Spanish = Español +Russian = Ruso + [Russian] English-USA = Английский-США German = Немецкий French = Французский +Italian = Итальянский +Spanish = Испанский Russian = Русский diff --git a/peppy.py b/peppy.py index 86d998fc..e0fc8952 100644 --- a/peppy.py +++ b/peppy.py @@ -28,7 +28,7 @@ from threading import RLock, Thread from subprocess import Popen from event.dispatcher import EventDispatcher -from player.proxy import Proxy, MPLAYER, MPD +from player.proxy import Proxy, MPLAYER_NAME, MPD_NAME, SHAIRPORT_SYNC_NAME, RASPOTIFY_NAME from screensaver.screensaverdispatcher import ScreensaverDispatcher from ui.state import State from ui.screen.radiogroup import RadioGroupScreen @@ -66,6 +66,8 @@ from ui.screen.podcasts import PodcastsScreen from ui.screen.podcastepisodes import PodcastEpisodesScreen from ui.screen.podcastplayer import PodcastPlayerScreen +from ui.screen.airplayplayer import AirplayPlayerScreen +from ui.screen.spotifyconnect import SpotifyConnectScreen from ui.screen.network import NetworkScreen from ui.screen.wifi import WiFiScreen from ui.screen.keyboard import KeyboardScreen @@ -83,6 +85,7 @@ def __init__(self): self.config = self.util.config self.cdutil = CdUtil(self.util) self.use_web = self.config[USAGE][USE_WEB] + self.players = {} s = self.config[SCRIPTS][STARTUP] if s != None and len(s.strip()) != 0: @@ -108,7 +111,7 @@ def __init__(self): sys.stdout = sys.stderr = f from web.server.webserver import WebServer self.web_server = WebServer(self.util, self) - except Exception as e: + except: self.use_web = False self.voice_assistant = None @@ -125,11 +128,12 @@ def __init__(self): about.add_listener(self.go_home) self.screens = {KEY_ABOUT : about} self.current_player_screen = None + self.initial_player_name = self.config[AUDIO][PLAYER_NAME] self.current_audio_file = None self.current_language = self.config[CURRENT][LANGUAGE] - if self.config[AUDIO][PLAYER_NAME] == MPD: + if self.config[AUDIO][PLAYER_NAME] == MPD_NAME: self.start_audio() if self.config[USAGE][USE_VU_METER]: self.util.load_screensaver(VUMETER) @@ -179,6 +183,12 @@ def __init__(self): state.episode_time = self.config[PODCASTS][PODCAST_EPISODE_TIME] state.source = INIT self.go_podcast_player(state) + elif self.config[CURRENT][MODE] == AIRPLAY: + self.reconfigure_player(SHAIRPORT_SYNC_NAME) + self.go_airplay() + elif self.config[CURRENT][MODE] == SPOTIFY_CONNECT: + self.reconfigure_player(RASPOTIFY_NAME) + self.go_spotify_connect() self.player_state = PLAYER_RUNNING self.run_timer_thread = False @@ -223,24 +233,30 @@ def is_internet_available(self, timeout): def start_audio(self): """ Starts audio server and client """ + if self.config[AUDIO][PLAYER_NAME] in self.players.keys(): + self.player = self.players[self.config[AUDIO][PLAYER_NAME]] + if self.player.proxy: + self.player.proxy.start() + return + folder = None try: folder = self.config[AUDIO][SERVER_FOLDER] except: pass - cmd = None + start_cmd = None try: - cmd = self.config[AUDIO][SERVER_COMMAND] + start_cmd = self.config[AUDIO][SERVER_START_COMMAND] except: pass default_cd_drive = self.cdutil.get_default_cd_drive() - if self.config[AUDIO][PLAYER_NAME] == MPLAYER and default_cd_drive: + if self.config[AUDIO][PLAYER_NAME] == MPLAYER_NAME and default_cd_drive: cd_drive_name = default_cd_drive[1] if ":" in cd_drive_name: # Windows cd_drive_name = cd_drive_name.split(":")[0] + ":" - cmd = cmd + " -cdrom-device " + cd_drive_name + start_cmd = start_cmd + " -cdrom-device " + cd_drive_name stream_server_parameters = None try: @@ -249,10 +265,10 @@ def start_audio(self): pass if self.config[USAGE][USE_STREAM_SERVER] and stream_server_parameters: - if cmd: - cmd = cmd + " " + stream_server_parameters + if start_cmd: + start_cmd = start_cmd + " " + stream_server_parameters else: - cmd = stream_server_parameters + start_cmd = stream_server_parameters stream_client_parameters = None try: @@ -261,31 +277,35 @@ def start_audio(self): pass if stream_client_parameters: - if cmd: - cmd = cmd + " " + stream_client_parameters + if start_cmd: + start_cmd = start_cmd + " " + stream_client_parameters else: - cmd = stream_client_parameters + start_cmd = stream_client_parameters client_name = self.config[AUDIO][CLIENT_NAME] linux = self.config[LINUX_PLATFORM] + stop_cmd = self.config[AUDIO][SERVER_STOP_COMMAND] - proxy = Proxy(linux, folder, cmd, self.config[PLAYER_SETTINGS][VOLUME]) - self.audio_server = proxy.start() + self.proxy = Proxy(linux, folder, start_cmd, stop_cmd, self.config[PLAYER_SETTINGS][VOLUME]) + self.proxy_process = self.proxy.start() logging.debug("Audio Server Started") p = "player.client." + client_name m = importlib.import_module(p) n = client_name.title() - self.player = getattr(m, n)() - self.player.set_platform(linux) - self.player.set_player_mode(self.config[CURRENT][MODE]) - self.player.set_proxy(self.audio_server) - self.player.set_util(self.util) - self.player.start_client() - self.player.cd_track_title = self.config[LABELS][CD_TRACK] + player = getattr(m, n)() + player.set_platform(linux) + player.set_player_mode(self.config[CURRENT][MODE]) + player.set_proxy(self.proxy_process, self.proxy) + player.set_util(self.util) + player.start_client() + player.cd_track_title = self.config[LABELS][CD_TRACK] if self.config[PLAYER_SETTINGS][PAUSE]: - self.player.pause() + player.pause() + + self.players[self.config[AUDIO][PLAYER_NAME]] = player + self.player = player def start_timer_thread(self): """ Start timer thread """ @@ -295,7 +315,6 @@ def start_timer_thread(self): sleep_selected = self.config[TIMER][SLEEP] and len(self.config[TIMER][SLEEP_TIME]) > 0 poweroff_selected = self.config[TIMER][POWEROFF] and len(self.config[TIMER][SLEEP_TIME]) > 0 - wake_up_selected = self.config[TIMER][WAKE_UP] and len(self.config[TIMER][WAKE_UP_TIME]) > 0 if not sleep_selected and not poweroff_selected: return @@ -401,16 +420,24 @@ def set_mode(self, state): if self.current_mode != mode: self.player.stop() + if self.current_mode == AIRPLAY or self.current_mode == SPOTIFY_CONNECT: + self.reconfigure_player(self.initial_player_name) + self.current_mode = mode self.player.set_player_mode(mode) - if mode == RADIO: - self.go_stations(state) + if mode == RADIO: self.go_stations(state) elif mode == AUDIO_FILES: self.go_file_playback(state) elif mode == STREAM: self.go_stream(state) elif mode == AUDIOBOOKS: self.go_audiobooks(state) elif mode == CD_PLAYER: self.go_cd_playback(state) elif mode == PODCASTS: self.go_podcast_player(state) + elif mode == AIRPLAY: + self.reconfigure_player(SHAIRPORT_SYNC_NAME) + self.go_airplay(state) + elif mode == SPOTIFY_CONNECT: + self.reconfigure_player(RASPOTIFY_NAME) + self.go_spotify_connect(state) def go_player(self, state): """ Go to the current player screen @@ -430,7 +457,11 @@ def go_player(self, state): elif self.current_player_screen == STREAM: self.go_stream(state) elif self.current_player_screen == KEY_PODCAST_PLAYER: - self.go_podcast_player(state) + self.go_podcast_player(state) + elif self.current_player_screen == KEY_AIRPLAY_PLAYER: + self.go_airplay(state) + elif self.current_player_screen == KEY_SPOTIFY_CONNECT_PLAYER: + self.go_spotify_connect(state) def go_favorites(self, state): """ Go to the favorites screen @@ -526,6 +557,8 @@ def change_language(self, state): self.voice_assistant = VoiceAssistant(self.util) except: pass + else: + self.voice_assistant.change_language() else: self.voice_assistant.change_language() @@ -1118,7 +1151,7 @@ def get_play_screen_listeners(self): listeners = {} listeners[KEY_HOME] = self.go_home - listeners[KEY_SHUTDOWN] = self.shutdown + listeners[KEY_SHUTDOWN] = self.shutdown listeners[KEY_PLAY_PAUSE] = self.play_pause listeners[KEY_SET_VOLUME] = self.set_volume listeners[KEY_SET_CONFIG_VOLUME] = self.set_config_volume @@ -1141,7 +1174,8 @@ def go_stream(self, state=None): stream_screen = StationScreen(listeners, self.util, self.voice_assistant, STREAM) self.screens[STREAM] = stream_screen self.set_current_screen(STREAM) - self.screensaver_dispatcher.change_image(stream_screen.station_menu.station_button.state) + if stream_screen.station_menu.station_button: + self.screensaver_dispatcher.change_image(stream_screen.station_menu.station_button.state) stream_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image) stream_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image_folder) self.player.add_player_listener(stream_screen.screen_title.set_text) @@ -1309,6 +1343,145 @@ def go_audiobooks(self, state=None): else: self.go_site_playback(s) + def go_airplay(self, state=None): + """ Go airplay screen + + :param state: button state + """ + self.deactivate_current_player(KEY_AIRPLAY_PLAYER) + try: + if self.screens[KEY_AIRPLAY_PLAYER]: + self.player.add_player_listener(self.screens[KEY_AIRPLAY_PLAYER].handle_metadata) + if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): + self.set_current_screen(KEY_AIRPLAY_PLAYER) + else: + if getattr(state, "source", None) == None: + state.source = RESUME + self.set_current_screen(name=KEY_AIRPLAY_PLAYER, state=state) + self.current_player_screen = KEY_AIRPLAY_PLAYER + return + except: + pass + + listeners = self.get_play_screen_listeners() + next = getattr(self.player, "next", None) + previous = getattr(self.player, "previous", None) + screen = AirplayPlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, self.player.stop, next, previous) + self.player.add_player_listener(screen.handle_metadata) + screen.play_button.add_listener("pause", self.player.pause) + screen.play_button.add_listener("play", self.player.play) + + self.screens[KEY_AIRPLAY_PLAYER] = screen + self.set_current_screen(KEY_AIRPLAY_PLAYER, state=state) + + if self.use_web: + update = self.web_server.update_web_ui + redraw = self.web_server.redraw_web_ui + title_to_json = self.web_server.title_to_json + screen.add_screen_observers(update, redraw, None, None, title_to_json) + screen.add_loading_listener(redraw) + self.player.add_player_listener(self.web_server.update_player_listeners) + + screen.time_volume_button.start_listeners = [] + screen.time_volume_button.label_listeners = [] + screen.time_volume_button.press_listeners = [] + screen.time_volume_button.release_listeners = [] + + screen.file_button.label_listeners = [] + screen.file_button.press_listeners = [] + screen.file_button.release_listeners = [] + + def go_spotify_connect(self, state=None): + """ Go spotify connect screen + + :param state: button state + """ + self.deactivate_current_player(KEY_SPOTIFY_CONNECT_PLAYER) + try: + if self.screens[KEY_SPOTIFY_CONNECT_PLAYER]: + if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): + self.set_current_screen(KEY_SPOTIFY_CONNECT_PLAYER) + else: + if getattr(state, "source", None) == None: + state.source = RESUME + self.set_current_screen(name=KEY_SPOTIFY_CONNECT_PLAYER, state=state) + self.current_player_screen = KEY_SPOTIFY_CONNECT_PLAYER + return + except: + pass + + listeners = {} + listeners[KEY_HOME] = self.go_home + listeners[KEY_SHUTDOWN] = self.shutdown + screen = SpotifyConnectScreen(listeners, self.util, self.voice_assistant) + self.screens[KEY_SPOTIFY_CONNECT_PLAYER] = screen + self.set_current_screen(KEY_SPOTIFY_CONNECT_PLAYER, state=state) + + if self.use_web: + update = self.web_server.update_web_ui + redraw = self.web_server.redraw_web_ui + screen.add_screen_observers(update, redraw, None, None, None) + screen.add_loading_listener(redraw) + self.player.add_player_listener(self.web_server.update_player_listeners) + + screen.play_button.start_listeners = [] + screen.play_button.press_listeners = [] + screen.play_button.release_listeners = [] + + screen.time_volume_button.start_listeners = [] + screen.time_volume_button.label_listeners = [] + screen.time_volume_button.press_listeners = [] + screen.time_volume_button.release_listeners = [] + + screen.left_button.label_listeners = [] + screen.left_button.press_listeners = [] + screen.left_button.release_listeners = [] + + screen.right_button.label_listeners = [] + screen.right_button.press_listeners = [] + screen.right_button.release_listeners = [] + + screen.file_button.label_listeners = [] + screen.file_button.press_listeners = [] + screen.file_button.release_listeners = [] + + def reconfigure_player(self, new_player_name): + if self.player.proxy.stop_command: + self.player.proxy.stop() + + if self.config[LINUX_PLATFORM]: + platform = "linux" + else: + platform = "windows" + + key = new_player_name + "." + platform + + if key not in self.config[PLAYERS].keys(): + return + + player_config = self.config[PLAYERS][key] + + self.config[AUDIO][PLAYER_NAME] = new_player_name + self.config[AUDIO][SERVER_START_COMMAND] = player_config[SERVER_START_COMMAND] + self.config[AUDIO][CLIENT_NAME] = player_config[CLIENT_NAME] + + try: + self.config[AUDIO][STREAM_SERVER_PARAMETERS] = player_config[STREAM_SERVER_PARAMETERS] + except: + self.config[AUDIO][STREAM_SERVER_PARAMETERS] = None + + try: + self.config[AUDIO][STREAM_CLIENT_PARAMETERS] = player_config[STREAM_CLIENT_PARAMETERS] + except: + self.config[AUDIO][STREAM_CLIENT_PARAMETERS] = None + + try: + self.config[AUDIO][SERVER_STOP_COMMAND] = player_config[SERVER_STOP_COMMAND] + except: + self.config[AUDIO][SERVER_STOP_COMMAND] = None + + self.start_audio() + def go_equalizer(self, state=None): """ Go to the Equalizer Screen @@ -1498,7 +1671,8 @@ def go_stations(self, state=None): station_screen = StationScreen(listeners, self.util, self.voice_assistant) self.screens[KEY_STATIONS] = station_screen self.set_current_screen(KEY_STATIONS) - self.screensaver_dispatcher.change_image(station_screen.station_menu.station_button.state) + if station_screen.station_menu.station_button: + self.screensaver_dispatcher.change_image(station_screen.station_menu.station_button.state) station_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image) station_screen.station_menu.add_change_logo_listener(self.screensaver_dispatcher.change_image) station_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image_folder) @@ -1558,7 +1732,7 @@ def set_current_screen(self, name, go_back=False, state=None): ps = self.screens[self.current_screen] ps.set_visible(False) self.current_screen = name - cs = self.screens[self.current_screen] + cs = self.screens[self.current_screen] p = getattr(cs, "player_screen", None) if p: cs.enable_player_screen(True) @@ -1579,7 +1753,7 @@ def set_current_screen(self, name, go_back=False, state=None): cs.set_current(state=state) elif name == KEY_PLAY_FILE: f = getattr(state, "file_name", None) - if f and self.current_audio_file != state.file_name or self.current_player_screen != name: + if f or self.current_player_screen != name: a = getattr(state, "file_name", None) if a != None: self.current_audio_file = a @@ -1618,7 +1792,8 @@ def set_current_screen(self, name, go_back=False, state=None): state.playlist = ps.get_playlist() state.current_track_index = ps.current_track_index cs.set_current(state) - elif name == KEY_CD_TRACKS or name == PODCASTS or name == KEY_PODCAST_EPISODES or name == WIFI or name == NETWORK: + elif (name == KEY_CD_TRACKS or name == PODCASTS or name == KEY_PODCAST_EPISODES or + name == WIFI or name == NETWORK or name == KEY_ABOUT): cs.set_current(state) elif name == KEY_PODCAST_PLAYER: f = getattr(state, "file_name", None) @@ -1770,6 +1945,10 @@ def pre_shutdown(self): title_screen_name = KEY_PLAY_SITE elif self.config[CURRENT][MODE] == CD_PLAYER: title_screen_name = KEY_PLAY_CD + elif self.config[CURRENT][MODE] == AIRPLAY: + self.player.proxy.stop() + elif self.config[CURRENT][MODE] == SPOTIFY_CONNECT: + self.player.proxy.stop() if title_screen_name: try: @@ -1797,6 +1976,8 @@ def shutdown(self, event=None): if self.config[LINUX_PLATFORM]: if self.config[USAGE][USE_POWEROFF]: subprocess.call("sudo poweroff", shell=True) + else: + os._exit(0) else: self.shutdown_windows() @@ -1813,9 +1994,9 @@ def reboot(self): def shutdown_windows(self): """ Shutdown Windows player """ - if self.config[AUDIO][PLAYER_NAME] == MPD: + if self.config[AUDIO][PLAYER_NAME] == MPD_NAME: try: - Popen("taskkill /F /T /PID {pid}".format(pid=self.audio_server.pid)) + Popen("taskkill /F /T /PID {pid}".format(pid=self.proxy_process.pid)) except: pass os._exit(0) diff --git a/peppy.pyw b/peppy.pyw index 275410b1..e0fc8952 100644 --- a/peppy.pyw +++ b/peppy.pyw @@ -1,17 +1,17 @@ # Copyright 2016-2019 Peppy Player peppy.player@gmail.com -# +# # This file is part of Peppy Player. -# +# # Peppy Player is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # Peppy Player is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with Peppy Player. If not, see . @@ -28,7 +28,7 @@ from datetime import datetime from threading import RLock, Thread from subprocess import Popen from event.dispatcher import EventDispatcher -from player.proxy import Proxy, MPLAYER, MPD +from player.proxy import Proxy, MPLAYER_NAME, MPD_NAME, SHAIRPORT_SYNC_NAME, RASPOTIFY_NAME from screensaver.screensaverdispatcher import ScreensaverDispatcher from ui.state import State from ui.screen.radiogroup import RadioGroupScreen @@ -66,34 +66,35 @@ from util.cdutil import CdUtil from ui.screen.podcasts import PodcastsScreen from ui.screen.podcastepisodes import PodcastEpisodesScreen from ui.screen.podcastplayer import PodcastPlayerScreen +from ui.screen.airplayplayer import AirplayPlayerScreen +from ui.screen.spotifyconnect import SpotifyConnectScreen from ui.screen.network import NetworkScreen from ui.screen.wifi import WiFiScreen from ui.screen.keyboard import KeyboardScreen - class Peppy(object): """ Main class """ - - lock = RLock() - + + lock = RLock() def __init__(self): """ Initializer """ connected_to_internet = self.check_internet_connectivity() - + self.util = Util(connected_to_internet) self.config = self.util.config self.cdutil = CdUtil(self.util) self.use_web = self.config[USAGE][USE_WEB] - + self.players = {} + s = self.config[SCRIPTS][STARTUP] if s != None and len(s.strip()) != 0: self.util.run_script(s) - + layout = BorderLayout(self.util.screen_rect) layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_TOP_HEIGHT, 0, 0) - self.config[MAXIMUM_FONT_SIZE] = int((layout.TOP.h * PERCENT_TITLE_FONT) / 100.0) - + self.config[MAXIMUM_FONT_SIZE] = int((layout.TOP.h * PERCENT_TITLE_FONT)/100.0) + self.screensaver_dispatcher = ScreensaverDispatcher(self.util) try: @@ -101,7 +102,7 @@ class Peppy(object): if values: self.util.set_equalizer(values) except: - pass + pass if self.use_web: try: @@ -110,10 +111,10 @@ class Peppy(object): sys.stdout = sys.stderr = f from web.server.webserver import WebServer self.web_server = WebServer(self.util, self) - except Exception as e: + except: self.use_web = False - - self.voice_assistant = None + + self.voice_assistant = None if self.config[USAGE][USE_VOICE_ASSISTANT]: language = self.util.get_voice_assistant_language_code(self.config[CURRENT][LANGUAGE]) if language: @@ -122,44 +123,45 @@ class Peppy(object): self.voice_assistant = VoiceAssistant(self.util) except: pass - + about = AboutScreen(self.util) about.add_listener(self.go_home) - self.screens = {KEY_ABOUT: about} + self.screens = {KEY_ABOUT : about} self.current_player_screen = None - + self.initial_player_name = self.config[AUDIO][PLAYER_NAME] + self.current_audio_file = None self.current_language = self.config[CURRENT][LANGUAGE] - - if self.config[AUDIO][PLAYER_NAME] == MPD: + + if self.config[AUDIO][PLAYER_NAME] == MPD_NAME: self.start_audio() if self.config[USAGE][USE_VU_METER]: self.util.load_screensaver(VUMETER) else: if self.config[USAGE][USE_VU_METER]: self.util.load_screensaver(VUMETER) - self.start_audio() - + self.start_audio() + if self.voice_assistant: - self.voice_assistant.assistant.add_start_conversation_listener(self.screensaver_dispatcher.handle_event) - + self.voice_assistant.assistant.add_start_conversation_listener(self.screensaver_dispatcher.handle_event) + if self.use_web: self.screensaver_dispatcher.add_start_listener(self.web_server.start_screensaver_to_json) self.screensaver_dispatcher.add_stop_listener(self.web_server.stop_screensaver_to_json) - - self.event_dispatcher = EventDispatcher(self.screensaver_dispatcher, self.util) + + self.event_dispatcher = EventDispatcher(self.screensaver_dispatcher, self.util) self.current_screen = None self.current_mode = self.config[CURRENT][MODE] self.PLAYER_SCREENS = [KEY_STATIONS, STREAM, KEY_PLAY_FILE, KEY_PLAY_CD, KEY_PODCAST_PLAYER] - + if not self.config[CURRENT][MODE] or not self.config[USAGE][USE_AUTO_PLAY]: - self.go_home(None) - elif self.config[CURRENT][MODE] == RADIO: + self.go_home(None) + elif self.config[CURRENT][MODE] == RADIO: self.go_stations() elif self.config[CURRENT][MODE] == AUDIO_FILES: state = State() state.folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER].replace('\\\\', '\\') - state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] + state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] state.url = state.folder + os.sep + state.file_name self.go_file_playback(state) elif self.config[CURRENT][MODE] == STREAM: @@ -181,11 +183,17 @@ class Peppy(object): state.episode_time = self.config[PODCASTS][PODCAST_EPISODE_TIME] state.source = INIT self.go_podcast_player(state) - + elif self.config[CURRENT][MODE] == AIRPLAY: + self.reconfigure_player(SHAIRPORT_SYNC_NAME) + self.go_airplay() + elif self.config[CURRENT][MODE] == SPOTIFY_CONNECT: + self.reconfigure_player(RASPOTIFY_NAME) + self.go_spotify_connect() + self.player_state = PLAYER_RUNNING - self.run_timer_thread = False + self.run_timer_thread = False self.start_timer_thread() - + def check_internet_connectivity(self): """ Exit if Internet is not available after 3 attempts 3 seconds each """ @@ -203,7 +211,7 @@ class Peppy(object): time.sleep(timeout) continue return True - + def is_internet_available(self, timeout): """ Check that Internet is available. The solution was taken from here: https://stackoverflow.com/questions/3764291/checking-network-connection @@ -213,7 +221,7 @@ class Peppy(object): """ google_dns_server = "8.8.8.8" google_dns_server_port = 53 - + try: socket.setdefaulttimeout(timeout) socket.socket(socket.AF_INET, socket.SOCK_STREAM).connect((google_dns_server, google_dns_server_port)) @@ -221,134 +229,142 @@ class Peppy(object): except Exception as e: logging.error("Connection error: {0}".format(e)) return False - + def start_audio(self): """ Starts audio server and client """ + + if self.config[AUDIO][PLAYER_NAME] in self.players.keys(): + self.player = self.players[self.config[AUDIO][PLAYER_NAME]] + if self.player.proxy: + self.player.proxy.start() + return folder = None try: folder = self.config[AUDIO][SERVER_FOLDER] except: pass - - cmd = None + + start_cmd = None try: - cmd = self.config[AUDIO][SERVER_COMMAND] + start_cmd = self.config[AUDIO][SERVER_START_COMMAND] except: pass - + default_cd_drive = self.cdutil.get_default_cd_drive() - if self.config[AUDIO][PLAYER_NAME] == MPLAYER and default_cd_drive: + if self.config[AUDIO][PLAYER_NAME] == MPLAYER_NAME and default_cd_drive: cd_drive_name = default_cd_drive[1] - if ":" in cd_drive_name: # Windows + if ":" in cd_drive_name: # Windows cd_drive_name = cd_drive_name.split(":")[0] + ":" - cmd = cmd + " -cdrom-device " + cd_drive_name - + start_cmd = start_cmd + " -cdrom-device " + cd_drive_name + stream_server_parameters = None try: stream_server_parameters = self.config[AUDIO][STREAM_SERVER_PARAMETERS] except: pass - + if self.config[USAGE][USE_STREAM_SERVER] and stream_server_parameters: - if cmd: - cmd = cmd + " " + stream_server_parameters + if start_cmd: + start_cmd = start_cmd + " " + stream_server_parameters else: - cmd = stream_server_parameters - + start_cmd = stream_server_parameters + stream_client_parameters = None try: stream_client_parameters = self.config[AUDIO][STREAM_CLIENT_PARAMETERS] except: pass - + if stream_client_parameters: - if cmd: - cmd = cmd + " " + stream_client_parameters + if start_cmd: + start_cmd = start_cmd + " " + stream_client_parameters else: - cmd = stream_client_parameters - + start_cmd = stream_client_parameters + client_name = self.config[AUDIO][CLIENT_NAME] linux = self.config[LINUX_PLATFORM] - - proxy = Proxy(linux, folder, cmd, self.config[PLAYER_SETTINGS][VOLUME]) - self.audio_server = proxy.start() + stop_cmd = self.config[AUDIO][SERVER_STOP_COMMAND] + + self.proxy = Proxy(linux, folder, start_cmd, stop_cmd, self.config[PLAYER_SETTINGS][VOLUME]) + self.proxy_process = self.proxy.start() logging.debug("Audio Server Started") - + p = "player.client." + client_name m = importlib.import_module(p) n = client_name.title() - self.player = getattr(m, n)() - self.player.set_platform(linux) - self.player.set_player_mode(self.config[CURRENT][MODE]) - self.player.set_proxy(self.audio_server) - self.player.set_util(self.util) - self.player.start_client() - self.player.cd_track_title = self.config[LABELS][CD_TRACK] - + player = getattr(m, n)() + player.set_platform(linux) + player.set_player_mode(self.config[CURRENT][MODE]) + player.set_proxy(self.proxy_process, self.proxy) + player.set_util(self.util) + player.start_client() + player.cd_track_title = self.config[LABELS][CD_TRACK] + if self.config[PLAYER_SETTINGS][PAUSE]: - self.player.pause() + player.pause() + self.players[self.config[AUDIO][PLAYER_NAME]] = player + self.player = player + def start_timer_thread(self): """ Start timer thread """ - + if not self.config[HOME_NAVIGATOR][TIMER] or self.run_timer_thread: return - + sleep_selected = self.config[TIMER][SLEEP] and len(self.config[TIMER][SLEEP_TIME]) > 0 poweroff_selected = self.config[TIMER][POWEROFF] and len(self.config[TIMER][SLEEP_TIME]) > 0 - wake_up_selected = self.config[TIMER][WAKE_UP] and len(self.config[TIMER][WAKE_UP_TIME]) > 0 - + if not sleep_selected and not poweroff_selected: return - + self.run_timer_thread = True self.timer_thread = Thread(target=self.timer_thread) self.timer_thread.start() - + def timer_thread(self): """ Timer thread function """ - + while self.run_timer_thread: time.sleep(2) - + with self.lock: sleep_selected = self.config[TIMER][SLEEP] poweroff_selected = self.config[TIMER][POWEROFF] - wake_up_selected = self.config[TIMER][WAKE_UP] + wake_up_selected = self.config[TIMER][WAKE_UP] sleep_time = self.config[TIMER][SLEEP_TIME] + "00" wake_up_time = self.config[TIMER][WAKE_UP_TIME] + "00" - + current_time = datetime.now().strftime("%H%M%S") - + if sleep_selected: - if wake_up_selected and self.player_state == PLAYER_SLEEPING and self.is_time_in_range(current_time, - wake_up_time): + if wake_up_selected and self.player_state == PLAYER_SLEEPING and self.is_time_in_range(current_time, wake_up_time): with self.lock: self.player_state = PLAYER_RUNNING - self.wake_up() + self.wake_up() if not self.is_time_in_range(current_time, sleep_time): - continue + continue if self.player_state == PLAYER_RUNNING: - self.sleep() + self.sleep() elif poweroff_selected: if not self.is_time_in_range(current_time, sleep_time): - continue + continue logging.debug("poweroff") self.run_timer_thread = False self.shutdown() - + def is_time_in_range(self, t1, t2): """ Check if provided time (t1) is in range of 4 seconds (t1) - + :param t1: current time :param t2: time to compare to - + :return: True - time in range, False - time out of range """ current_h_m = t1[0:4] current_sec = t1[4:] - + if current_h_m != t2[0:4]: return False @@ -356,10 +372,10 @@ class Peppy(object): return True else: return False - + def sleep(self, state=None): """ Go to sleep mode - + :param state: button state object """ logging.debug("sleep") @@ -368,12 +384,12 @@ class Peppy(object): self.player.stop() if self.screensaver_dispatcher.saver_running: self.screensaver_dispatcher.cancel_screensaver() - self.screensaver_dispatcher.current_delay = 0 + self.screensaver_dispatcher.current_delay = 0 self.go_black() - + def wake_up(self, state=None): """ Wake up from sleep mode - + :param state: button state object """ logging.debug("wake up") @@ -384,49 +400,52 @@ class Peppy(object): self.screensaver_dispatcher.current_delay = self.screensaver_dispatcher.get_delay() if self.use_web: self.web_server.redraw_web_ui() - + def exit_current_screen(self): """ Complete action required to exit screen """ - + with self.lock: cs = self.current_screen if cs and self.screens and self.screens[cs]: self.screens[cs].exit_screen() - + def set_mode(self, state): """ Set current mode (e.g. Radio, Language etc) - + :param state: button state """ self.store_current_track_time(self.current_screen) - + mode = state.genre - + if self.current_mode != mode: self.player.stop() + if self.current_mode == AIRPLAY or self.current_mode == SPOTIFY_CONNECT: + self.reconfigure_player(self.initial_player_name) + self.current_mode = mode self.player.set_player_mode(mode) - - if mode == RADIO: - self.go_stations(state) - elif mode == AUDIO_FILES: - self.go_file_playback(state) - elif mode == STREAM: - self.go_stream(state) - elif mode == AUDIOBOOKS: - self.go_audiobooks(state) - elif mode == CD_PLAYER: - self.go_cd_playback(state) - elif mode == PODCASTS: - self.go_podcast_player(state) - + + if mode == RADIO: self.go_stations(state) + elif mode == AUDIO_FILES: self.go_file_playback(state) + elif mode == STREAM: self.go_stream(state) + elif mode == AUDIOBOOKS: self.go_audiobooks(state) + elif mode == CD_PLAYER: self.go_cd_playback(state) + elif mode == PODCASTS: self.go_podcast_player(state) + elif mode == AIRPLAY: + self.reconfigure_player(SHAIRPORT_SYNC_NAME) + self.go_airplay(state) + elif mode == SPOTIFY_CONNECT: + self.reconfigure_player(RASPOTIFY_NAME) + self.go_spotify_connect(state) + def go_player(self, state): """ Go to the current player screen - + :param state: button state - """ + """ state.source = GO_PLAYER - + if self.current_player_screen == KEY_PLAY_SITE: self.go_site_playback(state) elif self.current_player_screen == KEY_STATIONS: @@ -439,20 +458,24 @@ class Peppy(object): self.go_stream(state) elif self.current_player_screen == KEY_PODCAST_PLAYER: self.go_podcast_player(state) + elif self.current_player_screen == KEY_AIRPLAY_PLAYER: + self.go_airplay(state) + elif self.current_player_screen == KEY_SPOTIFY_CONNECT_PLAYER: + self.go_spotify_connect(state) def go_favorites(self, state): """ Go to the favorites screen - + :param state: button state - """ + """ state.source = KEY_FAVORITES self.go_stations(state) def get_current_screen(self, key, state=None): """ Return current screen by name - + :param key: screen name - """ + """ s = None self.exit_current_screen() try: @@ -465,29 +488,29 @@ class Peppy(object): def add_screen_observers(self, screen): """ Add web obervers to the provided screen - + :param screen: screen for observers """ screen.add_screen_observers(self.web_server.update_web_ui, self.web_server.redraw_web_ui) def go_home(self, state): """ Go to the Home Screen - + :param state: button state - """ + """ if self.get_current_screen(KEY_HOME): return - + listeners = self.get_home_screen_listeners() home_screen = HomeScreen(self.util, listeners, self.voice_assistant) self.screens[KEY_HOME] = home_screen self.set_current_screen(KEY_HOME) - + if self.use_web: self.add_screen_observers(home_screen) - + def go_language(self, state): """ Go to the Language Screen - + :param state: button state """ if self.get_current_screen(LANGUAGE): return @@ -496,13 +519,13 @@ class Peppy(object): language_screen = LanguageScreen(self.util, self.change_language, listeners, self.voice_assistant) self.screens[LANGUAGE] = language_screen self.set_current_screen(LANGUAGE) - + if self.use_web: self.add_screen_observers(language_screen) - + def change_language(self, state): """ Change current language and go to the Home Screen - + :param state: button state """ if state.name != self.config[CURRENT][LANGUAGE]: @@ -513,18 +536,18 @@ class Peppy(object): self.player.remove_player_listener(stations.screen_title.set_text) except KeyError: pass - self.config[CURRENT][LANGUAGE] = state.name + self.config[CURRENT][LANGUAGE] = state.name self.config[LABELS] = self.util.get_labels() self.util.weather_config = self.util.get_weather_config() try: self.screensaver_dispatcher.current_screensaver.set_util(self.util) except: - pass - - self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = "" - self.screens = {k: v for k, v in self.screens.items() if k == KEY_ABOUT} + pass + + self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = "" + self.screens = {k : v for k, v in self.screens.items() if k == KEY_ABOUT} self.current_screen = None - + if self.config[USAGE][USE_VOICE_ASSISTANT]: language = self.util.get_voice_assistant_language_code(state.name) if language: @@ -534,50 +557,51 @@ class Peppy(object): self.voice_assistant = VoiceAssistant(self.util) except: pass + else: + self.voice_assistant.change_language() else: self.voice_assistant.change_language() - + self.go_home(state) self.player.stop() - + def go_file_browser(self, state=None): """ Go to the File Browser Screen - + :param state: button state """ if self.get_current_screen(AUDIO_FILES): return - + file_player = self.screens[KEY_PLAY_FILE] listeners = {} listeners[KEY_HOME] = self.go_home listeners[KEY_PLAY_FILE] = self.go_file_playback listeners[GO_BACK] = file_player.restore_current_folder - - file_browser_screen = FileBrowserScreen(self.util, self.player.get_current_playlist, self.player.load_playlist, - listeners, self.voice_assistant) - + + file_browser_screen = FileBrowserScreen(self.util, self.player.get_current_playlist, self.player.load_playlist, listeners, self.voice_assistant) + file_player.add_play_listener(file_browser_screen.file_menu.select_item) file_player.recursive_notifier = file_browser_screen.file_menu.change_folder - + file_browser_screen.file_menu.add_playlist_size_listener(file_player.set_playlist_size) file_browser_screen.file_menu.add_play_file_listener(file_player.play_button.draw_default_state) - - self.player.add_player_listener(file_browser_screen.file_menu.update_playlist_menu) - + + self.player.add_player_listener(file_browser_screen.file_menu.update_playlist_menu) + self.screens[AUDIO_FILES] = file_browser_screen self.set_current_screen(AUDIO_FILES) - + if self.use_web: self.add_screen_observers(file_browser_screen) def go_cd_drives(self, state=None): """ Go to the CD drives Screen - + :param state: button state """ if self.get_current_screen(KEY_CD_PLAYERS): return - + if self.cdutil.get_cd_drives_number() == 1: self.go_cd_tracks() @@ -588,26 +612,26 @@ class Peppy(object): cd_drives_screen = CdDrivesScreen(self.util, listeners, self.voice_assistant) self.screens[KEY_CD_PLAYERS] = cd_drives_screen self.set_current_screen(KEY_CD_PLAYERS) - + if self.use_web: self.add_screen_observers(cd_drives_screen) - + def go_cd_tracks(self, state=None): """ Go to the CD tracks Screen - + :param state: button state """ - + if self.cdutil.get_cd_drives_number() == 0: return - + try: if self.screens[KEY_CD_TRACKS]: self.set_current_screen(KEY_CD_TRACKS, state=state) return except: pass - + listeners = {} listeners[KEY_HOME] = self.go_home listeners[KEY_PLAYER] = self.go_cd_playback @@ -616,23 +640,23 @@ class Peppy(object): screen = CdTracksScreen(self.util, listeners, self.voice_assistant, state) screen.navigator.eject_button.add_release_listener(self.player.stop) self.screens[KEY_CD_TRACKS] = screen - + file_player = self.screens[KEY_PLAY_CD] screen.navigator.eject_button.add_release_listener(file_player.eject_cd) - self.player.cd_tracks = file_player.audio_files + self.player.cd_tracks = file_player.audio_files file_player.add_play_listener(screen.file_menu.select_item) screen.file_menu.add_playlist_size_listener(file_player.set_playlist_size) - screen.file_menu.add_play_file_listener(file_player.play_button.draw_default_state) - self.player.add_player_listener(screen.file_menu.update_playlist_menu) - + screen.file_menu.add_play_file_listener(file_player.play_button.draw_default_state) + self.player.add_player_listener(screen.file_menu.update_playlist_menu) + self.set_current_screen(KEY_CD_TRACKS, state=state) - + if self.use_web: self.add_screen_observers(screen) - + def go_file_playback(self, state=None): """ Go to the File Player Screen - + :param state: button state """ self.deactivate_current_player(KEY_PLAY_FILE) @@ -648,36 +672,35 @@ class Peppy(object): return except: pass - if getattr(state, "url", None): - tokens = state.url.split(os.sep) + if getattr(state, "url", None): + tokens = state.url.split(os.sep) self.config[FILE_PLAYBACK][CURRENT_FILE] = tokens[len(tokens) - 1] - + listeners = self.get_play_screen_listeners() listeners[AUDIO_FILES] = self.go_file_browser listeners[KEY_SEEK] = self.player.seek - screen = FilePlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, - self.player.stop) + screen = FilePlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, self.player.stop) self.screens[KEY_PLAY_FILE] = screen self.current_player_screen = KEY_PLAY_FILE screen.load_playlist = self.player.load_playlist - + self.player.add_player_listener(screen.screen_title.set_text) self.player.add_player_listener(screen.time_control.set_track_info) self.player.add_player_listener(screen.update_arrow_button_labels) self.player.add_end_of_track_listener(screen.end_of_track) - + screen.add_play_listener(self.screensaver_dispatcher.change_image) screen.add_play_listener(self.screensaver_dispatcher.change_image_folder) - + f = getattr(state, "file_name", None) if f == None and state != None: state.file_name = self.config[FILE_PLAYBACK][CURRENT_FILE] - + self.set_current_screen(KEY_PLAY_FILE, state=state) state = State() state.cover_art_folder = screen.file_button.state.cover_art_folder self.screensaver_dispatcher.change_image_folder(state) - + if self.use_web: update = self.web_server.update_web_ui redraw = self.web_server.redraw_web_ui @@ -690,19 +713,19 @@ class Peppy(object): def go_cd_playback(self, state=None): """ Go to the CD Player Screen - + :param state: button state - """ + """ self.deactivate_current_player(KEY_PLAY_CD) if getattr(state, "file_name", None): - state.url = state.file_name - + state.url = state.file_name + try: cd_player = self.screens[KEY_PLAY_CD] cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] cd_player.audio_files = self.cdutil.get_cd_tracks_summary(cd_drive_name) self.player.cd_tracks = cd_player.audio_files - + if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): self.set_current_screen(KEY_PLAY_CD, True) else: @@ -713,7 +736,7 @@ class Peppy(object): return except: pass - + listeners = self.get_play_screen_listeners() listeners[GO_BACK] = self.go_cd_playback listeners[AUDIO_FILES] = self.go_cd_tracks @@ -722,16 +745,16 @@ class Peppy(object): self.screens[KEY_PLAY_CD] = screen self.current_player_screen = KEY_PLAY_CD screen.load_playlist = self.player.load_playlist - + self.player.cd_tracks = screen.audio_files self.player.add_player_listener(screen.screen_title.set_text) self.player.add_player_listener(screen.time_control.set_track_info) self.player.add_player_listener(screen.update_arrow_button_labels) self.player.add_end_of_track_listener(screen.end_of_track) - + screen.add_play_listener(self.screensaver_dispatcher.change_image) screen.add_play_listener(self.screensaver_dispatcher.change_image_folder) - + if state == None: state = State() state.source = INIT @@ -740,7 +763,7 @@ class Peppy(object): state = State() state.cover_art_folder = screen.file_button.state.cover_art_folder self.screensaver_dispatcher.change_image_folder(state) - + if self.use_web: update = self.web_server.update_web_ui redraw = self.web_server.redraw_web_ui @@ -753,7 +776,7 @@ class Peppy(object): def go_site_playback(self, state=None): """ Go to the Site Player Screen - + :param state: button state """ self.deactivate_current_player(KEY_PLAY_SITE) @@ -764,12 +787,12 @@ class Peppy(object): a = getattr(state, "source", None) if a: s.source = a - else: + else: s.source = INIT - + if getattr(state, BOOK_URL, None): - self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = s.book_url = state.book_url - + self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = s.book_url = state.book_url + try: if self.screens[name]: if state.name == LOYALBOOKS or state.name == AUDIOKNIGI: @@ -784,21 +807,21 @@ class Peppy(object): listeners = self.get_play_screen_listeners() listeners[KEY_SEEK] = self.player.seek - listeners[AUDIO_FILES] = self.go_book_track_screen - + listeners[AUDIO_FILES] = self.go_book_track_screen + if not getattr(state, BOOK_URL, None): self.go_site_news_screen(state) return - + self.config[AUDIOBOOKS][BROWSER_BOOK_URL] = state.book_url self.config[AUDIOBOOKS][BROWSER_BOOK_TITLE] = state.name s = BookPlayer(listeners, self.util, self.get_parser(), self.voice_assistant) - - self.player.add_player_listener(s.time_control.set_track_info) + + self.player.add_player_listener(s.time_control.set_track_info) self.player.add_player_listener(s.update_arrow_button_labels) - self.player.add_end_of_track_listener(s.end_of_track) + self.player.add_end_of_track_listener(s.end_of_track) s.add_play_listener(self.screensaver_dispatcher.change_image) - + if self.use_web: update = self.web_server.update_web_ui redraw = self.web_server.redraw_web_ui @@ -808,19 +831,19 @@ class Peppy(object): s.add_screen_observers(update, redraw, start, stop, title_to_json) self.web_server.add_player_listener(s.time_control) self.player.add_player_listener(self.web_server.update_player_listeners) - + s.name = name self.screens[name] = s self.current_player_screen = KEY_PLAY_SITE - self.set_current_screen(name, state=state) + self.set_current_screen(name, state=state) def go_book_track_screen(self, state): """ Go to the Book Tracks Screen - + :param state: button state """ listeners = self.get_site_navigator_listeners() - self.exit_current_screen() + self.exit_current_screen() name = KEY_BOOK_TRACK_SCREEB try: if self.screens[name]: @@ -828,27 +851,27 @@ class Peppy(object): return except: pass - + d = self.get_book_menu_settings() s = BookTrack(self.util, listeners, self.go_site_playback, self.voice_assistant, d) ps = self.screens[KEY_PLAY_SITE] ps.add_play_listener(s.track_menu.select_track) - + self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) - + def go_site_abc_screen(self, state): """ Go to the Site ABC Screen - + :param state: button state """ if "abc.screen" == self.current_screen: return - - site = self.config[AUDIOBOOKS][BROWSER_SITE] + + site = self.config[AUDIOBOOKS][BROWSER_SITE] name = site + ".author.books" try: if self.screens[name] and self.current_screen != name and self.current_screen != site + ".authors.screen": @@ -858,19 +881,19 @@ class Peppy(object): return except: pass - + name = site + ".authors.screen" try: if self.screens[name] and self.current_screen != name: self.set_current_screen(name, state=state) cs = self.screens[name] - cs.set_current() + cs.set_current() return except: pass - + listeners = self.get_site_navigator_listeners() - self.exit_current_screen() + self.exit_current_screen() name = "abc.screen" try: if self.screens[name]: @@ -878,24 +901,24 @@ class Peppy(object): return except: pass - + d = self.get_book_menu_settings() s = BookAbc(self.util, listeners, self.go_site_authors_screen, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) - + def go_site_authors_screen(self, ch, f=None): """ Go to the Site Authors Screen - + :param ch: selected character :param f: selected filter """ listeners = self.get_site_navigator_listeners() self.exit_current_screen() - site = self.config[AUDIOBOOKS][BROWSER_SITE] + site = self.config[AUDIOBOOKS][BROWSER_SITE] name = site + ".authors.screen" try: if self.screens[name]: @@ -905,66 +928,64 @@ class Peppy(object): return except: pass - + base_url = None - + if site == AUDIOKNIGI: from websiteparser.audioknigi.constants import AUTHOR_URL base_url = AUTHOR_URL - - d = self.get_book_menu_settings() - s = BookAuthor(self.util, listeners, ch, f, self.go_site_books_by_author, self.get_parser(), base_url, - self.voice_assistant, d) + + d = self.get_book_menu_settings() + s = BookAuthor(self.util, listeners, ch, f, self.go_site_books_by_author, self.get_parser(), base_url, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: s.add_loading_listener(self.web_server.redraw_web_ui) - + s.set_current(ch, f) - + if self.use_web: self.add_screen_observers(s) def go_site_books_by_author(self, state): """ Go to the Author Books Screen - + :param state: button state """ listeners = self.get_site_navigator_listeners() - self.exit_current_screen() - site = self.config[AUDIOBOOKS][BROWSER_SITE] + self.exit_current_screen() + site = self.config[AUDIOBOOKS][BROWSER_SITE] name = site + ".author.books" try: if self.screens[name]: self.set_current_screen(name, state=state) cs = self.screens[name] - cs.set_current(state) + cs.set_current(state) return except: pass - + d = self.get_book_menu_settings(show_author=False) parser = self.get_parser() from websiteparser.audioknigi.constants import PAGE_URL_PREFIX parser.news_parser.page_url_prefix = PAGE_URL_PREFIX - s = BookAuthorBooks(self.util, listeners, state.name, self.go_site_playback, state.url, parser, - self.voice_assistant, d) + s = BookAuthorBooks(self.util, listeners, state.name, self.go_site_playback, state.url, parser, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) - + s.turn_page() - + def go_site_news_screen(self, state): """ Go to the Site New Books Screen - + :param state: button state """ listeners = self.get_site_navigator_listeners() - self.exit_current_screen() + self.exit_current_screen() name = self.config[AUDIOBOOKS][BROWSER_SITE] + ".new.books.screen" try: if self.screens[name]: @@ -972,11 +993,11 @@ class Peppy(object): return except: pass - + d = self.get_book_menu_settings() parser = self.get_parser() site = self.config[AUDIOBOOKS][BROWSER_SITE] - + if site == AUDIOKNIGI: from websiteparser.audioknigi.constants import PAGE_URL_PREFIX parser.news_parser.page_url_prefix = PAGE_URL_PREFIX @@ -984,51 +1005,51 @@ class Peppy(object): from websiteparser.loyalbooks.constants import TOP_100 parser.news_parser.page_url_prefix = TOP_100 parser.language_url = d[4] - + s = BookNew(self.util, listeners, self.go_site_playback, parser, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) - + s.turn_page() - + def get_book_menu_settings(self, show_author=True, show_genre=True): """ Return book menu settings for defined parameters - + :param show_author: flag indicating if authors button should be included :param show_genre: flag indicating if genre button should be included """ rows = AUDIOKNIGI_ROWS - columns = AUDIOKNIGI_COLUMNS + columns = AUDIOKNIGI_COLUMNS if self.config[AUDIOBOOKS][BROWSER_SITE] == LOYALBOOKS: from websiteparser.loyalbooks.constants import BOOKS_ROWS, BOOKS_COLUMNS rows = BOOKS_ROWS columns = BOOKS_COLUMNS show_genre = False return [rows, columns, show_author, show_genre, self.get_language_url()] - + def go_site_genre_screen(self, state): """ Go to the Site Genres Screen - + :param state: button state """ site = self.config[AUDIOBOOKS][BROWSER_SITE] - + if site + ".genre.screen" == self.current_screen: return - + name = site + ".genre.books" try: if self.screens[name] and self.current_screen != name: cs = self.screens[name] - cs.set_current(state) + cs.set_current(state) self.set_current_screen(name, state=state) return except: pass - + listeners = self.get_site_navigator_listeners() self.exit_current_screen() name = site + ".genre.screen" @@ -1038,10 +1059,10 @@ class Peppy(object): return except: pass - + constants = None base_url = None - + if site == AUDIOKNIGI: from websiteparser.audioknigi.constants import AUDIOKNIGI_GENRE, SECTION_URL constants = AUDIOKNIGI_GENRE @@ -1050,35 +1071,35 @@ class Peppy(object): from websiteparser.loyalbooks.constants import LOYALBOOKS_GENRE, GENRE_URL constants = LOYALBOOKS_GENRE base_url = GENRE_URL - - d = self.get_book_menu_settings() + + d = self.get_book_menu_settings() s = BookGenre(self.util, listeners, self.go_site_books_by_genre, constants, base_url, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) def go_site_books_by_genre(self, state): """ Go to the Genre Books Screen - + :param state: button state """ listeners = self.get_site_navigator_listeners() - self.exit_current_screen() - site = self.config[AUDIOBOOKS][BROWSER_SITE] + self.exit_current_screen() + site = self.config[AUDIOBOOKS][BROWSER_SITE] name = site + ".genre.books" try: - if self.screens[name]: - self.set_current_screen(name, state=state) + if self.screens[name]: + self.set_current_screen(name, state=state) cs = self.screens[name] - cs.set_current(state) + cs.set_current(state) return except: pass - + parser = self.get_parser() - + if site == AUDIOKNIGI: from websiteparser.audioknigi.constants import SECTION_URL, PAGE_URL_PREFIX parser.genre_books_parser.base_url = SECTION_URL @@ -1087,21 +1108,20 @@ class Peppy(object): from websiteparser.loyalbooks.constants import BASE_URL, PAGE_PREFIX parser.genre_books_parser.base_url = BASE_URL parser.genre_books_parser.page_url_prefix = PAGE_PREFIX - + d = self.get_book_menu_settings(show_genre=False) - s = BookGenreBooks(self.util, listeners, state.name, self.go_site_playback, state.genre, parser, - self.voice_assistant, d) + s = BookGenreBooks(self.util, listeners, state.name, self.go_site_playback, state.genre, parser, self.voice_assistant, d) self.screens[name] = s self.set_current_screen(name) - + if self.use_web: self.add_screen_observers(s) - - s.turn_page() - + + s.turn_page() + def get_site_navigator_listeners(self): """ Return site navigator listeners """ - + listeners = {} listeners[GO_USER_HOME] = self.go_site_abc_screen listeners[GO_ROOT] = self.go_site_news_screen @@ -1109,11 +1129,11 @@ class Peppy(object): listeners[GO_PLAYER] = self.go_player listeners[GO_BACK] = self.go_back listeners[KEY_HOME] = self.go_home - return listeners - + return listeners + def get_home_screen_listeners(self): """ Return home screen listeners """ - + listeners = {} listeners[KEY_MODE] = self.set_mode listeners[KEY_BACK] = self.go_back @@ -1128,7 +1148,7 @@ class Peppy(object): def get_play_screen_listeners(self): """ File player screen listeners getter """ - + listeners = {} listeners[KEY_HOME] = self.go_home listeners[KEY_SHUTDOWN] = self.shutdown @@ -1138,23 +1158,24 @@ class Peppy(object): listeners[KEY_SET_SAVER_VOLUME] = self.screensaver_dispatcher.change_volume listeners[KEY_MUTE] = self.mute listeners[KEY_PLAY] = self.player.play - listeners[KEY_STOP] = self.player.stop + listeners[KEY_STOP] = self.player.stop return listeners - + def go_stream(self, state=None): """ Go to the Stream Screen - + :param state: button state """ self.deactivate_current_player(STREAM) - + if self.get_current_screen(STREAM): return - + listeners = self.get_play_screen_listeners() stream_screen = StationScreen(listeners, self.util, self.voice_assistant, STREAM) self.screens[STREAM] = stream_screen self.set_current_screen(STREAM) - self.screensaver_dispatcher.change_image(stream_screen.station_menu.station_button.state) + if stream_screen.station_menu.station_button: + self.screensaver_dispatcher.change_image(stream_screen.station_menu.station_button.state) stream_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image) stream_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image_folder) self.player.add_player_listener(stream_screen.screen_title.set_text) @@ -1167,22 +1188,22 @@ class Peppy(object): stream_screen.add_screen_observers(update, redraw, title_to_json) self.web_server.station_menu = stream_screen.station_menu stream_screen.station_menu.add_menu_click_listener(self.web_server.station_menu_to_json) - stream_screen.station_menu.add_mode_listener(self.web_server.station_menu_to_json) + stream_screen.station_menu.add_mode_listener(self.web_server.station_menu_to_json) def go_podcasts(self, state=None): """ Go to the Podcasts Screen - + :param state: button state """ if self.get_current_screen(PODCASTS): return - + try: if self.screens[PODCASTS]: self.set_current_screen(PODCASTS, state=state) return except: pass - + listeners = {} listeners[KEY_HOME] = self.go_home listeners[KEY_PLAYER] = self.go_podcast_player @@ -1193,17 +1214,17 @@ class Peppy(object): if self.use_web: self.add_screen_observers(podcasts_screen) self.set_current_screen(PODCASTS) - + def go_podcast_episodes(self, state): """ Go to the podcast episodes screen - + :param state: button state """ url = getattr(state, "podcast_url", None) - + if url != None: self.config[PODCASTS][PODCAST_URL] = url - + try: if self.screens[KEY_PODCAST_EPISODES]: self.set_current_screen(KEY_PODCAST_EPISODES, state=state) @@ -1212,7 +1233,7 @@ class Peppy(object): if state and hasattr(state, "name") and len(state.name) == 0: self.go_podcasts(state) return - + listeners = {} listeners[KEY_HOME] = self.go_home listeners[PODCASTS] = self.go_podcasts @@ -1220,7 +1241,7 @@ class Peppy(object): listeners[KEY_PLAYER] = self.go_podcast_player screen = PodcastEpisodesScreen(self.util, listeners, self.voice_assistant, state) self.screens[KEY_PODCAST_EPISODES] = screen - + podcast_player = self.screens[KEY_PODCAST_PLAYER] podcast_player.add_play_listener(screen.turn_page) if self.use_web: @@ -1229,7 +1250,7 @@ class Peppy(object): def go_podcast_player(self, state): """ Go to the podcast player screen - + :param state: button state """ self.deactivate_current_player(KEY_PODCAST_PLAYER) @@ -1238,43 +1259,42 @@ class Peppy(object): if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): self.set_current_screen(KEY_PODCAST_PLAYER) else: - if getattr(state, "source", None) == None: + if getattr(state, "source", None) == None: state.source = RESUME self.set_current_screen(name=KEY_PODCAST_PLAYER, state=state) self.current_player_screen = KEY_PODCAST_PLAYER return except: pass - + if state.name != PODCASTS: self.config[PODCASTS][PODCAST_EPISODE_NAME] = state.name - + if hasattr(state, "file_name"): self.config[PODCASTS][PODCAST_EPISODE_URL] = state.file_name elif hasattr(state, "url"): self.config[PODCASTS][PODCAST_EPISODE_URL] = state.url - + listeners = self.get_play_screen_listeners() listeners[AUDIO_FILES] = self.go_podcast_episodes listeners[KEY_SEEK] = self.player.seek - screen = PodcastPlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, - self.player.stop) + screen = PodcastPlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, self.player.stop) self.screens[KEY_PODCAST_PLAYER] = screen self.current_player_screen = KEY_PODCAST_PLAYER screen.load_playlist = self.player.load_playlist - + self.player.add_player_listener(screen.time_control.set_track_info) self.player.add_player_listener(screen.update_arrow_button_labels) self.player.add_end_of_track_listener(screen.end_of_track) - + screen.add_play_listener(self.screensaver_dispatcher.change_image) screen.add_play_listener(self.screensaver_dispatcher.change_image_folder) - + self.set_current_screen(KEY_PODCAST_PLAYER, state=state) state = State() state.cover_art_folder = screen.file_button.state.cover_art_folder self.screensaver_dispatcher.change_image_folder(state) - + if self.use_web: update = self.web_server.update_web_ui redraw = self.web_server.redraw_web_ui @@ -1285,31 +1305,31 @@ class Peppy(object): screen.add_loading_listener(redraw) self.web_server.add_player_listener(screen.time_control) self.player.add_player_listener(self.web_server.update_player_listeners) - + def go_audiobooks(self, state=None): """ Go to the Audiobooks Screen - + :param state: button state """ listeners = self.get_play_screen_listeners() - listeners[KEY_SEEK] = self.player.seek + listeners[KEY_SEEK] = self.player.seek self.exit_current_screen() s = State() s.source = INIT s.book_url = self.config[AUDIOBOOKS][BROWSER_BOOK_URL] - + if self.config[CURRENT][LANGUAGE] == RUSSIAN: s.name = AUDIOKNIGI else: s.name = LOYALBOOKS - + s.language_url = self.get_language_url() self.config[AUDIOBOOKS][BROWSER_SITE] = s.name site_player = None - + state = State() self.screensaver_dispatcher.change_image_folder(state) - + try: site_player = self.screens[KEY_PLAY_SITE] s.source = RESUME @@ -1317,29 +1337,168 @@ class Peppy(object): s.file_name = self.config[AUDIOBOOKS][BROWSER_TRACK_FILENAME] except: pass - + if not self.config[AUDIOBOOKS][BROWSER_BOOK_URL]: self.go_site_news_screen(s) else: self.go_site_playback(s) + + def go_airplay(self, state=None): + """ Go airplay screen - def go_equalizer(self, state=None): - """ Go to the Equalizer Screen + :param state: button state + """ + self.deactivate_current_player(KEY_AIRPLAY_PLAYER) + try: + if self.screens[KEY_AIRPLAY_PLAYER]: + self.player.add_player_listener(self.screens[KEY_AIRPLAY_PLAYER].handle_metadata) + if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): + self.set_current_screen(KEY_AIRPLAY_PLAYER) + else: + if getattr(state, "source", None) == None: + state.source = RESUME + self.set_current_screen(name=KEY_AIRPLAY_PLAYER, state=state) + self.current_player_screen = KEY_AIRPLAY_PLAYER + return + except: + pass + + listeners = self.get_play_screen_listeners() + next = getattr(self.player, "next", None) + previous = getattr(self.player, "previous", None) + screen = AirplayPlayerScreen(listeners, self.util, self.player.get_current_playlist, self.voice_assistant, self.player.stop, next, previous) + self.player.add_player_listener(screen.handle_metadata) + screen.play_button.add_listener("pause", self.player.pause) + screen.play_button.add_listener("play", self.player.play) + + self.screens[KEY_AIRPLAY_PLAYER] = screen + self.set_current_screen(KEY_AIRPLAY_PLAYER, state=state) + + if self.use_web: + update = self.web_server.update_web_ui + redraw = self.web_server.redraw_web_ui + title_to_json = self.web_server.title_to_json + screen.add_screen_observers(update, redraw, None, None, title_to_json) + screen.add_loading_listener(redraw) + self.player.add_player_listener(self.web_server.update_player_listeners) + + screen.time_volume_button.start_listeners = [] + screen.time_volume_button.label_listeners = [] + screen.time_volume_button.press_listeners = [] + screen.time_volume_button.release_listeners = [] + + screen.file_button.label_listeners = [] + screen.file_button.press_listeners = [] + screen.file_button.release_listeners = [] + + def go_spotify_connect(self, state=None): + """ Go spotify connect screen :param state: button state """ - if self.get_current_screen(EQUALIZER): return + self.deactivate_current_player(KEY_SPOTIFY_CONNECT_PLAYER) + try: + if self.screens[KEY_SPOTIFY_CONNECT_PLAYER]: + if getattr(state, "name", None) and (state.name == KEY_HOME or state.name == KEY_BACK): + self.set_current_screen(KEY_SPOTIFY_CONNECT_PLAYER) + else: + if getattr(state, "source", None) == None: + state.source = RESUME + self.set_current_screen(name=KEY_SPOTIFY_CONNECT_PLAYER, state=state) + self.current_player_screen = KEY_SPOTIFY_CONNECT_PLAYER + return + except: + pass + listeners = {} + listeners[KEY_HOME] = self.go_home + listeners[KEY_SHUTDOWN] = self.shutdown + screen = SpotifyConnectScreen(listeners, self.util, self.voice_assistant) + self.screens[KEY_SPOTIFY_CONNECT_PLAYER] = screen + self.set_current_screen(KEY_SPOTIFY_CONNECT_PLAYER, state=state) + + if self.use_web: + update = self.web_server.update_web_ui + redraw = self.web_server.redraw_web_ui + screen.add_screen_observers(update, redraw, None, None, None) + screen.add_loading_listener(redraw) + self.player.add_player_listener(self.web_server.update_player_listeners) + + screen.play_button.start_listeners = [] + screen.play_button.press_listeners = [] + screen.play_button.release_listeners = [] + + screen.time_volume_button.start_listeners = [] + screen.time_volume_button.label_listeners = [] + screen.time_volume_button.press_listeners = [] + screen.time_volume_button.release_listeners = [] + + screen.left_button.label_listeners = [] + screen.left_button.press_listeners = [] + screen.left_button.release_listeners = [] + + screen.right_button.label_listeners = [] + screen.right_button.press_listeners = [] + screen.right_button.release_listeners = [] + + screen.file_button.label_listeners = [] + screen.file_button.press_listeners = [] + screen.file_button.release_listeners = [] + + def reconfigure_player(self, new_player_name): + if self.player.proxy.stop_command: + self.player.proxy.stop() + + if self.config[LINUX_PLATFORM]: + platform = "linux" + else: + platform = "windows" + + key = new_player_name + "." + platform + + if key not in self.config[PLAYERS].keys(): + return + + player_config = self.config[PLAYERS][key] + + self.config[AUDIO][PLAYER_NAME] = new_player_name + self.config[AUDIO][SERVER_START_COMMAND] = player_config[SERVER_START_COMMAND] + self.config[AUDIO][CLIENT_NAME] = player_config[CLIENT_NAME] + + try: + self.config[AUDIO][STREAM_SERVER_PARAMETERS] = player_config[STREAM_SERVER_PARAMETERS] + except: + self.config[AUDIO][STREAM_SERVER_PARAMETERS] = None + + try: + self.config[AUDIO][STREAM_CLIENT_PARAMETERS] = player_config[STREAM_CLIENT_PARAMETERS] + except: + self.config[AUDIO][STREAM_CLIENT_PARAMETERS] = None + + try: + self.config[AUDIO][SERVER_STOP_COMMAND] = player_config[SERVER_STOP_COMMAND] + except: + self.config[AUDIO][SERVER_STOP_COMMAND] = None + + self.start_audio() + + def go_equalizer(self, state=None): + """ Go to the Equalizer Screen + + :param state: button state + """ + if self.get_current_screen(EQUALIZER): return + listeners = {} listeners[KEY_HOME] = self.go_home listeners[KEY_PLAYER] = self.go_player equalizer_screen = EqualizerScreen(self.util, listeners, self.voice_assistant) self.screens[EQUALIZER] = equalizer_screen self.set_current_screen(EQUALIZER) - + if self.use_web: self.add_screen_observers(equalizer_screen) - + def go_timer(self, state=None): """ Go to the Timer Screen @@ -1426,22 +1585,22 @@ class Peppy(object): def get_language_url(self): """ Return language URL constant for current language """ - + language = self.config[CURRENT][LANGUAGE] - + if language == ENGLISH_USA: return "" elif language == RUSSIAN: return None else: return LANGUAGE_PREFIX + language + os.sep - + def get_parser(self): """ Return site parser for the current site """ - + name = self.config[AUDIOBOOKS][BROWSER_SITE] - if name == LOYALBOOKS: - return LoyalBooksParser() + if name == LOYALBOOKS: + return LoyalBooksParser() elif name == AUDIOKNIGI: return AudioKnigiParser() return None @@ -1455,73 +1614,74 @@ class Peppy(object): def go_savers(self, state): """ Go to the Screensavers Screen - + :param state: button state """ if self.get_current_screen(SCREENSAVER): return - + listeners = {KEY_HOME: self.go_home, KEY_PLAYER: self.go_player, KEY_START_SAVER: self.start_saver} saver_screen = SaverScreen(self.util, listeners, self.voice_assistant) saver_screen.saver_menu.add_listener(self.screensaver_dispatcher.change_saver_type) saver_screen.delay_menu.add_listener(self.screensaver_dispatcher.change_saver_delay) self.screens[SCREENSAVER] = saver_screen self.set_current_screen(SCREENSAVER) - + if self.use_web: self.add_screen_observers(saver_screen) - + def go_about(self, state): """ Go to the About Screen - + :param state: button state """ self.exit_current_screen() self.set_current_screen(KEY_ABOUT) if self.use_web: self.add_screen_observers(self.screens[KEY_ABOUT]) - + def go_black(self): """ Go to the Black Screen for sleeping mode - + :param state: button state """ self.exit_current_screen() - + try: - self.screens[KEY_BLACK] + self.screens[KEY_BLACK] except: black = BlackScreen(self.util) black.add_listener(self.wake_up) self.screens[KEY_BLACK] = black - + self.set_current_screen(KEY_BLACK) if self.use_web: self.web_server.redraw_web_ui() - + def go_stations(self, state=None): """ Go to the Stations Screen - + :param state: button state """ self.deactivate_current_player(KEY_STATIONS) - + if self.get_current_screen(KEY_STATIONS, state): return - + listeners = self.get_play_screen_listeners() listeners[KEY_GENRES] = self.go_genres station_screen = StationScreen(listeners, self.util, self.voice_assistant) self.screens[KEY_STATIONS] = station_screen self.set_current_screen(KEY_STATIONS) - self.screensaver_dispatcher.change_image(station_screen.station_menu.station_button.state) - station_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image) - station_screen.station_menu.add_change_logo_listener(self.screensaver_dispatcher.change_image) + if station_screen.station_menu.station_button: + self.screensaver_dispatcher.change_image(station_screen.station_menu.station_button.state) + station_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image) + station_screen.station_menu.add_change_logo_listener(self.screensaver_dispatcher.change_image) station_screen.station_menu.add_listener(self.screensaver_dispatcher.change_image_folder) self.player.add_player_listener(station_screen.screen_title.set_text) station_screen.station_menu.add_listener(station_screen.play_button.draw_default_state) - + if self.config[USAGE][USE_ALBUM_ART]: - self.player.add_player_listener(station_screen.station_menu.show_album_art) - + self.player.add_player_listener(station_screen.station_menu.show_album_art) + if self.use_web: update = self.web_server.update_web_ui redraw = self.web_server.redraw_web_ui @@ -1530,41 +1690,40 @@ class Peppy(object): self.web_server.station_menu = station_screen.station_menu station_screen.station_menu.add_menu_click_listener(self.web_server.station_menu_to_json) station_screen.station_menu.add_mode_listener(self.web_server.station_menu_to_json) - + def set_config_volume(self, volume): """ Listener for volume change events - + :param volume: new volume value """ self.config[PLAYER_SETTINGS][VOLUME] = str(int(volume.position)) - + def go_genres(self, state): """ Go to the Genre Screen - + :param state: button state """ if self.get_current_screen(KEY_GENRES): return - - listeners = {KEY_GENRE: self.go_stations, KEY_HOME: self.go_home, KEY_PLAYER: self.go_player, - KEY_FAVORITES: self.go_favorites} + + listeners = {KEY_GENRE: self.go_stations, KEY_HOME: self.go_home, KEY_PLAYER: self.go_player, KEY_FAVORITES: self.go_favorites} genre_screen = RadioGroupScreen(self.util, listeners, self.voice_assistant) self.screens[KEY_GENRES] = genre_screen self.set_current_screen(KEY_GENRES) - + if self.use_web: self.add_screen_observers(genre_screen) - + def play_pause(self, state=None): """ Handle Play/Pause - + :param state: button state """ self.config[PLAYER_SETTINGS][PAUSE] = not self.config[PLAYER_SETTINGS][PAUSE] self.player.play_pause(self.config[PLAYER_SETTINGS][PAUSE]) - + def set_current_screen(self, name, go_back=False, state=None): """ Set current screen defined by its name - + :param name: screen name """ with self.lock: @@ -1575,9 +1734,9 @@ class Peppy(object): self.current_screen = name cs = self.screens[self.current_screen] p = getattr(cs, "player_screen", None) - if p: + if p: cs.enable_player_screen(True) - + cs.set_visible(True) if go_back: cs.go_back() @@ -1594,19 +1753,19 @@ class Peppy(object): cs.set_current(state=state) elif name == KEY_PLAY_FILE: f = getattr(state, "file_name", None) - if f and self.current_audio_file != state.file_name or self.current_player_screen != name: + if f or self.current_player_screen != name: a = getattr(state, "file_name", None) - if a != None: - self.current_audio_file = a + if a != None: + self.current_audio_file = a cs.set_current(state=state) elif name == KEY_PLAY_CD: cd_drive_name = self.config[CD_PLAYBACK][CD_DRIVE_NAME] if self.cdutil.get_cd_drive_id_by_name(cd_drive_name) != None: - file_name = getattr(state, "file_name", None) + file_name = getattr(state, "file_name", None) if file_name and file_name.startswith("cdda:"): state.url = state.file_name parts = state.url.split() - cd_track_id = parts[1].split("=")[1] + cd_track_id = parts[1].split("=")[1] self.config[CD_PLAYBACK][CD_TRACK] = int(cd_track_id) if cs.cd_album != None: state.album = cs.cd_album @@ -1616,12 +1775,11 @@ class Peppy(object): if s and s.file_name: if state != None and getattr(state, "source", None) != None: s.source = state.source - + if cs.cd_album != None: s.album = cs.cd_album cd_track_id = int(s.file_name.split("=")[1]) - if cd_track_id != self.config[CD_PLAYBACK][ - CD_TRACK] or self.current_player_screen != name: + if cd_track_id != self.config[CD_PLAYBACK][CD_TRACK] or self.current_player_screen != name: cs.set_current(state=s) elif name.endswith(KEY_BOOK_SCREEN): if state: @@ -1634,7 +1792,8 @@ class Peppy(object): state.playlist = ps.get_playlist() state.current_track_index = ps.current_track_index cs.set_current(state) - elif name == KEY_CD_TRACKS or name == PODCASTS or name == KEY_PODCAST_EPISODES or name == WIFI or name == NETWORK: + elif (name == KEY_CD_TRACKS or name == PODCASTS or name == KEY_PODCAST_EPISODES or + name == WIFI or name == NETWORK or name == KEY_ABOUT): cs.set_current(state) elif name == KEY_PODCAST_PLAYER: f = getattr(state, "file_name", None) @@ -1645,12 +1804,11 @@ class Peppy(object): cs.set_current(state=state, new_track=True) elif source == RESUME: s = State() - s.name = self.config[PODCASTS][PODCAST_EPISODE_NAME] + s.name = self.config[PODCASTS][PODCAST_EPISODE_NAME] s.url = self.config[PODCASTS][PODCAST_EPISODE_URL] s.podcast_url = self.config[PODCASTS][PODCAST_URL] podcasts_util = self.util.get_podcasts_util() - s.podcast_image_url = podcasts_util.summary_cache[s.podcast_url].episodes[ - 0].podcast_image_url + s.podcast_image_url = podcasts_util.summary_cache[s.podcast_url].episodes[0].podcast_image_url s.status = podcasts_util.get_episode_status(s.podcast_url, s.url) if self.util.connected_to_internet: s.online = True @@ -1662,75 +1820,75 @@ class Peppy(object): else: source = getattr(state, "source", None) if source == RESUME: - cs.start_timer() + cs.start_timer() cs.clean_draw_update() self.event_dispatcher.set_current_screen(cs) self.set_volume() - - if p: + + if p: self.current_player_screen = name - + def go_back(self, state): """ Go to the previous screen - + :param state: button state """ if not self.previous_screen_name: return - + cs = self.screens[self.current_screen] cs.exit_screen() self.set_current_screen(self.previous_screen_name, state=state) - + def set_volume(self, volume=None): """ Set volume """ - + cs = self.screens[self.current_screen] - player_screen = getattr(cs, "player_screen", None) - if player_screen and not cs.volume.selected: - if volume == None: + player_screen = getattr(cs, "player_screen", None) + if player_screen and not cs.volume.selected: + if volume == None: config_volume = int(self.config[PLAYER_SETTINGS][VOLUME]) else: config_volume = volume.position - + if self.player.get_volume() != config_volume: self.player.set_volume(config_volume) - + def mute(self): """ Mute """ self.config[PLAYER_SETTINGS][MUTE] = not self.config[PLAYER_SETTINGS][MUTE] self.player.mute() - + def deactivate_current_player(self, new_player_screen_name): """ Disable current player - + :param new_player_screen_name: new player screen name """ for scr in self.screens.items(): p = getattr(scr[1], "player_screen", None) - if not p: + if not p: continue scr[1].enable_player_screen(False) - + self.exit_current_screen() - + if new_player_screen_name == self.current_player_screen: return - + with self.lock: try: s = self.screens[self.current_player_screen] s.stop_timer() except: pass - + self.player.cd_tracks = None - + def store_current_track_time(self, mode): """ Save current track time in configuration object - - :param mode: + + :param mode: """ k = None if self.current_player_screen == KEY_PLAY_FILE: @@ -1741,8 +1899,8 @@ class Peppy(object): k = KEY_PLAY_CD elif self.current_player_screen == KEY_PODCAST_PLAYER: k = KEY_PODCAST_PLAYER - - if k and k in self.screens: + + if k and k in self.screens: s = self.screens[k] tc = s.time_control t = tc.seek_time @@ -1787,6 +1945,10 @@ class Peppy(object): title_screen_name = KEY_PLAY_SITE elif self.config[CURRENT][MODE] == CD_PLAYER: title_screen_name = KEY_PLAY_CD + elif self.config[CURRENT][MODE] == AIRPLAY: + self.player.proxy.stop() + elif self.config[CURRENT][MODE] == SPOTIFY_CONNECT: + self.player.proxy.stop() if title_screen_name: try: @@ -1814,6 +1976,8 @@ class Peppy(object): if self.config[LINUX_PLATFORM]: if self.config[USAGE][USE_POWEROFF]: subprocess.call("sudo poweroff", shell=True) + else: + os._exit(0) else: self.shutdown_windows() @@ -1830,20 +1994,18 @@ class Peppy(object): def shutdown_windows(self): """ Shutdown Windows player """ - if self.config[AUDIO][PLAYER_NAME] == MPD: + if self.config[AUDIO][PLAYER_NAME] == MPD_NAME: try: - Popen("taskkill /F /T /PID {pid}".format(pid=self.audio_server.pid)) + Popen("taskkill /F /T /PID {pid}".format(pid=self.proxy_process.pid)) except: pass os._exit(0) - def main(): """ Main method """ - + peppy = Peppy() - peppy.event_dispatcher.dispatch(peppy.player, peppy.shutdown) - - + peppy.event_dispatcher.dispatch(peppy.player, peppy.shutdown) + if __name__ == "__main__": main() diff --git a/player/client/baseplayer.py b/player/client/baseplayer.py index bae6aa9e..51d5fcb3 100644 --- a/player/client/baseplayer.py +++ b/player/client/baseplayer.py @@ -45,6 +45,7 @@ def __init__(self): self.file_util = None self.util = None self.state = None + self.enabled = True def set_util(self, util): """ Utility setter @@ -141,7 +142,7 @@ def get_seconds_from_string(self, s): return result; def encode_url(self, url): - """ Encode URL using ascii incoding. If doesn't work use UTF-8 encoding + """ Encode URL using ascii encoding. If doesn't work use UTF-8 encoding :param url: input URL :return: encoded URL @@ -203,6 +204,9 @@ def notify_volume_listeners(self, volume): :param volume: new volume level """ + if not self.enabled: + return + for listener in self.volume_listeners: listener(volume) @@ -211,6 +215,8 @@ def notify_player_listeners(self, status): :param status: player status """ + if not self.enabled: + return for listener in self.player_listeners: listener(status) @@ -236,11 +242,14 @@ def notify_end_of_track_listeners(self, args=None): """ Notify end of track listeners :param args: arguments - """ + """ + if not self.enabled: + return + for listener in self.end_of_track_listeners: listener() def resume_playback(self): """ Resume stopped playback """ - self.play(self.state) + self.play() diff --git a/player/client/mpdsocket.py b/player/client/mpdsocket.py index 60b66300..2ff9e38c 100644 --- a/player/client/mpdsocket.py +++ b/player/client/mpdsocket.py @@ -45,7 +45,7 @@ def __init__(self): self.dont_parse_track_name = False self.current_volume_level = "-1" - def set_proxy(self, proxy): + def set_proxy(self, proxy_process, proxy=None): """ mpd socket client doesn't use proxy """ pass @@ -307,7 +307,8 @@ def get_track_time(self, state): def stop(self, state=None): """ Stop playback """ - self.conn.command(STOP) + if self.conn: + self.conn.command(STOP) def seek(self, time): """ Jump to the specified position in the track diff --git a/player/client/mplayer.py b/player/client/mplayer.py index 3212a23b..1e88be99 100644 --- a/player/client/mplayer.py +++ b/player/client/mplayer.py @@ -42,12 +42,12 @@ def __init__(self): self.current_track_time = None self.current_track_length = None - def set_proxy(self, proxy): + def set_proxy(self, proxy_process, proxy=None): """ Set proxy process. :param proxy: reference to the proxy process """ - self.proxy = proxy + self.proxy = proxy_process def start_client(self): """ This method starts reader and notification threads """ diff --git a/player/client/player.py b/player/client/player.py index d2c50524..c5c99515 100644 --- a/player/client/player.py +++ b/player/client/player.py @@ -207,4 +207,4 @@ def notify_end_of_track_listeners(self, args=None): def resume_playback(self): """ Resume stopped playback """ - pass \ No newline at end of file + pass diff --git a/player/client/raspotify.py b/player/client/raspotify.py new file mode 100644 index 00000000..0b532978 --- /dev/null +++ b/player/client/raspotify.py @@ -0,0 +1,65 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +from player.client.baseplayer import BasePlayer + +class Raspotify(BasePlayer): + """ This class provides raspotify client functionality. """ + + def __init__(self): + """ Initializer """ + + BasePlayer.__init__(self); + self.proxy = None + + def set_proxy(self, proxy_process, proxy=None): + """ Set proxy process. + + :param proxy: reference to the proxy process + """ + self.proxy = proxy + + def start_client(self): + """ There is no separate spotify connect client. """ + + pass + + def shutdown(self): + """ Shutdown the player """ + + pass + + def get_current_track_time(self): + """ Start getting current track time command + + :return: track time in seconds + """ + pass + + def seek(self, time): + """ Set current track time + + :param time: new track time in seconds + """ + pass + + def get_current_playlist(self): + """ Return current playlist + + :return: current playlist + """ + pass diff --git a/player/client/shairport.py b/player/client/shairport.py new file mode 100644 index 00000000..068b7291 --- /dev/null +++ b/player/client/shairport.py @@ -0,0 +1,130 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +import logging + +from player.client.baseplayer import BasePlayer +from player.client.shairportpipe import ShairportPipeConnector +from player.client.shairportdbus import ShairportDbusConnector + +class Shairport(BasePlayer): + """ This class provides shairport-sync client functionality. + It reads metadata from the named pipe and issues commands using D-bus + """ + + def __init__(self): + """ Initializer """ + + BasePlayer.__init__(self); + self.proxy = None + self.muted = False + self.file_playback = False + self.current_title = None + self.UTF8 = "UTF-8" + self.current_track_time = None + self.current_track_length = None + self.connector_pipe = None + self.connector_dbus = None + + def set_proxy(self, proxy_process, proxy=None): + """ Set proxy process. + + :param proxy: reference to the proxy process + """ + self.proxy = proxy + + def start_client(self): + """ This method starts metadata reader thread """ + + self.connector_pipe = ShairportPipeConnector(self.util, self.notify_player_listeners) + self.connector_pipe.start_metadata_reader() + self.connector_dbus = ShairportDbusConnector(self.util, self.notify_player_listeners) + + def next(self): + """ Next track """ + + self.connector_dbus.next() + + def previous(self): + """ Previous track """ + + self.connector_dbus.previous() + + def get_volume(self): + """ Get Volume """ + + pass + + def set_volume(self, level): + """ Set volume level + + :param level: new volume level in range 0-100 + """ + self.connector_pipe.enable_volume_callback = False + self.connector_dbus.set_volume(int(level)) + + def mute(self): + """ Mute """ + + self.connector_dbus.mute() + + def play(self): + """ Play """ + + self.connector_dbus.play() + + def pause(self): + """ Pause """ + + self.connector_dbus.pause() + + def play_pause(self, pause_flag=None): + """ Play/pause """ + + self.connector_dbus.play_pause(pause_flag) + + def stop(self, source=None): + """ Stop playback """ + + self.connector_dbus.pause() + + def shutdown(self): + """ Shutdown the player """ + + self.playing = False + self.connector_pipe.stop_metadata_reader() + + def get_current_track_time(self): + """ Start getting current track time command + + :return: track time in seconds + """ + pass + + def seek(self, time): + """ Set current track time + + :param time: new track time in seconds + """ + pass + + def get_current_playlist(self): + """ Return current playlist + + :return: current playlist + """ + pass diff --git a/player/client/shairportdbus.py b/player/client/shairportdbus.py new file mode 100644 index 00000000..b206d1f7 --- /dev/null +++ b/player/client/shairportdbus.py @@ -0,0 +1,162 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +import dbus +import logging +import time + +from threading import Thread +from dbus.mainloop.glib import DBusGMainLoop +DBusGMainLoop(set_as_default=True) +from gi.repository import GLib + +REMOTE_CONTROL_NAME = "org.gnome.ShairportSync.RemoteControl" +ADVANCED_REMOTE_CONTROL_NAME = "org.gnome.ShairportSync.AdvancedRemoteControl" +SHAIRPORT_SYNC_NAME = "org.gnome.ShairportSync" +SHAIRPORT_SYNC_PATH = "/org/gnome/ShairportSync" +DBUS_PROPERTIES = "org.freedesktop.DBus.Properties" +VOLUME_PROPERTY = "AirplayVolume" +PLAYER_STATE_PROPERTY = "PlayerState" +PLAYER_STATE_NA = "Not Available" +PLAYER_STATE_STOPPED = "Stopped" +PLAYER_STATE_PAUSED = "Paused" +PLAYER_STATE_PLAYING = "Playing" + +class ShairportDbusConnector(object): + """ This class provides dbus metadata reader and commander for shairport-sync. """ + + def __init__(self, util, notify_player_listeners): + """ Initializer + + :param util: utility functions + :param notify_player_listeners: player callback + """ + self.util = util + self.notify_player_listeners = notify_player_listeners + self.loop = GLib.MainLoop() + self.bus = dbus.SystemBus() + self.init_dbus_proxy() + self.init_dbus_properties() + + def init_dbus_proxy(self): + """ Initialize dbus proxy object """ + + attempts = 5 + timeout = 1 + self.proxy = None + + for n in range(attempts): + try: + self.proxy = self.bus.get_object(SHAIRPORT_SYNC_NAME, SHAIRPORT_SYNC_PATH) + except Exception as e: + logging.debug(e) + if self.proxy: + break + else: + if n == (attempts - 1): + return + else: + time.sleep(timeout) + continue + + def init_dbus_properties(self): + """ Initialize dbus properties object """ + + self.remote_control = None + self.dbus_properties = None + if self.proxy: + self.remote_control = dbus.Interface(self.proxy, dbus_interface=REMOTE_CONTROL_NAME) + self.dbus_properties = dbus.Interface(self.remote_control, DBUS_PROPERTIES) + + def get_dbus_prop(self, prop): + """ Get dbus property defined by name + + :param prop: property name + + :return: property value + """ + state = None + attempts = 2 + for _ in range(attempts): + try: + state = self.dbus_properties.Get(REMOTE_CONTROL_NAME, prop) + except Exception as e: + logging.debug(e) + self.init_dbus_proxy() + self.init_dbus_properties() + continue + else: + break + return state + + def play_pause(self, flag): + """ Play/pause + + :param flag: True - pause, False - play + """ + state = self.get_dbus_prop(PLAYER_STATE_PROPERTY) + if flag and state == PLAYER_STATE_PLAYING: + self.remote_control.Pause() + elif not flag and (state == PLAYER_STATE_STOPPED or state == PLAYER_STATE_PAUSED): + self.remote_control.Play() + + def play(self): + """ Play """ + + self.remote_control.Play() + + def pause(self): + """ Pause """ + + self.remote_control.Pause() + + def next(self): + """ Next track """ + + self.remote_control.Next() + + def previous(self): + """ Previous track """ + + self.remote_control.Previous() + + def set_volume(self, level): + """ Set volume level + + :param level: volume in range 0-100 + """ + old = self.get_dbus_prop(VOLUME_PROPERTY) + if old == None: + return + + if old == 0.0: + old = -30 + new = -(30 - (level * (30 / 100))) # convert from 0-100 range to -30-0 + + if abs(old) > abs(new): + steps = round((abs(old) - abs(new)) / 2.0) + for _ in range(steps): + self.remote_control.VolumeUp() + elif abs(old) < abs(new): + steps = round((abs(new) - abs(old)) / 2.0) + for _ in range(steps): + self.remote_control.VolumeDown() + + def mute(self): + """ Mute """ + + pass diff --git a/player/client/shairportpipe.py b/player/client/shairportpipe.py new file mode 100644 index 00000000..93cf51b9 --- /dev/null +++ b/player/client/shairportpipe.py @@ -0,0 +1,200 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +import logging +import base64 +import pygame +from io import BytesIO +import binascii +import re +import math + +from threading import Thread + +UTF8 = "utf-8" +ASCII = "ascii" +ITEM_START = "" +CODE_ARTIST = "asar" +CODE_TRACK_TITLE = "minm" +CODE_METADATA_END = "mden" +CODE_PLAYBACK_END = "pend" +CODE_PLAYBACK_BEGIN = "pbeg" +CODE_PLAYBACK_RESUME = "prsm" +CODE_VOLUME = "pvol" +CODE_PICTURE = "PICT" +VALID_CODES = [ + CODE_METADATA_END, + CODE_VOLUME, + CODE_ARTIST, + CODE_TRACK_TITLE, + CODE_PICTURE +] +PLAYBACK_CODES = [ + CODE_PLAYBACK_END, + CODE_PLAYBACK_BEGIN, + CODE_PLAYBACK_RESUME, +] + +METADATA_PIPE = "/tmp/shairport-sync-metadata" + +class ShairportPipeConnector(object): + """ Implements named pipe metadata reader for shairport-sync. """ + + def __init__(self, util, notify_player_listeners): + """ Initializer + + :param util: utility functions + :param notify_player_listeners: player callback + """ + self.util = util + self.notify_player_listeners = notify_player_listeners + self.metadata_reader_running = False + self.enable_volume_callback = True + self.item_re = r"(([A-Fa-f0-9]{2}){4})(([A-Fa-f0-9]{2}){4})(\d*)" + self.metadata = {} + + def start_metadata_reader(self): + """ Start metadata reader """ + + self.metadata_reader_running = True + metadata_thread = Thread(target=self.metadata_reader) + metadata_thread.start() + + def stop_metadata_reader(self): + """ Stop metadata reader """ + + self.metadata_reader_running = False + + def metadata_reader(self): + """ Thread method to read shairport-sync metadata from the named pipe """ + + metadata = {} + with open(METADATA_PIPE) as pipe: + while self.metadata_reader_running: + line = pipe.readline() + if not line.startswith(ITEM_START): + continue + + matches = re.findall(self.item_re, line) + item_code = str(binascii.unhexlify(matches[0][2]), ASCII) + item_length = int(matches[0][4]) + + if item_code in PLAYBACK_CODES: + self.trigger_playback_event(item_code) + continue + elif item_code not in VALID_CODES: + continue + + line = pipe.readline() + if not line.startswith(" 1 and (p == VLC or p == MPD) + show_drives = connected_cd_drives > 1 and (p == VLC_NAME or p == MPD_NAME) if show_drives: layout.set_pixel_constraints(1, 5, 1, 0) diff --git a/ui/menu/filemenu.py b/ui/menu/filemenu.py index 90d3f008..882aed85 100644 --- a/ui/menu/filemenu.py +++ b/ui/menu/filemenu.py @@ -22,7 +22,7 @@ from ui.state import State from ui.page import Page from ui.factory import Factory -from ui.menu.menu import Menu, ALIGN_MIDDLE +from ui.menu.menu import Menu, ALIGN_CENTER from util.keys import kbd_keys, USER_EVENT_TYPE, SUB_TYPE_KEYBOARD, KEY_LEFT, KEY_RIGHT, \ KEY_UP, KEY_DOWN, KEY_SELECT from util.fileutil import FOLDER, FOLDER_WITH_ICON, FILE_PLAYLIST, FILE_AUDIO, FILE_RECURSIVE @@ -34,7 +34,7 @@ class FileMenu(Menu): """ File Menu class. Extends base Menu class """ - def __init__(self, filelist, util, playlist_provider, bgr=None, bounding_box=None, align=ALIGN_MIDDLE): + def __init__(self, filelist, util, playlist_provider, bgr=None, bounding_box=None, align=ALIGN_CENTER): """ Initializer :param filelist: file list @@ -55,7 +55,7 @@ def __init__(self, filelist, util, playlist_provider, bgr=None, bounding_box=Non if filelist: r = filelist.rows c = filelist.columns - Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align) + Menu.__init__(self, util, bgr, self.bounding_box, r, c, create_item_method=m, align=align, button_padding_x=5) self.browsing_history = {} self.left_number_listeners = [] @@ -418,7 +418,7 @@ def init_page(self, index): else: self.item_selected(self.filelist.current_item) - def set_page(self, index_on_page, page, align=ALIGN_MIDDLE): + def set_page(self, index_on_page, page, align=ALIGN_CENTER): """ Page setter :param index_on_page: current item index on page diff --git a/ui/menu/homemenu.py b/ui/menu/homemenu.py index 1e501a7b..49279500 100644 --- a/ui/menu/homemenu.py +++ b/ui/menu/homemenu.py @@ -1,34 +1,37 @@ # Copyright 2016-2018 Peppy Player peppy.player@gmail.com -# +# # This file is part of Peppy Player. -# +# # Peppy Player is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. -# +# # Peppy Player is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. -# +# # You should have received a copy of the GNU General Public License # along with Peppy Player. If not, see . +import sys + from ui.factory import Factory from ui.menu.menu import Menu -from player.proxy import VLC +from player.proxy import VLC_NAME +from util.util import NUMBERS from util.cdutil import CdUtil from util.keys import LINUX_PLATFORM, V_ALIGN_TOP -from util.config import USAGE, USE_VOICE_ASSISTANT, HOME_MENU, RADIO, AUDIO_FILES, \ - CURRENT, MODE, NAME, AUDIOBOOKS, STREAM, CD_PLAYER, PODCASTS, AUDIO, PLAYER_NAME +from util.config import USAGE, USE_VOICE_ASSISTANT, HOME_MENU, RADIO, AUDIO_FILES, CURRENT, MODE, NAME, \ + AUDIOBOOKS, STREAM, CD_PLAYER, PODCASTS, AIRPLAY, AUDIO, PLAYER_NAME, SPOTIFY_CONNECT class HomeMenu(Menu): """ Home Menu class. Extends base Menu class """ - + def __init__(self, util, bgr=None, bounding_box=None, font_size=None): """ Initializer - + :param util: utility object :param bgr: menu background :param bounding_box: bounding box @@ -37,7 +40,8 @@ def __init__(self, util, bgr=None, bounding_box=None, font_size=None): self.factory = Factory(util) self.config = util.config m = self.factory.create_home_menu_button - Menu.__init__(self, util, bgr, bounding_box, None, None, create_item_method=m, font_size=font_size) + Menu.__init__(self, util, bgr, bounding_box, None, None, + create_item_method=m, font_size=font_size) self.cdutil = CdUtil(util) self.set_modes() @@ -75,33 +79,33 @@ def set_modes(self): downloads = podcasts_util.are_there_any_downloads() connected = self.util.connected_to_internet player = self.config[AUDIO][PLAYER_NAME] - if (connected and len(podcasts) == 0 and not downloads) or (not connected and not downloads) or player != VLC: + if (connected and len(podcasts) == 0 and not downloads) or (not connected and not downloads) or player != VLC_NAME: disabled_items.append(PODCASTS) items.append(PODCASTS) + if self.config[HOME_MENU][AIRPLAY]: + items.append(AIRPLAY) + if not self.util.config[LINUX_PLATFORM]: + disabled_items.append(AIRPLAY) + + if self.config[HOME_MENU][SPOTIFY_CONNECT]: + items.append(SPOTIFY_CONNECT) + if not self.util.config[LINUX_PLATFORM]: + disabled_items.append(SPOTIFY_CONNECT) + l = self.get_layout(items) bounding_box = l.get_next_constraints() - self.modes = self.util.load_menu(items, NAME, disabled_items, V_ALIGN_TOP, bb=bounding_box, scale=0.5) + self.modes = self.util.load_menu( + items, NAME, disabled_items, V_ALIGN_TOP, bb=bounding_box, scale=0.5) va_commands = self.util.get_voice_commands() if self.config[USAGE][USE_VOICE_ASSISTANT]: - if self.config[HOME_MENU][RADIO]: - r = [va_commands["VA_RADIO"].strip(), va_commands["VA_GO_RADIO"].strip()] - self.modes[RADIO].voice_commands = r - if self.config[HOME_MENU][AUDIO_FILES]: - f = [va_commands["VA_FILES"].strip(), va_commands["VA_GO_FILES"].strip(), - va_commands["VA_AUDIO_FILES"].strip()] - self.modes[AUDIO_FILES].voice_commands = f - if self.config[HOME_MENU][AUDIOBOOKS]: - a = [va_commands["VA_AUDIOBOOKS"].strip(), va_commands["VA_BOOKS"].strip(), - va_commands["VA_GO_BOOKS"].strip()] - self.modes[AUDIOBOOKS].voice_commands = a - if self.config[HOME_MENU][STREAM]: - s = [va_commands["VA_STREAM"].strip(), va_commands["VA_GO_STREAM"].strip()] - self.modes[STREAM].voice_commands = s - if self.config[HOME_MENU][CD_PLAYER]: - s = [va_commands["VA_CD_PLAYER"].strip()] - self.modes[STREAM].voice_commands = s + self.add_voice_command(RADIO, ["VA_RADIO", "VA_GO_RADIO"], va_commands) + self.add_voice_command(AUDIO_FILES, ["VA_FILES", "VA_GO_FILES"], va_commands) + self.add_voice_command(AUDIOBOOKS, ["VA_AUDIOBOOKS", "VA_BOOKS", "VA_GO_BOOKS"], va_commands) + self.add_voice_command(STREAM, ["VA_STREAM", "VA_GO_STREAM"], va_commands) + self.add_voice_command(CD_PLAYER, ["VA_CD_PLAYER"], va_commands) + self.add_voice_command(PODCASTS, ["VA_PODCAST", "VA_PODCASTS"], va_commands) if not items: return @@ -118,9 +122,23 @@ def set_modes(self): self.current_mode = self.modes[mode.lower()] self.item_selected(self.current_mode) + def add_voice_command(self, name, commands, va_commands): + """ Add voice command + + :param name: item name + :param commands: item commands + :param va_commands: voice commands + """ + if not self.config[HOME_MENU][name]: + return + c = [] + for m in commands: + c.append(va_commands[m].strip()) + self.modes[name].voice_commands = c + def change_mode(self, state): """ Change mode event listener - + :param state: button state """ if not self.visible: diff --git a/ui/menu/homenavigatormenu.py b/ui/menu/homenavigatormenu.py index 752db298..e5e3bcd4 100644 --- a/ui/menu/homenavigatormenu.py +++ b/ui/menu/homenavigatormenu.py @@ -20,7 +20,7 @@ from ui.factory import Factory from util.config import LANGUAGE, SCREENSAVER, EQUALIZER, HOME_MENU, HOME_NAVIGATOR, TIMER, \ HOME_SCREENSAVER, HOME_BACK, HOME_LANGUAGE, PLAYER, ABOUT, NETWORK -from util.keys import KEY_PLAYER, KEY_ABOUT, KEY_HOME, KEY_BACK, KEY_MENU, \ +from util.keys import KEY_PLAYER, KEY_ABOUT, KEY_HOME, KEY_BACK, KEY_MENU, KEY_SUBTITLE, \ KEY_PLAY_PAUSE, KEY_SETUP, KEY_ROOT, KEY_AUDIO class HomeNavigatorMenu(Container): @@ -102,7 +102,7 @@ def __init__(self, util, listeners, bgr=None, bounding_box=None): if util.config[HOME_NAVIGATOR][NETWORK]: constr = layout.get_next_constraints() - self.network_button = self.factory.create_button(NETWORK, KEY_AUDIO, constr, listeners[NETWORK], bgr, size) + self.network_button = self.factory.create_button(NETWORK, KEY_SUBTITLE, constr, listeners[NETWORK], bgr, size) self.add_component(self.network_button) self.menu_buttons.append(self.network_button) diff --git a/ui/menu/languagemenu.py b/ui/menu/languagemenu.py index ce289564..0520334e 100644 --- a/ui/menu/languagemenu.py +++ b/ui/menu/languagemenu.py @@ -43,19 +43,19 @@ def __init__(self, util, bgr=None, bounding_box=None): self.languages = self.util.load_languages_menu(button_rect) self.set_items(self.languages, 0, self.change_language, False) self.current_language = self.languages[language] - self.item_selected(self.current_language) - + self.item_selected(self.current_language) + def set_voice_commands(self, language): """ Set menu voice commands - + :param language: new language """ if not self.config[USAGE][USE_VOICE_ASSISTANT]: return - + va_commands = self.util.get_va_language_commands() - for language in self.languages: - language.voice_commands = va_commands[language.name] + for k, v in self.languages.items(): + v.voice_commands = va_commands[k] def change_language(self, state): """ Change language event listener diff --git a/ui/menu/menu.py b/ui/menu/menu.py index 2bdb5266..d522dc99 100644 --- a/ui/menu/menu.py +++ b/ui/menu/menu.py @@ -24,13 +24,14 @@ KEY_LEFT, KEY_RIGHT, KEY_UP, KEY_DOWN, KEY_SELECT ALIGN_LEFT = "left" -ALIGN_MIDDLE = "middle" +ALIGN_CENTER = "center" ALIGN_RIGHT = "right" class Menu(Container): """ Base class for all menu components. Extends Container class. """ - def __init__(self, util, bgr=None, bb=None, rows=3, cols=3, create_item_method=None, menu_button_layout=None, font_size=None, align=ALIGN_MIDDLE): + def __init__(self, util, bgr=None, bb=None, rows=3, cols=3, create_item_method=None, menu_button_layout=None, + font_size=None, align=ALIGN_CENTER, button_padding_x=None): """ Initializer :param util: utility object @@ -51,6 +52,7 @@ def __init__(self, util, bgr=None, bb=None, rows=3, cols=3, create_item_method=N self.move_listeners = [] self.menu_loaded_listeners = [] self.font_size = font_size + self.button_padding_x = button_padding_x self.buttons = {} self.factory = Factory(util) @@ -104,8 +106,8 @@ def set_items(self, it, page_index, listener, scale=True, order=None): self.add_component(button) self.buttons[comp_name] = button - if self.align != ALIGN_MIDDLE: - self.align_labels(self.align) + if self.align != ALIGN_CENTER: + self.align_content(self.align) self.notify_menu_loaded_listeners() @@ -145,21 +147,30 @@ def get_layout(self, items): layout.set_pixel_constraints(self.rows, self.cols, 1, 1) return layout - def align_labels(self, align): - """ Align menu button labels + def align_content(self, align): + """ Align menu button content - :param align: type of alignment + :param align: alignment type """ if not self.components: return b = self.components[0] - + + if b.components[1] and b.components[1].content: + button_has_image = True + else: + button_has_image = False + fixed_height = getattr(b.state, "fixed_height", None) if fixed_height: font_size = fixed_height else: - font_size = int((b.bounding_box.h * b.state.label_text_height)/100.0) + if button_has_image: + vert_gap = 4 #percent + font_size = int(b.bounding_box.h - (b.bounding_box.h * (100 - b.state.label_area_percent + vert_gap))/100) + else: + font_size = int((b.bounding_box.h * b.state.label_text_height)/100.0) longest_string = "" @@ -168,15 +179,35 @@ def align_labels(self, align): longest_string = b.state.l_name font = self.util.get_font(font_size) - size = font.size(longest_string) + label_size = font.size(longest_string) + + if label_size[0] >= b.bounding_box.w: + final_size = (b.bounding_box.w, label_size[1]) + else: + final_size = label_size + + if self.button_padding_x: + padding_x = int((b.bounding_box.w * self.button_padding_x) /100) + else: + padding_x = 0 for b in self.components: comps = b.components if align == ALIGN_LEFT: - comps[2].content_x = b.bounding_box.x + (b.bounding_box.w - size[0])/2 + x = b.bounding_box.x + padding_x + (b.bounding_box.w - final_size[0])/2 + if comps[2]: + comps[2].content_x = x + if button_has_image: + comps[1].content_x = x elif align == ALIGN_RIGHT: - s = font.size(b.state.l_name) - comps[2].content_x = b.bounding_box.x + (b.bounding_box.w - size[0])/2 + size[0] - s[0] + if final_size[0] < int((b.bounding_box.w * 2) / 3): + x = b.bounding_box.x + b.bounding_box.w - padding_x + else: + x = b.bounding_box.x + final_size[0] - padding_x + if comps[2]: + comps[2].content_x = x - comps[2].content.get_size()[0] + if button_has_image: + comps[1].content_x = x - comps[1].content[1].get_size()[0] def sort_items(self, d, order): """ Sort items according to the specified order diff --git a/ui/screen/about.py b/ui/screen/about.py index 761ab932..fd94f30d 100644 --- a/ui/screen/about.py +++ b/ui/screen/about.py @@ -1,4 +1,4 @@ -# Copyright 2016-2018 Peppy Player peppy.player@gmail.com +# Copyright 2016-2019 Peppy Player peppy.player@gmail.com # # This file is part of Peppy Player. # @@ -16,13 +16,16 @@ # along with Peppy Player. If not, see . import pygame +import logging from ui.container import Container from ui.layout.borderlayout import BorderLayout +from ui.layout.gridlayout import GridLayout from event.dispatcher import USER_EVENT_TYPE, SUB_TYPE_KEYBOARD from ui.factory import Factory -from util.config import COLOR_LOGO, COLORS, COLOR_WEB_BGR -from util.util import V_ALIGN_TOP +from util.config import COLOR_LOGO, COLOR_CONTRAST, COLORS, COLOR_WEB_BGR, RELEASE, EDITION_NAME, USAGE, \ + USE_CHECK_FOR_UPDATES, PRODUCT_NAME, RELEASE_YEAR, RELEASE_MONTH, RELEASE_DAY +from util.util import V_ALIGN_TOP, V_ALIGN_BOTTOM PERCENT_FOOTER_HEIGHT = 20.00 PERCENT_NAME_LONG_HEIGHT = 10.00 @@ -38,18 +41,25 @@ def __init__(self, util): """ self.util = util self.config = util.config + self.config_class = util.config_class self.color_web_bgr = self.config[COLORS][COLOR_WEB_BGR] + color_logo = self.config[COLORS][COLOR_CONTRAST] + color_status = self.config[COLORS][COLOR_LOGO] + Container.__init__(self, util, background=self.color_web_bgr) self.bounding_box = util.screen_rect self.start_listeners = [] factory = Factory(util) - edition = "Holbein Edition" + self.installed_release = self.config[RELEASE] + self.installed_edition = self.installed_release[EDITION_NAME] + self.installed_year = self.installed_release[RELEASE_YEAR] + self.installed_month = self.installed_release[RELEASE_MONTH] + self.installed_day = self.installed_release[RELEASE_DAY] layout = BorderLayout(self.bounding_box) layout.set_percent_constraints(0, PERCENT_FOOTER_HEIGHT, 0, 0) - release_font_size = (layout.BOTTOM.h * PERCENT_FOOTER_FONT)/100.0 - - color_logo = self.config[COLORS][COLOR_LOGO] + font_size = int((layout.BOTTOM.h * PERCENT_FOOTER_FONT)/100.0) + button = factory.create_image_button("peppy", bounding_box=layout.CENTER, bgr=self.color_web_bgr, image_size_percent=68, selected=False) x = layout.CENTER.w/2 - button.components[1].content.get_size()[0]/2 y = layout.CENTER.h/2 - button.components[1].content.get_size()[1]/2 @@ -57,12 +67,57 @@ def __init__(self, util): button.components[1].content_y = y self.add_component(button) - layout.BOTTOM.y -= 1 + layout.BOTTOM.y -= int((self.bounding_box.h * 5) / 100) layout.BOTTOM.h += 1 - release = factory.create_output_text("about-name", layout.BOTTOM, self.color_web_bgr, color_logo, int(release_font_size), full_width=True, valign=V_ALIGN_TOP) - release.set_text_no_draw(edition) - self.add_component(release) + + if self.util.connected_to_internet and self.config[USAGE][USE_CHECK_FOR_UPDATES]: + bottom_layout = GridLayout(layout.BOTTOM) + bottom_layout.set_pixel_constraints(2, 1) + line_top = bottom_layout.get_next_constraints() + line_bottom = bottom_layout.get_next_constraints() + else: + line_top = layout.BOTTOM + + self.release = factory.create_output_text("installed", line_top, self.color_web_bgr, color_logo, font_size, full_width=True, valign=V_ALIGN_BOTTOM) + self.add_component(self.release) + + if self.util.connected_to_internet and self.config[USAGE][USE_CHECK_FOR_UPDATES]: + self.status = factory.create_output_text("status", line_bottom, self.color_web_bgr, color_status, font_size, full_width=True, valign=V_ALIGN_TOP) + self.add_component(self.status) + self.new_release = self.get_new_release() + def set_current(self, state=None): + """ Set current screen + + :param state: button state + """ + self.release.set_text_no_draw(self.installed_edition) + if self.util.connected_to_internet and self.config[USAGE][USE_CHECK_FOR_UPDATES]: + if self.new_release: + template = self.util.get_labels()["new.version.released"] + status_msg = template.replace("{edition}", self.new_release) + else: + status_msg = self.util.get_labels()["player.is.up.to.date"] + self.status.set_text_no_draw(status_msg) + + def get_new_release(self): + """ Check if new release is avaialble on github + + :return: name of new release if any, None otherwise + """ + github_release = self.config_class.load_release(False) + github_edition = github_release[EDITION_NAME] + github_release_year = github_release[RELEASE_YEAR] + github_release_month = github_release[RELEASE_MONTH] + github_release_day = github_release[RELEASE_DAY] + + if (github_edition != self.installed_edition or + (github_edition == self.installed_edition and (github_release_year != self.installed_year or + github_release_month != self.installed_month or github_release_day != self.installed_day ))): + return github_edition + else: + return None + def add_listener(self, listener): """ Add About Screen event listener diff --git a/ui/screen/airplayplayer.py b/ui/screen/airplayplayer.py new file mode 100644 index 00000000..884919d8 --- /dev/null +++ b/ui/screen/airplayplayer.py @@ -0,0 +1,111 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +from ui.screen.fileplayer import FilePlayerScreen + +class AirplayPlayerScreen(FilePlayerScreen): + """ AirPlay Player Screen """ + + def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None, next=None, previous=None): + """ Initializer + + :param listeners: screen listeners + :param util: utility object + :param get_current_playlist: current playlist getter + :param voice_assistant: voice assistant + :param player_stop: stop player function + :param next: next track function + :param previous: previous track function + """ + FilePlayerScreen.__init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop, False, False, False) + self.next = next + self.previous = previous + self.file_button.state.name = "file.button" + self.volume.check_pause = False + self.volume.handle_knob_events = False + self.screen_title.set_text("AirPlay") + + self.toggle_time_volume() + bb = self.time_volume_button.states[0].bounding_box + b = self.factory.create_disabled_button(bb, "time", 0.4) + self.time_volume_button.states[1] = b.state + self.time_volume_button.draw_state(1) + self.time_volume_button.clean_draw_update() + self.time_volume_button.start_listeners = [] + + def set_current(self, new_track=False, state=None): + """ Set current file or playlist + + :param new_track: True - new audio file + :param state: button state + """ + pass + + def handle_metadata(self, state=None): + """ Handle metadata UI callback + + :param state: metadata object + """ + if not state: + return + + if "picture" in state.keys(): + img = ("current_shairport_image", state["picture"]) + self.set_file_button(img) + self.file_button.clean_draw_update() + elif "current_title" in state.keys(): + title = state["current_title"] + self.screen_title.set_text(title) + elif "volume" in state.keys(): + volume = state["volume"] + self.volume.set_position(volume) + self.volume.update_position() + self.volume.notify_slide_listeners() + elif "stream" in state.keys(): + type = state["stream"] + if type == "end": + self.play_button.draw_state(1) + elif type == "begin": + self.play_button.draw_state(0) + elif "Time" in state.keys() and "seek_time" in state.keys(): + state["state"] = "running" + + if self.visible: + if self.update_web_observer: + self.update_web_observer() + + def go_right(self, state): + """ Switch to the next track + + :param state: not used state object + """ + self.next() + + def go_left(self, state): + """ Switch to the previous track + + :param state: not used state object + """ + self.previous() + + def is_valid_mode(self): + """ Check that current mode is valid mode + + :return: True - airplay mode is valid + """ + return True + \ No newline at end of file diff --git a/ui/screen/bookauthor.py b/ui/screen/bookauthor.py index 75d3f77a..9eb3b333 100644 --- a/ui/screen/bookauthor.py +++ b/ui/screen/bookauthor.py @@ -113,7 +113,7 @@ def turn_page(self): page = filtered_authors[start : end] self.author_dict = self.factory.create_book_author_items(page) self.authors_menu.set_items(self.author_dict, 0, self.go_author, False) - self.authors_menu.align_labels(ALIGN_LEFT) + self.authors_menu.align_content(ALIGN_LEFT) self.authors_menu.select_by_index(0) self.authors_menu.clean_draw_update() diff --git a/ui/screen/bookgenre.py b/ui/screen/bookgenre.py index 03a1089e..1a261512 100644 --- a/ui/screen/bookgenre.py +++ b/ui/screen/bookgenre.py @@ -52,7 +52,7 @@ def turn_page(self): page = self.genres_list[start : end] self.genres_dict = self.factory.create_book_genre_items(page, self.base_url) self.genre_menu.set_items(self.genres_dict, 0, self.go_book_by_genre, False) - self.genre_menu.align_labels(ALIGN_LEFT) + self.genre_menu.align_content(ALIGN_LEFT) self.genre_menu.select_by_index(0) self.genre_menu.clean_draw_update() diff --git a/ui/screen/filebrowser.py b/ui/screen/filebrowser.py index 022d7356..5572d668 100644 --- a/ui/screen/filebrowser.py +++ b/ui/screen/filebrowser.py @@ -24,8 +24,9 @@ from ui.screen.screen import Screen from util.keys import GO_BACK, GO_LEFT_PAGE, GO_RIGHT_PAGE, GO_ROOT, GO_USER_HOME, GO_TO_PARENT, \ KEY_PLAY_FILE -from util.config import CURRENT_FOLDER, AUDIO, MUSIC_FOLDER, CURRENT_FILE_PLAYBACK_MODE, \ - CURRENT_FILE_PLAYLIST, COLORS, COLOR_DARK_LIGHT, COLOR_CONTRAST, FILE_PLAYBACK +from util.config import CURRENT_FOLDER, AUDIO, MUSIC_FOLDER, CURRENT_FILE_PLAYBACK_MODE, FILE_BROWSER_ROWS, \ + FILE_BROWSER_COLUMNS, CURRENT_FILE_PLAYLIST, COLORS, COLOR_DARK_LIGHT, COLOR_CONTRAST, FILE_PLAYBACK, \ + ALIGN_BUTTON_CONTENT_X from util.fileutil import FILE_AUDIO, FILE_PLAYLIST, FILE_RECURSIVE from ui.menu.navigator import Navigator from ui.menu.filemenu import FileMenu @@ -63,8 +64,8 @@ def __init__(self, util, get_current_playlist, playlist_provider, listeners, voi self.screen_title.set_text(d) - rows = 3 - columns = 3 + rows = self.config[FILE_BROWSER_ROWS] + columns = self.config[FILE_BROWSER_COLUMNS] self.filelist = None playback_mode = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] @@ -87,7 +88,7 @@ def __init__(self, util, get_current_playlist, playlist_provider, listeners, voi pl = self.util.load_playlist_content(pl, rows, columns) self.filelist = Page(pl, rows, columns) - self.file_menu = FileMenu(self.filelist, util, playlist_provider, (0, 0, 0), layout.CENTER) + self.file_menu = FileMenu(self.filelist, util, playlist_provider, (0, 0, 0), layout.CENTER, self.config[ALIGN_BUTTON_CONTENT_X]) Container.add_component(self, self.file_menu) self.file_menu.add_change_folder_listener(self.screen_title.set_text) diff --git a/ui/screen/fileplayer.py b/ui/screen/fileplayer.py index 52470769..7ef73a45 100644 --- a/ui/screen/fileplayer.py +++ b/ui/screen/fileplayer.py @@ -51,7 +51,7 @@ class FilePlayerScreen(Screen): """ File Player Screen """ - def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None): + def __init__(self, listeners, util, get_current_playlist, voice_assistant, player_stop=None, arrow_labels=True, active_file_button=True, show_time_control=True): """ Initializer :param listeners: screen listeners @@ -67,6 +67,7 @@ def __init__(self, listeners, util, get_current_playlist, voice_assistant, playe self.stop_player = player_stop self.get_current_playlist = get_current_playlist self.bounding_box = util.screen_rect + self.show_time_control = show_time_control self.layout = BorderLayout(self.bounding_box) k = self.bounding_box.w/self.bounding_box.h percent_menu_width = (100.0 - PERCENT_TOP_HEIGHT - PERCENT_BOTTOM_HEIGHT)/k @@ -77,9 +78,12 @@ def __init__(self, listeners, util, get_current_playlist, voice_assistant, playe self.layout = BorderLayout(self.bounding_box) self.layout.set_percent_constraints(PERCENT_TOP_HEIGHT, PERCENT_BOTTOM_HEIGHT, panel_width, panel_width) - self.create_left_panel(self.layout, listeners) - self.create_right_panel(self.layout, listeners) + self.create_left_panel(self.layout, listeners, arrow_labels) + self.create_right_panel(self.layout, listeners, arrow_labels) + if not active_file_button: + listeners[AUDIO_FILES] = None + self.file_button = self.factory.create_file_button(self.layout.CENTER, listeners[AUDIO_FILES]) Container.add_component(self, self.file_button) @@ -90,29 +94,31 @@ def __init__(self, listeners, util, get_current_playlist, voice_assistant, playe self.right_button.add_release_listener(self.go_right) self.volume = self.factory.create_volume_control(self.layout.BOTTOM) - self.volume.add_slide_listener(listeners[KEY_SET_VOLUME]) - self.volume.add_slide_listener(listeners[KEY_SET_CONFIG_VOLUME]) - self.volume.add_slide_listener(listeners[KEY_SET_SAVER_VOLUME]) - self.volume.add_knob_listener(listeners[KEY_MUTE]) + self.volume.add_slide_listener(self.get_listener(listeners, KEY_SET_VOLUME)) + self.volume.add_slide_listener(self.get_listener(listeners, KEY_SET_CONFIG_VOLUME)) + self.volume.add_slide_listener(self.get_listener(listeners, KEY_SET_SAVER_VOLUME)) + self.volume.add_knob_listener(self.get_listener(listeners, KEY_MUTE)) self.volume_visible = False self.volume.set_visible(self.volume_visible) Container.add_component(self, self.volume) - self.time_control = self.factory.create_time_control(self.layout.BOTTOM) - self.time_control.add_seek_listener(listeners[KEY_SEEK]) - - self.play_button.add_listener(PAUSE, self.time_control.pause) - self.play_button.add_listener(KEY_PLAY, self.time_control.resume) + if self.show_time_control: + self.time_control = self.factory.create_time_control(self.layout.BOTTOM) + if KEY_SEEK in listeners.keys(): + self.time_control.add_seek_listener(listeners[KEY_SEEK]) + + self.play_button.add_listener(PAUSE, self.time_control.pause) + self.play_button.add_listener(KEY_PLAY, self.time_control.resume) + + if self.config[PLAYER_SETTINGS][PAUSE]: + self.time_control.pause() + Container.add_component(self, self.time_control) + self.left_button.add_release_listener(self.play_button.draw_default_state) self.right_button.add_release_listener(self.play_button.draw_default_state) - - if self.config[PLAYER_SETTINGS][PAUSE]: - self.time_control.pause() - - Container.add_component(self, self.time_control) self.play_listeners = [] - self.add_play_listener(listeners[KEY_PLAY]) + self.add_play_listener(self.get_listener(listeners, KEY_PLAY)) self.current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] self.file_button.state.cover_art_folder = self.util.file_util.get_cover_art_folder(self.current_folder) @@ -211,8 +217,9 @@ def stop_recursive_playback(self): self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] = None self.config[FILE_PLAYBACK][CURRENT_TRACK_TIME] = None self.stop_timer() - self.time_control.stop_thread() - self.time_control.reset() + if self.show_time_control: + self.time_control.stop_thread() + self.time_control.reset() if self.stop_player != None: self.stop_player() @@ -248,7 +255,8 @@ def go_right(self, state): if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_RECURSIVE and self.current_track_index == filelist_size - 1: self.stop_timer() - self.time_control.stop_thread() + if self.show_time_control: + self.time_control.stop_thread() self.recursive_change_folder() self.current_track_index = 0 self.change_track(self.current_track_index) @@ -295,13 +303,20 @@ def change_track(self, track_index): if self.cd_album != None: s.album = self.cd_album + + if self.config[CURRENT][MODE] == AUDIO_FILES: + folder = self.current_folder + if not folder.endswith(os.sep): + folder += os.sep + s.url = folder + s.file_name self.set_current(True, s) def stop_timer(self): """ Stop time control timer """ - self.time_control.stop_timer() + if self.show_time_control: + self.time_control.stop_timer() def get_filename(self, index): """ Get filename by index @@ -362,15 +377,16 @@ def set_current_track_index(self, state): i = self.get_current_track_index(state) self.current_track_index = i - def create_left_panel(self, layout, listeners): + def create_left_panel(self, layout, listeners, arrow_labels): """ Create left side buttons panel :param layout: panel layout - :param listeners: button listeners + :param listeners: button listeners + :param arrow_labels: show arrow label or not """ panel_layout = BorderLayout(layout.LEFT) panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0) - self.left_button = self.factory.create_left_button(panel_layout.CENTER, '', 40, 100) + self.left_button = self.factory.create_left_button(panel_layout.CENTER, '', 40, 100, arrow_labels) self.shutdown_button = self.factory.create_shutdown_button(panel_layout.TOP) self.home_button = self.factory.create_button(KEY_HOME, KEY_HOME, panel_layout.BOTTOM, image_size_percent=36) panel = Container(self.util, layout.LEFT) @@ -379,36 +395,52 @@ def create_left_panel(self, layout, listeners): panel.add_component(self.home_button) Container.add_component(self, panel) - def create_right_panel(self, layout, listeners): + def create_right_panel(self, layout, listeners, arrow_labels): """ Create right side buttons panel :param layout: panel layout - :param listeners: button listeners + :param listeners: button listeners + :param arrow_labels: show arrow label or not """ panel_layout = BorderLayout(layout.RIGHT) panel_layout.set_percent_constraints(PERCENT_SIDE_BOTTOM_HEIGHT, PERCENT_SIDE_BOTTOM_HEIGHT, 0, 0) - self.play_button = self.factory.create_play_pause_button(panel_layout.TOP, listeners[KEY_PLAY_PAUSE]) - self.right_button = self.factory.create_right_button(panel_layout.CENTER, '', 40, 100) + self.play_button = self.factory.create_play_pause_button(panel_layout.TOP, self.get_listener(listeners, KEY_PLAY_PAUSE)) + self.right_button = self.factory.create_right_button(panel_layout.CENTER, '', 40, 100, arrow_labels) self.time_volume_button = self.factory.create_time_volume_button(panel_layout.BOTTOM, self.toggle_time_volume) panel = Container(self.util, layout.RIGHT) panel.add_component(self.play_button) panel.add_component(self.right_button) panel.add_component(self.time_volume_button) Container.add_component(self, panel) - + + def get_listener(self, listeners, name): + """ Return listener + + :param listeners: all listeners + :param name: listener name + + :return: listener if avaialble, None - otherwise + """ + if name in listeners.keys(): + return listeners[name] + else: + return None + def toggle_time_volume(self): """ Switch between time and volume controls """ if self.volume_visible: self.volume.set_visible(False) - self.time_control.set_visible(True) + if self.show_time_control: + self.time_control.set_visible(True) self.volume_visible = False else: volume_level = int(self.config[PLAYER_SETTINGS][VOLUME]) self.volume.set_position(volume_level) self.volume.update_position() self.volume.set_visible(True) - self.time_control.set_visible(False) + if self.show_time_control: + self.time_control.set_visible(False) self.volume_visible = True self.clean_draw_update() @@ -420,7 +452,8 @@ def eject_cd(self, state): self.audio_files = [] self.screen_title.set_text(" ") self.update_arrow_button_labels(state) - self.time_control.reset() + if self.show_time_control: + self.time_control.reset() self.cd_album = None self.set_cd_album_art_image() @@ -435,7 +468,7 @@ def set_current(self, new_track=False, state=None): if self.config[CURRENT][MODE] == AUDIO_FILES: if getattr(state, "url", None) is None: state.url = None - state.full_screen_image = self.set_audio_file_image() + state.full_screen_image = self.set_audio_file_image(state.url) elif self.config[CURRENT][MODE] == CD_PLAYER and getattr(state, "source", None) != INIT: state.full_screen_image = self.set_cd_album_art_image() state.image_base = self.file_button.components[1].content @@ -450,14 +483,19 @@ def set_current(self, new_track=False, state=None): self.volume.set_position(config_volume_level) self.volume.update_position() - def set_audio_file_image(self): - """ Set audio file image """ - + def set_audio_file_image(self, url=None): + """ Set audio file image + + :param url: audio file name + + :return: image + """ f = self.config[FILE_PLAYBACK][CURRENT_FOLDER] if not f: return None - img_tuple = self.util.get_audio_file_icon(f, self.bounding_box) + img_tuple = self.util.get_audio_file_icon(f, self.bounding_box, url) self.set_file_button(img_tuple) + self.file_button.clean_draw_update() return img_tuple[1] @@ -530,6 +568,9 @@ def set_audio_file(self, new_track, s=None): else: state.url = "\"" + state.folder + os.sep + state.file_name + "\"" + if s.url == None and state.url != None: + state.full_screen_image = self.set_audio_file_image(state.url.replace('\"', "")) + state.music_folder = self.config[AUDIO][MUSIC_FOLDER] elif self.config[CURRENT][MODE] == CD_PLAYER: state.file_name = s.file_name @@ -545,7 +586,7 @@ def set_audio_file(self, new_track, s=None): state.pause = self.config[PLAYER_SETTINGS][PAUSE] state.file_type = FILE_AUDIO state.dont_notify = True - state.source = FILE_AUDIO + state.source = FILE_AUDIO if self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYBACK_MODE] == FILE_AUDIO or self.config[CURRENT][MODE] == CD_PLAYER: self.audio_files = self.get_audio_files() @@ -579,7 +620,8 @@ def set_audio_file(self, new_track, s=None): if (isinstance(tt, str) and len(tt) != 0) or (isinstance(tt, float) or (source and source == RESUME)) or isinstance(tt, int): state.track_time = tt - self.time_control.slider.set_position(0) + if self.show_time_control: + self.time_control.slider.set_position(0) if self.file_button and self.file_button.components[1] and self.file_button.components[1].content: state.icon_base = self.file_button.components[1].content @@ -601,9 +643,9 @@ def set_audio_file(self, new_track, s=None): song_name = self.get_song_name(s) if song_name != None: state.album = song_name - + self.notify_play_listeners(state) - + def get_song_name(self, state): """ Get song name in the format: Artist - Song name @@ -680,21 +722,8 @@ def set_audio_file_playlist(self, index): def go_back(self): """ Go back """ - - if self.config[CURRENT][MODE] == CD_PLAYER: - return - - img_tuple = self.util.get_audio_file_icon(self.current_folder, self.layout.CENTER) - img = img_tuple[1] - self.file_button.components[1].content = img - self.file_button.state.icon_base = img_tuple - - self.file_button.components[1].content_x = self.layout.CENTER.x - if self.layout.CENTER.h > img.get_size()[1]: - self.file_button.components[1].content_y = self.layout.CENTER.y + int((self.layout.CENTER.h - img.get_size()[1])/2) - else: - self.file_button.components[1].content_y = self.layout.CENTER.y - + pass + def recursive_change_folder(self): start_folder = self.config[FILE_PLAYBACK][CURRENT_FILE_PLAYLIST] current_folder = self.config[FILE_PLAYBACK][CURRENT_FOLDER] @@ -731,7 +760,8 @@ def end_of_track(self): if mode == RADIO or mode == STREAM or not self.audio_files: return - self.time_control.stop_thread() + if self.show_time_control: + self.time_control.stop_thread() if self.config[AUTO_PLAY_NEXT_TRACK]: if self.current_track_index == len(self.audio_files) - 1: @@ -774,10 +804,12 @@ def set_visible(self, flag): if flag: if self.volume_visible: self.volume.set_visible(True) - self.time_control.set_visible(False) + if self.show_time_control: + self.time_control.set_visible(False) else: self.volume.set_visible(False) - self.time_control.set_visible(True) + if self.show_time_control: + self.time_control.set_visible(True) def add_play_listener(self, listener): """ Add play listener @@ -811,7 +843,8 @@ def enable_player_screen(self, flag): :param flag: enable/disable flag """ self.screen_title.active = flag - self.time_control.active = flag + if self.show_time_control: + self.time_control.active = flag def add_screen_observers(self, update_observer, redraw_observer, start_time_control, stop_time_control, title_to_json): """ Add screen observers @@ -841,13 +874,16 @@ def add_screen_observers(self, update_observer, redraw_observer, start_time_cont self.volume.add_press_listener(update_observer) self.volume.add_motion_listener(update_observer) - self.add_button_observers(self.time_volume_button, update_observer, redraw_observer, release=False) self.add_button_observers(self.file_button, update_observer, redraw_observer, press=False, release=False) - self.time_control.web_seek_listener = update_observer - self.time_control.add_start_timer_listener(start_time_control) - self.time_control.add_stop_timer_listener(stop_time_control) - self.time_control.slider.add_slide_listener(update_observer) - self.time_control.slider.add_knob_listener(update_observer) - self.time_control.slider.add_press_listener(update_observer) - self.time_control.slider.add_motion_listener(update_observer) + if self.show_time_control: + self.add_button_observers(self.time_volume_button, update_observer, redraw_observer, release=False) + self.time_control.web_seek_listener = update_observer + if start_time_control: + self.time_control.add_start_timer_listener(start_time_control) + if stop_time_control: + self.time_control.add_stop_timer_listener(stop_time_control) + self.time_control.slider.add_slide_listener(update_observer) + self.time_control.slider.add_knob_listener(update_observer) + self.time_control.slider.add_press_listener(update_observer) + self.time_control.slider.add_motion_listener(update_observer) diff --git a/ui/screen/podcastepisodes.py b/ui/screen/podcastepisodes.py index 73740b75..a5cd4e14 100644 --- a/ui/screen/podcastepisodes.py +++ b/ui/screen/podcastepisodes.py @@ -21,7 +21,7 @@ from ui.factory import Factory from ui.page import Page from ui.screen.menuscreen import MenuScreen -from ui.menu.menu import ALIGN_MIDDLE +from ui.menu.menu import ALIGN_CENTER from util.keys import KEY_PLAYER, KEY_BACK, FILE_BUTTON from util.config import COLORS, COLOR_DARK_LIGHT from ui.menu.multipagemenu import MultiPageMenu @@ -63,7 +63,7 @@ def __init__(self, util, listeners, voice_assistant, state): self.title = state.name m = self.factory.create_episode_menu_button - self.episodes_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_EPISODES, MENU_COLUMNS_EPISODES, None, (0, 0, 0), self.menu_layout, align=ALIGN_MIDDLE) + self.episodes_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_EPISODES, MENU_COLUMNS_EPISODES, None, (0, 0, 0), self.menu_layout, align=ALIGN_CENTER) self.set_menu(self.episodes_menu) self.total_pages = PAGE_SIZE_EPISODES * 2 diff --git a/ui/screen/podcasts.py b/ui/screen/podcasts.py index e4aa8c91..4736dc74 100644 --- a/ui/screen/podcasts.py +++ b/ui/screen/podcasts.py @@ -21,7 +21,7 @@ from ui.layout.borderlayout import BorderLayout from ui.factory import Factory from ui.screen.menuscreen import MenuScreen -from ui.menu.menu import ALIGN_MIDDLE +from ui.menu.menu import ALIGN_CENTER from util.keys import KEY_PODCAST_EPISODES from util.config import COLORS, COLOR_DARK_LIGHT, LABELS, PODCASTS, PODCAST_URL from ui.menu.multipagemenu import MultiPageMenu @@ -57,7 +57,7 @@ def __init__(self, util, listeners, voice_assistant): self.title = self.config[LABELS][PODCASTS] m = self.factory.create_podcast_menu_button - self.podcasts_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, None, (0, 0, 0), self.menu_layout, align=ALIGN_MIDDLE) + self.podcasts_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS_PODCASTS, MENU_COLUMNS_PODCASTS, None, (0, 0, 0), self.menu_layout, align=ALIGN_CENTER) self.set_menu(self.podcasts_menu) self.navigator = PodcastNavigator(self.util, self.layout.BOTTOM, listeners, self.config[COLORS][COLOR_DARK_LIGHT], PAGE_SIZE_PODCASTS + 1) diff --git a/ui/screen/radiogroup.py b/ui/screen/radiogroup.py index 8f880bfa..9ef6aff7 100644 --- a/ui/screen/radiogroup.py +++ b/ui/screen/radiogroup.py @@ -19,7 +19,7 @@ from ui.screen.menuscreen import MenuScreen from ui.menu.multipagemenu import MultiPageMenu from util.keys import KEY_CHOOSE_GENRE, LABELS, GENRE -from ui.menu.menu import ALIGN_MIDDLE +from ui.menu.menu import ALIGN_CENTER from ui.factory import Factory from util.util import KEY_GENRE from util.config import COLORS, COLOR_DARK_LIGHT, CURRENT, LANGUAGE, CURRENT_STATIONS, STATIONS @@ -45,7 +45,7 @@ def __init__(self, util, listeners, voice_assistant): self.title = util.get_stations_top_folder() m = self.factory.create_genre_menu_button - self.groups_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0), self.menu_layout, align=ALIGN_MIDDLE) + self.groups_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, self.go_to_page, m, MENU_ROWS, MENU_COLUMNS, None, (0, 0, 0), self.menu_layout, align=ALIGN_CENTER) self.groups_menu.add_listener(listeners[KEY_GENRE]) self.set_menu(self.groups_menu) diff --git a/ui/screen/saver.py b/ui/screen/saver.py index 87cf5fe6..51bc6a90 100644 --- a/ui/screen/saver.py +++ b/ui/screen/saver.py @@ -117,9 +117,9 @@ def handle_event(self, event): index += self.saver_menu.cols self.saver_menu.select_by_index(index) elif event.keyboard_key == kbd_keys[KEY_HOME]: - self.home_button.handle_event(event) + self.navigator.home_button.handle_event(event) elif event.keyboard_key == kbd_keys[KEY_PLAY_PAUSE]: - self.player_button.handle_event(event) + self.navigator.player_button.handle_event(event) else: if self.top_menu_enabled: self.saver_menu.handle_event(event) diff --git a/ui/screen/screen.py b/ui/screen/screen.py index 3e9fbce9..3a12b23f 100644 --- a/ui/screen/screen.py +++ b/ui/screen/screen.py @@ -15,12 +15,14 @@ # You should have received a copy of the GNU General Public License # along with Peppy Player. If not, see . +import time + from ui.container import Container from ui.factory import Factory from ui.layout.borderlayout import BorderLayout from util.keys import KEY_LOADING, LABELS -from util.config import COLORS, COLOR_CONTRAST, USAGE, USE_VOICE_ASSISTANT, COLOR_DARK, COLOR_BRIGHT, \ - KEY_VA_START, KEY_VA_STOP, KEY_WAITING_FOR_COMMAND, KEY_VA_COMMAND, COLOR_DARK_LIGHT +from util.config import COLORS, COLOR_CONTRAST, USAGE, USE_VOICE_ASSISTANT, COLOR_DARK, COLOR_BRIGHT, VOICE_ASSISTANT, \ + KEY_VA_START, KEY_VA_STOP, KEY_WAITING_FOR_COMMAND, KEY_VA_COMMAND, COLOR_DARK_LIGHT, VOICE_COMMAND_DISPLAY_TIME PERCENT_TOP_HEIGHT = 14.00 PERCENT_TITLE_FONT = 54.00 @@ -88,6 +90,7 @@ def __init__(self, util, title_key, percent_bottom_height=0, voice_assistant=Non self.loading_listeners = [] self.LOADING = util.config[LABELS][KEY_LOADING] + self.factory = factory def draw_title_bar(self): """ Draw title bar on top of the screen """ @@ -122,6 +125,7 @@ def text_recognized(self, text): c = self.config[LABELS][KEY_VA_COMMAND] + " " + text self.voice_command.set_text(c) self.voice_command.clean_draw_update() + time.sleep(self.config[VOICE_ASSISTANT][VOICE_COMMAND_DISPLAY_TIME]) if self.update_web_title: self.update_web_title(self.voice_command) diff --git a/ui/screen/spotifyconnect.py b/ui/screen/spotifyconnect.py new file mode 100644 index 00000000..ff1904ef --- /dev/null +++ b/ui/screen/spotifyconnect.py @@ -0,0 +1,59 @@ +# Copyright 2019 Peppy Player peppy.player@gmail.com +# +# This file is part of Peppy Player. +# +# Peppy Player is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# Peppy Player is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with Peppy Player. If not, see . + +from ui.screen.airplayplayer import AirplayPlayerScreen + +class SpotifyConnectScreen(AirplayPlayerScreen): + """ Spotify Connect Screen """ + + def __init__(self, listeners, util, voice_assistant): + """ Initializer + + :param listeners: screen listeners + :param util: utility object + :param voice_assistant: voice assistant + """ + AirplayPlayerScreen.__init__(self, listeners, util, None, voice_assistant) + self.volume.components[1] = None + self.volume.components[2] = None + self.screen_title.set_text("Spotify Connect") + s = self.left_button.state + s.show_img = False + self.left_button.set_state(s) + s = self.right_button.state + s.show_img = False + self.right_button.set_state(s) + + bb = self.play_button.states[0].bounding_box + b = self.factory.create_disabled_button(bb, "play", 0.4) + self.play_button.states[1] = b.state + self.play_button.draw_state(1) + self.play_button.clean_draw_update() + + def go_right(self, state): + """ Switch to the next track + + :param state: not used state object + """ + pass + + def go_left(self, state): + """ Switch to the previous track + + :param state: not used state object + """ + pass diff --git a/ui/screen/wifi.py b/ui/screen/wifi.py index b812c3bf..3008b5b0 100644 --- a/ui/screen/wifi.py +++ b/ui/screen/wifi.py @@ -21,7 +21,7 @@ from ui.layout.borderlayout import BorderLayout from ui.factory import Factory from ui.screen.menuscreen import MenuScreen -from ui.menu.menu import ALIGN_MIDDLE +from ui.menu.menu import ALIGN_CENTER from util.config import LABELS from ui.menu.multipagemenu import MultiPageMenu from util.wifiutil import WiFiUtil, MENU_ROWS_WIFI, MENU_COLUMNS_WIFI, PAGE_SIZE_WIFI @@ -68,8 +68,8 @@ def __init__(self, util, listeners, voice_assistant): m = self.factory.create_wifi_menu_button self.wifi_menu = MultiPageMenu(util, self.next_page, self.previous_page, self.set_title, self.reset_title, - self.go_to_page, m, MENU_ROWS_WIFI, MENU_COLUMNS_WIFI, None, - (0, 0, 0), self.menu_layout, align=ALIGN_MIDDLE) + self.go_to_page, m, MENU_ROWS_WIFI, MENU_COLUMNS_WIFI, None, + (0, 0, 0), self.menu_layout, align=ALIGN_CENTER) self.set_menu(self.wifi_menu) listeners[KEY_REFRESH] = self.set_current diff --git a/ui/slider/slider.py b/ui/slider/slider.py index fe5753a2..be27e1c9 100644 --- a/ui/slider/slider.py +++ b/ui/slider/slider.py @@ -62,6 +62,8 @@ def __init__(self, util, name, bgr, slider_color, img_knob, img_knob_on, img_sel self.knob_on_filename = img_knob_on[0] self.dragging = False self.initial_level = 0 + self.check_pause = True + self.handle_knob_events = True self.selected = False if knob_selected: @@ -171,12 +173,18 @@ def add_knob_listener(self, listener): :param listener: the listener """ + if not self.handle_knob_events: + return + if listener not in self.knob_listeners: self.knob_listeners.append(listener) def notify_knob_listeners(self): """ Notify all knob event listeners """ + if not self.handle_knob_events: + return + for listener in self.knob_listeners: n = listener.__name__ if "mute" in n: @@ -300,7 +308,7 @@ def handle_event(self, event): :param event: event to handle """ - if self.util.config[PLAYER_SETTINGS][PAUSE]: + if self.check_pause and self.util.config[PLAYER_SETTINGS][PAUSE]: return if not self.visible: @@ -320,7 +328,8 @@ def mouse_action(self, event): """ pos = event.pos - if self.selected and not(self.last_knob_position < pos[0] < self.last_knob_position + self.knob_width and pos[1] > self.bounding_box.y) and event.type != pygame.KEYUP: + if self.selected and not(self.last_knob_position < pos[0] < self.last_knob_position + self.knob_width and pos[1] > self.bounding_box.y) and \ + event.type != pygame.KEYUP and self.handle_knob_events: return button_press_simulation = getattr(event, "p", None) @@ -350,7 +359,7 @@ def keyboard_action(self, event): :param event: event to handle """ - if event.keyboard_key == self.key_knob: + if event.keyboard_key == self.key_knob and self.handle_knob_events: self.knob_event(event) return diff --git a/ui/slider/timeslider.py b/ui/slider/timeslider.py index 9676292f..5429ec75 100644 --- a/ui/slider/timeslider.py +++ b/ui/slider/timeslider.py @@ -16,6 +16,7 @@ # along with Peppy Player. If not, see . import time +import logging from threading import Thread, RLock from timeit import default_timer as timer @@ -92,12 +93,13 @@ def __init__(self, util, name, bgr, slider_color, img_knob, img_knob_on, key_inc def start_timer(self): """ Start timer thread """ - + logging.debug("start timer") self.timer_started = True def stop_timer(self): """ Stop timer thread """ - + + logging.debug("stop timer") self.timer_started = False def set_track_time(self, name, time, bb, layer_num): @@ -168,9 +170,11 @@ def stop_thread(self): """ Stop knob animation thread """ with self.lock: + logging.debug("stop thread") if self.timer_started: self.stop_timer() self.notify_stop_timer_listeners() + logging.debug("timer stopped") def start_loop(self): """ Animation loop """ diff --git a/util/config.py b/util/config.py index bd4e7cb9..0d9fa793 100644 --- a/util/config.py +++ b/util/config.py @@ -22,6 +22,8 @@ from configparser import ConfigParser from util.keys import * +from urllib import request +from player.proxy import VLC_NAME, MPLAYER_NAME, MPD_NAME, SHAIRPORT_SYNC_NAME, RASPOTIFY_NAME FOLDER_LANGUAGES = "languages" FOLDER_RADIO_STATIONS = "radio-stations" @@ -34,6 +36,14 @@ FILE_CURRENT = "current.txt" FILE_PLAYERS = "players.txt" FILE_LANGUAGES = "languages.txt" +FILE_RELEASE = "release.txt" + +RELEASE = "release" +PRODUCT_NAME = "product.name" +EDITION_NAME = "edition.name" +RELEASE_YEAR = "year" +RELEASE_MONTH = "month" +RELEASE_DAY = "day" SCREEN_INFO = "screen.info" WIDTH = "width" @@ -60,6 +70,7 @@ USE_AUTO_PLAY = "auto.play" USE_LONG_PRESS_TIME = "long.press.time.ms" USE_POWEROFF = "poweroff" +USE_CHECK_FOR_UPDATES = "check.for.updates" LOGGING = "logging" FILE_LOGGING = "file.logging" @@ -77,6 +88,9 @@ CYCLIC_PLAYBACK = "cyclic.playback" HIDE_FOLDER_NAME = "hide.folder.name" FOLDER_IMAGE_SCALE_RATIO = "folder.image.scale.ratio" +FILE_BROWSER_ROWS = "rows" +FILE_BROWSER_COLUMNS = "columns" +ALIGN_BUTTON_CONTENT_X = "alignment" WEB_SERVER = "web.server" HTTPS = "https" @@ -98,6 +112,8 @@ STREAM = "stream" CD_PLAYER = "cd-player" PODCASTS = "podcasts" +AIRPLAY = "airplay" +SPOTIFY_CONNECT = "spotify-connect" HOME_NAVIGATOR = "home.navigator" HOME_BACK = "back" @@ -124,6 +140,7 @@ VOICE_ASSISTANT_CREDENTIALS = "credentials" VOICE_DEVICE_MODEL_ID = "device.model.id" VOICE_DEVICE_ID = "device.id" +VOICE_COMMAND_DISPLAY_TIME = "command.display.time" COLORS = "colors" COLOR_WEB_BGR = "color.web.bgr" @@ -142,6 +159,16 @@ STARTUP = "startup.script.name" SHUTDOWN = "shutdown.script.name" +ROTARY_ENCODERS = "rotary.encoders" +GPIO_VOLUME_UP = "gpio.volume.up" +GPIO_VOLUME_DOWN = "gpio.volume.down" +GPIO_MUTE = "gpio.mute" +GPIO_MOVE_LEFT = "gpio.move.left" +GPIO_MOVE_RIGHT = "gpio.move.right" +GPIO_SELECT = "gpio.select" +JITTER_FILTER = "jitter.filter" +LANGUAGES_MENU = "languages.menu" + SCREENSAVER_MENU = "screensaver.menu" CLOCK = "clock" LOGO = "logo" @@ -193,9 +220,11 @@ AUDIO = "audio" PLAYER_NAME = "player.name" MUSIC_FOLDER = "music.folder" +PLAYERS = "players" SERVER_FOLDER = "server.folder" -SERVER_COMMAND = "server.command" +SERVER_START_COMMAND = "server.start.command" +SERVER_STOP_COMMAND = "server.stop.command" CLIENT_NAME = "client.name" STREAM_CLIENT_PARAMETERS = "stream.client.parameters" STREAM_SERVER_PARAMETERS = "stream.server.parameters" @@ -216,9 +245,9 @@ def __init__(self): """ Initializer """ self.screen_rect = None - self.config = {} - self.load_languages(self.config) + self.config = {RELEASE: self.load_release()} self.load_config(self.config) + self.load_languages(self.config) self.load_players(self.config) self.load_current(self.config) self.init_lcd() @@ -231,14 +260,20 @@ def load_languages(self, config): """ config_file = ConfigParser() config_file.optionxform = str + try: path = os.path.join(os.getcwd(), FOLDER_LANGUAGES, FILE_LANGUAGES) - config_file.read_file(codecs.open(path, "r", UTF8)) + config_file.read(path, encoding=UTF8) except Exception as e: logging.error(e) os._exit(0) - sections = config_file.sections() + s = config_file.sections() + sections = [] + for section in s: + if config[LANGUAGES_MENU][section]: + sections.append(section) + languages = [] if sections: @@ -248,7 +283,8 @@ def load_languages(self, config): self.exit("No sections found in file: " + FILE_LANGUAGES) for section in sections: - language = {NAME: section} + language = {NAME: section} + translations = {} for (k, v) in config_file.items(section): translations[k] = v @@ -304,7 +340,37 @@ def exit(self, msg): """ logging.error(msg) os._exit(0) + + def load_release(self, local=True): + """ Loads and parses release file release.txt. + Creates dictionary entry for each property in the file. + :param config: configuration object + :param online: True - read local file, False - read from github + :return: dictionary containing all properties from the release.txt file + """ + parser = ConfigParser() + + if local: + parser.read(FILE_RELEASE) + else: + link = "https://raw.githubusercontent.com/project-owner/Peppy/master/release.txt" + req = request.Request(link) + try: + r = request.urlopen(req) + parser.read_string(r.read().decode('utf-8')) + except Exception as e: + logging.debug(e) + return None + + c = {PRODUCT_NAME: parser.get(RELEASE, PRODUCT_NAME)} + c[EDITION_NAME] = parser.get(RELEASE, EDITION_NAME) + c[RELEASE_YEAR] = parser.getint(RELEASE, RELEASE_YEAR) + c[RELEASE_MONTH] = parser.getint(RELEASE, RELEASE_MONTH) + c[RELEASE_DAY] = parser.getint(RELEASE, RELEASE_DAY) + + return c + def load_config(self, config): """ Loads and parses configuration file config.txt. Creates dictionary entry for each property in the file. @@ -339,7 +405,10 @@ def load_config(self, config): config[CYCLIC_PLAYBACK] = config_file.getboolean(FILE_BROWSER, CYCLIC_PLAYBACK) config[HIDE_FOLDER_NAME] = config_file.getboolean(FILE_BROWSER, HIDE_FOLDER_NAME) config[FOLDER_IMAGE_SCALE_RATIO] = float(config_file.get(FILE_BROWSER, FOLDER_IMAGE_SCALE_RATIO)) - + config[FILE_BROWSER_ROWS] = config_file.getint(FILE_BROWSER, FILE_BROWSER_ROWS) + config[FILE_BROWSER_COLUMNS] = config_file.getint(FILE_BROWSER, FILE_BROWSER_COLUMNS) + config[ALIGN_BUTTON_CONTENT_X] = config_file.get(FILE_BROWSER, ALIGN_BUTTON_CONTENT_X) + c = {USE_LIRC : config_file.getboolean(USAGE, USE_LIRC)} c[USE_TOUCHSCREEN] = config_file.getboolean(USAGE, USE_TOUCHSCREEN) c[USE_MOUSE] = config_file.getboolean(USAGE, USE_MOUSE) @@ -354,6 +423,7 @@ def load_config(self, config): c[USE_AUTO_PLAY] = config_file.getboolean(USAGE, USE_AUTO_PLAY) c[USE_LONG_PRESS_TIME] = config_file.getint(USAGE, USE_LONG_PRESS_TIME) c[USE_POWEROFF] = config_file.getboolean(USAGE, USE_POWEROFF) + c[USE_CHECK_FOR_UPDATES] = config_file.getboolean(USAGE, USE_CHECK_FOR_UPDATES) config[USAGE] = c if not config_file.getboolean(LOGGING, ENABLE_STDOUT): @@ -362,6 +432,7 @@ def load_config(self, config): c[FILE_LOGGING] = config_file.getboolean(LOGGING, FILE_LOGGING) c[CONSOLE_LOGGING] = config_file.getboolean(LOGGING, CONSOLE_LOGGING) + c[ENABLE_STDOUT] = config_file.getboolean(LOGGING, ENABLE_STDOUT) c[LOG_FILENAME] = config_file.get(LOGGING, LOG_FILENAME) config[FILE_LOGGING] = c[FILE_LOGGING] config[SHOW_MOUSE_EVENTS] = config_file.getboolean(LOGGING, SHOW_MOUSE_EVENTS) @@ -369,7 +440,10 @@ def load_config(self, config): log_handlers = [] if c[FILE_LOGGING]: - log_handlers.append(logging.FileHandler(filename=c[LOG_FILENAME], mode='w')) + try: + log_handlers.append(logging.FileHandler(filename=c[LOG_FILENAME], mode='w')) + except: + pass if c[CONSOLE_LOGGING]: log_handlers.append(logging.StreamHandler(sys.stdout)) if len(log_handlers) > 0: @@ -398,6 +472,8 @@ def load_config(self, config): c[STREAM] = config_file.getboolean(HOME_MENU, STREAM) c[CD_PLAYER] = config_file.getboolean(HOME_MENU, CD_PLAYER) c[PODCASTS] = config_file.getboolean(HOME_MENU, PODCASTS) + c[AIRPLAY] = config_file.getboolean(HOME_MENU, AIRPLAY) + c[SPOTIFY_CONNECT] = config_file.getboolean(HOME_MENU, SPOTIFY_CONNECT) config[HOME_MENU] = c c = {EQUALIZER: config_file.getboolean(HOME_NAVIGATOR, EQUALIZER)} @@ -414,6 +490,7 @@ def load_config(self, config): c[VOICE_ASSISTANT_CREDENTIALS] = config_file.get(VOICE_ASSISTANT, VOICE_ASSISTANT_CREDENTIALS) c[VOICE_DEVICE_MODEL_ID] = config_file.get(VOICE_ASSISTANT, VOICE_DEVICE_MODEL_ID) c[VOICE_DEVICE_ID] = config_file.get(VOICE_ASSISTANT, VOICE_DEVICE_ID) + c[VOICE_COMMAND_DISPLAY_TIME] = float(config_file.get(VOICE_ASSISTANT, VOICE_COMMAND_DISPLAY_TIME)) config[VOICE_ASSISTANT] = c c = {COLOR_WEB_BGR : self.get_color_tuple(config_file.get(COLORS, COLOR_WEB_BGR))} @@ -432,6 +509,16 @@ def load_config(self, config): c[STARTUP] = config_file.get(SCRIPTS, STARTUP) c[SHUTDOWN] = config_file.get(SCRIPTS, SHUTDOWN) config[SCRIPTS] = c + + c = {} + c[GPIO_VOLUME_UP] = config_file.getint(ROTARY_ENCODERS, GPIO_VOLUME_UP) + c[GPIO_VOLUME_DOWN] = config_file.getint(ROTARY_ENCODERS, GPIO_VOLUME_DOWN) + c[GPIO_MUTE] = config_file.getint(ROTARY_ENCODERS, GPIO_MUTE) + c[GPIO_MOVE_LEFT] = config_file.getint(ROTARY_ENCODERS, GPIO_MOVE_LEFT) + c[GPIO_MOVE_RIGHT] = config_file.getint(ROTARY_ENCODERS, GPIO_MOVE_RIGHT) + c[GPIO_SELECT] = config_file.getint(ROTARY_ENCODERS, GPIO_SELECT) + c[JITTER_FILTER] = config_file.getint(ROTARY_ENCODERS, JITTER_FILTER) + config[ROTARY_ENCODERS] = c c = {CLOCK: config_file.getboolean(SCREENSAVER_MENU, CLOCK)} c[LOGO] = config_file.getboolean(SCREENSAVER_MENU, LOGO) @@ -442,6 +529,24 @@ def load_config(self, config): c[LYRICS] = config_file.getboolean(SCREENSAVER_MENU, LYRICS) c[RANDOM] = config_file.getboolean(SCREENSAVER_MENU, RANDOM) config[SCREENSAVER_MENU] = c + + c = {} + items = config_file.items(LANGUAGES_MENU) + languages = dict(items) + lang_dict = {} + for key in languages.keys(): + v = languages[key] + if key == "english-usa": + key = "English-USA" + else: + key = key.capitalize() + + if v == "True": + lang_dict[key] = True + else: + lang_dict[key] = False + + config[LANGUAGES_MENU] = lang_dict def load_players(self, config): """ Loads and parses configuration file players.txt. @@ -478,6 +583,8 @@ def load_players(self, config): c.update(current_player) config[AUDIO] = c + config[PLAYERS] = self.get_players() + def get_player_config(self, player_name, platform, config_file): section_name = player_name + "." + platform c = {} @@ -487,12 +594,20 @@ def get_player_config(self, player_name, platform, config_file): except: pass - c[SERVER_COMMAND] = config_file.get(section_name, SERVER_COMMAND) + c[SERVER_START_COMMAND] = config_file.get(section_name, SERVER_START_COMMAND) + + try: + c[SERVER_STOP_COMMAND] = config_file.get(section_name, SERVER_STOP_COMMAND) + except: + c[SERVER_STOP_COMMAND] = None + c[CLIENT_NAME] = config_file.get(section_name, CLIENT_NAME) + try: c[STREAM_CLIENT_PARAMETERS] = config_file.get(section_name, STREAM_CLIENT_PARAMETERS) except: pass + try: c[STREAM_SERVER_PARAMETERS] = config_file.get(section_name, STREAM_SERVER_PARAMETERS) except: @@ -507,12 +622,14 @@ def get_players(self): players[AUDIO]["music.folder.linux"] = config_file.get(AUDIO, MUSIC_FOLDER + "." + LINUX_PLATFORM) players[AUDIO]["music.folder.windows"] = config_file.get(AUDIO, MUSIC_FOLDER + "." + WINDOWS_PLATFORM) players[AUDIO][PLAYER_NAME] = config_file.get(AUDIO, PLAYER_NAME) - players["vlc" + "." + LINUX_PLATFORM] = self.get_player_config("vlc", LINUX_PLATFORM, config_file) - players["vlc" + "." + WINDOWS_PLATFORM] = self.get_player_config("vlc", WINDOWS_PLATFORM, config_file) - players["mpd" + "." + LINUX_PLATFORM] = self.get_player_config("mpd", LINUX_PLATFORM, config_file) - players["mpd" + "." + WINDOWS_PLATFORM] = self.get_player_config("mpd", WINDOWS_PLATFORM, config_file) - players["mplayer" + "." + LINUX_PLATFORM] = self.get_player_config("mplayer", LINUX_PLATFORM, config_file) - players["mplayer" + "." + WINDOWS_PLATFORM] = self.get_player_config("mplayer", WINDOWS_PLATFORM, config_file) + players[VLC_NAME + "." + LINUX_PLATFORM] = self.get_player_config(VLC_NAME, LINUX_PLATFORM, config_file) + players[VLC_NAME + "." + WINDOWS_PLATFORM] = self.get_player_config(VLC_NAME, WINDOWS_PLATFORM, config_file) + players[MPD_NAME + "." + LINUX_PLATFORM] = self.get_player_config(MPD_NAME, LINUX_PLATFORM, config_file) + players[MPD_NAME + "." + WINDOWS_PLATFORM] = self.get_player_config(MPD_NAME, WINDOWS_PLATFORM, config_file) + players[MPLAYER_NAME + "." + LINUX_PLATFORM] = self.get_player_config(MPLAYER_NAME, LINUX_PLATFORM, config_file) + players[MPLAYER_NAME + "." + WINDOWS_PLATFORM] = self.get_player_config(MPLAYER_NAME, WINDOWS_PLATFORM, config_file) + players[SHAIRPORT_SYNC_NAME + "." + LINUX_PLATFORM] = self.get_player_config(SHAIRPORT_SYNC_NAME, LINUX_PLATFORM, config_file) + players[RASPOTIFY_NAME + "." + LINUX_PLATFORM] = self.get_player_config(RASPOTIFY_NAME, LINUX_PLATFORM, config_file) return players def save_players(self, parameters): @@ -520,7 +637,7 @@ def save_players(self, parameters): config_parser = ConfigParser() config_parser.optionxform = str - config_parser.read_file(codecs.open(FILE_PLAYERS, "r", UTF8)) + config_parser.read(FILE_PLAYERS, encoding=UTF8) keys = list(parameters.keys()) for key in keys: @@ -540,7 +657,7 @@ def load_current(self, config): """ config_file = ConfigParser() config_file.optionxform = str - config_file.read_file(codecs.open(FILE_CURRENT, "r", UTF8)) + config_file.read(FILE_CURRENT, encoding=UTF8) m = config_file.get(CURRENT, MODE) c = {MODE : m} @@ -598,10 +715,11 @@ def load_current(self, config): pass c[PAUSE] = False - try: - c[PAUSE] = config_file.getboolean(PLAYER_SETTINGS, PAUSE) - except: - pass + # TODO fix during refactoring + # try: + # c[PAUSE] = config_file.getboolean(PLAYER_SETTINGS, PAUSE) + # except: + # pass config[PLAYER_SETTINGS] = c @@ -715,7 +833,7 @@ def save_current_settings(self): config_parser = ConfigParser() config_parser.optionxform = str - config_parser.read_file(codecs.open(FILE_CURRENT, "r", UTF8)) + config_parser.read(FILE_CURRENT, encoding=UTF8) a = b = c = d = e = f = g = h = stations_changed = None @@ -770,9 +888,9 @@ def load_config_parameters(self): :return: dictionary of parameters """ - params = {} - self.load_languages(params) + params = {RELEASE: self.load_release()} self.load_config(params) + self.load_languages(params) self.load_players(params) self.load_current(params) return params @@ -782,7 +900,7 @@ def save_config_parameters(self, parameters): config_parser = ConfigParser() config_parser.optionxform = str - config_parser.read_file(codecs.open(FILE_CONFIG, "r", UTF8)) + config_parser.read(FILE_CONFIG, encoding=UTF8) keys = list(parameters.keys()) for key in keys: diff --git a/util/fileutil.py b/util/fileutil.py index 9299ae14..9325a452 100644 --- a/util/fileutil.py +++ b/util/fileutil.py @@ -44,12 +44,13 @@ class FileUtil(object): """ Utility class containing methods necessary for file playback """ - def __init__(self, config): + def __init__(self, util): """ Initializer - :param config: configuration object + :param util: utility object """ - self.config = config + self.util = util + self.config = util.config self.platform = platform.system().lower() self.ROOT = os.path.abspath(os.sep) if WINDOWS in self.platform: @@ -157,6 +158,10 @@ def get_folder_content(self, folder_name): elif os.path.isfile(file_path) and not f.startswith("."): # file if self.is_audio_file(f): state.file_type = FILE_AUDIO + if self.util.get_image_from_audio_file(file_path): + state.has_embedded_image = True + else: + state.has_embedded_image = False files.append(state) elif self.is_playlist_file(f): # had issues with mplayer and cue files: diff --git a/util/keys.py b/util/keys.py index 666c83ac..eb19afd7 100644 --- a/util/keys.py +++ b/util/keys.py @@ -106,6 +106,8 @@ KEY_CONNECTING = "connecting" KEY_DISCONNECTING = "disconnecting" KEY_START_SAVER = "start-saver" +KEY_AIRPLAY_PLAYER = "airplay.player" +KEY_SPOTIFY_CONNECT_PLAYER = "spotify.connect.player" KEY_0 = "0" KEY_1 = "1" KEY_2 = "2" @@ -120,6 +122,7 @@ KEY_VA_STOP = "va stop" KEY_VOICE_COMMAND = "voice_command" KEY_AUDIO = "audio" +KEY_SUBTITLE = "subtitle" KEY_DELETE = "delete" KEY_VIEW = "view" KEY_DISCONNECT = "disconnect" @@ -180,6 +183,7 @@ KEY_ROOT: pygame.K_r, KEY_PARENT: pygame.K_p, KEY_AUDIO: pygame.K_a, + KEY_SUBTITLE: pygame.K_n, KEY_0: pygame.K_0, KEY_1: pygame.K_1, KEY_2: pygame.K_2, diff --git a/util/podcastsutil.py b/util/podcastsutil.py index fb49fc68..60c3b311 100644 --- a/util/podcastsutil.py +++ b/util/podcastsutil.py @@ -206,7 +206,9 @@ def get_podcasts(self, page, page_size): except: pass - result[link] = self.get_podcast_info(i, link) + r = self.get_podcast_info(i, link) + if r: + result[link] = r return result @@ -220,9 +222,13 @@ def get_podcast_info(self, index, podcast_url): """ try: response = requests.get(podcast_url) - rss = feedparser.parse(response.content) + if response.status_code == 404: + return None + rss = feedparser.parse(response.content) + if rss and getattr(rss, "bozo_exception", None): + return None except: - return + return None s = State() s.index = index @@ -243,7 +249,7 @@ def get_podcast_info(self, index, podcast_url): img = '' s.image_name = img - s.icon_base = self.get_podcast_image(img, 0.5, 0.8, self.podcast_button_bb) + s.icon_base = self.get_podcast_image(img, 0.48, 0.8, self.podcast_button_bb) self.summary_cache[s.url] = s return s diff --git a/util/util.py b/util/util.py index 55ee29f1..a14d8039 100644 --- a/util/util.py +++ b/util/util.py @@ -24,13 +24,16 @@ import hashlib import pygame import collections +import urllib from subprocess import Popen, PIPE from zipfile import ZipFile +from mutagen.id3 import ID3 +from mutagen.flac import FLAC from ui.state import State from util.config import Config, USAGE, USE_VOICE_ASSISTANT, COLORS, COLOR_DARK, FONT_KEY, CURRENT, FILE_LABELS, \ LANGUAGE, FILE_PLAYBACK, NAME, KEY_SCREENSAVER_DELAY_1, KEY_SCREENSAVER_DELAY_3, KEY_SCREENSAVER_DELAY_OFF, \ - FOLDER_LANGUAGES, FILE_FLAG, FOLDER_RADIO_STATIONS, UTF8, FILE_VOICE_COMMANDS, SCREENSAVER_MENU, USE_WEB, \ + FOLDER_LANGUAGES, FILE_FLAG, FOLDER_RADIO_STATIONS, FILE_VOICE_COMMANDS, SCREENSAVER_MENU, USE_WEB, \ FILE_WEATHER_CONFIG, EQUALIZER, SCREEN_INFO, WIDTH, HEIGHT, COLOR_BRIGHT, COLOR_CONTRAST, COLOR_DARK_LIGHT, \ COLOR_MUTE, SCRIPTS, FILE_BROWSER, FOLDER_IMAGE_SCALE_RATIO, HIDE_FOLDER_NAME from util.keys import * @@ -77,8 +80,11 @@ EXT_PROPERTIES = ".properties" EXT_PNG = ".png" +EXT_JPG = ".jpg" EXT_SVG = ".svg" EXT_M3U = ".m3u" +EXT_MP3 = ".mp3" +EXT_FLAC = ".flac" FOLDER_ICONS = "icons" FOLDER_SLIDES = "slides" @@ -106,7 +112,6 @@ UTF_8 = "utf-8-sig" FOLDER_BUNDLES = "bundles" FOLDER_VOICE_ASSISTANT = "voiceassistant" -FOLDER_VOICE_COMMANDS = "voicecommands" DEFAULT_CD_IMAGE = "cd.png" SVG_DEFAULT_COLOR = "#808080" NUMBERS = { @@ -143,7 +148,7 @@ def __init__(self, connected_to_internet): self.config[LABELS] = self.get_labels() self.weather_config = self.get_weather_config() self.pygame_screen = self.config_class.pygame_screen - self.file_util = FileUtil(self.config) + self.file_util = FileUtil(self) self.CURRENT_WORKING_DIRECTORY = os.getcwd() self.read_storage() self.discogs_util = DiscogsUtil(self.k1) @@ -246,27 +251,29 @@ def load_image(self, path, base64=False, bounding_box=None): else: return self.load_pygame_image(path, bounding_box) - def load_pygame_image(self, path, bounding_box=None): + def load_pygame_image(self, path, bounding_box=None, use_cache=True): """ Load image. First, check if image is in the cache. If yes, return the image from the cache. If not load image file and place it in the cache. :param path: image path - :param bounding_box: bounding box + :param bounding_box: bounding box + :param use_cache: True - use cache, False - don't use cache :return: tuple where the first element is the path to the image and the second element is the image itself """ image = None - - try: - p = path - if bounding_box: - p = path + str(bounding_box[0]) - i = self.image_cache[p] - return (path, i) - except KeyError: - pass + + if use_cache: + try: + p = path + if bounding_box: + p = path + str(bounding_box[0]) + i = self.image_cache[p] + return (path, i) + except KeyError: + pass try: image = pygame.image.load(path.encode("utf-8")).convert_alpha() @@ -280,11 +287,76 @@ def load_pygame_image(self, path, bounding_box=None): scale_ratio = self.get_scale_ratio(bounding_box, img) img = self.scale_image(image, scale_ratio) p = path + str(bounding_box[0]) - self.image_cache[p] = img + if use_cache: + self.image_cache[p] = img return (path, img) else: return None - + + def get_image_from_audio_file(self, filename, return_buffer=False): + """ Fetch image from audio file. Only MP3 and FLAC supported + + :param filename: file name + :param return_buffer: True - return image buffer, False - return Pygame image + :return: image or None if not found + """ + if not filename: return None + + name = filename.lower() + + if name.endswith(EXT_MP3): + return self.get_image_from_mp3(filename, return_buffer) + elif name.endswith(EXT_FLAC): + return self.get_image_from_flac(filename, return_buffer) + else: + return None + + def get_image_from_mp3(self, filename, return_buffer=False): + """ Fetch image from mp3 file + + :param filename: file name + :param return_buffer: True - return image buffer, False - return Pygame image + :return: image or None if not found + """ + try: + tags = ID3(filename) + except: + return None + + if tags and tags.get("APIC:"): + try: + data = tags.get("APIC:").data + buffer = BytesIO(data) + if return_buffer: + return buffer + else: + return pygame.image.load(buffer).convert_alpha() + except: + return None + else: + return None + + def get_image_from_flac(self, filename, return_buffer=False): + """ Fetch image from flac file + + :param filename: file name + :param return_buffer: True - return image buffer, False - return Pygame image + :return: image or None if not found + """ + try: + pictures = FLAC(filename).pictures + if pictures: + data = pictures[0].data + buffer = BytesIO(data) + if return_buffer: + return buffer + else: + return pygame.image.load(buffer).convert_alpha() + else: + return None + except: + return None + def get_scale_ratio(self, bounding_box, img, fit_height=False): """ Return scale ratio calculated from provided constraints (bounding box) and image @@ -323,10 +395,11 @@ def get_scale_ratio(self, bounding_box, img, fit_height=False): height = int(height * (min(k1, k2))) return (width, height) - def load_base64_image(self, path): + def load_base64_image(self, path, cache_key=None): """ Load image and encode it using base64 encoding. :param path: image path + :param cache_key: cache key :return: base64 encoded image """ @@ -335,16 +408,27 @@ def load_base64_image(self, path): return img except: pass + + key = path + if cache_key: + key = cache_key if EXT_SVG in path: svg_image = self.svg_cache[path] img = base64.b64encode(svg_image.encode()).decode() - self.image_cache_base64[path] = img + self.image_cache_base64[key] = img return img - else: + else: + if path.lower().endswith(EXT_MP3) or path.lower().endswith(EXT_FLAC): + image_buffer = self.get_image_from_audio_file(path, True) + if image_buffer: + img = base64.b64encode(image_buffer.read()).decode() + self.image_cache_base64[key] = img + return img + with open(path, 'rb') as f: img = base64.b64encode(f.read()).decode() - self.image_cache_base64[path] = img + self.image_cache_base64[key] = img return img def is_cached_svg_image(self, key): @@ -701,6 +785,10 @@ def load_m3u(self, path, folder, top_folder, items_per_page, default_icon_path): name = item_name.rstrip() path = os.path.join(folder, name + EXT_PNG) icon = self.load_image(path) + + if not icon: + path = os.path.join(folder, name + EXT_JPG) + icon = self.load_image(path) if not icon: icon = self.load_image(default_icon_path) @@ -968,9 +1056,8 @@ def load_menu(self, names, comparator, disabled_items=None, v_align=None, bb=Non :return: dictionary with menu items """ items = {} - i = 0 - for name in names: + for i, name in enumerate(names): icon = self.load_mono_svg_icon(name, self.COLOR_MAIN, bb, scale) icon_on = self.load_mono_svg_icon(name, self.COLOR_ON, bb, scale) @@ -1015,19 +1102,8 @@ def load_menu(self, names, comparator, disabled_items=None, v_align=None, bb=Non state.enabled = False state.index = i items[state.name] = state - i += 1 return items - def get_screensaver_labels(self): - """ Return localized screensaver labels - - :return: labels dictionary - """ - screensaver_labels = {} - for name in SCREENSAVER_ITEMS: - screensaver_labels[name.lower()] = self.config[LABELS][name.lower()] - return screensaver_labels - def get_screensaver_delays(self): """ Get screensaver delay button states @@ -1079,18 +1155,20 @@ def run_script(self, script_name): else: s.start_thread() - def get_file_icon(self, file_type, file_image_path=None, icon_bb=None, scale_factor=0.6): - """ Load image representing file. Five types of icons supported: + def get_file_icon(self, file_type, file_image_path=None, icon_bb=None, scale_factor=0.6, url=None): + """ Load image representing file. Six types of icons supported: 1. Folder icon 2. Audio file icon - 3. Folder with folder icon (folder icon will be displayed in this case) - 4. Playlist icon - 5. CD Drive + 3. Image fetched from audio file + 4. Folder with folder icon (folder icon will be displayed in this case) + 5. Playlist icon + 6. CD Drive :param file_type: defines file type :param file_image_path: path to image file :param icon_bb: image bounding box :param scale_factor: scale factor + :param url: file name :return: image representing file """ @@ -1103,18 +1181,27 @@ def get_file_icon(self, file_type, file_image_path=None, icon_bb=None, scale_fac icon_file_audio = self.load_mono_svg_icon(ICON_FILE_AUDIO, self.COLOR_MAIN, bb, scale_factor) icon_file_playlist = self.load_mono_svg_icon(ICON_FILE_PLAYLIST, self.COLOR_MAIN, bb, scale_factor) icon_cd_drive = self.load_mono_svg_icon(ICON_CD_DRIVE, self.COLOR_MAIN, bb, scale_factor) - + + scale_ratio = self.config[FOLDER_IMAGE_SCALE_RATIO] + if icon_bb: + if self.config[HIDE_FOLDER_NAME]: + bb = (icon_bb[0], ((icon_bb[1] * (1 / 0.7)) * scale_ratio) - 1) + else: + bb = (icon_bb[0] * scale_ratio, icon_bb[1] * scale_ratio) + if file_type == FOLDER: return icon_folder - elif file_type == FILE_AUDIO: return icon_file_audio + elif file_type == FILE_AUDIO: + img = self.get_image_from_audio_file(url) + if img: + ratio = self.get_scale_ratio(bb, img) + scaled_img = self.scale_image(img, ratio) + return (url, scaled_img) + else: + return icon_file_audio elif file_type == FILE_PLAYLIST: return icon_file_playlist elif file_type == FILE_CD_DRIVE: return icon_cd_drive elif file_type == FOLDER_WITH_ICON or file_type == FILE_IMAGE: - scale_ratio = self.config[FOLDER_IMAGE_SCALE_RATIO] - if self.config[HIDE_FOLDER_NAME]: - bb = (icon_bb[0], ((icon_bb[1] * (1/0.7)) * scale_ratio) - 1) - else: - bb = (icon_bb[0] * scale_ratio, icon_bb[1] * scale_ratio) img = self.load_image(file_image_path, bounding_box=bb) if img: return img @@ -1144,7 +1231,7 @@ def load_folder_content(self, folder_name, rows, cols, bounding_box): s.index = index s.name = s.file_name s.l_name = s.name - s.icon_base = self.get_file_icon(s.file_type, getattr(s, "file_image_path", ""), (item_width, item_height)) + s.icon_base = self.get_file_icon(s.file_type, getattr(s, "file_image_path", ""), (item_width, item_height), url=s.url) s.comparator_item = index s.bgr = self.config[COLORS][COLOR_DARK] @@ -1233,21 +1320,27 @@ def get_audio_files_in_folder(self, folder_name): return files - def get_audio_file_icon(self, folder, bb): + def get_audio_file_icon(self, folder, bb, url=None): """ Return audio file icon which is album art image. If it's not available then CD image will be returned. :param folder: folder name :param bb: bounding box - + :param url: audio file name + :return: audio file icon """ + if url: + img = self.get_image_from_audio_file(url) + if img: + ratio = self.get_scale_ratio((bb.w, bb.h), img) + scaled_img = self.scale_image(img, ratio) + return (url, scaled_img) + d = os.path.join(FOLDER_ICONS, DEFAULT_CD_IMAGE) p = self.file_util.get_folder_image_path(folder) if not p: p = d - - img = self.load_image(p, False, (bb.w, bb.h)) - + img = self.load_image(p, False, (bb.w, bb.h)) return (p, img[1]) def get_cd_album_art(self, album, bb): @@ -1378,7 +1471,7 @@ def is_screensaver_available(self): return False def encode_url(self, url): - """ Encode URL using ascii incoding. If doesn't work use UTF-8 encoding + """ Encode URL using ascii encoding. If doesn't work use UTF-8 encoding :param url: input URL :return: encoded URL diff --git a/voiceassistant/googleassistant/googleassistant.py b/voiceassistant/googleassistant/googleassistant.py index 078b32f4..4583fd32 100644 --- a/voiceassistant/googleassistant/googleassistant.py +++ b/voiceassistant/googleassistant/googleassistant.py @@ -145,10 +145,12 @@ def iter_assist_requests(): logging.info('End of audio request detected') self.conversation_stream.stop_recording() if resp.speech_results: - t = ' '.join(r.transcript for r in resp.speech_results) - logging.debug("text: " + t) - if t.strip() in self.commands: - self.notify_text_listeners(t) + received = "" + for r in resp.speech_results: + received = r.transcript.lower().strip() + + if received in self.commands: + self.notify_text_listeners(received) break self.conversation_stream.stop_playback() @@ -206,7 +208,10 @@ def add_start_conversation_listener(self, listener): def notify_start_conversation_listeners(self): """ Notify start conversation listeners """ - + + if not self.run_assistant: + return + for listener in self.start_conversation_listeners: s = State() s.type = USER_EVENT_TYPE diff --git a/voiceassistant/voiceassistant.py b/voiceassistant/voiceassistant.py index edddd9df..961f182e 100644 --- a/voiceassistant/voiceassistant.py +++ b/voiceassistant/voiceassistant.py @@ -117,7 +117,7 @@ def handle_text(self, text): elif text.startswith(self.commands["VA_PAGE_NUMBER"].strip()): self.generate_go_to_page_events(t, self.commands["VA_PAGE_NUMBER"].strip()) elif self.get_number(text) != None: - self.generate_number_events(n) + self.generate_number_events(self.get_number(text)) elif text == self.commands["VA_STOP"].strip(): self.stop() else: diff --git a/voiceassistant/voicecommands/de.properties b/voiceassistant/voicecommands/de.properties deleted file mode 100644 index ba586158..00000000 --- a/voiceassistant/voicecommands/de.properties +++ /dev/null @@ -1,107 +0,0 @@ -VA_RADIO = radio -VA_GO_RADIO = gehe radio -VA_FILES = dateien -VA_GO_FILES = gehe dateien -VA_AUDIO_FILES = audiodateien -VA_AUDIOBOOKS = hörbücher -VA_BOOKS = bücher -VA_GO_BOOKS = gehe bücher -VA_STREAM = strom -VA_GO_STREAM = gehen sie strom -VA_CD_PLAYER = cd player -VA_BACK = zurück -VA_GO_BACK = geh zurück -VA_SCREENSAVER = bildschirmschoner -VA_SAVER = sparer -VA_LANGUAGE = sprache -VA_GO_LANGUAGE = gehe sprache -VA_CHANGE_LANGUAGE = ändern sprache -VA_PLAYER = spieler -VA_GO_PLAYER = gehe spieler -VA_ABOUT = über -VA_GO_ABOUT = gehe über -VA_UP = oben -VA_GO_UP = geh hinauf -VA_DOWN = nieder -VA_GO_DOWN = gehen -VA_LEFT = links -VA_GO_LEFT = geh links -VA_RIGHT = recht -VA_GO_RIGHT = geh rechts -VA_OK = ok -VA_OKAY = okay -VA_ENTER = eingeben -VA_SELECT = wählen -VA_CLOCK = uhr -VA_LOGO = logo -VA_SLIDESHOW = diashow -VA_INDICATOR = indikator -VA_ONE_MINUTE = eine minute -VA_THREE_MINUTES = 3 minuten -VA_OFF = aus -VA_HOME = hause -VA_GO_HOME = nach hause gehen -VA_ENGLISH = englisch -VA_GERMAN = deutsche -VA_FRENCH = französisch -VA_RUSSIAN = russisch -VA_SHUTDOWN = schließen -VA_PLAY = spiel -VA_PAUSE = pause -VA_GENRE = genre -VA_GO_GENRE = genre gehen -VA_MUTE = stumm -VA_VOLUME_UP = lautstärke erhöhen -VA_VOLUME_DOWN = lautstärke runter -VA_PAGE_UP = seite nach oben -VA_PAGE_DOWN = seite nach unten -VA_NEXT_PAGE = nächste seite -VA_PREVIOUS_PAGE = vorherige seite -VA_NEWS = nachrichten -VA_CULTURE = kultur -VA_OLDIES = alte -VA_RETRO = retro -VA_CHILDREN = kinder -VA_CLASSICAL = klassisch -VA_POP = pop -VA_JAZZ = jazz -VA_ROCK = rock -VA_CONTEMPORARY = zeitgenössisch -VA_MUSIC = musik -VA_USER_HOME = benutzer zu Hause -VA_ROOT = root -VA_PARENT = übergeordneter -VA_VOLUME = volumen -VA_TIME = zeit einstellen -VA_TIME_UP = zeit vorbei -VA_TIME_DOWN = zeit runter -VA_NEXT = nächster -VA_PREVIOUS = bisherige -VA_NEW_BOOKS = neue bücher -VA_ABC = a b c -VA_ALPHABET = alphabet -VA_0 = 0 -VA_1 = 1 -VA_2 = 2 -VA_3 = 3 -VA_4 = 4 -VA_5 = 5 -VA_6 = 6 -VA_7 = 7 -VA_8 = 8 -VA_9 = 9 -VA_ZERO = null -VA_ONE = ein -VA_TWO = zwei -VA_THREE = drei -VA_FOUR = vier -VA_FIVE = fünf -VA_SIX = sechs -VA_SEVEN = sieben -VA_EIGHT = acht -VA_NINE = neun -VA_SEARCH_BY_GENRE = suche nach genre -VA_SEARCH_BY_AUTHOR = suche nach autor -VA_GO_TO_PAGE = gehe zur seite -VA_PAGE_NUMBER = seitennummer -VA_STOP = halt diff --git a/voiceassistant/voicecommands/en_us.properties b/voiceassistant/voicecommands/en_us.properties deleted file mode 100644 index f2e51fcc..00000000 --- a/voiceassistant/voicecommands/en_us.properties +++ /dev/null @@ -1,107 +0,0 @@ -VA_RADIO = radio -VA_GO_RADIO = go radio -VA_FILES = files -VA_GO_FILES = go files -VA_AUDIO_FILES = audio files -VA_AUDIOBOOKS = audiobooks -VA_BOOKS = books -VA_GO_BOOKS = go books -VA_STREAM = stream -VA_GO_STREAM = go stream -VA_CD_PLAYER = cd player -VA_BACK = back -VA_GO_BACK = go back -VA_SCREENSAVER = screensaver -VA_SAVER = saver -VA_LANGUAGE = language -VA_GO_LANGUAGE = go language -VA_CHANGE_LANGUAGE = change language -VA_PLAYER = player -VA_GO_PLAYER = go player -VA_ABOUT = about -VA_GO_ABOUT = go about -VA_UP = up -VA_GO_UP = go up -VA_DOWN = down -VA_GO_DOWN = go down -VA_LEFT = left -VA_GO_LEFT = go left -VA_RIGHT = right -VA_GO_RIGHT = go right -VA_OK = ok -VA_OKAY = okay -VA_ENTER = enter -VA_SELECT = select -VA_CLOCK = clock -VA_LOGO = logo -VA_SLIDESHOW = slide show -VA_INDICATOR = indicator -VA_ONE_MINUTE = one minute -VA_THREE_MINUTES = 3 minutes -VA_OFF = off -VA_HOME = home -VA_GO_HOME = go home -VA_ENGLISH = english -VA_GERMAN = german -VA_FRENCH = french -VA_RUSSIAN = russian -VA_SHUTDOWN = shut down -VA_PLAY = play -VA_PAUSE = pause -VA_GENRE = genre -VA_GO_GENRE = go genre -VA_MUTE = mute -VA_VOLUME_UP = volume up -VA_VOLUME_DOWN = volume down -VA_PAGE_UP = page up -VA_PAGE_DOWN = page down -VA_NEXT_PAGE = next page -VA_PREVIOUS_PAGE = previous page -VA_NEWS = news -VA_CULTURE = culture -VA_OLDIES = oldies -VA_RETRO = retro -VA_CHILDREN = children -VA_CLASSICAL = classical -VA_POP = pop -VA_JAZZ = jazz -VA_ROCK = rock -VA_CONTEMPORARY = contemporary -VA_MUSIC = music -VA_USER_HOME = user home -VA_ROOT = root -VA_PARENT = parent -VA_VOLUME = set volume -VA_TIME = time -VA_TIME_UP = increase time -VA_TIME_DOWN = decrease time -VA_NEXT = next -VA_PREVIOUS = previous -VA_NEW_BOOKS = new books -VA_ABC = a b c -VA_ALPHABET = alphabet -VA_0 = 0 -VA_1 = 1 -VA_2 = 2 -VA_3 = 3 -VA_4 = 4 -VA_5 = 5 -VA_6 = 6 -VA_7 = 7 -VA_8 = 8 -VA_9 = 9 -VA_ZERO = zero -VA_ONE = one -VA_TWO = two -VA_THREE = three -VA_FOUR = four -VA_FIVE = five -VA_SIX = six -VA_SEVEN = seven -VA_EIGHT = eight -VA_NINE = nine -VA_SEARCH_BY_GENRE = search by genre -VA_SEARCH_BY_AUTHOR = search by author -VA_GO_TO_PAGE = go to page -VA_PAGE_NUMBER = page number -VA_STOP = stop diff --git a/voiceassistant/voicecommands/fr.properties b/voiceassistant/voicecommands/fr.properties deleted file mode 100644 index f5c415ef..00000000 --- a/voiceassistant/voicecommands/fr.properties +++ /dev/null @@ -1,107 +0,0 @@ -VA_RADIO = radio -VA_GO_RADIO = aller à la radio -VA_FILES = des dossiers -VA_GO_FILES = aller fichiers -VA_AUDIO_FILES = fichiers audio -VA_AUDIOBOOKS = audio livre -VA_BOOKS = livre -VA_GO_BOOKS = aller livre -VA_STREAM = courant -VA_GO_STREAM = aller courant -VA_CD_PLAYER = lecteur cd -VA_BACK = arrière -VA_GO_BACK = retourner -VA_SCREENSAVER = économiseur d'écran -VA_SAVER = économiseur -VA_LANGUAGE = langue -VA_GO_LANGUAGE = passer la langue -VA_CHANGE_LANGUAGE = changer la langue -VA_PLAYER = lecteur -VA_GO_PLAYER = lecteur -VA_ABOUT = sur -VA_GO_ABOUT = aller sur -VA_UP = en haut -VA_GO_UP = monter -VA_DOWN = vers le bas -VA_GO_DOWN = descendre -VA_LEFT = à la gauche -VA_GO_LEFT = va à la gauche -VA_RIGHT = à la droite -VA_GO_RIGHT = va à la droite -VA_OK = d'accord -VA_OKAY = d'accord -VA_ENTER = entrer -VA_SELECT = sélectionner -VA_CLOCK = l'horloge -VA_LOGO = logo -VA_SLIDESHOW = diaporama -VA_INDICATOR = indicateur -VA_ONE_MINUTE = une minute -VA_THREE_MINUTES = 3 minutes -VA_OFF = éteindre -VA_HOME = menu d'accueil -VA_GO_HOME = rentrer chez soi -VA_ENGLISH = anglais -VA_GERMAN = allemand -VA_FRENCH = français -VA_RUSSIAN = russe -VA_SHUTDOWN = fermer -VA_PLAY = jouer -VA_PAUSE = pause -VA_GENRE = genre -VA_GO_GENRE = aller genre -VA_MUTE = muet -VA_VOLUME_UP = augmenter le volume -VA_VOLUME_DOWN = diminuer le volume -VA_PAGE_UP = page en haut -VA_PAGE_DOWN = bas de page -VA_NEXT_PAGE = page suivante -VA_PREVIOUS_PAGE = page précédente -VA_NEWS = nouvelles -VA_CULTURE = culture -VA_OLDIES = oldies -VA_RETRO = rétro -VA_CHILDREN = enfants -VA_CLASSICAL = classique -VA_POP = pop -VA_JAZZ = jazz -VA_ROCK = rock -VA_CONTEMPORARY = contemporain -VA_MUSIC = musique -VA_USER_HOME = maison de l'utilisateur -VA_ROOT = racine -VA_PARENT = parent -VA_VOLUME = volume -VA_TIME = régler le temps -VA_TIME_UP = temps écoulé -VA_TIME_DOWN = temps d'arrêt -VA_NEXT = prochain -VA_PREVIOUS = précédent -VA_NEW_BOOKS = nouveaux livres -VA_ABC = a b c -VA_ALPHABET = alphabet -VA_0 = 0 -VA_1 = 1 -VA_2 = 2 -VA_3 = 3 -VA_4 = 4 -VA_5 = 5 -VA_6 = 6 -VA_7 = 7 -VA_8 = 8 -VA_9 = 9 -VA_ZERO = zéro -VA_ONE = un -VA_TWO = deux -VA_THREE = trois -VA_FOUR = quatre -VA_FIVE = cinq -VA_SIX = six -VA_SEVEN = sept -VA_EIGHT = huit -VA_NINE = neuf -VA_SEARCH_BY_GENRE = recherche par genre -VA_SEARCH_BY_AUTHOR = recherche par auteur -VA_GO_TO_PAGE = aller à la page -VA_PAGE_NUMBER = numéro de page -VA_STOP = arrête diff --git a/voiceassistant/voicekeyboardmap.py b/voiceassistant/voicekeyboardmap.py index d250f06b..169aaf2f 100644 --- a/voiceassistant/voicekeyboardmap.py +++ b/voiceassistant/voicekeyboardmap.py @@ -59,10 +59,31 @@ "VA_NEW_BOOKS" : pygame.K_m, "VA_LANGUAGE" : pygame.K_m, "VA_GO_LANGUAGE" : pygame.K_m, - "VA_CHANGE_LANGUAGE" : pygame.K_m, + "VA_CHANGE_LANGUAGE" : pygame.K_m, "VA_SEARCH_BY_GENRE" : pygame.K_r, "VA_GENRE" : pygame.K_m, "VA_PARENT" : pygame.K_p, + "VA_PLAYER" : pygame.K_SPACE, + "VA_GO_PLAYER" : pygame.K_SPACE, + "VA_SCREENSAVER" : pygame.K_s, + "VA_SAVER" : pygame.K_s, + "VA_EQUALIZER" : pygame.K_r, + "VA_TIMER" : pygame.K_a, + "VA_NETWORK" : pygame.K_n, + "VA_FAVORITES" : pygame.K_s, + "VA_REFRESH" : pygame.K_s, + "VA_EJECT" : pygame.p, + "VA_MENU" : pygame.K_m, + "VA_SLEEP" : pygame.K_s, + "VA_SLEEP_NOW" : pygame.K_x, + "VA_POWEROFF" : pygame.K_END, + "VA_WAKE_UP" : pygame.K_ESCAPE, + "VA_WI_FI_NETWORKS" : pygame.K_r, + "VA_DISCONNECT_WI_FI" : pygame.K_p, + "VA_SORT_NETWORKS" : pygame.K_p, + "VA_DELETE_PASSWORD" : pygame.K_p, + "VA_SHOW_PASSWORD" : pygame.K_s, + "VA_HIDE_PASSWORD" : pygame.K_s, "VA_0" : pygame.K_0, "VA_1" : pygame.K_1, "VA_2" : pygame.K_2, @@ -72,8 +93,4 @@ "VA_6" : pygame.K_6, "VA_7" : pygame.K_7, "VA_8" : pygame.K_8, - "VA_9" : pygame.K_9, - "VA_PLAYER" : pygame.K_SPACE, - "VA_GO_PLAYER" : pygame.K_SPACE, - "VA_SCREENSAVER" : pygame.K_s, - "VA_SAVER" : pygame.K_s} + "VA_9" : pygame.K_9} diff --git a/web/client/config/asset-manifest.json b/web/client/config/asset-manifest.json index 0b06b7fe..04223830 100644 --- a/web/client/config/asset-manifest.json +++ b/web/client/config/asset-manifest.json @@ -1,15 +1,15 @@ { "files": { - "main.css": "/static/css/main.34de6062.chunk.css", - "main.js": "/static/js/main.11ba349f.chunk.js", - "main.js.map": "/static/js/main.11ba349f.chunk.js.map", + "main.css": "/static/css/main.498d002a.chunk.css", + "main.js": "/static/js/main.9502bf18.chunk.js", + "main.js.map": "/static/js/main.9502bf18.chunk.js.map", "runtime~main.js": "/static/js/runtime~main.a8a9905a.js", "runtime~main.js.map": "/static/js/runtime~main.a8a9905a.js.map", - "static/js/2.c47a08ee.chunk.js": "/static/js/2.c47a08ee.chunk.js", - "static/js/2.c47a08ee.chunk.js.map": "/static/js/2.c47a08ee.chunk.js.map", + "static/js/2.e845d7c3.chunk.js": "/static/js/2.e845d7c3.chunk.js", + "static/js/2.e845d7c3.chunk.js.map": "/static/js/2.e845d7c3.chunk.js.map", "index.html": "/index.html", - "precache-manifest.765abf9c95596a12236de53253a6f2bf.js": "/precache-manifest.765abf9c95596a12236de53253a6f2bf.js", + "precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js": "/precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js", "service-worker.js": "/service-worker.js", - "static/css/main.34de6062.chunk.css.map": "/static/css/main.34de6062.chunk.css.map" + "static/css/main.498d002a.chunk.css.map": "/static/css/main.498d002a.chunk.css.map" } } \ No newline at end of file diff --git a/web/client/config/index.html b/web/client/config/index.html index 90e8801a..67198335 100644 --- a/web/client/config/index.html +++ b/web/client/config/index.html @@ -1 +1 @@ -Peppy Config
\ No newline at end of file +Peppy Config
\ No newline at end of file diff --git a/web/client/config/precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js b/web/client/config/precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js new file mode 100644 index 00000000..a22c5760 --- /dev/null +++ b/web/client/config/precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js @@ -0,0 +1,22 @@ +self.__precacheManifest = (self.__precacheManifest || []).concat([ + { + "revision": "1980ad754438232e137ea22cdd15f7cf", + "url": "/index.html" + }, + { + "revision": "fbed898a787376ed0c49", + "url": "/static/css/main.498d002a.chunk.css" + }, + { + "revision": "ceda3d684f967a1ea5ef", + "url": "/static/js/2.e845d7c3.chunk.js" + }, + { + "revision": "fbed898a787376ed0c49", + "url": "/static/js/main.9502bf18.chunk.js" + }, + { + "revision": "42ac5946195a7306e2a5", + "url": "/static/js/runtime~main.a8a9905a.js" + } +]); \ No newline at end of file diff --git a/web/client/config/precache-manifest.765abf9c95596a12236de53253a6f2bf.js b/web/client/config/precache-manifest.765abf9c95596a12236de53253a6f2bf.js deleted file mode 100644 index f0c0850e..00000000 --- a/web/client/config/precache-manifest.765abf9c95596a12236de53253a6f2bf.js +++ /dev/null @@ -1,22 +0,0 @@ -self.__precacheManifest = (self.__precacheManifest || []).concat([ - { - "revision": "998ef9a95ef6a8d2bb7897f50db92335", - "url": "/index.html" - }, - { - "revision": "4748ceadc259203a9610", - "url": "/static/css/main.34de6062.chunk.css" - }, - { - "revision": "173afe68feabcae84750", - "url": "/static/js/2.c47a08ee.chunk.js" - }, - { - "revision": "4748ceadc259203a9610", - "url": "/static/js/main.11ba349f.chunk.js" - }, - { - "revision": "42ac5946195a7306e2a5", - "url": "/static/js/runtime~main.a8a9905a.js" - } -]); \ No newline at end of file diff --git a/web/client/config/service-worker.js b/web/client/config/service-worker.js index 39150861..fc3b1f43 100644 --- a/web/client/config/service-worker.js +++ b/web/client/config/service-worker.js @@ -14,7 +14,7 @@ importScripts("https://storage.googleapis.com/workbox-cdn/releases/4.3.1/workbox-sw.js"); importScripts( - "/precache-manifest.765abf9c95596a12236de53253a6f2bf.js" + "/precache-manifest.2009cf7f8f4a7579fdeb2bea7809b8ed.js" ); self.addEventListener('message', (event) => { diff --git a/web/client/config/static/css/main.34de6062.chunk.css.map b/web/client/config/static/css/main.34de6062.chunk.css.map deleted file mode 100644 index d7351b07..00000000 --- a/web/client/config/static/css/main.34de6062.chunk.css.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"sources":["index.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mIAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,uEAEF","file":"main.34de6062.chunk.css","sourcesContent":["body {\n margin: 0;\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\n sans-serif;\n -webkit-font-smoothing: antialiased;\n -moz-osx-font-smoothing: grayscale;\n}\n\ncode {\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\n monospace;\n}\n"]} \ No newline at end of file diff --git a/web/client/config/static/css/main.34de6062.chunk.css b/web/client/config/static/css/main.498d002a.chunk.css similarity index 85% rename from web/client/config/static/css/main.34de6062.chunk.css rename to web/client/config/static/css/main.498d002a.chunk.css index 4ada487c..28e63001 100644 --- a/web/client/config/static/css/main.34de6062.chunk.css +++ b/web/client/config/static/css/main.498d002a.chunk.css @@ -1,2 +1,2 @@ body{margin:0;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}code{font-family:source-code-pro,Menlo,Monaco,Consolas,Courier New,monospace} -/*# sourceMappingURL=main.34de6062.chunk.css.map */ \ No newline at end of file +/*# sourceMappingURL=main.498d002a.chunk.css.map */ \ No newline at end of file diff --git a/web/client/config/static/css/main.498d002a.chunk.css.map b/web/client/config/static/css/main.498d002a.chunk.css.map new file mode 100644 index 00000000..cf9b1078 --- /dev/null +++ b/web/client/config/static/css/main.498d002a.chunk.css.map @@ -0,0 +1 @@ +{"version":3,"sources":["index.css"],"names":[],"mappings":"AAAA,KACE,QAAS,CACT,mIAEY,CACZ,kCAAmC,CACnC,iCACF,CAEA,KACE,uEAEF","file":"main.498d002a.chunk.css","sourcesContent":["body {\r\n margin: 0;\r\n font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", \"Roboto\", \"Oxygen\",\r\n \"Ubuntu\", \"Cantarell\", \"Fira Sans\", \"Droid Sans\", \"Helvetica Neue\",\r\n sans-serif;\r\n -webkit-font-smoothing: antialiased;\r\n -moz-osx-font-smoothing: grayscale;\r\n}\r\n\r\ncode {\r\n font-family: source-code-pro, Menlo, Monaco, Consolas, \"Courier New\",\r\n monospace;\r\n}\r\n"]} \ No newline at end of file diff --git a/web/client/config/static/js/2.c47a08ee.chunk.js b/web/client/config/static/js/2.c47a08ee.chunk.js deleted file mode 100644 index 6773c377..00000000 --- a/web/client/config/static/js/2.c47a08ee.chunk.js +++ /dev/null @@ -1,2 +0,0 @@ -(window.webpackJsonp=window.webpackJsonp||[]).push([[2],[function(e,t,n){"use strict";e.exports=n(124)},function(e,t){function n(){return e.exports=n=Object.assign||function(e){for(var t=1;t=0||Object.prototype.propertyIsEnumerable.call(e,n)&&(a[n]=e[n])}return a}},function(e,t,n){"use strict";function r(e){var t,n,o="";if(e)if("object"===typeof e)if(e.push)for(t=0;t1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function o(e){if(e.type)return e;if("#"===e.charAt(0))return o(function(e){e=e.substr(1);var t=new RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}(e));var t=e.indexOf("("),n=e.substring(0,t);if(-1===["rgb","rgba","hsl","hsla"].indexOf(n))throw new Error(["Material-UI: unsupported `".concat(e,"` color."),"We support the following formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()."].join("\n"));var r=e.substring(t+1,e.length-1).split(",");return{type:n,values:r=r.map(function(e){return parseFloat(e)})}}function a(e){var t=e.type,n=e.values;return-1!==t.indexOf("rgb")?n=n.map(function(e,t){return t<3?parseInt(e,10):e}):-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(t,"(").concat(n.join(", "),")")}function i(e,t){var n=l(e),r=l(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)}function l(e){var t="hsl"===(e=o(e)).type?o(function(e){var t=(e=o(e)).values,n=t[0],r=t[1]/100,i=t[2]/100,l=r*Math.min(i,1-i),u=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(e+n/30)%12;return i-l*Math.max(Math.min(t-3,9-t,1),-1)},s="rgb",c=[Math.round(255*u(0)),Math.round(255*u(8)),Math.round(255*u(4))];return"hsla"===e.type&&(s+="a",c.push(t[3])),a({type:s,values:c})}(e)).values:e.values;return t=t.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)}),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function u(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return l(e)>.5?c(e,t):d(e,t)}function s(e,t){return e=o(e),t=r(t),"rgb"!==e.type&&"hsl"!==e.type||(e.type+="a"),e.values[3]=t,a(e)}function c(e,t){if(e=o(e),t=r(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return a(e)}function d(e,t){if(e=o(e),t=r(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return a(e)}},,function(e,t,n){"use strict";!function e(){if("undefined"!==typeof __REACT_DEVTOOLS_GLOBAL_HOOK__&&"function"===typeof __REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE)try{__REACT_DEVTOOLS_GLOBAL_HOOK__.checkDCE(e)}catch(t){console.error(t)}}(),e.exports=n(125)},function(e,t){e.exports=function(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";function r(){return(r=Object.assign||function(e){for(var t=1;t<+~=|^:(),"'`\s])/g,v="undefined"!==typeof CSS&&CSS.escape,g=function(e){return v?v(e):e.replace(m,"\\$1")},y=function(){function e(e,t,n){this.type="style",this.key=void 0,this.isProcessed=!1,this.style=void 0,this.renderer=void 0,this.renderable=void 0,this.options=void 0;var r=n.sheet,o=n.Renderer;this.key=e,this.options=n,this.style=t,r?this.renderer=r.renderer:o&&(this.renderer=new o)}return e.prototype.prop=function(e,t,n){if(void 0===t)return this.style[e];var r=!!n&&n.force;if(!r&&this.style[e]===t)return this;var o=t;n&&!1===n.process||(o=this.options.jss.plugins.onChangeValue(t,e,this));var a=null==o||!1===o,i=e in this.style;if(a&&!i&&!r)return this;var l=a&&i;if(l?delete this.style[e]:this.style[e]=o,this.renderable&&this.renderer)return l?this.renderer.removeProperty(this.renderable,e):this.renderer.setProperty(this.renderable,e,o),this;var u=this.options.sheet;return u&&u.attached,this},e}(),b=function(e){function t(t,n,r){var o;(o=e.call(this,t,n,r)||this).selectorText=void 0,o.id=void 0,o.renderable=void 0;var a=r.selector,i=r.scoped,u=r.sheet,s=r.generateId;return a?o.selectorText=a:!1!==i&&(o.id=s(Object(l.a)(Object(l.a)(o)),u),o.selectorText="."+g(o.id)),o}Object(i.a)(t,e);var n=t.prototype;return n.applyTo=function(e){var t=this.renderer;if(t){var n=this.toJSON();for(var r in n)t.setProperty(e,r,n[r])}return this},n.toJSON=function(){var e={};for(var t in this.style){var n=this.style[t];"object"!==typeof n?e[t]=n:Array.isArray(n)&&(e[t]=f(n))}return e},n.toString=function(e){var t=this.options.sheet,n=!!t&&t.options.link?Object(r.a)({},e,{allowEmpty:!0}):e;return h(this.selectorText,this.style,n)},Object(a.a)(t,[{key:"selector",set:function(e){if(e!==this.selectorText){this.selectorText=e;var t=this.renderer,n=this.renderable;if(n&&t)t.setSelector(n,e)||t.replaceRule(n,this)}},get:function(){return this.selectorText}}]),t}(y),x={onCreateRule:function(e,t,n){return"@"===e[0]||n.parent&&"keyframes"===n.parent.type?null:new b(e,t,n)}},w={indent:1,children:!0},k=/@([\w-]+)/,S=function(){function e(e,t,n){this.type="conditional",this.at=void 0,this.key=void 0,this.rules=void 0,this.options=void 0,this.isProcessed=!1,this.renderable=void 0,this.key=e;var o=e.match(k);for(var a in this.at=o?o[1]:"unknown",this.options=n,this.rules=new H(Object(r.a)({},n,{parent:this})),t)this.rules.add(a,t[a]);this.rules.process()}var t=e.prototype;return t.getRule=function(e){return this.rules.get(e)},t.indexOf=function(e){return this.rules.indexOf(e)},t.addRule=function(e,t,n){var r=this.rules.add(e,t,n);return r?(this.options.jss.plugins.onProcessRule(r),r):null},t.toString=function(e){if(void 0===e&&(e=w),!1===e.children)return this.key+" {}";var t=this.rules.toString(e);return t?this.key+" {\n"+t+"\n}":""},e}(),C=/@media|@supports\s+/,E={onCreateRule:function(e,t,n){return C.test(e)?new S(e,t,n):null}},O={indent:1,children:!0},T=/@keyframes\s+([\w-]+)/,P=function(){function e(e,t,n){this.type="keyframes",this.at="@keyframes",this.key=void 0,this.name=void 0,this.id=void 0,this.rules=void 0,this.options=void 0,this.isProcessed=!1,this.renderable=void 0;var o=e.match(T);o&&o[1]?this.name=o[1]:this.name="noname",this.key=this.type+"-"+this.name,this.options=n;var a=n.scoped,i=n.sheet,l=n.generateId;for(var u in this.id=!1===a?this.name:g(l(this,i)),this.rules=new H(Object(r.a)({},n,{parent:this})),t)this.rules.add(u,t[u],Object(r.a)({},n,{parent:this}));this.rules.process()}return e.prototype.toString=function(e){if(void 0===e&&(e=O),!1===e.children)return this.at+" "+this.id+" {}";var t=this.rules.toString(e);return t&&(t="\n"+t+"\n"),this.at+" "+this.id+" {"+t+"}"},e}(),j=/@keyframes\s+/,R=/\$([\w-]+)/g,N=function(e,t){return"string"===typeof e?e.replace(R,function(e,n){return n in t?t[n]:e}):e},M=function(e,t,n){var r=e[t],o=N(r,n);o!==r&&(e[t]=o)},_={onCreateRule:function(e,t,n){return"string"===typeof e&&j.test(e)?new P(e,t,n):null},onProcessStyle:function(e,t,n){return"style"===t.type&&n?("animation-name"in e&&M(e,"animation-name",n.keyframes),"animation"in e&&M(e,"animation",n.keyframes),e):e},onChangeValue:function(e,t,n){var r=n.options.sheet;if(!r)return e;switch(t){case"animation":case"animation-name":return N(e,r.keyframes);default:return e}}},A=function(e){function t(){for(var t,n=arguments.length,r=new Array(n),o=0;o=this.index)t.push(e);else for(var r=0;rn)return void t.splice(r,0,e)},t.reset=function(){this.registry=[]},t.remove=function(e){var t=this.registry.indexOf(e);this.registry.splice(t,1)},t.toString=function(e){return this.registry.filter(function(e){return e.attached}).map(function(t){return t.toString(e)}).join("\n")},Object(a.a)(e,[{key:"index",get:function(){return 0===this.registry.length?0:this.registry[this.registry.length-1].options.index}}]),e}(),G=new X,Y="undefined"!==typeof e?e:"undefined"!==typeof self?self:"undefined"!==typeof window?window:{},Q="2f1acc6c3a606b082e5eef5e54414ffb";null==Y[Q]&&(Y[Q]=0);var J=Y[Q]++,Z=function(e){void 0===e&&(e={});var t=0,n=e.minify?"c":"";return function(r,o){t+=1;var a=n,i="";return o&&(a=o.options.classNamePrefix||n,null!=o.options.jss.id&&(i+=o.options.jss.id)),e.minify?""+a+J+i+t:a+r.key+"-"+J+(i&&"-"+i)+"-"+t}},ee=function(e){var t;return function(){return t||(t=e()),t}};function te(e,t){try{return e.attributeStyleMap?e.attributeStyleMap.get(t):e.style.getPropertyValue(t)}catch(n){return""}}function ne(e,t,n){try{var r=n;if(Array.isArray(n)&&(r=f(n,!0),"!important"===n[n.length-1]))return e.style.setProperty(t,r,"important"),!0;e.attributeStyleMap?e.attributeStyleMap.set(t,r):e.style.setProperty(t,r)}catch(o){return!1}return!0}function re(e,t){try{e.attributeStyleMap?e.attributeStyleMap.delete(t):e.style.removeProperty(t)}catch(n){}}function oe(e,t){return e.selectorText=t,e.selectorText===t}var ae=ee(function(){return document.querySelector("head")});function ie(e){var t=G.registry;if(t.length>0){var n=function(e,t){for(var n=0;nt.index&&r.options.insertionPoint===t.insertionPoint)return r}return null}(t,e);if(n&&n.renderer)return{parent:n.renderer.element.parentNode,node:n.renderer.element};if((n=function(e,t){for(var n=e.length-1;n>=0;n--){var r=e[n];if(r.attached&&r.options.insertionPoint===t.insertionPoint)return r}return null}(t,e))&&n.renderer)return{parent:n.renderer.element.parentNode,node:n.renderer.element.nextSibling}}var r=e.insertionPoint;if(r&&"string"===typeof r){var o=function(e){for(var t=ae(),n=0;n0&&void 0!==arguments[0]?arguments[0]:["all"],t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},n=t.duration,r=void 0===n?i.standard:n,u=t.easing,s=void 0===u?a.easeInOut:u,c=t.delay,d=void 0===c?0:c;o()(t,["duration","easing","delay"]);return(Array.isArray(e)?e:[e]).map(function(e){return"".concat(e," ").concat("string"===typeof r?r:l(r)," ").concat(s," ").concat("string"===typeof d?d:l(d))}).join(",")},getAutoHeightDuration:function(e){if(!e)return 0;var t=e/36;return Math.round(10*(4+15*Math.pow(t,.25)+t/5))}}},function(e,t){e.exports=function(e,t){if(!(e instanceof t))throw new TypeError("Cannot call a class as a function")}},function(e,t){function n(e,t){for(var n=0;n=0?r=setTimeout(u,t-s):(r=null,n||(l=e.apply(a,o),a=o=null))}null==t&&(t=100);var s=function(){a=this,o=arguments,i=Date.now();var s=n&&!r;return r||(r=setTimeout(u,t)),s&&(l=e.apply(a,o),a=o=null),l};return s.clear=function(){r&&(clearTimeout(r),r=null)},s.flush=function(){r&&(l=e.apply(a,o),a=o=null,clearTimeout(r),r=null)},s}n.debounce=n,e.exports=n},function(e,t,n){"use strict";n.d(t,"a",function(){return o});var r=n(11);function o(e){for(var t=1;t1&&void 0!==arguments[1]&&arguments[1];return e&&(r(e.value)&&""!==e.value||t&&r(e.defaultValue)&&""!==e.defaultValue)}function a(e){return e.startAdornment}n.d(t,"b",function(){return o}),n.d(t,"a",function(){return a})},function(e,t,n){"use strict";var r="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e},o="object"===("undefined"===typeof window?"undefined":r(window))&&"object"===("undefined"===typeof document?"undefined":r(document))&&9===document.nodeType;t.a=o},function(e,t,n){"use strict";var r=n(0),o=n.n(r);t.a=o.a.createContext(null)},function(e,t,n){"use strict";var r=n(66);n.d(t,"a",function(){return r.a})},function(e,t,n){"use strict";n.r(t);var r=n(54);n.d(t,"default",function(){return r.a})},function(e,t,n){"use strict";n.r(t);var r=n(62);function o(e){return e}var a=n(82),i=n(83),l=n(63),u=n(84),s=n(1),c=n.n(s),d=n(31),f=n.n(d),p=n(32),h=n.n(p),m=n(0),v=n.n(m),g=n(22),y=n(61),b=n(86),x=function(){function e(){var t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};f()(this,e),this.options=t}return h()(e,[{key:"collect",value:function(e){var t=new Map;this.sheetsRegistry=new g.b;var n=Object(b.a)();return v.a.createElement(y.b,c()({sheetsManager:t,serverGenerateClassName:n,sheetsRegistry:this.sheetsRegistry},this.options),e)}},{key:"toString",value:function(){return this.sheetsRegistry?this.sheetsRegistry.toString():""}},{key:"getStyleElement",value:function(e){return v.a.createElement("style",c()({id:"jss-server-side",key:"jss-server-side",dangerouslySetInnerHTML:{__html:this.toString()}},e))}}]),e}(),w=n(100),k=n(64),S=(n(10),n(15),n(67)),C=n(66),E=n(68);var O=function(e){var t=e.children,n=e.theme,r=Object(C.a)(),o=v.a.useMemo(function(){var e=null===r?n:function(e,t){return"function"===typeof t?t(e):c()({},e,t)}(r,n);return null!==r&&e&&(e[E.a]=!0),e},[n,r]);return v.a.createElement(S.a.Provider,{value:o},t)},T=n(46),P=n(85),j=n(2),R=n.n(j),N=n(33),M=n.n(N);function _(){var e=(arguments.length>0&&void 0!==arguments[0]?arguments[0]:{}).defaultTheme;return function(t){var n=v.a.forwardRef(function(n,r){var o=n.innerRef,a=R()(n,["innerRef"]),i=Object(C.a)()||e;return v.a.createElement(t,c()({theme:i,ref:o||r},a))});return M()(n,t),n}}var A=_();n.d(t,"createGenerateClassName",function(){return r.a}),n.d(t,"createStyles",function(){return o}),n.d(t,"getThemeProps",function(){return a.a}),n.d(t,"jssPreset",function(){return i.a}),n.d(t,"makeStyles",function(){return l.a}),n.d(t,"mergeClasses",function(){return u.a}),n.d(t,"ServerStyleSheets",function(){return x}),n.d(t,"styled",function(){return w.a}),n.d(t,"StylesProvider",function(){return k.a}),n.d(t,"ThemeProvider",function(){return O}),n.d(t,"useTheme",function(){return T.a}),n.d(t,"withStyles",function(){return P.a}),n.d(t,"withTheme",function(){return A}),n.d(t,"withThemeCreator",function(){return _})},function(e,t,n){var r=n(38),o=n(139);e.exports=function(e,t){return!t||"object"!==r(t)&&"function"!==typeof t?o(e):t}},function(e,t){function n(t){return e.exports=n=Object.setPrototypeOf?Object.getPrototypeOf:function(e){return e.__proto__||Object.getPrototypeOf(e)},n(t)}e.exports=n},function(e,t,n){var r=n(140);e.exports=function(e,t){if("function"!==typeof t&&null!==t)throw new TypeError("Super expression must either be null or a function");e.prototype=Object.create(t&&t.prototype,{constructor:{value:e,writable:!0,configurable:!0}}),t&&r(e,t)}},function(e,t,n){"use strict";var r=n(14),o=n.n(r),a=n(1),i=n.n(a),l=n(2),u=n.n(l),s=n(27),c=n.n(s),d=n(88),f=(n(15),["xs","sm","md","lg","xl"]);function p(e,t,n){var r;return i()({gutters:function(){var n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{};return i()({paddingLeft:t(2),paddingRight:t(2)},n,o()({},e.up("sm"),i()({paddingLeft:t(3),paddingRight:t(3)},n[e.up("sm")])))},toolbar:(r={minHeight:56},o()(r,"".concat(e.up("xs")," and (orientation: landscape)"),{minHeight:48}),o()(r,e.up("sm"),{minHeight:64}),r)},n)}var h={50:"#e8eaf6",100:"#c5cae9",200:"#9fa8da",300:"#7986cb",400:"#5c6bc0",500:"#3f51b5",600:"#3949ab",700:"#303f9f",800:"#283593",900:"#1a237e",A100:"#8c9eff",A200:"#536dfe",A400:"#3d5afe",A700:"#304ffe"},m={50:"#fce4ec",100:"#f8bbd0",200:"#f48fb1",300:"#f06292",400:"#ec407a",500:"#e91e63",600:"#d81b60",700:"#c2185b",800:"#ad1457",900:"#880e4f",A100:"#ff80ab",A200:"#ff4081",A400:"#f50057",A700:"#c51162"},v={50:"#fafafa",100:"#f5f5f5",200:"#eeeeee",300:"#e0e0e0",400:"#bdbdbd",500:"#9e9e9e",600:"#757575",700:"#616161",800:"#424242",900:"#212121",A100:"#d5d5d5",A200:"#aaaaaa",A400:"#303030",A700:"#616161"},g={50:"#ffebee",100:"#ffcdd2",200:"#ef9a9a",300:"#e57373",400:"#ef5350",500:"#f44336",600:"#e53935",700:"#d32f2f",800:"#c62828",900:"#b71c1c",A100:"#ff8a80",A200:"#ff5252",A400:"#ff1744",A700:"#d50000"},y={black:"#000",white:"#fff"},b=n(17),x={text:{primary:"rgba(0, 0, 0, 0.87)",secondary:"rgba(0, 0, 0, 0.54)",disabled:"rgba(0, 0, 0, 0.38)",hint:"rgba(0, 0, 0, 0.38)"},divider:"rgba(0, 0, 0, 0.12)",background:{paper:y.white,default:v[50]},action:{active:"rgba(0, 0, 0, 0.54)",hover:"rgba(0, 0, 0, 0.08)",hoverOpacity:.08,selected:"rgba(0, 0, 0, 0.14)",disabled:"rgba(0, 0, 0, 0.26)",disabledBackground:"rgba(0, 0, 0, 0.12)"}},w={text:{primary:y.white,secondary:"rgba(255, 255, 255, 0.7)",disabled:"rgba(255, 255, 255, 0.5)",hint:"rgba(255, 255, 255, 0.5)",icon:"rgba(255, 255, 255, 0.5)"},divider:"rgba(255, 255, 255, 0.12)",background:{paper:v[800],default:"#303030"},action:{active:y.white,hover:"rgba(255, 255, 255, 0.1)",hoverOpacity:.1,selected:"rgba(255, 255, 255, 0.2)",disabled:"rgba(255, 255, 255, 0.3)",disabledBackground:"rgba(255, 255, 255, 0.12)"}};function k(e,t,n,r){e[t]||(e.hasOwnProperty(n)?e[t]=e[n]:"light"===t?e.light=Object(b.e)(e.main,r):"dark"===t&&(e.dark=Object(b.a)(e.main,1.5*r)))}function S(e){return Math.round(1e5*e)/1e5}var C={textTransform:"uppercase"},E='"Roboto", "Helvetica", "Arial", sans-serif';function O(e,t){var n="function"===typeof t?t(e):t,r=n.fontFamily,o=void 0===r?E:r,a=n.fontSize,l=void 0===a?14:a,s=n.fontWeightLight,d=void 0===s?300:s,f=n.fontWeightRegular,p=void 0===f?400:f,h=n.fontWeightMedium,m=void 0===h?500:h,v=n.fontWeightBold,g=void 0===v?700:v,y=n.htmlFontSize,b=void 0===y?16:y,x=n.allVariants,w=u()(n,["fontFamily","fontSize","fontWeightLight","fontWeightRegular","fontWeightMedium","fontWeightBold","htmlFontSize","allVariants"]),k=l/14,O=function(e){return"".concat(e/b*k,"rem")},T=function(e,t,n,r,a){return i()({fontFamily:o,fontWeight:e,fontSize:O(t),lineHeight:n},o===E?{letterSpacing:"".concat(S(r/t),"em")}:{},a,x)},P={h1:T(d,96,1,-1.5),h2:T(d,60,1,-.5),h3:T(p,48,1.04,0),h4:T(p,34,1.17,.25),h5:T(p,24,1.33,0),h6:T(m,20,1.6,.15),subtitle1:T(p,16,1.75,.15),subtitle2:T(m,14,1.57,.1),body1:T(p,16,1.5,.15),body2:T(p,14,1.43,.15),button:T(m,14,1.75,.4,C),caption:T(p,12,1.66,.4),overline:T(p,12,2.66,1,C)};return c()(i()({htmlFontSize:b,pxToRem:O,round:S,fontFamily:o,fontSize:l,fontWeightLight:d,fontWeightRegular:p,fontWeightMedium:m,fontWeightBold:g},P),w,{clone:!1})}var T=.2,P=.14,j=.12;function R(){return["".concat(arguments.length<=0?void 0:arguments[0],"px ").concat(arguments.length<=1?void 0:arguments[1],"px ").concat(arguments.length<=2?void 0:arguments[2],"px ").concat(arguments.length<=3?void 0:arguments[3],"px rgba(0,0,0,").concat(T,")"),"".concat(arguments.length<=4?void 0:arguments[4],"px ").concat(arguments.length<=5?void 0:arguments[5],"px ").concat(arguments.length<=6?void 0:arguments[6],"px ").concat(arguments.length<=7?void 0:arguments[7],"px rgba(0,0,0,").concat(P,")"),"".concat(arguments.length<=8?void 0:arguments[8],"px ").concat(arguments.length<=9?void 0:arguments[9],"px ").concat(arguments.length<=10?void 0:arguments[10],"px ").concat(arguments.length<=11?void 0:arguments[11],"px rgba(0,0,0,").concat(j,")")].join(",")}var N=["none",R(0,1,3,0,0,1,1,0,0,2,1,-1),R(0,1,5,0,0,2,2,0,0,3,1,-2),R(0,1,8,0,0,3,4,0,0,3,3,-2),R(0,2,4,-1,0,4,5,0,0,1,10,0),R(0,3,5,-1,0,5,8,0,0,1,14,0),R(0,3,5,-1,0,6,10,0,0,1,18,0),R(0,4,5,-2,0,7,10,1,0,2,16,1),R(0,5,5,-3,0,8,10,1,0,3,14,2),R(0,5,6,-3,0,9,12,1,0,3,16,2),R(0,6,6,-3,0,10,14,1,0,4,18,3),R(0,6,7,-4,0,11,15,1,0,4,20,3),R(0,7,8,-4,0,12,17,2,0,5,22,4),R(0,7,8,-4,0,13,19,2,0,5,24,4),R(0,7,9,-4,0,14,21,2,0,5,26,4),R(0,8,9,-5,0,15,22,2,0,6,28,5),R(0,8,10,-5,0,16,24,2,0,6,30,5),R(0,8,11,-5,0,17,26,2,0,6,32,5),R(0,9,11,-5,0,18,28,2,0,7,34,6),R(0,9,12,-6,0,19,29,2,0,7,36,6),R(0,10,13,-6,0,20,31,3,0,8,38,7),R(0,10,13,-6,0,21,33,3,0,8,40,7),R(0,10,14,-6,0,22,35,3,0,8,42,7),R(0,11,14,-7,0,23,36,3,0,9,44,8),R(0,11,15,-7,0,24,38,3,0,9,46,8)],M={borderRadius:4};var _=n(30),A=n(69);var I=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.breakpoints,n=void 0===t?{}:t,r=e.mixins,o=void 0===r?{}:r,a=e.palette,l=void 0===a?{}:a,s=e.shadows,S=e.spacing,C=e.typography,E=void 0===C?{}:C,T=u()(e,["breakpoints","mixins","palette","shadows","spacing","typography"]),P=function(e){var t=e.primary,n=void 0===t?{light:h[300],main:h[500],dark:h[700]}:t,r=e.secondary,o=void 0===r?{light:m.A200,main:m.A400,dark:m.A700}:r,a=e.error,l=void 0===a?{light:g[300],main:g[500],dark:g[700]}:a,s=e.type,d=void 0===s?"light":s,f=e.contrastThreshold,p=void 0===f?3:f,S=e.tonalOffset,C=void 0===S?.2:S,E=u()(e,["primary","secondary","error","type","contrastThreshold","tonalOffset"]);function O(e){return Object(b.d)(e,w.text.primary)>=p?w.text.primary:x.text.primary}function T(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:500,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:300,r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:700;return!(e=i()({},e)).main&&e[t]&&(e.main=e[t]),k(e,"light",n,C),k(e,"dark",r,C),e.contrastText||(e.contrastText=O(e.main)),e}var P={dark:w,light:x};return c()(i()({common:y,type:d,primary:T(n),secondary:T(o,"A400","A200","A700"),error:T(l),grey:v,contrastThreshold:p,getContrastText:O,augmentColor:T,tonalOffset:C},P[d]),E,{clone:!1})}(l),j=function(e){var t=e.values,n=void 0===t?{xs:0,sm:600,md:960,lg:1280,xl:1920}:t,r=e.unit,o=void 0===r?"px":r,a=e.step,l=void 0===a?5:a,s=u()(e,["values","unit","step"]);function c(e){var t="number"===typeof n[e]?n[e]:e;return"@media (min-width:".concat(t).concat(o,")")}function d(e,t){var r=f.indexOf(t)+1;return r===f.length?c(e):"@media (min-width:".concat(n[e]).concat(o,") and ")+"(max-width:".concat(n[f[r]]-l/100).concat(o,")")}return i()({keys:f,values:n,up:c,down:function(e){var t=f.indexOf(e)+1,r=n[f[t]];return t===f.length?c("xs"):"@media (max-width:".concat(("number"===typeof r&&t>0?r:e)-l/100).concat(o,")")},between:d,only:function(e){return d(e,e)},width:function(e){return n[e]}},s)}(n),R=function(){var e,t=arguments.length>0&&void 0!==arguments[0]?arguments[0]:8;if(t.mui)return t;e="function"===typeof t?t:function(e){return t*e};var n=function(){for(var t=arguments.length,n=new Array(t),r=0;r0&&void 0!==arguments[0]?arguments[0]:{},t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},r=arguments.length>2?arguments[2]:void 0,o=t.pulsate,a=void 0!==o&&o,i=t.center,l=void 0===i?n.props.center||t.pulsate:i,u=t.fakeElement,s=void 0!==u&&u;if("mousedown"===e.type&&n.ignoringMouseDown)n.ignoringMouseDown=!1;else{"touchstart"===e.type&&(n.ignoringMouseDown=!0);var c,d,f,p=s?null:n.container.current,h=p?p.getBoundingClientRect():{width:0,height:0,left:0,top:0};if(l||0===e.clientX&&0===e.clientY||!e.clientX&&!e.touches)c=Math.round(h.width/2),d=Math.round(h.height/2);else{var m=e.clientX?e.clientX:e.touches[0].clientX,v=e.clientY?e.clientY:e.touches[0].clientY;c=Math.round(m-h.left),d=Math.round(v-h.top)}if(l)(f=Math.sqrt((2*Math.pow(h.width,2)+Math.pow(h.height,2))/3))%2===0&&(f+=1);else{var g=2*Math.max(Math.abs((p?p.clientWidth:0)-c),c)+2,y=2*Math.max(Math.abs((p?p.clientHeight:0)-d),d)+2;f=Math.sqrt(Math.pow(g,2)+Math.pow(y,2))}e.touches?(n.startTimerCommit=function(){n.startCommit({pulsate:a,rippleX:c,rippleY:d,rippleSize:f,cb:r})},n.startTimer=setTimeout(function(){n.startTimerCommit&&(n.startTimerCommit(),n.startTimerCommit=null)},ee)):n.startCommit({pulsate:a,rippleX:c,rippleY:d,rippleSize:f,cb:r})}},n.startCommit=function(e){var t=e.pulsate,r=e.rippleX,o=e.rippleY,a=e.rippleSize,i=e.cb;n.setState(function(e){return{nextKey:e.nextKey+1,ripples:[].concat(j()(e.ripples),[c.a.createElement(J,{key:e.nextKey,classes:n.props.classes,timeout:{exit:Z,enter:Z},pulsate:t,rippleX:r,rippleY:o,rippleSize:a})])}},i)},n.stop=function(e,t){if(clearTimeout(n.startTimer),"touchend"===e.type&&n.startTimerCommit)return e.persist(),n.startTimerCommit(),n.startTimerCommit=null,void(n.startTimer=setTimeout(function(){n.stop(e,t)}));n.startTimerCommit=null,n.setState(function(e){var t=e.ripples;return t&&t.length?{ripples:t.slice(1)}:null},t)},n}return z()(t,e),_()(t,[{key:"componentWillUnmount",value:function(){clearTimeout(this.startTimer)}},{key:"render",value:function(){var e=this.props,t=(e.center,e.classes),n=e.className,r=u()(e,["center","classes","className"]);return c.a.createElement("span",o()({className:Object(p.a)(t.root,n),ref:this.container},r),c.a.createElement(Y,{component:null,enter:!0,exit:!0},this.state.ripples))}}]),t}(c.a.PureComponent);te.defaultProps={center:!1};var ne=Object(m.a)(function(e){return{root:{display:"block",position:"absolute",overflow:"hidden",borderRadius:"inherit",width:"100%",height:"100%",left:0,top:0,pointerEvents:"none",zIndex:0},ripple:{opacity:0,position:"absolute"},rippleVisible:{opacity:.3,transform:"scale(1)",animation:"mui-ripple-enter ".concat(Z,"ms ").concat(e.transitions.easing.easeInOut),animationName:"$mui-ripple-enter"},ripplePulsate:{animationDuration:"".concat(e.transitions.duration.shorter,"ms")},child:{opacity:1,display:"block",width:"100%",height:"100%",borderRadius:"50%",backgroundColor:"currentColor"},childLeaving:{opacity:0,animation:"mui-ripple-exit ".concat(Z,"ms ").concat(e.transitions.easing.easeInOut),animationName:"$mui-ripple-exit"},childPulsate:{position:"absolute",left:0,top:0,animation:"mui-ripple-pulsate 2500ms ".concat(e.transitions.easing.easeInOut," 200ms infinite"),animationName:"$mui-ripple-pulsate"},"@keyframes mui-ripple-enter":{"0%":{transform:"scale(0)",opacity:.1},"100%":{transform:"scale(1)",opacity:.3}},"@keyframes mui-ripple-exit":{"0%":{opacity:1},"100%":{opacity:0}},"@keyframes mui-ripple-pulsate":{"0%":{transform:"scale(1)"},"50%":{transform:"scale(0.92)"},"100%":{transform:"scale(1)"}}}},{flip:!1,name:"MuiTouchRipple"})(te),re="undefined"!==typeof window?c.a.useLayoutEffect:c.a.useEffect;function oe(e){var t=c.a.useRef(e);return re(function(){t.current=e}),c.a.useCallback(function(e){return(0,t.current)(e)},[])}var ae=c.a.forwardRef(function(e,t){var n=e.action,r=e.buttonRef,a=e.centerRipple,l=void 0!==a&&a,s=e.children,d=e.classes,m=e.className,v=e.component,y=void 0===v?"button":v,b=e.disabled,x=e.disableRipple,w=void 0!==x&&x,k=e.disableTouchRipple,S=void 0!==k&&k,C=e.focusRipple,E=void 0!==C&&C,O=e.focusVisibleClassName,P=e.onBlur,j=e.onClick,R=e.onFocus,N=e.onFocusVisible,M=e.onKeyDown,_=e.onKeyUp,A=e.onMouseDown,I=e.onMouseLeave,D=e.onMouseUp,F=e.onTouchEnd,L=e.onTouchMove,z=e.onTouchStart,W=e.onDragLeave,B=e.tabIndex,U=void 0===B?0:B,$=e.TouchRippleProps,V=e.type,H=void 0===V?"button":V,q=u()(e,["action","buttonRef","centerRipple","children","classes","className","component","disabled","disableRipple","disableTouchRipple","focusRipple","focusVisibleClassName","onBlur","onClick","onFocus","onFocusVisible","onKeyDown","onKeyUp","onMouseDown","onMouseLeave","onMouseUp","onTouchEnd","onTouchMove","onTouchStart","onDragLeave","tabIndex","TouchRippleProps","type"]),K=c.a.useRef(null);var X=c.a.useRef(null),G=c.a.useState(!1),Y=i()(G,2),Q=Y[0],J=Y[1];b&&Q&&J(!1);var Z=T(),ee=Z.isFocusVisible,te=Z.onBlurVisible,re=Z.ref;function ae(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:S;return oe(function(r){return t&&t(r),!(r.defaultPrevented||n)&&X.current&&X.current[e](r),!0})}c.a.useImperativeHandle(n,function(){return{focusVisible:function(){J(!0),K.current.focus()}}},[]),c.a.useEffect(function(){Q&&E&&!w&&X.current.pulsate()},[w,E,Q]);var ie=ae("start",A),le=ae("stop",W),ue=ae("stop",D),se=ae("stop",function(e){Q&&e.preventDefault(),I&&I(e)}),ce=ae("start",z),de=ae("stop",F),fe=ae("stop",L),pe=ae("stop",function(e){Q&&(te(e),J(!1)),P&&P(e)},!1),he=oe(function(e){b||(K.current||(K.current=e.currentTarget),ee(e)&&(J(!0),N&&N(e)),R&&R(e))}),me=c.a.useRef(!1),ve=oe(function(e){E&&!me.current&&Q&&X.current&&" "===e.key&&(me.current=!0,e.persist(),X.current.stop(e,function(){X.current.start(e)})),M&&M(e);var t=f.a.findDOMNode(K.current);e.target!==e.currentTarget||!y||"button"===y||" "!==e.key&&"Enter"!==e.key||"A"===t.tagName&&t.href||(e.preventDefault(),j&&j(e))}),ge=oe(function(e){E&&" "===e.key&&X.current&&Q&&(me.current=!1,e.persist(),X.current.stop(e,function(){X.current.pulsate(e)})),_&&_(e)}),ye=Object(p.a)(d.root,m,Q&&[d.focusVisible,O],b&&d.disabled),be=y;"button"===be&&q.href&&(be="a");var xe={};"button"===be?(xe.type=H,xe.disabled=b):(xe.role="button",xe["aria-disabled"]=b);var we=Object(h.c)(r,t),ke=Object(h.c)(re,K),Se=Object(h.c)(we,ke);return c.a.createElement(be,o()({className:ye,onBlur:pe,onClick:j,onFocus:he,onKeyDown:ve,onKeyUp:ge,onMouseDown:ie,onMouseLeave:se,onMouseUp:ue,onDragLeave:le,onTouchEnd:de,onTouchMove:fe,onTouchStart:ce,ref:Se,tabIndex:b?-1:U},xe,q),s,w||b?null:c.a.createElement(g,null,c.a.createElement(ne,o()({ref:X,center:l},$))))});t.a=Object(m.a)({root:{display:"inline-flex",alignItems:"center",justifyContent:"center",position:"relative",WebkitTapHighlightColor:"transparent",backgroundColor:"transparent",outline:"none",border:0,margin:0,borderRadius:0,padding:0,cursor:"pointer",userSelect:"none",verticalAlign:"middle","-moz-appearance":"none","-webkit-appearance":"none",textDecoration:"none",color:"inherit","&::-moz-focus-inner":{borderStyle:"none"},"&$disabled":{pointerEvents:"none",cursor:"default"}},disabled:{},focusVisible:{}},{name:"MuiButtonBase"})(ae)},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=r(n(141)),i=r(n(99));var l=function(e,t){var n=function(t){return o.default.createElement(i.default,t,e)};return n.displayName="".concat(t,"Icon"),(n=(0,a.default)(n)).muiName="SvgIcon",n};t.default=l},function(e,t,n){"use strict";e.exports=n(129)},function(e,t,n){"use strict";function r(e,t){return t||(t=e.slice(0)),Object.freeze(Object.defineProperties(e,{raw:{value:Object.freeze(t)}}))}n.d(t,"a",function(){return r})},function(e,t,n){"use strict";(function(e){n.d(t,"b",function(){return tt});var r=n(89),o=n.n(r),a=n(107),i=n.n(a),l=n(0),u=n.n(l),s=n(108),c=n(56),d=n(90),f=(n(10),n(115)),p=n(116),h=function(e,t){for(var n=[e[0]],r=0,o=t.length;r=0||Object.prototype.hasOwnProperty.call(e,r)&&(n[r]=e[r]);return n},w=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==typeof t&&"function"!==typeof t?e:t},k=function(e){return"object"===("undefined"===typeof e?"undefined":m(e))&&e.constructor===Object},S=Object.freeze([]),C=Object.freeze({});function E(e){return"function"===typeof e}function O(e){return e.displayName||e.name||"Component"}function T(e){return e&&"string"===typeof e.styledComponentId}var P="undefined"!==typeof e&&(Object({NODE_ENV:"production",PUBLIC_URL:""}).REACT_APP_SC_ATTR||Object({NODE_ENV:"production",PUBLIC_URL:""}).SC_ATTR)||"data-styled",j="undefined"!==typeof window&&"HTMLElement"in window,R="boolean"===typeof SC_DISABLE_SPEEDY&&SC_DISABLE_SPEEDY||"undefined"!==typeof e&&(Object({NODE_ENV:"production",PUBLIC_URL:""}).REACT_APP_SC_DISABLE_SPEEDY||Object({NODE_ENV:"production",PUBLIC_URL:""}).SC_DISABLE_SPEEDY)||!1;var N=function(e){function t(n){v(this,t);for(var r=arguments.length,o=Array(r>1?r-1:0),a=1;a0?" Additional arguments: "+o.join(", "):"")));return w(i)}return b(t,e),t}(Error),M=/^[^\S\n]*?\/\* sc-component-id:\s*(\S+)\s+\*\//gm,_=function(e){var t=""+(e||""),n=[];return t.replace(M,function(e,t,r){return n.push({componentId:t,matchIndex:r}),e}),n.map(function(e,r){var o=e.componentId,a=e.matchIndex,i=n[r+1];return{componentId:o,cssFromDOM:i?t.slice(a,i.matchIndex):t.slice(a)}})},A=/^\s*\/\/.*$/gm,I=new o.a({global:!1,cascade:!0,keyframe:!1,prefix:!1,compress:!1,semicolon:!0}),D=new o.a({global:!1,cascade:!0,keyframe:!1,prefix:!0,compress:!1,semicolon:!1}),F=[],L=function(e){if(-2===e){var t=F;return F=[],t}},z=i()(function(e){F.push(e)}),W=void 0,B=void 0,U=void 0,$=function(e,t,n){return t>0&&-1!==n.slice(0,t).indexOf(B)&&n.slice(t-B.length,t)!==B?"."+W:e};D.use([function(e,t,n){2===e&&n.length&&n[0].lastIndexOf(B)>0&&(n[0]=n[0].replace(U,$))},z,L]),I.use([z,L]);function V(e,t,n){var r=arguments.length>3&&void 0!==arguments[3]?arguments[3]:"&",o=e.join("").replace(A,""),a=t&&n?n+" "+t+" { "+o+" }":o;return W=r,B=t,U=new RegExp("\\"+B+"\\b","g"),D(n||!t?"":t,a)}var H=function(){return n.nc},q=function(e,t,n){n&&((e[t]||(e[t]=Object.create(null)))[n]=!0)},K=function(e,t){e[t]=Object.create(null)},X=function(e){return function(t,n){return void 0!==e[t]&&e[t][n]}},G=function(e){var t="";for(var n in e)t+=Object.keys(e[n]).join(" ")+" ";return t.trim()},Y=function(e){if(e.sheet)return e.sheet;for(var t=document.styleSheets.length,n=0;n"+e()+""}},te=function(e,t){return function(){var n,r=((n={})[P]=G(t),n["data-styled-version"]="4.3.2",n),o=H();return o&&(r.nonce=o),u.a.createElement("style",y({},r,{dangerouslySetInnerHTML:{__html:e()}}))}},ne=function(e){return function(){return Object.keys(e)}},re=function(e){return document.createTextNode(J(e))},oe=function e(t,n){var r=void 0===t?Object.create(null):t,o=void 0===n?Object.create(null):n,a=function(e){var t=o[e];return void 0!==t?t:o[e]=[""]},i=function(){var e="";for(var t in o){var n=o[t][0];n&&(e+=J(t)+n)}return e};return{clone:function(){var t=function(e){var t=Object.create(null);for(var n in e)t[n]=y({},e[n]);return t}(r),n=Object.create(null);for(var a in o)n[a]=[o[a][0]];return e(t,n)},css:i,getIds:ne(o),hasNameForId:X(r),insertMarker:a,insertRules:function(e,t,n){a(e)[0]+=t.join(" "),q(r,e,n)},removeRules:function(e){var t=o[e];void 0!==t&&(t[0]="",K(r,e))},sealed:!1,styleTag:null,toElement:te(i,r),toHTML:ee(i,r)}},ae=function(e,t,n,r,o){if(j&&!n){var a=function(e,t,n){var r=document.createElement("style");r.setAttribute(P,""),r.setAttribute("data-styled-version","4.3.2");var o=H();if(o&&r.setAttribute("nonce",o),r.appendChild(document.createTextNode("")),e&&!t)e.appendChild(r);else{if(!t||!e||!t.parentNode)throw new N(6);t.parentNode.insertBefore(r,n?t:t.nextSibling)}return r}(e,t,r);return R?function(e,t){var n=Object.create(null),r=Object.create(null),o=void 0!==t,a=!1,i=function(t){var o=r[t];return void 0!==o?o:(r[t]=re(t),e.appendChild(r[t]),n[t]=Object.create(null),r[t])},l=function(){var e="";for(var t in r)e+=r[t].data;return e};return{clone:function(){throw new N(5)},css:l,getIds:ne(r),hasNameForId:X(n),insertMarker:i,insertRules:function(e,r,l){for(var u=i(e),s=[],c=r.length,d=0;d0&&(a=!0,t().insertRules(e+"-import",s))},removeRules:function(i){var l=r[i];if(void 0!==l){var u=re(i);e.replaceChild(u,l),r[i]=u,K(n,i),o&&a&&t().removeRules(i+"-import")}},sealed:!1,styleTag:e,toElement:te(l,n),toHTML:ee(l,n)}}(a,o):function(e,t){var n=Object.create(null),r=Object.create(null),o=[],a=void 0!==t,i=!1,l=function(e){var t=r[e];return void 0!==t?t:(r[e]=o.length,o.push(0),K(n,e),r[e])},u=function(){var t=Y(e).cssRules,n="";for(var a in r){n+=J(a);for(var i=r[a],l=Z(o,i),u=l-o[i];u0&&(i=!0,t().insertRules(r+"-import",h)),o[c]+=p,q(n,r,s)},removeRules:function(l){var u=r[l];if(void 0!==u){var s=o[u];!function(e,t,n){for(var r=t-n,o=t;o>r;o-=1)e.deleteRule(o)}(Y(e),Z(o,u)-1,s),o[u]=0,K(n,l),a&&i&&t().removeRules(l+"-import")}},sealed:!1,styleTag:e,toElement:te(u,n),toHTML:ee(u,n)}}(a,o)}return oe()},ie=/\s+/,le=void 0;le=j?R?40:1e3:-1;var ue=0,se=void 0,ce=function(){function e(){var t=this,n=arguments.length>0&&void 0!==arguments[0]?arguments[0]:j?document.head:null,r=arguments.length>1&&void 0!==arguments[1]&&arguments[1];v(this,e),this.getImportRuleTag=function(){var e=t.importRuleTag;if(void 0!==e)return e;var n=t.tags[0];return t.importRuleTag=ae(t.target,n?n.styleTag:null,t.forceServer,!0)},ue+=1,this.id=ue,this.forceServer=r,this.target=r?null:n,this.tagMap={},this.deferred={},this.rehydratedNames={},this.ignoreRehydratedNames={},this.tags=[],this.capacity=1,this.clones=[]}return e.prototype.rehydrate=function(){if(!j||this.forceServer)return this;var e=[],t=[],n=!1,r=document.querySelectorAll("style["+P+'][data-styled-version="4.3.2"]'),o=r.length;if(!o)return this;for(var a=0;a0&&void 0!==arguments[0]&&arguments[0];se=new e(void 0,t).rehydrate()},e.prototype.clone=function(){var t=new e(this.target,this.forceServer);return this.clones.push(t),t.tags=this.tags.map(function(e){for(var n=e.getIds(),r=e.clone(),o=0;o1?t-1:0),r=1;r=4;)t=1540483477*(65535&(t=255&e.charCodeAt(o)|(255&e.charCodeAt(++o))<<8|(255&e.charCodeAt(++o))<<16|(255&e.charCodeAt(++o))<<24))+((1540483477*(t>>>16)&65535)<<16),r=1540483477*(65535&r)+((1540483477*(r>>>16)&65535)<<16)^(t=1540483477*(65535&(t^=t>>>24))+((1540483477*(t>>>16)&65535)<<16)),n-=4,++o;switch(n){case 3:r^=(255&e.charCodeAt(o+2))<<16;case 2:r^=(255&e.charCodeAt(o+1))<<8;case 1:r=1540483477*(65535&(r^=255&e.charCodeAt(o)))+((1540483477*(r>>>16)&65535)<<16)}return((r=1540483477*(65535&(r^=r>>>13))+((1540483477*(r>>>16)&65535)<<16))^r>>>15)>>>0}var xe=52,we=function(e){return String.fromCharCode(e+(e>25?39:97))};function ke(e){var t="",n=void 0;for(n=e;n>xe;n=Math.floor(n/xe))t=we(n%xe)+t;return we(n%xe)+t}function Se(e,t){for(var n=0;n2&&void 0!==arguments[2]?arguments[2]:C,r=!!n&&e.theme===n.theme;return e.theme&&!r?e.theme:t||n.theme},je=/[[\].#*$><+~=|^:(),"'`-]+/g,Re=/(^-|-$)/g;function Ne(e){return e.replace(je,"-").replace(Re,"")}function Me(e){return"string"===typeof e&&!0}var _e={childContextTypes:!0,contextTypes:!0,defaultProps:!0,displayName:!0,getDerivedStateFromProps:!0,propTypes:!0,type:!0},Ae={name:!0,length:!0,prototype:!0,caller:!0,callee:!0,arguments:!0,arity:!0},Ie=((Ce={})[c.ForwardRef]={$$typeof:!0,render:!0},Ce),De=Object.defineProperty,Fe=Object.getOwnPropertyNames,Le=Object.getOwnPropertySymbols,ze=void 0===Le?function(){return[]}:Le,We=Object.getOwnPropertyDescriptor,Be=Object.getPrototypeOf,Ue=Object.prototype,$e=Array.prototype;function Ve(e,t,n){if("string"!==typeof t){var r=Be(t);r&&r!==Ue&&Ve(e,r,n);for(var o=$e.concat(Fe(t),ze(t)),a=Ie[e.$$typeof]||_e,i=Ie[t.$$typeof]||_e,l=o.length,u=void 0,s=void 0;l--;)if(s=o[l],!Ae[s]&&(!n||!n[s])&&(!i||!i[s])&&(!a||!a[s])&&(u=We(t,s)))try{De(e,s,u)}catch(c){}return e}return e}var He=Object(l.createContext)(),qe=He.Consumer,Ke=(function(e){function t(n){v(this,t);var r=w(this,e.call(this,n));return r.getContext=Object(d.a)(r.getContext.bind(r)),r.renderInner=r.renderInner.bind(r),r}b(t,e),t.prototype.render=function(){return this.props.children?u.a.createElement(He.Consumer,null,this.renderInner):null},t.prototype.renderInner=function(e){var t=this.getContext(this.props.theme,e);return u.a.createElement(He.Provider,{value:t},u.a.Children.only(this.props.children))},t.prototype.getTheme=function(e,t){if(E(e))return e(t);if(null===e||Array.isArray(e)||"object"!==("undefined"===typeof e?"undefined":m(e)))throw new N(8);return y({},t,e)},t.prototype.getContext=function(e,t){return this.getTheme(e,t)}}(l.Component),function(){function e(){v(this,e),this.masterSheet=ce.master,this.instance=this.masterSheet.clone(),this.sealed=!1}e.prototype.seal=function(){if(!this.sealed){var e=this.masterSheet.clones.indexOf(this.instance);this.masterSheet.clones.splice(e,1),this.sealed=!0}},e.prototype.collectStyles=function(e){if(this.sealed)throw new N(2);return u.a.createElement(Ge,{sheet:this.instance},e)},e.prototype.getStyleTags=function(){return this.seal(),this.instance.toHTML()},e.prototype.getStyleElement=function(){return this.seal(),this.instance.toReactElements()},e.prototype.interleaveWithNodeStream=function(e){throw new N(3)}}(),Object(l.createContext)()),Xe=Ke.Consumer,Ge=function(e){function t(n){v(this,t);var r=w(this,e.call(this,n));return r.getContext=Object(d.a)(r.getContext),r}return b(t,e),t.prototype.getContext=function(e,t){if(e)return e;if(t)return new ce(t);throw new N(4)},t.prototype.render=function(){var e=this.props,t=e.children,n=e.sheet,r=e.target;return u.a.createElement(Ke.Provider,{value:this.getContext(n,r)},t)},t}(l.Component),Ye={};var Qe=function(e){function t(){v(this,t);var n=w(this,e.call(this));return n.attrs={},n.renderOuter=n.renderOuter.bind(n),n.renderInner=n.renderInner.bind(n),n}return b(t,e),t.prototype.render=function(){return u.a.createElement(Xe,null,this.renderOuter)},t.prototype.renderOuter=function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:ce.master;return this.styleSheet=e,this.props.forwardedComponent.componentStyle.isStatic?this.renderInner():u.a.createElement(qe,null,this.renderInner)},t.prototype.renderInner=function(e){var t=this.props.forwardedComponent,n=t.componentStyle,r=t.defaultProps,o=(t.displayName,t.foldedComponentIds),a=t.styledComponentId,i=t.target,u=void 0;u=n.isStatic?this.generateAndInjectStyles(C,this.props):this.generateAndInjectStyles(Pe(this.props,e,r)||C,this.props);var s=this.props.as||this.attrs.as||i,c=Me(s),d={},p=y({},this.attrs,this.props),h=void 0;for(h in p)"forwardedComponent"!==h&&"as"!==h&&("forwardedRef"===h?d.ref=p[h]:"forwardedAs"===h?d.as=p[h]:c&&!Object(f.a)(h)||(d[h]=p[h]));return this.props.style&&this.attrs.style&&(d.style=y({},this.attrs.style,this.props.style)),d.className=Array.prototype.concat(o,this.props.className,a,this.attrs.className,u).filter(Boolean).join(" "),Object(l.createElement)(s,d)},t.prototype.buildExecutionContext=function(e,t,n){var r=this,o=y({},t,{theme:e});return n.length?(this.attrs={},n.forEach(function(e){var t,n=e,a=!1,i=void 0,l=void 0;for(l in E(n)&&(n=n(o),a=!0),n)i=n[l],a||!E(i)||(t=i)&&t.prototype&&t.prototype.isReactComponent||T(i)||(i=i(o)),r.attrs[l]=i,o[l]=i}),o):o},t.prototype.generateAndInjectStyles=function(e,t){var n=t.forwardedComponent,r=n.attrs,o=n.componentStyle;n.warnTooManyClasses;return o.isStatic&&!r.length?o.generateAndInjectStyles(C,this.styleSheet):o.generateAndInjectStyles(this.buildExecutionContext(e,t,r),this.styleSheet)},t}(l.Component);function Je(e,t,n){var r=T(e),o=!Me(e),a=t.displayName,i=void 0===a?function(e){return Me(e)?"styled."+e:"Styled("+O(e)+")"}(e):a,l=t.componentId,s=void 0===l?function(e,t,n){var r="string"!==typeof t?"sc":Ne(t),o=(Ye[r]||0)+1;Ye[r]=o;var a=r+"-"+e.generateName(r+o);return n?n+"-"+a:a}(Te,t.displayName,t.parentComponentId):l,c=t.ParentComponent,d=void 0===c?Qe:c,f=t.attrs,h=void 0===f?S:f,m=t.displayName&&t.componentId?Ne(t.displayName)+"-"+t.componentId:t.componentId||s,v=r&&e.attrs?Array.prototype.concat(e.attrs,h).filter(Boolean):h,g=new Te(r?e.componentStyle.rules.concat(n):n,v,m),b=void 0,w=function(e,t){return u.a.createElement(d,y({},e,{forwardedComponent:b,forwardedRef:t}))};return w.displayName=i,(b=u.a.forwardRef(w)).displayName=i,b.attrs=v,b.componentStyle=g,b.foldedComponentIds=r?Array.prototype.concat(e.foldedComponentIds,e.styledComponentId):S,b.styledComponentId=m,b.target=r?e.target:e,b.withComponent=function(e){var r=t.componentId,o=x(t,["componentId"]),a=r&&r+"-"+(Me(e)?e:Ne(O(e)));return Je(e,y({},o,{attrs:v,componentId:a,ParentComponent:d}),n)},Object.defineProperty(b,"defaultProps",{get:function(){return this._foldedDefaultProps},set:function(t){this._foldedDefaultProps=r?Object(p.a)(e.defaultProps,t):t}}),b.toString=function(){return"."+b.styledComponentId},o&&Ve(b,e,{attrs:!0,componentStyle:!0,displayName:!0,foldedComponentIds:!0,styledComponentId:!0,target:!0,withComponent:!0}),b}var Ze=function(e){return function e(t,n){var r=arguments.length>2&&void 0!==arguments[2]?arguments[2]:C;if(!Object(c.isValidElementType)(n))throw new N(1,String(n));var o=function(){return t(n,r,ye.apply(void 0,arguments))};return o.withConfig=function(o){return e(t,n,y({},r,o))},o.attrs=function(o){return e(t,n,y({},r,{attrs:Array.prototype.concat(r.attrs,o).filter(Boolean)}))},o}(Je,e)};["a","abbr","address","area","article","aside","audio","b","base","bdi","bdo","big","blockquote","body","br","button","canvas","caption","cite","code","col","colgroup","data","datalist","dd","del","details","dfn","dialog","div","dl","dt","em","embed","fieldset","figcaption","figure","footer","form","h1","h2","h3","h4","h5","h6","head","header","hgroup","hr","html","i","iframe","img","input","ins","kbd","keygen","label","legend","li","link","main","map","mark","marquee","menu","menuitem","meta","meter","nav","noscript","object","ol","optgroup","option","output","p","param","picture","pre","progress","q","rp","rt","ruby","s","samp","script","section","select","small","source","span","strong","style","sub","summary","sup","table","tbody","td","textarea","tfoot","th","thead","time","title","tr","track","u","ul","var","video","wbr","circle","clipPath","defs","ellipse","foreignObject","g","image","line","linearGradient","marker","mask","path","pattern","polygon","polyline","radialGradient","rect","stop","svg","text","tspan"].forEach(function(e){Ze[e]=Ze(e)});!function(){function e(t,n){v(this,e),this.rules=t,this.componentId=n,this.isStatic=Se(t,S),ce.master.hasId(n)||ce.master.deferredInject(n,[])}e.prototype.createStyles=function(e,t){var n=V(ge(this.rules,e,t),"");t.inject(this.componentId,n)},e.prototype.removeStyles=function(e){var t=this.componentId;e.hasId(t)&&e.remove(t)},e.prototype.renderStyles=function(e,t){this.removeStyles(t),this.createStyles(e,t)}}();j&&(window.scCGSHMRCache={});var et=function(e){return e.replace(/\s|\\n/g,"")};function tt(e){for(var t=arguments.length,n=Array(t>1?t-1:0),r=1;r=0||(o[n]=e[n]);return o}n.d(t,"a",function(){return r})},function(e,t,n){"use strict";var r=n(26);t.a=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:window,n=Object(r.a)(e);return n.defaultView||n.parentView||t}},function(e,t,n){"use strict";t.a=function(){var e=document.createElement("div");e.style.width="99px",e.style.height="99px",e.style.position="absolute",e.style.top="-9999px",e.style.overflow="scroll",document.body.appendChild(e);var t=e.offsetWidth-e.clientWidth;return document.body.removeChild(e),t}},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=(0,r(n(55)).default)(o.default.createElement(o.default.Fragment,null,o.default.createElement("path",{d:"M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"}),o.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"})),"Close");t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=i(n(10)),o=i(n(0)),a=n(148);function i(e){return e&&e.__esModule?e:{default:e}}function l(e){return(l="function"===typeof Symbol&&"symbol"===typeof Symbol.iterator?function(e){return typeof e}:function(e){return e&&"function"===typeof Symbol&&e.constructor===Symbol&&e!==Symbol.prototype?"symbol":typeof e})(e)}function u(){return(u=Object.assign||function(e){for(var t=1;t0&&void 0!==arguments[0]?arguments[0]:"",t=this.props.decimalScale,n=this.getSeparators().decimalSeparator,r=this.getNumberRegex(!0),o="-"===e[0];o&&(e=e.replace("-","")),n&&0===t&&(e=e.split(n)[0]);var i=(e=(e.match(r)||[]).join("").replace(n,".")).indexOf(".");return-1!==i&&(e="".concat(e.substring(0,i),".").concat(e.substring(i+1,e.length).replace(new RegExp((0,a.escapeRegExp)(n),"g"),""))),o&&(e="-"+e),e}},{key:"getNumberRegex",value:function(e,t){var n=this.props,r=n.format,o=n.decimalScale,i=this.getSeparators().decimalSeparator;return new RegExp("\\d"+(!i||0===o||t||r?"":"|"+(0,a.escapeRegExp)(i)),e?"g":void 0)}},{key:"getSeparators",value:function(){var e=this.props.decimalSeparator,t=this.props.thousandSeparator;return!0===t&&(t=","),{decimalSeparator:e,thousandSeparator:t}}},{key:"getMaskAtIndex",value:function(e){var t=this.props.mask,n=void 0===t?" ":t;return"string"===typeof n?n:n[e]||" "}},{key:"getValueObject",value:function(e,t){var n=parseFloat(t);return{formattedValue:e,value:t,floatValue:isNaN(n)?void 0:n}}},{key:"validateProps",value:function(){var e=this.props.mask,t=this.getSeparators(),n=t.decimalSeparator,r=t.thousandSeparator;if(n===r)throw new Error("\n Decimal separator can't be same as thousand separator.\n thousandSeparator: ".concat(r,' (thousandSeparator = {true} is same as thousandSeparator = ",")\n decimalSeparator: ').concat(n," (default value for decimalSeparator is .)\n "));if(e&&("string"===e?e:e.toString()).match(/\d/g))throw new Error("\n Mask ".concat(e," should not contain numeric character;\n "))}},{key:"setPatchedCaretPosition",value:function(e,t,n){(0,a.setCaretPosition)(e,t),setTimeout(function(){e.value===n&&(0,a.setCaretPosition)(e,t)},0)}},{key:"correctCaretPosition",value:function(e,t,n){var r=this.props,o=r.prefix,i=r.suffix,l=r.format;if(""===e)return 0;if(t=(0,a.clamp)(t,0,e.length),!l){var u="-"===e[0];return(0,a.clamp)(t,o.length+(u?1:0),e.length-i.length)}if("function"===typeof l)return t;if("#"===l[t]&&(0,a.charIsNumber)(e[t]))return t;if("#"===l[t-1]&&(0,a.charIsNumber)(e[t-1]))return t;var s=l.indexOf("#"),c=l.lastIndexOf("#");t=(0,a.clamp)(t,s,c+1);for(var d=l.substring(t,l.length).indexOf("#"),f=t,p=t+(-1===d?0:d);f>s&&("#"!==l[f]||!(0,a.charIsNumber)(e[f]));)f-=1;return!(0,a.charIsNumber)(e[p])||"left"===n&&t!==s||t-f0&&void 0!==arguments[0]?arguments[0]:"",t=this.props,n=t.format,r=t.allowEmptyFormatting,o=e;return o=""!==e||r?"-"!==e||n?"string"===typeof n?this.formatWithPattern(o):"function"===typeof n?n(o):this.formatAsNumber(o):"-":""}},{key:"formatValueProp",value:function(e){var t=this.props,n=t.format,r=t.decimalScale,o=t.fixedDecimalScale,i=t.allowEmptyFormatting,l=this.props,u=l.value,s=void 0===u?e:u,c=l.isNumericString,d=!s&&0!==s;return d&&i&&(s=""),d&&!i?"":("number"===typeof s&&(s=s.toString(),c=!0),"Infinity"===s&&c&&(s=""),c&&!n&&"number"===typeof r&&(s=(0,a.roundToPrecision)(s,r,o)),c?this.formatNumString(s):this.formatInput(s))}},{key:"formatNegation",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"",t=this.props.allowNegative,n=new RegExp("(-)"),r=new RegExp("(-)(.)*(-)"),o=n.test(e),a=r.test(e);return e=e.replace(/-/g,""),o&&!a&&t&&(e="-"+e),e}},{key:"formatInput",value:function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:"";return this.props.format||(e=this.removePrefixAndSuffix(e),e=this.formatNegation(e)),e=this.removeFormatting(e),this.formatNumString(e)}},{key:"isCharacterAFormat",value:function(e,t){var n=this.props,r=n.format,o=n.prefix,a=n.suffix,i=n.decimalScale,l=n.fixedDecimalScale,u=this.getSeparators().decimalSeparator;return"string"===typeof r&&"#"!==r[e]||!(r||!(e=t.length-a.length||i&&l&&t[e]===u))}},{key:"checkIfFormatGotDeleted",value:function(e,t,n){for(var r=e;rt.length||!n.length||m===v||0===f&&p===t.length||f===g&&p===y)return n;if(this.checkIfFormatGotDeleted(m,v,t)&&(n=t),!o){var b=this.removeFormatting(n),x=(0,a.splitDecimal)(b,i),w=x.beforeDecimal,k=x.afterDecimal,S=x.addNegation,C=e1&&void 0!==arguments[1]?arguments[1]:a.noop,r=e.formattedValue,o=e.input,i=e.numAsString,l=e.caretPos,u=this.props.onValueChange,s=this.state.value;if(o){if(!l){var c=e.inputValue||o.value,d=(0,a.getCurrentCaretPosition)(o);l=this.getCaretPosition(c,r,d)}o.value=r,this.setPatchedCaretPosition(o,l,r)}void 0===i&&(i=this.removeFormatting(r)),r!==s?this.setState({value:r,numAsString:i},function(){u(t.getValueObject(r,i)),n()}):n()}},{key:"onChange",value:function(e){e.persist();var t=e.target,n=t.value,r=this.state,o=this.props,i=o.isAllowed,l=r.value||"",u=(0,a.getCurrentCaretPosition)(t);n=this.correctInputValue(u,l,n);var s=this.formatInput(n)||"",c=this.removeFormatting(s);i(this.getValueObject(s,c))||(s=l),this.updateValue({formattedValue:s,numAsString:c,inputValue:n,input:t},function(){o.onChange(e)})}},{key:"onBlur",value:function(e){var t=this.props,n=this.state,r=t.format,o=t.onBlur,i=n.numAsString,l=n.value;if(this.focusedElm=null,!r){i=(0,a.fixLeadingZero)(i);var u=this.formatNumString(i);if(u!==l)return e.persist(),void this.updateValue({formattedValue:u,numAsString:i},function(){o(e)})}o(e)}},{key:"onKeyDown",value:function(e){var t,n=e.target,r=e.key,o=n.selectionStart,a=n.selectionEnd,i=n.value,l=void 0===i?"":i,u=this.props,s=u.decimalScale,c=u.fixedDecimalScale,d=u.prefix,f=u.suffix,p=u.format,h=u.onKeyDown,m=(u.onValueChange,void 0!==s&&c),v=this.getNumberRegex(!1,m),g=new RegExp("-"),y="string"===typeof p;if(this.selectionBeforeInput={selectionStart:o,selectionEnd:a},"ArrowLeft"===r||"Backspace"===r?t=o-1:"ArrowRight"===r?t=o+1:"Delete"===r&&(t=o),void 0!==t&&o===a){var b=t,x=y?p.indexOf("#"):d.length,w=y?p.lastIndexOf("#")+1:l.length-f.length;if("ArrowLeft"===r||"ArrowRight"===r){var k="ArrowLeft"===r?"left":"right";b=this.correctCaretPosition(l,t,k)}else if("Delete"!==r||v.test(l[t])||g.test(l[t])){if("Backspace"===r&&!v.test(l[t]))if(o<=x+1&&"-"===l[0]&&"undefined"===typeof p){var S=l.substring(1);e.persist(),this.updateValue({formattedValue:S,caretPos:b,input:n})}else if(!g.test(l[t])){for(;!v.test(l[b-1])&&b>x;)b--;b=this.correctCaretPosition(l,b,"left")}}else for(;!v.test(l[b])&&bw)&&(e.preventDefault(),this.setPatchedCaretPosition(n,b,l)),e.isUnitTestRun&&this.setPatchedCaretPosition(n,b,l),this.props.onKeyDown(e)}else h(e)}},{key:"onMouseUp",value:function(e){var t=e.target,n=t.selectionStart,r=t.selectionEnd,o=t.value,a=void 0===o?"":o;if(n===r){var i=this.correctCaretPosition(a,n);i!==n&&this.setPatchedCaretPosition(t,i,a)}this.props.onMouseUp(e)}},{key:"onFocus",value:function(e){var t=this;e.persist(),this.focusedElm=e.target,setTimeout(function(){var n=e.target,r=n.selectionStart,o=n.selectionEnd,a=n.value,i=void 0===a?"":a,l=t.correctCaretPosition(i,r);l===r||0===r&&o===i.length||t.setPatchedCaretPosition(n,l,i),t.props.onFocus(e)},0)}},{key:"render",value:function(){var e=this.props,t=e.type,n=e.displayType,r=e.customInput,i=e.renderText,l=e.getInputRef,s=this.state.value,c=(0,a.omit)(this.props,p),d=u({},c,{type:t,value:s,onChange:this.onChange,onKeyDown:this.onKeyDown,onMouseUp:this.onMouseUp,onFocus:this.onFocus,onBlur:this.onBlur});if("text"===n)return i?i(s)||null:o.default.createElement("span",u({},c,{ref:l}),s);if(r){var f=r;return o.default.createElement(f,d)}return o.default.createElement("input",u({},d,{ref:l}))}}])&&s(n.prototype,r),i&&s(n,i),t}();m.propTypes=p,m.defaultProps=h;var v=m;t.default=v,e.exports=t.default},function(e,t,n){"use strict";var r=n(22),o=Date.now(),a="fnValues"+o,i="fnStyle"+ ++o;var l=function(){return{onCreateRule:function(e,t,n){if("function"!==typeof t)return null;var o=Object(r.d)(e,{},n);return o[i]=t,o},onProcessStyle:function(e,t){if(a in t||i in t)return e;var n={};for(var r in e){var o=e[r];"function"===typeof o&&(delete e[r],n[r]=o)}return t[a]=n,e},onUpdate:function(e,t,n,r){var o=t,l=o[i];l&&(o.style=l(e));var u=o[a];if(u)for(var s in u)o.prop(s,u[s](e),r)}}},u=n(21),s="@global",c="@global ",d=function(){function e(e,t,n){for(var o in this.type="global",this.at=s,this.rules=void 0,this.options=void 0,this.key=void 0,this.isProcessed=!1,this.key=e,this.options=n,this.rules=new r.a(Object(u.a)({},n,{parent:this})),t)this.rules.add(o,t[o]);this.rules.process()}var t=e.prototype;return t.getRule=function(e){return this.rules.get(e)},t.addRule=function(e,t,n){var r=this.rules.add(e,t,n);return this.options.jss.plugins.onProcessRule(r),r},t.indexOf=function(e){return this.rules.indexOf(e)},t.toString=function(){return this.rules.toString()},e}(),f=function(){function e(e,t,n){this.type="global",this.at=s,this.options=void 0,this.rule=void 0,this.isProcessed=!1,this.key=void 0,this.key=e,this.options=n;var r=e.substr(c.length);this.rule=n.jss.createRule(r,t,Object(u.a)({},n,{parent:this}))}return e.prototype.toString=function(e){return this.rule?this.rule.toString(e):""},e}(),p=/\s*,\s*/g;function h(e,t){for(var n=e.split(p),r="",o=0;o-1){var o=Z[e];if(!Array.isArray(o))return V.js+G(o)in t&&V.css+o;if(!r)return!1;for(var a=0;at?1:-1:e.length-t.length};return{onProcessStyle:function(t,n){if("style"!==n.type)return t;for(var r={},o=Object.keys(t).sort(e),a=0;a1&&void 0!==arguments[1]?arguments[1]:{},n=t.name,r=t.classNamePrefix,a=t.Component,l=t.defaultTheme,m=void 0===l?b:l,v=o()(t,["name","classNamePrefix","Component","defaultTheme"]),g=y(e),x=n||r||"makeStyles";g.options={index:h+=1,name:n,meta:x,classNamePrefix:x};var w=g.themingEnabled||"string"===typeof n;return function(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=(w?Object(f.a)():null)||m,r=i()({},u.a.useContext(p.a),v),o=u.a.useRef(),l=u.a.useRef();return function(e,t){var n,r=u.a.useRef([]),o=u.a.useMemo(function(){return{}},t);r.current!==o&&(r.current=o,n=e()),u.a.useEffect(function(){return function(){n&&n()}},[o])}(function(){var a={name:n,state:{},stylesCreator:g,stylesOptions:r,theme:t};return function(e,t){var n=e.state,r=e.theme,o=e.stylesOptions,a=e.stylesCreator,l=e.name;if(!o.disableGeneration){var u=d.get(o.sheetsManager,a,r);u||(u={refs:0,staticSheet:null,dynamicStyles:null},d.set(o.sheetsManager,a,r,u));var f=i()({},a.options,o,{theme:r,flip:"boolean"===typeof o.flip?o.flip:"rtl"===r.direction});f.generateId=f.serverGenerateClassName||f.generateClassName;var p=o.sheetsRegistry;if(0===u.refs){var h;o.sheetsCache&&(h=d.get(o.sheetsCache,a,r));var m=a.create(r,l);h||((h=o.jss.createStyleSheet(m,i()({link:!1},f))).attach(),o.sheetsCache&&d.set(o.sheetsCache,a,r,h)),p&&p.add(h),u.staticSheet=h,u.dynamicStyles=Object(s.e)(m)}if(u.dynamicStyles){var v=o.jss.createStyleSheet(u.dynamicStyles,i()({link:!0},f));v.update(t).attach(),n.dynamicSheet=v,n.classes=Object(c.a)({baseClasses:u.staticSheet.classes,newClasses:v.classes}),p&&p.add(v)}else n.classes=u.staticSheet.classes;u.refs+=1}}(a,e),l.current=!1,o.current=a,function(){!function(e){var t=e.state,n=e.theme,r=e.stylesOptions,o=e.stylesCreator;if(!r.disableGeneration){var a=d.get(r.sheetsManager,o,n);a.refs-=1;var i=r.sheetsRegistry;0===a.refs&&(d.delete(r.sheetsManager,o,n),r.jss.removeStyleSheet(a.staticSheet),i&&i.remove(a.staticSheet)),t.dynamicSheet&&(r.jss.removeStyleSheet(t.dynamicSheet),i&&i.remove(t.dynamicSheet))}}(a)}},[t,g]),u.a.useEffect(function(){l.current&&function(e,t){var n=e.state;n.dynamicSheet&&n.dynamicSheet.update(t)}(o.current,e),l.current=!0}),function(e,t,n){var r=e.state;if(e.stylesOptions.disableGeneration)return t||{};r.cacheClasses||(r.cacheClasses={value:null,lastProp:null,lastJSS:{}});var o=!1;return r.classes!==r.cacheClasses.lastJSS&&(r.cacheClasses.lastJSS=r.classes,o=!0),t!==r.cacheClasses.lastProp&&(r.cacheClasses.lastProp=t,o=!0),o&&(r.cacheClasses.value=Object(c.a)({baseClasses:r.cacheClasses.lastJSS,newClasses:t,Component:n})),r.cacheClasses.value}(o.current,e.classes,a)}}},function(e,t,n){"use strict";function r(e,t){for(var n=0;n1&&void 0!==arguments[1]?arguments[1]:{};return function(n){var r=t.defaultTheme,a=t.withTheme,l=void 0!==a&&a,s=t.name,h=i()(t,["defaultTheme","withTheme","name"]),m=s,v=Object(d.a)(e,o()({defaultTheme:r,Component:n,name:s||n.displayName,classNamePrefix:m},h)),g=u.a.forwardRef(function(e,t){e.classes;var a,c=e.innerRef,d=i()(e,["classes","innerRef"]),h=v(e),m=d;return("string"===typeof s||l)&&(a=Object(p.a)()||r,s&&(m=Object(f.a)({theme:a,name:s,props:d})),l&&!m.theme&&(m.theme=a)),u.a.createElement(n,o()({ref:c||t,classes:h},m))});return c()(g,n),g}}},function(e,t,n){"use strict";n.d(t,"a",function(){return a});n(15);var r=n(68),o=["checked","disabled","error","focused","focusVisible","required","expanded","selected"];function a(){var e=arguments.length>0&&void 0!==arguments[0]?arguments[0]:{},t=e.disableGlobal,n=void 0!==t&&t,a=e.productionPrefix,i=void 0===a?"jss":a,l=e.seed,u=void 0===l?"":l,s=""===u?"":"".concat(u,"-"),c=0;return function(e,t){c+=1;var a=t.options.name;if(a&&0===a.indexOf("Mui")&&!t.options.link&&!n){if(-1!==o.indexOf(e.key))return"Mui-".concat(e.key);var l="".concat(s).concat(a,"-").concat(e.key);return t.options.theme[r.a]&&""===u?"".concat(l,"-").concat(c):l}return"".concat(s).concat(i).concat(c)}}},function(e,t,n){"use strict";t.a=function(e){var t=e.theme,n=e.name,r=e.props;if(!t||!t.props||!t.props[n])return r;var o,a=t.props[n];for(o in a)void 0===r[o]&&(r[o]=a[o]);return r}},function(e,t,n){"use strict";function r(e){return!0===(null!=(t=e)&&"object"===typeof t&&!1===Array.isArray(t))&&"[object Object]"===Object.prototype.toString.call(e);var t}function o(e){var t,n;return!1!==r(e)&&("function"===typeof(t=e.constructor)&&(!1!==r(n=t.prototype)&&!1!==n.hasOwnProperty("isPrototypeOf")))}n.r(t),n.d(t,"default",function(){return o})},function(e,t,n){e.exports=function e(t){"use strict";var n=/^\0+/g,r=/[\0\r\f]/g,o=/: */g,a=/zoo|gra/,i=/([,: ])(transform)/g,l=/,+\s*(?![^(]*[)])/g,u=/ +\s*(?![^(]*[)])/g,s=/ *[\0] */g,c=/,\r+?/g,d=/([\t\r\n ])*\f?&/g,f=/:global\(((?:[^\(\)\[\]]*|\[.*\]|\([^\(\)]*\))*)\)/g,p=/\W+/g,h=/@(k\w+)\s*(\S*)\s*/,m=/::(place)/g,v=/:(read-only)/g,g=/\s+(?=[{\];=:>])/g,y=/([[}=:>])\s+/g,b=/(\{[^{]+?);(?=\})/g,x=/\s{2,}/g,w=/([^\(])(:+) */g,k=/[svh]\w+-[tblr]{2}/,S=/\(\s*(.*)\s*\)/g,C=/([\s\S]*?);/g,E=/-self|flex-/g,O=/[^]*?(:[rp][el]a[\w-]+)[^]*/,T=/stretch|:\s*\w+\-(?:conte|avail)/,P=/([^-])(image-set\()/,j="-webkit-",R="-moz-",N="-ms-",M=59,_=125,A=123,I=40,D=41,F=91,L=93,z=10,W=13,B=9,U=64,$=32,V=38,H=45,q=95,K=42,X=44,G=58,Y=39,Q=34,J=47,Z=62,ee=43,te=126,ne=0,re=12,oe=11,ae=107,ie=109,le=115,ue=112,se=111,ce=105,de=99,fe=100,pe=112,he=1,me=1,ve=0,ge=1,ye=1,be=1,xe=0,we=0,ke=0,Se=[],Ce=[],Ee=0,Oe=null,Te=-2,Pe=-1,je=0,Re=1,Ne=2,Me=3,_e=0,Ae=1,Ie="",De="",Fe="";function Le(e,t,o,a,i){for(var l,u,c=0,d=0,f=0,p=0,g=0,y=0,b=0,x=0,k=0,C=0,E=0,O=0,T=0,P=0,q=0,xe=0,Ce=0,Oe=0,Te=0,Pe=o.length,We=Pe-1,qe="",Ke="",Xe="",Ge="",Ye="",Qe="";q0&&(Ke=Ke.replace(r,"")),Ke.trim().length>0)){switch(b){case $:case B:case M:case W:case z:break;default:Ke+=o.charAt(q)}b=M}if(1===Ce)switch(b){case A:case _:case M:case Q:case Y:case I:case D:case X:Ce=0;case B:case W:case z:case $:break;default:for(Ce=0,Te=q,g=b,q--,b=M;Te0&&(++q,b=g);case A:Te=Pe}}switch(b){case A:for(g=(Ke=Ke.trim()).charCodeAt(0),E=1,Te=++q;q0&&(Ke=Ke.replace(r,"")),y=Ke.charCodeAt(1)){case fe:case ie:case le:case H:l=t;break;default:l=Se}if(Te=(Xe=Le(t,l,Xe,y,i+1)).length,ke>0&&0===Te&&(Te=Ke.length),Ee>0&&(l=ze(Se,Ke,Oe),u=Ve(Me,Xe,l,t,me,he,Te,y,i,a),Ke=l.join(""),void 0!==u&&0===(Te=(Xe=u.trim()).length)&&(y=0,Xe="")),Te>0)switch(y){case le:Ke=Ke.replace(S,$e);case fe:case ie:case H:Xe=Ke+"{"+Xe+"}";break;case ae:Xe=(Ke=Ke.replace(h,"$1 $2"+(Ae>0?Ie:"")))+"{"+Xe+"}",Xe=1===ye||2===ye&&Ue("@"+Xe,3)?"@"+j+Xe+"@"+Xe:"@"+Xe;break;default:Xe=Ke+Xe,a===pe&&(Ge+=Xe,Xe="")}else Xe="";break;default:Xe=Le(t,ze(t,Ke,Oe),Xe,a,i+1)}Ye+=Xe,O=0,Ce=0,P=0,xe=0,Oe=0,T=0,Ke="",Xe="",b=o.charCodeAt(++q);break;case _:case M:if((Te=(Ke=(xe>0?Ke.replace(r,""):Ke).trim()).length)>1)switch(0===P&&((g=Ke.charCodeAt(0))===H||g>96&&g<123)&&(Te=(Ke=Ke.replace(" ",":")).length),Ee>0&&void 0!==(u=Ve(Re,Ke,t,e,me,he,Ge.length,a,i,a))&&0===(Te=(Ke=u.trim()).length)&&(Ke="\0\0"),g=Ke.charCodeAt(0),y=Ke.charCodeAt(1),g){case ne:break;case U:if(y===ce||y===de){Qe+=Ke+o.charAt(q);break}default:if(Ke.charCodeAt(Te-1)===G)break;Ge+=Be(Ke,g,y,Ke.charCodeAt(2))}O=0,Ce=0,P=0,xe=0,Oe=0,Ke="",b=o.charCodeAt(++q)}}switch(b){case W:case z:if(d+p+f+c+we===0)switch(C){case D:case Y:case Q:case U:case te:case Z:case K:case ee:case J:case H:case G:case X:case M:case A:case _:break;default:P>0&&(Ce=1)}d===J?d=0:ge+O===0&&a!==ae&&Ke.length>0&&(xe=1,Ke+="\0"),Ee*_e>0&&Ve(je,Ke,t,e,me,he,Ge.length,a,i,a),he=1,me++;break;case M:case _:if(d+p+f+c===0){he++;break}default:switch(he++,qe=o.charAt(q),b){case B:case $:if(p+c+d===0)switch(x){case X:case G:case B:case $:qe="";break;default:b!==$&&(qe=" ")}break;case ne:qe="\\0";break;case re:qe="\\f";break;case oe:qe="\\v";break;case V:p+d+c===0&&ge>0&&(Oe=1,xe=1,qe="\f"+qe);break;case 108:if(p+d+c+ve===0&&P>0)switch(q-P){case 2:x===ue&&o.charCodeAt(q-3)===G&&(ve=x);case 8:k===se&&(ve=k)}break;case G:p+d+c===0&&(P=q);break;case X:d+f+p+c===0&&(xe=1,qe+="\r");break;case Q:case Y:0===d&&(p=p===b?0:0===p?b:p);break;case F:p+d+f===0&&c++;break;case L:p+d+f===0&&c--;break;case D:p+d+c===0&&f--;break;case I:if(p+d+c===0){if(0===O)switch(2*x+3*k){case 533:break;default:E=0,O=1}f++}break;case U:d+f+p+c+P+T===0&&(T=1);break;case K:case J:if(p+c+f>0)break;switch(d){case 0:switch(2*b+3*o.charCodeAt(q+1)){case 235:d=J;break;case 220:Te=q,d=K}break;case K:b===J&&x===K&&Te+2!==q&&(33===o.charCodeAt(Te+2)&&(Ge+=o.substring(Te,q+1)),qe="",d=0)}}if(0===d){if(ge+p+c+T===0&&a!==ae&&b!==M)switch(b){case X:case te:case Z:case ee:case D:case I:if(0===O){switch(x){case B:case $:case z:case W:qe+="\0";break;default:qe="\0"+qe+(b===X?"":"\0")}xe=1}else switch(b){case I:P+7===q&&108===x&&(P=0),O=++E;break;case D:0==(O=--E)&&(xe=1,qe+="\0")}break;case B:case $:switch(x){case ne:case A:case _:case M:case X:case re:case B:case $:case z:case W:break;default:0===O&&(xe=1,qe+="\0")}}Ke+=qe,b!==$&&b!==B&&(C=b)}}k=x,x=b,q++}if(Te=Ge.length,ke>0&&0===Te&&0===Ye.length&&0===t[0].length==0&&(a!==ie||1===t.length&&(ge>0?De:Fe)===t[0])&&(Te=t.join(",").length+2),Te>0){if(l=0===ge&&a!==ae?function(e){for(var t,n,o=0,a=e.length,i=Array(a);o1)){if(f=u.charCodeAt(u.length-1),p=n.charCodeAt(0),t="",0!==c)switch(f){case K:case te:case Z:case ee:case $:case I:break;default:t=" "}switch(p){case V:n=t+De;case te:case Z:case ee:case $:case D:case I:break;case F:n=t+n+De;break;case G:switch(2*n.charCodeAt(1)+3*n.charCodeAt(2)){case 530:if(be>0){n=t+n.substring(8,d-1);break}default:(c<1||l[c-1].length<1)&&(n=t+De+n)}break;case X:t="";default:n=d>1&&n.indexOf(":")>0?t+n.replace(w,"$1"+De+"$2"):t+n+De}u+=n}i[o]=u.replace(r,"").trim()}return i}(t):t,Ee>0&&void 0!==(u=Ve(Ne,Ge,l,e,me,he,Te,a,i,a))&&0===(Ge=u).length)return Qe+Ge+Ye;if(Ge=l.join(",")+"{"+Ge+"}",ye*ve!=0){switch(2!==ye||Ue(Ge,2)||(ve=0),ve){case se:Ge=Ge.replace(v,":"+R+"$1")+Ge;break;case ue:Ge=Ge.replace(m,"::"+j+"input-$1")+Ge.replace(m,"::"+R+"$1")+Ge.replace(m,":"+N+"input-$1")+Ge}ve=0}}return Qe+Ge+Ye}function ze(e,t,n){var r=t.trim().split(c),o=r,a=r.length,i=e.length;switch(i){case 0:case 1:for(var l=0,u=0===i?"":e[0]+" ";l0&&ge>0)return o.replace(f,"$1").replace(d,"$1"+Fe);break;default:return e.trim()+o.replace(d,"$1"+e.trim())}default:if(n*ge>0&&o.indexOf("\f")>0)return o.replace(d,(e.charCodeAt(0)===G?"":"$1")+e.trim())}return e+o}function Be(e,t,n,r){var s,c=0,d=e+";",f=2*t+3*n+4*r;if(944===f)return function(e){var t=e.length,n=e.indexOf(":",9)+1,r=e.substring(0,n).trim(),o=e.substring(n,t-1).trim();switch(e.charCodeAt(9)*Ae){case 0:break;case H:if(110!==e.charCodeAt(10))break;default:for(var a=o.split((o="",l)),i=0,n=0,t=a.length;iU&&d<90||d>96&&d<123||d===q||d===H&&s.charCodeAt(1)!==H))switch(isNaN(parseFloat(s))+(-1!==s.indexOf("("))){case 1:switch(s){case"infinite":case"alternate":case"backwards":case"running":case"normal":case"forwards":case"both":case"none":case"linear":case"ease":case"ease-in":case"ease-out":case"ease-in-out":case"paused":case"reverse":case"alternate-reverse":case"inherit":case"initial":case"unset":case"step-start":case"step-end":break;default:s+=Ie}}c[n++]=s}o+=(0===i?"":",")+c.join(" ")}}return o=r+o+";",1===ye||2===ye&&Ue(o,1)?j+o+o:o}(d);if(0===ye||2===ye&&!Ue(d,1))return d;switch(f){case 1015:return 97===d.charCodeAt(10)?j+d+d:d;case 951:return 116===d.charCodeAt(3)?j+d+d:d;case 963:return 110===d.charCodeAt(5)?j+d+d:d;case 1009:if(100!==d.charCodeAt(4))break;case 969:case 942:return j+d+d;case 978:return j+d+R+d+d;case 1019:case 983:return j+d+R+d+N+d+d;case 883:return d.charCodeAt(8)===H?j+d+d:d.indexOf("image-set(",11)>0?d.replace(P,"$1"+j+"$2")+d:d;case 932:if(d.charCodeAt(4)===H)switch(d.charCodeAt(5)){case 103:return j+"box-"+d.replace("-grow","")+j+d+N+d.replace("grow","positive")+d;case 115:return j+d+N+d.replace("shrink","negative")+d;case 98:return j+d+N+d.replace("basis","preferred-size")+d}return j+d+N+d+d;case 964:return j+d+N+"flex-"+d+d;case 1023:if(99!==d.charCodeAt(8))break;return s=d.substring(d.indexOf(":",15)).replace("flex-","").replace("space-between","justify"),j+"box-pack"+s+j+d+N+"flex-pack"+s+d;case 1005:return a.test(d)?d.replace(o,":"+j)+d.replace(o,":"+R)+d:d;case 1e3:switch(c=(s=d.substring(13).trim()).indexOf("-")+1,s.charCodeAt(0)+s.charCodeAt(c)){case 226:s=d.replace(k,"tb");break;case 232:s=d.replace(k,"tb-rl");break;case 220:s=d.replace(k,"lr");break;default:return d}return j+d+N+s+d;case 1017:if(-1===d.indexOf("sticky",9))return d;case 975:switch(c=(d=e).length-10,f=(s=(33===d.charCodeAt(c)?d.substring(0,c):d).substring(e.indexOf(":",7)+1).trim()).charCodeAt(0)+(0|s.charCodeAt(7))){case 203:if(s.charCodeAt(8)<111)break;case 115:d=d.replace(s,j+s)+";"+d;break;case 207:case 102:d=d.replace(s,j+(f>102?"inline-":"")+"box")+";"+d.replace(s,j+s)+";"+d.replace(s,N+s+"box")+";"+d}return d+";";case 938:if(d.charCodeAt(5)===H)switch(d.charCodeAt(6)){case 105:return s=d.replace("-items",""),j+d+j+"box-"+s+N+"flex-"+s+d;case 115:return j+d+N+"flex-item-"+d.replace(E,"")+d;default:return j+d+N+"flex-line-pack"+d.replace("align-content","").replace(E,"")+d}break;case 973:case 989:if(d.charCodeAt(3)!==H||122===d.charCodeAt(4))break;case 931:case 953:if(!0===T.test(e))return 115===(s=e.substring(e.indexOf(":")+1)).charCodeAt(0)?Be(e.replace("stretch","fill-available"),t,n,r).replace(":fill-available",":stretch"):d.replace(s,j+s)+d.replace(s,R+s.replace("fill-",""))+d;break;case 962:if(d=j+d+(102===d.charCodeAt(5)?N+d:"")+d,n+r===211&&105===d.charCodeAt(13)&&d.indexOf("transform",10)>0)return d.substring(0,d.indexOf(";",27)+1).replace(i,"$1"+j+"$2")+d}return d}function Ue(e,t){var n=e.indexOf(1===t?":":"{"),r=e.substring(0,3!==t?n:10),o=e.substring(n+1,e.length-1);return Oe(2!==t?r:r.replace(O,"$1"),o,t)}function $e(e,t){var n=Be(t,t.charCodeAt(0),t.charCodeAt(1),t.charCodeAt(2));return n!==t+";"?n.replace(C," or ($1)").substring(4):"("+t+")"}function Ve(e,t,n,r,o,a,i,l,u,s){for(var c,d=0,f=t;d0&&(Ie=o.replace(p,a===F?"":"-")),a=1,1===ge?Fe=o:De=o;var i,l=[Fe];Ee>0&&void 0!==(i=Ve(Pe,n,l,l,me,he,0,0,0,0))&&"string"==typeof i&&(n=i);var u=Le(Se,l,n,0,0);return Ee>0&&void 0!==(i=Ve(Te,u,l,l,me,he,u.length,0,0,0))&&"string"!=typeof(u=i)&&(a=0),Ie="",Fe="",De="",ve=0,me=1,he=1,xe*a==0?u:u.replace(r,"").replace(g,"").replace(y,"$1").replace(b,"$1").replace(x," ")}return Ke.use=function e(t){switch(t){case void 0:case null:Ee=Ce.length=0;break;default:if("function"==typeof t)Ce[Ee++]=t;else if("object"==typeof t)for(var n=0,r=t.length;n0&&void 0!==arguments[0]?arguments[0]:{},t=e.baseClasses,n=e.newClasses;if(e.Component,!n)return t;var r=o()({},t);return Object.keys(n).forEach(function(e){n[e]&&(r[e]="".concat(t[e]," ").concat(n[e]))}),r}},function(e,t,n){"use strict";var r=n(20);t.__esModule=!0,t.default=void 0;var o=r(n(144)),a=function(e){return(0,o.default)("displayName",e)};t.default=a},function(e,t,n){"use strict";var r=n(20);t.__esModule=!0,t.default=void 0;var o=r(n(145)),a=function(e,t){return t+"("+(0,o.default)(e)+")"};t.default=a},function(e,t,n){"use strict";n.r(t);var r=n(70);n.d(t,"default",function(){return r.a})},function(e,t,n){"use strict";var r=n(1),o=n.n(r),a=n(2),i=n.n(a),l=n(0),u=n.n(l),s=n(3),c=(n(10),n(33)),d=n.n(c),f=n(78);t.a=function(e){return function(t){var n,r=arguments.length>1&&void 0!==arguments[1]?arguments[1]:{},a=r.name,l=i()(r,["name"]),c=a,p="function"===typeof t?function(e){return{root:function(n){return t(o()({theme:e},n))}}}:{root:t},h=Object(f.a)(p,o()({Component:e,name:a||e.displayName,classNamePrefix:c},l));t.filterProps&&(n=t.filterProps,delete t.filterProps),t.propTypes&&(t.propTypes,delete t.propTypes);var m=u.a.forwardRef(function(t,r){var a=t.children,l=t.className,c=t.clone,d=t.component,f=i()(t,["children","className","clone","component"]),p=h(t),m=Object(s.a)(p.root,l);if(c)return u.a.cloneElement(a,{className:Object(s.a)(a.props.className,m)});var v=f;if(n&&(v=function(e,t){var n={};return Object.keys(e).forEach(function(r){-1===t.indexOf(r)&&(n[r]=e[r])}),n}(v,n)),"function"===typeof a)return a(o()({className:m},v));var g=d||e;return u.a.createElement(g,o()({ref:r,className:m},v),a)});return d()(m,e),m}}},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.hexToRgb=a,t.rgbToHex=function(e){if(0===e.indexOf("#"))return e;var t=l(e).values;return"#".concat(t.map(function(e){return function(e){var t=e.toString(16);return 1===t.length?"0".concat(t):t}(e)}).join(""))},t.hslToRgb=i,t.decomposeColor=l,t.recomposeColor=u,t.getContrastRatio=function(e,t){var n=s(e),r=s(t);return(Math.max(n,r)+.05)/(Math.min(n,r)+.05)},t.getLuminance=s,t.emphasize=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:.15;return s(e)>.5?c(e,t):d(e,t)},t.fade=function(e,t){e=l(e),t=o(t),("rgb"===e.type||"hsl"===e.type)&&(e.type+="a");return e.values[3]=t,u(e)},t.darken=c,t.lighten=d;r(n(15));function o(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:0,n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:1;return en?n:e}function a(e){e=e.substr(1);var t=new RegExp(".{1,".concat(e.length/3,"}"),"g"),n=e.match(t);return n&&1===n[0].length&&(n=n.map(function(e){return e+e})),n?"rgb(".concat(n.map(function(e){return parseInt(e,16)}).join(", "),")"):""}function i(e){var t=(e=l(e)).values,n=t[0],r=t[1]/100,o=t[2]/100,a=r*Math.min(o,1-o),i=function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:(e+n/30)%12;return o-a*Math.max(Math.min(t-3,9-t,1),-1)},s="rgb",c=[Math.round(255*i(0)),Math.round(255*i(8)),Math.round(255*i(4))];return"hsla"===e.type&&(s+="a",c.push(t[3])),u({type:s,values:c})}function l(e){if(e.type)return e;if("#"===e.charAt(0))return l(a(e));var t=e.indexOf("("),n=e.substring(0,t);if(-1===["rgb","rgba","hsl","hsla"].indexOf(n))throw new Error(["Material-UI: unsupported `".concat(e,"` color."),"We support the following formats: #nnn, #nnnnnn, rgb(), rgba(), hsl(), hsla()."].join("\n"));var r=e.substring(t+1,e.length-1).split(",");return{type:n,values:r=r.map(function(e){return parseFloat(e)})}}function u(e){var t=e.type,n=e.values;return-1!==t.indexOf("rgb")?n=n.map(function(e,t){return t<3?parseInt(e,10):e}):-1!==t.indexOf("hsl")&&(n[1]="".concat(n[1],"%"),n[2]="".concat(n[2],"%")),"".concat(t,"(").concat(n.join(", "),")")}function s(e){var t="hsl"===(e=l(e)).type?l(i(e)).values:e.values;return t=t.map(function(e){return(e/=255)<=.03928?e/12.92:Math.pow((e+.055)/1.055,2.4)}),Number((.2126*t[0]+.7152*t[1]+.0722*t[2]).toFixed(3))}function c(e,t){if(e=l(e),t=o(t),-1!==e.type.indexOf("hsl"))e.values[2]*=1-t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]*=1-t;return u(e)}function d(e,t){if(e=l(e),t=o(t),-1!==e.type.indexOf("hsl"))e.values[2]+=(100-e.values[2])*t;else if(-1!==e.type.indexOf("rgb"))for(var n=0;n<3;n+=1)e.values[n]+=(255-e.values[n])*t;return u(e)}},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;r(n(38)),n(56);var o=function(){return null};o.isRequired=function(){return null};var a=o;t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r=function(e,t){return function(){return null}};t.default=r},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=t.specialProperty=void 0;r(n(14)),r(n(1));var o="exact-prop: \u200b";t.specialProperty=o;var a=function(e){return e};t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.getFunctionName=o,t.default=void 0;var r=/^\s*function(?:\s|\s*\/\*.*\*\/\s*)+([^(\s\/]*)\s*/;function o(e){var t="".concat(e).match(r);return t&&t[1]||""}var a=function(e){return"string"===typeof e?e:e?e.displayName||e.name||o(e)||"Component":void 0};t.default=a},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var r="undefined"!=typeof window&&window.Math==Math?window:"undefined"!=typeof self&&self.Math==Math?self:Function("return this")();t.default=r},function(e,t,n){e.exports=function(){"use strict";return function(e){function t(t){if(t)try{e(t+"}")}catch(n){}}return function(n,r,o,a,i,l,u,s,c,d){switch(n){case 1:if(0===c&&64===r.charCodeAt(0))return e(r+";"),"";break;case 2:if(0===s)return r+"/*|*/";break;case 3:switch(s){case 102:case 112:return e(o[0]+r),"";default:return r+(0===d?"/*|*/":"")}case-2:r.split("/*|*/}").forEach(t)}}}}()},function(e,t,n){"use strict";t.a={animationIterationCount:1,borderImageOutset:1,borderImageSlice:1,borderImageWidth:1,boxFlex:1,boxFlexGroup:1,boxOrdinalGroup:1,columnCount:1,columns:1,flex:1,flexGrow:1,flexPositive:1,flexShrink:1,flexNegative:1,flexOrder:1,gridRow:1,gridRowEnd:1,gridRowSpan:1,gridRowStart:1,gridColumn:1,gridColumnEnd:1,gridColumnSpan:1,gridColumnStart:1,msGridRow:1,msGridRowSpan:1,msGridColumn:1,msGridColumnSpan:1,fontWeight:1,lineHeight:1,opacity:1,order:1,orphans:1,tabSize:1,widows:1,zIndex:1,zoom:1,WebkitLineClamp:1,fillOpacity:1,floodOpacity:1,stopOpacity:1,strokeDasharray:1,strokeDashoffset:1,strokeMiterlimit:1,strokeOpacity:1,strokeWidth:1}},function(e,t,n){"use strict";function r(e){return e&&"object"===typeof e&&"default"in e?e.default:e}Object.defineProperty(t,"__esModule",{value:!0});var o=r(n(31)),a=r(n(32)),i=r(n(49)),l=r(n(50)),u=r(n(51)),s=r(n(38)),c=r(n(2)),d=r(n(1)),f=r(n(0));r(n(10)),r(n(15));var p=function(){var e=null;return function(){if(null!==e)return e;var t,n,r,o=!1;try{window.addEventListener("test",null,(t={},n="passive",r={get:function(){o=!0}},Object.defineProperty(t,n,r)))}catch(a){}return e=o,o}()}(),h={capture:!1,passive:!1};function m(e){return d({},h,e)}function v(e,t,n){var r=[e,t];return r.push(p?n:n.capture),r}function g(e,t,n,r){e.addEventListener.apply(e,v(t,n,r))}function y(e,t,n,r){e.removeEventListener.apply(e,v(t,n,r))}var b=function(e){function t(){return o(this,t),i(this,l(t).apply(this,arguments))}return u(t,e),a(t,[{key:"componentDidMount",value:function(){this.applyListeners(g)}},{key:"componentDidUpdate",value:function(e){this.applyListeners(y,e),this.applyListeners(g)}},{key:"componentWillUnmount",value:function(){this.applyListeners(y)}},{key:"applyListeners",value:function(e){var t=arguments.length>1&&void 0!==arguments[1]?arguments[1]:this.props,n=t.target;if(n){var r=n;"string"===typeof n&&(r=window[n]),function(e,t){e.children,e.target;var n=c(e,["children","target"]);Object.keys(n).forEach(function(e){if("on"===e.substring(0,2)){var r=n[e],o=s(r),a="object"===o;if(a||"function"===o){var i="capture"===e.substr(-7).toLowerCase(),l=e.substring(2).toLowerCase();l=i?l.substring(0,l.length-7):l,a?t(l,r.handler,r.options):t(l,r,m({capture:i}))}}})}(t,e.bind(null,r))}}},{key:"render",value:function(){return this.props.children||null}}]),t}(f.PureComponent);b.propTypes={},t.withOptions=function(e,t){return{handler:e,options:m(t)}},t.default=b},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=(0,r(n(55)).default)(o.default.createElement(o.default.Fragment,null,o.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),o.default.createElement("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"})),"CheckCircle");t.default=a},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=(0,r(n(55)).default)(o.default.createElement(o.default.Fragment,null,o.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),o.default.createElement("path",{d:"M1 21h22L12 2 1 21zm12-3h-2v-2h2v2zm0-4h-2v-4h2v4z"})),"Warning");t.default=a},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=(0,r(n(55)).default)(o.default.createElement(o.default.Fragment,null,o.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),o.default.createElement("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-2h2v2zm0-4h-2V7h2v6z"})),"Error");t.default=a},function(e,t,n){"use strict";var r=n(20);Object.defineProperty(t,"__esModule",{value:!0}),t.default=void 0;var o=r(n(0)),a=(0,r(n(55)).default)(o.default.createElement(o.default.Fragment,null,o.default.createElement("path",{fill:"none",d:"M0 0h24v24H0z"}),o.default.createElement("path",{d:"M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm1 15h-2v-6h2v6zm0-8h-2V7h2v2z"})),"Info");t.default=a},function(e,t,n){"use strict";var r=n(149);Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"default",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"defaultValueReducer",{enumerable:!0,get:function(){return o.defaultValueReducer}});var o=r(n(150))},function(e,t,n){"use strict";var r=/^((children|dangerouslySetInnerHTML|key|ref|autoFocus|defaultValue|defaultChecked|innerHTML|suppressContentEditableWarning|suppressHydrationWarning|valueLink|accept|acceptCharset|accessKey|action|allow|allowUserMedia|allowPaymentRequest|allowFullScreen|allowTransparency|alt|async|autoComplete|autoPlay|capture|cellPadding|cellSpacing|challenge|charSet|checked|cite|classID|className|cols|colSpan|content|contentEditable|contextMenu|controls|controlsList|coords|crossOrigin|data|dateTime|decoding|default|defer|dir|disabled|download|draggable|encType|form|formAction|formEncType|formMethod|formNoValidate|formTarget|frameBorder|headers|height|hidden|high|href|hrefLang|htmlFor|httpEquiv|id|inputMode|integrity|is|keyParams|keyType|kind|label|lang|list|loading|loop|low|marginHeight|marginWidth|max|maxLength|media|mediaGroup|method|min|minLength|multiple|muted|name|nonce|noValidate|open|optimum|pattern|placeholder|playsInline|poster|preload|profile|radioGroup|readOnly|referrerPolicy|rel|required|reversed|role|rows|rowSpan|sandbox|scope|scoped|scrolling|seamless|selected|shape|size|sizes|slot|span|spellCheck|src|srcDoc|srcLang|srcSet|start|step|style|summary|tabIndex|target|title|type|useMap|value|width|wmode|wrap|about|datatype|inlist|prefix|property|resource|typeof|vocab|autoCapitalize|autoCorrect|autoSave|color|itemProp|itemScope|itemType|itemID|itemRef|results|security|unselectable|accentHeight|accumulate|additive|alignmentBaseline|allowReorder|alphabetic|amplitude|arabicForm|ascent|attributeName|attributeType|autoReverse|azimuth|baseFrequency|baselineShift|baseProfile|bbox|begin|bias|by|calcMode|capHeight|clip|clipPathUnits|clipPath|clipRule|colorInterpolation|colorInterpolationFilters|colorProfile|colorRendering|contentScriptType|contentStyleType|cursor|cx|cy|d|decelerate|descent|diffuseConstant|direction|display|divisor|dominantBaseline|dur|dx|dy|edgeMode|elevation|enableBackground|end|exponent|externalResourcesRequired|fill|fillOpacity|fillRule|filter|filterRes|filterUnits|floodColor|floodOpacity|focusable|fontFamily|fontSize|fontSizeAdjust|fontStretch|fontStyle|fontVariant|fontWeight|format|from|fr|fx|fy|g1|g2|glyphName|glyphOrientationHorizontal|glyphOrientationVertical|glyphRef|gradientTransform|gradientUnits|hanging|horizAdvX|horizOriginX|ideographic|imageRendering|in|in2|intercept|k|k1|k2|k3|k4|kernelMatrix|kernelUnitLength|kerning|keyPoints|keySplines|keyTimes|lengthAdjust|letterSpacing|lightingColor|limitingConeAngle|local|markerEnd|markerMid|markerStart|markerHeight|markerUnits|markerWidth|mask|maskContentUnits|maskUnits|mathematical|mode|numOctaves|offset|opacity|operator|order|orient|orientation|origin|overflow|overlinePosition|overlineThickness|panose1|paintOrder|pathLength|patternContentUnits|patternTransform|patternUnits|pointerEvents|points|pointsAtX|pointsAtY|pointsAtZ|preserveAlpha|preserveAspectRatio|primitiveUnits|r|radius|refX|refY|renderingIntent|repeatCount|repeatDur|requiredExtensions|requiredFeatures|restart|result|rotate|rx|ry|scale|seed|shapeRendering|slope|spacing|specularConstant|specularExponent|speed|spreadMethod|startOffset|stdDeviation|stemh|stemv|stitchTiles|stopColor|stopOpacity|strikethroughPosition|strikethroughThickness|string|stroke|strokeDasharray|strokeDashoffset|strokeLinecap|strokeLinejoin|strokeMiterlimit|strokeOpacity|strokeWidth|surfaceScale|systemLanguage|tableValues|targetX|targetY|textAnchor|textDecoration|textRendering|textLength|to|transform|u1|u2|underlinePosition|underlineThickness|unicode|unicodeBidi|unicodeRange|unitsPerEm|vAlphabetic|vHanging|vIdeographic|vMathematical|values|vectorEffect|version|vertAdvY|vertOriginX|vertOriginY|viewBox|viewTarget|visibility|widths|wordSpacing|writingMode|x|xHeight|x1|x2|xChannelSelector|xlinkActuate|xlinkArcrole|xlinkHref|xlinkRole|xlinkShow|xlinkTitle|xlinkType|xmlBase|xmlns|xmlnsXlink|xmlLang|xmlSpace|y|y1|y2|yChannelSelector|z|zoomAndPan|for|class|autofocus)|(([Dd][Aa][Tt][Aa]|[Aa][Rr][Ii][Aa]|x)-.*))$/,o=function(e){var t={};return function(n){return void 0===t[n]&&(t[n]=e(n)),t[n]}}(function(e){return r.test(e)||111===e.charCodeAt(0)&&110===e.charCodeAt(1)&&e.charCodeAt(2)<91});t.a=o},function(e,t,n){"use strict";function r(e){return Object.prototype.toString.call(e).slice(8,-1)}function o(e){return"Object"===r(e)&&(e.constructor===Object&&Object.getPrototypeOf(e)===Object.prototype)}function a(e){return"Array"===r(e)}t.a=function(e){for(var t=[],n=1;nM.length&&M.push(e)}function I(e,t,n){return null==e?0:function e(t,n,r,o){var l=typeof t;"undefined"!==l&&"boolean"!==l||(t=null);var u=!1;if(null===t)u=!0;else switch(l){case"string":case"number":u=!0;break;case"object":switch(t.$$typeof){case a:case i:u=!0}}if(u)return r(o,t,""===n?"."+D(t,0):n),1;if(u=0,n=""===n?".":n+":",Array.isArray(t))for(var s=0;sthis.eventPool.length&&this.eventPool.push(e)}function de(e){e.eventPool=[],e.getPooled=se,e.release=ce}o(ue.prototype,{preventDefault:function(){this.defaultPrevented=!0;var e=this.nativeEvent;e&&(e.preventDefault?e.preventDefault():"unknown"!==typeof e.returnValue&&(e.returnValue=!1),this.isDefaultPrevented=ie)},stopPropagation:function(){var e=this.nativeEvent;e&&(e.stopPropagation?e.stopPropagation():"unknown"!==typeof e.cancelBubble&&(e.cancelBubble=!0),this.isPropagationStopped=ie)},persist:function(){this.isPersistent=ie},isPersistent:le,destructor:function(){var e,t=this.constructor.Interface;for(e in t)this[e]=null;this.nativeEvent=this._targetInst=this.dispatchConfig=null,this.isPropagationStopped=this.isDefaultPrevented=le,this._dispatchInstances=this._dispatchListeners=null}}),ue.Interface={type:null,target:null,currentTarget:function(){return null},eventPhase:null,bubbles:null,cancelable:null,timeStamp:function(e){return e.timeStamp||Date.now()},defaultPrevented:null,isTrusted:null},ue.extend=function(e){function t(){}function n(){return r.apply(this,arguments)}var r=this;t.prototype=r.prototype;var a=new t;return o(a,n.prototype),n.prototype=a,n.prototype.constructor=n,n.Interface=o({},r.Interface,e),n.extend=r.extend,de(n),n},de(ue);var fe=ue.extend({data:null}),pe=ue.extend({data:null}),he=[9,13,27,32],me=H&&"CompositionEvent"in window,ve=null;H&&"documentMode"in document&&(ve=document.documentMode);var ge=H&&"TextEvent"in window&&!ve,ye=H&&(!me||ve&&8=ve),be=String.fromCharCode(32),xe={beforeInput:{phasedRegistrationNames:{bubbled:"onBeforeInput",captured:"onBeforeInputCapture"},dependencies:["compositionend","keypress","textInput","paste"]},compositionEnd:{phasedRegistrationNames:{bubbled:"onCompositionEnd",captured:"onCompositionEndCapture"},dependencies:"blur compositionend keydown keypress keyup mousedown".split(" ")},compositionStart:{phasedRegistrationNames:{bubbled:"onCompositionStart",captured:"onCompositionStartCapture"},dependencies:"blur compositionstart keydown keypress keyup mousedown".split(" ")},compositionUpdate:{phasedRegistrationNames:{bubbled:"onCompositionUpdate",captured:"onCompositionUpdateCapture"},dependencies:"blur compositionupdate keydown keypress keyup mousedown".split(" ")}},we=!1;function ke(e,t){switch(e){case"keyup":return-1!==he.indexOf(t.keyCode);case"keydown":return 229!==t.keyCode;case"keypress":case"mousedown":case"blur":return!0;default:return!1}}function Se(e){return"object"===typeof(e=e.detail)&&"data"in e?e.data:null}var Ce=!1;var Ee={eventTypes:xe,extractEvents:function(e,t,n,r){var o=void 0,a=void 0;if(me)e:{switch(e){case"compositionstart":o=xe.compositionStart;break e;case"compositionend":o=xe.compositionEnd;break e;case"compositionupdate":o=xe.compositionUpdate;break e}o=void 0}else Ce?ke(e,n)&&(o=xe.compositionEnd):"keydown"===e&&229===n.keyCode&&(o=xe.compositionStart);return o?(ye&&"ko"!==n.locale&&(Ce||o!==xe.compositionStart?o===xe.compositionEnd&&Ce&&(a=ae()):(re="value"in(ne=r)?ne.value:ne.textContent,Ce=!0)),o=fe.getPooled(o,t,n,r),a?o.data=a:null!==(a=Se(n))&&(o.data=a),V(o),a=o):a=null,(e=ge?function(e,t){switch(e){case"compositionend":return Se(t);case"keypress":return 32!==t.which?null:(we=!0,be);case"textInput":return(e=t.data)===be&&we?null:e;default:return null}}(e,n):function(e,t){if(Ce)return"compositionend"===e||!me&&ke(e,t)?(e=ae(),oe=re=ne=null,Ce=!1,e):null;switch(e){case"paste":return null;case"keypress":if(!(t.ctrlKey||t.altKey||t.metaKey)||t.ctrlKey&&t.altKey){if(t.char&&1