def merge(self): if self.detect is None: log.error( "Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output log.info("Merge audio and video into %s", orig_filename) tempfile = "{0}.temp".format(self.stream.options.output) audio_filename = "{0}.m4a".format( os.path.splitext(self.stream.options.output)[0]) arguments = [ "-c:v", "copy", "-c:a", "copy", "-f", "mp4", "-y", tempfile ] cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Merging done, removing old files.") os.remove(self.stream.options.output) os.remove(audio_filename) os.rename(tempfile, self.stream.options.output)
def remux(self): if self.detect is None: log.error( "Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return if self.stream.options.output.endswith('.mp4') is False: orig_filename = self.stream.options.output new_name = "{0}.mp4".format( os.path.splitext(self.stream.options.output)[0]) log.info("Muxing %s into %s", orig_filename, new_name) tempfile = "{0}.temp".format(self.stream.options.output) name, ext = os.path.splitext(orig_filename) arguments = ["-c", "copy", "-copyts", "-f", "mp4"] if ext == ".ts": arguments += ["-bsf:a", "aac_adtstoasc"] arguments += ["-y", tempfile] cmd = [self.detect, "-i", orig_filename] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Muxing done, removing the old file.") os.remove(self.stream.options.output) os.rename(tempfile, new_name)
def output(options, filename, extention="mp4", openfd=True): if is_py3: file_d = io.IOBase else: file_d = file if options.output != "-": ext = re.search(r"(\.[a-z0-9]+)$", filename) if not ext: options.output = "%s.%s" % (options.output, extention) log.info("Outfile: %s", options.output) if (os.path.isfile(options.output) or \ findexpisode(os.path.dirname(os.path.realpath(options.output)), options.service, os.path.basename(options.output))) and \ not options.force: log.error("File already exists. Use --force to overwrite") return None if openfd: file_d = open(options.output, "wb") else: if openfd: if is_py3: file_d = sys.stdout.buffer else: file_d = sys.stdout return file_d
def get_all_episodes(stream, url): name = os.path.dirname(formatname(dict(), stream.config)) if name and os.path.isfile(name): log.error("Output must be a directory if used with --all-episodes") sys.exit(2) elif name and not os.path.exists(name): try: os.makedirs(name) except OSError as e: log.error("%s: %s", e.strerror, e.filename) return episodes = stream.find_all_episodes(stream.config) if episodes is None: return for idx, o in enumerate(episodes): if o == url: substream = stream else: substream = service_handler(sites, copy.copy(stream.config), o) log.info("Episode %d of %d", idx + 1, len(episodes)) log.info("Url: %s", o) # get_one_media overwrites options.output... get_one_media(substream)
def get_all_episodes(stream, options, url): if options.output and os.path.isfile(options.output): log.error("Output must be a directory if used with --all-episodes") sys.exit(2) elif options.output and not os.path.exists(options.output): try: os.makedirs(options.output) except OSError as e: log.error("%s: %s", e.strerror, e.filename) return episodes = stream.find_all_episodes(options) if episodes is None: return for idx, o in enumerate(episodes): if o == url: substream = stream else: substream = service_handler(sites, copy.copy(options), o) log.info("Episode %d of %d", idx + 1, len(episodes)) log.info("Url: %s",o) # get_one_media overwrites options.output... get_one_media(substream, copy.copy(options))
def output(options, extension="mp4", openfd=True, mode="wb", **kwargs): subtitlefiles = ["srt", "smi", "tt","sami", "wrst"] ext = re.search(r"(\.\w{2,4})$", options.output) if not ext: options.output = "%s.%s" % (options.output, extension) if options.output_auto and ext: options.output = "%s.%s" % (options.output, extension) elif extension == "srt" and ext: options.output = "%s.srt" % options.output[:options.output.rfind(ext.group(1))] if ext and extension == "srt" and ext.group(1).split(".")[-1] in subtitlefiles: options.output = "%s.srt" % options.output[:options.output.rfind(ext.group(1))] log.info("Outfile: %s", options.output) if os.path.isfile(options.output) or \ findexpisode(os.path.dirname(os.path.realpath(options.output)), options.service, os.path.basename(options.output)): if extension in subtitlefiles: if not options.force_subtitle: log.error("File (%s) already exists. Use --force-subtitle to overwrite" % options.output) return None else: if not options.force: log.error("File (%s) already exists. Use --force to overwrite" % options.output) return None if openfd: file_d = open(options.output, mode, **kwargs) return file_d return True
def merge(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output log.info("Merge audio and video into %s", orig_filename) tempfile = "{0}.temp".format(self.stream.options.output) audio_filename = "{0}.m4a".format(os.path.splitext(self.stream.options.output)[0]) arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "mp4", "-y", tempfile] cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Merging done, removing old files.") os.remove(self.stream.options.output) os.remove(audio_filename) os.rename(tempfile, self.stream.options.output)
def output(options, extension="mp4", openfd=True, mode="wb", **kwargs): subtitlefiles = ["srt", "smi", "tt", "sami", "wrst"] ext = re.search(r"(\.\w{2,4})$", options.output) if not ext: options.output = "%s.%s" % (options.output, extension) if options.output_auto and ext: options.output = "%s.%s" % (options.output, extension) elif extension == "srt" and ext: options.output = "%s.srt" % options.output[:options.output.rfind(ext.group(1))] if ext and extension == "srt" and ext.group(1).split(".")[-1] in subtitlefiles: options.output = "%s.srt" % options.output[:options.output.rfind(ext.group(1))] log.info("Outfile: %s", options.output) if os.path.isfile(options.output) or \ findexpisode(os.path.dirname(os.path.realpath(options.output)), options.service, os.path.basename(options.output)): if extension in subtitlefiles: if not options.force_subtitle: log.error("File (%s) already exists. Use --force-subtitle to overwrite" % options.output) return None else: if not options.force: log.error("File (%s) already exists. Use --force to overwrite" % options.output) return None if openfd: file_d = open(options.output, mode, **kwargs) return file_d return True
def remux(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return if self.stream.options.output.endswith('.mp4') is False: orig_filename = self.stream.options.output new_name = "{0}.mp4".format(os.path.splitext(self.stream.options.output)[0]) log.info("Muxing %s into %s", orig_filename, new_name) tempfile = "{0}.temp".format(self.stream.options.output) name, ext = os.path.splitext(orig_filename) arguments = ["-c", "copy", "-copyts", "-f", "mp4"] if ext == ".ts": arguments += ["-bsf:a", "aac_adtstoasc"] arguments += ["-y", tempfile] cmd = [self.detect, "-i", orig_filename] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Muxing done, removing the old file.") os.remove(self.stream.options.output) os.rename(tempfile, new_name)
def get_media(url, options): stream = service_handler(url) if not stream: url, stream = Generic().get(url) if not stream: log.error("That site is not supported. Make a ticket or send a message") sys.exit(2) if options.all_episodes: if options.output and os.path.isfile(options.output): log.error("Output must be a directory if used with --all-episodes") sys.exit(2) elif options.output and not os.path.exists(options.output): try: os.makedirs(options.output) except OSError as e: log.error("%s: %s" % (e.strerror, e.filename)) return episodes = stream.find_all_episodes(options) for idx, o in enumerate(episodes): if o == url: substream = stream else: substream = service_handler(o) log.info("Episode %d of %d", idx + 1, len(episodes)) # get_one_media overwrites options.output... get_one_media(substream, copy.copy(options)) else: get_one_media(stream, options)
def download_rtmp(options, url): """ Get the stream from RTMP """ args = [] if options.live: args.append("-v") if options.resume: args.append("-e") extension = re.search("(\.[a-z0-9]+)$", url) if options.output != "-": if not extension: extension = re.search("-y (.+):[-_a-z0-9\/]", options.other) if not extension: options.output = "%s.flv" % options.output else: options.output = "%s.%s" % (options.output, extension.group(1)) else: options.output = options.output + extension.group(1) log.info("Outfile: %s", options.output) args += ["-o", options.output] if options.silent or options.output == "-": args.append("-q") if options.other: if sys.version_info < (3, 0): args += shlex.split(options.other.encode("utf-8")) else: args += shlex.split(options.other) command = ["rtmpdump", "-r", url] + args try: subprocess.call(command) except OSError as e: log.error("Could not execute rtmpdump: " + e.strerror)
def output(options, extention="mp4", openfd=True, mode="wb", **kwargs): if is_py2: file_d = file else: file_d = io.IOBase if options.output != "-": ext = re.search(r"(\.\w{2,3})$", options.output) if not ext: options.output = "%s.%s" % (options.output, extention) if options.output_auto and ext: options.output = "%s.%s" % (options.output, extention) if extention == "srt" and ext: options.output = "%s.srt" % options.output[:options.output.rfind(ext.group(1))] log.info("Outfile: %s", options.output) if os.path.isfile(options.output) or \ findexpisode(os.path.dirname(os.path.realpath(options.output)), options.service, os.path.basename(options.output)): if extention == "srt": if not options.force_subtitle: log.error("File (%s) already exists. Use --force-subtitle to overwrite" % options.output) return None else: if not options.force: log.error("File (%s) already exists. Use --force to overwrite" % options.output) return None if openfd: file_d = open(options.output, mode, **kwargs) else: if openfd: if is_py2: file_d = sys.stdout else: file_d = sys.stdout.buffer return file_d
def get_one_media(stream, options): if not options.output or os.path.isdir(options.output): data = stream.get_urldata() match = re.search(r"(?i)<title[^>]*>\s*(.*?)\s*</title>", data, re.S) if match: options.output_auto = True title_tag = decode_html_entities(match.group(1)) if not options.output: options.output = filenamify(title_tag) else: # output is a directory options.output = os.path.join(options.output, filenamify(title_tag)) if platform.system() == "Windows": # ugly hack. replace \ with / or add extra \ because c:\test\kalle.flv will add c:_tab_est\kalle.flv if options.output.find("\\") > 0: options.output = options.output.replace("\\", "/") videos = [] subs = [] streams = stream.get(options) for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if options.subtitle and options.output != "-": if subs: subs[0].download(copy.copy(options)) if options.force_subtitle: return if len(videos) == 0: log.error("Can't find any streams for that url") else: stream = select_quality(options, videos) log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) try: stream.download() except UIException as e: if options.verbose: raise e log.error(e.message) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout")
def download(self): if self.options.live and not self.options.force: raise LiveHLSException(self.url) m3u8 = get_http_data(self.url) globaldata, files = parsem3u(m3u8) encrypted = False key = None try: keydata = globaldata["KEY"] encrypted = True except KeyError: pass if encrypted: try: from Crypto.Cipher import AES except ImportError: log.error("You need to install pycrypto to download encrypted HLS streams") sys.exit(2) match = re.search(r'URI="(https?://.*?)"', keydata) key = get_http_data(match.group(1)) rand = os.urandom(16) decryptor = AES.new(key, AES.MODE_CBC, rand) if self.options.output != "-": extension = re.search(r"(\.[a-z0-9]+)$", self.options.output) if not extension: self.options.output = "%s.ts" % self.options.output log.info("Outfile: %s", self.options.output) if os.path.isfile(self.options.output) and not self.options.force: log.info("File already exists. use --force to overwrite") return file_d = open(self.options.output, "wb") else: file_d = sys.stdout n = 0 eta = ETA(len(files)) for i in files: item = _get_full_url(i[0], self.url) if self.options.output != "-": eta.increment() progressbar(len(files), n, ''.join(['ETA: ', str(eta)])) n += 1 data = get_http_data(item) if encrypted: data = decryptor.decrypt(data) file_d.write(data) if self.options.output != "-": file_d.close() progress_stream.write('\n')
def save(options, data): filename = re.search(r"(.*)\.[a-z0-9]{2,3}$", options.output) if filename: options.output = "%s.srt" % filename.group(1) else: options.output = "%s.srt" % options.output log.info("Subtitle: %s", options.output) fd = open(options.output, "w") fd.write(data) fd.close()
def get_one_media(stream, options): # Make an automagic filename if not filename(options, stream): return videos = [] subs = [] streams = stream.get(options) for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred.lower() == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if options.subtitle and options.output != "-": if subs: subs[0].download() if options.force_subtitle: return if len(videos) == 0: log.error("Can't find any streams for that url") else: if options.list_quality: list_quality(videos) return stream = select_quality(options, videos) log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) if options.get_url: print(stream.url) return try: stream.download() except UIException as e: if options.verbose: raise e log.error(e.message) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout")
def save(options, data): filename = re.search(r"(.*)\.[a-z0-9]{2,3}$", options.output) if filename: options.output = "%s.srt" % filename.group(1) else: options.output = "%s.srt" % options.output log.info("Subtitle: %s", options.output) if os.path.isfile(options.output) and not options.force: log.info("File already exists. use --force to overwrite") return fd = open(options.output, "w") fd.write(data) fd.close()
def sublanguage(self): # parse() function partly borrowed from a guy on github. /thanks! # https://github.com/riobard/srt.py/blob/master/srt.py def parse(self): def parse_block(block): lines = block.strip('-').split('\n') txt = '\r\n'.join(lines[2:]) return txt return list(map(parse_block, open(self).read().strip().replace('\r', '').split('\n\n'))) def query(self): random_sentences = ' '.join(sample(parse(self),8)).replace('\r\n', '') url = 'https://whatlanguage.herokuapp.com' payload = { "query": random_sentences } headers = {'content-type': 'application/json'} # Note: requests handles json from version 2.4.2 and onwards so i use json.dumps for now. try: r = post(url, data=dumps(payload), headers=headers, timeout=30) # Note: reasonable timeout i guess? svtplay-dl is mainly used while multitasking i presume, and it is heroku after all (fast enough) if r.status_code == codes.ok: try: response = r.json() return response['language'] except TypeError: return 'und' else: log.error("Server error appeared. Setting language as undetermined.") return 'und' except Timeout: log.error("30 seconds server timeout reached. Setting language as undetermined.") return 'und' langs = [] exceptions = { 'lulesamiska': 'smj', 'meankieli': 'fit', 'jiddisch': 'yid' } if len(self.subfixes) >= 2: log.info("Determining the languages of the subtitles.") else: log.info("Determining the language of the subtitle.") if self.get_all_subtitles: from re import match for subfix in self.subfixes: if [exceptions[key] for key in exceptions.keys() if match(key, subfix.strip('-'))]: if 'oversattning' in subfix.strip('-'): subfix = subfix.strip('-').split('.')[0] else: subfix = subfix.strip('-') langs += [exceptions[subfix]] continue subfile = "{}.srt".format(os.path.splitext(self.stream.options.output)[0] + subfix) langs += [query(subfile)] else: subfile = "{}.srt".format(os.path.splitext(self.stream.options.output)[0]) langs += [query(subfile)] if len(langs) >= 2: log.info("Language codes: " + ', '.join(langs)) else: log.info("Language code: " + langs[0]) return langs
def remux(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return if formatname(self.stream.output, self.config, self.stream.output_extention).endswith('.mp4') is False: orig_filename = formatname(self.stream.output, self.config, self.stream.output_extention) name, ext = os.path.splitext(orig_filename) new_name = u"{0}.mp4".format(name) cmd = [self.detect, "-i", orig_filename] _, stdout, stderr = run_program(cmd, False) # return 1 is good here. videotrack, audiotrack = self._checktracks(stderr) if self.config.get("merge_subtitle"): log.info(u"Muxing {0} and merging its subtitle into {1}".format(orig_filename, new_name)) else: log.info(u"Muxing {0} into {1}".format(orig_filename, new_name)) tempfile = u"{0}.temp".format(orig_filename) arguments = ["-map", "0:{}".format(videotrack), "-map", "0:{}".format(audiotrack), "-c", "copy", "-f", "mp4"] if ext == ".ts": arguments += ["-bsf:a", "aac_adtstoasc"] if self.config.get("merge_subtitle"): langs = self.sublanguage() for stream_num, language in enumerate(langs): arguments += ["-map", str(stream_num + 1), "-c:s:" + str(stream_num), "mov_text", "-metadata:s:s:" + str(stream_num), "language=" + language] if self.subfixes and len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{0}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments returncode, stdout, stderr = run_program(cmd) if returncode != 0: return if self.config.get("merge_subtitle") and not self.config.get("subtitle"): log.info("Muxing done, removing the old files.") if self.subfixes and len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) else: log.info("Muxing done, removing the old file.") os.remove(orig_filename) os.rename(tempfile, new_name)
def download(self): """ Get the stream from HTTP """ request = Request(self.url) request.add_header('User-Agent', 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-GB; rv:1.9.0.3) Gecko/2008092417 Firefox/3.0.3') try: response = urlopen(request) except HTTPError as e: log.error("Something wrong with that url") log.error("Error code: %s", e.code) sys.exit(5) try: total_size = response.info()['Content-Length'] except KeyError: total_size = 0 total_size = int(total_size) bytes_so_far = 0 if self.options.output != "-": extension = re.search(r"(\.[a-z0-9]+)$", self.url) if extension: self.options.output = self.options.output + extension.group(1) else: self.options.output = "%s.mp4" % self.options.output log.info("Outfile: %s", self.options.output) if os.path.isfile(self.options.output) and not self.options.force: log.info("File already exists. use --force to overwrite") return file_d = open(self.options.output, "wb") else: file_d = sys.stdout lastprogress = 0 while 1: chunk = response.read(8192) bytes_so_far += len(chunk) if not chunk: break file_d.write(chunk) if self.options.output != "-": now = time.time() if lastprogress + 1 < now: lastprogress = now progress(bytes_so_far, total_size) if self.options.output != "-": file_d.close()
def remux(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return if self.stream.options.output.endswith('.mp4') is False: orig_filename = self.stream.options.output name, ext = os.path.splitext(orig_filename) new_name = u"{0}.mp4".format(name) if self.merge_subtitle: log.info(u"Muxing %s and merging its subtitle into %s", orig_filename, new_name) else: log.info(u"Muxing %s into %s".format(orig_filename, new_name)) tempfile = u"{0}.temp".format(orig_filename) arguments = ["-map", "0:v", "-map", "0:a", "-c", "copy", "-copyts", "-f", "mp4"] if ext == ".ts": arguments += ["-bsf:a", "aac_adtstoasc"] cmd = [self.detect, "-i", orig_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs): arguments += ["-map", str(stream_num + 1), "-c:s:" + str(stream_num), "mov_text", "-metadata:s:s:" + str(stream_num), "language=" + language] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{0}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return if self.merge_subtitle and not self.external_subtitle: log.info("Muxing done, removing the old files.") if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) else: log.info("Muxing done, removing the old file.") os.remove(orig_filename) os.rename(tempfile, new_name)
def find_all_episodes(self, options): match = re.search(r'<link rel="alternate" type="application/rss\+xml" [^>]*href="([^"]+)"', self.get_urldata()) if match is None: log.info("Couldn't retrieve episode list as rss, trying to scrape") return self.scrape_episodes(options) url = "http://urplay.se%s" % match.group(1).replace("&", "&") xml = ET.XML(self.http.request("get", url).content) episodes = [x.text for x in xml.findall(".//item/link")] episodes_new = [] n = 0 for i in episodes: if n == options.all_last: break if i not in episodes_new: episodes_new.append(i) n += 1 return episodes_new
def get_media(url, options): if "http" not in url[:4]: url = "http://%s" % url stream = service_handler(sites, options, url) if not stream: generic = Generic(options, url) url, stream = generic.get(sites) if not stream: if url.find(".f4m") > 0 or url.find(".m3u8") > 0: stream = Raw(options, url) if not stream: log.error("That site is not supported. Make a ticket or send a message") sys.exit(2) if options.all_episodes: if options.output and os.path.isfile(options.output): log.error("Output must be a directory if used with --all-episodes") sys.exit(2) elif options.output and not os.path.exists(options.output): try: os.makedirs(options.output) except OSError as e: log.error("%s: %s" % (e.strerror, e.filename)) return episodes = stream.find_all_episodes(options) if episodes is None: return for idx, o in enumerate(episodes): if o == url: substream = stream else: substream = service_handler(sites, options, o) log.info("Episode %d of %d", idx + 1, len(episodes)) # get_one_media overwrites options.output... get_one_media(substream, copy.copy(options)) else: get_one_media(stream, options)
def find_all_episodes(self, options): match = re.search( r'<link rel="alternate" type="application/rss\+xml" [^>]*href="([^"]+)"', self.get_urldata()) if match is None: log.info("Couldn't retrieve episode list as rss, trying to scrape") return self.scrape_episodes(options) url = "http://urplay.se%s" % match.group(1).replace("&", "&") xml = ET.XML(self.http.request("get", url).content) episodes = [x.text for x in xml.findall(".//item/link")] episodes_new = [] n = 0 for i in episodes: if n == options.all_last: break if i not in episodes_new: episodes_new.append(i) n += 1 return episodes_new
def output(options, extention="mp4", openfd=True, mode="wb", **kwargs): if is_py2: file_d = file else: file_d = io.IOBase if options.output != "-": ext = re.search(r"(\.\w{2,3})$", options.output) if not ext: options.output = "%s.%s" % (options.output, extention) if options.output_auto and ext: options.output = "%s.%s" % (options.output, extention) if extention == "srt" and ext: options.output = "%s.srt" % options.output[:options.output. rfind(ext.group(1))] log.info("Outfile: %s", options.output) if os.path.isfile(options.output) or \ findexpisode(os.path.dirname(os.path.realpath(options.output)), options.service, os.path.basename(options.output)): if extention == "srt": if not options.force_subtitle: log.error( "File (%s) already exists. Use --force-subtitle to overwrite" % options.output) return None else: if not options.force: log.error( "File (%s) already exists. Use --force to overwrite" % options.output) return None if openfd: file_d = open(options.output, mode, **kwargs) else: if openfd: if is_py2: file_d = sys.stdout else: file_d = sys.stdout.buffer return file_d
def merge(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output cmd = [self.detect, "-i", orig_filename] _, stdout, stderr = run_program(cmd, False) # return 1 is good here. videotrack, audiotrack = self._checktracks(stderr) if self.merge_subtitle: log.info("Merge audio, video and subtitle into {0}".format(orig_filename)) else: log.info("Merge audio and video into {0}".format(orig_filename)) tempfile = u"{0}.temp".format(orig_filename) name, ext = os.path.splitext(orig_filename) arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "mp4"] if ext == ".ts": audio_filename = u"{0}.audio.ts".format(name) arguments += ["-bsf:a", "aac_adtstoasc"] else: audio_filename = u"{0}.m4a".format(name) cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs, start=audiotrack + 1): arguments += ["-map", "{}".format(videotrack), "-map", "{}".format(audiotrack), "-map", str(stream_num), "-c:s:" + str(stream_num - 2), "mov_text", "-metadata:s:s:" + str(stream_num - 2), "language=" + language] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{0}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments returncode, stdout, stderr = run_program(cmd) if returncode != 1: return log.info("Merging done, removing old files.") os.remove(orig_filename) os.remove(audio_filename) if self.merge_subtitle and not self.external_subtitle: if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) os.rename(tempfile, orig_filename)
def download(self): """ Get the stream from RTMP """ args = [] if self.options.live: args.append("-v") if self.options.resume: args.append("-e") extension = re.search(r"(\.[a-z0-9]+)$", self.url) if self.options.output != "-": if not extension: self.options.output = "%s.flv" % self.options.output else: self.options.output = self.options.output + extension.group(1) log.info("Outfile: %s", self.options.output) if os.path.isfile(self.options.output) and not self.options.force: log.info("File already exists. use --force to overwrite") return args += ["-o", self.options.output] if self.options.silent or self.options.output == "-": args.append("-q") if self.options.other: if is_py2: args += shlex.split(self.options.other.encode("utf-8")) else: args += shlex.split(self.options.other) if self.options.verbose: args.append("-V") command = ["rtmpdump", "-r", self.url] + args log.debug("Running: %s", " ".join(command)) try: subprocess.call(command) except OSError as e: log.error("Could not execute rtmpdump: " + e.strerror)
def merge(self): if self.detect is None: log.error("Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output if self.merge_subtitle: log.info("Merge audio, video and subtitle into %s", orig_filename) else: log.info("Merge audio and video into %s", orig_filename) tempfile = u"{0}.temp".format(orig_filename) name = os.path.splitext(orig_filename)[0] audio_filename = u"{0}.m4a".format(name) arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "mp4"] cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs, start=2): arguments += ["-map", "0", "-map", "1", "-map", str(stream_num), "-c:s:" + str(stream_num - 2), "mov_text", "-metadata:s:s:" + str(stream_num - 2), "language=" + language] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{0}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Merging done, removing old files.") os.remove(orig_filename) os.remove(audio_filename) if self.merge_subtitle and not self.external_subtitle: if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) os.rename(tempfile, orig_filename)
def remux(self): if self.detect is None: log.error( "Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return if self.stream.options.output.endswith('.mp4') is False: orig_filename = self.stream.options.output name, ext = os.path.splitext(orig_filename) new_name = "{}.mp4".format(name) if self.merge_subtitle: log.info("Muxing %s and merging its subtitle into %s", orig_filename, new_name) else: log.info("Muxing %s into %s", orig_filename, new_name) tempfile = "{}.temp".format(orig_filename) arguments = [ "-map", "0:v", "-map", "0:a", "-c", "copy", "-copyts", "-f", "mp4" ] if ext == ".ts": arguments += ["-bsf:a", "aac_adtstoasc"] cmd = [self.detect, "-i", orig_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs): arguments += [ "-map", str(stream_num + 1), "-c:s:" + str(stream_num), "mov_text", "-metadata:s:s:" + str(stream_num), "language=" + language ] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return if self.merge_subtitle and not self.external_subtitle: log.info("Muxing done, removing the old files.") if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) else: log.info("Muxing done, removing the old file.") os.remove(orig_filename) os.rename(tempfile, new_name)
def sublanguage(self): # parse() function partly borrowed from a guy on github. /thanks! # https://github.com/riobard/srt.py/blob/master/srt.py def parse(self): def parse_block(block): lines = block.strip('-').split('\n') txt = '\r\n'.join(lines[2:]) return txt return map( parse_block, open(self).read().strip().replace('\r', '').split('\n\n')) def query(self): random_sentences = ' '.join(sample(parse(self), 8)).replace('\r\n', '') url = 'https://whatlanguage.herokuapp.com' payload = {"query": random_sentences} headers = { 'content-type': 'application/json' } # Note: requests handles json from version 2.4.2 and onwards so i use json.dumps for now. try: r = post( url, data=dumps(payload), headers=headers, timeout=30 ) # Note: reasonable timeout i guess? svtplay-dl is mainly used while multitasking i presume, and it is heroku after all (fast enough) if r.status_code == codes.ok: response = r.json() return response['language'] else: log.error( "Server error appeared. Setting language as undetermined." ) return 'und' except Timeout: log.error( "30 seconds server timeout reached. Setting language as undetermined." ) return 'und' langs = [] exceptions = { 'lulesamiska': 'smj', 'meankieli': 'fit', 'jiddisch': 'yid' } if len(self.subfixes) >= 2: log.info("Determining the languages of the subtitles.") else: log.info("Determining the language of the subtitle.") if self.get_all_subtitles: from re import match for subfix in self.subfixes: if [ exceptions[key] for key in exceptions.keys() if match(key, subfix.strip('-')) ]: if 'oversattning' in subfix.strip('-'): subfix = subfix.strip('-').split('.')[0] else: subfix = subfix.strip('-') langs += [exceptions[subfix]] continue subfile = "{}.srt".format( os.path.splitext(self.stream.options.output)[0] + subfix) langs += [query(subfile)] else: subfile = "{}.srt".format( os.path.splitext(self.stream.options.output)[0]) langs += [query(subfile)] if len(langs) >= 2: log.info("Language codes: " + ', '.join(langs)) else: log.info("Language code: " + langs[0]) return langs
def merge(self): if self.detect is None: log.error( "Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output if self.merge_subtitle: log.info("Merge audio, video and subtitle into %s", orig_filename) else: log.info("Merge audio and video into %s", orig_filename) tempfile = "{}.temp".format(orig_filename) name = os.path.splitext(orig_filename)[0] audio_filename = "{}.m4a".format(name) arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "mp4"] cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs, start=2): arguments += [ "-map", "0", "-map", "1", "-map", str(stream_num), "-c:s:" + str(stream_num - 2), "mov_text", "-metadata:s:s:" + str(stream_num - 2), "language=" + language ] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE, stdin=subprocess.PIPE) stdout, stderr = p.communicate() if p.returncode != 0: stderr = stderr.decode('utf-8', 'replace') msg = stderr.strip().split('\n')[-1] log.error("Something went wrong: %s", msg) return log.info("Merging done, removing old files.") os.remove(orig_filename) os.remove(audio_filename) if self.merge_subtitle and not self.external_subtitle: if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) os.rename(tempfile, orig_filename)
def get_one_media(stream): # Make an automagic filename if not filename(stream): return if stream.config.get("merge_subtitle"): if not which('ffmpeg'): log.error("--merge-subtitle needs ffmpeg. Please install ffmpeg.") log.info("https://ffmpeg.org/download.html") sys.exit(2) videos = [] subs = [] subfixes = [] error = [] streams = stream.get() try: for i in streams: if isinstance(i, Exception): error.append(i) elif not exclude(stream.config, formatname(i.output, stream.config)): if isinstance(i, VideoRetriever): if stream.config.get("preferred"): if stream.config.get("preferred").lower() == i.name: videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) except Exception as e: if stream.config.get("verbose"): raise else: logging.error("svtplay-dl crashed") logging.error( "Run again and add --verbose as an argument, to get more information" ) logging.error( "If the error persists, you can report it at https://github.com/spaam/svtplay-dl/issues" ) logging.error( "Include the URL used, the stack trace and the output of svtplay-dl --version in the issue" ) return if stream.config.get("require_subtitle") and not subs: logging.info("No subtitles available") return if stream.config.get("subtitle") and stream.config.get("get_url"): if subs: if stream.config.get("get_all_subtitles"): for sub in subs: print(sub.url) else: print(subs[0].url) if stream.config.get("force_subtitle"): return def options_subs_dl(subfixes): if subs: if stream.config.get("get_all_subtitles"): for sub in subs: sub.download() if stream.config.get("merge_subtitle"): if sub.subfix: subfixes += [sub.subfix] else: stream.config.set("get_all_subtitles", False) else: subs[0].download() elif stream.config.get("merge_subtitle"): stream.config.set("merge_subtitle", False) if stream.config.get("subtitle") and not stream.config.get("get_url"): options_subs_dl(subfixes) if stream.config.get("force_subtitle"): return if stream.config.get( "merge_subtitle") and not stream.config.get("subtitle"): options_subs_dl(subfixes) if not videos: errormsg = None for exc in error: if errormsg: errormsg = "{}. {}".format(errormsg, str(exc)) else: errormsg = str(exc) logging.error("No videos found. {}".format(errormsg)) else: if stream.config.get("list_quality"): list_quality(videos) return try: stream = select_quality(stream.config, videos) if stream.config.get("get_url"): print(stream.url) return logging.info("Selected to download %s, bitrate: %s", stream.name, stream.bitrate) stream.download() except UIException as e: if stream.config.get("verbose"): raise e log.error(e) sys.exit(2) if stream.config.get("thumbnail") and hasattr(stream, "get_thumbnail"): stream.get_thumbnail(stream.config) post = postprocess(stream, stream.config, subfixes) if stream.audio and post.detect: post.merge() if stream.audio and not post.detect and stream.finished: logging.warning( "Cant find ffmpeg/avconv. audio and video is in seperate files. if you dont want this use -P hls or hds" ) if stream.name == "hls" or stream.config.get("remux"): post.remux() if stream.config.get("silent_semi") and stream.finished: logging.log(25, "Download of %s was completed" % stream.options.output)
def find_all_episodes(self, options): parse = urlparse(self._url) if len(parse.path) > 7 and parse.path[-7:] == "rss.xml": rss_url = self.url else: rss_url = re.search( r'<link rel="alternate" type="application/rss\+xml" [^>]*href="([^"]+)"', self.get_urldata()) if rss_url: rss_url = rss_url.group(1) valid_rss = False tab = None if parse.query: match = re.search("tab=(.+)", parse.query) if match: tab = match.group(1) #Clips and tab can not be used with RSS-feed if rss_url and not self.options.include_clips and not tab: rss_data = self.http.request("get", rss_url).content try: xml = ET.XML(rss_data) episodes = [x.text for x in xml.findall(".//item/link")] #TODO add better checks for valid RSS-feed here valid_rss = True except ET.ParseError: log.info( "Error parsing RSS-feed at %s, make sure it is a valid RSS-feed, will use other method to find episodes." % rss_url) else: #if either tab or include_clips is set remove rss.xml from url if set manually. if len(parse.path) > 7 and parse.path[-7:] == "rss.xml": self._url = self.url.replace("rss.xml", "") if not valid_rss: videos = [] tab = None match = re.search("__svtplay'] = ({.*});", self.get_urldata()) if re.search("sista-chansen", parse.path): videos = self._last_chance(videos, 1) elif not match: log.error("Couldn't retrieve episode list.") return else: dataj = json.loads(match.group(1)) if re.search("/genre", parse.path): videos = self._genre(dataj) else: if parse.query: match = re.search("tab=(.+)", parse.query) if match: tab = match.group(1) items = dataj["relatedVideoContent"][ "relatedVideosAccordion"] for i in items: if tab: if i["slug"] == tab: videos = self.videos_to_list( i["videos"], videos) else: if "klipp" not in i[ "slug"] and "kommande" not in i["slug"]: videos = self.videos_to_list( i["videos"], videos) if self.options.include_clips: if i["slug"] == "klipp": videos = self.videos_to_list( i["videos"], videos) episodes = [urljoin("http://www.svtplay.se", x) for x in videos] if options.all_last > 0: return sorted(episodes[-options.all_last:]) return sorted(episodes)
def find_all_episodes(self, options): parse = urlparse(self._url) if len(parse.path) > 7 and parse.path[-7:] == "rss.xml": rss_url = self.url else: rss_url = re.search(r'<link rel="alternate" type="application/rss\+xml" [^>]*href="([^"]+)"', self.get_urldata()) if rss_url: rss_url = rss_url.group(1) valid_rss = False tab = None if parse.query: match = re.search("tab=(.+)", parse.query) if match: tab = match.group(1) #Clips and tab can not be used with RSS-feed if rss_url and not self.options.include_clips and not tab: rss_data = self.http.request("get", rss_url).content try: xml = ET.XML(rss_data) episodes = [x.text for x in xml.findall(".//item/link")] #TODO add better checks for valid RSS-feed here valid_rss = True except ET.ParseError: log.info("Error parsing RSS-feed at {0}, make sure it is a valid RSS-feed, will use other method to find episodes.".format(rss_url)) else: #if either tab or include_clips is set remove rss.xml from url if set manually. if len(parse.path) > 7 and parse.path[-7:] == "rss.xml": self._url = self.url.replace("rss.xml","") if not valid_rss: videos = [] tab = None match = re.search("__svtplay'] = ({.*});", self.get_urldata()) if re.search("sista-chansen", parse.path): videos = self._last_chance(videos, 1) elif not match: log.error("Couldn't retrieve episode list.") return else: dataj = json.loads(match.group(1)) if re.search("/genre", parse.path): videos = self._genre(dataj) else: if parse.query: match = re.search("tab=(.+)", parse.query) if match: tab = match.group(1) items = dataj["relatedVideoContent"]["relatedVideosAccordion"] for i in items: if tab: if i["slug"] == tab: videos = self.videos_to_list(i["videos"], videos) else: if "klipp" not in i["slug"] and "kommande" not in i["slug"]: videos = self.videos_to_list(i["videos"], videos) if self.options.include_clips: if i["slug"] == "klipp": videos = self.videos_to_list(i["videos"], videos) episodes = [urljoin("http://www.svtplay.se", x) for x in videos] if options.all_last > 0: return sorted(episodes)[-options.all_last:] return sorted(episodes)
def merge(self): if self.detect is None: log.error( "Cant detect ffmpeg or avconv. Cant mux files without it.") return if self.stream.finished is False: return orig_filename = self.stream.options.output cmd = [self.detect, "-i", orig_filename] _, stdout, stderr = run_program(cmd, False) # return 1 is good here. videotrack, audiotrack = self._checktracks(stderr) if self.merge_subtitle: log.info("Merge audio, video and subtitle into {0}".format( orig_filename)) else: log.info("Merge audio and video into {0}".format(orig_filename)) tempfile = u"{0}.temp".format(orig_filename) name = os.path.splitext(orig_filename)[0] audio_filename = u"{0}.m4a".format(name) arguments = ["-c:v", "copy", "-c:a", "copy", "-f", "mp4"] cmd = [self.detect, "-i", orig_filename, "-i", audio_filename] if self.merge_subtitle: langs = self.sublanguage() for stream_num, language in enumerate(langs, start=audiotrack + 1): arguments += [ "-map", "{}".format(videotrack), "-map", "{}".format(audiotrack), "-map", str(stream_num), "-c:s:" + str(stream_num - 2), "mov_text", "-metadata:s:s:" + str(stream_num - 2), "language=" + language ] if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) cmd += ["-i", subfile] else: subfile = "{0}.srt".format(name) cmd += ["-i", subfile] arguments += ["-y", tempfile] cmd += arguments returncode, stdout, stderr = run_program(cmd) if returncode != 1: return log.info("Merging done, removing old files.") os.remove(orig_filename) os.remove(audio_filename) if self.merge_subtitle and not self.external_subtitle: if len(self.subfixes) >= 2: for subfix in self.subfixes: subfile = "{0}.srt".format(name + subfix) os.remove(subfile) else: os.remove(subfile) os.rename(tempfile, orig_filename)
def get_one_media(stream, options): # Make an automagic filename if not filename(stream): return videos = [] subs = [] error = [] streams = stream.get() try: for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred.lower() == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if isinstance(i, Exception): error.append(i) except Exception as e: if options.verbose: raise else: log.error("svtplay-dl crashed") log.error("Run again and add --verbose as an argument, to get more information") log.error("If the error persists, you can report it at https://github.com/spaam/svtplay-dl/issues") log.error("Include the URL used, the stack trace and the output of svtplay-dl --version in the issue") sys.exit(3) if options.require_subtitle and not subs: log.info("No subtitles available") return if options.subtitle and options.output != "-": if subs: subs[0].download() if options.force_subtitle: return if len(videos) == 0: for exc in error: log.error(str(exc)) else: if options.list_quality: list_quality(videos) return stream = select_quality(options, videos) log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) if options.get_url: print(stream.url) return try: stream.download() except UIException as e: if options.verbose: raise e log.error(e) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout") post = postprocess(stream) if stream.name() == "dash" and post.detect: post.merge() if stream.name() == "dash" and not post.detect and stream.finished: log.warning("Cant find ffmpeg/avconv. audio and video is in seperate files. if you dont want this use -P hls or hds") if options.remux: post.remux()
def get_one_media(stream, options): # Make an automagic filename if not filename(stream): return if options.merge_subtitle: from svtplay_dl.utils import which if not which('ffmpeg'): log.error("--merge-subtitle needs ffmpeg. Please install ffmpeg.") log.info("https://ffmpeg.org/download.html") sys.exit(2) videos = [] subs = [] subfixes = [] error = [] streams = stream.get() try: for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred.lower() == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if isinstance(i, Exception): error.append(i) except Exception as e: if options.verbose: log.error("version: %s" % __version__) raise else: log.error("svtplay-dl crashed") log.error("Run again and add --verbose as an argument, to get more information") log.error("If the error persists, you can report it at https://github.com/spaam/svtplay-dl/issues") log.error("Include the URL used, the stack trace and the output of svtplay-dl --version in the issue") sys.exit(3) if options.require_subtitle and not subs: log.info("No subtitles available") return if options.subtitle and options.get_url: if subs: if options.get_all_subtitles: for sub in subs: print(sub.url) else: print(subs[0].url) if options.force_subtitle: return def options_subs_dl(subfixes): if subs: if options.get_all_subtitles: for sub in subs: sub.download() if options.merge_subtitle: if sub.subfix: subfixes += [sub.subfix] else: options.get_all_subtitles = False else: subs[0].download() elif options.merge_subtitle: options.merge_subtitle = False if options.subtitle and options.output != "-" and not options.get_url: options_subs_dl(subfixes) if options.force_subtitle: return if options.merge_subtitle and not options.subtitle: options_subs_dl(subfixes) if len(videos) == 0: for exc in error: log.error(str(exc)) else: if options.list_quality: list_quality(videos) return try: stream = select_quality(options, videos) if options.get_url: print(stream.url) return log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) stream.download() except UIException as e: if options.verbose: raise e log.error(e) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout") post = postprocess(stream, options, subfixes) if stream.name() == "dash" and post.detect: post.merge() if stream.name() == "dash" and not post.detect and stream.finished: log.warning("Cant find ffmpeg/avconv. audio and video is in seperate files. if you dont want this use -P hls or hds") if options.remux: post.remux() if options.silent_semi and stream.finished: log.log(25, "Download of %s was completed" % stream.options.output)
def get_one_media(stream, options): # Make an automagic filename if not filename(options, stream): return videos = [] subs = [] error = [] streams = stream.get(options) try: for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred.lower() == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if isinstance(i, Exception): error.append(i) except Exception as e: if options.verbose: raise e else: print("Script crashed. please run the script again and add --verbose as an argument") print("Make an issue with the url you used and include the stacktrace. please include the version of the script") sys.exit(3) if options.require_subtitle and not subs: log.info("No subtitles available") return if options.subtitle and options.output != "-": if subs: subs[0].download() if options.force_subtitle: return if len(videos) == 0: for exc in error: log.error(str(exc)) sys.exit(2) else: if options.list_quality: list_quality(videos) return stream = select_quality(options, videos) log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) if options.get_url: print(stream.url) return try: stream.download() except UIException as e: if options.verbose: raise e log.error(e) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout")
def get_one_media(stream, options): # Make an automagic filename if not filename(stream): return if options.merge_subtitle: from svtplay_dl.utils import which if not which('ffmpeg'): log.error("--merge-subtitle needs ffmpeg. Please install ffmpeg.") log.info("https://ffmpeg.org/download.html") sys.exit(2) videos = [] subs = [] subfixes = [] error = [] streams = stream.get() try: for i in streams: if isinstance(i, VideoRetriever): if options.preferred: if options.preferred.lower() == i.name(): videos.append(i) else: videos.append(i) if isinstance(i, subtitle): subs.append(i) if isinstance(i, Exception): error.append(i) except Exception as e: if options.verbose: raise else: log.error("svtplay-dl crashed") log.error("Run again and add --verbose as an argument, to get more information") log.error("If the error persists, you can report it at https://github.com/spaam/svtplay-dl/issues") log.error("Include the URL used, the stack trace and the output of svtplay-dl --version in the issue") sys.exit(3) if options.require_subtitle and not subs: log.info("No subtitles available") return if options.subtitle and options.get_url: if subs: if options.get_all_subtitles: for sub in subs: print(sub.url) else: print(subs[0].url) if options.force_subtitle: return def options_subs_dl(subfixes): if subs: if options.get_all_subtitles: for sub in subs: sub.download() if options.merge_subtitle: if sub.subfix: subfixes += [sub.subfix] else: options.get_all_subtitles = False else: subs[0].download() elif options.merge_subtitle: options.merge_subtitle = False if options.subtitle and options.output != "-" and not options.get_url: options_subs_dl(subfixes) if options.force_subtitle: return if options.merge_subtitle and not options.subtitle: options_subs_dl(subfixes) if not videos: log.error("No videos found.") for exc in error: log.error(str(exc)) else: if options.list_quality: list_quality(videos) return try: stream = select_quality(options, videos) if options.get_url: print(stream.url) return log.info("Selected to download %s, bitrate: %s", stream.name(), stream.bitrate) stream.download() except UIException as e: if options.verbose: raise e log.error(e) sys.exit(2) if options.thumbnail and hasattr(stream, "get_thumbnail"): if options.output != "-": log.info("Getting thumbnail") stream.get_thumbnail(options) else: log.warning("Can not get thumbnail when fetching to stdout") post = postprocess(stream, options, subfixes) if stream.name() == "dash" and post.detect: post.merge() if stream.name() == "dash" and not post.detect and stream.finished: log.warning("Cant find ffmpeg/avconv. audio and video is in seperate files. if you dont want this use -P hls or hds") if options.remux: post.remux() if options.silent_semi and stream.finished: log.log(25, "Download of %s was completed" % stream.options.output)
def download_hls(options, url, baseurl=None): data = get_http_data(url) globaldata, files = parsem3u(data) streams = {} for i in files: streams[int(i[1]["BANDWIDTH"])] = i[0] test = select_quality(options, streams) if baseurl and test[:4] != 'http': test = "%s/%s" % (baseurl, test) m3u8 = get_http_data(test) globaldata, files = parsem3u(m3u8) encrypted = False key = None try: keydata = globaldata["KEY"] encrypted = True except: pass if encrypted: try: from Crypto.Cipher import AES except ImportError: log.error("You need to install pycrypto to download encrypted HLS streams") sys.exit(2) match = re.search("URI=\"(http://.*)\"", keydata) key = get_http_data(match.group(1)) rand = os.urandom(16) decryptor = AES.new(key, AES.MODE_CBC, rand) n = 1 if options.output != "-": extension = re.search("(\.[a-z0-9]+)$", options.output) if not extension: options.output = "%s.ts" % options.output log.info("Outfile: %s", options.output) file_d = open(options.output, "wb") else: file_d = sys.stdout start = time.time() estimated = "" for i in files: item = i[0] if options.output != "-": progressbar(len(files), n, estimated) if item[0:5] != "http:": item = "%s/%s" % (baseurl, item) data = get_http_data(item) if encrypted: lots = StringIO(data) plain = b"" crypt = lots.read(1024) decrypted = decryptor.decrypt(crypt) while decrypted: plain += decrypted crypt = lots.read(1024) decrypted = decryptor.decrypt(crypt) data = plain file_d.write(data) now = time.time() dt = now - start et = dt / (n + 1) * len(files) rt = et - dt td = timedelta(seconds = int(rt)) estimated = "Estimated Remaining: " + str(td) n += 1 if options.output != "-": file_d.close() progress_stream.write('\n')