VideoHelp Forum
+ Reply to Thread
Page 4 of 5
FirstFirst ... 2 3 4 5 LastLast
Results 91 to 120 of 148
Thread
  1. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by sipho View Post
    Two questions/requests

    1. Any way to download to a series folder instead of the default download location?

    2. Is there a possibility to download but NOT mux subtitles?
    I tried adding a line above the main download command to just download subs but it doesn't work.
    1. What's a video url you are looking at ? I can't readily find a stream with subtitles in it. Freevine had a --sub-no-mux command but that's not native to N_m3u8DL-RE. I'm not using any additional arguments at all with Ozivine, it's pure N_m3u8DL-RE. In theory --sub-only should work but I can't say I've ever tried it.

    2. You'd have to modify the function that gets the show information and then the main function modify the download command to something like this

    Code:
    # Create the download command with the show title in the save directory
                        download_dir = f"{downloads_path}/{show_title}"
                        download_command = f"""N_m3u8DL-RE "{mpd_url}" --select-video best --select-audio best --select-subtitle all -mt -M format=mkv --save-dir "{download_dir}" --save-name "{formatted_file_name}" --key """ + ' --key '.join(formatted_keys)
                        print(download_command)
    It's not something I'll be doing globally, so you'd have to modify all the individual service scripts if that's what you wanted as the default behaviour.
    Quote Quote  
  2. Member
    Join Date
    Dec 2022
    Location
    Lesotho
    Search Comp PM
    Originally Posted by billybanana View Post
    1. What's a video url you are looking at ? I can't readily find a stream with subtitles in it. Freevine had a --sub-no-mux command but that's not native to N_m3u8DL-RE. I'm not using any additional arguments at all with Ozivine, it's pure N_m3u8DL-RE. In theory --sub-only should work but I can't say I've ever tried it.
    This one.

    Code:
    https://7plus.com.au/stumptown?episode-id=SMPT01-001&autoplay=true

    2. You'd have to modify the function that gets the show information and then the main function modify the download command to something like this

    Code:
    # Create the download command with the show title in the save directory
                        download_dir = f"{downloads_path}/{show_title}"
                        download_command = f"""N_m3u8DL-RE "{mpd_url}" --select-video best --select-audio best --select-subtitle all -mt -M format=mkv --save-dir "{download_dir}" --save-name "{formatted_file_name}" --key """ + ' --key '.join(formatted_keys)
                        print(download_command)
    It's not something I'll be doing globally, so you'd have to modify all the individual service scripts if that's what you wanted as the default behaviour.
    Thanks, I'll see if it's worth the trouble but I doubt it. No biggie.
    Quote Quote  
  3. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by sipho View Post
    This one.

    Code:
    https://7plus.com.au/stumptown?episode-id=SMPT01-001&autoplay=true
    This got me the subs only for that show

    Code:
    N_m3u8DL-RE "https://manifest.prod.boltdns.net/manifest/v1/dash/live-baseurl/bccenc/5303576322001/1c8b594f-7bae-4254-85ff-faa3e4e9a050/2s/manifest.mpd?fastly_token=NjZjYzYyMWNfMGU4ZjM3MjVjYWMyYWMzZjQ2MmU1OWZjZWI5MDVjOGZmNmRlZDQ1NjUxYWVkYzNkYzYwZTZlNzQxYzQ2ZDQzOA%3D%3D&appId=7plus&deviceType=web&platformType=web&ppId=f9b62de0df06a7c1b6ee040a0ab5202f3290d049340f1edc629d8dd17f0f12b6&videoType=vod&accountId=5303576322001&uaId=f9b62de0df06a7c1b6ee040a0ab5202f3290d049340f1edc629d8dd17f0f12b6&optinDeviceType=&optinAdTracking=0&mstatus=true&hl=en&referenceId=SMPT01-001&pp=csai-web&cmsId=2466102&custParams=y%253D6%2526c%253Dn%2526dpc%253D3003&y=6&c=n&dpc=3003&behavior_id=acde4ed6-11dd-456b-9696-d788e9d12b93" --sub-only --save-dir "D:/Downloads/" --save-name "Stumptown.S01E01.720p.7PLUS.WEB-DL.AAC2.0.H.264"
    So you only need this for subs only

    Code:
    download_command = f"""N_m3u8DL-RE "{url}" --sub-only  --save-dir "{downloads_path}" --save-name "{formatted_file_name}" """
    Quote Quote  
  4. Member
    Join Date
    Dec 2022
    Location
    Lesotho
    Search Comp PM
    Thanks a lot!
    Quote Quote  
  5. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by SaLTy View Post
    Strange, I wonder why they're doing 576p now and also wonder how someone else managed to get 720p WEB-DL for the same show. Hopefully the rest is 720p
    S02E02 is back to 720p this week. So looks to be a one off only.
    Quote Quote  
  6. Had a play around with this and works great on what I tested.

    FYI your 9now section grabs the AVC HLS stream which can be anywhere as much as 20% lower bitrate than the H264 stream.

    EG: https://www.9now.com.au/tipping-point-australia/season-24/episode-121

    AVC Stream - ~1542 kb/s @ 553mb in size
    H264 - ~1998 kb/s @ 703mb in size

    Snapshot below of the two varients in a yt-dlp output
    Quote Quote  
  7. Thanks billybanana of your useful work.

    I have one question, what is the requirement for your code if we want to integrate them with Devine services.

    I tried to copy them with the same formula but it does'n work.
    Quote Quote  
  8. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by wastedhate View Post
    FYI your 9now section grabs the AVC HLS stream which can be anywhere as much as 20% lower bitrate than the H264 stream.

    EG: https://www.9now.com.au/tipping-point-australia/season-24/episode-121

    AVC Stream - ~1542 kb/s @ 553mb in size
    H264 - ~1998 kb/s @ 703mb in size
    Interesting info. I've only really coded this to look for encrypted first and then non-encrypted as a fall back, which is the m3u8 in this case.

    yt-dlp fetches the file info from
    http://players.brightcove.net/4460760524001/default_default/index.html?videoId=6361410...%22AU%22%5D%7D

    I'm using the api to get the manifest info from
    https://edge.api.brightcove.com/playback/v1/accounts/460760524001/videos/6361410167112

    I'd have to look into what the differences are if I have some time and understand how the higher bitrate streams are presented.

    Originally Posted by mr_thamer View Post
    I have one question, what is the requirement for your code if we want to integrate them with Devine services.

    I tried to copy them with the same formula but it does'n work.
    I started out trying to write these services for Devine and got a little way with ABC iView, but honestly found them easier to develop as standalone scripts and then Ozivine was born. I couldn't get my head around exactly what Devine was doing and besides 1. I wanted to use N_m3u8DL-RE as the downloader and 2. from a selfish perspective, my own use case was to only need the script to get the file from an episode/film url, as I have built my own GUI for the series and episode info.
    Quote Quote  
  9. oh and FYI @billybanana

    you can pull 1080p iview without resorting to the encrypted MPD file too.

    if you dump the JSON for the episode youll find unencrypted 720.m3u8 urls in there which can just be modified to 1080.m3u8 and you have unencrypted 1080p files
    Quote Quote  
  10. Member
    Join Date
    Dec 2022
    Location
    Lesotho
    Search Comp PM
    Strongly agree that the biggest issue with devine is the lack of N_m3u8DL-RE support as a downloader. It's painfully slow.
    Quote Quote  
  11. Originally Posted by billybanana View Post
    Originally Posted by wastedhate View Post
    FYI your 9now section grabs the AVC HLS stream which can be anywhere as much as 20% lower bitrate than the H264 stream.

    EG: https://www.9now.com.au/tipping-point-australia/season-24/episode-121

    AVC Stream - ~1542 kb/s @ 553mb in size
    H264 - ~1998 kb/s @ 703mb in size
    Interesting info. I've only really coded this to look for encrypted first and then non-encrypted as a fall back, which is the m3u8 in this case.

    yt-dlp fetches the file info from
    http://players.brightcove.net/4460760524001/default_default/index.html?videoId=6361410...%22AU%22%5D%7D

    I'm using the api to get the manifest info from
    https://edge.api.brightcove.com/playback/v1/accounts/460760524001/videos/6361410167112

    I'd have to look into what the differences are if I have some time and understand how the higher bitrate streams are presented.

    Originally Posted by mr_thamer View Post
    I have one question, what is the requirement for your code if we want to integrate them with Devine services.

    I tried to copy them with the same formula but it does'n work.
    I started out trying to write these services for Devine and got a little way with ABC iView, but honestly found them easier to develop as standalone scripts and then Ozivine was born. I couldn't get my head around exactly what Devine was doing and besides 1. I wanted to use N_m3u8DL-RE as the downloader and 2. from a selfish perspective, my own use case was to only need the script to get the file from an episode/film url, as I have built my own GUI for the series and episode info.
    Noted,

    Thank you anyway
    Quote Quote  
  12. Member
    Join Date
    Feb 2022
    Location
    Search the forum first!
    Search PM
    Originally Posted by billybanana View Post

    I started out trying to write these services for Devine and got a little way with ABC iView, but honestly found them easier to develop as standalone scripts and then Ozivine was born. I couldn't get my head around exactly what Devine was doing and besides 1. I wanted to use N_m3u8DL-RE as the downloader and 2. from a selfish perspective, my own use case was to only need the script to get the file from an episode/film url, as I have built my own GUI for the series and episode info.
    That is such an important point. And the scripts can be more flexible because of it. No one-size fits all; never has.
    Noob Starter Pack. Just download every Widevine mpd! Not kidding!.
    https://files.videohelp.com/u/301890/hellyes6.zip
    Quote Quote  
  13. 10play has chaged their site code today. breaks the old M3U8 sourcing used to get the output for both yt-dlp and N_m3u8DL-RE
    Quote Quote  
  14. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by wastedhate View Post
    10play has changed their site code today. breaks the old M3U8 sourcing used to get the output for both yt-dlp and N_m3u8DL-RE
    Well that's a bit of a pain. On first glance they seem to have injected ads or they're hiding the non-ad infested manifest. Don't think this is going to be a quick fix for me.
    Quote Quote  
  15. Originally Posted by billybanana View Post
    Originally Posted by wastedhate View Post
    10play has changed their site code today. breaks the old M3U8 sourcing used to get the output for both yt-dlp and N_m3u8DL-RE
    Well that's a bit of a pain. On first glance they seem to have injected ads or they're hiding the non-ad infested manifest. Don't think this is going to be a quick fix for me.
    It looks like the ads are served from: redirector.googlevideo.com, it might be worth taking advantage of m3u8dl's custom --ad-keyword "string" to see if it will remove/skip the ad segments? --ad-keyword "googlevideo" or something, regex might need tinkering, that would then be added into the current 10play.py download_command?
    Quote Quote  
  16. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by MonkeyMagic View Post

    It looks like the ads are served from: redirector.googlevideo.com,
    Yup this works fine to remove the ads from the manifest.

    Code:
    --ad-keyword redirector.googlevideo.com
    The manifest is limited to 540p, so gotta figure out how to get 720p version. The previous mod no longer works given the manifest is a different structure.

    It used to be picked up by the script from the source in the api response but that field is now blank, so trying work out what they've done with this.
    https://10play.com.au/api/v1/videos/playback/tpv240902vilde/?platform=web

    Code:
    	
    isLive	false
    isPreRollDisabled	false
    isMemberGated	false
    dai	Object { enabled: true, videoId: "7716070000007760", contentSourceId: "2489270" }
    enabled	true
    videoId	"7716070000007760"
    contentSourceId	"2489270"
    drm	Object { enabled: false }
    enabled	false
    cuePoints	Object { videoAds: [], richAds: [] }
    source	"https://"
    Anyone wants to help me out with tis, you're more than welcome
    Quote Quote  
  17. adding

    Code:
     --referer "https://10play.com.au"
    to yt-dlp gets the file. albeit it SD as previously mentioned and still contains the adverts. Episode url doesnt work yet so you have to use the master.m3u8 file.

    Side note:

    inside the m3u8 for the SD 540p version there is a line that contains:

    Code:
    #EXT-X-KEY:METHOD=AES-128,URI="https://10play-vod.global.ssl.fastly.net/OTFP/b924a87680503841595f597d9df6768aa46502c08bb35b90a2876801894c671d/0L-neighb-NEB28_9107_20240905-TEN-1500000.key",IV=xxxxxxxxxxxxxxxxxxxxxx"
    this key at the end seems to be they key to "unlocking" file access because if you change on of the .TS files to be 300000-1.ts etc it is possible to grab a chunk of the file but it doesnt play. It implies the 720p variant is still there just need to determine how to access it
    Quote Quote  
  18. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by wastedhate View Post
    this key at the end seems to be they key to "unlocking" file access because if you change on of the .TS files to be 300000-1.ts etc it is possible to grab a chunk of the file but it doesnt play. It implies the 720p variant is still there just need to determine how to access it
    I've now got the episode url working ok and without ads in the manifest that I identify (without using the --ad-keyword command).

    For those that are interested. Where the "source" field is now empty in the api repsonse. I ignored that and extracted the "videoId" and the "contentSourceId" fields. You can then use those items to make another call, let's call it "streams request" in the format

    Code:
    https://pubads.g.doubleclick.net/ondemand/hls/content/{content_source_id}/vid/{video_id}/streams
    The response will then give you the manifest url

    Code:
    {
        "stream_id": "3f0e59c9-54e7-4f83-8f9b-e2c60442d9f9",
        "duration": 3124.264,
        "stream_type": "on_demand",
        "stream_manifest": "https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/3f0e59c9-54e7-4f83-8f9b-e2c60442d9f9/master.m3u8",
        "manifest_format": "hls",
        "time_events_url": "https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/3f0e59c9-54e7-4f83-8f9b-e2c60442d9f9/time-events.json",
        "subtitles": [
            {
                "language": "en",
                "language_name": "English",
                "ttml": "https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/3f0e59c9-54e7-4f83-8f9b-e2c60442d9f9/ttml/f24332da-819c-4857-92d9-055a1979af9d.ttml",
                "webvtt": "https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/3f0e59c9-54e7-4f83-8f9b-e2c60442d9f9/vtt/f24332da-819c-4857-92d9-055a1979af9d.vtt"
            }
        ]
    }
    Now to fiddle about with the 720p issue. @wastedhate I did notice that key yesterday. Hopefully I can understand how that works and what to do next.

    Edit: I've been trying a few things with the 540p variant manifest. Saved it locally and modified all the 1500000 references to 3000000, then downloaded the file. It decrypted ok that would perhaps suggest the IV value is a constant no matter the resolution/bitrate. The downloaded file was still 540p but a higher bitrate than the standard (3,291k/bs vs 1,836k/bs). So I think we're on the right track looking for a higher resolution, but the question is how do they hide it now.

    Have also tried android platform and headers etc without any difference to date. Got me a bit stumped now.
    Last edited by billybanana; 6th Sep 2024 at 03:35. Reason: Updated info
    Quote Quote  
  19. Just a thanks to everyone contributing here, I can't add anything further other than a polite applause for your efforts so far. We're rooting for you billybanana !!
    Quote Quote  
  20. Originally Posted by sipho View Post
    Strongly agree that the biggest issue with devine is the lack of N_m3u8DL-RE support as a downloader. It's painfully slow.
    concur with this, even so why i still use freevine, eg for the uk sites, maybe its the lack of multithread, but devine on alot of services is very slow.
    Quote Quote  
  21. Successfully grabbed 720p this morning.

    Took the SD m3u8 file, replaced all instances of 1500000 with 3000000, ran that through the beta N_m3u8dl-re with the --ad-keyword redirector.googlevideo and got the 720p file
    Quote Quote  
  22. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by wastedhate View Post
    Successfully grabbed 720p this morning.
    I've now got this working as well. I'm having to save that modified 540p file locally and then run the download command with it. Still seeing if I can do this by committing the changes to memory rather than saving an additional file. Not the end of the world if I can't.

    Code:
    D:\Downloads\CDM>10play
    Enter the 10Play video URL: https://10play.com.au/have-you-been-paying-attention/episodes/2024/episode-17/tpv240902vilde
    Login successful, token obtained
    SD M3U8 URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/6b9f1c0d-0aa4-4214-8902-1e42272ae39f/media/b26a8d0b034d10102de54935d6e484bb.m3u8
    HD M3U8 File: D:/Downloads/b26a8d0b034d10102de54935d6e484bb.m3u8
    DOWNLOAD COMMAND:
    N_m3u8DL-RE "D:/Downloads/b26a8d0b034d10102de54935d6e484bb.m3u8" --select-video best --select-audio best --select-subtitle all -mt -M format=mkv --save-dir "D:/Downloads/" --save-name "Have.You.Been.Paying.Attention?.S2024E17.720p.10Play.WEB-DL.AAC2.0.H.264"
    Do you wish to download? Y or N: y
    10:55:08.390 INFO : N_m3u8DL-RE (Beta version) 20240630
    10:55:08.400 INFO : Loading URL: D:/Downloads/b26a8d0b034d10102de54935d6e484bb.m3u8
    10:55:08.409 INFO : Content Matched: HTTP Live Streaming
    10:55:08.410 INFO : Parsing streams...
    10:55:08.546 WARN : Writing meta json
    10:55:08.549 INFO : Extracted, there are 1 streams, with 1 basic streams, 0 audio streams, 0 subtitle streams
    10:55:08.550 INFO : Vid *AES_128 Kbps | 448 Segments | ~44m21s
    10:55:08.551 INFO : Selected streams:
    10:55:08.551 INFO : Vid *AES_128 Kbps | 448 Segments | ~44m21s
    10:55:08.552 WARN : Writing meta json
    10:55:08.554 INFO : Save Name: Have.You.Been.Paying.Attention..S2024E17.720p.10Play.WEB-DL.AAC2.0.H.264
    10:55:08.554 WARN : MuxAfterDone is detected, binary merging is automatically enabled
    10:55:08.555 INFO : Start downloading...Vid Kbps
    10:55:08.604 WARN : Reading media info...
    10:55:08.630 INFO : [0x100]: Video, h264 (High), 1280x720, 25 fps
    10:55:08.631 INFO : [0x101]: Audio, aac (LC), 255 kb/s
    10:55:19.658 INFO : Binary merging...
    10:55:21.498 WARN : Have.You.Been.Paying.Attention..S2024E17.720p.10Play.WEB-DL.AAC2.0.H.264.ts
    10:55:21.498 WARN : Muxing to Have.You.Been.Paying.Attention..S2024E17.720p.10Play.WEB-DL.AAC2.0.H.264.MUX.mkv
    10:55:25.349 WARN : Cleaning files...
    10:55:26.023 WARN : Rename to Have.You.Been.Paying.Attention..S2024E17.720p.10Play.WEB-DL.AAC2.0.H.264.mkv
    10:55:26.198 INFO : Done
    If anyone wishes to do some testing for me, take the script below, save it as 10play.py and replace the existing file in your Ozivine/services/10play folder

    Code:
    import requests
    import datetime as dt
    import base64
    import subprocess
    import re
    import os
    
    #   Ozivine: 10Play Video Downloader
    #   Author: billybanana
    #   Usage: enter the series/season/episode URL to retrieve the m3u8 Manifest.
    #   eg: https://10play.com.au/south-park/episodes/season-15/episode-6/tpv240705gpchj
    #   Authentication: Login
    #   Geo-Locking: requires an Australian IP address
    #   Quality: up to 720p
    #   Key Features:
    #   1. Extract Video ID: Parses the 10Play video URL to extract the video id and then fetches the show/movie info from the 10Play API.
    #   2. Print Download Information: Outputs the M3U8 URL required for downloading the video content.
    #   3. Note: this script functions for AES_128 encrypted video files only.
    
    # Formatting for output
    class bcolors:
        HEADER = '\033[95m'
        OKBLUE = '\033[94m'
        OKCYAN = '\033[96m'
        OKGREEN = '\033[92m'
        WARNING = '\033[93m'
        FAIL = '\033[91m'
        ENDC = '\033[0m'
        BOLD = '\033[1m'
        UNDERLINE = '\033[4m'
        LIGHTBLUE = '\033[94m'
        YELLOW = '\033[93m'
        ORANGE = '\033[93m'
    
    # URLs and Headers
    login_url = 'https://10play.com.au/api/user/auth'
    headers = {
        'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/126.0.0.0 Safari/537.36 Edg/126.0.0.0',
        'Accept': 'application/json, text/plain, */*',
        'Accept-Language': 'en-US,en;q=0.9',
        'Origin': 'https://10play.com.au',
        'Referer': 'https://10play.com.au/'
    }
    
    # Function to get bearer token
    def get_bearer_token(username, password):
        timestamp = dt.datetime.now().strftime('%Y%m%d000000')
        auth_header = base64.b64encode(timestamp.encode('ascii')).decode('ascii')
        login_payload = {'email': username, 'password': password}
        login_headers = headers.copy()
        login_headers['X-Network-Ten-Auth'] = auth_header
    
        response = requests.post(login_url, json=login_payload, headers=login_headers)
        if response.status_code == 200:
            data = response.json()
            if 'jwt' in data:
                return 'Bearer ' + data['jwt']['accessToken']
        return None
    
    # Function to extract video details and manifest URL
    def extract_video_details(video_id, token):
        video_api_url = f'https://10play.com.au/api/v1/videos/{video_id}'
        auth_headers = headers.copy()
        auth_headers['Authorization'] = token
    
        response = requests.get(video_api_url, headers=auth_headers)
        if response.status_code == 200:
            video_data = response.json()
            if 'playbackApiEndpoint' in video_data:
                playback_url = video_data['playbackApiEndpoint'] + "?platform=web"
                playback_response = requests.get(playback_url, headers=auth_headers)
                if playback_response.status_code == 200:
                    playback_data = playback_response.json()
                    
                    if 'source' in playback_data and playback_data['source'] != "https://":
                        return playback_data['source'], video_data
                    elif 'dai' in playback_data:
                        video_id = playback_data['dai'].get('videoId')
                        content_source_id = playback_data['dai'].get('contentSourceId')
                        if video_id and content_source_id:
                            return get_stream_manifest(content_source_id, video_id), video_data
                        else:
                            print(f"{bcolors.FAIL}Missing videoId or contentSourceId in playback data{bcolors.ENDC}")
        else:
            print(f"{bcolors.FAIL}Failed to fetch video details{bcolors.ENDC}")
        return None, None
    
    # Function to retrieve stream manifest URL using POST
    def get_stream_manifest(content_source_id, video_id):
        manifest_url = f"https://pubads.g.doubleclick.net/ondemand/hls/content/{content_source_id}/vid/{video_id}/streams"
        
        stream_headers = {
            'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 Edg/128.0.0.0',
            'Accept': '*/*',
            'Content-Type': 'application/x-www-form-urlencoded;charset=UTF-8',
            'Origin': 'https://10play.com.au',
        }
    
        post_data = {
            'cmsid': content_source_id,
            'vid': video_id
        }
    
        response = requests.post(manifest_url, headers=stream_headers, data=post_data)
        
        if response.status_code in [200, 201]:
            stream_data = response.json()
            if 'stream_manifest' in stream_data:
                return stream_data['stream_manifest']
            else:
                print(f"{bcolors.FAIL}No stream_manifest found in response{bcolors.ENDC}")
        else:
            print(f"{bcolors.FAIL}Failed to retrieve stream manifest. Status: {response.status_code}{bcolors.ENDC}")
        return None
    
    # Function to download the master M3U8 manifest and select 960x540 variant
    def download_and_select_variant(manifest_url):
        response = requests.get(manifest_url)
        if response.status_code == 200:
            manifest_content = response.text
            # Find 960x540 variant
            pattern = re.compile(r'RESOLUTION=960x540[^\n]+\n(https?://[^\s]+)', re.MULTILINE)
            match = pattern.search(manifest_content)
            if match:
                return match.group(1)
            else:
                print(f"{bcolors.FAIL}960x540 variant not found in manifest{bcolors.ENDC}")
                return None
        else:
            print(f"{bcolors.FAIL}Failed to download manifest: {response.status_code}{bcolors.ENDC}")
            return None
    
    # Function to modify the variant M3U8 content and save with proper filename
    def modify_and_save_m3u8(variant_url, downloads_path):
        response = requests.get(variant_url)
        if response.status_code == 200:
            m3u8_content = response.text
            modified_content = m3u8_content.replace("1500000", "3000000")
            
            # Extract the last part of the URL for naming
            filename = variant_url.split('/')[-1]  # This gives the last part, e.g., b26a8d0b034d10102de54935d6e484bb.m3u8
            local_m3u8_file = os.path.join(downloads_path, filename)
    
            # Save the modified content to the file
            with open(local_m3u8_file, 'w') as file:
                file.write(modified_content)
    
            return local_m3u8_file, variant_url  # Return both local path and the original 960x540 URL
        else:
            print(f"{bcolors.FAIL}Failed to fetch the variant m3u8 file. Status: {response.status_code}{bcolors.ENDC}")
            return None, None
    
    # Function to format the filename based on video details
    def format_file_name(video_data):
        show_name = video_data['tvShow'].replace(' ', '.')
        clip_title = video_data.get('clipTitle', '').replace(' ', '.')
        genre = video_data.get('genre', '').lower()
        season = int(video_data['season'])
    
        if genre == 'movies':
            formatted_file_name = f"{show_name}.720p.10Play.WEB-DL.AAC2.0.H.264"
        elif genre == 'sport':
            formatted_file_name = f"{clip_title}.S{season}.720p.10Play.WEB-DL.AAC2.0.H.264"
        else:
            episode = int(video_data['episode'])
            season_episode_tag = f"S{season:02d}E{episode:02d}"
            formatted_file_name = f"{show_name}.{season_episode_tag}.720p.10Play.WEB-DL.AAC2.0.H.264"
        
        return formatted_file_name
    
    # Function to format and display download command
    def display_download_command(m3u8_file_path, formatted_file_name, downloads_path):
        download_command = f"""N_m3u8DL-RE "{m3u8_file_path}" --select-video best --select-audio best --select-subtitle all -mt -M format=mkv --save-dir "{downloads_path}" --save-name "{formatted_file_name}" """    
        print(f"{bcolors.LIGHTBLUE}HD M3U8 File: {bcolors.ENDC}{m3u8_file_path}")
        print(f"{bcolors.YELLOW}DOWNLOAD COMMAND: {bcolors.ENDC}")
        print(download_command)
        
        user_input = input("Do you wish to download? Y or N: ").strip().lower()
        if user_input == 'y':
            subprocess.run(download_command, shell=True)
    
    # Function to extract video ID from URL
    def extract_video_id(url):
        match = re.search(r'/([^/]+)/?$', url)
        return match.group(1) if match else None
    
    # Main logic
    def main(video_url, downloads_path, credentials):
        username, password = credentials.split(':')
        video_id = extract_video_id(video_url)
        
        if not video_id:
            print(f"{bcolors.FAIL}Invalid URL. Please enter a valid 10Play video URL.{bcolors.ENDC}")
            return
    
        token = get_bearer_token(username, password)
        if token:
            print(f"{bcolors.OKGREEN}Login successful, token obtained{bcolors.ENDC}")
            manifest_url, video_data = extract_video_details(video_id, token)
            if manifest_url and video_data:
                variant_url = download_and_select_variant(manifest_url)
                if variant_url:
                    local_m3u8_file, original_variant_url = modify_and_save_m3u8(variant_url, downloads_path)
                    if local_m3u8_file:
                        # Print the original 960x540 URL and the local path
                        print(f"{bcolors.LIGHTBLUE}SD M3U8 URL: {bcolors.ENDC}{original_variant_url}")
                        
                        formatted_file_name = format_file_name(video_data)
                        display_download_command(local_m3u8_file, formatted_file_name, downloads_path)
                    else:
                        print(f"{bcolors.FAIL}Failed to modify and save the variant M3U8{bcolors.ENDC}")
                else:
                    print(f"{bcolors.FAIL}Failed to find 960x540 variant{bcolors.ENDC}")
            else:
                print(f"{bcolors.FAIL}Failed to extract manifest URL{bcolors.ENDC}")
        else:
            print(f"{bcolors.FAIL}Login failed{bcolors.ENDC}")
    Last edited by billybanana; 6th Sep 2024 at 22:31. Reason: Added updated 10play script
    Quote Quote  
  23. Originally Posted by billybanana View Post
    I've now got this working as well. I'm having to save that modified 540p file locally and then run the download command with it. Still seeing if I can do this by committing the changes to memory rather than saving an additional file. Not the end of the world if I can't.
    I'm in the same boat. Not going to spend much time on that when its simpler to run an extra line or two to delete the files after use. Especially considering there will be updates to yt-dlp soon that might tweak how its all run etc
    Quote Quote  
  24. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    It's interesting that each resolution has its own constant end to the m3u8 url ie: 540p being "b26a8d0b034d10102de54935d6e484bb.m3u8". If it is somehow possible to identify what the 720p one is, then that will make life much easier moving forward.
    Quote Quote  
  25. If we can determine which devices get 720p (if any) might be able to use something like mitmproxy to do it
    Quote Quote  
  26. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    I was able to extract the manifests for each platform that 10play supports. Unfortunately, none of them directly expose the 720p resolution in the manifest, so it looks like the modified m3u8 file is the way to go.

    Code:
    Platform web: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/c0c68254-5ab7-4726-a024-9cccf105d420/master.m3u8
    Platform android: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/d42e800c-4a1b-4361-ae33-5ecc4c295f3a/master.m3u8
    Platform foxtel: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/b21b691d-dc83-4378-8519-3fbb215dc484/master.m3u8
    Platform samsung: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/ac42bae1-3e09-4df0-8252-aedddc030f91/master.m3u8
    Platform lg: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/c509a4dc-e20e-4278-b3ab-6dd19cf5f38a/master.m3u8
    Platform tizen: SUCCESS - Manifest URL: https://pubads.g.doubleclick.net/ondemand/hls/content/2489270/vid/7716070000007760/SIN/streams/8a09f901-efb3-4620-939c-6ac0adfaf7aa/master.m3u8
    Be interesting to see what the yt-dlp guys come up with, but I doubt it's going to be anything that I haven't already figured out now.

    I'll push out a new release of Ozivine tomorrow. Had enough of this service for today. Time to watch the footy
    Quote Quote  
  27. I messed around with 10play a little before when people were asking about it, and found that you can get 720p using an android endpoint and modifying the URL:

    For the video id "7716070000007760":
    Code:
    # URL: https://10play-vod.global.ssl.fastly.net/OTFP/8acd909aa87c488f4ccb981cfa81ef3577e09c3a497f6d5760bd2a64b1c579f1/LVOD-V1042930-78517E1806253-1725277498000-,300,150,75,55,0000.mp4.m3u8?token=1725708664_7d21051ed5915f1aa456f461f6bea09c0ed42e2af82b87416342916dea00a3bf
    
    ID   EXT RESOLUTION FPS │   FILESIZE   TBR PROTO │ VCODEC      ACODEC
    ────────────────────────────────────────────────────────────────────────
    1062 mp4 640x360     25 │ ~337.13MiB 1063k m3u8  │ avc1.64001e mp4a.40.2
    1817 mp4 960x540     25 │ ~576.58MiB 1818k m3u8  │ avc1.64001f mp4a.40.2
    3371 mp4 1280x720    25 │ ~  1.04GiB 3371k m3u8  │ avc1.64001f mp4a.40.2
    I never made an automatic service script for it, but here's a simple writeup you can use as base and implement it to your service:

    Code:
    from requests import Session
    
    CONFIG = "https://vod.ten.com.au/config/androidapps-v2"
    VIDEO_ID = "7716070000007760"
    
    
    def get_manifest(video_id: str):
        config = session.get(CONFIG).json()
        url = config["endpoints"]["videos"]["server"] + config["endpoints"]["videos"]["methods"]["getVideobyIDs"]
        url = url.replace("[ids]", video_id).replace("[state]", "AU") # add video id and state (geolocation)
        content = session.get(url).json()
        items = content.get("items")[0]
    
        hls_url = session.head(items.get("HLSURL"), allow_redirects=True).url  # redirects
        real_url = hls_url.replace(",150,", ",300,150,") # add higher bitrate
    
        return real_url
    
    
    if __name__ == "__main__":
        session = Session()
        session.headers.update({"User-Agent": "Mobile Safari/537.36 10play/6.2.2 UAP"})
    
        manifest = get_manifest(VIDEO_ID)
        print(manifest)
    Quote Quote  
  28. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by stabbedbybrick View Post
    I messed around with 10play a little before when people were asking about it, and found that you can get 720p using an android endpoint and modifying the URL:

    For the video id "7716070000007760":
    Code:
    # URL: https://10play-vod.global.ssl.fastly.net/OTFP/8acd909aa87c488f4ccb981cfa81ef3577e09c3a497f6d5760bd2a64b1c579f1/LVOD-V1042930-78517E1806253-1725277498000-,300,150,75,55,0000.mp4.m3u8?token=1725708664_7d21051ed5915f1aa456f461f6bea09c0ed42e2af82b87416342916dea00a3bf
    
    ID   EXT RESOLUTION FPS │   FILESIZE   TBR PROTO │ VCODEC      ACODEC
    ────────────────────────────────────────────────────────────────────────
    1062 mp4 640x360     25 │ ~337.13MiB 1063k m3u8  │ avc1.64001e mp4a.40.2
    1817 mp4 960x540     25 │ ~576.58MiB 1818k m3u8  │ avc1.64001f mp4a.40.2
    3371 mp4 1280x720    25 │ ~  1.04GiB 3371k m3u8  │ avc1.64001f mp4a.40.2
    I never made an automatic service script for it, but here's a simple writeup you can use as base and implement it to your service:

    Code:
    from requests import Session
    
    CONFIG = "https://vod.ten.com.au/config/androidapps-v2"
    VIDEO_ID = "7716070000007760"
    
    
    def get_manifest(video_id: str):
        config = session.get(CONFIG).json()
        url = config["endpoints"]["videos"]["server"] + config["endpoints"]["videos"]["methods"]["getVideobyIDs"]
        url = url.replace("[ids]", video_id).replace("[state]", "AU") # add video id and state (geolocation)
        content = session.get(url).json()
        items = content.get("items")[0]
    
        hls_url = session.head(items.get("HLSURL"), allow_redirects=True).url  # redirects
        real_url = hls_url.replace(",150,", ",300,150,") # add higher bitrate
    
        return real_url
    
    
    if __name__ == "__main__":
        session = Session()
        session.headers.update({"User-Agent": "Mobile Safari/537.36 10play/6.2.2 UAP"})
    
        manifest = get_manifest(VIDEO_ID)
        print(manifest)
    Thanks stabby. That's brilliant. Guess I've still got a bit to learn

    How did you go about finding that android config to be able to find the endpoint ? Without that piece of the puzzle I ended up with a bit of a convoluted solution (albeit one that still works).
    Last edited by billybanana; 7th Sep 2024 at 05:20.
    Quote Quote  
  29. Originally Posted by billybanana View Post

    Thanks stabby. That's brilliant. Guess I've still got a bit to learn

    How did you go about finding that android config to be able to find the endpoint ? Without that piece of the puzzle I ended up with a bit of a convoluted solution (albeit one that still works).
    I honestly can't remember, but I'm guessing I found the config by either decompiling the .apk or by trolling through github projects. I was never motivated enough to actually capture the app traffic. It's not necessary to do any of that though, since the config URL is static. Just load it and base your script on the endpoints found in there.
    Quote Quote  
  30. Member
    Join Date
    Oct 2023
    Location
    Afghanistan
    Search PM
    Originally Posted by stabbedbybrick View Post
    Just load it and base your script on the endpoints found in there.
    Thanks mate @stabbedbybrick. That worked a treat. Saved me 50 odd lines of code in my solution.

    Note to anyone else following this thread, I will post an updated release to GitHub tomorrow.
    Quote Quote  



Similar Threads

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