From f39f215c5a49f05e038ef501770d92276f12c93a Mon Sep 17 00:00:00 2001 From: Peder Bergebakken Sundt Date: Sun, 5 Feb 2017 17:10:50 +0100 Subject: [PATCH] updated server.py to use the newest version of REMI and added a nice PVV logo in the background --- requirements.txt | 2 +- res/pvv logo.svg | 47 ++++ res/style.css | 601 +++++++++++++++++++++++++++++++++++++++++++++++ server.py | 58 +++-- 4 files changed, 682 insertions(+), 26 deletions(-) create mode 100644 res/pvv logo.svg create mode 100644 res/style.css diff --git a/requirements.txt b/requirements.txt index 6c7a177..841fdb3 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,3 +1,3 @@ mpv==0.1 -youtube-dl==2016.9.11.1 +youtube-dl git+https://github.com/dddomodossola/remi.git diff --git a/res/pvv logo.svg b/res/pvv logo.svg new file mode 100644 index 0000000..54a4113 --- /dev/null +++ b/res/pvv logo.svg @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + PVV + + diff --git a/res/style.css b/res/style.css new file mode 100644 index 0000000..005ad9b --- /dev/null +++ b/res/style.css @@ -0,0 +1,601 @@ +@charset "UTF-8"; +/* latin */ + +@font-face { + font-family: 'Roboto'; + font-style: normal; + font-weight: 400; + src: local('Roboto'), local('Roboto-Regular'), url('/res/font.woff2') format('woff2'); +} +textarea:focus, +input[type='checkbox']:focus, +input[type='color']:focus, +input[type='number']:focus, +input[type='date']:focus, +select:focus { + border: 0px; + outline: 0px; + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .14); + border-bottom: 1px solid rgba(33, 150, 243, .26); +} +::-moz-selection { + background: rgba(33, 150, 243, .26); + text-shadow: none +} +::selection { + background: rgba(33, 150, 243, .26); + text-shadow: none +} +audio, +canvas, +iframe, +img, +svg, +video { + vertical-align: middle +} +textarea { + resize: vertical +} +a, +a:visited { + text-decoration: underline +} +html { + height: 100%; +} +body { + width: 100%; + margin: 0px; + padding: 0px; + height: 100%; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 400; + min-height: 100%; +} +*[hidden] { + display: none!important +} +h1, +h2, +h3, +h4, +h5, +h6, +p { + padding: 0 +} +h1 small, +h2 small, +h3 small, +h4 small, +h5 small, +h6 small { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-weight: 400; + line-height: 1.35; + letter-spacing: -.02em; + opacity: .54; + font-size: .6em +} +h1 { + font-size: 56px; + line-height: 1.35; + letter-spacing: -.02em; + margin: 24px 0 +} +h1, +h2 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-weight: 400 +} +h2 { + font-size: 45px; + line-height: 48px +} +h2, +h3 { + margin: 24px 0 +} +h3 { + font-size: 34px; + line-height: 40px +} +h3, +h4 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-weight: 400 +} +h4 { + font-size: 24px; + line-height: 32px; + -moz-osx-font-smoothing: grayscale; + margin: 24px 0 16px +} +h5 { + font-size: 20px; + font-weight: 500; + line-height: 1; + letter-spacing: .02em +} +h5, +h6 { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + margin: 24px 0 16px +} +h6 { + font-size: 16px; + letter-spacing: .04em +} +h6, +p { + font-weight: 400; + line-height: 24px +} +p { + font-size: 14px; + letter-spacing: 0; + margin: 0 0 16px +} +a { + color: rgba(33, 150, 243, .8); + font-weight: 500 +} +blockquote { + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + position: relative; + font-size: 24px; + font-weight: 300; + font-style: italic; + line-height: 1.35; + letter-spacing: .08em +} +blockquote:before { + position: absolute; + left: -.5em; + content: '�' +} +blockquote:after { + content: '�'; + margin-left: -.05em +} +mark { + background-color: #f4ff81 +} +dt { + font-weight: 700 +} +address { + font-size: 12px; + line-height: 1; + font-style: normal +} +address, +ul, +ol { + font-weight: 400; + letter-spacing: 0 +} +ul, +ol { + font-size: 14px; + line-height: 24px +} +.RaisedFrame { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); + z-index: 1; +} +body>div { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); +} +div { + background-color: white; + z-index: 0; +} +.ListView { + border: none; + padding: 0; + background-color: white; + cursor: default; + overflow: auto; + list-style: none; +} +option:hover { + background: rgba(33, 150, 243, .26) outline: 1px solid red; +} +.ListItem:hover { + background: rgba(33, 150, 243, .26) +} +.ListItem[selected='True'] { + background: rgba(33, 150, 243, .26) +} +input[type='number'], +input[type='date'], +input[type='color'], +textarea, +li, +select { + border: none; + border-bottom: 1px solid rgba(0, 0, 0, .12); + display: block; + font-size: 14px; + font-family: inherit; + margin: 0; + width: 100%; + background: 0 0; + text-align: left; + color: inherit; + padding: 0; +} +select { + border-bottom: 2px solid rgba(0, 0, 0, .12); +} +input[type='checkbox'] { + height: 100%; + min-height: 20px; + min-width: 20px; +} +button { + background: 0 0; + border: none; + border-radius: 2px; + color: #000; + position: relative; + height: 36px; + margin: 0; + padding: 0 16px; + display: inline-block; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + font-size: 14px; + font-weight: 500; + letter-spacing: 0; + overflow: hidden; + overflow-x: hidden; + overflow-y: hidden; + will-change: box-shadow; + transition: box-shadow .1s cubic-bezier(.4, 0, 1, 1), background-color .1s cubic-bezier(.4, 0, .2, 1), color .1s cubic-bezier(.4, 0, .2, 1); + outline: none; + cursor: pointer; + text-decoration: none; + text-align: center; + vertical-align: middle; + background: rgb(33, 150, 243); + color: rgb(255, 255, 255); + box-shadow: 0 1px 1px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); +} +button:focus { + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .2), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); + font-weight: bold; +} +button:disabled { + background-color: #ddd; + background: #ddd; + border: 1px solid #ddd; +} +.TextInput { + border: none; + border-bottom: 1px solid rgba(0, 0, 0, .12); + display: block; + font-size: 14px; + font-family: "Roboto", "Helvetica", "Arial", sans-serif; + margin: 0; + padding: 0; + width: 100%; + background: 0 0; + text-align: left; + color: inherit; +} +table { + border-spacing: 0; + overflow: scroll; + border-collapse: collapse; + text-align: center; + box-shadow: 0 1px 2px 0 rgba(0, 0, 0, .1); +} +.TableItem { + padding: 0px; + border: none; + outline: 0px; + border-bottom: 1px solid rgb(218, 218, 218); +} +td { + border: none; + outline: 0px; + background-color: inherit; +} +th { + border: 0px; + outline: 0px; + background: rgb(33, 150, 243); + color: rgb(255, 255, 255); + font-weight: normal; +} +p.DialogTitle { + background: rgb(33, 150, 243); + border: 0px; + margin: 0px; + color: white; + font-weight: bold; + text-align: center; + margin: 0px; +} +p.Title { + border: 0px; + color: inherit; + font-weight: bold; +} +nav > ul.Menu { + background: rgb(33, 150, 243); + border: 0px; + color: white; +} +ul.Menu { + list-style-type: none; + padding: 0; + position: relative; +} +.MenuItem { + cursor: default; + text-align: center; + position: relative; +} +.Menu .Menu { + position: absolute; +} +.Menu .Menu .Menu { + top: 5%; + left: 95%; + position: absolute; +} +.MenuItem .Menu { + display: none; + background-color: white; + /*border: 1px solid #9C9B9B;*/ + + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); + color: black; + height: auto !important; + position: absolute; + top: 100%; +} +.MenuBar>.Menu>.MenuItem { + border-bottom: 0; +} +.MenuBar { + border-bottom: 1px solid rgba(0, 0, 0, .26); +} +.Menu > .MenuItem:hover { + background: rgb(33, 150, 243); + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); +} +.MenuItem .MenuItem:hover { + background: rgba(33, 150, 243, .26); +} +.Menu::after { + content: ""; + clear: both; +} +.MenuItem:hover > .Menu { + display: block; +} +input.file { + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: 0; + border: 0; + padding: 0; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: rgb(33, 150, 243); + box-shadow: 0 4px 5px 0 rgba(0, 0, 0, .14), 0 1px 10px 0 rgba(0, 0, 0, .12), 0 2px 4px -1px rgba(0, 0, 0, .2); +} +input[type='range'] { + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: 0 0; + -webkit-user-select: none; + -moz-user-select: none; + -ms-user-select: none; + user-select: none; + outline: 0; + padding: 0; + color: rgb(33, 150, 243); + -webkit-align-self: center; + -ms-flex-item-align: center; + align-self: center; + z-index: 1; + cursor: pointer; + height: 100%; +} +input[type='range']::-moz-focus-outer { + border: 0 +} +input[type='range']::-ms-tooltip { + display: none +} +input[type='range']::-webkit-slider-runnable-track { + background: rgba(33, 150, 243, .26); + height: 2px; +} +input[type='range']::-moz-range-track { + background: rgba(33, 150, 243, .26); + height: 2px; + border: none; +} +input[type='range']::-ms-track { + background: rgba(33, 150, 243, .26); + height: 2px; + color: transparent; + width: 100%; + border: none; +} +input[type='range']::-ms-fill-lower { + padding: 0; + background: linear-gradient(to right, transparent, transparent 16px, rgb(33, 150, 243), rgb(33, 150, 243)0) +} +input[type='range']::-ms-fill-upper { + padding: 0; + background: linear-gradient(to left, transparent, transparent 16px, rgba(0, 0, 0, .26), rgba(0, 0, 0, .26)0) +} +input[type='range']::-webkit-slider-thumb { + -webkit-appearance: none; + top: -5px; + width: 12px; + height: 12px; + position: relative; + box-sizing: border-box; + border-radius: 100%; + background: rgb(33, 150, 243); + border: none; + transition: transform .18s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1); + transition: transform .18s cubic-bezier(.4, 0, .2, 1), border .18s cubic-bezier(.4, 0, .2, 1), box-shadow .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1), -webkit-transform .18s cubic-bezier(.4, 0, .2, 1) +} +input[type='range']::-moz-range-thumb { + -moz-appearance: none; + width: 12px; + height: 12px; + box-sizing: border-box; + border-radius: 100%; + background-image: none; + background: rgb(33, 150, 243); + border: none +} +input[type='range']:focus:not(:active)::-webkit-slider-thumb { + box-shadow: 0 0 0 10px rgba(33, 150, 243, .26) +} +input[type='range']:focus:not(:active)::-moz-range-thumb { + box-shadow: 0 0 0 10px rgba(33, 150, 243, .26) +} +input[type='range']:active::-webkit-slider-thumb { + background-image: none; + background: rgb(33, 150, 243); + -webkit-transform: scale(1.5); + transform: scale(1.5) +} +input[type='range']:active::-moz-range-thumb { + background-image: none; + background: rgb(33, 150, 243); + transform: scale(1.5) +} +input[type='range']::-ms-thumb { + width: 32px; + height: 32px; + border: none; + border-radius: 50%; + background: rgb(33, 150, 243); + transform: scale(.375); + transition: transform .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1); + transition: transform .18s cubic-bezier(.4, 0, .2, 1), background .28s cubic-bezier(.4, 0, .2, 1), -webkit-transform .18s cubic-bezier(.4, 0, .2, 1) +} +input[type='range']:focus:not(:active)::-ms-thumb { + background: radial-gradient(circle closest-side, rgb(33, 150, 243)0%, rgb(33, 150, 243)37.5%, rgba(33, 150, 243, .26)37.5%, rgba(33, 150, 243, .26)100%); + transform: scale(1) +} +input[type='range']:active::-ms-thumb { + background: rgb(33, 150, 243); + transform: scale(.5625) +} +input[type='range']:disabled:focus::-webkit-slider-thumb, +input[type='range']:disabled:active::-webkit-slider-thumb, +input[type='range']:disabled::-webkit-slider-thumb { + -webkit-transform: scale(.667); + transform: scale(.667); + background: rgba(0, 0, 0, .26) +} +input[type='range']:disabled:focus::-moz-range-thumb, +input[type='range']:disabled:active::-moz-range-thumb, +input[type='range']:disabled::-moz-range-thumb { + transform: scale(.667); + background: rgba(0, 0, 0, .26) +} +#loading { + position: fixed; + left: 0; + top: 0; + bottom: 0; + right: 0; + width: 100%; + height: 100%; + z-index: 10; + background: #000; + opacity: 0.8; +} +#loading-animation { + width: 40px; + height: 40px; + background-color: rgb(33, 150, 243); + + margin: 100px auto; + -webkit-animation: sk-rotateplane 1.2s infinite ease-in-out; + animation: sk-rotateplane 1.2s infinite ease-in-out; +} + +@-webkit-keyframes sk-rotateplane { + 0% { -webkit-transform: perspective(120px) } + 50% { -webkit-transform: perspective(120px) rotateY(180deg) } + 100% { -webkit-transform: perspective(120px) rotateY(180deg) rotateX(180deg) } +} + +@keyframes sk-rotateplane { + 0% { + transform: perspective(120px) rotateX(0deg) rotateY(0deg); + -webkit-transform: perspective(120px) rotateX(0deg) rotateY(0deg) + } 50% { + transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg); + -webkit-transform: perspective(120px) rotateX(-180.1deg) rotateY(0deg) + } 100% { + transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); + -webkit-transform: perspective(120px) rotateX(-180deg) rotateY(-179.9deg); + } +} + +.TabBox ul { + padding-left: 0; +} + +.tabs li { + list-style-type: none; + border: none; +} + +.tabs a { + display: block; + text-align: center; + text-decoration: none; + color: #888; + padding: 20px 0; + border-bottom: 2px solid #888; + background: #f7f7f7; +} +.tabs a:hover, +.tabs a.active { + background: #ddd; +} +.clearfix:after { + content: ""; + display: table; + clear: both; +} + + +/*gregorz specific*/ +body::after { + position: fixed; + content: url('/res/pvv logo.svg'); + + -ms-transform: rotate(10deg); /* IE 9 */ + -webkit-transform: rotate(10deg); /* Chrome, Safari, Opera */ + transform: rotate(10deg); + + width: 40%; + bottom: -8%; + right: 0%; + + opacity:0.4; + z-index:-1; +} \ No newline at end of file diff --git a/server.py b/server.py index c37f96c..f768354 100644 --- a/server.py +++ b/server.py @@ -1,11 +1,11 @@ -#!/usr/bin/env python3 -import remi.gui as gui, random, os, time, shutil, sys -from remi import start, App +#!/usr/bin/env python3.6 +import random, os, time, shutil, sys from threading import Timer -if sys.version_info[0] == 2: - from ConfigParser import ConfigParser -else: - from configparser import ConfigParser +import remi.gui as gui +from remi import start, App +from grzegorz import nyasync +from configparser import ConfigParser + if "--no-mpv" not in sys.argv: from mpv_control import mpv @@ -34,14 +34,15 @@ def get_youtube_metadata(url, ydl = youtube_dl.YoutubeDL()): class MyApp(App): def __init__(self, *args): - res_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), 'res') - super(MyApp, self).__init__(*args, static_paths=(res_path,)) - + res_path = os.path.join(os.path.dirname(__file__), 'res') + super(MyApp, self).__init__(*args, static_file_path=res_path) #initalize mpv here? def main(self): container = gui.VBox(width=512) + container.style["margin-left"] = "auto" + container.style["margin-right"] = "auto" #logo: container.append(gui.Image('/res/logo.jpg', width=512)) @@ -53,7 +54,7 @@ class MyApp(App): button = gui.Button(i.capitalize(), margin="5px") setattr(self.playback, i, button) playbackContainer.append(button) - button.set_on_click_listener(self, 'playback_%s' % i) + button.set_on_click_listener(getattr(self,'playback_%s' % i)) self.playback.playing = gui.Label("Now playing: None") self.playback.slider = gui.Slider(0, 0, 100, 1, width="85%", height=20, margin='10px') @@ -64,7 +65,8 @@ class MyApp(App): #playlist self.playlist = namespace() self.playlist.table = gui.Table(width="100%", margin="10px") - self.playlist.table.from_2d_matrix([['#', 'Name', "length"]]) + self.playlist.table.append_from_list([['#', 'Name', "length"]], fill_title=True) + container.append(self.playlist.table) self.playlist.queue = []#[i] = [source, name, length] @@ -74,11 +76,11 @@ class MyApp(App): inputContainer = gui.HBox(width=512) self.input = namespace() self.input.field = gui.TextInput(single_line=True, height="20px", margin="5px") - self.input.field.style["border"] = "1px solid %s" % COLOR_BLUE + self.input.field.style["border"] = "1px solid %s" % COLOR_BLUE self.input.field.style["box-shadow"] = "0px 0px 5px 0px %s" % COLOR_BLUE_SHADOW self.input.submit = gui.Button("Submit!", margin="5px") - self.input.field.set_on_enter_listener(self, "input_submit") - self.input.submit.set_on_click_listener(self, "input_submit") + self.input.field.set_on_enter_listener(self.input_submit) + self.input.submit.set_on_click_listener(self.input_submit) inputContainer.append(self.input.field) inputContainer.append(self.input.submit) @@ -92,23 +94,28 @@ class MyApp(App): self.playback_update() - self.playlist.table.from_2d_matrix(self.playlist_update()) + + self.playlist.table.empty(keep_title=True) + self.playlist.table.append_from_list(self.playlist_update()) Timer(1, self.mainLoop).start() - def playback_play(self): pass - def playback_pause(self): pass - def playback_next(self): + #events: + def playback_play(self, widget): pass + def playback_pause(self, widget): pass + def playback_next(self, widget): source, name, length = self.playlist.queue.pop(0) pass - def input_submit(self, value=None): + def input_submit(self, widget, value=None): if not value: value = self.input.field.get_text() + self.input.field.set_text("") title, length = get_youtube_metadata(value) - self.input.field.set_text("") + self.playlist.queue.append([value, title, length]) + #playback steps: def playback_update(self): #talk to mpv, see wether the song is being played still @@ -120,13 +127,14 @@ class MyApp(App): return def playlist_update(self): - out = [['#', 'Name', "length"]] - + #out = [['#', 'Name', "length"]] + out = [] for i, (source, name, length) in enumerate(self.playlist.queue): out.append([str(i+1), name, length]) return out +#@nyasync.ify def main(): if not os.path.exists("config.ini"): shutil.copyfile("default_config.ini", "config.ini") @@ -141,7 +149,7 @@ def main(): multiple_instance = ini.getboolean("server", "multiple_instance") # starts the webserver - start(MyApp, address=host, port=port, start_browser=start_browser, multiple_instance=multiple_instance) + start(MyApp, title="Gregorz", address=host, port=port, start_browser=start_browser, multiple_instance=multiple_instance, enable_file_cache=True) if __name__ == "__main__": - main() \ No newline at end of file + main() \ No newline at end of file