party-upload: minor CSS and Python 3 fixes
[clinton/unknownlamer-kodi-addons.git] / party-upload / admin.cgi
dissimilarity index 79%
index 4c67bb9..c1be02e 100755 (executable)
-#!/usr/bin/python
-
-# ADD COMMAND TO RESTART PARTY MODE
-# (probably should require confirmation)
-# also add undelete link to post-del link just in case (reinsert at old pos)
-
-# Trivial xbmc admin script to view active playlist, control volume,
-# etc.
-
-# I would not recommend putting this online, no attempt is made at
-# being even trivially secure (e.g. form values are passed directly to
-# kodi with zero verification)
-
-# todo
-# any kind of error checking
-
-from __future__ import unicode_literals
-
-# Python is being obnoxious as hell and refusing to .format() utf-8
-# strings. I have no idea. Just hack around it and deal with the
-# actual problem later instead of scattering the code with .encode
-# calls.
-
-import sys
-reload(sys)
-sys.setdefaultencoding ('utf-8')
-
-import cgi, cgitb
-import os
-import subprocess
-import random
-from xbmcjson import XBMC
-
-cgitb.enable()
-
-print ("content-type: text/html; charset=utf-8\n\n")
-
-print (u'''
-<style>
-input, select, button { font-size: 200%}
-.horiz-menu li { display: inline }
- body { /* background-image: url("fire-under-construction-animation.gif"); */
-color: white;
-background-color: black;
-}
-</style>
-
-<ul class="horiz-menu"">
-<li><a href="admin.cgi">reload</a></li>
-<li><a href="#playlist">playlist</a></li>
-<li><a href="#controls">control</a></li>
-<li><a href="javascript:document.getElementById(&quot;quicksearch&quot;).focus()">search</a></li>
-</ul>
-''')
-
-music_dir = "/srv/archive/incoming/stolen-moosic"
-form = cgi.FieldStorage ()
-
-xbmc = XBMC ("http://localhost:8080/jsonrpc")
-
-def show_quick_search (term="",thereal=False):
-   print (u'''
-<form method="get" action="admin.cgi" style="display: inline-block">
-<input type="text" name="searchterm" value="{}" {} />
-<select name="searchfield">
-<option value="title">name</option>
-<option value="albumartist">artist</option>
-<option value="album">album</option>
-</select>
-<button type="submit" name="searchgo" value="1">Search</button>
-</form>
-   ''').format(term, 'id="quicksearch"' if thereal else '')
-
-def show_search_results (songs):
-   print (u"<h1>Results</h1>")
-   print (u"<ol>")
-   for song in songs:
-      print (u'<li>{} ({}) {}'.format (song['albumartist'][0], song['album'], song['label']))
-      print ('<form method="post" action="admin.cgi" style="display: inline-block">')
-      print ('<button type="submit" name="randomqueue" value="{}">yeh</button>'.format(song['songid']))
-      print ('</form>')
-      print ('</li>')
-   print (u"</ol>")
-
-if 'songdel' in form:
-   songid = int(form['songdel'].value)
-   print (songid)
-   (pos,name) = next ((i,s) for i,s in enumerate(xbmc.Playlist.GetItems (playlistid=0)['result']['items']) if s['id'] == songid)
-   print (u"<p>Deleted {}</p>".format(name['label']))
-   print (xbmc.Playlist.Remove (playlistid=0, position=pos))
-elif 'songup' in form:
-   songid = int(form['songup'].value)
-   print (songid)
-   (pos,name) = next ((i,s) for i,s in enumerate(xbmc.Playlist.GetItems (playlistid=0)['result']['items']) if s['id'] == songid)
-   print (u"<p>Promoted {}</p>".format(name['label']))
-   print (xbmc.Playlist.Swap (playlistid=0, position1=pos, position2=pos-1))
-elif 'songdown' in form:
-   songid = int(form['songdown'].value)
-   print (songid)
-   (pos,name) = next ((i,s) for i,s in enumerate(xbmc.Playlist.GetItems (playlistid=0)['result']['items']) if s['id'] == songid)
-   print (u"<p>Demoted {}</p>".format(name['label']))
-   print (xbmc.Playlist.Swap (playlistid=0, position1=pos, position2=pos+1))
-elif 'volchange' in form:
-   curvolume = xbmc.Application.GetProperties (properties=['volume'])['result']['volume']
-   newvolume = max (0, min (int (form['volchange'].value) + curvolume, 100))
-   print (xbmc.Application.SetVolume (volume=newvolume))
-elif 'volmute' in form:
-   print (xbmc.Application.SetMute (mute="toggle"))
-elif 'navigate' in form:
-   action = form['navigate'].value
-   if action == 'prev':
-      print xbmc.Player.GoTo (to="previous", playerid=0)
-   elif action == 'next':
-      print xbmc.Player.GoTo (to="next", playerid=0)
-   elif action == 'playpause':
-      print xbmc.Player.PlayPause (play="toggle",  playerid=0)
-elif 'searchgo' in form:
-   term = form['searchterm'].value
-   field = form['searchfield'].value
-   results = xbmc.AudioLibrary.GetSongs (filter={'operator': "contains", 'field': field, 'value': term}, properties=['album', 'albumartist'], sort={'order': 'ascending', 'method': 'artist'})['result']['songs']
-   show_quick_search (term)
-   show_search_results (results)
-elif 'randomqueue' in form:
-   songid = int(form['randomqueue'].value)
-   totalitems = xbmc.Playlist.GetItems (playlistid=0)['result']['limits']['total']
-   playpos = random.randint (1, totalitems / 3 + 1)
-   print xbmc.Playlist.Insert (playlistid=0, item={"songid": songid}, position=playpos)
-   print '<p style="font-size: x-large">Your song is number {0} in the queue ({1} songs in playlist).</p>'.format (playpos, totalitems+1)
-
-
-
-
-
-playlist = xbmc.Playlist.GetItems (playlistid=0, properties=['album', 'albumartist'])['result']['items']
-#playpos = random.randint (1, totalitems / (1 if 'asap' not in form else 3))
-
-print ('<a name="controls"></a>')
-print ('<p>Volume: {}%</p>'.format(xbmc.Application.GetProperties (properties=['volume'])['result']['volume']))
-print ('''
-<form method="post" action="admin.cgi" style="display: inline-block">
-<button name="volchange" value="5" type="submit">+5</button>
-<button name="volchange" value="-5" type="submit">-5</button>
-
-<button name="volchange" value="10" type="submit">+10</button>
-<button name="volchange" value="-10" type="submit">-10</button>
-
-<button name="volmute" value="1">Toggle Mute</button>
-
-</form>
-''')
-
-print ('''
-<form method="post" action="admin.cgi" style="display: inline-block">
-<button name="navigate" value="prev" type="submit">&#x23ee;</button>
-<button name="navigate" value="next" type="submit">&#x23ed;</button>
-<button name="navigate" value="playpause" type="submit">&#x23ef;</button>
-</form>
-''')
-
-
-print ('<a name="playlist"></a><h1>Playlist</h1>')
-print ("<ol>")
-for song in playlist:
-   print (u'<li>{} {}'.format(song['albumartist'][0], song['label']).encode('UTF-8'))
-
-   print ('<form method="post" action="admin.cgi" style="display: inline-block">')
-   print ('<button name="songdel" value="{}">del</button>'.format(song['id']))
-   print ('<button name="songup" value="{}">up</button>'.format(song['id']))
-   print ('<button name="songdown" value="{}">down</button>'.format(song['id']))
-   print ('</form>'   )
-   print ("</li>")
-print ("</ol>")
-
-print ('<a name="search"></a>')
-show_quick_search (thereal=True)
+#!/usr/bin/python3
+# Simple PartyMode Web Console
+# Copyright (c) 2015,2016  Clinton Ebadi <clinton@unknownlamer.org>
+# This program 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.
+
+# This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Trivial xbmc admin script to view active playlist, control volume,
+# etc.
+
+# I would not recommend putting this online, no attempt is made at
+# being even trivially secure (e.g. form values are passed directly to
+# kodi with zero verification)
+
+# ADD COMMAND TO RESTART PARTY MODE
+# (probably should require confirmation)
+# also add undelete link to post-del link just in case (reinsert at old pos)
+
+# todo
+# any kind of error checking
+
+import cgi, cgitb
+from datetime import datetime
+import hashlib
+import html
+import numbers
+import os
+import random
+import subprocess
+import urllib
+from kodijson import Kodi
+from yattag import Doc
+
+import partyparty
+from partyparty import Song, SongControls, Search, Playlist, PartyManager
+
+cgitb.enable()
+#PAGE_SELF = os.environ['SCRIPT_NAME'] if 'SCRIPT_NAME' in os.environ else ''
+PAGE_SELF = os.environ['SCRIPT_NAME'].rsplit('/', 1)[-1] if 'SCRIPT_NAME' in os.environ else ''
+#PAGE_SELF = 'admin.cgi'
+
+print ("content-type: text/html; charset=utf-8\n\n")
+print ("<!DOCTYPE html>\n<html><head><title>partyparty beb</title></head><body>")
+print (partyparty.css ())
+
+#print (os.environ)
+#print (os.environ['SCRIPT_NAME'])
+
+def show_menu ():
+   doc, tag, text = Doc().tagtext()
+   with tag ('ul', klass = 'horiz-menu flex_row'):
+      for target, description in [('#playlist', 'playlist'),
+                                  ('#controls', 'controls'),
+                                  ('javascript:document.getElementById("quicksearch").focus()', 'search'),
+                                  (PAGE_SELF, 'reload')]:
+         with tag ('li'):
+            with tag ('a', href = target):
+               text (description)
+
+   print (doc.getvalue ())
+
+xbmc = partyparty.connect (Kodi ("http://localhost:8080/jsonrpc"))
+
+def print_escaped (item):
+   print (u"<p>{}</p>".format (html.escape (u"{}".format (item))))
+
+show_menu ()
+
+manager = PartyManager (cgi.FieldStorage ())
+manager.process ()
+
+playlist = Playlist()
+#playpos = random.randint (1, totalitems / (1 if 'asap' not in form else 3))
+
+class PlayerControls:
+   def __init__ (self, name='controls'):
+      self.name = name
+
+   def info (self):
+      doc, tag, text = Doc().tagtext()
+      _playtime = xbmc.Player.GetProperties (playerid=0, properties = ['position', 'percentage', 'time', 'totaltime'])
+      pt = _playtime['result'] if 'result' in _playtime else None
+      with tag ('ul', klass = 'horiz-menu'):
+         for infotext in ['Volume {}%'.format(xbmc.Application.GetProperties (properties=['volume'])['result']['volume']),
+                          'Time {:02d}:{:02d} / {:02d}:{:02d} ({:.2f}%) @ {:%H:%M:%S}'.format (pt['time']['hours'] * 60 +  pt['time']['minutes'], pt['time']['seconds'], pt['totaltime']['hours'] * 60 + pt['totaltime']['minutes'], pt['totaltime']['seconds'], pt['percentage'], datetime.now())]:
+            with tag ('li'):
+               text (infotext)
+
+      return doc.getvalue ()
+
+
+
+controls = PlayerControls ()
+print (controls.info ())
+
+print ('<a name="controls"></a>')
+print ('''
+<form method="post" action="{}" style="display: inline-block">
+<button name="volchange" value="5" type="submit">+5</button>
+<button name="volchange" value="-5" type="submit">-5</button>
+
+<button name="volchange" value="10" type="submit">+10</button>
+<button name="volchange" value="-10" type="submit">-10</button>
+
+<button name="volmute" value="1">Toggle Mute</button>
+
+</form>
+'''.format (html.escape (PAGE_SELF)))
+
+print ('''
+<form method="post" action="{}" style="display: inline-block">
+<button name="navigate" value="prev" type="submit">&#x23ee;</button>
+<button name="navigate" value="next" type="submit">&#x23ed;</button>
+<button name="navigate" value="playpause" type="submit">&#x23ef;</button>
+</form>
+'''.format (html.escape (PAGE_SELF)))
+
+print ('<a name="playlist"></a><h1>Playlist</h1>')
+print (playlist.show ())
+
+
+
+
+print ('<a name="search"></a>')
+Search ().show_quick_search (thereal=True)
+show_menu ()
+
+print ('<form method="post" action="{}" style="display: inline-block">'.format (html.escape (PAGE_SELF)))
+print ('<button name="partyon" value="true">re-enable party</button>')
+#print ('<button name="lockon" value="true">lock em out</button>')
+print ('<button name="lights" value="on">lights on</button>')
+print ('<button name="lights" value="off">lights off</button>')
+print ('</form>')
+print ('</body></html>')