easyder 0.2.0__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.
@@ -0,0 +1,26 @@
1
+ name: Code Formatting (Black)
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main, develop ]
8
+
9
+ jobs:
10
+ black:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v4
18
+ with:
19
+ python-version: '3.10'
20
+
21
+ - name: Install black
22
+ run: pip install black
23
+
24
+ - name: Check code formatting with black
25
+ run: black --check easyder tests
26
+ continue-on-error: true
@@ -0,0 +1,28 @@
1
+ name: Documentation
2
+
3
+ on:
4
+ push:
5
+ branches: [ main ]
6
+ pull_request:
7
+ branches: [ main ]
8
+
9
+ jobs:
10
+ docs:
11
+ runs-on: ubuntu-latest
12
+
13
+ steps:
14
+ - uses: actions/checkout@v3
15
+
16
+ - name: Set up Python
17
+ uses: actions/setup-python@v4
18
+ with:
19
+ python-version: '3.10'
20
+
21
+ - name: Install dependencies
22
+ run: |
23
+ python -m pip install --upgrade pip
24
+ pip install -e .
25
+
26
+ - name: Check README
27
+ run: |
28
+ python -c "import easyder; print(f'EASYDER {easyder.__version__} ready!')"
@@ -0,0 +1,34 @@
1
+ name: Release to PyPI
2
+
3
+ on:
4
+ release:
5
+ types: [created]
6
+ workflow_dispatch:
7
+
8
+ jobs:
9
+ build-and-publish:
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - uses: actions/checkout@v3
14
+
15
+ - name: Set up Python
16
+ uses: actions/setup-python@v4
17
+ with:
18
+ python-version: '3.10'
19
+
20
+ - name: Install dependencies
21
+ run: |
22
+ python -m pip install --upgrade pip
23
+ pip install build wheel twine
24
+
25
+ - name: Build distribution
26
+ run: python -m build
27
+
28
+ - name: Check distribution
29
+ run: twine check dist/*
30
+
31
+ - name: Publish to PyPI
32
+ uses: pypa/gh-action-pypi-publish@release/v1
33
+ with:
34
+ password: ${{ secrets.PYPI_API_TOKEN }}
@@ -0,0 +1,34 @@
1
+ name: Security Checks
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main, develop ]
8
+ schedule:
9
+ - cron: '0 0 * * 0'
10
+
11
+ jobs:
12
+ security:
13
+ runs-on: ubuntu-latest
14
+
15
+ steps:
16
+ - uses: actions/checkout@v3
17
+
18
+ - name: Set up Python
19
+ uses: actions/setup-python@v4
20
+ with:
21
+ python-version: '3.10'
22
+
23
+ - name: Install dependencies
24
+ run: |
25
+ python -m pip install --upgrade pip
26
+ pip install bandit safety
27
+
28
+ - name: Run bandit security check
29
+ run: bandit -r easyder -f json -o bandit-report.json
30
+ continue-on-error: true
31
+
32
+ - name: Run safety check
33
+ run: safety check --json
34
+ continue-on-error: true
@@ -0,0 +1,51 @@
1
+ name: Tests
2
+
3
+ on:
4
+ push:
5
+ branches: [ main, develop ]
6
+ pull_request:
7
+ branches: [ main, develop ]
8
+
9
+ jobs:
10
+ test:
11
+ runs-on: ${{ matrix.os }}
12
+ strategy:
13
+ fail-fast: false
14
+ matrix:
15
+ os: [ubuntu-latest, macos-latest, windows-latest]
16
+ python-version: ['3.8', '3.9', '3.10', '3.11', '3.12']
17
+
18
+ steps:
19
+ - uses: actions/checkout@v3
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ uses: actions/setup-python@v4
23
+ with:
24
+ python-version: ${{ matrix.python-version }}
25
+
26
+ - name: Install dependencies
27
+ run: |
28
+ python -m pip install --upgrade pip
29
+ pip install -e .[dev]
30
+
31
+ - name: Lint with flake8
32
+ run: |
33
+ flake8 easyder --count --select=E9,F63,F7,F82 --show-source --statistics
34
+ flake8 easyder --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics
35
+
36
+ - name: Type check with mypy
37
+ run: |
38
+ mypy easyder --ignore-missing-imports
39
+ continue-on-error: true
40
+
41
+ - name: Run tests with pytest
42
+ run: |
43
+ pytest tests/ -v --cov=easyder --cov-report=xml
44
+
45
+ - name: Upload coverage to Codecov
46
+ uses: codecov/codecov-action@v3
47
+ with:
48
+ file: ./coverage.xml
49
+ flags: unittests
50
+ name: codecov-umbrella
51
+ fail_ci_if_error: false
easyder-0.2.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 ReiZyuki
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
easyder-0.2.0/PKG-INFO ADDED
@@ -0,0 +1,504 @@
1
+ Metadata-Version: 2.4
2
+ Name: easyder
3
+ Version: 0.2.0
4
+ Summary: EASYDER - CSS-inspired video downloader with automatic cookie fallback, powered by yt-dlp + FFmpeg
5
+ Home-page: https://github.com/ReiZyuki/easyder
6
+ Author: ReiZyuki
7
+ Author-email: ReiZyuki <rei@example.com>
8
+ License: MIT
9
+ Project-URL: Homepage, https://github.com/ReiZyuki/easyder
10
+ Project-URL: Bug Tracker, https://github.com/ReiZyuki/easyder/issues
11
+ Project-URL: Documentation, https://github.com/ReiZyuki/easyder#readme
12
+ Project-URL: Source Code, https://github.com/ReiZyuki/easyder
13
+ Keywords: video,downloader,youtube,instagram,tiktok,yt-dlp,ffmpeg,css-inspired,easy
14
+ Classifier: Development Status :: 3 - Alpha
15
+ Classifier: Intended Audience :: Developers
16
+ Classifier: Intended Audience :: End Users/Desktop
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Natural Language :: English
19
+ Classifier: Operating System :: OS Independent
20
+ Classifier: Programming Language :: Python :: 3
21
+ Classifier: Programming Language :: Python :: 3.8
22
+ Classifier: Programming Language :: Python :: 3.9
23
+ Classifier: Programming Language :: Python :: 3.10
24
+ Classifier: Programming Language :: Python :: 3.11
25
+ Classifier: Programming Language :: Python :: 3.12
26
+ Classifier: Topic :: Internet :: WWW/HTTP
27
+ Classifier: Topic :: Multimedia :: Video
28
+ Classifier: Topic :: Utilities
29
+ Requires-Python: >=3.8
30
+ Description-Content-Type: text/markdown
31
+ License-File: LICENSE
32
+ Requires-Dist: yt-dlp>=2023.12.30
33
+ Requires-Dist: requests>=2.31.0
34
+ Provides-Extra: dev
35
+ Requires-Dist: pytest>=7.0.0; extra == "dev"
36
+ Requires-Dist: pytest-cov>=4.0.0; extra == "dev"
37
+ Requires-Dist: black>=23.0.0; extra == "dev"
38
+ Requires-Dist: flake8>=6.0.0; extra == "dev"
39
+ Requires-Dist: mypy>=1.0.0; extra == "dev"
40
+ Dynamic: author
41
+ Dynamic: home-page
42
+ Dynamic: license-file
43
+ Dynamic: requires-python
44
+
45
+ EASYDER — CSS-Inspired Video Downloader
46
+
47
+ ""Python 3.8+" (https://img.shields.io/badge/python-3.8+-blue.svg)" (https://www.python.org/downloads/)
48
+ ""License: MIT" (https://img.shields.io/badge/License-MIT-yellow.svg)" (https://opensource.org/licenses/MIT)
49
+
50
+ EASYDER is a CSS-inspired video downloader built with yt-dlp + FFmpeg.
51
+
52
+ Easyder V1.0 focuses on downloading video/audio, extracting metadata, downloading thumbnails, handling playlists, and automatically trying supplied cookie files when a normal request fails.
53
+
54
+ ---
55
+
56
+ Features
57
+
58
+ - ✅ CSS-inspired dictionary syntax
59
+ - ✅ Video quality selection
60
+ - ✅ Audio-only downloads
61
+ - ✅ 360p, 480p, 720p and 1080p quality stages
62
+ - ✅ Original/best quality selection
63
+ - ✅ Automatic cookie fallback
64
+ - ✅ Multiple supplied cookie files
65
+ - ✅ Playlist downloads
66
+ - ✅ Video metadata extraction
67
+ - ✅ Thumbnail downloading
68
+ - ✅ yt-dlp + FFmpeg based downloading
69
+ - ✅ Download progress display
70
+ - ✅ MP4 output for video downloads
71
+
72
+ ---
73
+
74
+ Installation
75
+
76
+ From PyPI
77
+
78
+ pip install easyder
79
+
80
+ From GitHub
81
+
82
+ git clone https://github.com/ReiZyuki/Easyder.git
83
+ cd Easyder
84
+ pip install -e .
85
+
86
+ ---
87
+
88
+ Quick Start
89
+
90
+ from easyder import rz
91
+
92
+ result = rz(
93
+ {
94
+ "video[3]": "video",
95
+ "title": "title",
96
+ "creator": "creator",
97
+ },
98
+ url,
99
+ )
100
+
101
+ print("Video:", result["video"])
102
+ print("Title:", result["title"])
103
+ print("Creator:", result["creator"])
104
+
105
+ The right-side values such as ""video"", ""title"" and ""creator"" are user-defined variable names.
106
+
107
+ ---
108
+
109
+ Video Quality
110
+
111
+ Easyder uses CSS-inspired quality selectors:
112
+
113
+ "video[0]"
114
+ "video[1]"
115
+ "video[2]"
116
+ "video[3]"
117
+ "video[4]"
118
+ "video[5]"
119
+
120
+ Selector| Quality
121
+ "video[0]"| Audio only
122
+ "video[1]"| 360p
123
+ "video[2]"| 480p
124
+ "video[3]"| 720p
125
+ "video[4]"| 1080p
126
+ "video[5]"| Best/original available quality
127
+
128
+ Example:
129
+
130
+ from easyder import rz
131
+
132
+ result = rz(
133
+ {
134
+ "video[4]": "video",
135
+ },
136
+ url,
137
+ )
138
+
139
+ print(result["video"])
140
+
141
+ If the requested quality is unavailable, yt-dlp selects an appropriate available format according to Easyder's format selection rules.
142
+
143
+ ---
144
+
145
+ Audio Only
146
+
147
+ Use "video[0]" for audio:
148
+
149
+ from easyder import rz
150
+
151
+ result = rz(
152
+ {
153
+ "video[0]": "audio",
154
+ },
155
+ url,
156
+ )
157
+
158
+ print(result["audio"])
159
+
160
+ ---
161
+
162
+ Metadata
163
+
164
+ Easyder can extract video metadata without downloading the video.
165
+
166
+ from easyder import rz
167
+
168
+ result = rz(
169
+ {
170
+ "title": "title",
171
+ "creator": "creator",
172
+ "url": "video_url",
173
+ "views": "views",
174
+ "likes": "likes",
175
+ "count": "comments",
176
+ "time": "duration",
177
+ "thumbnail": "thumbnail",
178
+ "formats": "formats",
179
+ },
180
+ url,
181
+ )
182
+
183
+ print("Title:", result["title"])
184
+ print("Creator:", result["creator"])
185
+ print("URL:", result["video_url"])
186
+ print("Views:", result["views"])
187
+ print("Likes:", result["likes"])
188
+ print("Comments:", result["comments"])
189
+ print("Duration:", result["duration"])
190
+ print("Thumbnail:", result["thumbnail"])
191
+ print("Formats:", result["formats"])
192
+
193
+ Metadata variable names are completely user-defined.
194
+
195
+ For example:
196
+
197
+ result = rz(
198
+ {
199
+ "title": "MyTitle",
200
+ "creator": "MyCreator",
201
+ },
202
+ url,
203
+ )
204
+
205
+ print(result["MyTitle"])
206
+ print(result["MyCreator"])
207
+
208
+ ---
209
+
210
+ Thumbnail
211
+
212
+ Use the "thumbnail" selector to download the video's thumbnail.
213
+
214
+ from easyder import rz
215
+
216
+ result = rz(
217
+ {
218
+ "thumbnail": "thumb",
219
+ },
220
+ url,
221
+ )
222
+
223
+ print(result["thumb"])
224
+
225
+ The returned value is the path of the downloaded thumbnail.
226
+
227
+ Default download directory:
228
+
229
+ /storage/emulated/0/Download/ReiDownloader
230
+
231
+ ---
232
+
233
+ Playlist
234
+
235
+ Playlist syntax:
236
+
237
+ "playlist": "QUALITY:SKIP:COUNT"
238
+
239
+ Example:
240
+
241
+ from easyder import rz
242
+
243
+ result = rz(
244
+ {
245
+ "playlist": "3:5:10",
246
+ },
247
+ playlist_url,
248
+ )
249
+
250
+ print(result["videos"])
251
+
252
+ Meaning:
253
+
254
+ 3 = 720p
255
+ 5 = skip the first 5 videos
256
+ 10 = download the next 10 videos
257
+
258
+ Quality values
259
+
260
+ Quality| Meaning
261
+ "0"| Audio
262
+ "1"| 360p
263
+ "2"| 480p
264
+ "3"| 720p
265
+ "4"| 1080p
266
+ "5"| Best/original
267
+
268
+ Example:
269
+
270
+ result = rz(
271
+ {
272
+ "playlist": "4:0:5",
273
+ },
274
+ playlist_url,
275
+ )
276
+
277
+ This requests:
278
+
279
+ 1080p
280
+ Skip 0
281
+ Download 5 videos
282
+
283
+ Downloaded playlist files are returned in:
284
+
285
+ result["videos"]
286
+
287
+ ---
288
+
289
+ Automatic Cookie Fallback
290
+
291
+ Easyder first attempts the request without cookies.
292
+
293
+ If the normal request fails, Easyder checks the cookie files supplied through the "Cooki" variable.
294
+
295
+ from easyder import rz
296
+
297
+ Cooki = [
298
+ "/storage/emulated/0/Download/youtube.txt",
299
+ "/storage/emulated/0/Download/other.txt",
300
+ ]
301
+
302
+ result = rz(
303
+ {
304
+ "video[3]": "video",
305
+ "title": "title",
306
+ },
307
+ url,
308
+ )
309
+
310
+ Easyder tests the supplied cookie files one by one and uses the first working cookie.
311
+
312
+ No cookie filenames are hardcoded by Easyder.
313
+
314
+ ---
315
+
316
+ Cookie Variable
317
+
318
+ The cookie variable name is:
319
+
320
+ Cooki
321
+
322
+ It can contain a single path:
323
+
324
+ Cooki = "/path/to/cookies.txt"
325
+
326
+ or multiple paths:
327
+
328
+ Cooki = [
329
+ "/path/to/cookies1.txt",
330
+ "/path/to/cookies2.txt",
331
+ ]
332
+
333
+ Easyder does not scan directories for cookie files.
334
+
335
+ ---
336
+
337
+ Progress
338
+
339
+ During downloads Easyder displays progress information similar to:
340
+
341
+ Downloading: 1080p
342
+ [Download 50%] [Network 2.0 MB/s] [Mode Video]
343
+
344
+ The downloader can also receive a progress callback:
345
+
346
+ from easyder import rz
347
+
348
+ def progress(percent, network, mode):
349
+ print(percent, network, mode)
350
+
351
+ result = rz(
352
+ {
353
+ "video[3]": "video",
354
+ },
355
+ url,
356
+ progress_callback=progress,
357
+ )
358
+
359
+ The callback receives:
360
+
361
+ percent
362
+ network
363
+ mode
364
+
365
+ ---
366
+
367
+ Custom Variable Names
368
+
369
+ Easyder does not require fixed output variable names.
370
+
371
+ For example:
372
+
373
+ result = rz(
374
+ {
375
+ "video[3]": "MyVideo",
376
+ "title": "MyTitle",
377
+ "creator": "MyCreator",
378
+ "thumbnail": "MyThumbnail",
379
+ },
380
+ url,
381
+ )
382
+
383
+ Then:
384
+
385
+ print(result["MyVideo"])
386
+ print(result["MyTitle"])
387
+ print(result["MyCreator"])
388
+ print(result["MyThumbnail"])
389
+
390
+ This keeps the selector syntax separate from the variable names used by your application.
391
+
392
+ ---
393
+
394
+ Complete Example
395
+
396
+ from easyder import rz
397
+
398
+ Cooki = [
399
+ "/storage/emulated/0/Download/youtube.txt",
400
+ ]
401
+
402
+ result = rz(
403
+ {
404
+ "video[4]": "video",
405
+ "title": "title",
406
+ "creator": "creator",
407
+ "thumbnail": "thumbnail",
408
+ "views": "views",
409
+ "likes": "likes",
410
+ "time": "duration",
411
+ },
412
+ url,
413
+ )
414
+
415
+ print("Video:", result["video"])
416
+ print("Title:", result["title"])
417
+ print("Creator:", result["creator"])
418
+ print("Thumbnail:", result["thumbnail"])
419
+ print("Views:", result["views"])
420
+ print("Likes:", result["likes"])
421
+ print("Duration:", result["duration"])
422
+
423
+ ---
424
+
425
+ Selector Reference
426
+
427
+ Selector| Example value| Description
428
+ "video[0]"| ""video""| Audio only
429
+ "video[1]"| ""video""| 360p video
430
+ "video[2]"| ""video""| 480p video
431
+ "video[3]"| ""video""| 720p video
432
+ "video[4]"| ""video""| 1080p video
433
+ "video[5]"| ""video""| Best/original quality
434
+ "title"| ""title""| Video title
435
+ "creator"| ""creator""| Uploader/creator
436
+ "url"| ""video_url""| Video URL
437
+ "views"| ""views""| View count
438
+ "likes"| ""likes""| Like count
439
+ "count"| ""comments""| Comment count
440
+ "time"| ""duration""| Duration
441
+ "thumbnail"| ""thumbnail""| Download thumbnail
442
+ "formats"| ""formats""| Available formats
443
+ "playlist"| ""QUALITY:SKIP:COUNT""| Playlist download
444
+
445
+ ---
446
+
447
+ Quality Reference
448
+
449
+ video[0] = Audio only
450
+ video[1] = 360p
451
+ video[2] = 480p
452
+ video[3] = 720p
453
+ video[4] = 1080p
454
+ video[5] = Best/original available
455
+
456
+ ---
457
+
458
+ Requirements
459
+
460
+ Easyder uses:
461
+
462
+ - Python
463
+ - yt-dlp
464
+ - FFmpeg
465
+
466
+ FFmpeg is required for media processing and merging separate video/audio streams.
467
+
468
+ ---
469
+
470
+ Download Location
471
+
472
+ The default download directory is:
473
+
474
+ /storage/emulated/0/Download/ReiDownloader
475
+
476
+ Videos and thumbnails downloaded by Easyder are stored there.
477
+
478
+ ---
479
+
480
+ V1.0 Scope
481
+
482
+ Easyder V1.0 intentionally focuses on:
483
+
484
+ Video
485
+ Audio
486
+ Thumbnail
487
+ Metadata
488
+ Playlist
489
+ Automatic cookie fallback
490
+ Progress reporting
491
+
492
+ Easyder V1.0 does not include:
493
+
494
+ Gallery / gallery-dl
495
+ Telegram / TeleBot integration
496
+ Sender functionality
497
+
498
+ These features may be considered separately in future versions.
499
+
500
+ ---
501
+
502
+ License
503
+
504
+ MIT License