Add systemd start/stop for transmission.service
This commit is contained in:
		
							parent
							
								
									385694da91
								
							
						
					
					
						commit
						66acf6b421
					
				
					 7 changed files with 85 additions and 92 deletions
				
			
		|  | @ -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" | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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 | ||||
|  |  | |||
|  | @ -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")}, | ||||
|     ) | ||||
|  |  | |||
							
								
								
									
										24
									
								
								src/torrent_downloader/systemd.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/torrent_downloader/systemd.py
									
										
									
									
									
										Normal 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 | ||||
|  | @ -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> | ||||
|  |  | |||
							
								
								
									
										9
									
								
								templates/transmission.html
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								templates/transmission.html
									
										
									
									
									
										Normal 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 %} | ||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue