feat: torrent streaming with hls transcoding (#1)

* feat: add ffmpeg for hls streaming

* feat: torrent streaming with hls transcoding

- add nyaa.si torrent search client
- add streaming service using anacrolix/torrent
- add hls transcoding via ffmpeg for browser playback
- add watch page with episode selection
- add socks5 proxy support via TORRENT_PROXY env
- switch to modernc.org/sqlite (pure go, no cgo conflicts)
- update dockerfile with ffmpeg
This commit is contained in:
2026-04-07 13:23:08 +02:00
committed by GitHub
parent 579b194eb9
commit a25e8f1655
27 changed files with 3744 additions and 329 deletions

View File

@@ -109,15 +109,7 @@ func (h *Handler) HandleAnimeDetails(w http.ResponseWriter, r *http.Request) {
}
func (h *Handler) HandleAPIAnimeRelations(w http.ResponseWriter, r *http.Request) {
path := r.URL.Path[len("/api/anime/"):]
idStr := ""
for i, c := range path {
if c == '/' {
idStr = path[:i]
break
}
}
idStr := r.PathValue("id")
id, _ := strconv.Atoi(idStr)
if id <= 0 {
http.Error(w, "invalid id", http.StatusBadRequest)
@@ -172,3 +164,29 @@ func (h *Handler) HandleQuickSearch(w http.ResponseWriter, r *http.Request) {
w.WriteHeader(http.StatusOK)
json.NewEncoder(w).Encode(output)
}
func (h *Handler) HandleAPIAnimeEpisodes(w http.ResponseWriter, r *http.Request) {
idStr := r.PathValue("id")
id, _ := strconv.Atoi(idStr)
if id <= 0 {
http.Error(w, "invalid id", http.StatusBadRequest)
return
}
anime, err := h.svc.GetAnime(id)
if err != nil {
log.Printf("anime fetch error: %v", err)
http.Error(w, "Failed to fetch anime", http.StatusInternalServerError)
return
}
episodes, err := h.svc.GetEpisodes(id, 1)
if err != nil {
log.Printf("episodes fetch error: %v", err)
// Return empty episodes instead of error
templates.EpisodesList(id, anime.Title, nil, anime.Episodes).Render(r.Context(), w)
return
}
templates.EpisodesList(id, anime.Title, episodes.Episodes, anime.Episodes).Render(r.Context(), w)
}