VideoHelp Forum


Try StreamFab Downloader and download from Netflix, Amazon, Youtube! Or Try DVDFab and copy Blu-rays!


Try StreamFab Downloader and download streaming video from Youtube, Netflix, Amazon! Download free trial.


+ Reply to Thread
Page 3 of 5
FirstFirst 1 2 3 4 5 LastLast
Results 61 to 90 of 127
Thread
  1. joyn.de - from url to download (I have external yt-dlp extractors for joyn, plus.rtl.de, pluto.tv):

    - get access token like aqzs described; if logged in you can refresh your token as well - refresh token is valid for 180 days.
    - from regex r'^https://www.joyn.(de|at)(/play)?(?P<path>/serien/[\w-]+/[\w-]+)' save path
    - get player_video_id for path from graphql with operationName=PageSeriesEpisodePlayerClientSide; sha256Hash for graphql is constant, x-api-key for all graphql queries is constant as well. video_id is found at data.page.episode.id in the returned json object
    - fetch metadata for video_id from graphql PlayerSeriesEpisode
    - find video_id in metadata at data.episode.video.id
    - check if video is age restricted at data.episode.ageRating.minAge in metadata
    - get entitlement_token with video_id and flag if age restricted (minAge >= 16)
    - last: get playlist streams; playlist needs a signature that's built from
    Code:
     SIGNATURE_KEY = '3543373833383336354337383634363635433738363633383236354337383330' \
        '3634353935433738333933353234354337383635333935433738333833323346' \
        '35433738363633333344334235433738333836363335'
    sha_input = f'{data},{entitlement_token}{SIGNATURE_KEY}'
    signature = sha1(sha_input.encode('utf-8')).hexdigest()
    - inside playlist you'll find manifest and license urls.

    "filme" instead of "serien" is quite similar, just needs some different graphql requests.

    Now if aqzs knows a way to manipulate the mpd url to fetch higer resolution than usually 576p - that would be the burner - but I guess that's not possible for joyn as the requests are signed.
    Quote Quote  
  2. good work aqzs and Obo
    Quote Quote  
  3. Member aqzs's Avatar
    Join Date
    Mar 2024
    Location
    Paris
    Search Comp PM
    Originally Posted by Obo View Post
    Now if aqzs knows a way to manipulate the mpd url to fetch higer resolution than usually 576p - that would be the burner - but I guess that's not possible for joyn as the requests are signed.
    Request are signed by you know how to signature is generated, I tried with the best payload possible and still got 576p too :
    Code:
    {"manufacturer":"unknown","platform":"browser","maxSecurityLevel":1,"streamingFormat":"dash","model":"unknown","protectionSystem":"widevine","enableDolbyAudio":True,"enableSubtitles":True,"maxResolution":2160,"variantName":"default","version":"v1"}
    I didn't bother with "platform" and "maxSecurityLevel" since those are hardcoded here :
    Code:
    getClientCapabilities: _(eo, Object.assign(Object.assign({}, X), {
       maxSecurityLevel: 1,
       platform: "browser"
    })),
    I tried a PR/FP request to see if we get higher resolution since those are available :
    Code:
    let i = r.z.enum(["widevine", "fairplay", "playready"]);
    let t.streamingFormatSchema = r.z.enum(["dash", "hls"]);
    Just edit the payload like that :
    Code:
    {"manufacturer":"unknown","platform":"browser","maxSecurityLevel":1,"streamingFormat":"dash","model":"unknown","protectionSystem":"playready","enableDolbyAudio":True,"enableSubtitles":True,"maxResolution":2160,"variantName":"default","version":"v1"}
    {"manufacturer":"unknown","platform":"browser","maxSecurityLevel":1,"streamingFormat":"hls","model":"unknown","protectionSystem":"fairplay","enableDolbyAudio":True,"enableSubtitles":True,"maxResolution":2160,"variantName":"default","version":"v1"}
    I still got 576p.

    The thing that limit manifest to 576p is the token, when decoded we get that :
    Code:
    {'ads_break_spacing': 13,
     'ads_limit_midroll': 5,
     'ads_limit_preroll': 3,
     'ads_max_midroll_blocks': 10,
     'ads_test': '',
     'ads_variant': '',
     'anonymous_id': 'a5aeb22d-ed1a-4571-8bd2-beec7f720bb0',
     'business_model': 'RVOD',
     'catalog_country': 'DE',
     'content_id': 'a_p82ioscdb42',
     'copyrights': ['Brainpool Entertainment GmbH'],
     'distribution_tenant': 'JOYN',
     'entitlement_id': '00ffa125-3263-46e1-8c14-9ae966f29b37',
     'exp': 1723971982,
     'iat': 1723885582,
     'joyn_packages': ['DE_FREE'],
     'key_sign': 'prod',
     'location_country': 'DE',
     'profile_id': 'JNAA-0fbbe8bc-9844-5d8b-aa06-9a69de0e318f_0123456789abcdef',
     'quality': 'SD',
     'user_id': 'JNAA-0fbbe8bc-9844-5d8b-aa06-9a69de0e318f'}
    Because of 'joyn_packages': ['DE_FREE'] and 'quality': 'SD' we are getting 576p and will never get better res without paid account.

    Originally Posted by shellcmd View Post
    good work aqzs and Obo
    Thanks !
    Quote Quote  
  4. Joyn.de doesn't serve higher qualities than 576p
    Also don't forget joyn.ch
    https://github.com/DevLARLEY
    Keys from just the License URL: WidevineFetch
    Quote Quote  
  5. For some series I got 720p, but that seems to be the exception. I even tested the paid grace period once, and even then I didn't get higher resolution. I have the impression that my TV (some newer LG model) gets higher resolution from the joyn app, but it might just be my impression.
    Quote Quote  
  6. Thank you guys for help! Also there is 1080p with Premium Accounts but i think you need to manipulate the API a little bit. I read something with "Android" instead of "Browser"

    Also the Kodi Plugin does that. Seems like Android with an L3 Key gets 1080p but you need an Premium Account for that.

    TV Total has 1080p btw.

    https://www.joyn.de/play/serien/dcs-stargirl/3-1-kapitel-eins-der-mord

    Has 1280x720 with free acc and 1080p with Premium (atleast with Kodi Addon) has someone tested an premium account in a Browser? If you really get 1080p? Maybe its only 1080p for Android. Also the joyn App gets 1080p with Premium maybe there is a way to track that?

    I don't think you need an L1 key for 1080p.

    Originally Posted by Obo View Post
    joyn.de - from url to download (I have external yt-dlp extractors for joyn, plus.rtl.de, pluto.tv):

    - get access token like aqzs described; if logged in you can refresh your token as well - refresh token is valid for 180 days.
    - from regex r'^https://www.joyn.(de|at)(/play)?(?P<path>/serien/[\w-]+/[\w-]+)' save path
    - get player_video_id for path from graphql with operationName=PageSeriesEpisodePlayerClientSide; sha256Hash for graphql is constant, x-api-key for all graphql queries is constant as well. video_id is found at data.page.episode.id in the returned json object
    - fetch metadata for video_id from graphql PlayerSeriesEpisode
    - find video_id in metadata at data.episode.video.id
    - check if video is age restricted at data.episode.ageRating.minAge in metadata
    - get entitlement_token with video_id and flag if age restricted (minAge >= 16)
    - last: get playlist streams; playlist needs a signature that's built from
    Code:
     SIGNATURE_KEY = '3543373833383336354337383634363635433738363633383236354337383330' \
        '3634353935433738333933353234354337383635333935433738333833323346' \
        '35433738363633333344334235433738333836363335'
    sha_input = f'{data},{entitlement_token}{SIGNATURE_KEY}'
    signature = sha1(sha_input.encode('utf-8')).hexdigest()
    - inside playlist you'll find manifest and license urls.

    "filme" instead of "serien" is quite similar, just needs some different graphql requests.

    Now if aqzs knows a way to manipulate the mpd url to fetch higer resolution than usually 576p - that would be the burner - but I guess that's not possible for joyn as the requests are signed.
    I still dont get the {data} part? Data of what? The Age restrict thing is btw. the "PIN" option in the account settings you need an German ID for that (you can generate one not a Problem) had that handled in my Autohotkey version (i just searched for elements and then send the PIN).

    Sorry for all the questions i'am quiet new to Python and its quiet hard to understand if you never learned the language but well i'am trying to learn
    Last edited by Lostion; 17th Aug 2024 at 07:08.
    Quote Quote  
  7. The signature and data part hopefully get much more clear after reading this snippet:
    Code:
        def _build_signature(self, data, token):
            sha_input = f'{data},{token}{self._SIGNATURE_KEY}'
            return sha1(sha_input.encode('utf-8')).hexdigest()
    
        def _get_streams(self, video_id, entitlement_token):
            data = json.dumps({
                'manufacturer': 'unknown',
                'platform': 'browser',
                'maxSecurityLevel': 1,
                'streamingFormat': 'dash',
                'model': 'unknown',
                'protectionSystem': 'widevine',
                'enableDolbyAudio': False,
                'enableSubtitles': True,
                'maxResolution': 1080,
                'variantName': 'default',
                'version': 'v1'
            }, separators=(',',':'))
    
            signature = self._build_signature(data, entitlement_token)
            ...
    Quote Quote  
  8. But what happens if its age restricted? Still trying to understand that code. But thanks a lot!

    Has someone tested if you do 'platform': 'android', ?
    Quote Quote  
  9. Age restriction flag is used when you fetch the entitlement_token (which then needs the pin). The entitlement_token is used to get the stream urls.

    I haven't tested with platform 'android' yet; I'd need to implement the login procedure first - right now I have my saved acess_token that gets renewed with the refresh_token. I've copied the access_token from a browser request. And I only have a free account.

    The Kodi code is not the nicest and cleanest piece of python code on earth and rather hard to understand. I had to work through the requests the browser makes. That's what I've tried to summarize in #61.
    Quote Quote  
  10. Maybe i use the free premium trial (which i didn't knew about becaue at the beginning there were no trial at all) and test in Browser if i get 1080p.

    Because what i've understand the MPD and the License url is protected with a token and the generated signature it would be interesting to see if the browser then plays a 1080p file if you have premium and only the API gets the lower resolution. Maybe 1080p is only with Playready possible?
    Quote Quote  
  11. Guys its working:

    Image
    [Attachment 81542 - Click to enlarge]


    Is there a way to see the API endpoints?

    Edit: I censored the generated token because who knows if joyn can track that...
    Edit2: Only works for productions from joyn everything else like "The Irrational" is limited to 768x432 -.-
    Edit3: Same with Stargirl but that doesnt make any sense because with free acc its 1280x720 oO
    Edit4: Yeah with free acc its 1280x720 wtf also "FBI" is 1024x576 even with premium in Browser. Wtf is that? Why do people pay for such horrible quality seems like only the joyn productions are 1080p atleast in Browser.
    Last edited by Lostion; 17th Aug 2024 at 16:09.
    Quote Quote  
  12. I will download them and send you a pm. Because you need a premium acc for the playlist.

    Edit: check your dm's links send
    Last edited by Lostion; 17th Aug 2024 at 21:59.
    Quote Quote  
  13. Ok guys signature works thanks a lot! But now next there is the next problem

    Failed to retrieve entitlement token: [{'code': 'ENT_AgeVerificationSetupRequired', 'msg': "If you want to watch videos or channels with parental controls, you must first set a parental control PIN. You can't do this here, only in a web browser. Then set the PIN in the Joyn account area."}]

    Is there a way to add the login function?

    i think its something like that here?

    Code:
    				params = dict(username=username, password=password, requestId=request_id)
    				a, b = request_helper.get_url(url='https://auth.7pass.de/login-srv/login',
    											  config=self.config,
    											  post_data=params,
    											  cookie_file=cookie_file,
    											  return_final_url=True,
    											  no_cache=True)
    Iam searching for something like:

    login.txt
    Email
    PW
    PIN

    Is that possible to do? Sorry for the many questions its just like the first time with APIs and Python etc. Its a lot to understand and learn but my premium has 6 days left and i want to play around with the payload like @aqzs did. Would be nice if somebody could help me out, i will ofcourse post the finished .py script at the end
    Quote Quote  
  14. Yes, ofcourse it's possible; but it's a little tricky.

    It seems you need to use the httpx module instead of the requests module, because joyn is hosted at Cloudflare and uses anti bot measures; so HTTP/2 protocol is mandatory, capturing cookies as well, maybe more headers like User-Agent.

    For your personal use it is in my opinion much easier to once capture the JSON return of the token endpoint https://auth.joyn.de/auth/7pass/token, save the JSON, don't use the browser session anymore, and work with the saved tokens.

    Below is what I use in my yt-dlp plugin:
    Code:
        def _get_token(self):
            cached = self.cache.load('joyn', 'token')
            if cached:
                expire, client_id, client_name = traverse_obj(
                    cached['access_token'], ({jwt_decode_hs256}, ('exp', 'cId', 'cN')))
                if time.time() > expire:
                    self._ACCESS_TOKEN = self._refresh_token(client_id, client_name, cached['refresh_token'])
                else:
                    self._ACCESS_TOKEN = cached['access_token']
    
            if not self._ACCESS_TOKEN:
                # refresh token is valid for 180 days and I'm therefore
                # hesitant to implement 7pass authentication
                raise ExtractorError('Login reuqired.')
    
            self.decryption_keys = None
    
        def _refresh_token(self, client_id, client_name, refresh_token):
            data = {
                'client_id': client_id,
                'client_name': client_name,
                'grant_type': 'Bearer',
                'refresh_token': refresh_token
            }
            headers = {
                'content-type': 'application/json',
                'joyn-client-version': self._ACCESS_TOKEN,
                'joyn-country': 'DE',
                'joyn-distribution-tenant': 'JOYN',
                'joyn-platform': 'web',
                'joyn-request-id': f'{uuid.uuid4()}',
                'origin': 'https://www.joyn.de',
            }
            token = self._download_json(
                'https://auth.joyn.de/auth/refresh', None, note='Refresh access token',
                headers=headers, data=json.dumps(data).encode('ascii'))
            self.cache.store('joyn', 'token', token)
            return token['access_token']
    You'd need to implement JWT decomposition yourself (easy enough), everything else is straight forward.
    Quote Quote  
  15. hm i don't understand where the login is? I need to send the Username and the pw to joyn or? because in your code i only see the "https://auth.joyn.de/auth/refresh" but how can i like "login" to joyn first?
    Quote Quote  
  16. As I wrote:
    Originally Posted by Obo View Post
    For your personal use it is in my opinion much easier to once capture the JSON return of the token endpoint https://auth.joyn.de/auth/7pass/token, save the JSON, don't use the browser session anymore, and work with the saved tokens.
    Log in with the browser, in developer mode search the network traffic for the mentionend url, and save the JSON response for later use in your script. Don't use this browser session anymore (so it's best to do this in browsers private mode), that ensures you can use the refresh token in your script. An access token is valid for one hour, refresh token is valid for 180 days.

    The JSON object looks like (formatted)
    Code:
    {
        "access_token": "eyJh...",
        "refresh_token": "eyJh...",
        "token_type": "Bearer",
        "expires_in": 3600000
    }
    I've given up to implement login in script for now, because 7pass returns random 40x answers when I try.
    Last edited by Obo; 18th Aug 2024 at 14:27.
    Quote Quote  
  17. Ah ok i thought its a script for automatic login now it makes more sense
    Quote Quote  
  18. Edit: Now it works didn't change anything oO
    Quote Quote  
  19. Feels Good Man 2nHxWW6GkN1l916N3ayz8HQoi's Avatar
    Join Date
    Jan 2024
    Location
    Pepe Island
    Search Comp PM
    Originally Posted by Obo View Post
    I've given up to implement login in script for now
    Do you want help? I've managed to implement it by just exporting a HAR and following the sequence of requests. I get the final json with the access/refresh token.
    --[----->+<]>.++++++++++++.---.--------.
    [*drm mass downloader: widefrog*]~~~[*how to make your own mass downloader: guide*]
    Quote Quote  
  20. Yes, that would be great. I guess the sequence that the Kodi plugin uses doesn't really work (anymore probably). The sequence that doesn't work for me is:
    - https://auth.joyn.de/sso/endpoints
    - web-login with added redirect_uri
    - https://auth.7pass.de/registration-setup-srv/public/list
    - https://auth.7pass.de/users-srv/user/checkexists/
    - https://auth.7pass.de/verification-srv/v2/setup/public/configured/list
    - https://auth.7pass.de/login-srv/login
    - redeem-token

    What really don't understand is why this sequence sometimes works in debugger but almost never without.
    My HAR has some additional requests, that I've not yet added to the sequence.
    Quote Quote  
  21. access token method worked but i still dont get 1080p for non joyn productions

    some interesting error i found:

    Code:
    Failed to retrieve playlist: 400 {'issues': [{'received': 'joyn_app', 'code': 'invalid_enum_value', 'options': ['android-tv', 'android', 'browser', 'chromecast', 'fire-tv', 'hisense', 'ios', 'ipados', 'kepler', 'netrange', 'panasonic', 'philips', 'playstation', 'sky-q', 'tivo', 'tizen', 'tvos', 'vestel', 'webos'], 'path': ['body', 'platform'], 'message': "Invalid enum value. Expected 'android-tv' | 'android' | 'browser' | 'chromecast' | 'fire-tv' | 'hisense' | 'ios' | 'ipados' | 'kepler' | 'netrange' | 'panasonic' | 'philips' | 'playstation' | 'sky-q' | 'tivo' | 'tizen' | 'tvos' | 'vestel' | 'webos', received 'joyn_app'"}]}
    i think tvos is the right one but seems like it always throughs back the browser playlist hm
    Quote Quote  
  22. Feels Good Man 2nHxWW6GkN1l916N3ayz8HQoi's Avatar
    Join Date
    Jan 2024
    Location
    Pepe Island
    Search Comp PM
    Ok then. This is for joyn.de . Haven't used any paid account or VPN. Only the basic email/password

    Code:
    from urllib.parse import parse_qs, urlparse
    
    import requests
    
    EMAIL = "YOUR_EMAIL"
    PASSWORD = 'YOUR_PASSWORD'
    
    response = requests.get(
        'https://auth.joyn.de/sso/endpoints',
        params={
            'client_id': 'client_id',
            'client_name': 'web'
        }
    ).json()
    
    response = response["web-login"]
    response = parse_qs(urlparse(response).query)
    client_id = response["client_id"][0]
    
    response = requests.get(
        'https://auth.7pass.de/authz-srv/authz',
        params={
            'client_id': client_id,
            'response_type': 'code'
        },
        allow_redirects=False
    )
    response = response.headers["location"]
    response = parse_qs(urlparse(response).query)
    request_id = response["requestId"][0]
    
    response = requests.post(
        'https://auth.7pass.de/login-srv/login',
        data={
            'username': EMAIL,
            'requestId': request_id,
            'password': PASSWORD
        },
        allow_redirects=False
    )
    
    response = response.headers["location"]
    response = parse_qs(urlparse(response).query)
    code = response["code"][0]
    
    response = requests.post(
        'https://auth.joyn.de/auth/7pass/token',
        json={
            'code': code,
            'client_id': client_id,
            'redirect_uri': 'https://www.joyn.de/oauth',
            'tracking_name': 'web'
        }
    )
    
    print(response.json())
    For HAR, I used incognito to make sure nothing was saved in cookies/cache/etc. I saved all possible requests even after redirecting. And I started with the main page joyn.de . I then identified the request that returned what you said (tokens). Copied to curl , then to python, and started building from that. Obviously that curl you generate to python, it's not gonna work, cause it's a one time request. But you can still start building from it, by looking what was used prior to it and seeing that getting new values for those will work.

    Edit: I spammed that script for a while, and if you do too many logins, it may crash, so be careful
    --[----->+<]>.++++++++++++.---.--------.
    [*drm mass downloader: widefrog*]~~~[*how to make your own mass downloader: guide*]
    Quote Quote  
  23. @2nHxWW6GkN1l916N3ayz8HQoi

    Works like a charme! Thank you very much
    Quote Quote  
  24. Can someone point me out how to get the video id for

    https://www.joyn.de/play/playlist/1018628

    There is no video id in the header :/

    Edit:

    https://www.joyn.de/play/highlight/serien/ran-fussball-baller-league-dp4mjk4u2ejx/zusa...ung-spieltag-4

    Now it works its just a playlist with different videos one after another.
    Last edited by Lostion; 18th Aug 2024 at 19:19.
    Quote Quote  
  25. Guys i have some good news:

    https://www.joyn.de/play/serien/the-irrational-kriminell-logisch/1-1-erinnerungsluecken

    Audio EAC3 256.

    with

    Code:
                'manufacturer': 'unknown',
                'platform': 'browser',
                'maxSecurityLevel': 1,
                'streamingFormat': 'dash',
                'model': 'unknown',
                'protectionSystem': 'widevine',
                'enableDolbyAudio': False,
                'enableSubtitles': True,
                'maxResolution': 1080,
                'variantName': 'default',
                'version': 'v1'
    You get stereo AAC 160 2.0 audio

    the trick is

    Code:
                'manufacturer': 'unknown',
                'platform': 'browser',
                'maxSecurityLevel': 1,
                'streamingFormat': 'dash',
                'model': 'unknown',
                'protectionSystem': 'widevine',
                'enableDolbyAudio': True,
                'enableSubtitles': True,
                'maxResolution': 1080,
                'variantName': 'default',
                'version': 'v2'
    Still didnt get 1080p but iam on it. They are atleast 5 maxSecurityLevels. All 5 gives SD but i think its the combination which will work.

    Edit:

    Code:
            data = json.dumps({
                'manufacturer': 'unknown',
                'platform': 'tvos',
                'maxSecurityLevel': 5,
                'streamingFormat': 'dash',
                'model': 'unknown',
                'protectionSystem': 'widevine',
                'enableDolbyAudio': True,
                'enableSubtitles': True,
                'maxResolution': 2160,
                'variantName': 'default',
                'version': 'v2'
            }, separators=(',', ':'))
    Gives you 1080p my friends atleast with Premium Account. Not sure about Free Acc.

    Edit done testing with Premium:

    FullHD/EAC3 = 'android-tv', 'android', 'chromecast', 'fire-tv', 'hisense', 'ios', 'ipados', 'kepler', 'netrange', 'panasonic', 'philips', 'playstation', 'sky-q', 'tivo', 'tizen', 'tvos', 'vestel', 'webos'
    SD/EAC3 = 'browser'

    Some also gives you Stereo + EAC3 5.1 some not will look into that later.
    Last edited by Lostion; 18th Aug 2024 at 20:37.
    Quote Quote  
  26. Thanks for the script!
    Originally Posted by 2nHxWW6GkN1l916N3ayz8HQoi View Post
    Edit: I spammed that script for a while, and if you do too many logins, it may crash, so be careful
    Yeah, that may have happended for me - it doesn't work with my login right now. I guess Cloudflare measures are active here. I'll wait for a week (or longer) and try again.

    Originally Posted by Lostion View Post
    Gives you 1080p my friends atleast with Premium Account. Not sure about Free Acc.
    Nice findings! But in result unfortunately for free accounts only more and different audio options, not the higher resolution.
    Quote Quote  
  27. Yeah it seems 1080p is for premium only atleast it's possible now
    Quote Quote  
  28. Did joyn change something?

    raise RequestsJSONDecodeError(e.msg, e.doc, e.pos)
    requests.exceptions.JSONDecodeError: Expecting value: line 1 column 1 (char 0)

    my script isn't working anymore oO but it did 5 hours ago wtf.

    Edit:

    Error: Received status code 404 when fetching the URL.
    Failed to retrieve content details.

    wtf -.-

    def getid(videourl):
    if 'https://www.joyn.de' in videourl:
    slug = videourl.replace('https://www.joyn.de/', '')
    data = requests.get(f'https://www.joyn.de/_next/data/-ED4ji1a6D8khV7D7beLb/{slug}.json').json()

    isnt working anymore it just shows 404

    Edit: fixxed it with another method hope it works more.
    Last edited by Lostion; 19th Aug 2024 at 06:49.
    Quote Quote  
  29. Feels Good Man 2nHxWW6GkN1l916N3ayz8HQoi's Avatar
    Join Date
    Jan 2024
    Location
    Pepe Island
    Search Comp PM
    Originally Posted by Obo View Post
    Yeah, that may have happended for me - it doesn't work with my login right now. I guess Cloudflare measures are active here. I'll wait for a week (or longer) and try again.
    In those cases, it's best just to use a cache mechanism + refresh token endpoint. And save it locally again each time you refresh it.
    --[----->+<]>.++++++++++++.---.--------.
    [*drm mass downloader: widefrog*]~~~[*how to make your own mass downloader: guide*]
    Quote Quote  



Similar Threads

Visit our sponsor! Try DVDFab and backup Blu-rays!