PCigales / DLNAPlayOn

A script in Python 3 to play, with control through a web interface, local and remote contents to a DLNA / UPnP renderer
GNU General Public License v3.0
16 stars 3 forks source link

simple code #2

Closed zoreu closed 1 year ago

zoreu commented 2 years ago

could you send me a simpler code to transmit a url to tv? I want to adapt for addon of kodi if you can show me a simple code to transmit a url to tv so i can adapt it in kodi i would be very grateful

note: kodi has dlna but it doesn't work with smart tv from LG, I wanted a separate script

PCigales commented 2 years ago

I would be glad to help you, but I am not sure to quite understand what you are asking me, and I don't know either if the script works with a LG smart tv.

To transmit a url to a DLNA renderer, you have to send this kind of message to the device:

b'POST ###path### HTTP/1.1\r\nHost: ###address###\r\nUser-Agent: PlayOn DLNA Controller\r\nContent-Type: text/xml; charset="utf-8"\r\nSOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"\r\nAccept-Encoding: identity\r\nContent-Length: 1115\r\nConnection: close\r\n\r\n<?xml version="1.0"?>\n<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">\n<s:Body>\n<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">\n<InstanceID>0</InstanceID>\n<CurrentURI>###uri###</CurrentURI>\n<CurrentURIMetaData>&lt;DIDL-Lite xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:dlna=&quot;urn:schemas-dlna-org:metadata-1-0/&quot; xmlns:upnp=&quot;urn:schemas-upnp-org:metadata-1-0/upnp/&quot; xmlns:sec=&quot;http://www.sec.co.kr/&quot; xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item restricted=&quot;1&quot; id=&quot;PlayOn-content&quot; parentID=&quot;&quot;&gt;&lt;upnp:class&gt;object.item.videoItem&lt;/upnp:class&gt;&lt;dc:title&gt;v.mkv&lt;/dc:title&gt;&lt;res protocolInfo=&quot;http-get:*:application/octet-stream:DLNA.ORG_PN=;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=21700000000000000000000000000000&quot;&gt;###uri###&lt;/res&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</CurrentURIMetaData>\n</u:SetAVTransportURI>\n</s:Body>\n</s:Envelope>'

or, if it is an uri beyond the private network:

b'POST ###path### HTTP/1.1\r\nHost: ###address###\r\nUser-Agent: PlayOn DLNA Controller\r\nContent-Type: text/xml; charset="utf-8"\r\nSOAPAction: "urn:schemas-upnp-org:service:AVTransport:1#SetAVTransportURI"\r\nAccept-Encoding: identity\r\nContent-Length: 1146\r\nConnection: close\r\n\r\n<?xml version="1.0"?>\n<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">\n<s:Body>\n<u:SetAVTransportURI xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">\n<InstanceID>0</InstanceID>\n<CurrentURI>###uri###</CurrentURI>\n<CurrentURIMetaData>&lt;DIDL-Lite xmlns:dc=&quot;http://purl.org/dc/elements/1.1/&quot; xmlns:dlna=&quot;urn:schemas-dlna-org:metadata-1-0/&quot; xmlns:upnp=&quot;urn:schemas-upnp-org:metadata-1-0/upnp/&quot; xmlns:sec=&quot;http://www.sec.co.kr/&quot; xmlns=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item restricted=&quot;1&quot; id=&quot;PlayOn-content&quot; parentID=&quot;&quot;&gt;&lt;upnp:class&gt;object.item.videoItem&lt;/upnp:class&gt;&lt;dc:title&gt;v.mkv&lt;/dc:title&gt;&lt;res protocolInfo=&quot;http-get:*:application/octet-stream:DLNA.ORG_PN=;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=01700000000000000000000000000000&quot; sec:URIType=&quot;public&quot;&gt;###uri###&lt;/res&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</CurrentURIMetaData>\n</u:SetAVTransportURI>\n</s:Body>\n</s:Envelope>'

where:

address### must be replaced by the address of the renderer (ex: 192.168.1.12:9100)

uri### by the url (ex: http://192.168.1.12:9003/media.mkv)

path### by the path of the control url of the AVTransport service (ex: /AVT_C)

I could provide you with a code for that, extracted from this script, but I would need more details on how it must integrate itself in kodi (will kodi provide the control url ? trigger the playback ?...).

zoreu commented 2 years ago

could you not create a simple one based on PlayOn.py ? I just need a module it has to be one to discover the device and put it on a list and then select the device and send the url to tv PlayOn.py works on the LG smartv if it could turn it into a module that could be used inside a python script my idea is to create a context menu in the addon to open a function to discover the tv, the user chooses the tv and the script sends the url of the video and start video https://i.imgur.com/FmSVLNO.jpg

if necessary, the documentation https://alwinesch.github.io/index.html

example module to kodi - https://mirrors.kodi.tv/addons/matrix/script.module.requests/script.module.requests-2.27.1+matrix.1.zip

PCigales commented 2 years ago

I think I have understood. I wonder if the most convenient for the user would not be to run PlayOn from the context menu so that the playback could be controlled through the web interface and in order to take advantage of the various features (buffering, playlist...) but let's stick to what you ask for.

PlayOn.py has been designed to be used both as a script and as a module. DLNAController.py illustrates the second option.

In your case, what you would have to do is:

zoreu commented 2 years ago

ok i will try

zoreu commented 2 years ago

this error appears: [(0, <PlayOn.DLNARenderer object at 0x000001BFE63327C8>)] Traceback (most recent call last): File "c:\Users\Joel\Desktop\dlnascript\dlna.py", line 13, in <module> renderer = DLNARendererControllerInstance.Renderer[r] AttributeError: 'DLNAController' object has no attribute 'Renderer'

from this code: `import PlayOn

DLNARendererControllerInstance = PlayOn.DLNAController(ip='0.0.0.0')

mylist = [(r, renderer) for r, renderer in enumerate(DLNARendererControllerInstance.Renderers) if renderer.StatusAlive and bool(renderer.BaseURL)]

print(mylist)

mylist[0][0] indice

mylist[0][1] objeto

r = mylist[0][0]

renderer = DLNARendererControllerInstance.Renderer[r]

uri = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4'

kind = 'video'

size = ''

duration = ''

title = 'teste'

DLNARendererControllerInstance.send_URI(renderer, uri, title, kind, size, duration)

DLNARendererControllerInstance.send_Play(renderer) `

PCigales commented 2 years ago

Sorry, it was: renderer = DLNARendererControllerInstance.Renderers[r]

zoreu commented 2 years ago

Is size and duration mandatory? how do i detect this from a url? and if it's a channel like .m3u8? are they integers or strings?

here is not going

import PlayOn

DLNARendererControllerInstance = PlayOn.DLNAController(ip='0.0.0.0')

DLNARendererControllerInstance.discover(timeout=5)

mylist = [(r, renderer) for r, renderer in enumerate(DLNARendererControllerInstance.Renderers) if renderer.StatusAlive and bool(renderer.BaseURL)]

print(mylist)

mylist[0][0] indice

mylist[0][1] objeto

if mylist:

r = mylist[0][0]

renderer = DLNARendererControllerInstance.Renderers[r]

uri = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4'

kind = 'video'

size = ''

duration = ''

title = 'teste'

DLNARendererControllerInstance.send_URI(renderer, uri, title, kind, size, duration)

DLNARendererControllerInstance.send_Play(renderer)

PCigales commented 2 years ago

Not necessarily, it depends on the renderer. These arguments can be provided as string or number. Try to not provide them in the call, you will see.

zoreu commented 2 years ago

here is not going

import PlayOn

DLNARendererControllerInstance = PlayOn.DLNAController(ip='0.0.0.0')

DLNARendererControllerInstance.discover(timeout=5)

mylist = [(r, renderer) for r, renderer in enumerate(DLNARendererControllerInstance.Renderers) if renderer.StatusAlive and bool(renderer.BaseURL)]

print(mylist)

mylist[0][0] indice

mylist[0][1] objeto

if mylist:

r = mylist[0][0]

renderer = DLNARendererControllerInstance.Renderers[r]

uri = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4'

kind = 'video'

size = ''

duration = ''

title = 'teste'

DLNARendererControllerInstance.send_URI(renderer, uri, title, kind, size, duration)

DLNARendererControllerInstance.send_Play(renderer)

PCigales commented 2 years ago

Try to put the send_URI inside a print(). If you get False, the command was rejected by the device.

zoreu commented 2 years ago

Try to put the send_URI inside a print(). If you get False, the command was rejected by the device.

gave me value None

by command playon.py c http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4

it works but not by this code

PCigales commented 2 years ago

It is the same, the TV does not accept the command, maybe because it is a public address. Could you try: PlayOn c -t n uri

zoreu commented 2 years ago

PlayOn c -tn uri

open the panel with: [LG] webOS TV UN8000PSD 192.168.0.4

zoreu commented 2 years ago

I changed: DLNARendererControllerInstance = PlayOn.DLNA Controller(ip='0.0.0.0') per: DLNARenderer Controller Instance = PlayOn.DLNAController()

and it worked but the tv does not recognize the file, do you need something?

PCigales commented 2 years ago

The option -t n prevents the delivery of the media from a local server operated by the script, and directly send the uri to the device. As I mentioned previously, some renderers refuse public address or request a specific parameter (sec:URIType="public" for Samsung TV), for security reasons. I have no idea regarding LG TV.

zoreu commented 2 years ago

this command works: playon.py c http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4 but not by the code

zoreu commented 2 years ago

XML TV - http://192.168.0.4:2022/

https://pastecode.io/s/8rv8h12p

PCigales commented 2 years ago

I just tested your code with my Samsung TV, and it worked like a charm.

Can you confirm that "playon.py c http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4" works but not "playon.py c -t n http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4" ?

zoreu commented 2 years ago

playon.py c

exactly playon.py c works but not playon.py c -tn

PCigales commented 2 years ago

So that is the explanation: your TV does not accept public addresses or it needs a trick.

You can therefore try:

renderer_hip = DLNARendererControllerInstance.Hips[r] MediaServerInstance = PlayOn.MediaServer(PlayOn.MediaProvider.SERVER_MODE_RANDOM, (renderer_hip, 8000), uri, MediaSrcType='ContentURL', MediaProcessProfile=renderer.FriendlyName, auth_ip=(renderer.Ip, *DLNARendererControllerInstance.ips)) MediaServerInstance.start() print(MediaServerInstance.wait()) uri2='http://%s:%s/media%s' % (*MediaServerInstance.MediaServerAddress, MediaServerInstance.MediaProviderInstance.MediaFeedExt) DLNARendererControllerInstance.send_URI(renderer, uri2, title, kind, size, duration) DLNARendererControllerInstance.send_Play(renderer)

You will need to authorize Python to listen on TCP port 8000 (or choose another one) in your firewall.

Eventually, you have to close the media server: MediaServerInstance.shutdown()

zoreu commented 2 years ago

So that is the explanation: your TV does not accept public addresses or it needs a trick.

You can therefore try:

renderer_hip = DLNARendererControllerInstance.Hips[r] MediaServerInstance = PlayOn.MediaServer(PlayOn.MediaProvider.SERVER_MODE_RANDOM, (renderer_hip, 8000), uri, MediaSrcType='ContentURL', MediaProcessProfile=renderer.FriendlyName, auth_ip=(renderer.Ip, *DLNARendererControllerInstance.ips)) MediaServerInstance.start() print(MediaServerInstance.wait()) uri2='http://%s:%s/media%s' % (*MediaServerInstance.MediaServerAddress, MediaServerInstance.MediaProviderInstance.MediaFeedExt) DLNARendererControllerInstance.send_URI(renderer, uri2, title, kind, size, duration) DLNARendererControllerInstance.send_Play(renderer)

You will need to authorize Python to listen on TCP port 8000 (or choose another one) in your firewall.

Eventually, you have to close the media server: MediaServerInstance.shutdown()

is returning me None in: print(DLNARendererControllerInstance.send_URI(renderer, uri2, title, type, size, duration))

PCigales commented 2 years ago

Have you tried print(DLNARendererControllerInstance.send_Local_URI(renderer, uri2, title, type, size, duration)) ?

After uri2 = ..., could you print(uri2) to check its content ?

Also, consider increasing the verbosity by: DLNARendererControllerInstance = PlayOn.DLNAController(ip='0.0.0.0',verbosity=2) or DLNARendererControllerInstance = PlayOn.DLNAController(verbosity=2)

zoreu commented 2 years ago

there was an error I still think that this scheme does not work with lg, I'm thinking of putting together an addon with a web server for someone to add to the smartv ssiptv, almost all of them have this app, if you want you can close the issue

zoreu commented 1 year ago

Got it with a web server, now I can stream the channels to the TV