Major overhaul to the theme and now functioning.
This commit is contained in:
@@ -0,0 +1,43 @@
|
||||
from fastapi import APIRouter, HTTPException
|
||||
from pydantic import BaseModel
|
||||
from typing import Optional, List
|
||||
from ..downloader_manager import manager
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
class DownloadRequest(BaseModel):
|
||||
urls: List[str]
|
||||
download_images: bool = True
|
||||
download_videos: bool = True
|
||||
max_workers: int = 3
|
||||
force_overwrite: bool = False
|
||||
|
||||
class StatusResponse(BaseModel):
|
||||
active: bool
|
||||
status: str
|
||||
downloaded: int
|
||||
total: int
|
||||
speed: float
|
||||
eta: float
|
||||
current_file: str
|
||||
|
||||
@router.post("/start")
|
||||
def start_download(request: DownloadRequest):
|
||||
try:
|
||||
manager.start_download(request.urls, request.model_dump())
|
||||
return {"message": "Download started"}
|
||||
except Exception as e:
|
||||
raise HTTPException(status_code=400, detail=str(e))
|
||||
|
||||
@router.post("/cancel")
|
||||
def cancel_download():
|
||||
manager.cancel_download()
|
||||
return {"message": "Cancellation requested"}
|
||||
|
||||
@router.get("/status", response_model=StatusResponse)
|
||||
def get_status():
|
||||
return manager.progress
|
||||
|
||||
@router.get("/logs", response_model=List[str])
|
||||
def get_logs():
|
||||
return manager.logs
|
||||
@@ -1,12 +1,18 @@
|
||||
import os
|
||||
import io
|
||||
import mimetypes
|
||||
import zipfile
|
||||
import hashlib
|
||||
import shutil
|
||||
from fastapi import APIRouter, UploadFile, File, Request, Response
|
||||
from fastapi.responses import StreamingResponse
|
||||
from pydantic import BaseModel
|
||||
from ..samba_manager import SambaManager
|
||||
from ..config import settings
|
||||
import os
|
||||
import io
|
||||
import mimetypes
|
||||
import zipfile
|
||||
|
||||
# CBZ Cache Configuration
|
||||
CACHE_DIR = "temp_cbz"
|
||||
os.makedirs(CACHE_DIR, exist_ok=True)
|
||||
|
||||
class RenameRequest(BaseModel):
|
||||
old_path: str
|
||||
@@ -14,6 +20,32 @@ class RenameRequest(BaseModel):
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
def get_cached_cbz_path(share_name: str, path: str):
|
||||
"""Returns the local path to the cached CBZ file, downloading it if necessary."""
|
||||
file_hash = hashlib.md5(f"{share_name}:{path}".encode()).hexdigest()
|
||||
cache_path = os.path.join(CACHE_DIR, f"{file_hash}.cbz")
|
||||
|
||||
if not os.path.exists(cache_path):
|
||||
# Check if we need to clean up cache? (Simple FIFO or size check could be added later)
|
||||
# For now, we download.
|
||||
manager = SambaManager(
|
||||
settings.samba_server_ip,
|
||||
share_name,
|
||||
username=settings.samba_username,
|
||||
password=settings.samba_password,
|
||||
)
|
||||
try:
|
||||
with open(cache_path, "wb") as f:
|
||||
manager.download_file(path, f)
|
||||
except Exception as e:
|
||||
# Clean up partial file
|
||||
if os.path.exists(cache_path):
|
||||
os.remove(cache_path)
|
||||
raise e
|
||||
finally:
|
||||
manager.close()
|
||||
|
||||
return cache_path
|
||||
|
||||
@router.get("/list/{share_name}")
|
||||
def list_files(share_name: str, path: str = "/"):
|
||||
@@ -36,8 +68,23 @@ def delete_file(share_name: str, path: str):
|
||||
username=settings.samba_username,
|
||||
password=settings.samba_password,
|
||||
)
|
||||
result = manager.delete_file(path)
|
||||
manager.close()
|
||||
|
||||
try:
|
||||
# Check if it's a directory
|
||||
attributes = manager.get_attributes(path)
|
||||
if isinstance(attributes, dict) and "error" in attributes:
|
||||
# If getting attributes fails, try deleting as file (maybe simple file)
|
||||
# or return error. But standard delete_file tries deleteFiles.
|
||||
result = manager.delete_file(path)
|
||||
elif attributes.isDirectory:
|
||||
result = manager.delete_directory_recursive(path)
|
||||
else:
|
||||
result = manager.delete_file(path)
|
||||
except Exception as e:
|
||||
result = {"error": str(e)}
|
||||
finally:
|
||||
manager.close()
|
||||
|
||||
return result
|
||||
|
||||
|
||||
@@ -122,47 +169,39 @@ def view_file(share_name: str, path: str, request: Request):
|
||||
|
||||
@router.get("/cbz/list/{share_name}")
|
||||
def list_cbz_contents(share_name: str, path: str):
|
||||
manager = SambaManager(
|
||||
settings.samba_server_ip,
|
||||
share_name,
|
||||
username=settings.samba_username,
|
||||
password=settings.samba_password,
|
||||
)
|
||||
file_obj = io.BytesIO()
|
||||
manager.download_file(path, file_obj)
|
||||
manager.close()
|
||||
file_obj.seek(0)
|
||||
|
||||
image_files = []
|
||||
with zipfile.ZipFile(file_obj, 'r') as zip_ref:
|
||||
for file_info in zip_ref.infolist():
|
||||
if file_info.filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp')):
|
||||
image_files.append(file_info.filename)
|
||||
|
||||
return sorted(image_files)
|
||||
try:
|
||||
cache_path = get_cached_cbz_path(share_name, path)
|
||||
|
||||
image_files = []
|
||||
with zipfile.ZipFile(cache_path, 'r') as zip_ref:
|
||||
for file_info in zip_ref.infolist():
|
||||
if file_info.filename.lower().endswith(('.png', '.jpg', '.jpeg', '.gif', '.bmp', '.webp')):
|
||||
image_files.append(file_info.filename)
|
||||
|
||||
return sorted(image_files)
|
||||
except Exception as e:
|
||||
return Response(content=str(e), status_code=500)
|
||||
|
||||
@router.get("/cbz/image/{share_name}")
|
||||
def get_cbz_image(share_name: str, path: str, image_name: str):
|
||||
manager = SambaManager(
|
||||
settings.samba_server_ip,
|
||||
share_name,
|
||||
username=settings.samba_username,
|
||||
password=settings.samba_password,
|
||||
)
|
||||
file_obj = io.BytesIO()
|
||||
manager.download_file(path, file_obj)
|
||||
manager.close()
|
||||
file_obj.seek(0)
|
||||
|
||||
with zipfile.ZipFile(file_obj, 'r') as zip_ref:
|
||||
with zip_ref.open(image_name) as image_file:
|
||||
image_data = io.BytesIO(image_file.read())
|
||||
|
||||
media_type, _ = mimetypes.guess_type(image_name)
|
||||
if media_type is None:
|
||||
media_type = "application/octet-stream"
|
||||
try:
|
||||
cache_path = get_cached_cbz_path(share_name, path)
|
||||
|
||||
return StreamingResponse(image_data, media_type=media_type)
|
||||
# Open zip from cache
|
||||
# We need to return a stream. We can read the specific file into BytesIO.
|
||||
# This is fast since it's local disk read.
|
||||
|
||||
with zipfile.ZipFile(cache_path, 'r') as zip_ref:
|
||||
with zip_ref.open(image_name) as image_file:
|
||||
image_data = io.BytesIO(image_file.read())
|
||||
|
||||
media_type, _ = mimetypes.guess_type(image_name)
|
||||
if media_type is None:
|
||||
media_type = "application/octet-stream"
|
||||
|
||||
return StreamingResponse(image_data, media_type=media_type)
|
||||
except Exception as e:
|
||||
return Response(content=str(e), status_code=500)
|
||||
|
||||
|
||||
@router.put("/files/rename/{share_name}")
|
||||
|
||||
Reference in New Issue
Block a user