From 571e57904bc2b007dbf9a2fce2438076dd277b92 Mon Sep 17 00:00:00 2001 From: Ben Sarmiento Date: Sun, 22 Oct 2023 23:54:52 +0200 Subject: [PATCH] file metadata --- internal/http/get.go | 79 +++++++++++++++++++++++++++++++++++++ internal/net/router.go | 5 ++- internal/torrent/manager.go | 46 +++++++++++++++++---- rclone.conf | 7 ++-- 4 files changed, 125 insertions(+), 12 deletions(-) diff --git a/internal/http/get.go b/internal/http/get.go index 5c3466e..39fa57d 100644 --- a/internal/http/get.go +++ b/internal/http/get.go @@ -15,6 +15,85 @@ import ( "github.com/hashicorp/golang-lru/v2/expirable" ) +func HandleHeadRequest(w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, c config.ConfigInterface, cache *expirable.LRU[string, string]) { + requestPath := path.Clean(r.URL.Path) + requestPath = strings.Replace(requestPath, "/http", "/", 1) + if requestPath == "/favicon.ico" { + return + } + + segments := strings.Split(requestPath, "/") + // If there are less than 3 segments, return an error or adjust as needed + if len(segments) < 4 { + log.Println("Method not implemented", r.Method, r.URL.Path) + http.Error(w, "Method not implemented", http.StatusMethodNotAllowed) + return + } + + if data, exists := cache.Get("head:" + requestPath); exists { + splits := strings.Split(data, " ") + contentType := splits[0] + contentLength := splits[1] + w.Header().Set("Content-Type", contentType) + w.Header().Set("Content-Length", contentLength) + w.WriteHeader(http.StatusOK) + return + } + + baseDirectory := segments[len(segments)-3] + torrentName := segments[len(segments)-2] + filename := segments[len(segments)-1] + + torrents := findAllTorrentsWithName(t, baseDirectory, torrentName) + if torrents == nil { + log.Println("Cannot find torrent", torrentName, segments) + http.Error(w, "Cannot find file", http.StatusNotFound) + return + } + + filenameV2, linkFragment := davextra.ExtractLinkFragment(filename) + _, file := getFile(torrents, filenameV2, linkFragment) + if file == nil { + log.Println("Cannot find file", filename, segments) + http.Error(w, "Cannot find file", http.StatusNotFound) + return + } + if file.Link == "" { + log.Println("Link not found", filename) + http.Error(w, "Cannot find file", http.StatusNotFound) + return + } + contentType := getContentMimeType(filename) + contentLength := fmt.Sprintf("%d", file.Bytes) + w.Header().Set("Content-Type", contentType) + w.Header().Set("Content-Length", contentLength) + cache.Add("head:"+requestPath, contentType+" "+contentLength) + w.WriteHeader(http.StatusOK) +} + +func getContentMimeType(filePath string) string { + switch filepath.Ext(filePath) { + case ".mkv": + return "video/x-matroska" + case ".mp4": + return "video/mp4" + case ".avi": + return "video/x-msvideo" + case ".mp3": + return "audio/mpeg" + case ".rar": + return "application/x-rar-compressed" + case ".zip": + return "application/zip" + case ".7z": + return "application/x-7z-compressed" + case ".srt": + return "text/plain" + default: + return "application/octet-stream" + } +} + func HandleGetRequest(w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, c config.ConfigInterface, cache *expirable.LRU[string, string]) { requestPath := path.Clean(r.URL.Path) requestPath = strings.Replace(requestPath, "/http", "/", 1) diff --git a/internal/net/router.go b/internal/net/router.go index 7d07512..130d307 100644 --- a/internal/net/router.go +++ b/internal/net/router.go @@ -18,6 +18,9 @@ func Router(mux *http.ServeMux, c config.ConfigInterface, t *torrent.TorrentMana case http.MethodGet: intHttp.HandleDirectoryListing(w, r, t, c, cache) + case http.MethodHead: + intHttp.HandleHeadRequest(w, r, t, c, cache) + default: log.Println("Method not implemented", r.Method) http.Error(w, "Method not implemented", http.StatusMethodNotAllowed) @@ -36,7 +39,7 @@ func Router(mux *http.ServeMux, c config.ConfigInterface, t *torrent.TorrentMana w.WriteHeader(http.StatusOK) default: - log.Println("Method not implemented", r.Method) + log.Println("Method not implemented", r.Method, r.URL.Path) http.Error(w, "Method not implemented", http.StatusMethodNotAllowed) } }) diff --git a/internal/torrent/manager.go b/internal/torrent/manager.go index 1ec04d0..221c224 100644 --- a/internal/torrent/manager.go +++ b/internal/torrent/manager.go @@ -32,14 +32,43 @@ func (t *TorrentManager) refreshTorrents() { } t.checksum = checksum t.cache.Purge() - t.torrents = t.getAll() - for _, torrent := range t.torrents { - go func(id string) { - t.workerPool <- true - t.getInfo(id) - <-t.workerPool - time.Sleep(1 * time.Second) // sleep for 1 second to avoid rate limiting - }(torrent.ID) + + newTorrents := t.getAll() + + // Identify removed torrents + for i := 0; i < len(t.torrents); i++ { + found := false + for _, newTorrent := range newTorrents { + if t.torrents[i].ID == newTorrent.ID { + found = true + break + } + } + if !found { + // Remove this torrent from the slice + t.torrents = append(t.torrents[:i], t.torrents[i+1:]...) + i-- // Decrement index since we modified the slice + } + } + + // Identify and handle added torrents + for _, newTorrent := range newTorrents { + found := false + for _, torrent := range t.torrents { + if newTorrent.ID == torrent.ID { + found = true + break + } + } + if !found { + t.torrents = append(t.torrents, newTorrent) + go func(id string) { + t.workerPool <- true + t.getInfo(id) + <-t.workerPool + time.Sleep(1 * time.Second) // sleep for 1 second to avoid rate limiting + }(newTorrent.ID) + } } } } @@ -193,6 +222,7 @@ func (t *TorrentManager) getInfo(torrentID string) *Torrent { // TODO: This means some files have expired // we need to 'fix' this torrent then, at least the missing selected files log.Println("Some links has expired for", info.Name) + type Result struct { Response *realdebrid.UnrestrictResponse } diff --git a/rclone.conf b/rclone.conf index d493edd..d8e8f95 100644 --- a/rclone.conf +++ b/rclone.conf @@ -1,4 +1,5 @@ [zurg] -type = webdav -url = http://zurg:9999 -vendor = other +type = http +url = http://zurg:9999/http +no_head = true +no_slash = true