library 3.2.7__tar.gz → 3.2.11__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.
- {library-3.2.7 → library-3.2.11}/.github/README.md +74 -4
- {library-3.2.7 → library-3.2.11}/PKG-INFO +126 -54
- {library-3.2.7 → library-3.2.11}/library/__main__.py +1 -2
- library-3.2.11/library/_version.py +25 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/gallery_backend.py +37 -35
- {library-3.2.7 → library-3.2.11}/library/createdb/links_add.py +11 -2
- {library-3.2.7 → library-3.2.11}/library/mediadb/download.py +11 -3
- {library-3.2.7 → library-3.2.11}/library/mediafiles/images_to_pdf.py +1 -1
- {library-3.2.7 → library-3.2.11}/library/mediafiles/process_image.py +1 -1
- {library-3.2.7 → library-3.2.11}/library/mediafiles/unardel.py +39 -9
- {library-3.2.7 → library-3.2.11}/library/readme.py +28 -2
- library-3.2.11/library/text/extract_links.py +422 -0
- {library-3.2.7 → library-3.2.11}/library/usage.py +45 -1
- {library-3.2.7 → library-3.2.11}/library/utils/arggroups.py +84 -11
- {library-3.2.7 → library-3.2.11}/library/utils/consts.py +24 -0
- {library-3.2.7 → library-3.2.11}/library/utils/devices.py +1 -1
- {library-3.2.7 → library-3.2.11}/library/utils/printing.py +3 -6
- {library-3.2.7 → library-3.2.11}/library/utils/processes.py +9 -6
- {library-3.2.7 → library-3.2.11}/library/utils/shell_utils.py +12 -4
- {library-3.2.7 → library-3.2.11}/library/utils/strings.py +10 -6
- {library-3.2.7 → library-3.2.11}/library/utils/web.py +279 -11
- {library-3.2.7 → library-3.2.11}/pyproject.toml +23 -37
- library-3.2.11/pyproject.toml.orig +207 -0
- library-3.2.7/library/text/extract_links.py +0 -274
- {library-3.2.7 → library-3.2.11}/LICENSE +0 -0
- {library-3.2.7 → library-3.2.11}/library/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/assets/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/assets/calibre.css +0 -0
- {library-3.2.7 → library-3.2.11}/library/assets/kotobago.png +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/av.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/computer_info.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/computers_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/fs_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/fs_add_metadata.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/gallery_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/getty_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/hn_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/nicotine_import.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/places_import.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/reddit_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/row_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/site_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/substack.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/subtitle.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/tables_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/tabs_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/tildes.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/torrents_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/tube_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/tube_backend.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/createdb/web_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/dictionary.pkl +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/ffmpeg_errors.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/http_errors.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/imagemagick_errors.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/unar_errors.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/wordbank.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/data/yt_dlp_errors.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/dedupe_db.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/dedupe_media.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/merge_online_local.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/mpv_watchlater.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/pushshift.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/editdb/reddit_selftext.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/files/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/files/christen.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/files/sample_compare.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/files/sample_hash.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/files/similar_files.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/big_dirs.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/filter_src.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/merge_mv.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/mergerfs_cp.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/mount_stats.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/move_list.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/scatter.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/folders/similar_folders.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/fsdb/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/fsdb/disk_usage.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/fsdb/filesystem.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/fsdb/folder_stats.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/fsdb/search_db.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/lb.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/block.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/db_history.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/db_media.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/db_playlists.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/download_status.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/history.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/history_add.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/optimize_db.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/playlists.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/redownload.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/search.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediadb/stats.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/media_check.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/pdf_edit.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/process_ffmpeg.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/process_media.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/process_text.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/torrents_dump.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/mediafiles/torrents_start.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/misc/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/misc/dedupe_czkawka.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/misc/export_text.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/misc/search_help.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/multidb/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/multidb/allocate_torrents.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/multidb/copy_play_counts.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/multidb/merge_dbs.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/links_open.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/media_player.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/media_printer.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/play_actions.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/playback_control.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/post_actions.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/surf.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/tabs_open.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/torrents_info.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/playback/torrents_remaining.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/columns.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/eda.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/incremental_diff.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/markdown_tables.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/mcda.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/tablefiles/plot.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/cluster_sort.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/combinations.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/expand_links.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/extract_text.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/json_keys_rename.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/markdown_links.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/nouns.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/regex_sort.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/text/timestamps.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/__init__.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/arg_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/argparse_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/date_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/db_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/file_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/filter_engine.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/gui.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/iterables.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/log_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/mpv_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/nums.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/objects.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/path_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/pd_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/remote_processes.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/sql_utils.py +0 -0
- {library-3.2.7 → library-3.2.11}/library/utils/sqlgroups.py +0 -0
|
@@ -10,7 +10,9 @@ tracking online video playlists (eg. YouTube subscriptions) and scheduling brows
|
|
|
10
10
|
|
|
11
11
|
[](https://pepy.tech/project/library)
|
|
12
12
|
|
|
13
|
-
##
|
|
13
|
+
## Getting started
|
|
14
|
+
|
|
15
|
+
<details><summary>Install</summary>
|
|
14
16
|
|
|
15
17
|
Linux recommended but [Windows setup instructions](./Windows.md) available.
|
|
16
18
|
|
|
@@ -24,7 +26,31 @@ Required: `ffmpeg`
|
|
|
24
26
|
|
|
25
27
|
Some features work better with: `mpv`, `fd-find`, `fish`
|
|
26
28
|
|
|
27
|
-
|
|
29
|
+
Optional Python extras are grouped under `library[deluxe]`. This includes
|
|
30
|
+
`gallery-dl` (used by `gallery-add`), `internetarchive` (used for Internet
|
|
31
|
+
Archive downloads), and `cdx_toolkit` (used by the `--webcache`/`--wayback`
|
|
32
|
+
CDX extractor):
|
|
33
|
+
|
|
34
|
+
pip install "library[deluxe]"
|
|
35
|
+
|
|
36
|
+
Torrent metadata commands (`torrents-add` and `torrents-dump`) require the
|
|
37
|
+
`libtorrent` Python bindings. They are included by `library[deluxe]` when using
|
|
38
|
+
Python 3.12 or 3.13; Python 3.14 wheels are not available yet, so use Python
|
|
39
|
+
3.13 for torrent support.
|
|
40
|
+
|
|
41
|
+
If the PyPI wheel is unavailable for your Python or platform, these system
|
|
42
|
+
packages provide the bindings:
|
|
43
|
+
|
|
44
|
+
* Debian/Ubuntu: `sudo apt install python3-libtorrent`
|
|
45
|
+
* Fedora: `sudo dnf install rb_libtorrent-python3`
|
|
46
|
+
* macOS/Homebrew: `brew install libtorrent-rasterbar`
|
|
47
|
+
|
|
48
|
+
The Debian, Fedora, and Homebrew packages are built for their system or
|
|
49
|
+
Homebrew Python and may not be importable from a separate uv virtualenv. There
|
|
50
|
+
is no official Scoop package for the Python bindings; on Windows, use Python
|
|
51
|
+
3.13 and `pip install "library[deluxe]"`.
|
|
52
|
+
|
|
53
|
+
</details>
|
|
28
54
|
|
|
29
55
|
<details><summary>Local media</summary>
|
|
30
56
|
|
|
@@ -99,7 +125,7 @@ To stop playing press Ctrl+C in either the terminal or mpv
|
|
|
99
125
|
<details><summary>List all subcommands</summary>
|
|
100
126
|
|
|
101
127
|
$ library
|
|
102
|
-
library (v3.2.
|
|
128
|
+
library (v3.2.011; 102 subcommands)
|
|
103
129
|
|
|
104
130
|
Create database subcommands:
|
|
105
131
|
╭─────────────────┬──────────────────────────────────────────╮
|
|
@@ -797,6 +823,14 @@ BTW, for some cols like time_deleted you'll need to specify a where clause so th
|
|
|
797
823
|
--page-key start --page-start 0 --page-step 50 --fixed-pages 14 --stop-pages-no-match 1 \
|
|
798
824
|
plab.db https://plab/forum/tracker.php?o=(string replace ' ' \n -- 1 4 7 10 15)&s=2&tm=-1&f=(string replace ' ' \n -- 1670 1768 60 1671 1644 1672 1111 508 555 1112 1718 1143 1717 1851 1713 1712 1775 1674 902 1675 36 1830 1803 1831 1741 1676 1677 1780 1110 1124 1784 1769 1793 1797 1804 1819 1825 1836 1842 1846 1857 1861 1867 1451 1788 1789 1792 1798 1805 1820 1826 1837 1843 1847 1856 1862 1868 284 1853 1823 1800 1801 1719 997 1818 1849 1711 1791 1762)
|
|
799
825
|
|
|
826
|
+
Recursively add every link on a site (glob excludes prune subtrees from the crawl)
|
|
827
|
+
|
|
828
|
+
library links-add links.db --recursive https://example.com/docs/ --path-exclude '*/tags/*'
|
|
829
|
+
|
|
830
|
+
Add every archived link for a site from the Internet Archive CDX index
|
|
831
|
+
|
|
832
|
+
library links-add links.db --webcache https://example.com/docs/
|
|
833
|
+
|
|
800
834
|
|
|
801
835
|
</details>
|
|
802
836
|
|
|
@@ -1130,6 +1164,31 @@ BTW, for some cols like time_deleted you'll need to specify a where clause so th
|
|
|
1130
1164
|
library links https://en.wikipedia.org/wiki/List_of_bacon_dishes --path-include https://en.wikipedia.org/wiki/ --after-include famous
|
|
1131
1165
|
https://en.wikipedia.org/wiki/Omelette
|
|
1132
1166
|
|
|
1167
|
+
Download the filtered links. Internet Archive details pages use the Internet Archive downloader and preserve all original files:
|
|
1168
|
+
|
|
1169
|
+
library extract-links --download https://readrare.com/
|
|
1170
|
+
|
|
1171
|
+
Mirror a site recursively. Only links within the same domain and parent directory as the given
|
|
1172
|
+
path are followed; links pointing elsewhere are downloaded but not followed. Includes/excludes
|
|
1173
|
+
accept globs, so you can prune whole subtrees while crawling:
|
|
1174
|
+
|
|
1175
|
+
library links --recursive --download https://example.com/docs/
|
|
1176
|
+
library links -R --download https://example.com/docs/ --path-exclude '*/tag/*' '*/tags/*'
|
|
1177
|
+
|
|
1178
|
+
Extract links from a web archive CDX index instead of crawling live pages. Internet Archive
|
|
1179
|
+
Wayback snapshots are emitted by default. Wayback URLs are collapsed to their original
|
|
1180
|
+
archived URL while crawling: sibling pages that only exist under a different timestamp are
|
|
1181
|
+
still followed, but multiple captures of the same page are collapsed so only one copy of
|
|
1182
|
+
each page is downloaded. Use --webcache-from/--webcache-to to target a time period:
|
|
1183
|
+
|
|
1184
|
+
library links --webcache https://example.com/docs/
|
|
1185
|
+
library links --webcache --recursive --download https://example.com/docs/
|
|
1186
|
+
library links --webcache --webcache-source cc https://example.com/docs/
|
|
1187
|
+
library links --webcache --webcache-from 2020 --webcache-to 2021 https://example.com/docs/
|
|
1188
|
+
|
|
1189
|
+
Common tracking and analytics URLs, including Google Tag Manager and Google Analytics,
|
|
1190
|
+
are excluded by default. Use --path-exclude to replace the default exclusions when needed.
|
|
1191
|
+
|
|
1133
1192
|
Read from local clipboard and filter out links based on nearby plain text
|
|
1134
1193
|
|
|
1135
1194
|
library links --local-html (cb -t text/html | psub) --after-exclude paranormal spooky horror podcast tech fantasy supernatural lecture sport
|
|
@@ -2320,7 +2379,7 @@ Inspired somewhat by https://nikkhokkho.sourceforge.io/?page=FileOptimizer
|
|
|
2320
2379
|
| /home/xk/github/xk/lb/.ruff_cache/ | 19.5 kB | 100 |
|
|
2321
2380
|
| /home/xk/github/xk/lb/.gitattributes | 119 Bytes | |
|
|
2322
2381
|
| /home/xk/github/xk/lb/.mypy_cache/ | 280 Bytes | 4 |
|
|
2323
|
-
| /home/xk/github/xk/lb/.
|
|
2382
|
+
| /home/xk/github/xk/lb/.venv | 15 Bytes | |
|
|
2324
2383
|
|
|
2325
2384
|
Only include files with a specific depth
|
|
2326
2385
|
|
|
@@ -2493,6 +2552,17 @@ Inspired somewhat by https://nikkhokkho.sourceforge.io/?page=FileOptimizer
|
|
|
2493
2552
|
library download dl.db --include https://www.youtube.com/watch?v=YE7VzlLtp-4
|
|
2494
2553
|
library download dl.db -s https://www.youtube.com/watch?v=YE7VzlLtp-4 # equivalent
|
|
2495
2554
|
|
|
2555
|
+
Recursively download a site (filesystem profile). Only links within the same domain and
|
|
2556
|
+
parent directory as the seed are followed; other links are downloaded but not followed.
|
|
2557
|
+
|
|
2558
|
+
library download links.db --filesystem --recursive --prefix ~/mirror/ https://example.com/docs/
|
|
2559
|
+
|
|
2560
|
+
Download a site's archived pages from the Internet Archive Wayback Machine using the CDX API.
|
|
2561
|
+
`--webcache` implies `--links`; add `--recursive` to also parse the archived pages for
|
|
2562
|
+
further links:
|
|
2563
|
+
|
|
2564
|
+
library download links.db --filesystem --webcache --prefix ~/mirror/ https://example.com/docs/
|
|
2565
|
+
|
|
2496
2566
|
Maximizing the variety of subdomains
|
|
2497
2567
|
|
|
2498
2568
|
library download photos.db --photos --image --sort "ROW_NUMBER() OVER ( PARTITION BY SUBSTR(m.path, INSTR(m.path, '//') + 2, INSTR( SUBSTR(m.path, INSTR(m.path, '//') + 2), '/') - 1) )"
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
Metadata-Version: 2.
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
2
|
Name: library
|
|
3
|
-
Version: 3.2.
|
|
3
|
+
Version: 3.2.11
|
|
4
4
|
Summary: xk media library
|
|
5
|
-
Author
|
|
5
|
+
Author: Jacob Chapman
|
|
6
|
+
Author-email: Jacob Chapman <7908073+chapmanjacobd@users.noreply.github.com>
|
|
6
7
|
License: BSD 3-Clause License
|
|
7
8
|
|
|
8
9
|
Copyright (c) 2024, Jacob Chapman
|
|
@@ -31,16 +32,10 @@ License: BSD 3-Clause License
|
|
|
31
32
|
CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
|
|
32
33
|
OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
|
33
34
|
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
34
|
-
|
|
35
|
-
Project-URL: documentation, https://github.com/chapmanjacobd/library#usage
|
|
36
|
-
Project-URL: homepage, https://github.com/chapmanjacobd/library#readme
|
|
37
|
-
Project-URL: repository, https://github.com/chapmanjacobd/library/
|
|
38
|
-
Requires-Python: >=3.12
|
|
39
35
|
Requires-Dist: beautifulsoup4>=4.10.0
|
|
40
36
|
Requires-Dist: sqlite-utils>=3.38
|
|
41
37
|
Requires-Dist: ipython>=9.0.0
|
|
42
38
|
Requires-Dist: ffmpeg-python
|
|
43
|
-
Requires-Dist: gallery-dl
|
|
44
39
|
Requires-Dist: yt-dlp[default]
|
|
45
40
|
Requires-Dist: natsort
|
|
46
41
|
Requires-Dist: charset-normalizer
|
|
@@ -61,49 +56,56 @@ Requires-Dist: screeninfo
|
|
|
61
56
|
Requires-Dist: tabulate
|
|
62
57
|
Requires-Dist: tinytag
|
|
63
58
|
Requires-Dist: tldextract
|
|
64
|
-
Requires-Dist: pyreadline3;
|
|
65
|
-
|
|
66
|
-
Requires-Dist:
|
|
67
|
-
Requires-Dist:
|
|
68
|
-
Requires-Dist:
|
|
69
|
-
|
|
70
|
-
Requires-Dist:
|
|
71
|
-
Requires-Dist:
|
|
72
|
-
Requires-Dist:
|
|
73
|
-
Requires-Dist:
|
|
74
|
-
Requires-Dist:
|
|
75
|
-
Requires-Dist:
|
|
59
|
+
Requires-Dist: pyreadline3 ; sys_platform == 'win32'
|
|
60
|
+
Requires-Dist: aiohttp ; extra == 'deluxe'
|
|
61
|
+
Requires-Dist: annoy ; extra == 'deluxe'
|
|
62
|
+
Requires-Dist: catt ; extra == 'deluxe'
|
|
63
|
+
Requires-Dist: cdx-toolkit ; extra == 'deluxe'
|
|
64
|
+
Requires-Dist: curl-cffi ; extra == 'deluxe'
|
|
65
|
+
Requires-Dist: gallery-dl ; extra == 'deluxe'
|
|
66
|
+
Requires-Dist: geopandas ; extra == 'deluxe'
|
|
67
|
+
Requires-Dist: img2pdf ; extra == 'deluxe'
|
|
68
|
+
Requires-Dist: internetarchive ; extra == 'deluxe'
|
|
69
|
+
Requires-Dist: ocrmypdf ; extra == 'deluxe'
|
|
70
|
+
Requires-Dist: openpyxl ; extra == 'deluxe'
|
|
71
|
+
Requires-Dist: paramiko ; extra == 'deluxe'
|
|
72
|
+
Requires-Dist: pdf2image ; extra == 'deluxe'
|
|
73
|
+
Requires-Dist: pillow ; extra == 'deluxe'
|
|
74
|
+
Requires-Dist: pyexiftool ; extra == 'deluxe'
|
|
75
|
+
Requires-Dist: pymcdm ; extra == 'deluxe'
|
|
76
|
+
Requires-Dist: pyvirtualdisplay ; extra == 'deluxe'
|
|
77
|
+
Requires-Dist: qbittorrent-api ; extra == 'deluxe'
|
|
78
|
+
Requires-Dist: scikit-learn ; extra == 'deluxe'
|
|
79
|
+
Requires-Dist: selenium ; extra == 'deluxe'
|
|
80
|
+
Requires-Dist: libtorrent ; python_full_version < '3.14' and extra == 'deluxe'
|
|
81
|
+
Requires-Dist: tqdm ; extra == 'deluxe'
|
|
82
|
+
Requires-Dist: wordllama>=0.2.7.post0 ; extra == 'deluxe'
|
|
83
|
+
Requires-Dist: xattr ; sys_platform != 'win32' and extra == 'deluxe'
|
|
84
|
+
Requires-Dist: black ; extra == 'dev'
|
|
85
|
+
Requires-Dist: isort ; extra == 'dev'
|
|
86
|
+
Requires-Dist: ssort ; extra == 'dev'
|
|
87
|
+
Requires-Dist: brotab ; extra == 'fat'
|
|
88
|
+
Requires-Dist: camelot-py>=0.11.0 ; extra == 'fat'
|
|
89
|
+
Requires-Dist: ghostscript ; extra == 'fat'
|
|
90
|
+
Requires-Dist: opencv-python ; extra == 'fat'
|
|
91
|
+
Requires-Dist: orjson ; extra == 'fat'
|
|
92
|
+
Requires-Dist: selenium-wire-lw ; extra == 'fat'
|
|
93
|
+
Requires-Dist: subliminal ; extra == 'fat'
|
|
94
|
+
Requires-Dist: textract-py3==2.0.1 ; extra == 'fat'
|
|
95
|
+
Requires-Dist: ruff ; extra == 'test'
|
|
96
|
+
Requires-Dist: pytest ; extra == 'test'
|
|
97
|
+
Requires-Dist: pytest-regressions ; extra == 'test'
|
|
98
|
+
Requires-Dist: freezegun ; extra == 'test'
|
|
99
|
+
Requires-Dist: pandas ; extra == 'test'
|
|
100
|
+
Requires-Dist: pyfakefs ; extra == 'test'
|
|
101
|
+
Requires-Python: >=3.12
|
|
102
|
+
Project-URL: documentation, https://github.com/chapmanjacobd/library#usage
|
|
103
|
+
Project-URL: homepage, https://github.com/chapmanjacobd/library#readme
|
|
104
|
+
Project-URL: repository, https://github.com/chapmanjacobd/library/
|
|
76
105
|
Provides-Extra: deluxe
|
|
77
|
-
|
|
78
|
-
Requires-Dist: annoy; extra == "deluxe"
|
|
79
|
-
Requires-Dist: catt; extra == "deluxe"
|
|
80
|
-
Requires-Dist: curl-cffi; extra == "deluxe"
|
|
81
|
-
Requires-Dist: geopandas; extra == "deluxe"
|
|
82
|
-
Requires-Dist: img2pdf; extra == "deluxe"
|
|
83
|
-
Requires-Dist: ocrmypdf; extra == "deluxe"
|
|
84
|
-
Requires-Dist: openpyxl; extra == "deluxe"
|
|
85
|
-
Requires-Dist: paramiko; extra == "deluxe"
|
|
86
|
-
Requires-Dist: pdf2image; extra == "deluxe"
|
|
87
|
-
Requires-Dist: pillow; extra == "deluxe"
|
|
88
|
-
Requires-Dist: PyExifTool; extra == "deluxe"
|
|
89
|
-
Requires-Dist: pymcdm; extra == "deluxe"
|
|
90
|
-
Requires-Dist: pyvirtualdisplay; extra == "deluxe"
|
|
91
|
-
Requires-Dist: qbittorrent-api; extra == "deluxe"
|
|
92
|
-
Requires-Dist: scikit-learn; extra == "deluxe"
|
|
93
|
-
Requires-Dist: selenium; extra == "deluxe"
|
|
94
|
-
Requires-Dist: libtorrent; extra == "deluxe"
|
|
95
|
-
Requires-Dist: tqdm; extra == "deluxe"
|
|
96
|
-
Requires-Dist: wordllama>=0.2.7.post0; extra == "deluxe"
|
|
97
|
-
Requires-Dist: xattr; extra == "deluxe"
|
|
106
|
+
Provides-Extra: dev
|
|
98
107
|
Provides-Extra: fat
|
|
99
|
-
|
|
100
|
-
Requires-Dist: camelot-py>=0.11.0; extra == "fat"
|
|
101
|
-
Requires-Dist: ghostscript; extra == "fat"
|
|
102
|
-
Requires-Dist: opencv-python; extra == "fat"
|
|
103
|
-
Requires-Dist: orjson; extra == "fat"
|
|
104
|
-
Requires-Dist: selenium-wire-lw; extra == "fat"
|
|
105
|
-
Requires-Dist: subliminal; extra == "fat"
|
|
106
|
-
Requires-Dist: textract-py3==2.0.1; extra == "fat"
|
|
108
|
+
Provides-Extra: test
|
|
107
109
|
Description-Content-Type: text/markdown
|
|
108
110
|
|
|
109
111
|
# library (media toolkit)
|
|
@@ -118,7 +120,9 @@ tracking online video playlists (eg. YouTube subscriptions) and scheduling brows
|
|
|
118
120
|
|
|
119
121
|
[](https://pepy.tech/project/library)
|
|
120
122
|
|
|
121
|
-
##
|
|
123
|
+
## Getting started
|
|
124
|
+
|
|
125
|
+
<details><summary>Install</summary>
|
|
122
126
|
|
|
123
127
|
Linux recommended but [Windows setup instructions](./Windows.md) available.
|
|
124
128
|
|
|
@@ -132,7 +136,31 @@ Required: `ffmpeg`
|
|
|
132
136
|
|
|
133
137
|
Some features work better with: `mpv`, `fd-find`, `fish`
|
|
134
138
|
|
|
135
|
-
|
|
139
|
+
Optional Python extras are grouped under `library[deluxe]`. This includes
|
|
140
|
+
`gallery-dl` (used by `gallery-add`), `internetarchive` (used for Internet
|
|
141
|
+
Archive downloads), and `cdx_toolkit` (used by the `--webcache`/`--wayback`
|
|
142
|
+
CDX extractor):
|
|
143
|
+
|
|
144
|
+
pip install "library[deluxe]"
|
|
145
|
+
|
|
146
|
+
Torrent metadata commands (`torrents-add` and `torrents-dump`) require the
|
|
147
|
+
`libtorrent` Python bindings. They are included by `library[deluxe]` when using
|
|
148
|
+
Python 3.12 or 3.13; Python 3.14 wheels are not available yet, so use Python
|
|
149
|
+
3.13 for torrent support.
|
|
150
|
+
|
|
151
|
+
If the PyPI wheel is unavailable for your Python or platform, these system
|
|
152
|
+
packages provide the bindings:
|
|
153
|
+
|
|
154
|
+
* Debian/Ubuntu: `sudo apt install python3-libtorrent`
|
|
155
|
+
* Fedora: `sudo dnf install rb_libtorrent-python3`
|
|
156
|
+
* macOS/Homebrew: `brew install libtorrent-rasterbar`
|
|
157
|
+
|
|
158
|
+
The Debian, Fedora, and Homebrew packages are built for their system or
|
|
159
|
+
Homebrew Python and may not be importable from a separate uv virtualenv. There
|
|
160
|
+
is no official Scoop package for the Python bindings; on Windows, use Python
|
|
161
|
+
3.13 and `pip install "library[deluxe]"`.
|
|
162
|
+
|
|
163
|
+
</details>
|
|
136
164
|
|
|
137
165
|
<details><summary>Local media</summary>
|
|
138
166
|
|
|
@@ -207,7 +235,7 @@ To stop playing press Ctrl+C in either the terminal or mpv
|
|
|
207
235
|
<details><summary>List all subcommands</summary>
|
|
208
236
|
|
|
209
237
|
$ library
|
|
210
|
-
library (v3.2.
|
|
238
|
+
library (v3.2.011; 102 subcommands)
|
|
211
239
|
|
|
212
240
|
Create database subcommands:
|
|
213
241
|
╭─────────────────┬──────────────────────────────────────────╮
|
|
@@ -905,6 +933,14 @@ BTW, for some cols like time_deleted you'll need to specify a where clause so th
|
|
|
905
933
|
--page-key start --page-start 0 --page-step 50 --fixed-pages 14 --stop-pages-no-match 1 \
|
|
906
934
|
plab.db https://plab/forum/tracker.php?o=(string replace ' ' \n -- 1 4 7 10 15)&s=2&tm=-1&f=(string replace ' ' \n -- 1670 1768 60 1671 1644 1672 1111 508 555 1112 1718 1143 1717 1851 1713 1712 1775 1674 902 1675 36 1830 1803 1831 1741 1676 1677 1780 1110 1124 1784 1769 1793 1797 1804 1819 1825 1836 1842 1846 1857 1861 1867 1451 1788 1789 1792 1798 1805 1820 1826 1837 1843 1847 1856 1862 1868 284 1853 1823 1800 1801 1719 997 1818 1849 1711 1791 1762)
|
|
907
935
|
|
|
936
|
+
Recursively add every link on a site (glob excludes prune subtrees from the crawl)
|
|
937
|
+
|
|
938
|
+
library links-add links.db --recursive https://example.com/docs/ --path-exclude '*/tags/*'
|
|
939
|
+
|
|
940
|
+
Add every archived link for a site from the Internet Archive CDX index
|
|
941
|
+
|
|
942
|
+
library links-add links.db --webcache https://example.com/docs/
|
|
943
|
+
|
|
908
944
|
|
|
909
945
|
</details>
|
|
910
946
|
|
|
@@ -1238,6 +1274,31 @@ BTW, for some cols like time_deleted you'll need to specify a where clause so th
|
|
|
1238
1274
|
library links https://en.wikipedia.org/wiki/List_of_bacon_dishes --path-include https://en.wikipedia.org/wiki/ --after-include famous
|
|
1239
1275
|
https://en.wikipedia.org/wiki/Omelette
|
|
1240
1276
|
|
|
1277
|
+
Download the filtered links. Internet Archive details pages use the Internet Archive downloader and preserve all original files:
|
|
1278
|
+
|
|
1279
|
+
library extract-links --download https://readrare.com/
|
|
1280
|
+
|
|
1281
|
+
Mirror a site recursively. Only links within the same domain and parent directory as the given
|
|
1282
|
+
path are followed; links pointing elsewhere are downloaded but not followed. Includes/excludes
|
|
1283
|
+
accept globs, so you can prune whole subtrees while crawling:
|
|
1284
|
+
|
|
1285
|
+
library links --recursive --download https://example.com/docs/
|
|
1286
|
+
library links -R --download https://example.com/docs/ --path-exclude '*/tag/*' '*/tags/*'
|
|
1287
|
+
|
|
1288
|
+
Extract links from a web archive CDX index instead of crawling live pages. Internet Archive
|
|
1289
|
+
Wayback snapshots are emitted by default. Wayback URLs are collapsed to their original
|
|
1290
|
+
archived URL while crawling: sibling pages that only exist under a different timestamp are
|
|
1291
|
+
still followed, but multiple captures of the same page are collapsed so only one copy of
|
|
1292
|
+
each page is downloaded. Use --webcache-from/--webcache-to to target a time period:
|
|
1293
|
+
|
|
1294
|
+
library links --webcache https://example.com/docs/
|
|
1295
|
+
library links --webcache --recursive --download https://example.com/docs/
|
|
1296
|
+
library links --webcache --webcache-source cc https://example.com/docs/
|
|
1297
|
+
library links --webcache --webcache-from 2020 --webcache-to 2021 https://example.com/docs/
|
|
1298
|
+
|
|
1299
|
+
Common tracking and analytics URLs, including Google Tag Manager and Google Analytics,
|
|
1300
|
+
are excluded by default. Use --path-exclude to replace the default exclusions when needed.
|
|
1301
|
+
|
|
1241
1302
|
Read from local clipboard and filter out links based on nearby plain text
|
|
1242
1303
|
|
|
1243
1304
|
library links --local-html (cb -t text/html | psub) --after-exclude paranormal spooky horror podcast tech fantasy supernatural lecture sport
|
|
@@ -2428,7 +2489,7 @@ Inspired somewhat by https://nikkhokkho.sourceforge.io/?page=FileOptimizer
|
|
|
2428
2489
|
| /home/xk/github/xk/lb/.ruff_cache/ | 19.5 kB | 100 |
|
|
2429
2490
|
| /home/xk/github/xk/lb/.gitattributes | 119 Bytes | |
|
|
2430
2491
|
| /home/xk/github/xk/lb/.mypy_cache/ | 280 Bytes | 4 |
|
|
2431
|
-
| /home/xk/github/xk/lb/.
|
|
2492
|
+
| /home/xk/github/xk/lb/.venv | 15 Bytes | |
|
|
2432
2493
|
|
|
2433
2494
|
Only include files with a specific depth
|
|
2434
2495
|
|
|
@@ -2601,6 +2662,17 @@ Inspired somewhat by https://nikkhokkho.sourceforge.io/?page=FileOptimizer
|
|
|
2601
2662
|
library download dl.db --include https://www.youtube.com/watch?v=YE7VzlLtp-4
|
|
2602
2663
|
library download dl.db -s https://www.youtube.com/watch?v=YE7VzlLtp-4 # equivalent
|
|
2603
2664
|
|
|
2665
|
+
Recursively download a site (filesystem profile). Only links within the same domain and
|
|
2666
|
+
parent directory as the seed are followed; other links are downloaded but not followed.
|
|
2667
|
+
|
|
2668
|
+
library download links.db --filesystem --recursive --prefix ~/mirror/ https://example.com/docs/
|
|
2669
|
+
|
|
2670
|
+
Download a site's archived pages from the Internet Archive Wayback Machine using the CDX API.
|
|
2671
|
+
`--webcache` implies `--links`; add `--recursive` to also parse the archived pages for
|
|
2672
|
+
further links:
|
|
2673
|
+
|
|
2674
|
+
library download links.db --filesystem --webcache --prefix ~/mirror/ https://example.com/docs/
|
|
2675
|
+
|
|
2604
2676
|
Maximizing the variety of subdomains
|
|
2605
2677
|
|
|
2606
2678
|
library download photos.db --photos --image --sort "ROW_NUMBER() OVER ( PARTITION BY SUBSTR(m.path, INSTR(m.path, '//') + 2, INSTR( SUBSTR(m.path, INSTR(m.path, '//') + 2), '/') - 1) )"
|
|
@@ -2,11 +2,10 @@ import argparse, importlib, os, sys, textwrap
|
|
|
2
2
|
|
|
3
3
|
from tabulate import tabulate
|
|
4
4
|
|
|
5
|
+
from library._version import __version__
|
|
5
6
|
from library.utils import argparse_utils, iterables
|
|
6
7
|
from library.utils.log_utils import log
|
|
7
8
|
|
|
8
|
-
__version__ = "3.2.007"
|
|
9
|
-
|
|
10
9
|
progs = {
|
|
11
10
|
"Create database subcommands": {
|
|
12
11
|
"fs_add": "Add local media",
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Copyright (c) 2026, Jacob Chapman
|
|
2
|
+
|
|
3
|
+
from importlib.metadata import PackageNotFoundError
|
|
4
|
+
from importlib.metadata import version as installed_version
|
|
5
|
+
from pathlib import Path
|
|
6
|
+
import tomllib
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def get_version() -> str:
|
|
10
|
+
pyproject_path = Path(__file__).resolve().parents[1] / "pyproject.toml"
|
|
11
|
+
if pyproject_path.is_file():
|
|
12
|
+
with pyproject_path.open("rb") as pyproject_file:
|
|
13
|
+
project_version = tomllib.load(pyproject_file)["project"].get("version")
|
|
14
|
+
if isinstance(project_version, str):
|
|
15
|
+
return project_version
|
|
16
|
+
message = f"Missing string project version in {pyproject_path}"
|
|
17
|
+
raise RuntimeError(message)
|
|
18
|
+
|
|
19
|
+
try:
|
|
20
|
+
return installed_version("library")
|
|
21
|
+
except PackageNotFoundError as error:
|
|
22
|
+
raise RuntimeError("Unable to determine the library version") from error
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
__version__ = get_version()
|
|
@@ -2,9 +2,6 @@ import os
|
|
|
2
2
|
from pathlib import Path
|
|
3
3
|
from types import ModuleType
|
|
4
4
|
|
|
5
|
-
import gallery_dl
|
|
6
|
-
from gallery_dl.job import Job
|
|
7
|
-
|
|
8
5
|
from library.mediadb import db_media, db_playlists
|
|
9
6
|
from library.utils import consts, printing, strings
|
|
10
7
|
from library.utils.log_utils import log
|
|
@@ -142,52 +139,57 @@ def download(args, m):
|
|
|
142
139
|
)
|
|
143
140
|
|
|
144
141
|
|
|
145
|
-
|
|
146
|
-
|
|
142
|
+
def url_job_class(gallery_dl):
|
|
143
|
+
# gallery_dl is an optional (deluxe) dependency, so the Job base class
|
|
144
|
+
# can only be resolved once gallery_dl has been imported
|
|
145
|
+
class UrlJob(gallery_dl.job.Job):
|
|
146
|
+
resolve = 1 # depth of queue resolution
|
|
147
147
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
148
|
+
def __init__(self, url, parent=None, resolve=None):
|
|
149
|
+
super().__init__(url, parent)
|
|
150
|
+
self.results = []
|
|
151
|
+
self.visited = set()
|
|
152
|
+
if resolve is not None:
|
|
153
|
+
self.resolve = resolve
|
|
154
154
|
|
|
155
|
-
|
|
156
|
-
|
|
155
|
+
if self.resolve > 0:
|
|
156
|
+
self.handle_queue = self.handle_queue_resolve
|
|
157
157
|
|
|
158
|
-
|
|
159
|
-
|
|
158
|
+
def handle_url(self, url, kwdict):
|
|
159
|
+
self.results.append((url, kwdict))
|
|
160
160
|
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
161
|
+
def handle_queue(self, url, kwdict):
|
|
162
|
+
# unresolved queue entry
|
|
163
|
+
self.results.append((url, kwdict))
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
165
|
+
def handle_queue_resolve(self, url, kwdict):
|
|
166
|
+
if url in self.visited:
|
|
167
|
+
return
|
|
168
|
+
self.visited.add(url)
|
|
169
169
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
170
|
+
cls = kwdict.get("_extractor")
|
|
171
|
+
if cls:
|
|
172
|
+
extr = cls.from_url(url)
|
|
173
|
+
else:
|
|
174
|
+
extr = self.extractor.find(url)
|
|
175
175
|
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
176
|
+
if not extr:
|
|
177
|
+
self.results.append((url, kwdict))
|
|
178
|
+
return
|
|
179
179
|
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
180
|
+
job = self.__class__(extr, self, self.resolve - 1)
|
|
181
|
+
job.results = self.results # shared accumulator
|
|
182
|
+
job.visited = self.visited # shared visited set
|
|
183
|
+
job.run()
|
|
184
|
+
|
|
185
|
+
return UrlJob
|
|
184
186
|
|
|
185
187
|
|
|
186
188
|
def get_playlist_metadata(args, playlist_path):
|
|
187
189
|
gallery_dl = load_module_level_gallery_dl(args)
|
|
188
190
|
|
|
189
191
|
added_media_count = 0
|
|
190
|
-
job =
|
|
192
|
+
job = url_job_class(gallery_dl)(playlist_path)
|
|
191
193
|
job.run()
|
|
192
194
|
|
|
193
195
|
is_playlist = len(job.results) > 1
|
|
@@ -130,6 +130,7 @@ To compensate for this the script will only continue fetching pages until there
|
|
|
130
130
|
)
|
|
131
131
|
|
|
132
132
|
arggroups.filter_links(parser)
|
|
133
|
+
arggroups.spider(parser)
|
|
133
134
|
|
|
134
135
|
arggroups.requests(parser)
|
|
135
136
|
arggroups.selenium(parser)
|
|
@@ -254,6 +255,8 @@ def extractor(args, playlist_path):
|
|
|
254
255
|
new_media = set()
|
|
255
256
|
end_of_playlist = False
|
|
256
257
|
page_limit = args.backfill_pages or args.fixed_pages or args.max_pages
|
|
258
|
+
if args.recursive or args.webcache:
|
|
259
|
+
page_limit = 1
|
|
257
260
|
|
|
258
261
|
if args.confirm_ready:
|
|
259
262
|
if args.selenium:
|
|
@@ -283,8 +286,14 @@ def extractor(args, playlist_path):
|
|
|
283
286
|
page_known = set()
|
|
284
287
|
page_new = {}
|
|
285
288
|
try:
|
|
286
|
-
|
|
289
|
+
link_iter = (
|
|
290
|
+
extract_links.crawl(args, [page_path])
|
|
291
|
+
if args.recursive
|
|
292
|
+
else extract_links.iter_links(args, page_path)
|
|
293
|
+
)
|
|
294
|
+
for link_dict in link_iter:
|
|
287
295
|
link = link_dict.pop("link")
|
|
296
|
+
link_dict.pop("mime", None)
|
|
288
297
|
|
|
289
298
|
if link == args.stop_link:
|
|
290
299
|
end_of_playlist = True
|
|
@@ -302,7 +311,7 @@ def extractor(args, playlist_path):
|
|
|
302
311
|
printing.print_overwrite(f"Page {page_count} link scan: {len(page_new)} new [{len(page_known)} known]")
|
|
303
312
|
print(file=sys.stderr)
|
|
304
313
|
|
|
305
|
-
if not (args.backfill_pages or args.fixed_pages):
|
|
314
|
+
if not args.recursive and not (args.backfill_pages or args.fixed_pages):
|
|
306
315
|
if (args.stop_known and len(page_known) > args.stop_known) or (
|
|
307
316
|
args.stop_new and args.stop_new >= len(page_new)
|
|
308
317
|
):
|
|
@@ -35,6 +35,7 @@ def parse_args():
|
|
|
35
35
|
arggroups.requests(parser)
|
|
36
36
|
arggroups.selenium(parser)
|
|
37
37
|
arggroups.filter_links(parser)
|
|
38
|
+
arggroups.spider(parser)
|
|
38
39
|
|
|
39
40
|
parser.add_argument("--same-domain", action="store_true", help="Choose a random domain to focus on")
|
|
40
41
|
|
|
@@ -88,6 +89,9 @@ def download(args=None) -> None:
|
|
|
88
89
|
db_playlists.create(args)
|
|
89
90
|
db_media.create(args)
|
|
90
91
|
|
|
92
|
+
if args.recursive or args.webcache:
|
|
93
|
+
args.links = True
|
|
94
|
+
|
|
91
95
|
m_columns = db_utils.columns(args, "media")
|
|
92
96
|
|
|
93
97
|
if "limit" in args.defaults and "media" in args.db.table_names() and "webpath" in m_columns:
|
|
@@ -118,7 +122,7 @@ def download(args=None) -> None:
|
|
|
118
122
|
media_printer.media_printer(args, media)
|
|
119
123
|
return
|
|
120
124
|
|
|
121
|
-
get_inner_urls = iterables.return_unique(extract_links.
|
|
125
|
+
get_inner_urls = iterables.return_unique(extract_links.iter_links, lambda d: d["link"])
|
|
122
126
|
if args.safe and args.profile == DBType.image:
|
|
123
127
|
gallery_backend.load_module_level_gallery_dl(args)
|
|
124
128
|
for m in media:
|
|
@@ -180,7 +184,11 @@ def download(args=None) -> None:
|
|
|
180
184
|
if args.links:
|
|
181
185
|
dl_paths = []
|
|
182
186
|
try:
|
|
183
|
-
|
|
187
|
+
if args.recursive:
|
|
188
|
+
link_iter = extract_links.crawl(args, [original_path])
|
|
189
|
+
else:
|
|
190
|
+
link_iter = get_inner_urls(args, original_path)
|
|
191
|
+
for link_dict in link_iter:
|
|
184
192
|
dl_paths.append(link_dict["link"])
|
|
185
193
|
except requests.HTTPError as excinfo:
|
|
186
194
|
log.warning(
|
|
@@ -207,7 +215,7 @@ def download(args=None) -> None:
|
|
|
207
215
|
for i, dl_path in enumerate(dl_paths):
|
|
208
216
|
error = None
|
|
209
217
|
try:
|
|
210
|
-
local_path = web.
|
|
218
|
+
local_path = web.download_link(args, dl_path)
|
|
211
219
|
except RuntimeError as excinfo:
|
|
212
220
|
local_path = None
|
|
213
221
|
error = str(excinfo)
|
|
@@ -112,7 +112,7 @@ def gen_arg_groups(args):
|
|
|
112
112
|
else:
|
|
113
113
|
log.warning("No images found in %s", path)
|
|
114
114
|
elif path_utils.ext(path) in consts.ARCHIVE_EXTENSIONS:
|
|
115
|
-
archive_dir = processes.unar_delete(path)
|
|
115
|
+
archive_dir, _ = processes.unar_delete(path)
|
|
116
116
|
archive_image_paths = shell_utils.rglob(str(archive_dir), DEFAULT_EXTENSIONS, quiet=True)[0]
|
|
117
117
|
if archive_image_paths:
|
|
118
118
|
yield archive_image_paths
|
|
@@ -52,7 +52,7 @@ def process_path(args, path) -> str | None:
|
|
|
52
52
|
if args.simulate:
|
|
53
53
|
log.info("Extracting images %s", path)
|
|
54
54
|
else:
|
|
55
|
-
archive_dir = processes.unar_delete(path)
|
|
55
|
+
archive_dir, _ = processes.unar_delete(path)
|
|
56
56
|
image_paths = shell_utils.rglob(str(archive_dir), consts.IMAGE_EXTENSIONS, quiet=True)[0]
|
|
57
57
|
for p in image_paths:
|
|
58
58
|
process_path(args, p)
|