package universal import ( "fmt" "net/http" "path" "path/filepath" "strings" "github.com/debridmediamanager.com/zurg/internal/torrent" "github.com/debridmediamanager.com/zurg/pkg/logutil" "github.com/hashicorp/golang-lru/v2/expirable" ) const ( SPLIT_TOKEN = "$" ) func HandleHeadRequest(w http.ResponseWriter, r *http.Request, t *torrent.TorrentManager, cache *expirable.LRU[string, string]) { log := logutil.NewLogger().Named("head") 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.Errorf("Request %s %s not supported yet", 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, SPLIT_TOKEN) contentType := splits[0] contentLength := splits[1] lastModified := splits[2] w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Length", contentLength) w.Header().Set("Last-Modified", lastModified) w.WriteHeader(http.StatusOK) return } baseDirectory := segments[len(segments)-3] accessKey := segments[len(segments)-2] filename := segments[len(segments)-1] torrents, ok := t.DirectoryMap.Get(baseDirectory) if !ok { log.Warnf("Cannot find directory %s", baseDirectory) http.Error(w, "File not found", http.StatusNotFound) return } torrent, ok := torrents.Get(accessKey) if !ok { log.Warnf("Cannot find torrent %s in the directory %s", accessKey, baseDirectory) http.Error(w, "File not found", http.StatusNotFound) return } file, _ := torrent.SelectedFiles.Get(filename) if file == nil { log.Warnf("Cannot find file from path %s", requestPath) http.Error(w, "Cannot find file", http.StatusNotFound) return } if !strings.HasPrefix(file.Link, "http") { // This is a dead file, serve an alternate file log.Warnf("File %s is no longer available", filename) http.Error(w, "Cannot find file", http.StatusNotFound) return } contentType := getContentMimeType(filename) contentLength := fmt.Sprintf("%d", file.Bytes) lastModified := file.Ended w.Header().Set("Content-Type", contentType) w.Header().Set("Content-Length", contentLength) w.Header().Set("Last-Modified", lastModified) cacheVal := strings.Join([]string{contentType, contentLength, lastModified}, SPLIT_TOKEN) cache.Add("head:"+requestPath, cacheVal) 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" } }