Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 30 additions & 15 deletions app/server/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@ package server
import (
"context"
"fmt"
"net"
"net/http"
"path/filepath"
"time"

"github.com/gorilla/mux"
"gopkg.in/unrolled/render.v1"
Expand All @@ -25,24 +27,25 @@ const AppName = "http_server"
type Server struct {
*subapp.Base

config *configuration.Config
library *library.Library
authManager *auth.Manager
gracefulServer *http.Server
hub *sseHub
log *logrus.Entry
render *render.Render
config *configuration.Config
library *library.Library
authManager *auth.Manager
gracefulServer *http.Server
shutdownCancel context.CancelFunc
hub *sseHub
log *logrus.Entry
render *render.Render
}

// New returns a new server
func New(config *configuration.Config, vs *library.Library, auth *auth.Manager) *Server {
return &Server{
Base: subapp.NewBase(AppName),
config: config,
library: vs,
authManager: auth,
hub: newSSEHub(),
render: render.New(),
Base: subapp.NewBase(AppName),
config: config,
library: vs,
authManager: auth,
hub: newSSEHub(),
render: render.New(),
}
}

Expand All @@ -53,7 +56,14 @@ func (s *Server) Run(log *logrus.Entry) error {
// Init the app
s.InitStart(log)

s.gracefulServer = s.httpServer(s.log)
ctx, cancel := context.WithCancel(context.Background())
s.shutdownCancel = cancel
defer cancel()

srv := s.httpServer(s.log)
srv.BaseContext = func(_ net.Listener) context.Context { return ctx }
s.gracefulServer = srv

err := s.gracefulServer.ListenAndServe()
if err != nil && err != http.ErrServerClosed {
return err
Expand All @@ -63,7 +73,12 @@ func (s *Server) Run(log *logrus.Entry) error {

// Stop stops the http server
func (s *Server) Stop(log *logrus.Entry) {
if err := s.gracefulServer.Shutdown(context.Background()); err != nil {
if s.shutdownCancel != nil {
s.shutdownCancel()
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
if err := s.gracefulServer.Shutdown(ctx); err != nil {
log.WithError(err).Error("failed to shutdown http server")
}
}
Expand Down
20 changes: 20 additions & 0 deletions app/server/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,16 @@ func (s *Server) httpServer(log *logrus.Entry) *http.Server {
methods: "PUT",
handler: s.uploadMovieSubtitle,
},
{
path: "/movies/{id}/subtitles/{lang}/available",
methods: "GET",
handler: s.listMovieSubtitles,
},
{
path: "/movies/{id}/subtitles/{lang}/available",
methods: "POST",
handler: s.downloadMovieSubtitleByEntry,
},
{
path: "/shows",
methods: "GET",
Expand Down Expand Up @@ -136,6 +146,16 @@ func (s *Server) httpServer(log *logrus.Entry) *http.Server {
methods: "PUT",
handler: s.uploadEpisodeSubtitle,
},
{
path: "/shows/{id}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/{lang}/available",
methods: "GET",
handler: s.listEpisodeSubtitles,
},
{
path: "/shows/{id}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/subtitles/{lang}/available",
methods: "POST",
handler: s.downloadEpisodeSubtitleByEntry,
},
{
path: "/shows/{id}/seasons/{season:[0-9]+}/episodes/{episode:[0-9]+}/download",
methods: "GET",
Expand Down
104 changes: 104 additions & 0 deletions app/server/subtitles.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package server

import (
"encoding/json"
"fmt"
"io"
"net/http"

Expand All @@ -9,6 +11,108 @@ import (
index "github.com/odwrtw/polochon/lib/media_index"
)

func (s *Server) listSubtitles(v polochon.Video, w http.ResponseWriter, r *http.Request) {
log := s.logEntry(r)

lang, err := getLanguage(r)
if err != nil {
s.renderError(w, r, err)
return
}

entries, err := polochon.ListSubtitles(v, lang, log)
if err != nil && err != polochon.ErrNoSubtitleFound {
s.renderError(w, r, err)
return
}

s.renderOK(w, entries)
}

func (s *Server) downloadSubtitleByEntry(v polochon.Video, w http.ResponseWriter, r *http.Request) {
log := s.logEntry(r)

lang, err := getLanguage(r)
if err != nil {
s.renderError(w, r, err)
return
}

var entry polochon.SubtitleEntry
if err := json.NewDecoder(r.Body).Decode(&entry); err != nil {
s.renderError(w, r, err)
return
}
if entry.Source == "" || entry.ID == "" {
s.renderError(w, r, fmt.Errorf("server: subtitle source and id are required"))
return
}
entry.Language = lang

subtitler := polochon.FindSubtitler(v.GetSubtitlers(), entry.Source)
if subtitler == nil {
s.renderError(w, r, fmt.Errorf("server: subtitler %q not found", entry.Source))
return
}

sub, err := subtitler.DownloadSubtitle(v, &entry, log)
if err != nil {
s.renderError(w, r, err)
return
}

v.SetSubtitles([]*polochon.Subtitle{sub})

if err := s.library.SaveSubtitles(v, log); err != nil {
s.renderError(w, r, err)
return
}

if err := s.library.UpdateSubtitleIndex(v, sub); err != nil {
s.renderError(w, r, err)
return
}

s.hub.broadcast()
w.WriteHeader(http.StatusNoContent)
}

func (s *Server) listMovieSubtitles(w http.ResponseWriter, r *http.Request) {
m := s.getMovie(w, r)
if m == nil {
s.renderError(w, r, index.ErrNotFound)
return
}
s.listSubtitles(m, w, r)
}

func (s *Server) downloadMovieSubtitleByEntry(w http.ResponseWriter, r *http.Request) {
m := s.getMovie(w, r)
if m == nil {
s.renderError(w, r, index.ErrNotFound)
return
}
s.downloadSubtitleByEntry(m, w, r)
}

func (s *Server) listEpisodeSubtitles(w http.ResponseWriter, r *http.Request) {
e := s.getEpisode(w, r)
if e == nil {
s.renderError(w, r, index.ErrNotFound)
return
}
s.listSubtitles(e, w, r)
}

func (s *Server) downloadEpisodeSubtitleByEntry(w http.ResponseWriter, r *http.Request) {
e := s.getEpisode(w, r)
if e == nil {
s.renderError(w, r, index.ErrNotFound)
return
}
s.downloadSubtitleByEntry(e, w, r)
}

func getLanguage(r *http.Request) (polochon.Language, error) {
vars := mux.Vars(r)
return polochon.NewLanguage(vars["lang"])
Expand Down
15 changes: 5 additions & 10 deletions config.example.yml
Original file line number Diff line number Diff line change
Expand Up @@ -165,11 +165,12 @@ modules_params:
key: sdf7as8f8ds7f9sf
recipient: 9327a472s3947234792
# Opensubtitles is used to download the subtitles for movies and episodes.
# The username and password are mandatory.
# Get an API key at https://www.opensubtitles.com/consumers
- name: opensubtitles
user: opensubtitle@canapeapp.com
lang: en_US
password: my@w3$0m3p@$$w0rD
api_key: my_api_key
username: my_username
password: my_password
# api_base: https://stoplight.io/mocks/opensubtitles/opensubtitles-api/2781383 # mock server for testing
# Imdb is used to get the wishlist from a *public* list for a user id, you
# can specify multiple user ids to tracks multiple lists.
- name: imdb
Expand All @@ -195,8 +196,6 @@ modules_params:
- name: thepiratebay
# timeout for the search (optional, default 30s)
timeout: 30s
# guessit endpoint (optional)
guessit_endpoint: "https://api.myguessit.mydomain"
urls:
- https://thepiratebay.org
- https://mypirate.cc
Expand All @@ -211,8 +210,4 @@ modules_params:
hooks:
- url: http://urlhook/new_movie
method: POST
# Guessit is a wrapper for the guessit python program answering over http.
# A container is available for self hosting the service:
# https://github.com/odwrtw/docker-guessit
- name: guessit
endpoint: "https://guessit.quimbo.fr/guess"
28 changes: 12 additions & 16 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/odwrtw/polochon

go 1.26.0
go 1.26.1

require (
github.com/agnivade/levenshtein v1.2.1
Expand All @@ -10,17 +10,16 @@ require (
github.com/gregdel/pushover v1.4.0
github.com/hanwen/go-fuse/v2 v2.9.0
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
github.com/odwrtw/addicted v0.0.0-20231023211155-d92e1eb251c5
github.com/odwrtw/addicted v0.0.0-20260331124050-5f397e4f1ac9
github.com/odwrtw/eztv v0.0.0-20231026192001-039613c81a8e
github.com/odwrtw/fanarttv v0.0.0-20170412122542-9f67d3cf0188
github.com/odwrtw/guessit v0.0.0-20221028215709-d4336685bdaa
github.com/odwrtw/imdb-watchlist v0.0.0-20190417175016-b7a9f7503d69
github.com/odwrtw/tpb v0.0.0-20200507114501-df19547bbff1
github.com/odwrtw/tpb v0.0.0-20260324184152-590534670773
github.com/odwrtw/trakttv v0.0.0-20260303085205-6da049dbce68
github.com/odwrtw/transmission v0.0.0-20221028215408-b11d7d55c759
github.com/odwrtw/yifysubs v0.0.0-20240207155719-c57d8c244477
github.com/odwrtw/whatsthis v0.0.0-20260324183316-86994131f0d2
github.com/odwrtw/yifysubs v0.0.0-20260324231500-2a22e2158ed9
github.com/odwrtw/yts v0.0.0-20231024130053-dfa826fee7b6
github.com/oz/osdb v0.0.0-20221214175751-f169057712ec
github.com/phyber/negroni-gzip v1.0.0
github.com/pioz/tvdb v0.0.0-20221212235421-03519fb7a0e2
github.com/prometheus/client_golang v1.23.2
Expand All @@ -35,11 +34,11 @@ require (
)

require (
github.com/PuerkitoBio/goquery v1.11.0 // indirect
github.com/PuerkitoBio/goquery v1.12.0 // indirect
github.com/andybalholm/cascadia v1.3.3 // indirect
github.com/antchfx/htmlquery v1.3.5 // indirect
github.com/antchfx/xmlquery v1.5.0 // indirect
github.com/antchfx/xpath v1.3.5 // indirect
github.com/antchfx/htmlquery v1.3.6 // indirect
github.com/antchfx/xmlquery v1.5.1 // indirect
github.com/antchfx/xpath v1.3.6 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.24.4 // indirect
github.com/cespare/xxhash/v2 v2.3.0 // indirect
Expand All @@ -51,9 +50,7 @@ require (
github.com/golang/protobuf v1.5.4 // indirect
github.com/gorilla/rpc v1.2.1 // indirect
github.com/gorilla/websocket v1.5.3 // indirect
github.com/jpillora/scraper v0.3.0 // indirect
github.com/kennygrant/sanitize v1.2.4 // indirect
github.com/kolo/xmlrpc v0.0.0-20220921171641-a4b6fa1dd06b // indirect
github.com/kr/text v0.2.0 // indirect
github.com/kylelemons/go-gypsy v1.0.0 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
Expand All @@ -64,10 +61,9 @@ require (
github.com/saintfish/chardet v0.0.0-20230101081208-5e3ef4b5456d // indirect
github.com/temoto/robotstxt v1.1.2 // indirect
go.yaml.in/yaml/v2 v2.4.3 // indirect
golang.org/x/net v0.50.0 // indirect
golang.org/x/sys v0.41.0 // indirect
golang.org/x/text v0.34.0 // indirect
golang.org/x/net v0.52.0 // indirect
golang.org/x/sys v0.42.0 // indirect
golang.org/x/text v0.35.0 // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/protobuf v1.36.11 // indirect
gopkg.in/xmlpath.v2 v2.0.0-20150820204837-860cbeca3ebc // indirect
)
Loading
Loading