def wrstsegment(self, subdata): time = 0 subs = [] for i in self.kwargs["m3u8"].media_segment: itemurl = get_full_url(i["URI"], self.url) cont = self.http.get(itemurl) if "cmore" in self.url: cont.encoding = "utf-8" text = cont.text.split("\n") for t in text: # is in text[1] for tv4play, but this should be more future proof if 'X-TIMESTAMP-MAP=MPEGTS' in t: time = float( re.search(r"X-TIMESTAMP-MAP=MPEGTS:(\d+)", t).group(1)) / 90000 - 10 text = text[3:len(text) - 2] if len(text) > 1: itmes = [] for n in text: if n: itmes.append(n) else: if len(subs) > 1 and itmes[1] == subs[-1][ 1]: # This will happen when there is two sections in file ha = strdate(subs[-1][0]) ha3 = strdate(itmes[0]) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format( ha.group(1), sec2str(second)) itmes = [] else: ha = strdate(itmes[0]) first = str2sec(ha.group(1)) + time second = str2sec(ha.group(2)) + time itmes[0] = "{} --> {}".format( sec2str(first), sec2str(second)) subs.append(itmes) itmes = [] if itmes: if len(subs) > 0 and itmes[1] == subs[-1][1]: ha = strdate(subs[-1][0]) ha3 = strdate(itmes[0]) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format( ha.group(1), sec2str(second)) else: ha = strdate(itmes[0]) first = str2sec(ha.group(1)) + time second = str2sec(ha.group(2)) + time itmes[0] = "{} --> {}".format(sec2str(first), sec2str(second)) subs.append(itmes) string = "" nr = 1 for sub in subs: string += "{}\n{}\n\n".format(nr, '\n'.join(sub)) nr += 1 return string
def wrstsegment(self, subdata): time = 0 subs = [] for i in self.kwargs["m3u8"].media_segment: itemurl = get_full_url(i["URI"], self.url) cont = self.http.get(itemurl) if "cmore" in self.url: cont.encoding = "utf-8" text = cont.text.split("\n") for t in text: # is in text[1] for tv4play, but this should be more future proof if "X-TIMESTAMP-MAP=MPEGTS" in t: time = float( re.search(r"X-TIMESTAMP-MAP=MPEGTS:(\d+)", t).group(1)) / 90000 - 10 text = text[3:len(text) - 2] itmes = [] if len(text) > 1: for n in text: if n: # don't get the empty lines. itmes.append(n) several_items = False skip = False sub = [] for x in range(len(itmes)): item = itmes[x] if strdate(item) and len(subs) > 0 and itmes[x + 1] == subs[-1][1]: ha = strdate(subs[-1][0]) ha3 = strdate(item) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format(ha.group(1), sec2str(second)) skip = True continue has_date = strdate(item) if has_date: if several_items: subs.append(sub) sub = [] skip = False first = str2sec(has_date.group(1)) + time second = str2sec(has_date.group(2)) + time sub.append("{} --> {}".format(sec2str(first), sec2str(second))) several_items = True elif has_date is None and skip is False: sub.append(item) if sub: subs.append(sub) string = "" nr = 1 for sub in subs: string += "{}\n{}\n\n".format(nr, "\n".join(sub)) nr += 1 return string
def wrstsegment(self, subdata): time = 0 subs = [] for i in self.kwargs["m3u8"].media_segment: itemurl = get_full_url(i["URI"], self.url) cont = self.http.get(itemurl) if "cmore" in self.url: cont.encoding = "utf-8" text = cont.text.split("\n") for t in text: # is in text[1] for tv4play, but this should be more future proof if 'X-TIMESTAMP-MAP=MPEGTS' in t: time = float(re.search(r"X-TIMESTAMP-MAP=MPEGTS:(\d+)", t).group(1)) / 90000 - 10 text = text[3:len(text) - 2] if len(text) > 1: itmes = [] for n in text: if n: itmes.append(n) else: if len(subs) > 1 and len(itmes) < 2: # Ignore empty lines in unexpected places pass elif len(subs) > 1 and itmes[1] == subs[-1][1]: # This will happen when there are two sections in file ha = strdate(subs[-1][0]) ha3 = strdate(itmes[0]) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format(ha.group(1), sec2str(second)) itmes = [] else: ha = strdate(itmes[0]) first = str2sec(ha.group(1)) + time second = str2sec(ha.group(2)) + time itmes[0] = "{} --> {}".format(sec2str(first), sec2str(second)) subs.append(itmes) itmes = [] if itmes: if len(subs) > 0 and itmes[1] == subs[-1][1]: ha = strdate(subs[-1][0]) ha3 = strdate(itmes[0]) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format(ha.group(1), sec2str(second)) else: ha = strdate(itmes[0]) first = str2sec(ha.group(1)) + time second = str2sec(ha.group(2)) + time itmes[0] = "{} --> {}".format(sec2str(first), sec2str(second)) subs.append(itmes) string = "" nr = 1 for sub in subs: string += "{}\n{}\n\n".format(nr, '\n'.join(sub)) nr += 1 return string
def wrstsegment(self, subdata): time = 0 subs = [] for i in self.kwargs["m3u8"].media_segment: itemurl = get_full_url(i["URI"], self.url) cont = self.http.get(itemurl) if "cmore" in self.url: cont.encoding = "utf-8" text = cont.text.split("\n") for t in text: # is in text[1] for tv4play, but this should be more future proof if 'X-TIMESTAMP-MAP=MPEGTS' in t: time = float(re.search(r"X-TIMESTAMP-MAP=MPEGTS:(\d+)", t).group(1)) / 90000 - 10 text = text[3:len(text) - 2] itmes = [] if len(text) > 1: for n in text: if n: # don't get the empty lines. itmes.append(n) several_items = False skip = False sub = [] for x in range(len(itmes)): item = itmes[x] if strdate(item) and len(subs) > 0 and itmes[x + 1] == subs[-1][1]: ha = strdate(subs[-1][0]) ha3 = strdate(item) second = str2sec(ha3.group(2)) + time subs[-1][0] = "{} --> {}".format(ha.group(1), sec2str(second)) skip = True continue has_date = strdate(item) if has_date: if several_items: subs.append(sub) sub = [] skip = False first = str2sec(has_date.group(1)) + time second = str2sec(has_date.group(2)) + time sub.append("{} --> {}".format(sec2str(first), sec2str(second))) several_items = True elif has_date is None and skip is False: sub.append(item) if sub: subs.append(sub) string = "" nr = 1 for sub in subs: string += "{}\n{}\n\n".format(nr, '\n'.join(sub)) nr += 1 return string
def test_get_full_url_1(self): for test in [ # full http:// url as media segment in playlist { "srcurl": "INVALID", "segment": "http://example.com/", "expected": "http://example.com/" }, # full https:// url as media segment in playlist { "srcurl": "INVALID", "segment": "https://example.com/", "expected": "https://example.com/" }, # filename as media segment in playlist (http) { "srcurl": "http://example.com/", "segment": "foo.ts", "expected": "http://example.com/foo.ts" }, # filename as media segment in playlist (https) { "srcurl": "https://example.com/", "segment": "foo.ts", "expected": "https://example.com/foo.ts" }, # replacing srcurl file { "srcurl": "http://example.com/bar", "segment": "foo.ts", "expected": "http://example.com/foo.ts" }, # with query parameters { "srcurl": "http://example.com/bar?baz=qux", "segment": "foo.ts", "expected": "http://example.com/foo.ts" }, # with segment with slash { "srcurl": "http://example.com/bar", "segment": "/test", "expected": "http://example.com/test" }, ]: assert get_full_url(test["segment"], test["srcurl"]) == test["expected"]
def test_get_full_url_1(self): for test in [ # full http:// url as media segment in playlist { 'srcurl': 'INVALID', 'segment': 'http://example.com/', 'expected': 'http://example.com/' }, # full https:// url as media segment in playlist { 'srcurl': 'INVALID', 'segment': 'https://example.com/', 'expected': 'https://example.com/' }, # filename as media segment in playlist (http) { 'srcurl': 'http://example.com/', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, # filename as media segment in playlist (https) { 'srcurl': 'https://example.com/', 'segment': 'foo.ts', 'expected': 'https://example.com/foo.ts' }, # replacing srcurl file { 'srcurl': 'http://example.com/bar', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, # with query parameters { 'srcurl': 'http://example.com/bar?baz=qux', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, ]: self.assertEqual( get_full_url(test['segment'], test['srcurl']), test['expected'])
def test_get_full_url_1(self): for test in [ # full http:// url as media segment in playlist { 'srcurl': 'INVALID', 'segment': 'http://example.com/', 'expected': 'http://example.com/' }, # full https:// url as media segment in playlist { 'srcurl': 'INVALID', 'segment': 'https://example.com/', 'expected': 'https://example.com/' }, # filename as media segment in playlist (http) { 'srcurl': 'http://example.com/', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, # filename as media segment in playlist (https) { 'srcurl': 'https://example.com/', 'segment': 'foo.ts', 'expected': 'https://example.com/foo.ts' }, # replacing srcurl file { 'srcurl': 'http://example.com/bar', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, # with query parameters { 'srcurl': 'http://example.com/bar?baz=qux', 'segment': 'foo.ts', 'expected': 'http://example.com/foo.ts' }, ]: self.assertEqual(get_full_url(test['segment'], test['srcurl']), test['expected'])
def hlsparse(config, res, url, **kwargs): streams = {} if not res: return streams if res.status_code > 400: streams[0] = ServiceError("Can't read HLS playlist. {0}".format( res.status_code)) return streams m3u8 = M3U8(res.text) keycookie = kwargs.pop("keycookie", None) authorization = kwargs.pop("authorization", None) httpobject = kwargs.pop("httpobject", None) output = kwargs.pop("output", None) media = {} subtitles = {} segments = None if m3u8.master_playlist: for i in m3u8.master_playlist: audio_url = None if i["TAG"] == "EXT-X-MEDIA": if "AUTOSELECT" in i and (i["AUTOSELECT"].upper() == "YES"): if i["TYPE"] and i["TYPE"] != "SUBTITLES": if "URI" in i: if segments is None: segments = True if i["GROUP-ID"] not in media: media[i["GROUP-ID"]] = [] media[i["GROUP-ID"]].append(i["URI"]) else: segments = False if i["TYPE"] == "SUBTITLES": if "URI" in i: if i["GROUP-ID"] not in subtitles: subtitles[i["GROUP-ID"]] = [] item = [i["URI"], i["LANGUAGE"]] if item not in subtitles[i["GROUP-ID"]]: subtitles[i["GROUP-ID"]].append(item) continue elif i["TAG"] == "EXT-X-STREAM-INF": bit_rate = float(i["BANDWIDTH"]) / 1000 if "AUDIO" in i and (i["AUDIO"] in media): audio_url = get_full_url(media[i["AUDIO"]][0], url) urls = get_full_url(i["URI"], url) else: continue # Needs to be changed to utilise other tags. streams[int(bit_rate)] = HLS(copy.copy(config), urls, bit_rate, cookies=res.cookies, keycookie=keycookie, authorization=authorization, audio=audio_url, output=output, segments=bool(segments), kwargs=kwargs) if subtitles and httpobject: for sub in list(subtitles.keys()): for n in subtitles[sub]: m3u8s = M3U8( httpobject.request("get", get_full_url(n[0], url), cookies=res.cookies).text) if "cmore" in url: subtype = "wrstsegment" # this have been seen in tv4play else: subtype = "wrst" streams[int(random.randint(1, 40))] = subtitle( copy.copy(config), subtype, get_full_url(m3u8s.media_segment[0]["URI"], url), subfix=n[1], output=copy.copy(output), m3u8=m3u8s) elif m3u8.media_segment: config.set("segments", False) streams[0] = HLS(copy.copy(config), url, 0, cookies=res.cookies, keycookie=keycookie, authorization=authorization, output=output, segments=False) else: streams[0] = ServiceError("Can't find HLS playlist in m3u8 file.") return streams
def _download(self, url, file_name): cookies = self.kwargs.get("cookies", None) start_time = time.time() m3u8 = M3U8(self.http.request("get", url, cookies=cookies).text) key = None if m3u8.encrypted: from Crypto.Cipher import AES def random_iv(): try: from Crypto import Random return Random.new().read(AES.block_size) except ImportError: return os.urandom(16) file_d = output(file_name[0], self.config, file_name[1]) if file_d is None: return hls_time_stamp = self.kwargs.pop("hls_time_stamp", False) decryptor = None size_media = len(m3u8.media_segment) eta = ETA(size_media) total_duration = 0 duration = 0 max_duration = 0 for index, i in enumerate(m3u8.media_segment): if "duration" in i["EXTINF"]: duration = i["EXTINF"]["duration"] max_duration = max(max_duration, duration) total_duration += duration item = get_full_url(i["URI"], url) if not self.config.get("silent"): if self.config.get("live"): progressbar( size_media, index + 1, ''.join([ 'DU: ', str(timedelta(seconds=int(total_duration))) ])) else: eta.increment() progressbar(size_media, index + 1, ''.join(['ETA: ', str(eta)])) data = self.http.request("get", item, cookies=cookies) if data.status_code == 404: break data = data.content if m3u8.encrypted: headers = {} if self.keycookie: keycookies = self.keycookie else: keycookies = cookies if self.authorization: headers["authorization"] = self.authorization # Update key/decryptor if "EXT-X-KEY" in i: keyurl = get_full_url(i["EXT-X-KEY"]["URI"], url) key = self.http.request("get", keyurl, cookies=keycookies, headers=headers).content iv = binascii.unhexlify(i["EXT-X-KEY"]["IV"][2:].zfill( 32)) if "IV" in i["EXT-X-KEY"] else random_iv() decryptor = AES.new(key, AES.MODE_CBC, iv) if decryptor: data = decryptor.decrypt(data) else: raise ValueError( "No decryptor found for encrypted hls steam.") file_d.write(data) if self.config.get( "capture_time" ) > 0 and total_duration >= self.config.get("capture_time") * 60: break if (size_media == (index + 1)) and self.config.get("live"): sleep_int = (start_time + max_duration * 2) - time.time() if sleep_int > 0: time.sleep(sleep_int) size_media_old = size_media while size_media_old == size_media: start_time = time.time() if hls_time_stamp: end_time_stamp = (datetime.utcnow() - timedelta( minutes=1, seconds=max_duration * 2)).replace( microsecond=0) start_time_stamp = end_time_stamp - timedelta( minutes=1) base_url = url.split(".m3u8")[0] url = "{0}.m3u8?in={1}&out={2}?".format( base_url, start_time_stamp.isoformat(), end_time_stamp.isoformat()) new_m3u8 = M3U8( self.http.request("get", url, cookies=cookies).text) for n_m3u in new_m3u8.media_segment: if not any(d["URI"] == n_m3u["URI"] for d in m3u8.media_segment): m3u8.media_segment.append(n_m3u) size_media = len(m3u8.media_segment) if size_media_old == size_media: time.sleep(max_duration) file_d.close() if not self.config.get("silent"): progress_stream.write('\n') self.finished = True
def hlsparse(config, res, url, **kwargs): streams = {} if not res: return streams if res.status_code > 400: streams[0] = ServiceError("Can't read HLS playlist. {0}".format(res.status_code)) return streams m3u8 = M3U8(res.text) keycookie = kwargs.pop("keycookie", None) authorization = kwargs.pop("authorization", None) httpobject = kwargs.pop("httpobject", None) output = kwargs.pop("output", None) media = {} subtitles = {} segments = None if m3u8.master_playlist: for i in m3u8.master_playlist: audio_url = None if i["TAG"] == "EXT-X-MEDIA": if "AUTOSELECT" in i and (i["AUTOSELECT"].upper() == "YES"): if i["TYPE"] and i["TYPE"] != "SUBTITLES": if "URI" in i: if segments is None: segments = True if i["GROUP-ID"] not in media: media[i["GROUP-ID"]] = [] media[i["GROUP-ID"]].append(i["URI"]) else: segments = False if i["TYPE"] == "SUBTITLES": if "URI" in i: if i["GROUP-ID"] not in subtitles: subtitles[i["GROUP-ID"]] = [] item = [i["URI"], i["LANGUAGE"]] if item not in subtitles[i["GROUP-ID"]]: subtitles[i["GROUP-ID"]].append(item) continue elif i["TAG"] == "EXT-X-STREAM-INF": bit_rate = float(i["BANDWIDTH"]) / 1000 if "AUDIO" in i and (i["AUDIO"] in media): audio_url = get_full_url(media[i["AUDIO"]][0], url) urls = get_full_url(i["URI"], url) else: continue # Needs to be changed to utilise other tags. streams[int(bit_rate)] = HLS(copy.copy(config), urls, bit_rate, cookies=res.cookies, keycookie=keycookie, authorization=authorization, audio=audio_url, output=output, segments=bool(segments), kwargs=kwargs) if subtitles and httpobject: for sub in list(subtitles.keys()): for n in subtitles[sub]: m3u8s = M3U8(httpobject.request("get", get_full_url(n[0], url), cookies=res.cookies).text) if "cmore" in url: subtype = "wrstsegment" # this have been seen in tv4play else: subtype = "wrst" streams[int(random.randint(1, 40))] = subtitle(copy.copy(config), subtype, get_full_url(m3u8s.media_segment[0]["URI"], url), subfix=n[1], output=copy.copy(output), m3u8=m3u8s) elif m3u8.media_segment: config.set("segments", False) streams[0] = HLS(copy.copy(config), url, 0, cookies=res.cookies, keycookie=keycookie, authorization=authorization, output=output, segments=False) else: streams[0] = ServiceError("Can't find HLS playlist in m3u8 file.") return streams
def _download(self, url, file_name): cookies = self.kwargs.get("cookies", None) start_time = time.time() m3u8 = M3U8(self.http.request("get", url, cookies=cookies).text) key = None def random_iv(): return os.urandom(16) file_d = output(file_name[0], self.config, file_name[1]) if file_d is None: return hls_time_stamp = self.kwargs.pop("hls_time_stamp", False) decryptor = None size_media = len(m3u8.media_segment) eta = ETA(size_media) total_duration = 0 duration = 0 max_duration = 0 for index, i in enumerate(m3u8.media_segment): if "duration" in i["EXTINF"]: duration = i["EXTINF"]["duration"] max_duration = max(max_duration, duration) total_duration += duration item = get_full_url(i["URI"], url) if not self.config.get("silent"): if self.config.get("live"): progressbar(size_media, index + 1, ''.join(['DU: ', str(timedelta(seconds=int(total_duration)))])) else: eta.increment() progressbar(size_media, index + 1, ''.join(['ETA: ', str(eta)])) data = self.http.request("get", item, cookies=cookies) if data.status_code == 404: break data = data.content if m3u8.encrypted: headers = {} if self.keycookie: keycookies = self.keycookie else: keycookies = cookies if self.authorization: headers["authorization"] = self.authorization # Update key/decryptor if "EXT-X-KEY" in i: keyurl = get_full_url(i["EXT-X-KEY"]["URI"], url) if keyurl and keyurl[:4] == "skd:": raise HLSException(keyurl, "Can't decrypt beacuse of DRM") key = self.http.request("get", keyurl, cookies=keycookies, headers=headers).content iv = binascii.unhexlify(i["EXT-X-KEY"]["IV"][2:].zfill(32)) if "IV" in i["EXT-X-KEY"] else random_iv() backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) decryptor = cipher.decryptor() if decryptor: data = decryptor.update(data) else: raise ValueError("No decryptor found for encrypted hls steam.") file_d.write(data) if self.config.get("capture_time") > 0 and total_duration >= self.config.get("capture_time") * 60: break if (size_media == (index + 1)) and self.config.get("live"): sleep_int = (start_time + max_duration * 2) - time.time() if sleep_int > 0: time.sleep(sleep_int) size_media_old = size_media while size_media_old == size_media: start_time = time.time() if hls_time_stamp: end_time_stamp = (datetime.utcnow() - timedelta(minutes=1, seconds=max_duration * 2)).replace(microsecond=0) start_time_stamp = end_time_stamp - timedelta(minutes=1) base_url = url.split(".m3u8")[0] url = "{0}.m3u8?in={1}&out={2}?".format(base_url, start_time_stamp.isoformat(), end_time_stamp.isoformat()) new_m3u8 = M3U8(self.http.request("get", url, cookies=cookies).text) for n_m3u in new_m3u8.media_segment: if not any(d["URI"] == n_m3u["URI"] for d in m3u8.media_segment): m3u8.media_segment.append(n_m3u) size_media = len(m3u8.media_segment) if size_media_old == size_media: time.sleep(max_duration) file_d.close() if not self.config.get("silent"): progress_stream.write('\n') self.finished = True
def _download(self, url, file_name): cookies = self.kwargs.get("cookies", None) start_time = time.time() m3u8 = M3U8(self.http.request("get", url, cookies=cookies).text) key = None def random_iv(): return os.urandom(16) file_d = output(file_name[0], self.config, file_name[1]) if file_d is None: return if "EXT-X-MAP" in m3u8.media_segment[0]: entry = { "URI": get_full_url(m3u8.media_segment[0]["EXT-X-MAP"]["URI"], url), "EXTINF": { "duration": 0 } } if "EXT-X-KEY" in m3u8.media_segment[0]: entry["EXT-X-KEY"] = { "URI": m3u8.media_segment[0]["EXT-X-KEY"]["URI"] } m3u8.media_segment.insert(0, entry) hls_time_stamp = self.kwargs.pop("hls_time_stamp", False) decryptor = None size_media = len(m3u8.media_segment) eta = ETA(size_media) total_duration = 0 duration = 0 max_duration = 0 for index, i in enumerate(m3u8.media_segment): if "duration" in i["EXTINF"]: duration = i["EXTINF"]["duration"] max_duration = max(max_duration, duration) total_duration += duration item = get_full_url(i["URI"], url) if not self.config.get("silent"): if self.config.get("live"): progressbar( size_media, index + 1, "".join([ "DU: ", str(timedelta(seconds=int(total_duration))) ])) else: eta.increment() progressbar(size_media, index + 1, "".join(["ETA: ", str(eta)])) data = self.http.request("get", item, cookies=cookies) if data.status_code == 404: break data = data.content if m3u8.encrypted: headers = {} if self.keycookie: keycookies = self.keycookie else: keycookies = cookies if self.authorization: headers["authorization"] = self.authorization # Update key/decryptor if "EXT-X-KEY" in i: keyurl = get_full_url(i["EXT-X-KEY"]["URI"], url) if keyurl and keyurl[:4] == "skd:": raise HLSException(keyurl, "Can't decrypt beacuse of DRM") key = self.http.request("get", keyurl, cookies=keycookies, headers=headers).content iv = binascii.unhexlify(i["EXT-X-KEY"]["IV"][2:].zfill( 32)) if "IV" in i["EXT-X-KEY"] else random_iv() backend = default_backend() cipher = Cipher(algorithms.AES(key), modes.CBC(iv), backend=backend) decryptor = cipher.decryptor() # In some cases the playlist say its encrypted but the files is not. # This happen on svtplay 5.1ch stream where it started with ID3.. # Adding the other ones is header for mpeg-ts files. third byte is 10 or 11.. if data[: 3] != b"ID3" and data[: 3] != b"\x47\x40\x11" and data[:3] != b"\x47\x40\x10" and data[ 4:12] != b"ftypisom": if decryptor: data = decryptor.update(data) else: raise ValueError( "No decryptor found for encrypted hls steam.") file_d.write(data) if self.config.get( "capture_time" ) > 0 and total_duration >= self.config.get("capture_time") * 60: break if (size_media == (index + 1)) and self.config.get("live"): sleep_int = (start_time + max_duration * 2) - time.time() if sleep_int > 0: time.sleep(sleep_int) size_media_old = size_media while size_media_old == size_media: start_time = time.time() if hls_time_stamp: end_time_stamp = (datetime.utcnow() - timedelta( minutes=1, seconds=max_duration * 2)).replace( microsecond=0) start_time_stamp = end_time_stamp - timedelta( minutes=1) base_url = url.split(".m3u8")[0] url = f"{base_url}.m3u8?in={start_time_stamp.isoformat()}&out={end_time_stamp.isoformat()}?" new_m3u8 = M3U8( self.http.request("get", url, cookies=cookies).text) for n_m3u in new_m3u8.media_segment: if not any(d["URI"] == n_m3u["URI"] for d in m3u8.media_segment): m3u8.media_segment.append(n_m3u) size_media = len(m3u8.media_segment) if size_media_old == size_media: time.sleep(max_duration) file_d.close() if not self.config.get("silent"): progress_stream.write("\n") self.finished = True