danielvijge / lms_mixcloud

Mixcloud plugin for Squeezebox
GNU General Public License v2.0
8 stars 10 forks source link

Slim::Player::Song::open (424) Error: Couldn't create command line for unk playback #35

Closed microrache closed 6 months ago

microrache commented 6 months ago

Thank you for developing this plugin. Unfortunately, it seems that it is currently broken - I cannot play any mixes anymore. This is what is shown in the Server-logs:

[24-03-29 10:29:58.8733] Plugins::MixCloud::ProtocolHandler::__ANON__ (214) Empty response for play URL for mixcloud://angstpop/ebm-classxmix/{ error => "ERROR: URL not supported. We will investigate.", url => "https://www.mixcloud.com/angstpop/ebm-classxmix/", } [24-03-29 10:29:58.8750] Slim::Player::Song::open (424) Error: Couldn't create command line for unk playback for [mixcloud://angstpop/ebm-classxmix/]

Tried with Logitech Media Server 8.4.0 and Mixcloud v0.10

Could you confirm the issue and hopefully fix it with a new release?

danielvijge commented 6 months ago

Mixcloud doesn't have an official way to stream music via other devices. The plugin uses an external "downloader" site to get a streamable URL. Currently this is https://www.savelink.info/ That site doesn't seem to be working for Mixcloud at the moment. It might be that functionality is restored at some point by that site, and then this plugin will also work again. If not, and it takes a long time, I might have to look for another service (again). If you know of a Mixcloud download website that is working, I can see if it can be used by this plugin.

richardhenwood commented 6 months ago

I'm a huge fan of mixcloud and very grateful for your work on this @danielvijge .

I am curious why the third party site is needed. Can you outline the technical (or other?) challenges identifying the streaming endpoint from mixcloud.com directly?

danielvijge commented 6 months ago

To interact with a service, such as Mixcloud, often an API (application programming interface) is used. This is a way for applications (whether a mobile app, website, TV, or a Squeezebox plugin) to interact with a service and request (get) information, or send information (post). Mixcloud has such an API, and all the details are published at https://www.mixcloud.com/developers/ There are API methods to search, follow, upload, etc. However, under streaming Mixcloud states:

The audio streams are not available through the Mixcloud API. There are two reasons for this.

Firstly, we need to know what has been listened to so that we can report usage, pay royalties and provide features such as 'Suggested Shows'.Secondly, Mixcloud needs to pay the bills! We can't give away the audio for free outside of mixcloud.com simply because it costs us to host and stream the files and pay royalties.

Of course there is the official app and website, which do stream audio. People have reverse engineered how this works. This is exactly what websites like savelink do. There are more similar websites, and applications like youtube-dl. Relying on a third-party service for this allow this plugin to be a lot simpler, as it doesn't need all that reverse engineering code.

But sometimes the third-partry service breaks, or Mixcloud changes something that breaks things. In such cases this plugin is also broken until the method to play Mixcloud tracks externally is reverse engineered again.

I guess it's up to everyone to decide if you think it's justified to play Mixcloud tracks in this way if Mixcloud doesn't want to offer it like this.

internoot commented 6 months ago

I ran into this a few days ago and made a quick patch to the Mixcloud plugin to obtain the stream url by invoking yt-dlp (a youtube-dl fork).

yt-dlp produces a json of several stream options - one conventional http mp3/m4a encoded audio and several HLS and DASH options. LMS is able to play the http stream natively, unfortunately the bitrate is quite low compared to the other options.

I'm planning on expanding on this and having LMS play the highest bitrate HLS stream using the PlayHLS plugin. I'm happy to send a PR for that once I have something worthwhile, thanks for your work maintaining this project @danielvijge

danielvijge commented 6 months ago

(crossposted from the forum)

Indeed things like yt-dl (or a fork) would work, and make the plugin less dependent on am external service. Bit it would also complicate the installation a bit. Either users would have to manually install yt-dl, or the plugin would need to distribute a copy. But that would then require different versions for Windows/MacOS/Linux i384/arm/etc.

There are two github repos i experimented with. The first is a very alpha thing that I didn't continue with further: https://github.com/danielvijge/squeezebox-cloudplay It would potentially allow to play any stream supported by yt-dl, and I had the thought of using yt-dl's update command to update binary independent of the plugin.

The other option is to host a cloud service of yt-dl just for this plugin. An AWS lambda is available in https://github.com/danielvijge/youtu...ct-info-lambda But hosting that, and having the plugin use it, might be a bit of a risk for me. I have no idea how many people use the Mixcloud plugin, so what the costs might be of hosting it. And I cannot limit it to just this plugin; it would be publicly accessible for everyone. And on top of the costs there might be the legal risk of hosting this is a public service.

austin99 commented 6 months ago

If you know of a Mixcloud download website that is working, I can see if it can be used by this plugin.

I came across https://mixclouddownloader.net/download-track which might slot in better than yt-dl ?

danielvijge commented 6 months ago

@internoot I'm indeed trying to incorporate your patch into a new release, bundling the yt-dlp binary for each platform. Maybe I don't fully understand the plugin I maintain, but with yt-dlp I indeed get an m4a steam URL, but then an error message Slim::Player::Squeezebox2::statHandler (156) Error: Decoder does not support file format, code 0 Did you install/configure anything else to decode the file format?

danielvijge commented 6 months ago

A possible fix uses yt-dlp has been added in a16c752046243a247d1ad6de95473b6f1b3700d0 The first development version that uses this is version 0.10.1. If the dev repo is added to LMS, this version can be installed.

danielvijge commented 6 months ago

Being able to play all files also requires https://github.com/LMS-Community/slimserver/pull/1056 to be merged. Some newer files on Mixcloud use an mp4 format that could not be streamed directly by LMS.

danielvijge commented 6 months ago

Released https://github.com/danielvijge/lms_mixcloud/releases/tag/0.11 to resolve the issue

richardhenwood commented 6 months ago

Tested 0.11 this morning. It works great! Your contribution to the quality of my life is significant and I really appreciate it!

One minor issue for me: I use the official LMS container from here: https://hub.docker.com/r/lmscommunity/logitechmediaserver . The issue appeared in my log file as:

[24-04-19 07:26:51.1964] Slim::Player::Song::open (424) Error: Couldn't create command line for unk playback for [mixcloud://alucidnation/eclectronica-show-82/]
[24-04-19 07:27:06.1909] Plugins::MixCloud::ProtocolHandler::_fetchTrackExtra (250) Failed to determine stream URL for mixcloud://alucidnation/eclectronica-show-82/
[24-04-19 07:27:06.1920] Plugins::MixCloud::ProtocolHandler::_fetchTrackExtra (251) Tried to execure command: /config/cache/InstalledPlugins/Plugins/MixCloud/Bin/yt-dlp --skip-download --dump-json https://www.mixcloud.com/alucidnation/eclectronica-show-82/ 2>&1
[24-04-19 07:27:06.1985] Plugins::MixCloud::ProtocolHandler::_fetchTrackExtra (252) /usr/bin/env: ‘python3’: No such file or directory

The problem was that the container does not include python3... so the solution was to install python3 in the container, something like this:

podman exec -it logitechmediaserver /bin/bash
# apt install python3
danielvijge commented 6 months ago

@richardhenwood One the forum the same problem was mentioned as well. If you dont' want to go installing python everytime you pull a new version of the container, you can use a version of yt-dlp with bundled python3:

  1. Download the Linux standalone x64 binary
  2. Save/copy it to a folder on the server that is mounted inside the docker image, let's say your music folder at /music, to the binary path becomes /music/yt-dlp_linux
  3. Make it executable by running from a terminal "chmod +x /music/yt-dlp_linux"
  4. In the Mixcloud settings, change the helper application from bundled to system, and in the path text box set "/music/yt-dlp_linux"
  5. Try to play a Mixcloud track. In the logging instead of "Tried to execure command: /config/cache/InstalledPlugins/Plugins/MixCloud/Bin/yt-dlp --skip-download --dump-json ..." you should now see "Tried to execure command: /music/yt-dlp_linux --skip-download --dump-json ..."
mousemat86 commented 5 months ago

just dropping by to say thanks for this fix, much appreciated

austin99 commented 4 months ago

Many thanks for getting this back working!

I was wondering if there was a way to play the HQ feed if it is available? e.g. this link was uploaded in HQ (192kb) https://www.mixcloud.com/NTSRadio/150-session-cycladic-figurines-11th-may-2024/

but it plays at 64kb;

File Format: MPEG-4
Duration: 59:52
Bitrate: 64kbps CBR
Sample Rate: 44.1 kHz
Sample Size: 16Bits
URL: mixcloud://NTSRadio/150-session-cycladic-figurines-11th-may-2024/

Examining the output from yt-dlp --skip-download --dump-json https://www.mixcloud.com/NTSRadio/150-session-cycladic-figurines-11th-may-2024/ shows streams which are suffixed with "-192K". I've tried modifying the plugin to get it to play these but I don't really know much about Perl :(

danielvijge commented 4 months ago

@austin99 First thing you could try is to copy url from that stream into "Radio > Tune In URL" and see if it works.

If I don't mix two things up now... I think it didn't work work. It's a m8u file, so technically a playlist of multiple files and not a single file. And when LMS tries to retrieve a single entry for the playlist, Mixcloud blocks the request because "iTunes" appears in the User-Agent string of the request.

I'm sure both can be addressed, but I haven't looked into it at all.

austin99 commented 4 months ago

Mixcloud is rejecting the request with a 403 forbidden, so it sounds like it could be like User-Agent parameter that is causing the rejection Error: Can't connect to remote server to retrieve playlist for, https://audio13.mixcloud.com/secure/hls/a/2/3/7/9fd7-e5d9-486f-82c3-051368bd55be-192K.m4a/streamindex-a1.m3u8: 403 Forbidden. That url plays ok using VLC Media Player. Also I'm using LMS 8.5.2 btw. I also have the PlayHLS v2.12 plugin installed

-- Update: It's definitely the User-Agent string; curl -H "User-Agent: iTunes/4.7.1 (Linux; N; piCore; aarch64-linux; EN_GB; utf8) SqueezeCenter, Squeezebox Server, Logitech Media Server/8.5.2/1716215514" https://audio13.mixcloud.com/secure/hls/a/2/3/7/9fd7-e5d9-486f-82c3-051368bd55be-192K.m4a/streamindex-a1.m3u8 returns a 403 Forbidden. Changing the User-Agent to anything else and it works.
I can see that string is built in Slim::Utils::Misc::userAgentString() but I don't think there's a hook available to alter it :(