Skip to content

Commit 4bbb060

Browse files
committed
wip: allocate-torrents
1 parent b9d0ae3 commit 4bbb060

32 files changed

+1425
-534
lines changed

pdm.lock

Lines changed: 461 additions & 424 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

pyproject.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,11 @@ deluxe = [
5050
"PyExifTool",
5151
"pymcdm",
5252
"pyvirtualdisplay",
53+
"qbittorrent-api",
5354
"scikit-learn",
5455
"selenium-wire",
5556
"subliminal",
57+
"torrentool",
5658
"tqdm",
5759
"wordllama>=0.2.7.post0",
5860
"xattr",

tests/createdb/test_computer_add.py

Whitespace-only changes.

tests/createdb/test_computers_add.py

Whitespace-only changes.

tests/createdb/test_torrent_add.py

Whitespace-only changes.

tests/multidb/test_allocate_torrents.py

Whitespace-only changes.

xklb/__main__.py

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"nicotine_import": "Import paths from nicotine+",
2525
"places_import": "Import places of interest (POIs)",
2626
"row_add": "Add arbitrary data to SQLite",
27-
"computer_add": "Add computer info to SQLite",
27+
"computers_add": "Add computer info to SQLite",
28+
"torrents_add": "Add torrent info to SQLite",
2829
},
2930
"Text subcommands": {
3031
"cluster_sort": "Sort text and images by similarity",
@@ -73,10 +74,13 @@
7374
"process_text": "Shrink documents to HTML+AV1 image format (requires Calibre)",
7475
"images_to_pdf": "Convert folders of images into image PDFs",
7576
"pdf_edit": "Apply brightness, contrast, saturation, and sharpness adjustments to PDFs",
77+
"torrents_start": "Start torrents (qBittorrent-nox)",
78+
"torrents_stop": "Stop torrents (qBittorrent-nox)",
7679
},
7780
"Multi-database subcommands": {
7881
"merge_dbs": "Merge SQLite databases",
7982
"copy_play_counts": "Copy play history",
83+
"allocate_torrents": "Use computers.db and torrents.db to allocate torrents",
8084
},
8185
"Filesystem Database subcommands": {
8286
"disk_usage": "Show disk usage",
@@ -121,6 +125,7 @@
121125
"gallery_update": "Update online gallery media",
122126
"links_update": "Update a link-scraping database",
123127
"reddit_update": "Update reddit media",
128+
"computers_update": "Update computer stats",
124129
},
125130
"Misc subcommands": {
126131
"export_text": "Export HTML files from SQLite databases",
@@ -152,9 +157,10 @@ def print_help(parser) -> None:
152157

153158

154159
modules = {
155-
"xklb.createdb.computer_add.computer_add": ["pc-add", "ssh-add"],
156-
"xklb.createdb.fs_add.fs_add": ["x", "extract"],
157-
"xklb.createdb.fs_add.fs_update": ["xu"],
160+
"xklb.createdb.computers_add.computers_add": ["computer-add", "pc-add", "ssh-add"],
161+
"xklb.createdb.computers_add.computers_update": ["computer-update", "pc-update", "ssh-update"],
162+
"xklb.createdb.fs_add.fs_add": ["filesystem-add", "x", "extract"],
163+
"xklb.createdb.fs_add.fs_update": ["filesystem-update", "xu"],
158164
"xklb.createdb.gallery_add.gallery_add": ["gdl-add", "ga"],
159165
"xklb.createdb.gallery_add.gallery_update": ["gdl-update", "gu"],
160166
"xklb.createdb.hn_add.hacker_news_add": ["hn-add"],
@@ -171,6 +177,7 @@ def print_help(parser) -> None:
171177
"xklb.createdb.tabs_add.tabs_add": [],
172178
"xklb.createdb.tabs_add.tabs_shuffle": [],
173179
"xklb.createdb.tildes.tildes": [],
180+
"xklb.createdb.torrents_add.torrents_add": ["torrent-add"],
174181
"xklb.createdb.tube_add.tube_add": ["ta", "dladd", "da"],
175182
"xklb.createdb.tube_add.tube_update": ["dlupdate", "tu"],
176183
"xklb.createdb.web_add.web_add": ["web-dir-add"],
@@ -218,10 +225,13 @@ def print_help(parser) -> None:
218225
"xklb.mediafiles.process_text.process_text": ["text-process"],
219226
"xklb.mediafiles.images_to_pdf.images_to_pdf": ["images2pdf"],
220227
"xklb.mediafiles.pdf_edit.pdf_edit": [],
228+
"xklb.mediafiles.torrents_start.torrents_start": ["torrent-start"],
229+
"xklb.mediafiles.torrents_stop.torrents_stop": ["torrent-stop"],
221230
"xklb.misc.dedupe_czkawka.czkawka_dedupe": ["dedupe-czkawka"],
222231
"xklb.misc.export_text.export_text": [],
223232
"xklb.multidb.copy_play_counts.copy_play_counts": [],
224233
"xklb.multidb.merge_dbs.merge_dbs": ["merge-db"],
234+
"xklb.multidb.allocate_torrents.allocate_torrents": [],
225235
"xklb.playback.links_open.links_open": ["open-links"],
226236
"xklb.playback.play_actions.media": [],
227237
"xklb.playback.play_actions.filesystem": ["fs", "open"],

xklb/createdb/computer_add.py

Lines changed: 0 additions & 65 deletions
This file was deleted.

xklb/createdb/computer_info.py

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ def get_uptime_info():
5252

5353

5454
def get_system_name():
55-
ignore_text = ['To Be Filled By O.E.M.']
55+
ignore_text = ["To Be Filled By O.E.M."]
5656
info_strings = []
5757

5858
if IS_LINUX:
@@ -217,21 +217,45 @@ def get_mem_info():
217217
}
218218

219219

220+
def find_mount_point(path):
221+
if not os.path.islink(path):
222+
path = os.path.abspath(path)
223+
elif os.path.islink(path) and os.path.lexists(os.readlink(path)):
224+
path = os.path.realpath(path)
225+
226+
while not os.path.ismount(path):
227+
path = os.path.dirname(path)
228+
if os.path.islink(path) and os.path.lexists(os.readlink(path)):
229+
path = os.path.realpath(path)
230+
return path
231+
232+
233+
def dev_name(path):
234+
dev = os.stat(path).st_dev
235+
major, minor = os.major(dev), os.minor(dev)
236+
link = os.readlink(f"/sys/dev/block/{major}:{minor}")
237+
device = os.path.basename(link)
238+
return device
239+
240+
220241
def get_mounts():
221242
disk_io = psutil.disk_io_counters(perdisk=True)
222243

223244
mounts = {}
224245
for partition in psutil.disk_partitions():
225-
if partition.mountpoint == os.sep or partition.mountpoint.startswith(("/boot",)):
246+
if partition.mountpoint in [os.sep, "/var", "/etc", "/usr"] or partition.mountpoint.startswith(
247+
("/boot", "/sysroot")
248+
):
226249
continue
227250

228251
try:
229252
usage = psutil.disk_usage(partition.mountpoint)
230253
except PermissionError: # CD-ROM, etc
254+
print(f"PermissionError: Skipping {partition.mountpoint}", file=sys.stderr)
231255
continue
232256
else:
233257
mapped_device = (
234-
os.path.realpath(partition.device) if partition.device.startswith('/dev/mapper/') else partition.device
258+
os.path.realpath(partition.device) if partition.device.startswith("/dev/mapper/") else partition.device
235259
)
236260
device_key = mapped_device.replace("\\", "/").split("/")[-1] # without /dev/ prefix
237261
io = disk_io[device_key]

xklb/createdb/computers_add.py

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import concurrent.futures, json, os
2+
from pathlib import Path
3+
4+
import paramiko
5+
6+
from xklb import usage
7+
from xklb.mediadb import db_playlists
8+
from xklb.utils import arggroups, argparse_utils, consts, db_utils, objects, remote_processes
9+
from xklb.utils.log_utils import log
10+
11+
12+
def parse_args(action, usage):
13+
parser = argparse_utils.ArgumentParser(usage=usage)
14+
arggroups.debug(parser)
15+
16+
arggroups.database(parser)
17+
if action == consts.SC.computers_add:
18+
parser.add_argument("hostnames", nargs="+", help="List of hostnames to connect to")
19+
args = parser.parse_args()
20+
arggroups.args_post(args, parser, create_db=True)
21+
return args
22+
23+
24+
def gather_system_info(hostname):
25+
with paramiko.SSHClient() as ssh:
26+
ssh.load_system_host_keys()
27+
ssh.set_missing_host_key_policy(paramiko.WarningPolicy())
28+
ssh.connect(hostname)
29+
30+
tempdir = remote_processes.ssh_tempdir(ssh) or "."
31+
xklb_dir = os.path.join(tempdir, "xklb")
32+
r = remote_processes.cmd(ssh, "mkdir", "-p", xklb_dir)
33+
34+
with ssh.open_sftp() as sftp:
35+
src = Path(__file__).parent / "computer_info.py"
36+
dst = Path(xklb_dir) / "computer_info.py"
37+
sftp.put(bytes(src), bytes(dst))
38+
39+
r = remote_processes.cmd(ssh, "python3", dst)
40+
data = json.loads(r.stdout)
41+
return data
42+
raise RuntimeError
43+
44+
45+
def log_warning_if_same_free_space(computer_info, disks):
46+
seen_free_spaces = set()
47+
for i, disk in enumerate(disks):
48+
free_space = disk["free"]
49+
if free_space in seen_free_spaces:
50+
log.warning(
51+
"%s mount %s has the same free space as another disk! You should open a ticket with this info: %s",
52+
computer_info["path"],
53+
disk["path"],
54+
disks,
55+
)
56+
else:
57+
seen_free_spaces.add(free_space)
58+
59+
60+
def computer_add(args, hostnames):
61+
with concurrent.futures.ThreadPoolExecutor() as ex:
62+
future_to_hostname = {ex.submit(gather_system_info, hostname): hostname for hostname in hostnames}
63+
64+
for future in concurrent.futures.as_completed(future_to_hostname):
65+
hostname = future_to_hostname[future]
66+
try:
67+
computer_info = future.result()
68+
except Exception:
69+
log.exception(hostname)
70+
if args.verbose >= consts.LOG_DEBUG:
71+
raise
72+
else:
73+
disks = computer_info.pop("disks")
74+
log.debug(computer_info)
75+
76+
log_warning_if_same_free_space(computer_info, disks)
77+
78+
computer_info["path"] = hostname
79+
playlists_id = db_playlists._add(args, objects.dict_filter_bool(computer_info))
80+
for disk in disks:
81+
disk = disk | {"playlists_id": playlists_id}
82+
args.db["media"].insert(disk, pk=["playlists_id", "path"], alter=True, replace=True)
83+
84+
if not args.db["media"].detect_fts():
85+
db_utils.optimize(args)
86+
87+
88+
def computers_add():
89+
args = parse_args(consts.SC.computers_add, usage.computers_add)
90+
91+
computer_add(args, args.hostnames)
92+
93+
94+
def computers_update():
95+
args = parse_args(consts.SC.computers_update, usage.computers_update)
96+
97+
computer_add(args, [d["path"] for d in args.db.query("select path from playlists")])

0 commit comments

Comments
 (0)