diff --git a/config/logger.go b/config/logger.go new file mode 100644 index 00000000..dcdccdbd --- /dev/null +++ b/config/logger.go @@ -0,0 +1,15 @@ +package config + +// Constants for logger. +const ( + AccessLogFilePath = "log/access" + AccessLogFileExtension = ".txt" + AccessLogMaxSize = 5 // megabytes + AccessLogMaxBackups = 7 + AccessLogMaxAge = 30 //days + ErrorLogFilePath = "log/error" + ErrorLogFileExtension = ".json" + ErrorLogMaxSize = 10 // megabytes + ErrorLogMaxBackups = 7 + ErrorLogMaxAge = 30 //days +) diff --git a/css/style.css b/css/style.css index 8f43a117..5eb9efb2 100644 --- a/css/style.css +++ b/css/style.css @@ -15,7 +15,7 @@ nav#mainmenu { position: fixed; color: white; width: 100%; - z-index: 2; + z-index: 3; } nav#mainmenu a { color: white; @@ -63,3 +63,10 @@ a { .torrent-info .filesize { white-space: nowrap; } + +div.container div.blockBody:nth-of-type(2) table{table-layout:fixed;} +div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:first-of-type, div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:nth-of-type(5){width:10%;} +div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:nth-of-type(3){width:15%;} +div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:nth-of-type(4){width:19%;} +div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-type{width:6%;} +tr.torrent-info td.hash,tr.torrent-info td.date{word-wrap:break-word;} diff --git a/js/main.js b/js/main.js index 32833ac8..04089014 100644 --- a/js/main.js +++ b/js/main.js @@ -28,3 +28,11 @@ document.getElementById('page-next').href = pageString + next + query; document.getElementById('page-prev').href = pageString + prev + query; + +// Used by spoiler tags +function toggleLayer(elem) { + if (elem.classList.contains("hide")) + elem.classList.remove("hide"); + else + elem.classList.add("hide"); +} diff --git a/main.go b/main.go index 254cab4e..fddc75fb 100644 --- a/main.go +++ b/main.go @@ -18,7 +18,14 @@ import ( ) var router *mux.Router - +type SearchParam struct { + Category string + Order string + Query string + Max int + Status string + Sort string +} func apiHandler(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) @@ -73,21 +80,51 @@ func searchHandler(w http.ResponseWriter, r *http.Request) { page := vars["page"] // db params url - maxPerPage, errConv := strconv.Atoi(r.URL.Query().Get("max")) - if errConv != nil { - maxPerPage = 50 // default Value maxPerPage - } pagenum, _ := strconv.Atoi(html.EscapeString(page)) if pagenum == 0 { pagenum = 1 } - searchQuery := r.URL.Query().Get("q") - cat := r.URL.Query().Get("c") - stat := r.URL.Query().Get("s") - sort := r.URL.Query().Get("sort") - order := r.URL.Query().Get("order") + + b := []model.TorrentsJson{} + + search_param, torrents, nbTorrents := searchByQuery( r, pagenum ) - catsSplit := strings.Split(cat, "_") + for i, _ := range torrents { + res := torrents[i].ToJson() + b = append(b, res) + } + + navigationTorrents := Navigation{nbTorrents, search_param.Max, pagenum, "search_page"} + searchForm := SearchForm{ + search_param.Query, + search_param.Status, + search_param.Category, + search_param.Sort, + search_param.Order, + } + htv := HomeTemplateVariables{b, torrentService.GetAllCategories(false), searchForm, navigationTorrents, r.URL, mux.CurrentRoute(r)} + + err := templates.ExecuteTemplate(w, "index.html", htv) + if err != nil { + http.Error(w, err.Error(), http.StatusInternalServerError) + } +} + +func searchByQuery(r *http.Request, pagenum int) (SearchParam, []model.Torrents, int) { + maxPerPage, errConv := strconv.Atoi(r.URL.Query().Get("max")) + if errConv != nil { + maxPerPage = 50 // default Value maxPerPage + } + + search_param := SearchParam{} + search_param.Max = maxPerPage + search_param.Query = r.URL.Query().Get("q") + search_param.Category = r.URL.Query().Get("c") + search_param.Status = r.URL.Query().Get("s") + search_param.Sort = r.URL.Query().Get("sort") + search_param.Order = r.URL.Query().Get("order") + + catsSplit := strings.Split(search_param.Category, "_") // need this to prevent out of index panics var searchCatId, searchSubCatId string if len(catsSplit) == 2 { @@ -95,35 +132,38 @@ func searchHandler(w http.ResponseWriter, r *http.Request) { searchCatId = html.EscapeString(catsSplit[0]) searchSubCatId = html.EscapeString(catsSplit[1]) } - if sort == "" { - sort = "torrent_id" + if search_param.Sort == "" { + search_param.Sort = "torrent_id" } - if order == "" { - order = "desc" + if search_param.Order == "" { + search_param.Order = "desc" } - order_by := sort + " " + order + order_by := search_param.Sort + " " + search_param.Order - nbTorrents := 0 - - b := []model.TorrentsJson{} - - parameters := torrentService.CreateWhereParams("torrent_name LIKE ? AND status_id LIKE ? AND category_id LIKE ? AND sub_category_id LIKE ?", - "%"+searchQuery+"%", stat+"%", searchCatId+"%", searchSubCatId+"%") - torrents, nbTorrents := torrentService.GetTorrentsOrderBy(¶meters, order_by, maxPerPage, maxPerPage*(pagenum-1)) - - for i, _ := range torrents { - res := torrents[i].ToJson() - b = append(b, res) + parameters := torrentService.WhereParams{} + conditions := []string{} + if searchCatId != "" { + conditions = append(conditions, "category_id = ?") + parameters.Params = append(parameters.Params, searchCatId) + } + if searchSubCatId != "" { + conditions = append(conditions, "sub_category_id = ?") + parameters.Params = append(parameters.Params, searchSubCatId) + } + if search_param.Status != "" { + conditions = append(conditions, "status_id = ?") + parameters.Params = append(parameters.Params, search_param.Status) + } + searchQuerySplit := strings.Split(search_param.Query, " ") + for i, _ := range searchQuerySplit { + conditions = append(conditions, "torrent_name LIKE ?") + parameters.Params = append(parameters.Params, "%"+searchQuerySplit[i]+"%") } - navigationTorrents := Navigation{nbTorrents, maxPerPage, pagenum, "search_page"} - searchForm := SearchForm{searchQuery, stat, cat, sort, order} - htv := HomeTemplateVariables{b, torrentService.GetAllCategories(false), searchForm, navigationTorrents, r.URL, mux.CurrentRoute(r)} - - err := templates.ExecuteTemplate(w, "index.html", htv) - if err != nil { - http.Error(w, err.Error(), http.StatusInternalServerError) - } + parameters.Conditions = strings.Join(conditions[:], " AND ") + log.Infof("SQL query is :: %s\n", parameters.Conditions) + torrents, n := torrentService.GetTorrentsOrderBy(¶meters, order_by, maxPerPage, maxPerPage*(pagenum-1)) + return search_param, torrents, n } func faqHandler(w http.ResponseWriter, r *http.Request) { @@ -135,20 +175,12 @@ func faqHandler(w http.ResponseWriter, r *http.Request) { } func rssHandler(w http.ResponseWriter, r *http.Request) { - //vars := mux.Vars(r) - //category := vars["c"] - // db params url - //maxPerPage := 50 // default Value maxPerPage + _, torrents, _ := searchByQuery( r, 1 ) + created_as_time := time.Now() - torrents := torrentService.GetFeeds() - created := time.Now().String() if len(torrents) > 0 { - created = torrents[0].Timestamp - } - created_as_time, err := time.Parse("2006-01-02 15:04:05", created) - if err == nil { - + created_as_time = time.Unix(torrents[0].Date, 0) } feed := &feeds.Feed{ Title: "Nyaa Pantsu", @@ -159,17 +191,16 @@ func rssHandler(w http.ResponseWriter, r *http.Request) { feed.Items = make([]*feeds.Item, len(torrents)) for i, _ := range torrents { - timestamp_as_time, err := time.Parse("2006-01-02 15:04:05", torrents[i].Timestamp) - if err == nil { - feed.Items[i] = &feeds.Item{ - // need a torrent view first - //Id: URL + torrents[i].Hash, - Title: torrents[i].Name, - Link: &feeds.Link{Href: string(torrents[i].Magnet)}, - Description: "", - Created: timestamp_as_time, - Updated: timestamp_as_time, - } + timestamp_as_time := time.Unix(torrents[0].Date, 0) + torrent_json := torrents[i].ToJson() + feed.Items[i] = &feeds.Item{ + // need a torrent view first + //Id: URL + torrents[i].Hash, + Title: torrents[i].Name, + Link: &feeds.Link{Href: string(torrent_json.Magnet)}, + Description: "", + Created: timestamp_as_time, + Updated: timestamp_as_time, } } @@ -180,6 +211,7 @@ func rssHandler(w http.ResponseWriter, r *http.Request) { http.Error(w, err.Error(), http.StatusInternalServerError) } } + func viewHandler(w http.ResponseWriter, r *http.Request) { var templates = template.Must(template.ParseFiles("templates/index.html", "templates/view.html")) vars := mux.Vars(r) @@ -264,4 +296,4 @@ func main() { err := srv.ListenAndServe() log.CheckError(err) -} \ No newline at end of file +} diff --git a/service/torrent/torrent.go b/service/torrent/torrent.go index ea8841ad..c057d9c6 100644 --- a/service/torrent/torrent.go +++ b/service/torrent/torrent.go @@ -9,8 +9,8 @@ import ( ) type WhereParams struct { - conditions string // Ex : name LIKE ? AND category_id LIKE ? - params []interface{} + Conditions string // Ex : name LIKE ? AND category_id LIKE ? + Params []interface{} } /* Function to interact with Models @@ -57,8 +57,8 @@ func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs conditions := "torrent_hash is not null" //filter out broken entries var params []interface{} if parameters != nil { // if there is where parameters - conditions += " AND " + parameters.conditions - params = parameters.params + conditions += " AND " + parameters.Conditions + params = parameters.Params } db.ORM.Model(&torrents).Where(conditions, params...).Count(&count) dbQuery = db.ORM.Model(&torrents).Where(conditions, params...) @@ -118,9 +118,9 @@ func GetAllCategories(populatedWithTorrents bool) []model.Categories { func CreateWhereParams(conditions string, params ...string) WhereParams { whereParams := WhereParams{} - whereParams.conditions = conditions + whereParams.Conditions = conditions for i, _ := range params { - whereParams.params = append(whereParams.params, params[i]) + whereParams.Params = append(whereParams.Params, params[i]) } return whereParams diff --git a/templates/FAQ.html b/templates/FAQ.html index 029256b8..f7403c6c 100644 --- a/templates/FAQ.html +++ b/templates/FAQ.html @@ -1,28 +1,31 @@ {{define "title"}}FAQ{{end}} {{define "content"}}
-

NOTICE: KEEP SEEDING YOU RETARD

+ +

NOTICE: KEEP SEEDING YOU RETARD

Official Nyaapocalypse FAQ

+

Links for the replacement/mirror

- Nyaa - nyaa.pantsu.cat + Nyaa - nyaa.pantsu.cat
Sukebei - sukebei.pantsu.cat

What happened?

-

Is everything Lost?

+

Is everything lost?

In short, No.

Are some things lost?

-

We have a database of the torrents on nyaa up to April 5. That means that everything past April 5 is gone. - Sukebei, however is in worse shape. We only have sukebei databases up to 2016.

+

We have a database of the torrents on nyaa up to April 5 May 1. That means almost nothing is lost.

+

Sukebei, however might be in worse shape. Currently we only have sukebei databases up to 2016, + but a newer database might be available for use.

How are we recovering?

The aforementioned databases are being hosted at nyaa.pantsu.cat and sukebei.pantsu.cat. @@ -38,11 +41,16 @@

Just use the magnet link. The magnet link will used by your BitTorrent client to look up the file on the DHT network and it should download just fine.

If your magnet link starts with "magnet:magnet:", delete the first "magnet:". It should look like: - magnet:?xt=urn:btih:[hash]&dn=[name]&tr=[tracker]

+ magnet:?xt=urn:btih:[hash]&dn=[name]&tr=[tracker]&tr=[...]

-

How can I help?

-

If you have website development expertise, you can join the #nyaapantsu IRC channel on irc.rizon.net. If you have any current databases, UPLOAD THEM.

+

How can I help?

+

If you have website development expertise, you can join the #nyaapantsu IRC channel on irc.rizon.net. + If you have any current databases, especially for sukebei, UPLOAD THEM.

-

nyaa.pantsu.cat and sukebei.pantsu.cat do not host any files.

+

Your design sucks / I found a bug

+

https://github.com/ewhal/nyaa/issues.

+ +
+

nyaa.pantsu.cat and sukebei.pantsu.cat do not host any files.

-{{end}} \ No newline at end of file +{{end}} diff --git a/templates/home.html b/templates/home.html index a27aa24c..0c47a7b9 100644 --- a/templates/home.html +++ b/templates/home.html @@ -32,9 +32,9 @@ - - - + {{end}} @@ -45,4 +45,4 @@ -{{end}} \ No newline at end of file +{{end}} diff --git a/templates/view.html b/templates/view.html index 3f085593..b113c36b 100644 --- a/templates/view.html +++ b/templates/view.html @@ -28,7 +28,8 @@ Links - + @@ -38,4 +39,4 @@ {{end}} -{{end}} \ No newline at end of file +{{end}} diff --git a/util/log/logger.go b/util/log/logger.go new file mode 100644 index 00000000..02bdf522 --- /dev/null +++ b/util/log/logger.go @@ -0,0 +1,130 @@ +package log + +import ( + "net/http" + "os" + + "github.com/Sirupsen/logrus" + "github.com/ewhal/nyaa/config" + lumberjack "gopkg.in/natefinch/lumberjack.v2" +) + +func LumberJackLogger(filePath string, maxSize int, maxBackups int, maxAge int) *lumberjack.Logger { + return &lumberjack.Logger{ + Filename: filePath, + MaxSize: maxSize, // megabytes + MaxBackups: maxBackups, + MaxAge: maxAge, //days + } +} + +func InitLogToStdoutDebug() { + logrus.SetFormatter(&logrus.TextFormatter{ForceColors: true}) + logrus.SetOutput(os.Stdout) + logrus.SetLevel(logrus.DebugLevel) +} + +func InitLogToStdout() { + logrus.SetFormatter(&logrus.TextFormatter{}) + logrus.SetOutput(os.Stdout) + logrus.SetLevel(logrus.WarnLevel) +} + +func InitLogToFile() { + logrus.SetFormatter(&logrus.JSONFormatter{}) + + out := LumberJackLogger(config.ErrorLogFilePath+config.ErrorLogFileExtension, config.ErrorLogMaxSize, config.ErrorLogMaxBackups, config.ErrorLogMaxAge) + + + logrus.SetOutput(out) + logrus.SetLevel(logrus.WarnLevel) +} + + + +// Init logrus +func Init(environment string) { + switch environment { + case "DEVELOPMENT": + InitLogToStdoutDebug() + case "TEST": + InitLogToFile() + case "PRODUCTION": + InitLogToFile() + } + logrus.Debugf("Environment : %s", environment) +} + +// Debug logs a message with debug log level. +func Debug(msg string) { + logrus.Debug(msg) +} + +// Debugf logs a formatted message with debug log level. +func Debugf(msg string, args ...interface{}) { + logrus.Debugf(msg, args...) +} + +// Info logs a message with info log level. +func Info(msg string) { + logrus.Info(msg) +} + +// Infof logs a formatted message with info log level. +func Infof(msg string, args ...interface{}) { + logrus.Infof(msg, args...) +} + +// Warn logs a message with warn log level. +func Warn(msg string) { + logrus.Warn(msg) +} + +// Warnf logs a formatted message with warn log level. +func Warnf(msg string, args ...interface{}) { + logrus.Warnf(msg, args...) +} + +// Error logs a message with error log level. +func Error(msg string) { + logrus.Error(msg) +} + +// Errorf logs a formatted message with error log level. +func Errorf(msg string, args ...interface{}) { + logrus.Errorf(msg, args...) +} + +// Fatal logs a message with fatal log level. +func Fatal(msg string) { + logrus.Fatal(msg) +} + +// Fatalf logs a formatted message with fatal log level. +func Fatalf(msg string, args ...interface{}) { + logrus.Fatalf(msg, args...) +} + +// Panic logs a message with panic log level. +func Panic(msg string) { + logrus.Panic(msg) +} + +// Panicf logs a formatted message with panic log level. +func Panicf(msg string, args ...interface{}) { + logrus.Panicf(msg, args...) +} + +// log response body data for debugging +func DebugResponse(response *http.Response) string { + bodyBuffer := make([]byte, 5000) + var str string + count, err := response.Body.Read(bodyBuffer) + for ; count > 0; count, err = response.Body.Read(bodyBuffer) { + if err != nil { + } + str += string(bodyBuffer[:count]) + } + Debugf("response data : %v", str) + return str +}