mirror of
https://github.com/NohamR/OqeeRewind.git
synced 2026-10-11 10:14:14 +00:00
Compare commits
31 Commits
586a45aeda
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6900624ff | ||
|
|
45c78ac87b | ||
|
|
7c566a24a9 | ||
|
|
3732b57562 | ||
|
|
ea0223c94a | ||
|
|
44742ecc1e | ||
|
|
88e0f558e2 | ||
|
|
80565f70fe | ||
|
|
453929c9d9 | ||
|
|
c682d46b0f | ||
|
|
749e19e5c5 | ||
|
|
455e967196 | ||
|
|
392ac6d3aa | ||
|
|
e12c6f47a3 | ||
|
|
f78bf1d6c0 | ||
|
|
b7efe34ed0 | ||
|
|
ae5035c6a8 | ||
|
|
cada374158 | ||
|
|
daebae4411 | ||
|
|
86e370b86d | ||
|
|
ee5ba75a50 | ||
|
|
94e7b71bf6 | ||
|
|
03549172f0 | ||
|
|
cbb6275aff | ||
|
|
7f465affbb | ||
|
|
4524d474eb | ||
|
|
03512e4430 | ||
|
|
619c91b71d | ||
|
|
9f97f7ff33 | ||
|
|
5634871a35 | ||
|
|
0063753c47 |
77
main.py
77
main.py
@@ -9,6 +9,7 @@ import shutil
|
||||
import logging
|
||||
from datetime import datetime, timedelta
|
||||
from dotenv import load_dotenv
|
||||
import aiohttp
|
||||
from utils.input import (
|
||||
stream_selection,
|
||||
get_date_input,
|
||||
@@ -190,45 +191,21 @@ if __name__ == "__main__":
|
||||
mpd_content = get_manifest(dash_id)
|
||||
manifest_info = parse_mpd_manifest(mpd_content)
|
||||
|
||||
avc_tick = None
|
||||
avc_track_id = None
|
||||
if "video" in selections_avc:
|
||||
avc_sel = selections_avc["video"]
|
||||
avc_init_segment = avc_sel["segments"]["initialization"]
|
||||
avc_track_id = avc_init_segment.split("/")[-1].split("_init")[0]
|
||||
|
||||
logger.info("Bruteforcing AVC video track %s...", avc_track_id)
|
||||
avc_valid_ticks = asyncio.run(
|
||||
bruteforce(avc_track_id, start_tick_user, batch_size)
|
||||
)
|
||||
if len(avc_valid_ticks) == 0:
|
||||
logger.warning(
|
||||
"No valid ticks found for AVC video. AVC tracks will be removed from manifest."
|
||||
)
|
||||
else:
|
||||
avc_tick = avc_valid_ticks[0]
|
||||
logger.info("AVC video tick found: %s", avc_tick)
|
||||
else:
|
||||
logger.warning(
|
||||
"No AVC video track available. AVC tracks will be removed from manifest."
|
||||
)
|
||||
|
||||
hevc_tick = None
|
||||
hevc_track_id = None
|
||||
if "video" in selections_hevc:
|
||||
hevc_sel = selections_hevc["video"]
|
||||
hevc_init_segment = hevc_sel["segments"]["initialization"]
|
||||
hevc_track_id = hevc_init_segment.split("/")[-1].split("_init")[0]
|
||||
|
||||
logger.info("Bruteforcing HEVC video track %s...", hevc_track_id)
|
||||
hevc_valid_ticks = asyncio.run(
|
||||
bruteforce(hevc_track_id, start_tick_user, batch_size)
|
||||
)
|
||||
if len(hevc_valid_ticks) == 0:
|
||||
logger.warning(
|
||||
"No valid ticks found for HEVC video. HEVC tracks will be removed from manifest."
|
||||
)
|
||||
else:
|
||||
hevc_tick = hevc_valid_ticks[0]
|
||||
logger.info("HEVC video tick found: %s", hevc_tick)
|
||||
else:
|
||||
logger.warning(
|
||||
"No HEVC video track available. HEVC tracks will be removed from manifest."
|
||||
@@ -239,10 +216,52 @@ if __name__ == "__main__":
|
||||
audio_init_segment = audio_sel["segments"]["initialization"]
|
||||
audio_track_id = audio_init_segment.split("/")[-1].split("_init")[0]
|
||||
|
||||
logger.info("Bruteforcing audio track %s...", audio_track_id)
|
||||
audio_valid_ticks = asyncio.run(
|
||||
bruteforce(audio_track_id, start_tick_user, batch_size)
|
||||
async def bruteforce_all():
|
||||
async with aiohttp.ClientSession() as session:
|
||||
avc_ticks = None
|
||||
hevc_ticks = None
|
||||
audio_ticks = []
|
||||
|
||||
if avc_track_id:
|
||||
logger.info(
|
||||
"Bruteforcing AVC video track %s...", avc_track_id
|
||||
)
|
||||
avc_valid = await bruteforce(
|
||||
avc_track_id, start_tick_user, batch_size, session=session
|
||||
)
|
||||
if len(avc_valid) == 0:
|
||||
logger.warning(
|
||||
"No valid ticks found for AVC video. AVC tracks will be removed from manifest."
|
||||
)
|
||||
else:
|
||||
avc_ticks = avc_valid[0]
|
||||
logger.info("AVC video tick found: %s", avc_ticks)
|
||||
|
||||
if hevc_track_id:
|
||||
logger.info(
|
||||
"Bruteforcing HEVC video track %s...", hevc_track_id
|
||||
)
|
||||
hevc_valid = await bruteforce(
|
||||
hevc_track_id, start_tick_user, batch_size, session=session
|
||||
)
|
||||
if len(hevc_valid) == 0:
|
||||
logger.warning(
|
||||
"No valid ticks found for HEVC video. HEVC tracks will be removed from manifest."
|
||||
)
|
||||
else:
|
||||
hevc_ticks = hevc_valid[0]
|
||||
logger.info("HEVC video tick found: %s", hevc_ticks)
|
||||
|
||||
logger.info("Bruteforcing audio track %s...", audio_track_id)
|
||||
audio_valid = await bruteforce(
|
||||
audio_track_id, start_tick_user, batch_size, session=session
|
||||
)
|
||||
if len(audio_valid) > 0:
|
||||
audio_ticks = audio_valid
|
||||
|
||||
return avc_ticks, hevc_ticks, audio_ticks
|
||||
|
||||
avc_tick, hevc_tick, audio_valid_ticks = asyncio.run(bruteforce_all())
|
||||
if len(audio_valid_ticks) == 0:
|
||||
logger.error("No valid ticks found for audio.")
|
||||
sys.exit(1)
|
||||
|
||||
@@ -17,7 +17,7 @@ dependencies = [
|
||||
"pywidevine>=1.9.0",
|
||||
"requests>=2.32.5",
|
||||
"tabulate>=0.9.0",
|
||||
"tqdm>=4.69.0",
|
||||
"tqdm>=4.70.0",
|
||||
"tzdata>=2026.3",
|
||||
]
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
aiohttp==3.14.1
|
||||
aiohttp==3.14.3
|
||||
beautifulsoup4==4.15.0
|
||||
InquirerPy==0.3.4
|
||||
prompt_toolkit==3.0.52
|
||||
python-dotenv==1.2.2
|
||||
prompt_toolkit==3.0.53
|
||||
python-dotenv==1.2.4
|
||||
pywidevine==1.9.0
|
||||
Requests==2.34.2
|
||||
tabulate==0.10.0
|
||||
tqdm==4.69.0
|
||||
tzdata==2026.3
|
||||
tqdm==4.70.1
|
||||
tzdata==2026.5
|
||||
|
||||
@@ -18,6 +18,16 @@ ET.register_namespace("", "urn:mpeg:dash:schema:mpd:2011")
|
||||
ET.register_namespace("xsi", "http://www.w3.org/2001/XMLSchema-instance")
|
||||
ET.register_namespace("cenc", "urn:mpeg:cenc:2013")
|
||||
|
||||
SEGMENT_HEADERS = {
|
||||
"Accept": "*/*",
|
||||
"Referer": "https://tv.free.fr/",
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/143.0.0.0 Safari/537.36"
|
||||
),
|
||||
}
|
||||
|
||||
|
||||
def parse_mpd_manifest(mpd_content: str) -> Dict[str, Any]:
|
||||
"""Parse an MPD manifest and extract metadata.
|
||||
@@ -340,7 +350,7 @@ def get_manifest(manifest_id):
|
||||
|
||||
|
||||
async def fetch_segment(session, ticks, track_id):
|
||||
"""Fetch a media segment asynchronously.
|
||||
"""Probe whether a media segment exists using a lightweight HEAD request.
|
||||
|
||||
Args:
|
||||
session: The aiohttp ClientSession.
|
||||
@@ -348,20 +358,11 @@ async def fetch_segment(session, ticks, track_id):
|
||||
track_id: The track identifier.
|
||||
|
||||
Returns:
|
||||
The tick value if successful, None otherwise.
|
||||
The tick value if the segment exists, None otherwise.
|
||||
"""
|
||||
url = f"https://media4.stream.proxad.net/media/{track_id}_{ticks}"
|
||||
headers = {
|
||||
"Accept": "*/*",
|
||||
"Referer": "https://tv.free.fr/",
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/143.0.0.0 Safari/537.36"
|
||||
),
|
||||
}
|
||||
try:
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
async with session.head(url, headers=SEGMENT_HEADERS) as resp:
|
||||
if resp.status == 200:
|
||||
return ticks
|
||||
return None
|
||||
@@ -377,16 +378,7 @@ def get_init(output_folder, track_id):
|
||||
track_id: The track identifier.
|
||||
"""
|
||||
url = f"https://media4.stream.proxad.net/media/{track_id}_init"
|
||||
headers = {
|
||||
"Accept": "*/*",
|
||||
"Referer": "https://tv.free.fr/",
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/143.0.0.0 Safari/537.36"
|
||||
),
|
||||
}
|
||||
response = requests.get(url, headers=headers, timeout=10)
|
||||
response = requests.get(url, headers=SEGMENT_HEADERS, timeout=10)
|
||||
if response.status_code == 200:
|
||||
os.makedirs(f"{output_folder}/segments_{track_id}", exist_ok=True)
|
||||
init_path = f"{output_folder}/segments_{track_id}/init.mp4"
|
||||
@@ -418,17 +410,8 @@ async def save_segments(
|
||||
Tuple of (success: bool, tick: int, rep: int)
|
||||
"""
|
||||
url = f"https://media4.stream.proxad.net/media/{track_id}_{tick}"
|
||||
headers = {
|
||||
"Accept": "*/*",
|
||||
"Referer": "https://tv.free.fr/",
|
||||
"User-Agent": (
|
||||
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) "
|
||||
"AppleWebKit/537.36 (KHTML, like Gecko) "
|
||||
"Chrome/143.0.0.0 Safari/537.36"
|
||||
),
|
||||
}
|
||||
try:
|
||||
async with session.get(url, headers=headers) as resp:
|
||||
async with session.get(url, headers=SEGMENT_HEADERS) as resp:
|
||||
if resp.status == 200:
|
||||
content = await resp.read()
|
||||
filename = f"{output_folder}/segments_{track_id}/{tick}.m4s"
|
||||
@@ -458,11 +441,11 @@ async def save_segments(
|
||||
segments_to_download = [(start_tick + i * duration, i) for i in range(rep_nb)]
|
||||
|
||||
# In case of resuming, check which segments are already downloaded
|
||||
already_downloaded = [
|
||||
already_downloaded = {
|
||||
int(f.split(".")[0])
|
||||
for f in os.listdir(f"{output_folder}/segments_{track_id}")
|
||||
if f.endswith(".m4s") and f.split(".")[0].isdigit()
|
||||
]
|
||||
}
|
||||
segments_to_download = [
|
||||
(tick, rep) for tick, rep in segments_to_download if tick not in already_downloaded
|
||||
]
|
||||
|
||||
@@ -55,23 +55,39 @@ def future(rep, base, duration):
|
||||
return base + rep * duration
|
||||
|
||||
|
||||
async def bruteforce(track_id, date, batch_size=20000):
|
||||
"""Bruteforce segments to find valid ticks."""
|
||||
async def bruteforce(track_id, date, batch_size=20000, concurrency=100, session=None):
|
||||
"""Bruteforce segments to find valid ticks.
|
||||
|
||||
Args:
|
||||
track_id: The track identifier.
|
||||
date: The base tick to start probing from.
|
||||
batch_size: Number of ticks to probe per batch.
|
||||
concurrency: Maximum number of in-flight requests at once.
|
||||
session: Optional shared aiohttp session. A new one is created if omitted.
|
||||
|
||||
Returns:
|
||||
List of valid ticks found (empty if none).
|
||||
"""
|
||||
valid_ticks = []
|
||||
total_requests = 288000
|
||||
|
||||
logger.debug("Starting bruteforce for %s near (%s) %s", track_id, date, convert_sec_to_date(convert_ticks_to_sec(date, TIMESCALE)))
|
||||
|
||||
start_time = time.time()
|
||||
owns_session = session is None
|
||||
if owns_session:
|
||||
session = aiohttp.ClientSession()
|
||||
|
||||
try:
|
||||
async with aiohttp.ClientSession() as session:
|
||||
semaphore = asyncio.Semaphore(concurrency)
|
||||
|
||||
async def probe(t):
|
||||
async with semaphore:
|
||||
return await fetch_segment(session, t + date, track_id)
|
||||
|
||||
for batch_start in range(0, total_requests, batch_size):
|
||||
batch_end = min(batch_start + batch_size, total_requests)
|
||||
tasks = [
|
||||
fetch_segment(session, t + date, track_id)
|
||||
for t in range(batch_start, batch_end)
|
||||
]
|
||||
tasks = [probe(t) for t in range(batch_start, batch_end)]
|
||||
|
||||
results = []
|
||||
for coro in tqdm(
|
||||
@@ -90,10 +106,15 @@ async def bruteforce(track_id, date, batch_size=20000):
|
||||
# Stop if we found valid ticks
|
||||
if valid_ticks:
|
||||
logger.debug("Found valid ticks: %s, stopping bruteforce.", valid_ticks)
|
||||
for task in tasks:
|
||||
task.cancel()
|
||||
break
|
||||
|
||||
except KeyboardInterrupt:
|
||||
logger.error("Interrupted by user (Ctrl+C)")
|
||||
finally:
|
||||
if owns_session:
|
||||
await session.close()
|
||||
|
||||
elapsed = time.time() - start_time
|
||||
logger.debug("Completed in %.2fs", elapsed)
|
||||
|
||||
@@ -39,7 +39,7 @@ def merge_segments(input_folder: str, track_id: str, output_file: str):
|
||||
with open(output_file, "wb") as outfile:
|
||||
for fname in segment_files:
|
||||
with open(f"{segment_folder}/{fname}", "rb") as infile:
|
||||
outfile.write(infile.read())
|
||||
shutil.copyfileobj(infile, outfile)
|
||||
logger.info("Merged segments into %s", output_file)
|
||||
|
||||
|
||||
@@ -104,7 +104,7 @@ def decrypt(segment_dir, init_path, output_file, key):
|
||||
with open(chunk_merged, "wb") as outfile:
|
||||
for fname in chunk_files:
|
||||
with open(os.path.join(segment_dir, fname), "rb") as infile:
|
||||
outfile.write(infile.read())
|
||||
shutil.copyfileobj(infile, outfile)
|
||||
|
||||
logger.debug("Decrypting chunk %d", chunk_num)
|
||||
result = subprocess.run(
|
||||
|
||||
86
uv.lock
generated
86
uv.lock
generated
@@ -175,7 +175,7 @@ resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.10'" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/18/74/dfb75f9ccd592bbedb175d4a32fc643cf569d7c218508bfbd6ea7ef9c091/astroid-3.3.11.tar.gz", hash = "sha256:1e5a5011af2920c7c67a53f65d536d65bfa7116feeaf2354d8b94f29573bb0ce", size = 400439, upload-time = "2025-07-13T18:04:23.177Z" }
|
||||
wheels = [
|
||||
@@ -192,7 +192,7 @@ resolution-markers = [
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "typing-extensions", marker = "python_full_version == '3.10.*'" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.11'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b7/22/97df040e15d964e592d3a180598ace67e91b7c559d8298bdb3c949dc6e42/astroid-4.0.2.tar.gz", hash = "sha256:ac8fb7ca1c08eb9afec91ccc23edbd8ac73bb22cbdd7da1d488d9fb8d6579070", size = 405714, upload-time = "2025-11-09T21:21:18.373Z" }
|
||||
wheels = [
|
||||
@@ -217,10 +217,27 @@ wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/3a/2a/7cc015f5b9f5db42b7d48157e23356022889fc354a2813c15934b7cb5c0e/attrs-25.4.0-py3-none-any.whl", hash = "sha256:adcf7e2a1fb3b36ac48d97835bb6d8ade15b8dcce26aba8bf1d14847b57a3373", size = 67615, upload-time = "2025-10-06T13:54:43.17Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.6.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/88/df/86bffad6309f74f3ff85ea69344a078fc30003270c8df6894fca7a3c72ff/beautifulsoup4-4.6.3.tar.gz", hash = "sha256:90f8e61121d6ae58362ce3bed8cd997efb00c914eae0ff3d363c32f9a9822d10", size = 167469, upload-time = "2018-08-12T16:39:49.655Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/21/0a/47fdf541c97fd9b6a610cb5fd518175308a7cc60569962e776ac52420387/beautifulsoup4-4.6.3-py3-none-any.whl", hash = "sha256:194ec62a25438adcb3fdb06378b26559eda1ea8a747367d34c33cef9c7f48d57", size = 90375, upload-time = "2018-08-12T16:39:48.02Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "beautifulsoup4"
|
||||
version = "4.14.3"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
resolution-markers = [
|
||||
"python_full_version >= '3.12'",
|
||||
"python_full_version == '3.11.*'",
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "soupsieve" },
|
||||
{ name = "typing-extensions" },
|
||||
@@ -235,7 +252,8 @@ name = "bs4"
|
||||
version = "0.0.2"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "beautifulsoup4" },
|
||||
{ name = "beautifulsoup4", version = "4.6.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||
{ name = "beautifulsoup4", version = "4.14.3", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/c9/aa/4acaf814ff901145da37332e05bb510452ebed97bc9602695059dd46ef39/bs4-0.0.2.tar.gz", hash = "sha256:a48685c58f50fe127722417bae83fe6badf500d54b55f7e39ffe43b798653925", size = 698, upload-time = "2024-01-17T18:15:47.371Z" }
|
||||
wheels = [
|
||||
@@ -364,7 +382,7 @@ resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/b9/2e/0090cbf739cee7d23781ad4b89a9894a41538e4fcf4c31dcdd705b78eb8b/click-8.1.8.tar.gz", hash = "sha256:ed53c9d8990d83c2a27deae68e4ee337473f6330c040a31d4225c9574d16096a", size = 226593, upload-time = "2024-12-21T18:38:44.339Z" }
|
||||
wheels = [
|
||||
@@ -381,7 +399,7 @@ resolution-markers = [
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/3d/fa/656b739db8587d7b5dfa22e22ed02566950fbfbcdc20311993483657a5c0/click-8.3.1.tar.gz", hash = "sha256:12ff4785d337a1bb490bb7e9c2b1ee5da3112e94a8622f26a6c77f5d2fc6842a", size = 295065, upload-time = "2025-11-15T20:45:42.706Z" }
|
||||
wheels = [
|
||||
@@ -563,7 +581,7 @@ name = "importlib-metadata"
|
||||
version = "8.7.0"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "zipp", marker = "python_full_version < '3.10'" },
|
||||
{ name = "zipp" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/76/66/650a33bd90f786193e4de4b3ad86ea60b53c89b669a5c7be931fac31cdb0/importlib_metadata-8.7.0.tar.gz", hash = "sha256:d13b81ad223b890aa16c5471f2ac3056cf76c5f10f82d6f9292f0b415f389000", size = 56641, upload-time = "2025-04-27T15:29:01.736Z" }
|
||||
wheels = [
|
||||
@@ -591,7 +609,7 @@ resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "importlib-metadata", marker = "python_full_version < '3.10'" },
|
||||
{ name = "importlib-metadata" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/1e/82/fa43935523efdfcce6abbae9da7f372b627b27142c3419fcf13bf5b0c397/isort-6.1.0.tar.gz", hash = "sha256:9b8f96a14cfee0677e78e941ff62f03769a06d412aabb9e2a90487b3b7e8d481", size = 824325, upload-time = "2025-10-01T16:26:45.027Z" }
|
||||
wheels = [
|
||||
@@ -808,7 +826,7 @@ requires-dist = [
|
||||
{ name = "pywidevine", specifier = ">=1.9.0" },
|
||||
{ name = "requests", specifier = ">=2.32.5" },
|
||||
{ name = "tabulate", specifier = ">=0.9.0" },
|
||||
{ name = "tqdm", specifier = ">=4.69.0" },
|
||||
{ name = "tqdm", specifier = ">=4.70.0" },
|
||||
{ name = "tzdata", specifier = ">=2026.3" },
|
||||
]
|
||||
|
||||
@@ -1056,15 +1074,15 @@ resolution-markers = [
|
||||
"python_full_version < '3.10'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "astroid", version = "3.3.11", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||
{ name = "colorama", marker = "python_full_version < '3.10' and sys_platform == 'win32'" },
|
||||
{ name = "dill", marker = "python_full_version < '3.10'" },
|
||||
{ name = "isort", version = "6.1.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||
{ name = "mccabe", marker = "python_full_version < '3.10'" },
|
||||
{ name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version < '3.10'" },
|
||||
{ name = "tomli", marker = "python_full_version < '3.10'" },
|
||||
{ name = "tomlkit", marker = "python_full_version < '3.10'" },
|
||||
{ name = "typing-extensions", marker = "python_full_version < '3.10'" },
|
||||
{ name = "astroid", version = "3.3.11", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "dill" },
|
||||
{ name = "isort", version = "6.1.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "mccabe" },
|
||||
{ name = "platformdirs", version = "4.4.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "tomli" },
|
||||
{ name = "tomlkit" },
|
||||
{ name = "typing-extensions" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/04/9d/81c84a312d1fa8133b0db0c76148542a98349298a01747ab122f9314b04e/pylint-3.3.9.tar.gz", hash = "sha256:d312737d7b25ccf6b01cc4ac629b5dcd14a0fcf3ec392735ac70f137a9d5f83a", size = 1525946, upload-time = "2025-10-05T18:41:43.786Z" }
|
||||
wheels = [
|
||||
@@ -1081,14 +1099,14 @@ resolution-markers = [
|
||||
"python_full_version == '3.10.*'",
|
||||
]
|
||||
dependencies = [
|
||||
{ name = "astroid", version = "4.0.2", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||
{ name = "colorama", marker = "python_full_version >= '3.10' and sys_platform == 'win32'" },
|
||||
{ name = "dill", marker = "python_full_version >= '3.10'" },
|
||||
{ name = "isort", version = "7.0.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||
{ name = "mccabe", marker = "python_full_version >= '3.10'" },
|
||||
{ name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" }, marker = "python_full_version >= '3.10'" },
|
||||
{ name = "tomli", marker = "python_full_version == '3.10.*'" },
|
||||
{ name = "tomlkit", marker = "python_full_version >= '3.10'" },
|
||||
{ name = "astroid", version = "4.0.2", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
{ name = "dill" },
|
||||
{ name = "isort", version = "7.0.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "mccabe" },
|
||||
{ name = "platformdirs", version = "4.5.0", source = { registry = "https://pypi.org/simple" } },
|
||||
{ name = "tomli", marker = "python_full_version < '3.11'" },
|
||||
{ name = "tomlkit" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/dd/9c/0500020a5446031220f487ca0c762713c6f3ddad7231b811aaf1d473f6aa/pylint-4.0.3.tar.gz", hash = "sha256:a427fe76e0e5355e9fb9b604fd106c419cafb395886ba7f3cebebb03f30e081d", size = 1570368, upload-time = "2025-11-13T15:54:41.394Z" }
|
||||
wheels = [
|
||||
@@ -1225,11 +1243,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "soupsieve"
|
||||
version = "2.8.4"
|
||||
version = "2.9"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/47/2c/0a5f6f8ee0d5589e48c7640213ed5175d52cf540a06725b628cc1a45d6ce/soupsieve-2.8.4.tar.gz", hash = "sha256:e121fd02e975c695e4e9e8774a5ee35d74714b59307868dcc5319ad2d9e3328e", size = 121110, upload-time = "2026-05-24T13:55:57.154Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/80/f1/93422647dd7e461f23d254e6b2bfa687a85b53aeb4903fcdbb74474d4584/soupsieve-2.9.tar.gz", hash = "sha256:acee8417325c5653e1377dc31eccad59eb82cbc65942afe6174c53b3aaad63fc", size = 122122, upload-time = "2026-07-19T01:35:18.425Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/5e/f5/0c41cb68dcae6b7de4fac4188a3a9589e21fb31df21ea3a2e888db95e6c9/soupsieve-2.8.4-py3-none-any.whl", hash = "sha256:e7e6b0769c8f51ed59acab6e994b00621096cfb1c640a7509295987388fbaf65", size = 37304, upload-time = "2026-05-24T13:55:55.406Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/7b/d6/3185ab5ad1280319b31986898f3206dd7227cd75e293d4dba2a5e6bf27a0/soupsieve-2.9-py3-none-any.whl", hash = "sha256:a2b2c76d67df2382d245409fd71e321a571717e58463efa32ace87dcadac2c12", size = 37387, upload-time = "2026-07-19T01:35:17.106Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1301,14 +1319,14 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "tqdm"
|
||||
version = "4.69.0"
|
||||
version = "4.70.1"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
dependencies = [
|
||||
{ name = "colorama", marker = "sys_platform == 'win32'" },
|
||||
]
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/8c/69/40407dfc835517f058b603dbf37a6df094d8582b015a51eddc988febbcb7/tqdm-4.69.0.tar.gz", hash = "sha256:700c5e85dcd5f009dd6222588a29180a193a748247a5d855b4d67db93d79a53b", size = 792569, upload-time = "2026-07-17T18:09:06.2Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/0d/ea/b2a5bd54b28a324dae8211928b2d730b6547500342c7e6c6dea08bd0a485/tqdm-4.70.1.tar.gz", hash = "sha256:cefd0eca11b2a37a3aee776544d4f4ae913f02688135b5556b8788dfa474afc4", size = 171846, upload-time = "2026-09-11T07:25:16.601Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/fe/21/99a0cdaf54eb35e77623c41b5a2c9472ee4404bba687052791fe2aba6773/tqdm-4.69.0-py3-none-any.whl", hash = "sha256:9979978912be667a6ef21fd5d8abf54e324e63d82f7f43c360792ebc2bc4e622", size = 676680, upload-time = "2026-07-17T18:09:04.172Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/a7/03/921a3d3c75785aca9ebfbfcabfbc3a1be12e2ab5265deb026d55a5a3f83e/tqdm-4.70.1-py3-none-any.whl", hash = "sha256:c293e525e6fef9c20e8728fd4612df02a0aa31bb5fe91ecd93e123b1b7bffa73", size = 80199, upload-time = "2026-09-11T07:25:14.599Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1322,11 +1340,11 @@ wheels = [
|
||||
|
||||
[[package]]
|
||||
name = "tzdata"
|
||||
version = "2026.3"
|
||||
version = "2026.4"
|
||||
source = { registry = "https://pypi.org/simple" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/92/ff/5a28bdfd8c3ebec42564ac7d0e54ca3db65044a9314a97f9564fa7a1e926/tzdata-2026.3.tar.gz", hash = "sha256:4a1518b8993086a7982523e071643f3c0e5f213e75b21318e78bcabfff9d1415", size = 198674, upload-time = "2026-07-10T08:50:37.887Z" }
|
||||
sdist = { url = "https://files.pythonhosted.org/packages/e4/31/3d74fa778a63b98b7374323befcc0be5ab3bd94afd4096a0124e7379152c/tzdata-2026.4.tar.gz", hash = "sha256:f1b8bd365d8d210c55353f4d7f8d6d8561c0ba50d704b700d195a9424bba0d79", size = 199350, upload-time = "2026-09-12T12:56:03.251Z" }
|
||||
wheels = [
|
||||
{ url = "https://files.pythonhosted.org/packages/e5/6d/b53b99a9f2766d095985947a5782f1702cabb129a34f7a802d7197af832f/tzdata-2026.3-py2.py3-none-any.whl", hash = "sha256:dc096730c87af6cab1b171c9d532be840741ff5d459015e7f6947bd7d7e54931", size = 348168, upload-time = "2026-07-10T08:50:36.46Z" },
|
||||
{ url = "https://files.pythonhosted.org/packages/f9/bc/8737e8d54cf51106118039b83f485a4783112fab49ea9d044b234978a46e/tzdata-2026.4-py2.py3-none-any.whl", hash = "sha256:c2169a8b0a7a5e9674da5a135ccdfb2b3e671b333ed9fed17b41f73c34476e81", size = 347494, upload-time = "2026-09-12T12:56:01.67Z" },
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
Reference in New Issue
Block a user