Torznab caps compatible
Cette révision appartient à :
Parent
6681a6b985
révision
fb2c69a612
5 fichiers modifiés avec 229 ajouts et 50 suppressions
|
@ -58,7 +58,9 @@ func init() {
|
|||
Router.HandleFunc("/feed", RSSHandler).Name("feed")
|
||||
Router.HandleFunc("/feed/{page:[0-9]+}", RSSHandler).Name("feed_page")
|
||||
Router.HandleFunc("/feed/torznab", RSSTorznabHandler).Name("feed_torznab")
|
||||
Router.HandleFunc("/feed/torznab/{page:[0-9]+}", RSSTorznabHandler).Name("feed_torznab_page")
|
||||
Router.HandleFunc("/feed/eztv", RSSEztvHandler).Name("feed_eztv")
|
||||
Router.HandleFunc("/feed/eztv/{page:[0-9]+}", RSSEztvHandler).Name("feed_eztv_page")
|
||||
|
||||
// !!! This line need to have the same download location as the one define in config.TorrentStorageLink !!!
|
||||
Router.Handle("/download/{hash}", wrapHandler(downloadTorrentHandler)).Name("torrent_download")
|
||||
|
|
|
@ -7,10 +7,14 @@ import (
|
|||
"strconv"
|
||||
"time"
|
||||
|
||||
"sort"
|
||||
|
||||
"github.com/NyaaPantsu/nyaa/config"
|
||||
"github.com/NyaaPantsu/nyaa/model"
|
||||
userService "github.com/NyaaPantsu/nyaa/service/user"
|
||||
"github.com/NyaaPantsu/nyaa/util/categories"
|
||||
"github.com/NyaaPantsu/nyaa/util/feeds"
|
||||
"github.com/NyaaPantsu/nyaa/util/publicSettings"
|
||||
"github.com/NyaaPantsu/nyaa/util/search"
|
||||
"github.com/gorilla/feeds"
|
||||
"github.com/gorilla/mux"
|
||||
|
@ -122,60 +126,130 @@ func RSSEztvHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
}
|
||||
|
||||
// RSSEztvHandler : Controller for displaying rss feed, accepting common search arguments
|
||||
// RSSTorznabHandler : Controller for displaying rss feed, accepting common search arguments
|
||||
func RSSTorznabHandler(w http.ResponseWriter, r *http.Request) {
|
||||
defer r.Body.Close()
|
||||
|
||||
// We only get the basic variable for rss based on search param
|
||||
torrents, createdAsTime, title, err := getTorrentList(r)
|
||||
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
t := r.URL.Query().Get("t")
|
||||
rss := ""
|
||||
title := "Nyaa Pantsu"
|
||||
if config.IsSukebei() {
|
||||
title = "Sukebei Pantsu"
|
||||
}
|
||||
if t == "caps" {
|
||||
T := publicSettings.GetTfuncFromRequest(r)
|
||||
cat := categories.GetCategoriesSelect(true)
|
||||
var categories []*nyaafeeds.RssCategoryTorznab
|
||||
var keys []string
|
||||
for name := range cat {
|
||||
keys = append(keys, name)
|
||||
}
|
||||
sort.Strings(keys)
|
||||
last := -1
|
||||
for _, key := range keys {
|
||||
if len(cat[key]) <= 2 {
|
||||
categories = append(categories, &nyaafeeds.RssCategoryTorznab{
|
||||
ID: nyaafeeds.ConvertFromCat(cat[key]),
|
||||
Name: string(T(key)),
|
||||
})
|
||||
last++
|
||||
} else {
|
||||
categories[last].Subcat = append(categories[last].Subcat, &nyaafeeds.RssSubCat{
|
||||
ID: nyaafeeds.ConvertFromCat(cat[key]),
|
||||
Name: string(T(key)),
|
||||
})
|
||||
}
|
||||
}
|
||||
feed := &nyaafeeds.RssCaps{
|
||||
Server: &nyaafeeds.RssServer{
|
||||
Version: "1.0",
|
||||
Title: title,
|
||||
Strapline: "...",
|
||||
Email: config.Conf.Email.From,
|
||||
URL: config.WebAddress(),
|
||||
Image: config.WebAddress() + "/img/logo.png",
|
||||
},
|
||||
Limits: &nyaafeeds.RssLimits{
|
||||
Max: "300",
|
||||
Default: "50",
|
||||
},
|
||||
Registration: &nyaafeeds.RssRegistration{
|
||||
Available: "yes",
|
||||
Open: "yes",
|
||||
},
|
||||
Searching: &nyaafeeds.RssSearching{
|
||||
Search: &nyaafeeds.RssSearch{
|
||||
Available: "yes",
|
||||
SupportedParams: "q",
|
||||
},
|
||||
TvSearch: &nyaafeeds.RssSearch{
|
||||
Available: "no",
|
||||
},
|
||||
MovieSearch: &nyaafeeds.RssSearch{
|
||||
Available: "no",
|
||||
},
|
||||
},
|
||||
Categories: &nyaafeeds.RssCategories{
|
||||
Category: categories,
|
||||
},
|
||||
}
|
||||
var rssErr error
|
||||
rss, rssErr = feeds.ToXML(feed)
|
||||
if rssErr != nil {
|
||||
http.Error(w, rssErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
} else {
|
||||
// We only get the basic variable for rss based on search param
|
||||
torrents, createdAsTime, title, err := getTorrentList(r)
|
||||
|
||||
feed := &nyaafeeds.RssFeed{
|
||||
Title: title,
|
||||
Link: config.WebAddress() + "/",
|
||||
PubDate: createdAsTime.String(),
|
||||
}
|
||||
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
|
||||
if err != nil {
|
||||
http.Error(w, err.Error(), http.StatusBadRequest)
|
||||
return
|
||||
}
|
||||
|
||||
for i, torrent := range torrents {
|
||||
torrentJSON := torrent.ToJSON()
|
||||
feed.Items[i] = &nyaafeeds.RssItem{
|
||||
Title: torrentJSON.Name,
|
||||
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
|
||||
Category: &nyaafeeds.RssCategory{
|
||||
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
|
||||
},
|
||||
Description: string(torrentJSON.Description),
|
||||
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
|
||||
PubDate: torrent.Date.String(),
|
||||
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
|
||||
Enclosure: &nyaafeeds.RssEnclosure{
|
||||
URL: config.WebAddress() + "/download/" + torrentJSON.Hash,
|
||||
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
|
||||
Type: "application/x-bittorrent",
|
||||
},
|
||||
Torznab: &nyaafeeds.RssTorznab{
|
||||
Xmlns: "http://torznab.com/schemas/2015/feed",
|
||||
Size: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
|
||||
Files: strconv.Itoa(len(torrentJSON.FileList)),
|
||||
Grabs: strconv.Itoa(torrentJSON.Downloads),
|
||||
Seeders: strconv.Itoa(int(torrentJSON.Seeders)),
|
||||
Leechers: strconv.Itoa(int(torrentJSON.Leechers)),
|
||||
Infohash: torrentJSON.Hash,
|
||||
MagnetURL: string(torrentJSON.Magnet),
|
||||
},
|
||||
feed := &nyaafeeds.RssFeed{
|
||||
Title: title,
|
||||
Link: config.WebAddress() + "/",
|
||||
PubDate: createdAsTime.String(),
|
||||
}
|
||||
feed.Items = make([]*nyaafeeds.RssItem, len(torrents))
|
||||
|
||||
for i, torrent := range torrents {
|
||||
torrentJSON := torrent.ToJSON()
|
||||
feed.Items[i] = &nyaafeeds.RssItem{
|
||||
Title: torrentJSON.Name,
|
||||
Link: config.WebAddress() + "/download/" + torrentJSON.Hash,
|
||||
Category: &nyaafeeds.RssCategory{
|
||||
Domain: config.WebAddress() + "/search?c=" + torrentJSON.Category + "_" + torrentJSON.SubCategory,
|
||||
},
|
||||
Description: string(torrentJSON.Description),
|
||||
Comments: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
|
||||
PubDate: torrent.Date.String(),
|
||||
GUID: config.WebAddress() + "/view/" + strconv.FormatUint(uint64(torrentJSON.ID), 10),
|
||||
Enclosure: &nyaafeeds.RssEnclosure{
|
||||
URL: config.WebAddress() + "/download/" + torrentJSON.Hash,
|
||||
Length: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
|
||||
Type: "application/x-bittorrent",
|
||||
},
|
||||
Torznab: &nyaafeeds.RssTorznab{
|
||||
Xmlns: "http://torznab.com/schemas/2015/feed",
|
||||
Size: strconv.FormatUint(uint64(torrentJSON.Filesize), 10),
|
||||
Files: strconv.Itoa(len(torrentJSON.FileList)),
|
||||
Grabs: strconv.Itoa(torrentJSON.Downloads),
|
||||
Seeders: strconv.Itoa(int(torrentJSON.Seeders)),
|
||||
Leechers: strconv.Itoa(int(torrentJSON.Leechers)),
|
||||
Infohash: torrentJSON.Hash,
|
||||
MagnetURL: string(torrentJSON.Magnet),
|
||||
},
|
||||
}
|
||||
}
|
||||
var rssErr error
|
||||
rss, rssErr = feeds.ToXML(feed)
|
||||
if rssErr != nil {
|
||||
http.Error(w, rssErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
}
|
||||
// allow cross domain AJAX requests
|
||||
w.Header().Set("Access-Control-Allow-Origin", "*")
|
||||
rss, rssErr := feeds.ToXML(feed)
|
||||
if rssErr != nil {
|
||||
http.Error(w, rssErr.Error(), http.StatusInternalServerError)
|
||||
}
|
||||
|
||||
_, writeErr := w.Write([]byte(rss))
|
||||
if writeErr != nil {
|
||||
|
@ -187,6 +261,7 @@ func getTorrentList(r *http.Request) (torrents []model.Torrent, createdAsTime ti
|
|||
vars := mux.Vars(r)
|
||||
page := vars["page"]
|
||||
userID := vars["id"]
|
||||
cat := r.URL.Query().Get("cat")
|
||||
|
||||
offset := r.URL.Query().Get("offset")
|
||||
pagenum := 1
|
||||
|
@ -222,6 +297,12 @@ func getTorrentList(r *http.Request) (torrents []model.Torrent, createdAsTime ti
|
|||
r.URL.RawQuery = query.Encode()
|
||||
}
|
||||
|
||||
if cat != "" {
|
||||
query := r.URL.Query()
|
||||
c, sub := nyaafeeds.ConvertToCat(cat)
|
||||
query.Set("c", c+"_"+sub)
|
||||
}
|
||||
|
||||
_, torrents, err = search.SearchByQueryNoCount(r, pagenum)
|
||||
|
||||
createdAsTime = time.Now()
|
||||
|
|
|
@ -161,7 +161,7 @@ func getTorrentsOrderBy(parameters *serviceBase.WhereParams, orderBy string, lim
|
|||
if countAll {
|
||||
dbQ = dbQ.Preload("Comments")
|
||||
}
|
||||
err = dbQ.Raw(dbQuery, params...).Find(&torrents).Error
|
||||
err = dbQ.Preload("FileList").Raw(dbQuery, params...).Find(&torrents).Error
|
||||
return
|
||||
}
|
||||
|
||||
|
|
25
util/feeds/convert.go
Fichier normal
25
util/feeds/convert.go
Fichier normal
|
@ -0,0 +1,25 @@
|
|||
package nyaafeeds
|
||||
|
||||
import (
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ConvertToCat : Convert a torznab cat to our cat
|
||||
func ConvertToCat(cat string) (string, string) {
|
||||
c := strings.Split(cat, "0000")
|
||||
if len(c) < 2 {
|
||||
return cat, ""
|
||||
}
|
||||
return c[0], c[1]
|
||||
}
|
||||
|
||||
// ConvertFromCat : Convert a cat to a torznab cat
|
||||
func ConvertFromCat(category string) (cat string) {
|
||||
c := strings.Split(category, "_")
|
||||
if len(c) < 2 {
|
||||
cat = c[0] + "0000"
|
||||
return
|
||||
}
|
||||
cat = c[0] + "0000" + c[1]
|
||||
return
|
||||
}
|
|
@ -15,9 +15,11 @@ import (
|
|||
|
||||
// private wrapper around the RssFeed which gives us the <rss>..</rss> xml
|
||||
type rssFeedXML struct {
|
||||
XMLName xml.Name `xml:"rss"`
|
||||
Version string `xml:"version,attr"`
|
||||
Channel *RssFeed
|
||||
XMLName xml.Name `xml:"rss"`
|
||||
Version string `xml:"version,attr"`
|
||||
Encoding string `xml:"encoding,attr"`
|
||||
Channel *RssFeed `xml:"channel,omitempty"`
|
||||
Caps *RssCaps `xml:"caps,omitempty"`
|
||||
}
|
||||
|
||||
type RssImage struct {
|
||||
|
@ -77,6 +79,70 @@ type RssItem struct {
|
|||
Torznab *RssTorznab `xml:"torznab,omitempty"`
|
||||
}
|
||||
|
||||
type RssCaps struct {
|
||||
XMLName xml.Name `xml:"caps"`
|
||||
Server *RssServer `xml:"server,omitempty"`
|
||||
Limits *RssLimits `xml:"limits,omitempty"`
|
||||
Registration *RssRegistration `xml:"registration,omitempty"`
|
||||
Searching *RssSearching `xml:"searching,omitempty"`
|
||||
Categories *RssCategories `xml:"categories,omitempty"`
|
||||
}
|
||||
|
||||
type RssServer struct {
|
||||
XMLName xml.Name `xml:"server"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
Version string `xml:"version,attr"`
|
||||
Title string `xml:"title,attr"`
|
||||
Strapline string `xml:"strapline,attr"`
|
||||
Email string `xml:"email,attr"`
|
||||
URL string `xml:"url,attr"`
|
||||
Image string `xml:"image,attr"`
|
||||
}
|
||||
|
||||
type RssLimits struct {
|
||||
XMLName xml.Name `xml:"limits"`
|
||||
Max string `xml:"limits,attr"`
|
||||
Default string `xml:"default,attr"`
|
||||
}
|
||||
|
||||
type RssRegistration struct {
|
||||
XMLName xml.Name `xml:"registration"`
|
||||
Available string `xml:"available,attr"`
|
||||
Open string `xml:"open,attr"`
|
||||
}
|
||||
|
||||
type RssSearching struct {
|
||||
XMLName xml.Name `xml:"searching"`
|
||||
Search *RssSearch `xml:"search,omitempty"`
|
||||
TvSearch *RssSearch `xml:"tv-search,omitempty"`
|
||||
MovieSearch *RssSearch `xml:"movie-search,omitempty"`
|
||||
}
|
||||
|
||||
type RssSearch struct {
|
||||
Available string `xml:"available,attr"`
|
||||
SupportedParams string `xml:"supportedParams,attr,omitempty"`
|
||||
}
|
||||
|
||||
type RssCategories struct {
|
||||
XMLName xml.Name `xml:"categories"`
|
||||
Category []*RssCategoryTorznab
|
||||
}
|
||||
|
||||
type RssCategoryTorznab struct {
|
||||
XMLName xml.Name `xml:"category"`
|
||||
ID string `xml:"id,attr"`
|
||||
Name string `xml:"name,attr"`
|
||||
Subcat []*RssSubCat
|
||||
Description string `xml:"description,attr,omitempty"`
|
||||
}
|
||||
|
||||
type RssSubCat struct {
|
||||
XMLName xml.Name `xml:"subcat"`
|
||||
ID string `xml:"id"`
|
||||
Name string `xml:"name"`
|
||||
Description string `xml:"description,omitempty"`
|
||||
}
|
||||
|
||||
type RssTorrent struct {
|
||||
XMLName xml.Name `xml:"torrent"`
|
||||
Xmlns string `xml:"xmlns,attr"`
|
||||
|
@ -195,5 +261,10 @@ func (r *Rss) FeedXml() interface{} {
|
|||
|
||||
// FeedXml : return an XML-ready object for an RssFeed object
|
||||
func (r *RssFeed) FeedXml() interface{} {
|
||||
return &rssFeedXML{Version: "2.0", Channel: r}
|
||||
return &rssFeedXML{Version: "2.0", Encoding: "UTF-8", Channel: r}
|
||||
}
|
||||
|
||||
// FeedXml : return an XML-ready object for an RssFeed object
|
||||
func (r *RssCaps) FeedXml() interface{} {
|
||||
return &rssFeedXML{Version: "2.0", Encoding: "UTF-8", Caps: r}
|
||||
}
|
||||
|
|
Référencer dans un nouveau ticket