Closed zoreu closed 1 year 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><DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:sec="http://www.sec.co.kr/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item restricted="1" id="PlayOn-content" parentID=""><upnp:class>object.item.videoItem</upnp:class><dc:title>v.mkv</dc:title><res protocolInfo="http-get:*:application/octet-stream:DLNA.ORG_PN=;DLNA.ORG_OP=01;DLNA.ORG_FLAGS=21700000000000000000000000000000">###uri###</res></item></DIDL-Lite></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><DIDL-Lite xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:dlna="urn:schemas-dlna-org:metadata-1-0/" xmlns:upnp="urn:schemas-upnp-org:metadata-1-0/upnp/" xmlns:sec="http://www.sec.co.kr/" xmlns="urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/"><item restricted="1" id="PlayOn-content" parentID=""><upnp:class>object.item.videoItem</upnp:class><dc:title>v.mkv</dc:title><res protocolInfo="http-get:*:application/octet-stream:DLNA.ORG_PN=;DLNA.ORG_OP=00;DLNA.ORG_FLAGS=01700000000000000000000000000000" sec:URIType="public">###uri###</res></item></DIDL-Lite></CurrentURIMetaData>\n</u:SetAVTransportURI>\n</s:Body>\n</s:Envelope>'
where:
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 ?...).
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
example module to kodi - https://mirrors.kodi.tv/addons/matrix/script.module.requests/script.module.requests-2.27.1+matrix.1.zip
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:
import the module and instantiate the DLNA Controller:
import PlayOn
DLNARendererControllerInstance = PlayOn.DLNAController()
to use the default network interface or DLNARendererControllerInstance = PlayOn.DLNAController(ip='0.0.0.0')
to operate on all interfaces
then discover the renderers, using either search or advertisements listening (or both); if we opt for the first one, it can be run in a synchronous or asynchronous way
DLNARendererControllerInstance.discover(timeout=5)
to allow 5 seconds to the renderers to respond
code to present the renderers to the user
or
DLNARendererControllerInstance.start_discovery_polling(timeout=5, alive_persistence=86400, polling_period=10)
to search every 10 seconds during 5 seconds
while XXX:
. DLNARendererControllerInstance.wait_for_discovery()
. code to present the new registered renderers to the user
DLNARendererControllerInstance.stop_discovery_polling()
where the renderers can be found in DLNARendererControllerInstance.Renderers by checking that they are alive and fully registered
[(r, renderer) for r, renderer in enumerate(DLNARendererControllerInstance.Renderers) if renderer.StatusAlive and bool(renderer.BaseURL)]
and for each renderer, the useful infos are in renderer.FriendlyName, renderer.Ip, renderer.UDN et renderer.IconURL
allow the user to select the desired renderer from the list, using the index "r" to retrieve it from DLNARendererControllerInstance.Renderers
renderer = DLNARendererControllerInstance.Renderers[r]
then send the infos related to the media to the renderer (not only the url, other data are also expected by the protocol)
DLNARendererControllerInstance.send_Local_URI(renderer, uri, title, kind, size, duration)
for a local uri accepting partial requests
or
DLNARendererControllerInstancer.send_URI(renderer, uri, title, kind, size, duration)
or to try the first option and fall back to the second one if the renderer rejects the command
if not DLNARendererControllerInstance.send_Local_URI(renderer, uri, title, kind, size, duration):
. DLNARendererControllerInstance.send_URI(renderer, uri, title, kind, size, duration)
where "kind" should be "video", "audio" or "music"
Whether the renderer will accept an incorrect "kind" or no "size" nor "duration" data, and whether it will accept uri outside of the private network mask is totally device dependant (my Samsung TV requests 'sec:URIType="public"' in the DIDL to accept such uris, but "sec" is in a Samsung specific namespace so is unlikely to be recognized by LG devices).
then send the "play" command
DLNARendererControllerInstancer.send_Play(renderer)
ok i will try
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)
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) `
Sorry, it was:
renderer = DLNARendererControllerInstance.Renderers[r]
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)
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)
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.
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)
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)
Try to put the send_URI inside a print(). If you get False, the command was rejected by the device.
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
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
PlayOn c -tn uri
open the panel with: [LG] webOS TV UN8000PSD 192.168.0.4
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?
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.
this command works: playon.py c http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4 but not by the code
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" ?
playon.py c
exactly playon.py c works but not playon.py c -tn
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()
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))
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)
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
Got it with a web server, now I can stream the channels to the TV
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