Last active
May 28, 2025 04:34
-
-
Save Gottfr1ed/835465601f0dbcd5d4611bd151ba903f to your computer and use it in GitHub Desktop.
RUTUBE video/playlist downloader
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/usr/bin/python3 | |
| import argparse | |
| import subprocess | |
| import urllib.request | |
| import urllib.error | |
| import json | |
| import re | |
| import os | |
| import shutil | |
| API_URL = "https://rutube.ru/api" | |
| REQUEST_HEADERS = { | |
| "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:131.0) Gecko/20100101 Firefox/131.0" | |
| } | |
| def url_open(url): | |
| req = urllib.request.Request(url, headers=REQUEST_HEADERS) | |
| with urllib.request.urlopen(req) as res: | |
| return res.read() | |
| def url_open_utf8(url): | |
| return url_open(url).decode("utf-8") | |
| def url_open_json(url): | |
| return json.loads(url_open(url)) | |
| def download_video(video_id, dest_dir): | |
| video_info_url = f"{API_URL}/play/options/{video_id}/" | |
| video_info = url_open_json(video_info_url) | |
| video_title = video_info["title"] | |
| ts_path = f"{dest_dir}/{video_title}.ts" | |
| mp4_path = f"{dest_dir}/{video_title}.mp4" | |
| video_list_url = video_info["video_balancer"]["m3u8"] | |
| video_list = url_open_utf8(video_list_url) | |
| video_urls = re.findall(r"https:\S+", video_list) | |
| video_url_highest_quality = video_urls[-1] | |
| seg_base_url = video_url_highest_quality.split(".m3u8")[0] | |
| seg_list = url_open_utf8(video_url_highest_quality) | |
| seg_names = re.findall(r"segment-\S+", seg_list) | |
| if not os.path.isdir(dest_dir): | |
| os.makedirs(dest_dir) | |
| with open(ts_path, "wb") as ts: | |
| print(f'Downloading "{video_title}" ...') | |
| for seg_idx, seg_name in enumerate(seg_names): | |
| print(f"{seg_name} [{seg_idx}/{len(seg_names)}]") | |
| seg_url = f"{seg_base_url}/{seg_name}" | |
| seg_data = url_open(seg_url) | |
| ts.write(seg_data) | |
| print(f'Converting "{ts_path}" to "{mp4_path}" with FFmpeg ...') | |
| subprocess.run(["ffmpeg", "-i", ts_path, mp4_path]) | |
| os.remove(ts_path) | |
| if shutil.which("ffmpeg") is None: | |
| print(f"FFmpeg is required to run this script. Please install it and try again.") | |
| exit(1) | |
| arg_parser = argparse.ArgumentParser(prog=os.path.basename(__file__)) | |
| arg_parser.add_argument("url", nargs="+") | |
| arg_parser.add_argument("-d", "--destination", help="destination directory") | |
| args = arg_parser.parse_args() | |
| dest_dir = args.destination if args.destination else "rutube-videos" | |
| for url in args.url: | |
| video_pattern = r"^\s*(https:\/\/rutube\.ru)\/(video)\/(\w+)\/?\s*$" | |
| video_match = re.fullmatch(video_pattern, url) | |
| if video_match: | |
| video_id = video_match.group(3) | |
| download_video(video_id, dest_dir) | |
| else: | |
| playlist_pattern = r"^\s*(https:\/\/rutube\.ru)\/(plst)\/(\d+)\/?\s*$" | |
| playlist_match = re.fullmatch(playlist_pattern, url) | |
| if playlist_match: | |
| playlist_id = playlist_match.group(3) | |
| playlist_info_url = f"{API_URL}/playlist/custom/{playlist_id}" | |
| playlist_info = url_open_json(playlist_info_url) | |
| playlist_title = playlist_info["title"] | |
| playlist_dest_dir = f"{dest_dir}/{playlist_title}" | |
| video_infos = url_open_json(playlist_info_url + "/videos/")["results"] | |
| for video_info in video_infos: | |
| video_id = video_info["playlist_id"] | |
| download_video(video_id, playlist_dest_dir) | |
| else: | |
| print(f'"{url}" is not a valid RUTUBE video/playlist URL, skipping...') |
Author
The script works well. But it won't start as shown. To run, change the following lines:
91 video_infos = url_open_json(plst_info_url + "/videos/")["results"] ---> video_infos = url_open_json(playlist_info_url + "/videos/")["results"]
93 video_id = video_info["plst_id"] ---> video_id = video_info["id"]
94 download_video(video_id, plst_dest_dir) ---> download_video(video_id, playlist_dest_dir)
P.S - For Windows machines include ffmpeg/bin folder in Path.
Author
@squituit Thank you. I decided to change the names of some variables and forgot to test the script :) Everything should be fine now.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FFmpeg is required to run this script.
Usage example:
python3 downloader.py -d ~/rutube_videos https://rutube.ru/video/1q2w3e4r5t6y/ https://rutube.ru/plst/123456/