quick and dirty browser "admin panel" for kodi
authorClinton Ebadi <clinton@unknownlamer.org>
Fri, 19 Jun 2015 23:57:02 +0000 (19:57 -0400)
committerClinton Ebadi <clinton@unknownlamer.org>
Fri, 19 Jun 2015 23:57:02 +0000 (19:57 -0400)
Basic volume + player controls, playlist management, and search +
queue functionality.

I wouldn't trust this code if I were me, but it gets the job done for
now (hacked it together for a party).

party-upload/admin.cgi [new file with mode: 0755]

diff --git a/party-upload/admin.cgi b/party-upload/admin.cgi
new file mode 100755 (executable)
index 0000000..4c67bb9
--- /dev/null
@@ -0,0 +1,175 @@
+#!/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)