Last active 1531452378

MiniDLNA Python REST API server and associated Tkinter GUI for reading from it https://github.com/blha303/PythonMiniDLNARestAPI

Steven Smith revised this gist 1377183648. 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 1377182845. 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 1377182698. 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 1377182312. 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 1377182300. 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 1377182082. 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 1377182003. 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')
Newer Older