Skip to content

Instantly share code, notes, and snippets.

@alexeygrigorev
Created September 17, 2016 09:09
Show Gist options
  • Save alexeygrigorev/a1bc540925054b71e1a7268e50ad55cd to your computer and use it in GitHub Desktop.
Save alexeygrigorev/a1bc540925054b71e1a7268e50ad55cd to your computer and use it in GitHub Desktop.
Downloading segmented video from vimeo
import requests
import base64
from tqdm import tqdm
master_json_url = 'https://178skyfiregce-a.akamaihd.net/exp=1474107106~acl=%2F142089577%2F%2A~hmac=0d9becc441fc5385462d53bf59cf019c0184690862f49b414e9a2f1c5bafbe0d/142089577/video/426274424,426274425,426274423,426274422/master.json?base64_init=1'
base_url = master_json_url[:master_json_url.rfind('/', 0, -26) + 1]
resp = requests.get(master_json_url)
content = resp.json()
heights = [(i, d['height']) for (i, d) in enumerate(content['video'])]
idx, _ = max(heights, key=lambda (_, h): h)
video = content['video'][idx]
video_base_url = base_url + video['base_url']
print 'base url:', video_base_url
filename = 'video_%d.mp4' % video['id']
print 'saving to %s' % filename
video_file = open(filename, 'wb')
init_segment = base64.b64decode(video['init_segment'])
video_file.write(init_segment)
for segment in tqdm(video['segments']):
segment_url = video_base_url + segment['url']
resp = requests.get(segment_url, stream=True)
if resp.status_code != 200:
print 'not 200!'
print resp
print segment_url
break
for chunk in resp:
video_file.write(chunk)
video_file.flush()
video_file.close()
@Javi3rV
Copy link

Javi3rV commented Nov 12, 2024

so I skidded modifications from comments and added a bit of multi threading. It downloads video and audio, accepts playlist.json and master.json (mainly for playlist.json).

import os
import sys
import base64
import requests
import subprocess
from concurrent.futures import ThreadPoolExecutor

from tqdm import tqdm
from moviepy.editor import *
import ffmpeg


url = input('enter [master|playlist].json url: ')
name = input('enter output name: ')

if 'master.json' in url:
    url = url[:url.find('?')] + '?query_string_ranges=1'
    url = url.replace('master.json', 'master.mpd')
    print(url)
    subprocess.run(['youtube-dl', url, '-o', name])
    sys.exit(0)


def download_segment(segment_url, segment_path):
    resp = requests.get(segment_url, stream=True)
    if resp.status_code != 200:
        print('not 200!')
        print(segment_url)
        return
    with open(segment_path, 'wb') as segment_file:
        for chunk in resp:
            segment_file.write(chunk)

def download(what, to, base):
    print('saving', what['mime_type'], 'to', to)
    init_segment = base64.b64decode(what['init_segment'])
    
    segment_urls = [base + segment['url'] for segment in what['segments']]
    segment_paths = [f"segment_{i}.tmp" for i in range(len(segment_urls))]

    with ThreadPoolExecutor(max_workers=15) as executor:
        list(tqdm(executor.map(download_segment, segment_urls, segment_paths), total=len(segment_urls)))

    with open(to, 'wb') as file:
        file.write(init_segment)
        for segment_path in segment_paths:
            with open(segment_path, 'rb') as segment_file:
                file.write(segment_file.read())
            os.remove(segment_path)
    
    print('done')


name += '.mp4'
base_url = url[:url.rfind('/', 0, -26) + 1]
content = requests.get(url).json()

vid_heights = [(i, d['height']) for (i, d) in enumerate(content['video'])]
vid_idx, _ = max(vid_heights, key=lambda _h: _h[1])

audio_quality = [(i, d['bitrate']) for (i, d) in enumerate(content['audio'])]
audio_idx, _ = max(audio_quality, key=lambda _h: _h[1])

video = content['video'][vid_idx]
audio = content['audio'][audio_idx]
base_url = base_url + content['base_url']

video_tmp_file = 'video.mp4'
audio_tmp_file = 'audio.mp4'

download(video, video_tmp_file, base_url + video['base_url'])
download(audio, audio_tmp_file, base_url + audio['base_url'])

def combine_video_audio(video_file, audio_file, output_file):
    try:
        video_stream = ffmpeg.input(video_file)
        audio_stream = ffmpeg.input(audio_file)
        
        ffmpeg.output(video_stream, audio_stream, output_file, vcodec='copy', acodec='copy').run(overwrite_output=True)
        
        print(f"Archivo combinado guardado como {output_file}")
    except ffmpeg.Error as e:
        print(f"Error al combinar archivos: {e.stderr.decode()}")

combine_video_audio('video.mp4', 'audio.mp4', name)

os.remove(video_tmp_file)
os.remove(audio_tmp_file)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment