replace libtorrent with torf (#506)

torf is a python library which deals with torrents, magnets and more. It
is a python only library and has no C backend.

The main reason for replacing it is that libtorrent doesn't have
bindings for pyhton 3.14, which is now the default on arch (I use arch
btw.)

---

Since I don't have a torrent downloader, someone should verify that this
still works (:

Maybe one should add tests for it as well :D

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

* **Chores**
* Replaced the torrent parsing library and updated project dependency
accordingly.
  * Updated container build to remove the now-unused OS package.

* **Bug Fixes**
* Improved reliability of torrent info extraction during magnet and
fallback handling.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Marcel Hellwig
2026-05-01 16:24:34 +02:00
committed by GitHub
parent f5253990e0
commit c46239db86
4 changed files with 603 additions and 561 deletions

View File

@@ -13,7 +13,7 @@ RUN env PUBLIC_VERSION=${VERSION} PUBLIC_API_URL=${BASE_PATH} BASE_PATH=${BASE_P
FROM ghcr.io/astral-sh/uv:python3.13-trixie-slim AS base
RUN apt-get update && \
apt-get install -y ca-certificates bash libtorrent21 gcc bc locales postgresql media-types mailcap curl gzip unzip tar 7zip bzip2 unar gosu && \
apt-get install -y ca-certificates bash gcc bc locales postgresql media-types mailcap curl gzip unzip tar 7zip bzip2 unar gosu && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*

View File

@@ -6,9 +6,9 @@ import shutil
from pathlib import Path, UnsupportedOperation
import bencoder
import libtorrent
import patoolib
import requests
import torf
from pathvalidate import sanitize_filename
from requests.exceptions import InvalidSchema
@@ -142,7 +142,7 @@ def get_torrent_hash(torrent: IndexerQueryResult) -> str:
if torrent.download_url.startswith("magnet:"):
log.info(f"Parsing torrent with magnet URL: {torrent.title}")
log.debug(f"Magnet URL: {torrent.download_url}")
torrent_hash = str(libtorrent.parse_magnet_uri(torrent.download_url).info_hash)
torrent_hash = torf.Magnet.from_string(torrent.download_url).infohash
else:
# downloading the torrent file
log.info(f"Downloading .torrent file of torrent: {torrent.title}")
@@ -157,7 +157,7 @@ def get_torrent_hash(torrent: IndexerQueryResult) -> str:
session=requests.Session(),
timeout=MediaManagerConfig().indexers.prowlarr.timeout_seconds,
)
return str(libtorrent.parse_magnet_uri(final_url).info_hash)
return torf.Magnet.from_string(final_url).infohash
except Exception:
log.exception("Failed to download torrent file")
raise

View File

@@ -34,9 +34,9 @@ dependencies = [
"pillow>=11.3.0",
"sabnzbd-api>=0.1.2",
"transmission-rpc>=7.0.11",
"libtorrent>=2.0.11",
"pathvalidate>=3.3.1",
"asgi-correlation-id>=4.3.4",
"torf>=4.3.1",
]
[dependency-groups]

1154
uv.lock generated
View File

File diff suppressed because it is too large Load Diff