Skip to content

Commit

Permalink
Add files via upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Jules-A authored Sep 30, 2023
1 parent c54ddfb commit 51eeb4a
Show file tree
Hide file tree
Showing 2 changed files with 135 additions and 0 deletions.
36 changes: 36 additions & 0 deletions yt_dlp/utils/_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -4812,6 +4812,41 @@ def determine_file_encoding(data):
return mobj.group(1).decode() if mobj else None, 0


class TimeKeeper:
def __init__(self):
self._last_ts = time.monotonic()

def elapsed(self, seconds: float) -> bool:
time_now = time.monotonic()
dif = time_now - self._last_ts
if dif > seconds:
self._last_ts = time_now
return True
return False


class TsTracker:
def __init__(self, updates, initial_bytes=0):
self._ts_data = collections.deque([[0] * 2] * updates, maxlen=updates)
self._initial_bytes = initial_bytes
self._started = time.monotonic()

def update(self, bytes_down):
time_now = time.monotonic()
session_down = float(bytes_down - self._initial_bytes)
self._ts_data.append((time_now, bytes_down))
time_dif = time_now - self._ts_data[0][0]

if self._ts_data[0][1] > 0 and time_dif > 0:
speed = float(bytes_down - self._ts_data[0][1]) / time_dif
elif session_down > 0:
speed = session_down / (time_now - self._started)
else:
speed = None

return speed


class Config:
own_args = None
parsed_args = None
Expand Down Expand Up @@ -5173,6 +5208,7 @@ def orderedSet_from_options(options, alias_dict, *, use_regex=False, start=None)
return orderedSet(requested)



# TODO: Rewrite
class FormatSorter:
regex = r' *((?P<reverse>\+)?(?P<field>[a-zA-Z0-9_]+)((?P<separator>[~:])(?P<limit>.*?))?)? *$'
Expand Down
99 changes: 99 additions & 0 deletions yt_dlp/utils/progress.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
from __future__ import annotations

import bisect
# import operator
import statistics
import threading
import time
from dataclasses import dataclass


@dataclass
class ThreadInfo:
speed: float
last_update: float
last_size: int
times: list[float]
speeds: list[float]


class ProgressCalculator:
# Time to calculate the average over (in seconds)
WINDOW_SIZE = 2.0
# Minimum time before we add another datapoint (in seconds)
# This is *NOT* the same as the time between a progress change
UPDATE_TIME = 0.1

def __init__(self, initial):
self.downloaded = initial if initial else 0

self.elapsed = 0
self.speed = None
self.eta = None
self._total = None

self._start_time = time.monotonic()
self._thread_infos: dict[int, ThreadInfo] = {}
self._lock = threading.Lock()

@property
def total(self):
return self._total

@total.setter
def total(self, value):
with self._lock:
if not value or value <= 0.01:
value = None
elif value < self.downloaded:
value = self.downloaded

self._total = value

def update(self, size):
with self._lock:
return self._update(size)

def _update(self, size):
current_thread = threading.get_ident()
thread_info = self._thread_infos.get(current_thread)
if not thread_info:
thread_info = ThreadInfo(self._start_time, 0, 0, [], [])
self._thread_infos[current_thread] = thread_info

last_size = thread_info.last_size
if size < last_size:
chunk = size
elif size > last_size:
chunk = size - last_size
else:
return
self.downloaded += chunk
if self.total and self.downloaded > self.total:
self._total = self.downloaded
thread_info.last_size = size

current_time = time.monotonic()
self.elapsed = current_time - self._start_time

last_update = thread_info.last_update
if current_time - self.UPDATE_TIME <= last_update:
return
thread_info.last_update = current_time

offset = bisect.bisect_left(thread_info.times, current_time - self.WINDOW_SIZE)
del thread_info.times[:offset]
del thread_info.speeds[:offset]
thread_info.times.append(current_time)
thread_info.speeds.append(size / (current_time - last_update))

# weights = tuple(1 + (point - current_time) / self.WINDOW_SIZE for point in thread_info.times)
# Same as `statistics.fmean(self.data_points, weights)`, but weights is >=3.11
# thread_info.speed = sum(map(operator.mul, thread_info.speeds, weights)) / sum(weights)
thread_info.speed = statistics.fmean(thread_info.speeds)
self.speed = sum(info.speed for info in self._thread_infos.values())

if not self.total:
self.eta = None
else:
self.eta = (self.total - self.downloaded) / self.speed

0 comments on commit 51eeb4a

Please sign in to comment.