jellyfin / jellyfin-plugin-dlna

GNU General Public License v3.0
12 stars 7 forks source link

DLNA Remote Control / Playlists don't work #7

Open zodi1337 opened 4 years ago

zodi1337 commented 4 years ago

Describe the bug Hey there!

After testing some medi-centers for my music libary i finally would like to stick with jellyfin because i really like it! Thanks for all your hard work dear developers!

Finally i face a problem like described in the issue title.

My Set up / Home Environment:

Jellyfin works like a charm using the webinterface or the android client while playing music and playlists on the local device. As you see on the screenshot all "control elements" are there and working correctly:

1

2

If i choose to push a playlist to an device via DLNA (button upper right corner), just the actual / first song is correctly playing on the selected device, but then it's always stop to play anything. At this time when i select a device the control elements" are gone. When using the "Remote Control" option from the selected device i see a more or less blank screen (last screenshot below). Weird thing is, that the Volume Control" is working properly remotely

With both devices the exact same happens.

3

4

To Reproduce

Expected behavior

Logs

jellyfin.log

Screenshots

System (please complete the following information):

Additional context Maybe you can merge this issue with issue jellyfin/jellyfin#2028 This guy describes exactly the same, but managed it with a workaround......

If i can deliver more info just feel free to ask!

gerroon commented 4 years ago

I was just going to bug about this too. Casting to Kodi is broken . This used to work in Emby times and the early Jellyfin times.

I do not mean the Kodi plugin, I mean casting the actual content to Kodi using the top right cast- playto menu.

The workaround mentioned is a totally different functionality since you also need a DLNA client to mitigate between Jellyfin and Kodi, in my view that is not the same thing.

willipreuk commented 4 years ago

I think the issue is, that the DLNA playback device sends malformed XML. Prior to version 10.5.0.0, the log threw an exception about non encoded URL chars. Maybe we could make the streaming more error resistant to support more and older DLNA devices.

JustAMan commented 4 years ago

cc @Bond-009

Bond-009 commented 4 years ago

Would need to see the returned xml to find out what's wrong

willipreuk commented 4 years ago

Can I turn on some kind of debug logging to see the returned XML?

JustAMan commented 4 years ago

I think you can do run stuff like tcpdump or wireshark to intercept the packets. Not sure if there's currently any logging that stores it (would be useful to have though, what do you think @Bond-009?)

Bond-009 commented 4 years ago

@JustAMan Yep, you are right afaik

JustAMan commented 4 years ago

Want to add some logs? :)

willipreuk commented 4 years ago

So first off, we have a MusicCast system from yamaha. In the musiccast app I can choose as a source a DLNA Player, there I can find Jellyfin and all Tracks - but the app is just garbage. I've never done a tcpdump, but I will paste the contents of some packets, which I think may be usefull, if you need more just let me know.

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:GetPositionInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <Track>1</Track>
      <TrackDuration>0:05:36</TrackDuration>
      <TrackMetaData>&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=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item restricted=&quot;1&quot; id=&quot;659c8429b055d5b039133a2694a76288&quot; parentID=&quot;228a1cc7b3bc4a8c96e5ce7d2e95901b&quot;&gt;&lt;dc:title&gt;Where the Streets Have No Name&lt;/dc:title&gt;&lt;upnp:class&gt;object.item.audioItem.musicTrack&lt;/upnp:class&gt;&lt;upnp:genre&gt;Rock&lt;/upnp:genre&gt;&lt;upnp:publisher&gt;Island&lt;/upnp:publisher&gt;&lt;upnp:artist&gt;U2&lt;/upnp:artist&gt;&lt;dc:creator&gt;U2&lt;/dc:creator&gt;&lt;upnp:artist role=&quot;AlbumArtist&quot;&gt;U2&lt;/upnp:artist&gt;&lt;upnp:album&gt;The Joshua Tree&lt;/upnp:album&gt;&lt;upnp:originalTrackNumber&gt;1&lt;/upnp:originalTrackNumber&gt;&lt;res duration=&quot;00:05:36.6661120&quot; size=&quot;10731992&quot; nrAudioChannels=&quot;2&quot; sampleFrequency=&quot;44100&quot; bitrate=&quot;254060&quot; protocolInfo=&quot;http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01D00000000000000000000000000000&quot;&gt;http://10.0.20.1:8096/audio/659c8429-b055-d5b0-3913-3a2694a76288/stream.mp3?DeviceId=uuid:9ab0c000-f668-11de-9976-ac44f268db96&amp;amp;MediaSourceId=659c8429b055d5b039133a2694a76288&amp;amp;Static=true&amp;amp;StartTimeTicks=360725539&amp;amp;Tag=4e1b061eb59b45005e35972bcdc20a19&amp;amp;dlnaheaders=true&lt;/res&gt;&lt;upnp:albumArtURI dlna:profileID=&quot;JPEG_SM&quot;&gt;http://10.0.20.1:8096/Items/659c8429b055d5b039133a2694a76288/Images/Primary/0/a7219cdca69d76ccce39f099374f5a55/jpg/480/480/0/0&lt;/upnp:albumArtURI&gt;&lt;upnp:icon&gt;http://10.0.20.1:8096/Items/659c8429b055d5b039133a2694a76288/Images/Primary/0/a7219cdca69d76ccce39f099374f5a55/jpg/48/48/0/0&lt;/upnp:icon&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</TrackMetaData>
      <TrackURI>http://10.0.20.1:8096/audio/659c8429-b055-d5b0-3913-3a2694a76288/stream.mp3?DeviceId=uuid:9ab0c000-f668-11de-9976-ac44f268db96&MediaSourceId=659c8429b055d5b039133a2694a76288&Static=true&StartTimeTicks=360725539&Tag=4e1b061eb59b45005e35972bcdc20a19&dlnaheaders=true</TrackURI>
      <RelTime>0:00:00</RelTime>
      <AbsTime>0:00:00</AbsTime>
      <RelCount>0</RelCount>
      <AbsCount>0</AbsCount>
    </u:GetPositionInfoResponse>
  </s:Body>
</s:Envelope>
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:PlayResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1"></u:PlayResponse>
  </s:Body>
</s:Envelope>
<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:GetPositionInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <Track>1</Track>
      <TrackDuration>0:05:36</TrackDuration>
      <TrackMetaData>&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=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item restricted=&quot;1&quot; id=&quot;659c8429b055d5b039133a2694a76288&quot; parentID=&quot;228a1cc7b3bc4a8c96e5ce7d2e95901b&quot;&gt;&lt;dc:title&gt;Where the Streets Have No Name&lt;/dc:title&gt;&lt;upnp:class&gt;object.item.audioItem.musicTrack&lt;/upnp:class&gt;&lt;upnp:genre&gt;Rock&lt;/upnp:genre&gt;&lt;upnp:publisher&gt;Island&lt;/upnp:publisher&gt;&lt;upnp:artist&gt;U2&lt;/upnp:artist&gt;&lt;dc:creator&gt;U2&lt;/dc:creator&gt;&lt;upnp:artist role=&quot;AlbumArtist&quot;&gt;U2&lt;/upnp:artist&gt;&lt;upnp:album&gt;The Joshua Tree&lt;/upnp:album&gt;&lt;upnp:originalTrackNumber&gt;1&lt;/upnp:originalTrackNumber&gt;&lt;res duration=&quot;00:05:36.6661120&quot; size=&quot;10731992&quot; nrAudioChannels=&quot;2&quot; sampleFrequency=&quot;44100&quot; bitrate=&quot;254060&quot; protocolInfo=&quot;http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01D00000000000000000000000000000&quot;&gt;http://10.0.20.1:8096/audio/659c8429-b055-d5b0-3913-3a2694a76288/stream.mp3?DeviceId=uuid:9ab0c000-f668-11de-9976-ac44f268db96&amp;amp;MediaSourceId=659c8429b055d5b039133a2694a76288&amp;amp;Static=true&amp;amp;Tag=4e1b061eb59b45005e35972bcdc20a19&amp;amp;dlnaheaders=true&lt;/res&gt;&lt;upnp:albumArtURI dlna:profileID=&quot;JPEG_SM&quot;&gt;http://10.0.20.1:8096/Items/659c8429b055d5b039133a2694a76288/Images/Primary/0/a7219cdca69d76ccce39f099374f5a55/jpg/480/480/0/0&lt;/upnp:albumArtURI&gt;&lt;upnp:icon&gt;http://10.0.20.1:8096/Items/659c8429b055d5b039133a2694a76288/Images/Primary/0/a7219cdca69d76ccce39f099374f5a55/jpg/48/48/0/0&lt;/upnp:icon&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;
      </TrackMetaData>
      <TrackURI>http://10.0.20.1:8096/audio/659c8429-b055-d5b0-3913-3a2694a76288/stream.mp3?DeviceId=uuid:9ab0c000-f668-11de-9976-ac44f268db96&MediaSourceId=659c8429b055d5b039133a2694a76288&Static=true&Tag=4e1b061eb59b45005e35972bcdc20a19&dlnaheaders=true</TrackURI>
      <RelTime>0:00:00</RelTime>
      <AbsTime>0:00:00</AbsTime>
      <RelCount>0</RelCount>
      <AbsCount>0</AbsCount>
    </u:GetPositionInfoResponse>
  </s:Body>
</s:Envelope>
PrplHaz4 commented 4 years ago

Can I turn on some kind of debug logging to see the returned XML?

@JustAMan @Bond-009

DLNA Debug Logging in settings should show these now as long as regular logging.json is in Debug mode too.

bcharlier commented 4 years ago

Hi,

I am experiencing the same problem as perfectly described by @zodi1337 . I guess this is also related to issue jellyfin/jellyfin#888. My Set up / Home Environment:

When using a DLNA device, there is no playing queue. Adding a track in the queue stops the current track and jump to the latest added track.

My logs do not contain [ERR] Failed to parse xml: . But here are the (I guess) relevant part:

Device found:

[2020-04-21 15:06:24.318 +01:00] [DBG] [28] Dlna: "CXNv2" - Received PlayRequest: PlayNow
[2020-04-21 15:06:24.326 +01:00] [INF] [28] Dlna: No matching device profile found. The default will need to be used.
DeviceDescription:
FriendlyName:CXNv2
Manufacturer:Cambridge Audio
ManufacturerUrl:http://www.cambridgeaudio.com/
ModelDescription:
ModelName:CXNv2
ModelNumber:3475
ModelUrl:
SerialNumber:00201647

A playlist is created but does not appear in Jellyfin nor on the DAC

[2020-04-21 15:06:24.374 +01:00] [DBG] [28] Dlna: "CXNv2" - Playlist created
[2020-04-21 15:06:24.377 +01:00] [DBG] [28] Dlna: "CXNv2" - Playing 4 items
[2020-04-21 15:06:24.380 +01:00] [DBG] [28] Dlna: "CXNv2" - SetAvTransport Uri: "http://192.168.1.51:8096/audio/de36362c-be51-3d34-1b84-a891ef33aea9/stream.flac?DeviceId=uuid:0266dc35-0242-4878-9602-881298aeeb53&amp;MediaSourceId=de36362cbe513d341b84a891ef33aea9&amp;Static=true&amp;Tag=54d29124c9db23d5c882977a758938b8&amp;dlnaheaders=true" DlnaHeaders: "DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01D00000000000000000000000000000"
[2020-04-21 15:06:24.449 +01:00] [ERR] [23] Emby.Server.Implementations.HttpServer.HttpListenerHost: Error processing request: "The operation was canceled". URL: "http://192.168.1.51:8096/audio/ffe7eb89-7622-41da-3985-4fcf8755ccbb/stream.mp3?DeviceId=uuid:0266dc35-0242-4878-9602-881298aeeb53&MediaSourceId=ffe7eb89762241da39854fcf8755ccbb&Static=true&Tag=5ba70ff31eeca3153aa194b7d3971c36&dlnaheaders=true"
[2020-04-21 15:06:24.449 +01:00] [WRN] [23] Emby.Server.Implementations.HttpServer.HttpListenerHost: HTTP Response 206 to "192.168.1.41". Time (slow): 0:05:45.1027512. "http://192.168.1.51:8096/audio/ffe7eb89-7622-41da-3985-4fcf8755ccbb/stream.mp3?DeviceId=uuid:0266dc35-0242-4878-9602-881298aeeb53&MediaSourceId=ffe7eb89762241da39854fcf8755ccbb&Static=true&Tag=5ba70ff31eeca3153aa194b7d3971c36&dlnaheaders=true"
[2020-04-21 15:06:24.484 +01:00] [ERR] [16] Emby.Server.Implementations.HttpClientManager.HttpClientManager: HTTP request failed with message: "<?xml version=\"1.0\" ?>
<s:Envelope xmlns:s=\"http://schemas.xmlsoap.org/soap/envelope/\" s:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\"><s:Body><s:Fault><faultcode>s:Client</faultcode>
<faultstring>UPnPError</faultstring>
<detail><UPnPError xmlns=\"urn:schemas-upnp-org:control-1-0\"><errorCode>701</errorCode>
<errorDescription>Transition not available</errorDescription>
</UPnPError>
</detail>
</s:Fault>
</s:Body>
</s:Envelope>
"

It starts to play the first track:

[2020-04-21 15:06:24.610 +01:00] [DBG] [16] HttpResultFactory: Transmit file "/Music/La Pompe Moderne/Plus dur, meilleur, plus rapide, plus fort/01 Le Mia.flac"
[2020-04-21 15:06:24.694 +01:00] [DBG] [28] HttpResultFactory: Transmit file "/cache/images/resized-images/a/a83a6d3f-f387-a92f-b65b-f4ec63e10fa1.jpg"
[2020-04-21 15:06:25.113 +01:00] [DBG] [55] HttpResultFactory: Transmit file "/cache/images/resized-images/7/79464811-bda6-cd03-1197-90ddff43d2ed.webp"

It detect the end of the first track

[2020-04-21 15:11:14.985 +01:00] [WRN] [22] Emby.Server.Implementations.HttpServer.HttpListenerHost: HTTP Response 200 to "192.168.1.41". Time (slow): 0:04:50.3768304. "http://192.168.1.51:8096/audio/de36362c-be51-3d34-1b84-a891ef33aea9/stream.flac?DeviceId=uuid:0266dc35-0242-4878-9602-881298aeeb53&MediaSourceId=de36362cbe513d341b84a891ef33aea9&Static=true&Tag=54d29124c9db23d5c882977a758938b8&dlnaheaders=true"
[2020-04-21 15:12:05.456 +01:00] [INF] [61] Emby.Server.Implementations.Session.SessionManager: Playback stopped reported by app "DLNA" "10.5.4" playing "Le Mia". Stopped at "330000" ms
[2020-04-21 15:12:05.765 +01:00] [DBG] [61] Dlna: "CXNv2" - SetAvTransport Uri: "http://192.168.1.51:8096/audio/cf859e8b-c01b-7e53-b373-b98a4343692b/stream.flac?DeviceId=uuid:0266dc35-0242-4878-9602-881298aeeb53&amp;MediaSourceId=cf859e8bc01b7e53b373b98a4343692b&amp;Static=true&amp;Tag=54d29124c9db23d5c882977a758938b8&amp;dlnaheaders=true" DlnaHeaders: "DLNA.ORG_PN=FLAC;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01D00000000000000000000000000000"

It starts to play the second track:

[2020-04-21 15:12:06.025 +01:00] [DBG] [61] HttpResultFactory: Transmit file "/Music/La Pompe Moderne/Plus dur, meilleur, plus rapide, plus fort/02 Le Bal.flac"
[2020-04-21 15:12:06.026 +01:00] [DBG] [23] HttpResultFactory: Transmit file "/cache/images/resized-images/8/8276c68d-5750-39f9-ad9d-ca2d9c76871b.jpg"
[2020-04-21 15:12:16.555 +01:00] [DBG] [61] HttpResultFactory: Transmit file "/cache/images/resized-images/d/d3c488c6-7e8f-1482-f339-516ba5687ce8.webp"

etc...

bcharlier commented 4 years ago

To keep the thread alive:

I checked Emby, and it suffer from the same bug (almost the same logs as in my previous post). This is a long last standing issue as this link shows. It is highly unclear to me when Emby team will really fix that and if a patch will be accessible to Jellyfin developers.

That being said, there exists upplay that is able to link upnp services (e.g. from a computer; playing on a DAC files hosted on a Jellyfin server). It works well in my use case even if the gui is not as nice as jellyfin.

hope this helps...

PhyberApex commented 3 years ago

I've been using BubbleUpnp for this. But that includes not being able to know which user actually is playing anything as there it will use the DLNA default user. I've been struggeling with this on emby for so long and really hope this will get some prio on jellyfin as the emby devs never addressed this.

Would be glad to even help out fixing this if pointed in the right direction!

~Cheers

stale[bot] commented 3 years ago

This issue has gone 120 days without comment. To avoid abandoned issues, it will be closed in 21 days if there are no new comments. If you're the original submitter of this issue, please comment confirming if this issue still affects you in the latest release or nightlies, or close the issue if it has been fixed. If you're another user also affected by this bug, please comment confirming so. Either action will remove the stale label. This bot exists to prevent issues from becoming stale and forgotten. Jellyfin is always moving forward, and bugs are often fixed as side effects of other changes. We therefore ask that bug report authors remain vigilant about their issues to ensure they are closed if fixed, or re-confirmed - perhaps with fresh logs or reproduction examples - regularly. If you have any questions you can reach us on Matrix or Social Media.

alexander-th commented 3 years ago

I am observing the same issue as decribed above using Version 10.6.4 when I try DLNA streaming to a Bose 500 soundbar. The issue occurs both using the Jellyfin Android app and using Jellyfin out of a Chrome Webbrowser: All controlls disappear when starting playback (no more pause, stop, next button).

stale[bot] commented 3 years ago

This issue has gone 120 days without comment. To avoid abandoned issues, it will be closed in 21 days if there are no new comments. If you're the original submitter of this issue, please comment confirming if this issue still affects you in the latest release or nightlies, or close the issue if it has been fixed. If you're another user also affected by this bug, please comment confirming so. Either action will remove the stale label. This bot exists to prevent issues from becoming stale and forgotten. Jellyfin is always moving forward, and bugs are often fixed as side effects of other changes. We therefore ask that bug report authors remain vigilant about their issues to ensure they are closed if fixed, or re-confirmed - perhaps with fresh logs or reproduction examples - regularly. If you have any questions you can reach us on Matrix or Social Media.

AndyAtKandeo commented 2 years ago

This issue remains using Jellyfin 10.7.7 on Windows X64. As described it is the same where only 1 track plays if you cast from Jellyfin UI to the device, and in reverse if you cast using Jellyfin as the source from Musiccast android app to the speaker it just plays something random and not what you queued. The error doesn't exist if you try to do the same from Windows DLNA through Windows Media Player (which sucks because it is so slow and can't handle a large number of files).

hervedevos commented 2 years ago

I had same weird issues that were listed before with a Yamaha Musiccast amplifier and Jellyfin.

I troubleshooted upnp responses coming from the amplifier and here is the issue:

This ends up in jellyfin not being able to track your DLNA device and breaks everything.

My solution :

If someone is interested i can provide this piece of script (not quite a big deal, 5lines of python as mitmproxy addon).

I don't know if other amps/devices may have these issues with handling query params (but i wouldnt be surprised), but if it's possible to handle the playing session in a different manner in Jellyfin and avoid sending query params to the upnp devices, it would probably avoid some of the issues DLNA users are encountering.

hatl commented 1 year ago

Playlists not working on web interface when choosing Kodi (DLNA) for playback. Jellyfin 10.8.1 Kodi 19.4

The playlist is even not working when choosing another Jellyfin web interface as target.

I would be willing to pay some money if someone fixes this :smile:

phildespres commented 1 year ago

If someone is interested i can provide this piece of script (not quite a big deal, 5lines of python as mitmproxy addon).

Nice catch. I would be interested in your solution. Thanks!

D43m0n commented 1 year ago

I had same weird issues that were listed before with a Yamaha Musiccast amplifier and Jellyfin.

I'm trying to ditch Plex and Emby in favor of Jellyfin but experience similar issues with Jellyfin compared to Emby with Yamaha MusicCast renderers.

I troubleshooted upnp responses coming from the amplifier and here is the issue:

...

  • The issue is that Yamaha upnp does respond with a wrongly formatted response, in particular the field "TrackURI" : '&' are not escaped as they should be (whereas jellyfin is escaping them rightly in the request) : it should be &amp; , as '&' has a particular meaning in Soap format

This ends up in jellyfin not being able to track your DLNA device and breaks everything.

Nice catch! šŸ‘

My solution :

  • I ended up putting a Mitmproxy and rewriting Yamaha amp responses (escaping & character in TrackURI field of the GetPositionInfo request) (hopefully temp solution, I tried to reach them out by mail to explain their techies the issue but no news at the moment)

If someone is interested i can provide this piece of script (not quite a big deal, 5lines of python as mitmproxy addon).

I'm interested!

hervedevos commented 1 year ago

Hello @D43m0n and @phildespres, sorry for late answer @phildespres I missed your message.

You will find following mitmproxy script, probably not that optimized cause i'm quite noob in python, but it does the job.

rewrite_trackuri.py script:

import re
from mitmproxy import http
from mitmproxy import ctx

class RewriteTrackURI:
    def response(self, flow: http.HTTPFlow) -> None:
        result = re.search(r"<TrackURI>(.+)</TrackURI>", flow.response.content.decode())
        if (result):
            flow.response.text = re.sub(r'<TrackURI>(.+)</TrackURI>', "<TrackURI>" +result.group(1).replace('&', '&amp;') + "</TrackURI>", flow.response.content.decode())

addons = [RewriteTrackURI()]

You may want to add additionals filters on request (example on jellyfin IP) if you use mitmproxy for other purposes than only upnp yamaha fix, as provided it will scan all requests and that may be performance costly. For my own purpose this mitmproxy is dedicated to jellyfin so I dit not need to go this way

Hope it serves you well and allows you to enjoy Jellyfin with your loved yamaha amp ;)

D43m0n commented 1 year ago

Thank you!

  • Run mitmproxy with following arguments (only provided as sample, you may need to customize it, --web-host argument is mandatory to expose your mitmproxy outside localhost and -s also mandatory to provide rewrite script) : mitmproxy -p <port you want to expose to proxy clients> --web-port <port to expose UI if u need to check/debug trafic> --web-host 0.0.0.0 -s /scripts/rewrite_trackuri.py
  • You need to configure Jellyfin to use your mitmproxy by setting http_proxy environment variable

Iā€™m looking into this, do you happen to run Jellyfin and mitmproxy in Docker by any chance? I currently run Jellyfin as a container and use macvlan to assign a LAN ip address to the Jellyfin container so my Yamaha devices can see the DLNA service from Jellyfin. I not only use Jellyfin for my music to the Yamaha devices, but also for my movies, so some kind of filtering would indeed be a good idea. Iā€™m not able to find examples I understand to translate them to my use case šŸ˜‡ . Do you have some additional tips please? šŸ™Œ

Well, managed to get it working after all! I learn by example and then make mistakes. I found a mitmproxy-tutorial that explained some steps that allowed me to understand what I needed to do. So for prosperity to others I'll add my working set-up with Docker-compose. I run a number of containers, all by using docker-compose. My Jellyfin container runs with a macvlan so it has it's own ip-address on the local network, solely for DLNA purposes. But it's true that discovery of a Jellyfin server by clients is also beneficial for that.

I use docker-compose with a macvlan so all containers can find each other on that docker network by their container_name or if you've defined an alias because ip-addresses can change. So I added an mitmproxy container in my docker-compose.yml:

  mitmproxy:                                                                                                                                                                               
    image: mitmproxy/mitmproxy                                                                                                                                                             
    container_name: mitmproxy                                                                                                                                                              
    mem_swappiness: 0                                                                                                                                                                      
    command: "mitmweb --web-host 0.0.0.0 --listen-port 8765 -s /mnt/rewrite_trackuri.py"                                                                                                   
    volumes:                                                                                                                                                                               
      - "${CONFIG_DIRECTORY}/mitmproxy:/mnt"                                                                                                                                               
    ports:                                                                                                                                                                                 
      - 8081:8081                                                                                                                                                                          
      - 8765:8765                                                                                                                                                                          
    restart: unless-stopped

I use a different --listen-port since I have another container running on the default port 8080. I therefore also mapped that port 8765 but I think I don't really need it. I mapped port 8081 so I could easily see in a browser what passed through mitmproxy and what not. I mapped a volume to the container to expose the rewrite_trackuri.py script from @hervedevos inside the container.

Then on the Jellyfin container, I needed to add two things; first the following two environment variables:

      - http_proxy=http://mitmproxy:8765/                                                                                                                                                  
      - HTTP_PROXY=http://mitmproxy:8765/ 

And secondly I needed to add the default docker-compose network to the Jellyfin container so it could connect to the mitmproxy container. So my complete Jellyfin container configuration in docker-compose is now:

  jellyfin:                                                                                                                                                                                
    image: lscr.io/linuxserver/jellyfin:latest                                                                                                                                             
    container_name: jellyfin                                                                                                                                                               
    mem_swappiness: 0                                                                                                                                                                      
    environment:                                                                                                                                                                           
      - PUID=${PUID}                                                                                                                                                                       
      - PGID=${PGID}                                                                                                                                                                       
      - TZ=${TZ}                                                                                                                                                                           
      - http_proxy=http://mitmproxy:8765/                                                                                                                                                  
      - HTTP_PROXY=http://mitmproxy:8765/                                                                                                                                                  
    volumes:                                                                                                                                                                               
      - "${DATA_DIRECTORY}/jellyfin:/config"                                                                                                                                               
      - "${DATA_DIRECTORY}/movies:/data/movies"                                                                                                                                                                                                                                                                                       
      - "${DATA_DIRECTORY}/homevideo:/data/homevideos"                                                                                                                                     
      - "${DATA_DIRECTORY}/music:/data/music"                                                                                                                                                                                                                                                                     
    networks:                                                                                                                                                                              
      macvlan-for-containers:                                                                                                                                                              
        ipv4_address: 192.168.1.220                                                                                                                                                        
      default:                                                                                                                                                                             
    group_add:                                                                                                                                                                             
      - 125                                                                  # for hardware transcoding                                                                                                              
    devices:                                                                                                                                                                               
      - /dev/dri/renderD128:/dev/dri/renderD128    # for hardware transcoding                                                                                                                                        
      - /dev/dri/card0:/dev/dri/card0                        # for hardware transcoding                                                                                                                              
    labels:                                                                                                                                                                                
      - "traefik.enable=true"                                                                                                                                                              
      - "traefik.http.routers.jellyfin.rule=Host(`jellyfin.${DOMAIN}`)"                                                                                                                    
      - "traefik.http.routers.jellyfin.entrypoints=https"                                                                                                                                  
      - "traefik.http.routers.jellyfin.tls.certresolver=myresolver"                                                                                                                        
      - "traefik.http.routers.jellyfin.middlewares=secure-headers@file, compress-content@file"                                                                                             
      - "traefik.docker.network=macvlan-for-containers"                                                                                                                                    
      - "traefik.http.services.jellyfin.loadbalancer.server.port=8096"                                                                                                                     
    restart: unless-stopped

And this works with mitmproxy and the rewrite_trackuri script. I can now open a Jellyfin app/browser, connect to my Yamaha DLNA device via the Cast icon and then start playing an album or a playlist. Very happy with that!

Now this set-up makes it possible to use the "Play To" functionality from Jellyfin to a DLNA device. In the past I was used to open the Yamaha MusicCast app, select a DLNA device and then via the "Server" option select a DLNA source and browse the music library on the DLNA source (Plex, minidlna). With Jellyfin I can do all that, but no matter which album or playlist I choose to play from the MusicCast app, it's always the same album that get's played. Weird. I guess that's another issue not related to this issue. But this workaround with mitmproxy does work great with "Play To" and helps very much in ditching Plex/Emby for Jellyfin!

basos9 commented 1 year ago

Hello, I experience this issue with Jellyfin version: 10.8.7 and the upmpdcli media render that exposes mpd player daemon as a DLNA renderer. version is upmpdcli 1.5.19-1~ppa1~bullseye.

patrislav1 commented 1 year ago

I have this issue with my Yamaha MusicCast receiver and @hervedevos' script fixes it.

I modified the script a bit to only modify responses from a explicit list of DLNA servers, and to only replace the ampersand if it's not already escaped (to avoid messing up non-buggy responses).

#!/usr/bin/python3

import re
from mitmproxy import http

# Workaround for corrupt (unescaped) TrackURI response in DLNA players such as Yamaha receivers
# See also https://github.com/jellyfin/jellyfin-plugin-dlna/issues/7

# List of IP addresses of the affected DLNA player
DLNA_PLAYERS = ['192.168.111.20']

class RewriteTrackURI:
    # Match TrackURIs in the response XML
    RE_TRACKURI = re.compile(r'(?<=<TrackURI>)([\s\S]+?)(?=</TrackURI>)')

    # Match '&' only if not followed by amp;
    RE_AMPERSAND = re.compile(r'(&(?!amp;))')

    def response(self, flow: http.HTTPFlow) -> None:

        def handle_trackuri(trackuri_match: re.match) -> str:
            return re.sub(
                RewriteTrackURI.RE_AMPERSAND,
                '&amp;',
                trackuri_match.group(1)
            )

        if flow.server_conn.ip_address[0] not in DLNA_PLAYERS:
            return

        flow.response.text = re.sub(
            RewriteTrackURI.RE_TRACKURI,
            handle_trackuri,
            flow.response.text
        )

addons = [RewriteTrackURI()]
cvium commented 1 year ago

I'm surprised this is the issue. It should've been fixed in 10.8

patrislav1 commented 1 year ago

I'm surprised this is the issue. It should've been fixed in 10.8

Iā€˜m observing this issue in 10.8.8

cvium commented 1 year ago

What is the full URL that it chokes on?

patrislav1 commented 1 year ago

What is the full URL that it chokes on?

Here's the offending AVTransport/ctrl response from the Yamaha receiver and the jellyfin log message

<?xml version="1.0" encoding="utf-8"?>
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/" s:encodingStyle="http://schemas.xmlsoap.org/soap/encoding/">
  <s:Body>
    <u:GetPositionInfoResponse xmlns:u="urn:schemas-upnp-org:service:AVTransport:1">
      <Track>
      1
      </Track>
      <TrackDuration>0:08:18</TrackDuration>
      <TrackMetaData>&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=&quot;urn:schemas-upnp-org:metadata-1-0/DIDL-Lite/&quot;&gt;&lt;item restricted=&quot;1&quot; id=&quot;de5d14c158812976a0805f35240a3114&quot; parentID=&quot;01fb242f4743d32f46c92643a679dfe1&quot;&gt;&lt;dc:title&gt;Side A - Panaceum&lt;/dc:title&gt;&lt;upnp:class&gt;object.item.audioItem.musicTrack&lt;/upnp:class&gt;&lt;dc:date&gt;2019-01-01&lt;/dc:date&gt;&lt;upnp:artist&gt;2MORPH&lt;/upnp:artist&gt;&lt;dc:creator&gt;2MORPH&lt;/dc:creator&gt;&lt;upnp:artist role=&quot;AlbumArtist&quot;&gt;2MORPH&lt;/upnp:artist&gt;&lt;upnp:album&gt;GMT25 2Morph - Panaceum&lt;/upnp:album&gt;&lt;upnp:originalTrackNumber&gt;1&lt;/upnp:originalTrackNumber&gt;&lt;res duration=&quot;00:23:28.7836672&quot; size=&quot;43023112&quot; nrAudioChannels=&quot;2&quot; sampleFrequency=&quot;44100&quot; bitrate=&quot;243703&quot; protocolInfo=&quot;http-get:*:audio/mpeg:DLNA.ORG_PN=MP3;DLNA.ORG_OP=01;DLNA.ORG_CI=0;DLNA.ORG_FLAGS=01D00000000000000000000000000000&quot;&gt;http://192.168.111.10:8096/audio/de5d14c1-5881-2976-a080-5f35240a3114/stream.mp3?DeviceProfileId=548fdafc56b04001b61563da3b6f2b45&amp;amp;DeviceId=9ab0c000-f668-11de-9976-00a0ded5b552&amp;amp;MediaSourceId=de5d14c158812976a0805f35240a3114&amp;amp;Static=true&amp;amp;Tag=b9bc89d0bc5db4953c2d097055d41a91&amp;amp;dlnaheaders=true&lt;/res&gt;&lt;upnp:albumArtURI dlna:profileID=&quot;JPEG_SM&quot;&gt;http://192.168.111.10:8096/Items/de5d14c158812976a0805f35240a3114/Images/Primary/0/69cdfdfe29b415076f2cd42f176f2163/jpg/480/480/0/0&lt;/upnp:albumArtURI&gt;&lt;upnp:icon&gt;http://192.168.111.10:8096/Items/de5d14c158812976a0805f35240a3114/Images/Primary/0/69cdfdfe29b415076f2cd42f176f2163/jpg/48/48/0/0&lt;/upnp:icon&gt;&lt;/item&gt;&lt;/DIDL-Lite&gt;</TrackMetaData>
      <TrackURI>http://192.168.111.10:8096/audio/de5d14c1-5881-2976-a080-5f35240a3114/stream.mp3?DeviceProfileId=548fdafc56b04001b61563da3b6f2b45&DeviceId=9ab0c000-f668-11de-9976-00a0ded5b552&MediaSourceId=de5d14c158812976a0805f35240a3114&Static=true&Tag=b9bc89d0bc5db4953c2d097055d41a91&dlnaheaders=true</TrackURI>
      <RelTime>0:00:00</RelTime>
      <AbsTime>0:00:00</AbsTime>
      <RelCount>0</RelCount>
      <AbsCount>0</AbsCount>
    </u:GetPositionInfoResponse>
  </s:Body>
</s:Envelope>
root@jellyfin:~# journalctl -u jellyfin -f
Jan 08 18:08:22 jellyfin jellyfin[182]: [18:08:22] [INF] IntervalTrigger fired for task: Clean Transcode Directory
Jan 08 18:08:22 jellyfin jellyfin[182]: [18:08:22] [INF] Queuing task DeleteTranscodeFileTask
Jan 08 18:08:22 jellyfin jellyfin[182]: [18:08:22] [INF] Executing Clean Transcode Directory
Jan 08 18:08:22 jellyfin jellyfin[182]: [18:08:22] [INF] Clean Transcode Directory Completed after 0 minute(s) and 0 seconds
Jan 08 18:08:22 jellyfin jellyfin[182]: [18:08:22] [INF] ExecuteQueuedTasks
Jan 08 18:12:17 jellyfin jellyfin[182]: [18:12:17] [INF] Sending ForceKeepAlive message to 1 inactive WebSockets.
Jan 08 18:12:29 jellyfin jellyfin[182]: [18:12:29] [INF] Lost 1 WebSockets.
Jan 08 18:13:51 jellyfin jellyfin[182]: [18:13:51] [INF] WS 192.168.111.63 request
Jan 08 18:14:23 jellyfin jellyfin[182]: [18:14:23] [INF] No matching device profile found. The default will need to be used.
Jan 08 18:14:23 jellyfin jellyfin[182]: {"FriendlyName": "Wohnzimmer", "ModelNumber": "N602", "SerialNumber": "00877983", "ModelName": "R-N602", "ModelDescription": "MusicCast", "ModelUrl": "http://www.yamaha.com/", "Manufacturer": "Yamaha Corporation", "ManufacturerUrl": "http://www.yamaha.com/", "Headers": [], "$type": "DeviceIdentification"}
Jan 08 18:14:23 jellyfin jellyfin[182]: [18:14:23] [INF] No matching device profile found. The default will need to be used.
Jan 08 18:14:23 jellyfin jellyfin[182]: {"FriendlyName": "Wohnzimmer", "ModelNumber": "N602", "SerialNumber": "00877983", "ModelName": "R-N602", "ModelDescription": "MusicCast", "ModelUrl": "http://www.yamaha.com/", "Manufacturer": "Yamaha Corporation", "ManufacturerUrl": "http://www.yamaha.com/", "Headers": [], "$type": "DeviceIdentification"}
Jan 08 18:14:23 jellyfin jellyfin[182]: [18:14:23] [ERR] Error updating device info for Wohnzimmer
Jan 08 18:14:23 jellyfin jellyfin[182]: System.Xml.XmlException: '=' is an unexpected token. The expected token is ';'. Line 1, position 2382.
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.Throw(Exception e)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.Throw(String res, String[] args)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.ThrowUnexpectedToken(String expectedToken1, String expectedToken2)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.HandleEntityReferenceAsync(Boolean isInAttributeValue, EntityExpandType expandType)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.ParseTextAsync_ParseEntity(Int32 outOrChars, Char[] chars, Int32 pos, Int32 rcount, Int32 rpos, Int32 orChars, Char c)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.ParseTextAsync_AsyncFunc(Task`1 task)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl.FinishPartialValueAsync()
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.XmlTextReaderImpl._GetValueAsync()
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.Linq.XContainer.ContentReader.ReadContentFromAsync(XContainer rootContainer, XmlReader r)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.Linq.XContainer.ReadContentFromAsync(XmlReader r, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.Linq.XContainer.ReadContentFromAsync(XmlReader r, LoadOptions o, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.Linq.XDocument.LoadAsyncInternal(XmlReader reader, LoadOptions options, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at System.Xml.Linq.XDocument.LoadAsync(Stream stream, LoadOptions options, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at Emby.Dlna.PlayTo.SsdpHttpClient.SendCommandAsync(String baseUrl, DeviceService service, String command, String postData, String header, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at Emby.Dlna.PlayTo.SsdpHttpClient.SendCommandAsync(String baseUrl, DeviceService service, String command, String postData, String header, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at Emby.Dlna.PlayTo.Device.GetPositionInfo(TransportCommands avCommands, CancellationToken cancellationToken)
Jan 08 18:14:23 jellyfin jellyfin[182]:    at Emby.Dlna.PlayTo.Device.TimerCallback(Object sender)
patrislav1 commented 1 year ago

BTW, I observe the same issue when using https://github.com/jellyfin/jellyfin-expo on my iPad. It can be mitigated by pointing the iPad to the mitmproxy.

espector commented 1 year ago

Did you ever get this working on Bose? I think I'm having a similar issue here - https://github.com/jellyfin/jellyfin-plugin-dlna/issues/26

I installed mitmproxy and script, but it didn't work for me.