xbmc file upload / playlist insert example
authorClinton Ebadi <clinton@unknownlamer.org>
Mon, 24 Nov 2014 03:15:25 +0000 (22:15 -0500)
committerClinton Ebadi <clinton@unknownlamer.org>
Mon, 24 Nov 2014 03:15:25 +0000 (22:15 -0500)
XBMC party mode is good for background music at parties, but sometimes
guests want to listen to their music and not mine. After trying to get
UPnP/DLNA and bluetooth streaming to work I gave up and threw together
a trivial file upload + python script.

Primitive, so far. It lets users upload a single file to a specified
directory, replaygains it (if it is mp3/flac/vorbis at least), and
then inserts it at a random position on the playlist.

xbmc/upload.html [new file with mode: 0644]
xbmc/upload.py.cgi [new file with mode: 0755]

diff --git a/xbmc/upload.html b/xbmc/upload.html
new file mode 100644 (file)
index 0000000..3f7eae0
--- /dev/null
@@ -0,0 +1,18 @@
+<html>
+  <head>
+    <style>
+      input[type=file], input[type=submit] { height: 20em; width: 100%; }
+    </style>
+  </head>
+  <body>
+    <form action="upload.py.cgi" method="post" enctype="multipart/form-data">
+      <p>
+       <input name="song" type="file" accept="audio/*"
+              <!-- multiple="multiple" --> />
+       <input type="submit" value="Party On!" />
+       <input type="checkbox" value="faster" name="asap" />
+       <label for="faster">ASAP</label>
+      </p>
+    </form>
+  </body>
+</html>
diff --git a/xbmc/upload.py.cgi b/xbmc/upload.py.cgi
new file mode 100755 (executable)
index 0000000..a5d8682
--- /dev/null
@@ -0,0 +1,98 @@
+#!/usr/bin/python
+
+# Trivial xbmc file upload script for parties
+# Copyright (c) 2014 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/>.
+
+# todo:
+# fix weird characters (see erica's song)
+# use shutil.copyfileobj to possibly speed up copying
+# - check if it actually causes chunked reads from the browser
+# support multiple files
+# - daemonize replaygain?
+# track uploads
+# - phone ip is hopefully good enough
+# - track # of uses of asap/Next Please
+# - track files we have queued (need at least next-please so we can queue those in order)
+# integrate better with native queue
+
+
+## crazy idea: if the playlist can be watched with a script... (maybe
+## a json rpc notification? but ... reliability, and upload.cgi runs
+## infrequently enough that it cannot record the playlist and extract
+## a meaningful image of the queue ...).
+
+# diff playlist whenever item is inserted (or song changes, or whatever we can hook on).
+# scan for common items (discarding the head of the old snapshot, since we could just be advancing)
+# when the first different item is found... if it ain't the end of the list it's been queued
+# keep going until we match up again and record the end of the queue position in a file
+# what about when we delete in the list?
+#  
+
+# upload.html
+# - show playlist length, # of next/asap available, likely queue position
+# - show upcoming songs (5? just next-please?)
+# - - just use SSI + python virtual includes, seriously
+
+import cgi, cgitb
+import os, sys
+import daemon
+import subprocess
+import random
+from xbmcjson import XBMC
+
+cgitb.enable()
+
+print "content-type: text/html\n\n"
+
+music_dir = "/srv/archive/incoming/stolen-moosic"
+form = cgi.FieldStorage ()
+
+# Evil: just run replaygain/mp3gain/metaflac on the file and hope one
+# works instead of dealing with MIME. For now.
+def attempt_rpgain (file_name): 
+   subprocess.call (["/usr/bin/vorbisgain", "-q", file_name])
+   subprocess.call (["/usr/bin/mp3gain", "-q", "-s", "i", file_name])
+   subprocess.call (["/usr/bin/metaflac", "--add-replay-gain", file_name])
+
+def save_uploaded_file (form_field, upload_dir):
+    if form_field not in form:
+        print "<p>No file provided.</p>"
+        sys.exit ()
+    fileitem = form[form_field]
+    fout = file (os.path.join(upload_dir, fileitem.filename), 'wb')
+    fout.write (fileitem.value)
+    fout.close()
+    return fileitem.filename
+
+song_name = save_uploaded_file ("song", music_dir)
+
+print '<p><a href="upload.html">Upload another song</a></p>'
+sys.stdout.flush ()
+
+#with daemon.DaemonContext ():
+attempt_rpgain ("{0}/{1}".format (music_dir, song_name))
+
+xbmc = XBMC ("http://localhost:8080/jsonrpc")
+
+# todo: use REMOTE_ADDR to limit how many asap requests a person can
+# make in a time period
+totalitems = xbmc.Playlist.GetItems (playlistid=0)['result']['limits']['total']
+playpos = random.randint (1, totalitems / (1 if 'asap' not in form else 3))
+
+print xbmc.Playlist.Insert (playlistid=0, item={"file": "{0}/{1}".format (music_dir, song_name)}, 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)
+
+