Steven Smith revised this gist . Go to revision
1 file changed, 2 insertions
minidlnagui.py
| @@ -1,3 +1,5 @@ | |||
| 1 | + | # https://github.com/blha303/PythonMiniDLNARestAPI | |
| 2 | + | ||
| 1 | 3 | # Run this on a client machine (not the media server) | |
| 2 | 4 | # This is my first GUI! | |
| 3 | 5 | ||
Steven Smith revised this gist . Go to revision
1 file changed, 1 insertion
minidlnagui.py
| @@ -28,6 +28,7 @@ def search(term, name='artist'): | |||
| 28 | 28 | return response.json() | |
| 29 | 29 | ||
| 30 | 30 | master = Tk() | |
| 31 | + | master.wm_title("MiniDLNA REST API gui (by blha303)") | |
| 31 | 32 | windows = PanedWindow() | |
| 32 | 33 | windows.pack(fill=BOTH, expand=1) | |
| 33 | 34 | textbox = Text(windows) | |
Steven Smith revised this gist . Go to revision
1 file changed, 11 insertions, 30 deletions
minidlnagui.py
| @@ -1,15 +1,15 @@ | |||
| 1 | 1 | # Run this on a client machine (not the media server) | |
| 2 | 2 | # This is my first GUI! | |
| 3 | - | ||
| 3 | + | ||
| 4 | 4 | # Copyright 2013 Steven Smith (blha303). All Rights Reserved. | |
| 5 | 5 | # New BSD license | |
| 6 | 6 | # http://www.opensource.org/licenses/BSD-3-Clause | |
| 7 | - | ||
| 7 | + | ||
| 8 | 8 | from Tkinter import * | |
| 9 | 9 | import tkMessageBox | |
| 10 | 10 | import requests | |
| 11 | 11 | import json | |
| 12 | - | ||
| 12 | + | ||
| 13 | 13 | hostname = "home.blha303.com.au" | |
| 14 | 14 | port = "5000" | |
| 15 | 15 | url = "http://%s:%s/api/DETAILS" % (hostname, port if port else "5000") | |
| @@ -17,7 +17,7 @@ fields = ['ARTIST', 'ID', 'PATH', 'SIZE', 'TIMESTAMP', 'TITLE', 'DURATION', 'BIT | |||
| 17 | 17 | 'SAMPLERATE', 'CREATOR', 'ALBUM', 'GENRE', 'COMMENT', 'CHANNELS', 'DISC', | |
| 18 | 18 | 'TRACK', 'DATE', 'RESOLUTION', 'THUMBNAIL', 'ALBUM_ART', 'ROTATION', | |
| 19 | 19 | 'DLNA_PN', 'MIME'] | |
| 20 | - | ||
| 20 | + | ||
| 21 | 21 | def search(term, name='artist'): | |
| 22 | 22 | url = "http://home.blha303.com.au:5000/api/DETAILS" | |
| 23 | 23 | headers = {'Content-Type': 'application/json'} | |
| @@ -26,7 +26,7 @@ def search(term, name='artist'): | |||
| 26 | 26 | response = requests.get(url, params=params, headers=headers) | |
| 27 | 27 | assert response.status_code == 200 | |
| 28 | 28 | return response.json() | |
| 29 | - | ||
| 29 | + | ||
| 30 | 30 | master = Tk() | |
| 31 | 31 | windows = PanedWindow() | |
| 32 | 32 | windows.pack(fill=BOTH, expand=1) | |
| @@ -41,9 +41,9 @@ x = 1 | |||
| 41 | 41 | for i in fields: | |
| 42 | 42 | middle.insert(x, i) | |
| 43 | 43 | x += 1 | |
| 44 | - | ||
| 44 | + | ||
| 45 | 45 | rightside.add(middle) | |
| 46 | - | ||
| 46 | + | ||
| 47 | 47 | def buttonCallback(): | |
| 48 | 48 | term = top.get() | |
| 49 | 49 | name = middle.get(middle.curselection() if middle.curselection() else 0) | |
| @@ -57,31 +57,12 @@ def buttonCallback(): | |||
| 57 | 57 | for i in data['objects']: | |
| 58 | 58 | if str(i['PATH']) != "None": | |
| 59 | 59 | output.append("PATH: " + str(i['PATH'])) | |
| 60 | - | output.append(" ID: " + str(i['ID'])) | |
| 61 | - | output.append(" SIZE: " + str(i['SIZE'])) | |
| 62 | - | output.append(" TIMESTAMP: " + str(i['TIMESTAMP'])) | |
| 63 | - | output.append(" TITLE: " + str(i['TITLE'])) | |
| 64 | - | output.append(" DURATION: " + str(i['DURATION'])) | |
| 65 | - | output.append(" BITRATE: " + str(i['BITRATE'])) | |
| 66 | - | output.append(" SAMPLERATE: " + str(i['SAMPLERATE'])) | |
| 67 | - | output.append(" CREATOR: " + str(i['CREATOR'])) | |
| 68 | - | output.append(" ARTIST: " + str(i['ARTIST'])) | |
| 69 | - | output.append(" ALBUM: " + str(i['ALBUM'])) | |
| 70 | - | output.append(" GENRE: " + str(i['GENRE'])) | |
| 71 | - | output.append(" COMMENT: " + str(i['COMMENT'])) | |
| 72 | - | output.append(" CHANNELS: " + str(i['CHANNELS'])) | |
| 73 | - | output.append(" DISC: " + str(i['DISC'])) | |
| 74 | - | output.append(" TRACK: " + str(i['TRACK'])) | |
| 75 | - | output.append(" DATE: " + str(i['DATE'])) | |
| 76 | - | output.append(" RESOLUTION: " + str(i['RESOLUTION'])) | |
| 77 | - | output.append(" THUMBNAIL: " + str(i['THUMBNAIL'])) | |
| 78 | - | output.append(" ALBUM_ART: " + str(i['ALBUM_ART'])) | |
| 79 | - | output.append(" ROTATION: " + str(i['ROTATION'])) | |
| 80 | - | output.append(" DLNA_PN: " + str(i['DLNA_PN'])) | |
| 81 | - | output.append(" MIME: " + str(i['MIME'])) | |
| 60 | + | for a in fields: | |
| 61 | + | if a != "PATH": | |
| 62 | + | output.append(" " + a + ": " + str(i[a])) | |
| 82 | 63 | output.append("") | |
| 83 | 64 | textbox.insert(INSERT, "\n".join(output)) | |
| 84 | - | ||
| 65 | + | ||
| 85 | 66 | bottom = Button(rightside, text="Submit", command=buttonCallback) | |
| 86 | 67 | rightside.add(bottom) | |
| 87 | 68 | mainloop() | |
Steven Smith revised this gist . Go to revision
1 file changed, 1 deletion
README.md (file deleted)
| @@ -1 +0,0 @@ | |||
| 1 | - | I made this because I really wanted to be able to search my media server with Python. Please leave questions in the comments below, or email me: https://github.com/blha303 | |
Steven Smith revised this gist . Go to revision
3 files changed, 1 insertion, 1 deletion
README.md
| @@ -1 +1 @@ | |||
| 1 | - | I made this because I really wanted to be able to search my media server with Python. I need to write a longer README here. | |
| 1 | + | I made this because I really wanted to be able to search my media server with Python. Please leave questions in the comments below, or email me: https://github.com/blha303 | |
gui.py renamed to minidlnagui.py
File renamed without changes
server.py renamed to minidlnarestserver.py
File renamed without changes
Steven Smith revised this gist . Go to revision
1 file changed, 1 insertion
gui.py
| @@ -11,6 +11,7 @@ import requests | |||
| 11 | 11 | import json | |
| 12 | 12 | ||
| 13 | 13 | hostname = "home.blha303.com.au" | |
| 14 | + | port = "5000" | |
| 14 | 15 | url = "http://%s:%s/api/DETAILS" % (hostname, port if port else "5000") | |
| 15 | 16 | fields = ['ARTIST', 'ID', 'PATH', 'SIZE', 'TIMESTAMP', 'TITLE', 'DURATION', 'BITRATE', | |
| 16 | 17 | 'SAMPLERATE', 'CREATOR', 'ALBUM', 'GENRE', 'COMMENT', 'CHANNELS', 'DISC', | |
Steven Smith revised this gist . Go to revision
3 files changed, 140 insertions
README.md(file created)
| @@ -0,0 +1 @@ | |||
| 1 | + | I made this because I really wanted to be able to search my media server with Python. I need to write a longer README here. | |
gui.py(file created)
| @@ -0,0 +1,86 @@ | |||
| 1 | + | # Run this on a client machine (not the media server) | |
| 2 | + | # This is my first GUI! | |
| 3 | + | ||
| 4 | + | # Copyright 2013 Steven Smith (blha303). All Rights Reserved. | |
| 5 | + | # New BSD license | |
| 6 | + | # http://www.opensource.org/licenses/BSD-3-Clause | |
| 7 | + | ||
| 8 | + | from Tkinter import * | |
| 9 | + | import tkMessageBox | |
| 10 | + | import requests | |
| 11 | + | import json | |
| 12 | + | ||
| 13 | + | hostname = "home.blha303.com.au" | |
| 14 | + | url = "http://%s:%s/api/DETAILS" % (hostname, port if port else "5000") | |
| 15 | + | fields = ['ARTIST', 'ID', 'PATH', 'SIZE', 'TIMESTAMP', 'TITLE', 'DURATION', 'BITRATE', | |
| 16 | + | 'SAMPLERATE', 'CREATOR', 'ALBUM', 'GENRE', 'COMMENT', 'CHANNELS', 'DISC', | |
| 17 | + | 'TRACK', 'DATE', 'RESOLUTION', 'THUMBNAIL', 'ALBUM_ART', 'ROTATION', | |
| 18 | + | 'DLNA_PN', 'MIME'] | |
| 19 | + | ||
| 20 | + | def search(term, name='artist'): | |
| 21 | + | url = "http://home.blha303.com.au:5000/api/DETAILS" | |
| 22 | + | headers = {'Content-Type': 'application/json'} | |
| 23 | + | filters = [dict(name=name.upper(), op='like', val=term)] | |
| 24 | + | params = dict(q=json.dumps(dict(filters=filters))) | |
| 25 | + | response = requests.get(url, params=params, headers=headers) | |
| 26 | + | assert response.status_code == 200 | |
| 27 | + | return response.json() | |
| 28 | + | ||
| 29 | + | master = Tk() | |
| 30 | + | windows = PanedWindow() | |
| 31 | + | windows.pack(fill=BOTH, expand=1) | |
| 32 | + | textbox = Text(windows) | |
| 33 | + | windows.add(textbox) | |
| 34 | + | rightside = PanedWindow(windows, orient=VERTICAL) | |
| 35 | + | windows.add(rightside) | |
| 36 | + | top = Entry(rightside) | |
| 37 | + | rightside.add(top) | |
| 38 | + | middle = Listbox(rightside) | |
| 39 | + | x = 1 | |
| 40 | + | for i in fields: | |
| 41 | + | middle.insert(x, i) | |
| 42 | + | x += 1 | |
| 43 | + | ||
| 44 | + | rightside.add(middle) | |
| 45 | + | ||
| 46 | + | def buttonCallback(): | |
| 47 | + | term = top.get() | |
| 48 | + | name = middle.get(middle.curselection() if middle.curselection() else 0) | |
| 49 | + | data = search(term, name=name) | |
| 50 | + | textbox.delete(1.0, END) | |
| 51 | + | if data['num_results'] == 0: | |
| 52 | + | textbox.insert(INSERT, str(data)) | |
| 53 | + | return | |
| 54 | + | else: | |
| 55 | + | output = [] | |
| 56 | + | for i in data['objects']: | |
| 57 | + | if str(i['PATH']) != "None": | |
| 58 | + | output.append("PATH: " + str(i['PATH'])) | |
| 59 | + | output.append(" ID: " + str(i['ID'])) | |
| 60 | + | output.append(" SIZE: " + str(i['SIZE'])) | |
| 61 | + | output.append(" TIMESTAMP: " + str(i['TIMESTAMP'])) | |
| 62 | + | output.append(" TITLE: " + str(i['TITLE'])) | |
| 63 | + | output.append(" DURATION: " + str(i['DURATION'])) | |
| 64 | + | output.append(" BITRATE: " + str(i['BITRATE'])) | |
| 65 | + | output.append(" SAMPLERATE: " + str(i['SAMPLERATE'])) | |
| 66 | + | output.append(" CREATOR: " + str(i['CREATOR'])) | |
| 67 | + | output.append(" ARTIST: " + str(i['ARTIST'])) | |
| 68 | + | output.append(" ALBUM: " + str(i['ALBUM'])) | |
| 69 | + | output.append(" GENRE: " + str(i['GENRE'])) | |
| 70 | + | output.append(" COMMENT: " + str(i['COMMENT'])) | |
| 71 | + | output.append(" CHANNELS: " + str(i['CHANNELS'])) | |
| 72 | + | output.append(" DISC: " + str(i['DISC'])) | |
| 73 | + | output.append(" TRACK: " + str(i['TRACK'])) | |
| 74 | + | output.append(" DATE: " + str(i['DATE'])) | |
| 75 | + | output.append(" RESOLUTION: " + str(i['RESOLUTION'])) | |
| 76 | + | output.append(" THUMBNAIL: " + str(i['THUMBNAIL'])) | |
| 77 | + | output.append(" ALBUM_ART: " + str(i['ALBUM_ART'])) | |
| 78 | + | output.append(" ROTATION: " + str(i['ROTATION'])) | |
| 79 | + | output.append(" DLNA_PN: " + str(i['DLNA_PN'])) | |
| 80 | + | output.append(" MIME: " + str(i['MIME'])) | |
| 81 | + | output.append("") | |
| 82 | + | textbox.insert(INSERT, "\n".join(output)) | |
| 83 | + | ||
| 84 | + | bottom = Button(rightside, text="Submit", command=buttonCallback) | |
| 85 | + | rightside.add(bottom) | |
| 86 | + | mainloop() | |
server.py(file created)
| @@ -0,0 +1,53 @@ | |||
| 1 | + | # Requirements (rather, the versions of these requirements that I have): | |
| 2 | + | # Flask==0.10.1 | |
| 3 | + | # Flask-Restless==0.12.0 | |
| 4 | + | # Flask-SQLAlchemy==1.0 | |
| 5 | + | # SQLAlchemy==0.8.2 | |
| 6 | + | ||
| 7 | + | # Run this on the media server. It runs on port 5000 by default. | |
| 8 | + | ||
| 9 | + | # Copyright 2013 Steven Smith (blha303). All Rights Reserved. | |
| 10 | + | # New BSD license | |
| 11 | + | # http://www.opensource.org/licenses/BSD-3-Clause | |
| 12 | + | ||
| 13 | + | import flask | |
| 14 | + | import flask.ext.sqlalchemy | |
| 15 | + | app = flask.Flask(__name__) | |
| 16 | + | app.config['DEBUG'] = True | |
| 17 | + | app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:////var/lib/minidlna/files.db' | |
| 18 | + | #app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///data.db' | |
| 19 | + | db = flask.ext.sqlalchemy.SQLAlchemy(app) | |
| 20 | + | ||
| 21 | + | class Details(db.Model): | |
| 22 | + | __tablename__ = "DETAILS" | |
| 23 | + | ID = db.Column(db.Integer, primary_key=True) | |
| 24 | + | PATH = db.Column(db.Text) | |
| 25 | + | SIZE = db.Column(db.Integer) | |
| 26 | + | TIMESTAMP = db.Column(db.Integer) | |
| 27 | + | TITLE = db.Column(db.Text) | |
| 28 | + | DURATION = db.Column(db.Text) | |
| 29 | + | BITRATE = db.Column(db.Integer) | |
| 30 | + | SAMPLERATE = db.Column(db.Integer) | |
| 31 | + | CREATOR = db.Column(db.Text) | |
| 32 | + | ARTIST = db.Column(db.Text) | |
| 33 | + | ALBUM = db.Column(db.Text) | |
| 34 | + | GENRE = db.Column(db.Text) | |
| 35 | + | COMMENT = db.Column(db.Text) | |
| 36 | + | CHANNELS = db.Column(db.Integer) | |
| 37 | + | DISC = db.Column(db.Integer) | |
| 38 | + | TRACK = db.Column(db.Integer) | |
| 39 | + | DATE = db.Column(db.Date) | |
| 40 | + | RESOLUTION = db.Column(db.Text) | |
| 41 | + | THUMBNAIL = db.Column(db.Boolean) | |
| 42 | + | ALBUM_ART = db.Column(db.Integer) | |
| 43 | + | ROTATION = db.Column(db.Integer) | |
| 44 | + | DLNA_PN = db.Column(db.Text) | |
| 45 | + | MIME = db.Column(db.Text) | |
| 46 | + | ||
| 47 | + | import flask.ext.restless | |
| 48 | + | ||
| 49 | + | manager = flask.ext.restless.APIManager(app, flask_sqlalchemy_db=db) | |
| 50 | + | ||
| 51 | + | manager.create_api(Details, methods=['GET'], results_per_page=20) | |
| 52 | + | ||
| 53 | + | app.run(host='0.0.0.0') | |