2
2
/usr/bin/python3
# pylint: disable=R,C,W,E
"""
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
"""
import subprocess
from udemy.compat import re, time
class FFMPeg:
_PROGRESS_PATTERN = re.compile(
r"(frame|fps|total_size|out_time|bitrate|speed|progress)\s*\=\s*(\S+)"
)
def __init__(
self, duration, url, token, filepath, quiet=False, callback=lambda *x:
None
):
self.url = url
self.filepath = filepath
self.quiet = quiet
self.duration = duration
self.callback = callback
self.token = token
def _command(self):
"""
ffmpeg.exe -headers "Authorization: Bearer {token}" -i "" -c copy -bsf:a
aac_adtstoasc out.mp4
"""
command = [
"ffmpeg",
"-headers",
f"Authorization: Bearer {self.token}",
"-i",
f"{self.url}",
"-c",
"copy",
"-bsf:a",
"aac_adtstoasc",
f"{self.filepath}",
"-y",
"-progress",
"pipe:2",
]
return command
def _progress(
self, iterations, total, bytesdone, speed, elapsed, bar_length=30,
fps=None
):
offset = 0
filled_length = int(round(bar_length * iterations / float(total)))
percents = format(100.00 * (iterations * 1.0 / float(total)), ".2f")
total_time = self._prepare_time_str(total)
done_time = self._prepare_time_str(iterations)
downloaded = f"{total_time}/{done_time}"
progress.hls_progress(
downloaded=downloaded,
percents=percents,
filled_length=filled_length,
rate=str(rate) + str(suffix_rate),
suffix=eta,
bar_length=bar_length,
)
def download(self):
total_time = None
t0 = time.time()
progress_lines = []
active = True
retVal = {}
command = self._command()
bytes_done = 0
download_speed = 0
try:
with subprocess.Popen(
command, stdout=subprocess.PIPE, stderr=subprocess.PIPE
) as proc:
while active:
elapsed = time.time() - t0
try:
line = proc.stderr.readline().decode("utf-8").strip()
if not total_time:
total_time = self._fetch_total_duration(line)
if "progress=end" in line:
try:
self._progress(
total_time,
total_time,
bytes_done,
download_speed,
elapsed,
)
except KeyboardInterrupt:
retVal = {
"status": "False",
"msg": "Error: KeyboardInterrupt",
}
raise KeyboardInterrupt
except Exception as err:
{"status": "False", "msg": f"Error: {err}"}
active = False
retVal = {"status": "True", "msg": "download"}
break
if "progress" not in line:
progress_lines.append(line)
else:
lines = "\n".join(progress_lines)
items = self._parse_progress(lines)
if items:
secs = self._fetch_current_duration_done(
items.get("out_time")
)
_tsize = (
items.get("total_size").lower().replace("kb", "")
)
_brate = (
items.get("bitrate").lower().replace("kbits/s", "")
)
fps = items.get("fps")
bytes_done = float(_tsize) if _tsize != "n/a" else 0
download_speed = float(_brate) if _brate != "n/a" else 0
try:
self._progress(
secs,
total_time,
bytes_done,
download_speed,
elapsed,
fps=fps,
)
except KeyboardInterrupt:
retVal = {
"status": "False",
"msg": "Error: KeyboardInterrupt",
}
raise KeyboardInterrupt
except Exception as err:
{"status": "False", "msg": f"Error: {err}"}
progress_lines = []
except KeyboardInterrupt:
active = False
retVal = {"status": "False", "msg": "Error: KeyboardInterrupt"}
raise KeyboardInterrupt
except KeyboardInterrupt:
raise KeyboardInterrupt
return retVal