polytool 0.2.6__tar.gz → 0.2.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {polytool-0.2.6 → polytool-0.2.7}/PKG-INFO +3 -1
- {polytool-0.2.6 → polytool-0.2.7}/pyproject.toml +2 -2
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/__init__.py +1 -1
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/dl.py +24 -2
- {polytool-0.2.6 → polytool-0.2.7}/.gitignore +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/LICENSE +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/README.md +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/docs/README.md +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/__main__.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/__init__.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/clip.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/color.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/convert.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/cron.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/data.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/enc.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/file.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/gen.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/img.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/net.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/pdf.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/qr.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/shot.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/text.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/cli/vid.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/__init__.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/browsers.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/config.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/console.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/errors.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/ffmpeg.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/io.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/lazy.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/progress.py +0 -0
- {polytool-0.2.6 → polytool-0.2.7}/src/polytool/core/runtime.py +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: polytool
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.7
|
|
4
4
|
Summary: One-binary CLI bundling 26 everyday utilities — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more
|
|
5
5
|
Project-URL: Homepage, https://github.com/k6w/polytool
|
|
6
6
|
Project-URL: Repository, https://github.com/k6w/polytool
|
|
@@ -48,6 +48,7 @@ Requires-Dist: pytest-cov>=5; extra == 'dev'
|
|
|
48
48
|
Requires-Dist: pytest>=8; extra == 'dev'
|
|
49
49
|
Requires-Dist: ruff>=0.5; extra == 'dev'
|
|
50
50
|
Provides-Extra: dl
|
|
51
|
+
Requires-Dist: yt-dlp-ejs>=0.8; extra == 'dl'
|
|
51
52
|
Requires-Dist: yt-dlp>=2024.5; extra == 'dl'
|
|
52
53
|
Provides-Extra: full
|
|
53
54
|
Requires-Dist: ascii-magic>=2; extra == 'full'
|
|
@@ -70,6 +71,7 @@ Requires-Dist: pytesseract>=0.3; extra == 'full'
|
|
|
70
71
|
Requires-Dist: pyzbar>=0.1; extra == 'full'
|
|
71
72
|
Requires-Dist: rembg[cpu]>=2.0; extra == 'full'
|
|
72
73
|
Requires-Dist: resvg-py>=0.1; extra == 'full'
|
|
74
|
+
Requires-Dist: yt-dlp-ejs>=0.8; extra == 'full'
|
|
73
75
|
Requires-Dist: yt-dlp>=2024.5; extra == 'full'
|
|
74
76
|
Provides-Extra: img
|
|
75
77
|
Requires-Dist: ascii-magic>=2; extra == 'img'
|
|
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
|
|
|
4
4
|
|
|
5
5
|
[project]
|
|
6
6
|
name = "polytool"
|
|
7
|
-
version = "0.2.
|
|
7
|
+
version = "0.2.7"
|
|
8
8
|
description = "One-binary CLI bundling 26 everyday utilities — image/video/PDF conversion, background removal, OCR, QR codes, hashing, downloads, and more"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
requires-python = ">=3.13"
|
|
@@ -58,7 +58,7 @@ img = [
|
|
|
58
58
|
]
|
|
59
59
|
vid = ["ffmpeg-python>=0.2", "imageio-ffmpeg>=0.5"]
|
|
60
60
|
pdf = ["pypdf>=4", "pikepdf>=8", "pdfplumber>=0.11", "pymupdf>=1.24"]
|
|
61
|
-
dl = ["yt-dlp>=2024.5"]
|
|
61
|
+
dl = ["yt-dlp>=2024.5", "yt-dlp-ejs>=0.8"]
|
|
62
62
|
ocr = ["pytesseract>=0.3", "easyocr>=1.7"]
|
|
63
63
|
ai = ["rembg[cpu]>=2.0"]
|
|
64
64
|
qr-decode = ["pyzbar>=0.1"]
|
|
@@ -56,6 +56,13 @@ N_CHALLENGE_PATTERNS = (
|
|
|
56
56
|
"requested format is not available",
|
|
57
57
|
)
|
|
58
58
|
|
|
59
|
+
# Patterns that indicate per-session DRM lock — not something we can solve.
|
|
60
|
+
DRM_PATTERNS = (
|
|
61
|
+
"drm protected",
|
|
62
|
+
"drm-protected",
|
|
63
|
+
"experiment that applies drm",
|
|
64
|
+
)
|
|
65
|
+
|
|
59
66
|
|
|
60
67
|
_ANSI_RE = re.compile(r"\x1b\[[0-9;]*[A-Za-z]")
|
|
61
68
|
_NOISE_RE = re.compile(
|
|
@@ -151,10 +158,25 @@ def _n_challenge_hint(messages: list[str]) -> str | None:
|
|
|
151
158
|
)
|
|
152
159
|
|
|
153
160
|
|
|
161
|
+
def _drm_hint(messages: list[str]) -> str | None:
|
|
162
|
+
text = " ".join(messages).lower()
|
|
163
|
+
if not any(p in text for p in DRM_PATTERNS):
|
|
164
|
+
return None
|
|
165
|
+
return (
|
|
166
|
+
"YouTube has flagged this video as DRM-protected for your current session.\n"
|
|
167
|
+
"This is a per-account / per-session A/B experiment yt-dlp can't bypass.\n\n"
|
|
168
|
+
"Workarounds (any one usually works):\n"
|
|
169
|
+
" • Try without cookies: [cyan]pt dl get URL --cookies-from-browser ''[/cyan]\n"
|
|
170
|
+
" • Use a different browser profile: [cyan]pt dl setup --browser chrome[/cyan]\n"
|
|
171
|
+
" • Try a different YouTube account.\n"
|
|
172
|
+
" • Pick a different video — only some are DRM-flagged in your session."
|
|
173
|
+
)
|
|
174
|
+
|
|
175
|
+
|
|
154
176
|
def _hint_for_error(message: str, logger: _DlLogger) -> str | None:
|
|
155
|
-
"""Pick the best hint for a failure: bot-check
|
|
177
|
+
"""Pick the best hint for a failure: DRM > bot-check > n-challenge."""
|
|
156
178
|
pool = [message, *logger.warnings, *logger.errors]
|
|
157
|
-
return _bot_check_hint(message) or _n_challenge_hint(pool)
|
|
179
|
+
return _drm_hint(pool) or _bot_check_hint(message) or _n_challenge_hint(pool)
|
|
158
180
|
|
|
159
181
|
|
|
160
182
|
# --------------------------------------------------------------------------- #
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|