tamland/python-tidal

Support for 24bit 192kHz

Closed this issue · 27 comments

At the moment the files are only streaming at 24bit 48kHz instead of the 192kHz expected

At the moment, Tidal only allows it's own apps to use the HiRes Flac files higher than 24bit 48kHz

@jozefKruszynski with tidal-dl i could get 192hz flac files with my personal jwt token that i got from the desktop app on windows

I can confirm that using the token provided by a native app (MacOS in my case) downloads a much bigger file (tested on https://tidal.com/browse/track/542179)

With a normal token, I get a 48Khz 24 bits file, around 75Mb.
With a native token, the file is uncrypted but weights 217Mb.

Once decrypted:

ffprobe -hide_banner Rosanna.flac 
Input #0, flac, from 'Rosanna.flac':
  Duration: 00:05:30.94, start: 0.000000, bitrate: 5256 kb/s
  Stream #0:0: Audio: flac, 192000 Hz, stereo, s32 (24 bit)

Don't know if this helps, but always good to know.

Where can you find your personal TIDAL JWT on a Mac?

Closing this issue, as tidal only allows official apps to use high res / 24bit 192kHz bitrates.

You are closing this without even trying to properly reverse engineering this? I would like to help here.

@exislow Playback should be possible as long as you use the correct token, as stated in the previous comments. I have not tested this myself as I do not currently have a subscription with high res.

Sorry, we cannot assist you with how to get hold of these tokens for obvious reasons.

I am currently looking into using pkce authentication, as used by the android app. This should allow us to use high res playback in the future, since using the device code link login method will not work.

I'm using a network tool to check the API calls from the native app, and getting my token and refreshToken from there.

With the correct deviceId and refreshToken, you should be able to refresh the token correctly, allowing for hi-res download (I tested this a little tool, it does work).

@exislow Playback should be possible as long as you use the correct token, as stated in the previous comments. I have not tested this myself as I do not currently have a subscription with high res.

Sorry, we cannot assist you with how to get hold of these tokens for obvious reasons.

I am currently looking into using pkce authentication, as used by the android app. This should allow us to use high res playback in the future, since using the device code link login method will not work.

That's a bummer but thank you for sharing your knowledge. I will do some analysis there as well.

I'm using a network tool to check the API calls from the native app, and getting my token and refreshToken from there.

With the correct deviceId and refreshToken, you should be able to refresh the token correctly, allowing for hi-res download (I tested this a little tool, it does work).

So, you are basically using Wireshark / Burp for traffic analysis / interception. I thought somebody figured out where the electron app saves the token.

Btw... After decompilation of the desktop electron app (asar package) I miss the electron backend code files. Only the frontend files are available. But I cannot figure out where the code file are who are handling the IPC calls from the frontend. Does anybody has hint on that?

Reopening.

FYI, the Kodi Tidal plugin (containing an old fork of tidalapi) already has support for this, including obtaining tokens from the android apps and using PKCE login: https://github.com/arnesongit/plugin.audio.tidal2

My plan is to port these features to tidalapi

This sounds great. Amazing, that the already implemented this (https://github.com/arnesongit/plugin.audio.tidal2/blob/e9429d601d0c303d775d05a19a66415b57479d87/resources/lib/tidal2/tidalapi/__init__.py#L86).

Do you need help with porting their code? What is your timeline for that?

@exislow Exactly. There are many very nice advanced features in this plugin that are yet to be ported to tidalapi, including all the PKCE login and high res playback that was added a couple of months ago. I think most of the legwork has already been done by arnesongit.

I was hoping to port it one of the next couple of months before the next tidalapi release, if I have time aside from work. But you are very welcome to help, PRs are always welcome. Just give me a heads-up if you start working on it 👍

@tehkillerbee: I have started working on the PKCE port. First PoC seems to work. As soon as I have something really suitable for testing I will inform you. Would be great, if we could align on code style and tests later.

Hell yeah, it works! I can login using PKCE and download Hi Res FLAC files: exislow@6f031a0

$ afinfo The\ Doobie\ Brothers\ -\ Listen\ to\ the\ Music\ \(2016\ Remaster\).mp4 
File:          The Doobie Brothers - Listen to the Music (2016 Remaster).mp4
File type ID:   mp4fLine.flac                                                                                                                     
Num Tracks:     1
----
Data format:     2 ch, 192000 Hz, flac (0x00000003) from 24-bit source, 4096 frames/packet
                no channel layout.
estimated duration: 288.021333 sec
audio bytes: 195354502
audio packets: 13501
bit rate: 5426112 bits per second
packet size upper bound: 16164
maximum packet size: 16164
audio data file offset: 219697
not optimized
----

That is amazing news :-)

A question here would be how to handle the client_id.
I believe that the Kodi plugin extracts it from a given APK as part of the setup process and I would urge against storing it in the repo. I would also urge against adding the same extraction process to the repo here.
However this then assumes a level of knowledge and technical competency in order for a user to extract the required value.

@exislow @jozefKruszynski Great to hear you have already had progress. However, as Jozef mentioned, storing the client_id in the repo is a no-go.

Including the utilities to extract it from the APK and/or including the instructions to obtain it will also be a bad idea IMO.

Edit: Another issue is the PKCE login code as this is code by arnesongit so we would need his permission to use it.

Can you tell me, why this is a no go? It is already done the same way right now.
If you like, we can obfuscate this using base64 encoding or what so ever.

Getting the permission is great but we do not need it, since a) their code is under GPL (https://github.com/arnesongit/plugin.audio.tidal2/blob/master/LICENSE.txt) and b) anyway I would fully re-write the code to properply integrate it into this library.

I kinda do not really get the trouble here. Maybe somebody explain to me what actual issues we are facing / what is right now knew compared to the already existing ways this API is accessing TIDAL.

@exislow

Including a non-obfuscated id will quickly get noticed and it will stop working. Hence the reason we do not do it like that right now. Otherwise, we have to keep updating the ids, each time they get taken down.

Including an id with highres support will most likely cause this project to get taken down by Tidal, once and for all, as it will make it too easy to download HiRes music directly from tidal. So I still think the only way forward is to allow the user to input the id that he/she has obtained manually somehow.

Regarding indirect contributions from other developers such as arnesongit; I think they should still be acknowledged in one way or another and I would prefer to get his opinion on the matter, before adopting his code.

Now if only Tidal would get a move on and release their public api with all these features included, and we could build against that instead.

Agreed, or provide us with a rate limited client id similar to the official api. That should at least help mitigating misuse (batch downloads etc)

Why should tidal take this down immediately, if we base64 encode the client is, if they haven’t done it so far. It is already like this in the code. We only would replace / extend the current client id. This doesn’t make sense to me…

Regarding the API discussion: WTF? I don’t think tidal likes it, if we store their music instead of immediately deleting it after listening (which is called streaming). You are mad men :D

@tehkillerbee / @tamland: I do not really want to have super super long discussions about fictional possibilities which can happen, if we replace / extend the already in the code present client id. I would like to get this done ASAP and continue to spent my free time on something else. My proposal is to store the new client id the same way (as already done by this project), since nothing happened so far. What is your opinion on this? Do you have a better solution? I am not voting for a solution, where a user needs to extract the client is by themself. If this is what you are voting for I would fork this code and create a new library called tidal-api-ng which has the client id present. Let me know your thoughts.

Why should tidal take this down immediately, if we base64 encode the client is, if they haven’t done it so far. It is already like this in the code. We only would replace / extend the current client id. This doesn’t make sense to me…

Regarding the API discussion: WTF? I don’t think tidal likes it, if we store their music instead of immediately deleting it after listening (which is called streaming). You are mad men :D

@tehkillerbee / @tamland: I do not really want to have super super long discussions about fictional possibilities which can happen, if we replace / extend the already in the code present client id. I would like to get this done ASAP and continue to spent my free time on something else. My proposal is to store the new client id the same way (as already done by this project), since nothing happened so far. What is your opinion on this? Do you have a better solution? I am not voting for a solution, where a user needs to extract the client is by themself. If this is what you are voting for I would fork this code and create a new library called tidal-api-ng which has the client id present. Let me know your thoughts.

This library here is created for streaming. I don't know what you mean about downloading stuff long term, I guess you're doing that some other way.

And Tidal are currently creating a public API, currently it doesn't support any kind of playback, but hopefully it will do in the future.

Why should tidal take this down immediately, if we base64 encode the client is, if they haven’t done it so far. It is already like this in the code. We only would replace / extend the current client id. This doesn’t make sense to me…

Regarding the API discussion: WTF? I don’t think tidal likes it, if we store their music instead of immediately deleting it after listening (which is called streaming). You are mad men :D

@tehkillerbee / @tamland: I do not really want to have super super long discussions about fictional possibilities which can happen, if we replace / extend the already in the code present client id. I would like to get this done ASAP and continue to spent my free time on something else. My proposal is to store the new client id the same way (as already done by this project), since nothing happened so far. What is your opinion on this? Do you have a better solution? I am not voting for a solution, where a user needs to extract the client is by themself. If this is what you are voting for I would fork this code and create a new library called tidal-api-ng which has the client id present. Let me know your thoughts.

To be fair, I understand exactly where you are coming from, you're right about the project already containing an obfuscated client_id. I think the point that both myself, and @tehkillerbee were trying to make is that actually that probably never should have happened in the history of the project.

In the end, I just want to say thank you for putting in the work that you have done so far. Please do not see my comments thus far as anything but simple musings on the grey area that this project skirts in.

@exislow Its not ideal but if the (obfuscated) client_id should be added for high-res playback, I prefer that we add it as an additional client_id that will be used when high-res mode is requested by the user. So in this case we have the original id to fall back on, in case the one obtained from the apk gets rotated and/or stops working.

In any case, thank you for your contribution. PRs are always very appreciated and proper high-res playback has been one of the big tasks that I'd been wanting for a long time. It would be nice to finally add it to the next release of tidalapi.

By the way, @tamland is not maintaining this project anymore but you should be able to reach out to other contributors and maintainers such as myself if you have questions.

@tehkillerbee: I agree to your suggestion and will get you a PR with a second obfuscated client id. But keep in mind, that the current client id was also extracted from an APK by someone and can be rotated as well. But client id rotation is very unlikely, since all users would be forced to update the app otherwise it wouldn't work from one day to another -- just saying. But of course this can happen.

@tehkillerbee: I would love to get comments / PR acceptance for this #221