tiny-dlna 0.2.0__tar.gz → 0.4.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.2.0 → tiny-dlna-0.4.0}/PKG-INFO +1 -1
- tiny-dlna-0.4.0/README.md +30 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/setup.py +1 -1
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/ssdp.py +18 -15
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/PKG-INFO +1 -1
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_render.py +40 -44
- tiny-dlna-0.2.0/README.md +0 -13
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/setup.cfg +0 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/SOURCES.txt +0 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/dependency_links.txt +0 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/entry_points.txt +0 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/requires.txt +0 -0
- {tiny-dlna-0.2.0 → tiny-dlna-0.4.0}/tiny_dlna.egg-info/top_level.txt +0 -0
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
# Tiny DLNA
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```
|
|
6
|
+
$ pip install tiny-dlna
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
## Tiny DLNA Render
|
|
10
|
+
|
|
11
|
+
Just to support subtitles.
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
$ tiny-render
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
This will activate a DLNA receiver named "Tiny Render", which can stream videos
|
|
18
|
+
from apps like 虎牙直播, Bilibili, and other video platforms. Additionally, you
|
|
19
|
+
can also use `nano-dlna` to play local videos (like in your RaspberryPi) on it.
|
|
20
|
+
|
|
21
|
+
> Note: [mpv](https://mpv.io/) needs to be installed on your system.
|
|
22
|
+
|
|
23
|
+
## Tiny DLNA Cli
|
|
24
|
+
|
|
25
|
+
To do.
|
|
26
|
+
|
|
27
|
+
## Related projects
|
|
28
|
+
|
|
29
|
+
- https://github.com/xfangfang/Macast
|
|
30
|
+
- https://github.com/gabrielmagno/nano-dlna
|
|
@@ -1,24 +1,27 @@
|
|
|
1
|
+
import datetime
|
|
1
2
|
import logging
|
|
2
3
|
import socket
|
|
3
4
|
|
|
4
5
|
SSDP_MULTICAST = '239.255.255.250'
|
|
5
6
|
SSDP_PORT = 1900
|
|
6
|
-
|
|
7
|
-
|
|
7
|
+
RENDER_PORT = 55000
|
|
8
|
+
LOCATION = f'http://192.168.1.228:{RENDER_PORT}/description.xml'
|
|
9
|
+
UUID = 'd095ee0c-7bed-43d0-bf98-f815496e8383'
|
|
10
|
+
logger = logging.getLogger('ssdp')
|
|
8
11
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
'EXT:\r\n'
|
|
13
|
-
f'LOCATION: {LOCATION}\r\n'
|
|
14
|
-
'HOSTNAME: 192.168.1.228\r\n'
|
|
15
|
-
'SERVER: Custom/1.0 UPnP/1.0 DLNADOC/1.50\r\n'
|
|
16
|
-
f'ST: urn:schemas-upnp-org:service:AVTransport:1\r\n'
|
|
17
|
-
f'USN: {USN}\r\n'
|
|
18
|
-
'\r\n'
|
|
19
|
-
)
|
|
12
|
+
def build_m_search_response():
|
|
13
|
+
now = datetime.datetime.utcnow()
|
|
14
|
+
date_str = now.strftime("%a, %d %b %Y %H:%M:%S GMT")
|
|
20
15
|
|
|
21
|
-
|
|
16
|
+
text = 'HTTP/1.1 200 OK\r\n'
|
|
17
|
+
text += f'USN: uuid:{UUID}::urn:schemas-upnp-org:service:AVTransport:1\r\n'
|
|
18
|
+
text += f'Location: {LOCATION}\r\n'
|
|
19
|
+
text += 'ST: urn:schemas-upnp-org:service:AVTransport:1\r\n'
|
|
20
|
+
text += 'EXT: \r\n'
|
|
21
|
+
text += 'Server: Werkzeug/3.0.3 Python/3.11.0\r\n'
|
|
22
|
+
text += 'Cache-Control: max-age=70\r\n'
|
|
23
|
+
text += f'Date: {date_str}\r\n\r\n'
|
|
24
|
+
return text.encode('utf-8')
|
|
22
25
|
|
|
23
26
|
def ssdp_listener():
|
|
24
27
|
sock = socket.socket(socket.AF_INET, socket.SOCK_DGRAM, socket.IPPROTO_UDP)
|
|
@@ -33,7 +36,7 @@ def ssdp_listener():
|
|
|
33
36
|
data, addr = sock.recvfrom(1024)
|
|
34
37
|
if b'M-SEARCH' in data and b'ssdp:discover' in data:
|
|
35
38
|
logger.info(f'Received M-SEARCH from {addr}, sending response...')
|
|
36
|
-
sock.sendto(
|
|
39
|
+
sock.sendto(build_m_search_response(), addr)
|
|
37
40
|
|
|
38
41
|
if __name__ == '__main__':
|
|
39
42
|
ssdp_listener()
|
|
@@ -7,11 +7,38 @@ import time
|
|
|
7
7
|
import xml.etree.ElementTree as ET
|
|
8
8
|
|
|
9
9
|
from flask import Flask, request, Response
|
|
10
|
-
from ssdp import ssdp_listener
|
|
10
|
+
from ssdp import ssdp_listener, RENDER_PORT, UUID
|
|
11
11
|
|
|
12
12
|
app = Flask(__name__)
|
|
13
13
|
logger = logging.getLogger('tiny_render')
|
|
14
14
|
|
|
15
|
+
|
|
16
|
+
XML_DESC_PTN = """<?xml version="1.0" encoding="UTF-8"?>
|
|
17
|
+
<root xmlns:dlna="urn:schemas-dlna-org:device-1-0" xmlns="urn:schemas-upnp-org:device-1-0">
|
|
18
|
+
<specVersion>
|
|
19
|
+
<major>1</major>
|
|
20
|
+
<minor>0</minor>
|
|
21
|
+
</specVersion>
|
|
22
|
+
<device>
|
|
23
|
+
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
|
|
24
|
+
<friendlyName>{}</friendlyName>
|
|
25
|
+
<manufacturer>mitnk</manufacturer>
|
|
26
|
+
<modelName>Tiny-Render</modelName>
|
|
27
|
+
<modelDescription>AVTransport Media Renderer</modelDescription>
|
|
28
|
+
<UDN>uuid:{}</UDN>
|
|
29
|
+
<dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC>
|
|
30
|
+
<serviceList>
|
|
31
|
+
<service>
|
|
32
|
+
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
|
|
33
|
+
<serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
|
|
34
|
+
<SCPDURL>AVTransport/scpd.xml</SCPDURL>
|
|
35
|
+
<controlURL>AVTransport/control</controlURL>
|
|
36
|
+
<eventSubURL>AVTransport/event</eventSubURL>
|
|
37
|
+
</service>
|
|
38
|
+
</serviceList>
|
|
39
|
+
</device>
|
|
40
|
+
</root>"""
|
|
41
|
+
|
|
15
42
|
XML_AVSET_DONE = """
|
|
16
43
|
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
|
|
17
44
|
<s:Body>
|
|
@@ -95,44 +122,8 @@ _DATA = {
|
|
|
95
122
|
|
|
96
123
|
@app.route('/description.xml')
|
|
97
124
|
def description():
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<specVersion>
|
|
101
|
-
<major>1</major>
|
|
102
|
-
<minor>0</minor>
|
|
103
|
-
</specVersion>
|
|
104
|
-
<device>
|
|
105
|
-
<deviceType>urn:schemas-upnp-org:device:MediaRenderer:1</deviceType>
|
|
106
|
-
<friendlyName>Tiny Render</friendlyName>
|
|
107
|
-
<manufacturer>mitnk</manufacturer>
|
|
108
|
-
<modelName>T001</modelName>
|
|
109
|
-
<UDN>uuid:dlna-tiny-render-t001</UDN>
|
|
110
|
-
<dlna:X_DLNADOC xmlns:dlna="urn:schemas-dlna-org:device-1-0">DMR-1.50</dlna:X_DLNADOC>
|
|
111
|
-
<serviceList>
|
|
112
|
-
<service>
|
|
113
|
-
<serviceType>urn:schemas-upnp-org:service:AVTransport:1</serviceType>
|
|
114
|
-
<serviceId>urn:upnp-org:serviceId:AVTransport</serviceId>
|
|
115
|
-
<SCPDURL>AVTransport/82d8-eb72-b097/scpd.xml</SCPDURL>
|
|
116
|
-
<controlURL>AVTransport/82d8-eb72-b097/control</controlURL>
|
|
117
|
-
<eventSubURL>AVTransport/82d8-eb72-b097/event</eventSubURL>
|
|
118
|
-
</service>
|
|
119
|
-
<service>
|
|
120
|
-
<serviceType>urn:schemas-upnp-org:service:ConnectionManager:1</serviceType>
|
|
121
|
-
<serviceId>urn:upnp-org:serviceId:ConnectionManager</serviceId>
|
|
122
|
-
<SCPDURL>ConnectionManager/82d8-eb72-b097/scpd.xml</SCPDURL>
|
|
123
|
-
<controlURL>ConnectionManager/82d8-eb72-b097/control</controlURL>
|
|
124
|
-
<eventSubURL>ConnectionManager/82d8-eb72-b097/event</eventSubURL>
|
|
125
|
-
</service>
|
|
126
|
-
<service>
|
|
127
|
-
<serviceType>urn:schemas-upnp-org:service:RenderingControl:1</serviceType>
|
|
128
|
-
<serviceId>urn:upnp-org:serviceId:RenderingControl</serviceId>
|
|
129
|
-
<SCPDURL>RenderingControl/82d8-eb72-b097/scpd.xml</SCPDURL>
|
|
130
|
-
<controlURL>RenderingControl/82d8-eb72-b097/control</controlURL>
|
|
131
|
-
<eventSubURL>RenderingControl/82d8-eb72-b097/event</eventSubURL>
|
|
132
|
-
</service>
|
|
133
|
-
</serviceList>
|
|
134
|
-
</device>
|
|
135
|
-
</root>"""
|
|
125
|
+
friendly_name = app.config['FRIENDLY_NAME']
|
|
126
|
+
xml = XML_DESC_PTN.format(friendly_name, UUID)
|
|
136
127
|
return Response(xml, mimetype="text/xml")
|
|
137
128
|
|
|
138
129
|
def to_track_time(seconds):
|
|
@@ -199,7 +190,7 @@ def get_metadata(request):
|
|
|
199
190
|
}
|
|
200
191
|
|
|
201
192
|
|
|
202
|
-
@app.route('/AVTransport/
|
|
193
|
+
@app.route('/AVTransport/control', methods=['POST'])
|
|
203
194
|
def control():
|
|
204
195
|
if is_setav(request):
|
|
205
196
|
metadata = get_metadata(request)
|
|
@@ -260,9 +251,10 @@ class SSDPServer(threading.Thread):
|
|
|
260
251
|
def main():
|
|
261
252
|
import argparse
|
|
262
253
|
|
|
263
|
-
parser = argparse.ArgumentParser(prog='tiny-
|
|
264
|
-
parser.add_argument('--http-log', action='store_true')
|
|
265
|
-
parser.add_argument('--verbose', '-v', action='store_true')
|
|
254
|
+
parser = argparse.ArgumentParser(prog='tiny-render')
|
|
255
|
+
parser.add_argument('--http-log', action='store_true', help='Enable server logs')
|
|
256
|
+
parser.add_argument('--verbose', '-v', action='store_true', help='Enable debug logs')
|
|
257
|
+
parser.add_argument('--name', type=str, default='Tiny Render', help='Change render name')
|
|
266
258
|
|
|
267
259
|
args = parser.parse_args()
|
|
268
260
|
|
|
@@ -280,7 +272,11 @@ def main():
|
|
|
280
272
|
|
|
281
273
|
ssdp = SSDPServer()
|
|
282
274
|
ssdp.start()
|
|
283
|
-
|
|
275
|
+
|
|
276
|
+
friendly_name = args.name
|
|
277
|
+
app.config['FRIENDLY_NAME'] = friendly_name
|
|
278
|
+
logging.info(f'Starting DLNA Receiver: {friendly_name}')
|
|
279
|
+
app.run(host="0.0.0.0", port=RENDER_PORT, debug=False)
|
|
284
280
|
|
|
285
281
|
|
|
286
282
|
if __name__ == "__main__":
|
tiny-dlna-0.2.0/README.md
DELETED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|