5rahim / seanime

Free and open-source media server for anime and manga that includes library scanning, downloading, transcoding, torrent streaming, and more.
https://seanime.rahim.app
MIT License
308 stars 17 forks source link

feature request: respect only torrent file avaliable scenario in anime-torrent-provider #138

Open EnergoStalin opened 4 days ago

EnergoStalin commented 4 days ago

Checklist

Problem Description / Use Case

I'm writing extension to support jackett aggregator cause i need authentication/proxy for most trackers to work and turns out some trackers don't use magnets at all for example animelayer

part of jackett aggregated response ``` http://127.0.0.1:9117/api/v2.0/indexers/all/results?apikey=[REDACTED]&Query=VTuber&Category[]=5070 ``` ```json { "1": { "FirstSeen": "0001-01-01T00:00:00", "Tracker": "AnimeLayer", "TrackerId": "animelayer", "TrackerType": "semi-private", "CategoryDesc": "TV/Anime", "BlackholeLink": null, "Title": "VTuber Nanda ga Haishin Kiriwasuretara Densetsu ni Natteta / Витубер (12 из 12) Complete [1080p]", "Guid": "https://www.animelayer.ru/torrent/668c20076603002d6d4d4009/download/", "Link": "http://127.0.0.1:9117/dl/animelayer/?jackett_apikey=[REDACTED]&path=Q2ZESjhLb1ZtQllNaHR0TXRmcXlJUXNDWmRFV2M3U3pxTmRhbkk5ZndHOU9kU2VCMWdWaVlDWC16WkVyOHlCT0FSUXlqcHpsYjJPdFRsamhCT0k0SG9WQnlJOUtqRERndFhhcVZLN3J3akdTOVl0N0wxTzE2RkVhNDdNb3Mtb01PQ2ZZRGpDRC1uM185OFRsa25vSUM1eWgxS2xiMHdjVlNiWi1HMkF5a2ZuV3Uxd3hMUEVvNl9VQWRhMXktUG5qOVB3ZVpHMEdRd1cwREF6QVJSbjVlWnRic1Fj&file=VTuber+Nanda+ga+Haishin+Kiriwasuretara+Densetsu+ni+Natteta+_+%D0%92%D0%B8%D1%82%D1%83%D0%B1%D0%B5%D1%80+(12+%D0%B8%D0%B7+12)+Complete+%5B1080p%5D", "Details": "https://www.animelayer.ru/torrent/668c20076603002d6d4d4009/", "PublishDate": "2024-09-22T19:26:00", "Category": [ 5070, 128002 ], "Size": 4273492480, "Files": null, "Grabs": null, "Description": "Субтитры: русские (софтсаб) - Язык: японский", "RageID": null, "TVDBId": null, "Imdb": null, "TMDb": null, "TVMazeId": null, "TraktId": null, "DoubanId": null, "Genres": null, "Languages": [], "Subs": [], "Year": null, "Author": null, "BookTitle": null, "Publisher": null, "Artist": null, "Album": null, "Label": null, "Track": null, "Seeders": 16, "Peers": 2, "Poster": "http://127.0.0.1:9117/img/animelayer/?jackett_apikey=[REDACTED]&path=Q2ZESjhLb1ZtQllNaHR0TXRmcXlJUXNDWmRFRlVyRWN3ZUc5LWxkMFE0NHFHajZaLXE4RjZyQi1zZXRlMFZFUjFUV3hYazBCQnZFZFhRelRLTXd5cDVPdjI4LWxmallOV2FtXzdOX2Z5R2VyVjIzZFdOR0Q1Z05wdHk5Tkhfb3FSMmJZRkhDRkkxQnJwWFk5dXNfM2h6WmlYa1VMWVdiLThyVGlMdUVZQ3ZwR2NfWkxzdUFGVkdjU2xmcW5EeklLdDhFaTV4NVlHLTF2d3RYQW9qZGg0alRTUm9FVUdZd2lGbENjVUc5QWJoYkxfOG5iT0RJdnZ6SUtFbGFjVVd3aUxxQVRScFU1TlFkV2c4MW4zeHZKVFVhd1lINA&file=poster", "InfoHash": null, "MagnetUri": null, "MinimumRatio": null, "MinimumSeedTime": null, "DownloadVolumeFactor": 0, "UploadVolumeFactor": 1, "Gain": 63.68000030517578 } } ```

Proposed Solution

Although i can definitely try bundling parse-torrent from webtorrent i want to avoid doing so at all cost since it makes no sense when extension host can perform the conversion.

So any of this would be sufficient in my case

  1. Respect torrent.Link in case magnet is omitted (disregard potential cookie authentication)
  2. Expose torrent file to magnet conversion in api
5rahim commented 2 days ago

So, if I'm following correctly, by "Respect torrent.Link in case magnet is omitted" you mean handling the case where only the downloadUrl is provided and not the magnet link. If so, I can add the logic to download it to a temporary folder & sending that to the torrent client. There's no ETA for the next release however.

EnergoStalin commented 2 days ago

Yes but it would disregard potential cookie authentication as I stated already so it might not be perfect solution.

As far as I know animelayer is the only tracker which doesn't provide magnet links at all.

Option 2 is preferable cause someone might need it eventually when implementing direct private tracker extension. I remember that's in not planned list so do as you see fit.

Technically it's still possible to write extension for private tracker it just require messing up with code first which is not hard since it's always plaintext or host settings via http since extensions lack native support for them. I mean jackett API won't work without token either.

5rahim commented 2 days ago

it just require messing up with code first which is not hard since it's always plaintext or host settings via http since extensions lack native support for them.

Yeah, extensions can't store user info for now but for later versions I might add a feature to allow them to ask for config values that will be exposed in the code. To avoid issues though, these configs will be reset after every extension update.

Option 2 is preferable cause someone might need it eventually when implementing direct private tracker extension

I'm not really familiar with how to parse private tracker torrent to magnet links, Seanime also doesn't currently have a built-in way to do that. Also don't know how that would work towards cookie authentication since I guess in both cases the file needs to be downloaded (unless I'm wrong).

EnergoStalin commented 2 days ago

I imagine the flow in second case that way:

Extension domain -> On getTorrentMagnetLink called download torrent file(handle cookie there) -> Convert received buffer to base64 for simplicity -> Call provided by seanime convert method -> Seanime domain -> Convert received base64 encoded file to magnet(seems like anacrolix/torrent/metainfo can handle that) -> Extension domain -> Return magnet.

Working conversion example ```go import ( "bytes" "encoding/base64" "fmt" "os" "github.com/anacrolix/torrent/metainfo" ) func b64torrent2magnet(base64Torrent string) (string, error) { torrentData, err := base64.StdEncoding.DecodeString(base64Torrent) if err != nil { return "", err } torrentDataReader := bytes.NewReader(torrentData) meta, err := metainfo.Load(torrentDataReader) if err != nil { return "", err } magnetLink, err := meta.MagnetV2() if err != nil { return "", err } return magnetLink.String(), nil } func main() { content, _ := os.ReadFile("b64torrent.txt") fmt.Println(b64torrent2magnet(string(content))) } ```
Extension site example ```ts class Provider { async getTorrentMagnetLink(torrent: AnimeTorrent): Promise { if(torrent.magnetLink) { return torrent.magnetLink } if(!!torrent.downloadUrl) { return "" } // Should be binary but i don't see blob in response definition this might break torrent const data = await fetch(torrent.downloadUrl).then(e => e.text()) // Kinda try to restore original buffer const buffer = CryptoJS.enc.Utf8.parse(data) const b64 = CryptoJS.enc.Base64.stringify(buffer) return b64torrent2magnet(b64) // globall call } } ```

Base64 is optional cause i'm myself not sure how to pass raw buffers across host and extension. If you know the way please avoid base64.

There's another option i was thinking of is to directly accept base64 encoded torrent file in getTorrentMagnetLink callback but it's kinda counter intuitive and ambiguous.