refactor: consolidate proxy handlers and simplify ranking/watchlist
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"database/sql"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log"
|
||||
"net/http"
|
||||
@@ -184,72 +185,48 @@ func convertSegments(segments []SkipSegment) []templates.SkipSegment {
|
||||
return result
|
||||
}
|
||||
|
||||
func (h *Handler) HandleProxyStream(w http.ResponseWriter, r *http.Request) {
|
||||
func (h *Handler) HandleProxy(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
mode := normalizeMode(r.URL.Query().Get("mode"))
|
||||
if mode == "" {
|
||||
mode = "dub"
|
||||
}
|
||||
|
||||
token := strings.TrimSpace(r.URL.Query().Get("token"))
|
||||
if token == "" {
|
||||
http.Error(w, "missing playback token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
targetURL, referer, err := h.svc.resolveProxyToken(r.Context(), token, proxyScopeStream)
|
||||
scope := proxyScope(strings.TrimPrefix(r.URL.Path, "/watch/proxy/"))
|
||||
scopeLabel := map[proxyScope]string{
|
||||
proxyScopeStream: "stream",
|
||||
proxyScopeSegment: "segment",
|
||||
proxyScopeSubtitle: "subtitle",
|
||||
}[scope]
|
||||
if scopeLabel == "" {
|
||||
http.Error(w, "invalid proxy scope", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
targetURL, referer, err := h.svc.resolveProxyToken(r.Context(), token, scope)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid stream token", http.StatusBadRequest)
|
||||
http.Error(w, fmt.Sprintf("invalid %s token", scopeLabel), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.proxyUpstream(w, r, targetURL, referer)
|
||||
}
|
||||
|
||||
func (h *Handler) HandleProxyStream(w http.ResponseWriter, r *http.Request) {
|
||||
h.HandleProxy(w, r)
|
||||
}
|
||||
|
||||
func (h *Handler) HandleProxySegment(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
token := strings.TrimSpace(r.URL.Query().Get("token"))
|
||||
if token == "" {
|
||||
http.Error(w, "missing segment token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
targetURL, referer, err := h.svc.resolveProxyToken(r.Context(), token, proxyScopeSegment)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid segment token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.proxyUpstream(w, r, targetURL, referer)
|
||||
h.HandleProxy(w, r)
|
||||
}
|
||||
|
||||
func (h *Handler) HandleProxySubtitle(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method not allowed", http.StatusMethodNotAllowed)
|
||||
return
|
||||
}
|
||||
|
||||
token := strings.TrimSpace(r.URL.Query().Get("token"))
|
||||
if token == "" {
|
||||
http.Error(w, "missing subtitle token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
targetURL, referer, err := h.svc.resolveProxyToken(r.Context(), token, proxyScopeSubtitle)
|
||||
if err != nil {
|
||||
http.Error(w, "invalid subtitle token", http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
h.proxyUpstream(w, r, targetURL, referer)
|
||||
h.HandleProxy(w, r)
|
||||
}
|
||||
|
||||
func (h *Handler) HandleSaveProgress(w http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -30,8 +30,8 @@ func rankSources(sources []StreamSource, quality string) ([]sourceScore, error)
|
||||
targetQuality := normalizeQuality(quality)
|
||||
scored := make([]sourceScore, 0, len(filtered))
|
||||
for _, source := range filtered {
|
||||
typeScore := sourceTypePriority(source.Type)
|
||||
providerScore := providerPriority(source.Provider)
|
||||
typeScore := sourceTypePriorityFn(source.Type)
|
||||
providerScore := providerPriorityFn(source.Provider)
|
||||
qualityScore := sourceQualityPriority(source.Quality, targetQuality)
|
||||
refererScore := 0
|
||||
if source.Referer != "" {
|
||||
@@ -65,48 +65,43 @@ func normalizeQuality(quality string) string {
|
||||
return lower
|
||||
}
|
||||
|
||||
func sourceTypePriority(sourceType string) int {
|
||||
switch strings.ToLower(sourceType) {
|
||||
case "mp4":
|
||||
return 500
|
||||
case "m3u8":
|
||||
return 450
|
||||
case "unknown":
|
||||
return 300
|
||||
case "embed":
|
||||
return 100
|
||||
default:
|
||||
return 200
|
||||
}
|
||||
var sourceTypePriority = map[string]int{
|
||||
"mp4": 500,
|
||||
"m3u8": 450,
|
||||
"unknown": 300,
|
||||
"embed": 100,
|
||||
}
|
||||
|
||||
func providerPriority(provider string) int {
|
||||
switch strings.ToLower(provider) {
|
||||
case "s-mp4":
|
||||
return 120
|
||||
case "default":
|
||||
return 115
|
||||
case "luf-mp4":
|
||||
return 110
|
||||
case "vid-mp4":
|
||||
return 105
|
||||
case "yt-mp4":
|
||||
return 100
|
||||
case "mp4":
|
||||
return 95
|
||||
case "uv-mp4":
|
||||
return 90
|
||||
case "hls":
|
||||
return 80
|
||||
case "sw":
|
||||
return 40
|
||||
case "ok":
|
||||
return 35
|
||||
case "ss-hls":
|
||||
return 30
|
||||
default:
|
||||
return 60
|
||||
var providerPriority = map[string]int{
|
||||
"s-mp4": 120,
|
||||
"default": 115,
|
||||
"luf-mp4": 110,
|
||||
"vid-mp4": 105,
|
||||
"yt-mp4": 100,
|
||||
"mp4": 95,
|
||||
"uv-mp4": 90,
|
||||
"hls": 80,
|
||||
"sw": 40,
|
||||
"ok": 35,
|
||||
"ss-hls": 30,
|
||||
}
|
||||
|
||||
var sourceQualityDefaults = map[string]int{
|
||||
"auto": 240,
|
||||
}
|
||||
|
||||
func sourceTypePriorityFn(sourceType string) int {
|
||||
if p, ok := sourceTypePriority[strings.ToLower(sourceType)]; ok {
|
||||
return p
|
||||
}
|
||||
return 200
|
||||
}
|
||||
|
||||
func providerPriorityFn(provider string) int {
|
||||
if p, ok := providerPriority[strings.ToLower(provider)]; ok {
|
||||
return p
|
||||
}
|
||||
return 60
|
||||
}
|
||||
|
||||
func sourceQualityPriority(sourceQuality string, targetQuality string) int {
|
||||
@@ -126,34 +121,6 @@ func sourceQualityPriority(sourceQuality string, targetQuality string) int {
|
||||
}
|
||||
}
|
||||
|
||||
func parseQualityValue(rawQuality string) int {
|
||||
lower := strings.ToLower(rawQuality)
|
||||
var digits strings.Builder
|
||||
|
||||
for _, char := range lower {
|
||||
if char >= '0' && char <= '9' {
|
||||
digits.WriteRune(char)
|
||||
continue
|
||||
}
|
||||
if digits.Len() > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if digits.Len() > 0 {
|
||||
value, err := strconv.Atoi(digits.String())
|
||||
if err == nil {
|
||||
return value
|
||||
}
|
||||
}
|
||||
|
||||
if lower == "auto" {
|
||||
return 240
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
func qualityMatches(sourceQuality string, targetQuality string) bool {
|
||||
sourceLower := strings.ToLower(sourceQuality)
|
||||
targetLower := strings.ToLower(targetQuality)
|
||||
@@ -166,10 +133,25 @@ func qualityMatches(sourceQuality string, targetQuality string) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
sourceDigits := extractDigits(sourceLower)
|
||||
targetDigits := extractDigits(targetLower)
|
||||
return extractDigits(sourceLower) == extractDigits(targetLower)
|
||||
}
|
||||
|
||||
return sourceDigits != "" && sourceDigits == targetDigits
|
||||
func parseQualityValue(rawQuality string) int {
|
||||
lower := strings.ToLower(rawQuality)
|
||||
if lower == "auto" {
|
||||
return 240
|
||||
}
|
||||
|
||||
digits := extractDigits(lower)
|
||||
if digits == "" {
|
||||
return 0
|
||||
}
|
||||
|
||||
value, err := strconv.Atoi(digits)
|
||||
if err != nil {
|
||||
return 0
|
||||
}
|
||||
return value
|
||||
}
|
||||
|
||||
func extractDigits(value string) string {
|
||||
@@ -177,13 +159,10 @@ func extractDigits(value string) string {
|
||||
for _, char := range value {
|
||||
if char >= '0' && char <= '9' {
|
||||
digits.WriteRune(char)
|
||||
continue
|
||||
}
|
||||
if digits.Len() > 0 {
|
||||
} else if digits.Len() > 0 {
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
return digits.String()
|
||||
}
|
||||
|
||||
|
||||
@@ -133,24 +133,23 @@ func (s *Service) DeleteContinueWatching(ctx context.Context, userID string, ani
|
||||
return ErrInvalidAnimeID
|
||||
}
|
||||
|
||||
params := database.DeleteContinueWatchingEntryParams{
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}
|
||||
|
||||
clearProgress := database.SaveWatchProgressParams{
|
||||
CurrentEpisode: sql.NullInt64{Valid: false},
|
||||
CurrentTimeSeconds: 0,
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}
|
||||
|
||||
if s.sqlDB == nil {
|
||||
if err := s.db.DeleteContinueWatchingEntry(ctx, database.DeleteContinueWatchingEntryParams{
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}); err != nil {
|
||||
if err := s.db.DeleteContinueWatchingEntry(ctx, params); err != nil {
|
||||
return fmt.Errorf("failed to delete continue watching entry: %w", err)
|
||||
}
|
||||
|
||||
if err := s.db.SaveWatchProgress(ctx, database.SaveWatchProgressParams{
|
||||
CurrentEpisode: sql.NullInt64{Valid: false},
|
||||
CurrentTimeSeconds: 0,
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}); err != nil {
|
||||
return fmt.Errorf("failed to clear watchlist progress: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return s.db.SaveWatchProgress(ctx, clearProgress)
|
||||
}
|
||||
|
||||
tx, err := s.sqlDB.BeginTx(ctx, nil)
|
||||
@@ -160,27 +159,14 @@ func (s *Service) DeleteContinueWatching(ctx context.Context, userID string, ani
|
||||
defer tx.Rollback()
|
||||
|
||||
txQueries := database.New(tx)
|
||||
if err := txQueries.DeleteContinueWatchingEntry(ctx, database.DeleteContinueWatchingEntryParams{
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}); err != nil {
|
||||
if err := txQueries.DeleteContinueWatchingEntry(ctx, params); err != nil {
|
||||
return fmt.Errorf("failed to delete continue watching entry: %w", err)
|
||||
}
|
||||
|
||||
if err := txQueries.SaveWatchProgress(ctx, database.SaveWatchProgressParams{
|
||||
CurrentEpisode: sql.NullInt64{Valid: false},
|
||||
CurrentTimeSeconds: 0,
|
||||
UserID: userID,
|
||||
AnimeID: animeID,
|
||||
}); err != nil {
|
||||
if err := txQueries.SaveWatchProgress(ctx, clearProgress); err != nil {
|
||||
return fmt.Errorf("failed to clear watchlist progress: %w", err)
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return fmt.Errorf("failed to commit continue watching deletion: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
return tx.Commit()
|
||||
}
|
||||
|
||||
type ExportEntry struct {
|
||||
|
||||
Reference in New Issue
Block a user