Skip to content

Commit

Permalink
✨ support video streaming
Browse files Browse the repository at this point in the history
  • Loading branch information
zhaomaoniu committed May 5, 2024
1 parent 5ecc558 commit 1e4cf3b
Show file tree
Hide file tree
Showing 3 changed files with 57 additions and 50 deletions.
65 changes: 50 additions & 15 deletions nonebot_plugin_anime_downloader/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
from pathlib import Path
from nonebot.log import logger
from fastapi import FastAPI, Request
from fastapi.staticfiles import StaticFiles
from fastapi.templating import Jinja2Templates
from fastapi.responses import StreamingResponse


class VideoManager:
Expand All @@ -14,30 +14,65 @@ def __init__(self, app: FastAPI, download_path: Path):
self.ids: List[int] = []
self.app = app
self.download_path = download_path
self.templates = Jinja2Templates(
directory=(Path(__file__).parent / "templates").resolve()
)

app.mount(
"/video",
StaticFiles(directory=download_path.resolve()),
name="video",
)
self.templates = Jinja2Templates(directory=Path(__file__).parent / "templates")

def add_route(self, video_path: Path, torrent_id: int) -> None:
if torrent_id not in self.ids:
logger.success(f"Added route for video {video_path.name}.")
if torrent_id in self.ids:
return None

self.ids.append(torrent_id)

@self.app.get(f"/anime/{torrent_id}")
async def anime_display(request: Request):
async def anime_page(request: Request):
return self.templates.TemplateResponse(
"index.html",
{
"request": request,
"title": video_path.name,
"video_path": f"/{video_path.parent.name}/{video_path.name}",
"video_type": f"video/{video_path.suffix[1:]}",
"video_url": f"/res/{torrent_id}",
"mime_type": f"video/{video_path.suffix[1:]}",
},
)

@self.app.get(f"/res/{torrent_id}")
async def anime_res(request: Request):
file_size = video_path.stat().st_size
start, end = 0, file_size - 1
range_header = request.headers.get("Range")
if range_header:
start, end = range_header.replace("bytes=", "").split("-")
start = int(start)
end = int(end) if end else file_size - 1
status_code = 206
else:
status_code = 200

def iterfile():
with open(video_path, mode="rb") as file_like:
file_like.seek(start)
bytes_to_send = end - start + 1
while bytes_to_send > 0:
chunk_size = min(
bytes_to_send, 1024 * 1024
) # 1MB chunks or less
data = file_like.read(chunk_size)
if not data:
break
yield data
bytes_to_send -= len(data)

headers = {
"Content-Range": f"bytes {start}-{end}/{file_size}",
"Accept-Ranges": "bytes",
"Content-Length": str(end - start + 1),
"Content-Type": f"video/{video_path.suffix[1:]}",
}

return StreamingResponse(
iterfile(),
status_code=status_code,
headers=headers,
media_type=f"video/{video_path.suffix[1:]}",
)

logger.success(f"Added route for video {video_path.name}.")
10 changes: 7 additions & 3 deletions nonebot_plugin_anime_downloader/templates/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,16 @@
<html>
<head>
<title>{{ title }}</title>
<link rel="stylesheet" href="https://cdn.plyr.io/3.6.4/plyr.css" />
</head>
<body>
<h1>{{ title }}</h1>
<video width="668" height="376" controls>
<source src="{{ url_for('video', path=video_path) }}" type="{{ video_type }}">
<script src="https://cdn.plyr.io/3.6.4/plyr.polyfilled.js"></script>
<video id="player" playsinline controls>
<source src="{{ video_url }}" type="{{ mime_type }}">
Your browser does not support the video tag.
</video>
<script>
const player = new Plyr('#player');
</script>
</body>
</html>
32 changes: 0 additions & 32 deletions nonebot_plugin_anime_downloader/test.py

This file was deleted.

0 comments on commit 1e4cf3b

Please sign in to comment.