Add retain_folder_name_extension option
This commit is contained in:
@@ -11,6 +11,7 @@ enable_repair: true # BEWARE! THERE CAN ONLY BE 1 INSTANCE OF ZURG THAT SHOULD R
|
|||||||
on_library_update: |
|
on_library_update: |
|
||||||
echo "hook"
|
echo "hook"
|
||||||
network_buffer_size: 32768 # 32KB
|
network_buffer_size: 32768 # 32KB
|
||||||
|
retain_folder_name_extension: false # if true, the folder name will contain the file extension when it is a torrent for a single file
|
||||||
|
|
||||||
# List of directory definitions and their filtering rules
|
# List of directory definitions and their filtering rules
|
||||||
directories:
|
directories:
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ type ConfigInterface interface {
|
|||||||
GetOnLibraryUpdate() string
|
GetOnLibraryUpdate() string
|
||||||
GetNetworkBufferSize() int
|
GetNetworkBufferSize() int
|
||||||
GetMountPoint() string
|
GetMountPoint() string
|
||||||
|
EnableRetainFolderNameExtension() bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func LoadZurgConfig(filename string) (ConfigInterface, error) {
|
func LoadZurgConfig(filename string) (ConfigInterface, error) {
|
||||||
|
|||||||
@@ -1,17 +1,18 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
type ZurgConfig struct {
|
type ZurgConfig struct {
|
||||||
Version string `yaml:"zurg"`
|
Version string `yaml:"zurg"`
|
||||||
Token string `yaml:"token"`
|
Token string `yaml:"token"`
|
||||||
Host string `yaml:"host"`
|
Host string `yaml:"host"`
|
||||||
Port string `yaml:"port"`
|
Port string `yaml:"port"`
|
||||||
NumOfWorkers int `yaml:"concurrent_workers"`
|
NumOfWorkers int `yaml:"concurrent_workers"`
|
||||||
RefreshEverySeconds int `yaml:"check_for_changes_every_secs"`
|
RefreshEverySeconds int `yaml:"check_for_changes_every_secs"`
|
||||||
CacheTimeHours int `yaml:"info_cache_time_hours"`
|
CacheTimeHours int `yaml:"info_cache_time_hours"`
|
||||||
CanRepair bool `yaml:"enable_repair"`
|
CanRepair bool `yaml:"enable_repair"`
|
||||||
OnLibraryUpdate string `yaml:"on_library_update"`
|
OnLibraryUpdate string `yaml:"on_library_update"`
|
||||||
NetworkBufferSize int `yaml:"network_buffer_size"`
|
NetworkBufferSize int `yaml:"network_buffer_size"`
|
||||||
MountPoint string `yaml:"mount_point"`
|
MountPoint string `yaml:"mount_point"`
|
||||||
|
RetainFolderNameExtension bool `yaml:"retain_folder_name_extension"`
|
||||||
}
|
}
|
||||||
|
|
||||||
func (z *ZurgConfig) GetToken() string {
|
func (z *ZurgConfig) GetToken() string {
|
||||||
@@ -68,3 +69,7 @@ func (z *ZurgConfig) GetNetworkBufferSize() int {
|
|||||||
func (z *ZurgConfig) GetMountPoint() string {
|
func (z *ZurgConfig) GetMountPoint() string {
|
||||||
return z.MountPoint
|
return z.MountPoint
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (z *ZurgConfig) EnableRetainFolderNameExtension() bool {
|
||||||
|
return z.RetainFolderNameExtension
|
||||||
|
}
|
||||||
|
|||||||
@@ -49,14 +49,13 @@ func createSingleTorrentResponse(basePath string, torrents []torrent.Torrent) (*
|
|||||||
for _, torrent := range torrents {
|
for _, torrent := range torrents {
|
||||||
for _, file := range torrent.SelectedFiles {
|
for _, file := range torrent.SelectedFiles {
|
||||||
if file.Link == "" {
|
if file.Link == "" {
|
||||||
|
// TODO: fix the file?
|
||||||
// log.Println("File has no link, skipping (repairing links take time)", file.Path)
|
// log.Println("File has no link, skipping (repairing links take time)", file.Path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := filepath.Base(file.Path)
|
filename := filepath.Base(file.Path)
|
||||||
if finalName[filename] {
|
if finalName[filename] {
|
||||||
// fragment := davextra.GetLinkFragment(file.Link)
|
|
||||||
// filename = davextra.InsertLinkFragment(filename, fragment)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
finalName[filename] = true
|
finalName[filename] = true
|
||||||
|
|||||||
@@ -40,14 +40,13 @@ func createSingleTorrentResponse(basePath string, torrents []torrent.Torrent) (s
|
|||||||
for _, torrent := range torrents {
|
for _, torrent := range torrents {
|
||||||
for _, file := range torrent.SelectedFiles {
|
for _, file := range torrent.SelectedFiles {
|
||||||
if file.Link == "" {
|
if file.Link == "" {
|
||||||
|
// TODO: fix the file?
|
||||||
// log.Println("File has no link, skipping", file.Path)
|
// log.Println("File has no link, skipping", file.Path)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
filename := filepath.Base(file.Path)
|
filename := filepath.Base(file.Path)
|
||||||
if finalName[filename] {
|
if finalName[filename] {
|
||||||
// fragment := davextra.GetLinkFragment(file.Link)
|
|
||||||
// filename = davextra.InsertLinkFragment(filename, fragment)
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
finalName[filename] = true
|
finalName[filename] = true
|
||||||
|
|||||||
@@ -35,7 +35,7 @@ type TorrentManager struct {
|
|||||||
// and store them in-memory; it is called only once at startup
|
// and store them in-memory; it is called only once at startup
|
||||||
func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string]) *TorrentManager {
|
func NewTorrentManager(config config.ConfigInterface, cache *expirable.LRU[string, string]) *TorrentManager {
|
||||||
t := &TorrentManager{
|
t := &TorrentManager{
|
||||||
requiredVersion: "4.11.2023",
|
requiredVersion: fmt.Sprintf("4.11.2023 - retain:%v", config.EnableRetainFolderNameExtension()),
|
||||||
config: config,
|
config: config,
|
||||||
cache: cache,
|
cache: cache,
|
||||||
workerPool: make(chan bool, config.GetNumOfWorkers()),
|
workerPool: make(chan bool, config.GetNumOfWorkers()),
|
||||||
@@ -256,7 +256,7 @@ func (t *TorrentManager) addMoreInfo(torrent *Torrent) {
|
|||||||
// see if api data and file data still match
|
// see if api data and file data still match
|
||||||
// then it means data is still usable
|
// then it means data is still usable
|
||||||
if len(torrentFromFile.Links) == len(torrent.Links) {
|
if len(torrentFromFile.Links) == len(torrent.Links) {
|
||||||
torrent.Name = getName(torrentFromFile)
|
torrent.Name = t.getName(torrentFromFile)
|
||||||
torrent.ForRepair = torrentFromFile.ForRepair
|
torrent.ForRepair = torrentFromFile.ForRepair
|
||||||
torrent.SelectedFiles = torrentFromFile.SelectedFiles[:]
|
torrent.SelectedFiles = torrentFromFile.SelectedFiles[:]
|
||||||
return
|
return
|
||||||
@@ -323,7 +323,7 @@ func (t *TorrentManager) addMoreInfo(torrent *Torrent) {
|
|||||||
}
|
}
|
||||||
// update file cache
|
// update file cache
|
||||||
torrent.OriginalName = info.OriginalName
|
torrent.OriginalName = info.OriginalName
|
||||||
torrent.Name = getName(torrent)
|
torrent.Name = t.getName(torrent)
|
||||||
if len(selectedFiles) > 0 {
|
if len(selectedFiles) > 0 {
|
||||||
// update the torrent with more data!
|
// update the torrent with more data!
|
||||||
torrent.SelectedFiles = selectedFiles
|
torrent.SelectedFiles = selectedFiles
|
||||||
@@ -332,16 +332,17 @@ func (t *TorrentManager) addMoreInfo(torrent *Torrent) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func getName(torrent *Torrent) string {
|
func (t *TorrentManager) getName(torrent *Torrent) string {
|
||||||
ret := ""
|
// drop the extension from the name
|
||||||
if torrent.OriginalName != "" {
|
t.log.Debugf("Original name: %s", torrent.OriginalName)
|
||||||
ret = torrent.OriginalName
|
t.log.Debugf("Name: %s", torrent.Name)
|
||||||
|
if t.config.EnableRetainFolderNameExtension() && strings.Contains(torrent.Name, torrent.OriginalName) {
|
||||||
|
return torrent.Name
|
||||||
} else {
|
} else {
|
||||||
ret = torrent.Name
|
ret := strings.TrimSuffix(torrent.OriginalName, ".mp4")
|
||||||
|
ret = strings.TrimSuffix(ret, ".mkv")
|
||||||
|
return ret
|
||||||
}
|
}
|
||||||
ret = strings.TrimSuffix(ret, ".mkv")
|
|
||||||
ret = strings.TrimSuffix(ret, ".mp4")
|
|
||||||
return ret
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// mapToDirectories maps torrents to directories
|
// mapToDirectories maps torrents to directories
|
||||||
|
|||||||
@@ -11,7 +11,6 @@ import (
|
|||||||
"github.com/debridmediamanager.com/zurg/internal/dav"
|
"github.com/debridmediamanager.com/zurg/internal/dav"
|
||||||
intHttp "github.com/debridmediamanager.com/zurg/internal/http"
|
intHttp "github.com/debridmediamanager.com/zurg/internal/http"
|
||||||
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
||||||
"github.com/debridmediamanager.com/zurg/pkg/davextra"
|
|
||||||
"github.com/debridmediamanager.com/zurg/pkg/logutil"
|
"github.com/debridmediamanager.com/zurg/pkg/logutil"
|
||||||
"github.com/debridmediamanager.com/zurg/pkg/realdebrid"
|
"github.com/debridmediamanager.com/zurg/pkg/realdebrid"
|
||||||
"github.com/hashicorp/golang-lru/v2/expirable"
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||||
@@ -58,8 +57,7 @@ func HandleGetRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torrent
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filenameV2, linkFragment := davextra.ExtractLinkFragment(filename)
|
torrent, file := getFile(torrents, filename)
|
||||||
torrent, file := getFile(torrents, filenameV2, linkFragment)
|
|
||||||
if file == nil {
|
if file == nil {
|
||||||
log.Errorf("Cannot find file from path %s", requestPath)
|
log.Errorf("Cannot find file from path %s", requestPath)
|
||||||
http.Error(w, "File not found", http.StatusNotFound)
|
http.Error(w, "File not found", http.StatusNotFound)
|
||||||
@@ -79,20 +77,20 @@ func HandleGetRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torrent
|
|||||||
resp := realdebrid.RetryUntilOk(unrestrictFn)
|
resp := realdebrid.RetryUntilOk(unrestrictFn)
|
||||||
if resp == nil {
|
if resp == nil {
|
||||||
if !file.Unavailable {
|
if !file.Unavailable {
|
||||||
log.Errorf("Cannot unrestrict file %s %s", filenameV2, link)
|
log.Errorf("Cannot unrestrict file %s %s", filename, link)
|
||||||
t.HideTheFile(torrent, file)
|
t.HideTheFile(torrent, file)
|
||||||
}
|
}
|
||||||
streamErrorVideo("https://www.youtube.com/watch?v=gea_FJrtFVA", w, r, c, log)
|
streamErrorVideo("https://www.youtube.com/watch?v=gea_FJrtFVA", w, r, c, log)
|
||||||
return
|
return
|
||||||
} else if resp.Filename != filenameV2 {
|
} else if resp.Filename != filename {
|
||||||
actualExt := filepath.Ext(resp.Filename)
|
actualExt := filepath.Ext(resp.Filename)
|
||||||
expectedExt := filepath.Ext(filenameV2)
|
expectedExt := filepath.Ext(filename)
|
||||||
if actualExt != expectedExt && resp.Streamable != 1 {
|
if actualExt != expectedExt && resp.Streamable != 1 {
|
||||||
log.Errorf("File extension mismatch: %s and %s", filenameV2, resp.Filename)
|
log.Errorf("File extension mismatch: %s and %s", filename, resp.Filename)
|
||||||
streamErrorVideo("https://www.youtube.com/watch?v=t9VgOriBHwE", w, r, c, log)
|
streamErrorVideo("https://www.youtube.com/watch?v=t9VgOriBHwE", w, r, c, log)
|
||||||
return
|
return
|
||||||
} else {
|
} else {
|
||||||
log.Errorf("Filename mismatch: %s and %s", filenameV2, resp.Filename)
|
log.Errorf("Filename mismatch: %s and %s", filename, resp.Filename)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cache.Add(requestPath, resp.Download)
|
cache.Add(requestPath, resp.Download)
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import (
|
|||||||
|
|
||||||
"github.com/debridmediamanager.com/zurg/internal/config"
|
"github.com/debridmediamanager.com/zurg/internal/config"
|
||||||
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
||||||
"github.com/debridmediamanager.com/zurg/pkg/davextra"
|
|
||||||
"github.com/debridmediamanager.com/zurg/pkg/logutil"
|
"github.com/debridmediamanager.com/zurg/pkg/logutil"
|
||||||
"github.com/hashicorp/golang-lru/v2/expirable"
|
"github.com/hashicorp/golang-lru/v2/expirable"
|
||||||
)
|
)
|
||||||
@@ -53,8 +52,7 @@ func HandleHeadRequest(w http.ResponseWriter, r *http.Request, t *torrent.Torren
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
filenameV2, linkFragment := davextra.ExtractLinkFragment(filename)
|
_, file := getFile(torrents, filename)
|
||||||
_, file := getFile(torrents, filenameV2, linkFragment)
|
|
||||||
if file == nil {
|
if file == nil {
|
||||||
log.Errorf("Cannot find file from path %s", requestPath)
|
log.Errorf("Cannot find file from path %s", requestPath)
|
||||||
http.Error(w, "Cannot find file", http.StatusNotFound)
|
http.Error(w, "Cannot find file", http.StatusNotFound)
|
||||||
|
|||||||
@@ -2,17 +2,16 @@ package universal
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
"github.com/debridmediamanager.com/zurg/internal/torrent"
|
||||||
)
|
)
|
||||||
|
|
||||||
// getFile finds a link by a fragment, it might be wrong
|
// getFile finds a link by a fragment, it might be wrong
|
||||||
func getFile(torrents []torrent.Torrent, filename, fragment string) (*torrent.Torrent, *torrent.File) {
|
func getFile(torrents []torrent.Torrent, filename string) (*torrent.Torrent, *torrent.File) {
|
||||||
for t := range torrents {
|
for t := range torrents {
|
||||||
for f, file := range torrents[t].SelectedFiles {
|
for f, file := range torrents[t].SelectedFiles {
|
||||||
fname := filepath.Base(file.Path)
|
fname := filepath.Base(file.Path)
|
||||||
if filename == fname && strings.Contains(file.Link, fragment) {
|
if filename == fname {
|
||||||
return &torrents[t], &torrents[t].SelectedFiles[f]
|
return &torrents[t], &torrents[t].SelectedFiles[f]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,11 +1,7 @@
|
|||||||
package davextra
|
package davextra
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"net/url"
|
|
||||||
"path/filepath"
|
|
||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// GetLinkFragment returns the longest alphanumeric string from a link
|
// GetLinkFragment returns the longest alphanumeric string from a link
|
||||||
@@ -20,33 +16,3 @@ func GetLinkFragment(link string) string {
|
|||||||
}
|
}
|
||||||
return longestMatch[:4]
|
return longestMatch[:4]
|
||||||
}
|
}
|
||||||
|
|
||||||
// InsertLinkFragment inserts the link ID into a filename
|
|
||||||
// returns the new filename
|
|
||||||
func InsertLinkFragment(filename, dupeID string) string {
|
|
||||||
ext := filepath.Ext(filename)
|
|
||||||
name := strings.TrimSuffix(filename, ext)
|
|
||||||
return fmt.Sprintf("%s DMM%s%s", name, dupeID, ext)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ExtractLinkFragment extracts the link ID from a filename
|
|
||||||
// returns the original filename and the link ID
|
|
||||||
func ExtractLinkFragment(filename string) (string, string) {
|
|
||||||
filenameV2, err := url.PathUnescape(filename)
|
|
||||||
if err != nil {
|
|
||||||
filenameV2 = filename
|
|
||||||
}
|
|
||||||
ext := filepath.Ext(filenameV2)
|
|
||||||
name := strings.TrimSuffix(filenameV2, ext)
|
|
||||||
|
|
||||||
r := regexp.MustCompile(`\sDMM(\w+)`)
|
|
||||||
matches := r.FindStringSubmatch(name)
|
|
||||||
if len(matches) < 2 {
|
|
||||||
// No ID found
|
|
||||||
return filenameV2, ""
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove ID from filename
|
|
||||||
originalName := strings.Replace(name, matches[0], "", 1)
|
|
||||||
return originalName + ext, matches[1]
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user