tiny-dlna 0.0.1__tar.gz → 0.2.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/PKG-INFO +1 -1
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/setup.py +1 -1
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/ssdp.py +4 -1
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/PKG-INFO +1 -1
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_render.py +49 -19
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/README.md +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/setup.cfg +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/SOURCES.txt +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/dependency_links.txt +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/entry_points.txt +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/requires.txt +0 -0
- {tiny-dlna-0.0.1 → tiny-dlna-0.2.0}/tiny_dlna.egg-info/top_level.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import logging
|
|
1
2
|
import socket
|
|
2
3
|
|
|
3
4
|
SSDP_MULTICAST = '239.255.255.250'
|
|
@@ -17,6 +18,8 @@ ssdp_response = (
|
|
|
17
18
|
'\r\n'
|
|
18
19
|
)
|
|
19
20
|
|
|
21
|
+
logger = logging.getLogger('ssdp')
|
|
22
|
+
|
|
20
23
|
def ssdp_listener():
|
|
21
24
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
|
22
25
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
|
|
@@ -29,7 +32,7 @@ def ssdp_listener():
|
|
|
29
32
|
while True:
|
|
30
33
|
data, addr = sock.recvfrom(1024)
|
|
31
34
|
if b'M-SEARCH' in data and b'ssdp:discover' in data:
|
|
32
|
-
|
|
35
|
+
logger.info(f'Received M-SEARCH from {addr}, sending response...')
|
|
33
36
|
sock.sendto(ssdp_response.encode('utf-8'), addr)
|
|
34
37
|
|
|
35
38
|
if __name__ == '__main__':
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import html
|
|
2
|
+
import logging
|
|
2
3
|
import re
|
|
3
4
|
import subprocess
|
|
4
5
|
import threading
|
|
@@ -9,6 +10,7 @@ from flask import Flask, request, Response
|
|
|
9
10
|
from ssdp import ssdp_listener
|
|
10
11
|
|
|
11
12
|
app = Flask(__name__)
|
|
13
|
+
logger = logging.getLogger('tiny_render')
|
|
12
14
|
|
|
13
15
|
XML_AVSET_DONE = """
|
|
14
16
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
|
@@ -72,7 +74,9 @@ class MPVRenderer:
|
|
|
72
74
|
cmd.append('--title={}'.format(title))
|
|
73
75
|
if srt:
|
|
74
76
|
cmd.append('--sub-file={}'.format(srt))
|
|
75
|
-
|
|
77
|
+
|
|
78
|
+
logger.debug(f'running mpv: {cmd}')
|
|
79
|
+
self.process = subprocess.Popen(cmd, stderr=subprocess.DEVNULL)
|
|
76
80
|
|
|
77
81
|
def stop_media(self):
|
|
78
82
|
if self.process:
|
|
@@ -152,6 +156,9 @@ def is_gettrans(request):
|
|
|
152
156
|
def is_getpos(request):
|
|
153
157
|
return b'u:GetPositionInfo' in request.data
|
|
154
158
|
|
|
159
|
+
def is_seek(request):
|
|
160
|
+
return b'u:Seek' in request.data
|
|
161
|
+
|
|
155
162
|
def get_title_re(xml_data):
|
|
156
163
|
pattern = re.compile(r'<dc:title>(.*?)</dc:title>', re.DOTALL)
|
|
157
164
|
match = pattern.search(xml_data)
|
|
@@ -163,15 +170,15 @@ def get_metadata(request):
|
|
|
163
170
|
current_uri = root.find('.//CurrentURI').text
|
|
164
171
|
metadata = root.find('.//CurrentURIMetaData').text
|
|
165
172
|
|
|
166
|
-
current_srt =
|
|
167
|
-
title =
|
|
173
|
+
current_srt = ''
|
|
174
|
+
title = ''
|
|
168
175
|
|
|
169
176
|
metadata = html.unescape(metadata)
|
|
170
177
|
try:
|
|
171
178
|
metadata = ET.fromstring(metadata)
|
|
172
179
|
except ET.ParseError:
|
|
173
180
|
# HACK: fall back to `re` to get title only (e.g. Huya)
|
|
174
|
-
|
|
181
|
+
logger.debug('** got xml.ParseError, fall back to re')
|
|
175
182
|
title = get_title_re(metadata)
|
|
176
183
|
return {'video': current_uri, 'title': title}
|
|
177
184
|
|
|
@@ -196,18 +203,15 @@ def get_metadata(request):
|
|
|
196
203
|
def control():
|
|
197
204
|
if is_setav(request):
|
|
198
205
|
metadata = get_metadata(request)
|
|
199
|
-
|
|
200
206
|
current_uri = metadata['video']
|
|
201
|
-
current_srt = metadata.get('srt')
|
|
202
|
-
video_title = metadata.get('title')
|
|
207
|
+
current_srt = metadata.get('srt', '')
|
|
208
|
+
video_title = metadata.get('title', '')
|
|
203
209
|
|
|
204
|
-
|
|
210
|
+
logger.debug(f'Action: SetAV: {current_uri}')
|
|
211
|
+
logger.debug(f'SRT: {current_srt}')
|
|
205
212
|
_DATA['CURRENT_URI'] = current_uri
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
_DATA['CURRENT_SRT'] = current_srt
|
|
209
|
-
if video_title:
|
|
210
|
-
_DATA['VIDEO_TITLE'] = video_title
|
|
213
|
+
_DATA['CURRENT_SRT'] = current_srt
|
|
214
|
+
_DATA['VIDEO_TITLE'] = video_title
|
|
211
215
|
return Response(XML_AVSET_DONE, mimetype="text/xml")
|
|
212
216
|
|
|
213
217
|
elif is_play(request):
|
|
@@ -215,22 +219,24 @@ def control():
|
|
|
215
219
|
url = _DATA['CURRENT_URI']
|
|
216
220
|
srt = _DATA['CURRENT_SRT']
|
|
217
221
|
title = _DATA['VIDEO_TITLE']
|
|
218
|
-
|
|
222
|
+
logger.debug(f'action: Play: {url}')
|
|
223
|
+
logger.debug(f'title: {title} srt: {srt}')
|
|
219
224
|
renderer.play_media(url, title, srt)
|
|
220
225
|
return Response(XML_PLAY_DONE, mimetype="text/xml")
|
|
221
226
|
|
|
222
227
|
elif is_getpos(request):
|
|
223
|
-
|
|
228
|
+
logger.debug('action: GetPositionInfo')
|
|
224
229
|
seconds = int(time.time() - _DATA['STARTED_AT'])
|
|
225
230
|
reltime = to_track_time(seconds)
|
|
226
231
|
return Response(XML_POSINFO.format(reltime), mimetype="text/xml")
|
|
227
232
|
|
|
228
233
|
elif is_gettrans(request):
|
|
229
|
-
|
|
234
|
+
logger.debug('action: GetTransportInfo')
|
|
230
235
|
return Response(XML_TRANSINFO, mimetype="text/xml")
|
|
231
236
|
|
|
232
237
|
elif is_stop(request):
|
|
233
|
-
|
|
238
|
+
logger.debug('stopping')
|
|
239
|
+
|
|
234
240
|
_DATA['CURRENT_URI'] = ''
|
|
235
241
|
_DATA['CURRENT_SRT'] = ''
|
|
236
242
|
_DATA['VIDEO_TITLE'] = ''
|
|
@@ -238,7 +244,11 @@ def control():
|
|
|
238
244
|
renderer.stop_media()
|
|
239
245
|
return Response(XML_STOP_DONE, mimetype="text/xml")
|
|
240
246
|
|
|
241
|
-
|
|
247
|
+
elif is_seek(request):
|
|
248
|
+
logger.debug('seek')
|
|
249
|
+
return Response('To Seek', status=500)
|
|
250
|
+
|
|
251
|
+
logger.error(f'action not support: {request.data}')
|
|
242
252
|
return Response('Action Not Supported', status=500)
|
|
243
253
|
|
|
244
254
|
|
|
@@ -248,9 +258,29 @@ class SSDPServer(threading.Thread):
|
|
|
248
258
|
|
|
249
259
|
|
|
250
260
|
def main():
|
|
261
|
+
import argparse
|
|
262
|
+
|
|
263
|
+
parser = argparse.ArgumentParser(prog='tiny-dlna')
|
|
264
|
+
parser.add_argument('--http-log', action='store_true')
|
|
265
|
+
parser.add_argument('--verbose', '-v', action='store_true')
|
|
266
|
+
|
|
267
|
+
args = parser.parse_args()
|
|
268
|
+
|
|
269
|
+
logging.basicConfig(
|
|
270
|
+
level=logging.INFO,
|
|
271
|
+
format='[%(asctime)s][%(levelname)s] %(message)s',
|
|
272
|
+
)
|
|
273
|
+
|
|
274
|
+
if not args.http_log:
|
|
275
|
+
logging.getLogger('werkzeug').setLevel(logging.ERROR)
|
|
276
|
+
logging.getLogger('ssdp').setLevel(logging.ERROR)
|
|
277
|
+
|
|
278
|
+
if args.verbose:
|
|
279
|
+
logging.basicConfig(level=logging.DEBUG)
|
|
280
|
+
|
|
251
281
|
ssdp = SSDPServer()
|
|
252
282
|
ssdp.start()
|
|
253
|
-
app.run(host="0.0.0.0", port=5000)
|
|
283
|
+
app.run(host="0.0.0.0", port=5000, debug=False)
|
|
254
284
|
|
|
255
285
|
|
|
256
286
|
if __name__ == "__main__":
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|