Add systemd start/stop for transmission.service

This commit is contained in:
Vladan Popovic 2024-10-27 01:39:20 +02:00
parent 385694da91
commit 66acf6b421
7 changed files with 85 additions and 92 deletions

View file

@ -1,7 +1,7 @@
[project]
name = "torrent-downloader"
version = "0.1.0"
description = "Add your description here"
version = "0.1.1"
description = "Web interface for searching and downloading torrents"
authors = [
{ name = "Vladan Popovic", email = "vladanovic@gmail.com" }
]
@ -12,6 +12,7 @@ dependencies = [
"fastapi>=0.114.2",
"jinja2>=3.1.4",
"cinemagoer>=2023.5.1",
"dbus-python>=1.3.2",
]
readme = "README.md"
requires-python = ">= 3.8"

View file

@ -11,92 +11,45 @@
-e file:.
annotated-types==0.7.0
# via pydantic
anyio==4.4.0
# via starlette
asttokens==2.4.1
# via stack-data
certifi==2024.8.30
# via requests
charset-normalizer==3.3.2
# via requests
cinemagoer==2023.5.1
# via torrent-downloader
click==8.1.7
# via uvicorn
dbus-python==1.3.2
decorator==5.1.1
# via ipython
executing==2.1.0
# via stack-data
fastapi==0.114.2
# via torrent-downloader
greenlet==3.1.0
# via sqlalchemy
h11==0.14.0
# via uvicorn
idna==3.8
# via anyio
# via requests
ipython==8.27.0
jedi==0.19.1
# via ipython
jinja2==3.1.4
# via torrent-downloader
lxml==5.3.0
# via cinemagoer
# via tpblite
markupsafe==2.1.5
# via jinja2
matplotlib-inline==0.1.7
# via ipython
parso==0.8.4
# via jedi
pexpect==4.9.0
# via ipython
prompt-toolkit==3.0.47
# via ipython
ptyprocess==0.7.0
# via pexpect
pure-eval==0.2.3
# via stack-data
pydantic==2.8.2
# via fastapi
# via pydantic-settings
pydantic-core==2.20.1
# via pydantic
pydantic-settings==2.4.0
# via torrent-downloader
pygments==2.18.0
# via ipython
python-dotenv==1.0.1
# via pydantic-settings
requests==2.32.3
# via transmission-rpc
six==1.16.0
# via asttokens
sniffio==1.3.1
# via anyio
sqlalchemy==2.0.34
# via cinemagoer
stack-data==0.6.3
# via ipython
starlette==0.38.5
# via fastapi
tpblite==0.8.0
# via torrent-downloader
traitlets==5.14.3
# via ipython
# via matplotlib-inline
transmission-rpc==7.0.11
# via torrent-downloader
typing-extensions==4.12.2
# via fastapi
# via pydantic
# via pydantic-core
# via sqlalchemy
# via transmission-rpc
urllib3==2.2.2
# via requests
uvicorn==0.30.6
wcwidth==0.2.13
# via prompt-toolkit

View file

@ -11,55 +11,26 @@
-e file:.
annotated-types==0.7.0
# via pydantic
anyio==4.4.0
# via starlette
certifi==2024.8.30
# via requests
charset-normalizer==3.3.2
# via requests
cinemagoer==2023.5.1
# via torrent-downloader
dbus-python==1.3.2
fastapi==0.114.2
# via torrent-downloader
greenlet==3.1.0
# via sqlalchemy
idna==3.8
# via anyio
# via requests
jinja2==3.1.4
# via torrent-downloader
lxml==5.3.0
# via cinemagoer
# via tpblite
markupsafe==2.1.5
# via jinja2
pydantic==2.8.2
# via fastapi
# via pydantic-settings
pydantic-core==2.20.1
# via pydantic
pydantic-settings==2.4.0
# via torrent-downloader
python-dotenv==1.0.1
# via pydantic-settings
requests==2.32.3
# via transmission-rpc
sniffio==1.3.1
# via anyio
sqlalchemy==2.0.34
# via cinemagoer
starlette==0.38.5
# via fastapi
tpblite==0.8.0
# via torrent-downloader
transmission-rpc==7.0.11
# via torrent-downloader
typing-extensions==4.12.2
# via fastapi
# via pydantic
# via pydantic-core
# via sqlalchemy
# via transmission-rpc
urllib3==2.2.2
# via requests

View file

@ -3,12 +3,13 @@ import urllib.parse
import transmission_rpc
from fastapi import Depends, FastAPI, Request
from fastapi.responses import HTMLResponse, RedirectResponse
from fastapi.responses import HTMLResponse
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from torrent_downloader.client import TorrentDownloader
from torrent_downloader.imdb import search_string_from_url
from torrent_downloader.systemd import Systemd
app = FastAPI()
app.mount("/static", StaticFiles(directory="static"), name="static")
@ -19,8 +20,16 @@ def get_downloader() -> TorrentDownloader:
return TorrentDownloader()
def get_active_torrents(downloader=get_downloader()) -> list[transmission_rpc.Torrent]:
return [t for t in downloader.get_active_torrents() if t.format_eta() != "not available"]
def get_systemd() -> Systemd:
return Systemd()
def get_active_torrents(
downloader=get_downloader(),
) -> list[transmission_rpc.Torrent]:
return [
t for t in downloader.get_active_torrents() if t.format_eta().lower() != "not available"
]
def hx(func):
@ -41,13 +50,8 @@ def hx(func):
@app.get("/")
async def index(_: Request):
return RedirectResponse("/search")
@app.get("/search", response_class=HTMLResponse)
@hx
async def search_for_torrents(request: Request):
async def index(request: Request):
return templates.TemplateResponse(request=request, name="search.html")
@ -70,7 +74,9 @@ async def download(request: Request, downloader=Depends(get_downloader)):
downloader.download_magnet(magnet)
active = downloader.get_active_torrents()
return templates.TemplateResponse(
request=request, name="active_torrents.html", context={"torrents": active}
request=request,
name="active_torrents.html",
context={"torrents": active},
)
@ -78,5 +84,34 @@ async def download(request: Request, downloader=Depends(get_downloader)):
@hx
async def active(request: Request, active=Depends(get_active_torrents)):
return templates.TemplateResponse(
request=request, name="active_torrents.html", context={"torrents": active}
request=request,
name="active_torrents.html",
context={"torrents": active},
)
@app.get("/transmission", response_class=HTMLResponse)
@hx
async def transmission_status(request: Request, systemd=Depends(get_systemd)):
return templates.TemplateResponse(
request=request,
name="transmission.html",
context={"is_active": systemd.service_is_active("transmission")},
)
@app.post("/transmission/{action}", response_class=HTMLResponse)
@hx
async def transmission_start(request: Request, action: str, systemd=Depends(get_systemd)):
match action:
case "start":
systemd.service_start("transmission")
case "stop":
systemd.service_stop("transmission")
case _:
return 404
return templates.TemplateResponse(
request=request,
name="transmission.html",
context={"is_active": systemd.service_is_active("transmission")},
)

View file

@ -0,0 +1,24 @@
import dbus
class Systemd:
def __init__(self):
self.bus = dbus.SessionBus()
self.systemd = self.bus.get_object(
"org.freedesktop.systemd1",
"/org/freedesktop/systemd1",
)
self.manager = dbus.Interface(self.systemd, "org.freedesktop.systemd1.Manager")
def service_start(self, service: str):
return self.manager.StartUnit(f"{service}.service", "replace")
def service_stop(self, service: str):
return self.manager.StopUnit(f"{service}.service", "replace")
def service_is_active(self, service: str):
try:
self.manager.GetUnit(service)
return True
except dbus.exceptions.DBusException:
return False

View file

@ -5,7 +5,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Search and download torrents directly to mediacenter</title>
<script src="https://unpkg.com/htmx.org@2.0.0" integrity="sha384-wS5l5IKJBvK6sPTKa2WZ1js3d947pvWXbPJ1OmWfEuxLgeHcEbjUUA5i9V5ZkpCw" crossorigin="anonymous"></script>
<link href="{{ url_for('static', path='/style.css') }}" rel="stylesheet">
<link href="/static/style.css" rel="stylesheet">
</head>
<body>
<menu>

View file

@ -0,0 +1,9 @@
{% block content %}
{% if is_active %}
<h3>Transmission is running!</h3>
<button hx-post="/transmission/stop" hx-target="#content">Stop now!</button>
{% else %}
<h3>Transmission is stopped!</h3>
<button hx-post="/transmission/start" hx-target="#content">Start now!</button>
{% endif %}
{% endblock %}