Overdue update for python 3 and kodijson. No functional changes.
# 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
# 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
# todo
# any kind of error checking
# 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
from datetime import datetime
import hashlib
import cgi, cgitb
from datetime import datetime
import hashlib
import numbers
import os
import random
import subprocess
import numbers
import os
import random
import subprocess
-from xbmcjson import XBMC
+from kodijson import Kodi
from yattag import Doc
import partyparty
from yattag import Doc
import partyparty
-xbmc = partyparty.connect (XBMC ("http://localhost:8080/jsonrpc"))
+xbmc = partyparty.connect (Kodi ("http://localhost:8080/jsonrpc"))
def print_escaped (item):
def print_escaped (item):
- print (u"<p>{}</p>".format (cgi.escape (u"{}".format (item))))
+ print (u"<p>{}</p>".format (html.escape (u"{}".format (item))))
<button name="volmute" value="1">Toggle Mute</button>
</form>
<button name="volmute" value="1">Toggle Mute</button>
</form>
-'''.format (cgi.escape (PAGE_SELF)))
+'''.format (html.escape (PAGE_SELF)))
print ('''
<form method="post" action="{}" style="display: inline-block">
print ('''
<form method="post" action="{}" style="display: inline-block">
<button name="navigate" value="next" type="submit">⏭</button>
<button name="navigate" value="playpause" type="submit">⏯</button>
</form>
<button name="navigate" value="next" type="submit">⏭</button>
<button name="navigate" value="playpause" type="submit">⏯</button>
</form>
-'''.format (cgi.escape (PAGE_SELF)))
+'''.format (html.escape (PAGE_SELF)))
print ('<a name="playlist"></a><h1>Playlist</h1>')
print (playlist.show ())
print ('<a name="playlist"></a><h1>Playlist</h1>')
print (playlist.show ())
Search ().show_quick_search (thereal=True)
show_menu ()
Search ().show_quick_search (thereal=True)
show_menu ()
-print ('<form method="post" action="{}" style="display: inline-block">'.format (cgi.escape (PAGE_SELF)))
+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="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>')
# Simple PartyMode Web Console
# Limited interface for normal party goers
# Simple PartyMode Web Console
# Limited interface for normal party goers
# limit playlist view to next five
# limit playlist view to next five
-import sys
-reload(sys)
-sys.setdefaultencoding ('utf-8')
-
import cgi, cgitb
from datetime import datetime
import hashlib
import cgi, cgitb
from datetime import datetime
import hashlib
import os
import random
import subprocess
import os
import random
import subprocess
-from xbmcjson import XBMC
+import sys
+from kodijson import Kodi
from yattag import Doc
import partyparty
from yattag import Doc
import partyparty
print ("<!DOCTYPE html>\n<html><head><title>partyparty beb</title></head><body>")
print (partyparty.css ())
print ("<!DOCTYPE html>\n<html><head><title>partyparty beb</title></head><body>")
print (partyparty.css ())
-print '<p style="font-size: 5rem"><a href="upload.html">Upload A Song</a> | <a href="youtube.html">Add From YouTube</a> | <a href="normals.cgi">home</a> | <a href="normals.cgi?browseartists=1">browse</a></p>'
+print ('<p style="font-size: 5rem"><a href="upload.html">Upload A Song</a> | <a href="youtube.html">Add From YouTube</a> | <a href="normals.cgi">home</a> | <a href="normals.cgi?browseartists=1">browse</a></p>')
class NormalsPlaylist (Playlist):
def get_playlist (self):
class NormalsPlaylist (Playlist):
def get_playlist (self):
- return Playlist.get_playlist (self)[0:6]
+ return Playlist.get_playlist (self)#[0:10]
class NormalsManager (PartyManager):
DEFAULT_QUEUE_DIVISOR = 1
class NormalsManager (PartyManager):
DEFAULT_QUEUE_DIVISOR = 1
-xbmc = partyparty.connect (XBMC ("http://localhost:8080/jsonrpc"))
+xbmc = partyparty.connect (Kodi ("http://localhost:8080/jsonrpc"))
manager = NormalsManager (cgi.FieldStorage ())
manager.process ()
manager = NormalsManager (cgi.FieldStorage ())
manager.process ()
import cgi, cgitb
from datetime import datetime
import hashlib
import cgi, cgitb
from datetime import datetime
import hashlib
import itertools
import numbers
import os
import itertools
import numbers
import os
import re
import subprocess
import urllib
import re
import subprocess
import urllib
-from xbmcjson import XBMC
+from kodijson import Kodi
from yattag import Doc
import youtube_dl
from yattag import Doc
import youtube_dl
-def connect (_xbmc):
- global xbmc
- xbmc = _xbmc
- return xbmc
+def connect (_kodi):
+ global kodi
+ kodi = _kodi
+ return kodi
SONG_PROPERTIES = ['album', 'artist', 'albumartist', 'dateadded', 'userrating', 'displayartist']
PAGE_SELF = os.environ['SCRIPT_NAME'] if 'SCRIPT_NAME' in os.environ else ''
SONG_PROPERTIES = ['album', 'artist', 'albumartist', 'dateadded', 'userrating', 'displayartist']
PAGE_SELF = os.environ['SCRIPT_NAME'] if 'SCRIPT_NAME' in os.environ else ''
if 'id' in song:
# item from playlist
if 'id' in song:
# item from playlist
- self.key = hashlib.sha256(str(song['id'])).hexdigest()
+ self.key = hashlib.sha256(str(song['id']).encode('utf-8')).hexdigest()
self.kodi_id = song['id']
# the playlist will not update things like ratings if we
# update via RPC. Just grab it from the library instead.
if 'userrating' in song:
self.kodi_id = song['id']
# the playlist will not update things like ratings if we
# update via RPC. Just grab it from the library instead.
if 'userrating' in song:
- libsong = xbmc.AudioLibrary.GetSongDetails (songid = song['id'], properties = ['userrating'])
+ libsong = kodi.AudioLibrary.GetSongDetails (songid = song['id'], properties = ['userrating'])
#print (libsong)
if 'result' in libsong and 'songdetails' in libsong['result']:
song['userrating'] = libsong['result']['songdetails']['userrating']
elif 'songid' in song:
# search results
#print (libsong)
if 'result' in libsong and 'songdetails' in libsong['result']:
song['userrating'] = libsong['result']['songdetails']['userrating']
elif 'songid' in song:
# search results
- self.key = hashlib.sha256(str(song['songid'])).hexdigest()
+ self.key = hashlib.sha256(str(song['songid']).encode('utf-8')).hexdigest()
self.kodi_id = song['songid']
else:
self.kodi_id = song['songid']
else:
- self.key = hashlib.sha256(song['label'] + self.artist).hexdigest()
+ self.key = hashlib.sha256((song['label'] + self.artist).encode('utf-8')).hexdigest()
self.kodi_id = 0
# videos can still be labeled as songs, but the rating will be a
self.kodi_id = 0
# videos can still be labeled as songs, but the rating will be a
return [Song(item) for item in items]
def get_playlist (playlistid=0):
return [Song(item) for item in items]
def get_playlist (playlistid=0):
- return songs (xbmc.Playlist.GetItems (playlistid=playlistid, properties=SONG_PROPERTIES)['result']['items'])
+ return songs (kodi.Playlist.GetItems (playlistid=playlistid, properties=SONG_PROPERTIES)['result']['items'])
class SongControls:
aactions = {'songup': 'up', 'songdown': 'down', 'songtop': 'next!', 'songbottom': 'banish!',
class SongControls:
aactions = {'songup': 'up', 'songdown': 'down', 'songtop': 'next!', 'songbottom': 'banish!',
return {}
if (self.prop != 'any'):
return {}
if (self.prop != 'any'):
- res = xbmc.AudioLibrary.GetSongs (filter={'operator': "contains", 'field': self.prop, 'value': self.term}, properties=SONG_PROPERTIES, sort={'order': 'ascending', 'method': 'artist'})['result']
+ res = kodi.AudioLibrary.GetSongs (filter={'operator': "contains", 'field': self.prop, 'value': self.term}, properties=SONG_PROPERTIES, sort={'order': 'ascending', 'method': 'artist'})['result']
if 'songs' in res:
return songs(res['songs'])
else:
return []
else:
if 'songs' in res:
return songs(res['songs'])
else:
return []
else:
- all_songs = [xbmc.AudioLibrary.GetSongs (filter={'operator': "contains", 'field': p, 'value': self.term}, properties=SONG_PROPERTIES, sort={'order': 'ascending', 'method': 'artist'})['result']
+ all_songs = [kodi.AudioLibrary.GetSongs (filter={'operator': "contains", 'field': p, 'value': self.term}, properties=SONG_PROPERTIES, sort={'order': 'ascending', 'method': 'artist'})['result']
for p
in self.ANY_SEARCH_PROPERTIES]
# does not remove duplicates...
for p
in self.ANY_SEARCH_PROPERTIES]
# does not remove duplicates...
text (prop)
with tag ('button', type = 'submit', name = 'searchgo', value = '1'):
text ('Search')
text (prop)
with tag ('button', type = 'submit', name = 'searchgo', value = '1'):
text ('Search')
+ print (doc.getvalue ())
def show_search_results (self):
doc, tag, text = Doc().tagtext()
def show_search_results (self):
doc, tag, text = Doc().tagtext()
return doc.getvalue ()
def get_playlist (self, playlistid=0):
return doc.getvalue ()
def get_playlist (self, playlistid=0):
- return songs (xbmc.Playlist.GetItems (playlistid=playlistid, properties=SONG_PROPERTIES)['result']['items'])
+ return songs (kodi.Playlist.GetItems (playlistid=playlistid, properties=SONG_PROPERTIES)['result']['items'])
class Upload:
upload_dir = '/srv/archive/incoming/stolen-moosic'
class Upload:
upload_dir = '/srv/archive/incoming/stolen-moosic'
# works instead of dealing with MIME. For now.
def attempt_rpgain (self):
subprocess.call (["/usr/bin/vorbisgain", "-q", self.filename])
# works instead of dealing with MIME. For now.
def attempt_rpgain (self):
subprocess.call (["/usr/bin/vorbisgain", "-q", self.filename])
- subprocess.call (["/usr/bin/mp3gain", "-q", "-s", "i", self.filename])
+ subprocess.call (["/usr/local/bin/mp3gain", "-q", "-s", "i", self.filename])
subprocess.call (["/usr/bin/aacgain", "-q", "-s", "i", self.filename])
subprocess.call (["/usr/bin/metaflac", "--add-replay-gain", self.filename])
def save (self):
subprocess.call (["/usr/bin/aacgain", "-q", "-s", "i", self.filename])
subprocess.call (["/usr/bin/metaflac", "--add-replay-gain", self.filename])
def save (self):
- fout = file (os.path.join(self.upload_dir, self.fileitem.filename), 'wb')
+ fout = open (os.path.join(self.upload_dir, self.fileitem.filename), 'wb')
fout.write (self.fileitem.value)
fout.close()
self.attempt_rpgain ()
fout.write (self.fileitem.value)
fout.close()
self.attempt_rpgain ()
return doc.getvalue ()
def print_escaped (item):
return doc.getvalue ()
def print_escaped (item):
- print (u"<p>{}</p>".format (cgi.escape (u"{}".format (item))))
+ print (u"<p>{}</p>".format (html.escape (u"{}".format (item))))
# This is awful
class PartyManager:
# This is awful
class PartyManager:
# divisor) songs
if divisor is None:
divisor = self.DEFAULT_QUEUE_DIVISOR
# divisor) songs
if divisor is None:
divisor = self.DEFAULT_QUEUE_DIVISOR
- totalitems = xbmc.Playlist.GetItems (playlistid=0)['result']['limits']['total']
+ totalitems = kodi.Playlist.GetItems (playlistid=0)['result']['limits']['total']
playpos = random.randint (1, totalitems / divisor + 1)
playpos = random.randint (1, totalitems / divisor + 1)
- print_escaped (xbmc.Playlist.Insert (playlistid=0, item=item, 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)
+ print_escaped (kodi.Playlist.Insert (playlistid=0, item=item, 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))
return (playpos, totalitems+1)
def process (self):
return (playpos, totalitems+1)
def process (self):
songid = form['songdel'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
songid = form['songdel'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
- print (u'<p>Deleted {}</p>'.format(cgi.escape (song.label)))
- print_escaped (xbmc.Playlist.Remove (playlistid=0, position=pos))
+ print (u'<p>Deleted {}</p>'.format(html.escape (song.label)))
+ print_escaped (kodi.Playlist.Remove (playlistid=0, position=pos))
elif 'songup' in form:
songid = form['songup'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
elif 'songup' in form:
songid = form['songup'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
- print (u"<p>Promoted {}</p>".format(cgi.escape(song.label)))
- print_escaped (xbmc.Playlist.Swap (playlistid=0, position1=pos, position2=pos-1))
+ print (u"<p>Promoted {}</p>".format(html.escape(song.label)))
+ print_escaped (kodi.Playlist.Swap (playlistid=0, position1=pos, position2=pos-1))
elif 'songdown' in form:
songid = form['songdown'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
elif 'songdown' in form:
songid = form['songdown'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
- print (u"<p>Demoted {}</p>".format(cgi.escape(song.label)))
- print_escaped (xbmc.Playlist.Swap (playlistid=0, position1=pos, position2=pos+1))
+ print (u"<p>Demoted {}</p>".format(html.escape(song.label)))
+ print_escaped (kodi.Playlist.Swap (playlistid=0, position1=pos, position2=pos+1))
elif 'songtop' in form:
songid = form['songtop'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
elif 'songtop' in form:
songid = form['songtop'].value
print (u"<p>{}</p>".format (songid))
(pos,song) = next ((i,s) for i,s in enumerate(get_playlist ()) if s.key == songid)
- print (u"<p>Bumped Up {}</p>".format(cgi.escape(song.label)))
+ print (u"<p>Bumped Up {}</p>".format(html.escape(song.label)))
for i in range (pos, 1, -1):
for i in range (pos, 1, -1):
- print_escaped (xbmc.Playlist.Swap (playlistid=0, position1=i, position2=i-1))
+ print_escaped (kodi.Playlist.Swap (playlistid=0, position1=i, position2=i-1))
elif 'songbottom' in form:
songid = form['songbottom'].value
print (u"<p>{}</p>".format (songid))
playlist = get_playlist ()
(pos,song) = next ((i,s) for i,s in enumerate(playlist) if s.key == songid)
elif 'songbottom' in form:
songid = form['songbottom'].value
print (u"<p>{}</p>".format (songid))
playlist = get_playlist ()
(pos,song) = next ((i,s) for i,s in enumerate(playlist) if s.key == songid)
- print (u"<p>Banished {}</p>".format(cgi.escape(song.label)))
+ print (u"<p>Banished {}</p>".format(html.escape(song.label)))
for i in range (pos, len (playlist), 1):
for i in range (pos, len (playlist), 1):
- print_escaped (xbmc.Playlist.Swap (playlistid=0, position1=i, position2=i+1))
+ print_escaped (kodi.Playlist.Swap (playlistid=0, position1=i, position2=i+1))
elif 'volchange' in form:
elif 'volchange' in form:
- curvolume = xbmc.Application.GetProperties (properties=['volume'])['result']['volume']
+ curvolume = kodi.Application.GetProperties (properties=['volume'])['result']['volume']
newvolume = max (0, min (int (form['volchange'].value) + curvolume, 100))
newvolume = max (0, min (int (form['volchange'].value) + curvolume, 100))
- print_escaped (xbmc.Application.SetVolume (volume=newvolume))
+ print_escaped (kodi.Application.SetVolume (volume=newvolume))
- print_escaped (xbmc.Application.SetMute (mute="toggle"))
+ print_escaped (kodi.Application.SetMute (mute="toggle"))
elif 'navigate' in form:
action = form['navigate'].value
if action == 'prev':
elif 'navigate' in form:
action = form['navigate'].value
if action == 'prev':
- print_escaped (xbmc.Player.GoTo (to="previous", playerid=0))
+ print_escaped (kodi.Player.GoTo (to="previous", playerid=0))
- print_escaped (xbmc.Player.GoTo (to="next", playerid=0))
+ print_escaped (kodi.Player.GoTo (to="next", playerid=0))
elif action == 'playpause':
elif action == 'playpause':
- print_escaped (xbmc.Player.PlayPause (play="toggle", playerid=0))
+ print_escaped (kodi.Player.PlayPause (play="toggle", playerid=0))
elif 'searchgo' in form:
term = form['searchterm'].value
field = form['searchfield'].value
elif 'searchgo' in form:
term = form['searchterm'].value
field = form['searchfield'].value
newrating = int(form['songrating'].value)
print (songid)
print (newrating)
newrating = int(form['songrating'].value)
print (songid)
print (newrating)
- print_escaped (xbmc.AudioLibrary.SetSongDetails (songid = songid, userrating = newrating))
+ print_escaped (kodi.AudioLibrary.SetSongDetails (songid = songid, userrating = newrating))
print_escaped (u'Rating Changed')
elif 'browseartists' in form:
print_escaped (u'Rating Changed')
elif 'browseartists' in form:
- artists = xbmc.AudioLibrary.GetArtists (sort={'order': 'ascending', 'method': 'artist'})['result']['artists']
+ artists = kodi.AudioLibrary.GetArtists (sort={'order': 'ascending', 'method': 'artist'})['result']['artists']
doc, tag, text = Doc().tagtext()
with tag ('ol', klass='flex_list'):
for artist in artists:
doc, tag, text = Doc().tagtext()
with tag ('ol', klass='flex_list'):
for artist in artists:
item = youtube.save ()
self.randomqueue (item, 1 if 'asap' not in form else 3)
elif 'partyon' in form:
item = youtube.save ()
self.randomqueue (item, 1 if 'asap' not in form else 3)
elif 'partyon' in form:
- if 'error' in xbmc.Player.SetPartymode (partymode=True, playerid=0):
- xbmc.Player.Open (item={"partymode": "music"})
+ if 'error' in kodi.Player.SetPartymode (partymode=True, playerid=0):
+ kodi.Player.Open (item={"partymode": "music"})
elif 'lockon' in form:
subprocess.call (['/usr/bin/xscreensaver-command', 'lock'])
elif 'lights' in form:
elif 'lockon' in form:
subprocess.call (['/usr/bin/xscreensaver-command', 'lock'])
elif 'lights' in form:
# 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
# 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
import daemon
import subprocess
import random
import daemon
import subprocess
import random
-from xbmcjson import XBMC
+from kodijson import Kodi
import partyparty
from partyparty import Upload, PartyManager
import partyparty
from partyparty import Upload, PartyManager
print '<p><a href="upload.html">Upload another song</a></p>'
sys.stdout.flush ()
print '<p><a href="upload.html">Upload another song</a></p>'
sys.stdout.flush ()
-xbmc = partyparty.connect (XBMC ("http://localhost:8080/jsonrpc"))
+xbmc = partyparty.connect (Kodi ("http://localhost:8080/jsonrpc"))
manager.randomqueue ({"file": filename}, 1 if 'asap' not in form else 3)
# todo: use REMOTE_ADDR to limit how many asap requests a person can
manager.randomqueue ({"file": filename}, 1 if 'asap' not in form else 3)
# todo: use REMOTE_ADDR to limit how many asap requests a person can