# License: GNU AGPL v3: http://www.gnu.org/licenses/ # This file is part of `delarte` (https://git.afpy.org/fcode/delarte.git) """delarte - ArteTV downloader.""" __version__ = "0.1" from .error import * from .model import * def fetch_program_sources(url, http): """Fetch program sources listed on given ArteTV page.""" from .www import iter_programs return [ ProgramSource( program, player_config_url, ) for program, player_config_url in iter_programs(url, http) ] def fetch_rendition_sources(program_sources, http): """Fetch renditions for given programs.""" from itertools import groupby from .api import iter_renditions sources = [ RenditionSource( program, rendition, protocol, program_index_url, ) for program, player_config_url in program_sources for rendition, protocol, program_index_url in iter_renditions( program.id, player_config_url, http, ) ] descriptors = list({(s.rendition.code, s.rendition.label) for s in sources}) descriptors.sort() for code, group in groupby(descriptors, key=lambda t: t[0]): labels_for_code = [t[1] for t in group] if len(labels_for_code) != 1: raise UnexpectedError("MULTIPLE_RENDITION_LABELS", code, labels_for_code) return sources def fetch_variant_sources(renditions_sources, http): """Fetch variants for given renditions.""" from itertools import groupby from .hls import iter_variants sources = [ VariantSource( program, rendition, variant, VariantSource.VideoMedia(*video), VariantSource.AudioMedia(*audio), VariantSource.SubtitlesMedia(*subtitles) if subtitles else None, ) for program, rendition, protocol, program_index_url in renditions_sources for variant, video, audio, subtitles in iter_variants( protocol, program_index_url, http ) ] descriptors = list( {(s.variant.code, s.video_media.track.frame_rate) for s in sources} ) descriptors.sort() for code, group in groupby(descriptors, key=lambda t: t[0]): frame_rates_for_code = [t[1] for t in group] if len(frame_rates_for_code) != 1: raise UnexpectedError( "MULTIPLE_RENDITION_FRAME_RATES", code, frame_rates_for_code ) return sources def fetch_targets(variant_sources, http, **naming_options): """Compile download targets for given variants.""" from .hls import fetch_mp4_media, fetch_vtt_media from .naming import file_name_builder build_file_name = file_name_builder(**naming_options) targets = [ Target( Target.VideoInput( video_media.track, fetch_mp4_media(video_media.track_index_url, http), ), Target.AudioInput( audio_media.track, fetch_mp4_media(audio_media.track_index_url, http), ), ( Target.SubtitlesInput( subtitles_media.track, fetch_vtt_media(subtitles_media.track_index_url, http), ) if subtitles_media else None ), (program.title, program.subtitle) if program.subtitle else program.title, build_file_name(program, rendition, variant), ) for program, rendition, variant, video_media, audio_media, subtitles_media in variant_sources ] return targets def download_targets(targets, http, on_progress): """Download given target.""" import os from .download import download_mp4_media, download_vtt_media from .muxing import mux_target for target in targets: output_path = f"{target.output}.mkv" if os.path.isfile(output_path): print(f"Skipping {output_path!r}") continue video_path = target.output + ".video.mp4" audio_path = target.output + ".audio.mp4" subtitles_path = target.output + ".srt" download_mp4_media(target.video_input.url, video_path, http, on_progress) download_mp4_media(target.audio_input.url, audio_path, http, on_progress) if target.subtitles_input: download_vtt_media( target.subtitles_input.url, subtitles_path, http, on_progress ) mux_target( target._replace( video_input=target.video_input._replace(url=video_path), audio_input=target.audio_input._replace(url=audio_path), subtitles_input=( target.subtitles_input._replace(url=subtitles_path) if target.subtitles_input else None ), ), on_progress, ) if os.path.isfile(subtitles_path): os.unlink(subtitles_path) if os.path.isfile(audio_path): os.unlink(audio_path) if os.path.isfile(video_path): os.unlink(video_path)