2017-05-02 12:39:53 +02:00
package main
import (
2017-05-05 15:08:02 +02:00
"bufio"
2017-05-02 12:39:53 +02:00
"encoding/json"
2017-05-05 14:10:35 +02:00
"fmt"
"flag"
2017-05-04 21:48:40 +02:00
"github.com/gorilla/feeds"
2017-05-02 12:39:53 +02:00
"github.com/gorilla/mux"
2017-05-05 14:20:51 +02:00
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/util/log"
2017-05-05 15:08:02 +02:00
"github.com/ewhal/nyaa/config"
2017-05-05 14:20:51 +02:00
2017-05-02 12:39:53 +02:00
"html"
"html/template"
"net/http"
2017-05-05 14:10:35 +02:00
"os"
2017-05-02 12:39:53 +02:00
"strconv"
2017-05-03 06:59:27 +02:00
"strings"
2017-05-02 12:39:53 +02:00
"time"
)
2017-05-05 03:53:38 +02:00
var router * mux . Router
2017-05-05 13:37:22 +02:00
type SearchParam struct {
Category string
Order string
Query string
Max int
Status string
Sort string
}
2017-05-02 12:39:53 +02:00
func apiHandler ( w http . ResponseWriter , r * http . Request ) {
vars := mux . Vars ( r )
page := vars [ "page" ]
pagenum , _ := strconv . Atoi ( html . EscapeString ( page ) )
2017-05-05 14:20:51 +02:00
b := model . CategoryJson { Torrents : [ ] model . TorrentsJson { } }
2017-05-04 05:28:42 +02:00
maxPerPage := 50
nbTorrents := 0
2017-05-05 14:20:51 +02:00
torrents , nbTorrents := torrentService . GetAllTorrents ( maxPerPage , maxPerPage * ( pagenum - 1 ) )
2017-05-04 05:28:42 +02:00
for i , _ := range torrents {
2017-05-05 14:20:51 +02:00
res := torrents [ i ] . ToJson ( )
2017-05-04 05:28:42 +02:00
b . Torrents = append ( b . Torrents , res )
2017-05-02 12:39:53 +02:00
}
2017-05-05 03:53:38 +02:00
2017-05-04 05:28:42 +02:00
b . QueryRecordCount = maxPerPage
b . TotalRecordCount = nbTorrents
2017-05-02 12:39:53 +02:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
2017-05-04 05:28:42 +02:00
err := json . NewEncoder ( w ) . Encode ( b )
2017-05-02 12:39:53 +02:00
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
}
2017-05-04 17:16:20 +02:00
2017-05-05 02:54:37 +02:00
func apiViewHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-02 12:39:53 +02:00
vars := mux . Vars ( r )
id := vars [ "id" ]
2017-05-05 14:20:51 +02:00
b := model . CategoryJson { Torrents : [ ] model . TorrentsJson { } }
2017-05-04 05:28:42 +02:00
2017-05-05 14:20:51 +02:00
torrent , err := torrentService . GetTorrentById ( id )
res := torrent . ToJson ( )
2017-05-04 05:28:42 +02:00
b . Torrents = append ( b . Torrents , res )
2017-05-02 12:39:53 +02:00
b . QueryRecordCount = 1
2017-05-04 05:28:42 +02:00
b . TotalRecordCount = 1
2017-05-02 12:39:53 +02:00
w . Header ( ) . Set ( "Content-Type" , "application/json" )
err = json . NewEncoder ( w ) . Encode ( b )
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
return
}
}
func searchHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-05 03:53:38 +02:00
var templates = template . Must ( template . New ( "home" ) . Funcs ( funcMap ) . ParseFiles ( "templates/index.html" , "templates/home.html" ) )
2017-05-05 15:23:49 +02:00
templates . ParseGlob ( "templates/_*.html" ) // common
2017-05-02 12:39:53 +02:00
vars := mux . Vars ( r )
page := vars [ "page" ]
2017-05-03 19:45:18 +02:00
// db params url
2017-05-02 12:39:53 +02:00
pagenum , _ := strconv . Atoi ( html . EscapeString ( page ) )
2017-05-05 06:07:45 +02:00
if pagenum == 0 {
pagenum = 1
}
2017-05-05 13:37:22 +02:00
2017-05-05 14:20:51 +02:00
b := [ ] model . TorrentsJson { }
2017-05-05 13:37:22 +02:00
search_param , torrents , nbTorrents := searchByQuery ( r , pagenum )
2017-05-04 05:38:11 +02:00
2017-05-04 05:28:42 +02:00
for i , _ := range torrents {
2017-05-05 14:20:51 +02:00
res := torrents [ i ] . ToJson ( )
2017-05-04 05:28:42 +02:00
b = append ( b , res )
2017-05-02 12:39:53 +02:00
}
2017-05-05 13:37:22 +02:00
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 ,
2017-05-05 18:02:18 +02:00
false ,
2017-05-05 13:37:22 +02:00
}
2017-05-05 14:20:51 +02:00
htv := HomeTemplateVariables { b , torrentService . GetAllCategories ( false ) , searchForm , navigationTorrents , r . URL , mux . CurrentRoute ( r ) }
2017-05-05 05:04:04 +02:00
2017-05-04 05:28:42 +02:00
err := templates . ExecuteTemplate ( w , "index.html" , htv )
2017-05-02 12:39:53 +02:00
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
}
}
2017-05-05 14:51:19 +02:00
func searchByQuery ( r * http . Request , pagenum int ) ( SearchParam , [ ] model . Torrents , int ) {
2017-05-05 13:37:22 +02:00
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 , "_" )
2017-05-04 07:01:29 +02:00
// need this to prevent out of index panics
var searchCatId , searchSubCatId string
if len ( catsSplit ) == 2 {
2017-05-05 14:51:19 +02:00
2017-05-04 07:01:29 +02:00
searchCatId = html . EscapeString ( catsSplit [ 0 ] )
searchSubCatId = html . EscapeString ( catsSplit [ 1 ] )
}
2017-05-05 13:37:22 +02:00
if search_param . Sort == "" {
search_param . Sort = "torrent_id"
2017-05-05 06:24:58 +02:00
}
2017-05-05 13:37:22 +02:00
if search_param . Order == "" {
search_param . Order = "desc"
2017-05-05 06:24:58 +02:00
}
2017-05-05 13:37:22 +02:00
order_by := search_param . Sort + " " + search_param . Order
2017-05-04 00:54:07 +02:00
2017-05-05 14:51:19 +02:00
parameters := torrentService . WhereParams { }
2017-05-05 11:04:28 +02:00
conditions := [ ] string { }
if searchCatId != "" {
conditions = append ( conditions , "category_id = ?" )
2017-05-05 14:51:19 +02:00
parameters . Params = append ( parameters . Params , searchCatId )
2017-05-05 11:04:28 +02:00
}
if searchSubCatId != "" {
conditions = append ( conditions , "sub_category_id = ?" )
2017-05-05 14:51:19 +02:00
parameters . Params = append ( parameters . Params , searchSubCatId )
2017-05-05 11:04:28 +02:00
}
2017-05-05 13:37:22 +02:00
if search_param . Status != "" {
2017-05-05 11:04:28 +02:00
conditions = append ( conditions , "status_id = ?" )
2017-05-05 14:51:19 +02:00
parameters . Params = append ( parameters . Params , search_param . Status )
2017-05-05 11:04:28 +02:00
}
2017-05-05 13:37:22 +02:00
searchQuerySplit := strings . Split ( search_param . Query , " " )
2017-05-05 11:04:28 +02:00
for i , _ := range searchQuerySplit {
conditions = append ( conditions , "torrent_name LIKE ?" )
2017-05-05 14:51:19 +02:00
parameters . Params = append ( parameters . Params , "%" + searchQuerySplit [ i ] + "%" )
2017-05-05 11:04:28 +02:00
}
2017-05-05 14:51:19 +02:00
parameters . Conditions = strings . Join ( conditions [ : ] , " AND " )
log . Infof ( "SQL query is :: %s\n" , parameters . Conditions )
torrents , n := torrentService . GetTorrentsOrderBy ( & parameters , order_by , maxPerPage , maxPerPage * ( pagenum - 1 ) )
2017-05-05 13:37:22 +02:00
return search_param , torrents , n
2017-05-02 12:39:53 +02:00
}
2017-05-05 13:37:22 +02:00
2017-05-04 01:15:20 +02:00
func faqHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-05 03:53:38 +02:00
var templates = template . Must ( template . New ( "FAQ" ) . Funcs ( funcMap ) . ParseFiles ( "templates/index.html" , "templates/FAQ.html" ) )
2017-05-05 15:23:49 +02:00
templates . ParseGlob ( "templates/_*.html" ) // common
2017-05-05 18:02:18 +02:00
searchForm := NewSearchForm ( )
searchForm . HideAdvancedSearch = true
err := templates . ExecuteTemplate ( w , "index.html" , FaqTemplateVariables { Navigation { } , searchForm , r . URL , mux . CurrentRoute ( r ) } )
2017-05-04 01:15:20 +02:00
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
}
}
2017-05-04 21:48:40 +02:00
func rssHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-05 13:37:22 +02:00
_ , torrents , _ := searchByQuery ( r , 1 )
created_as_time := time . Now ( )
2017-05-04 21:48:40 +02:00
2017-05-05 06:24:58 +02:00
if len ( torrents ) > 0 {
2017-05-05 13:37:22 +02:00
created_as_time = time . Unix ( torrents [ 0 ] . Date , 0 )
2017-05-04 21:48:40 +02:00
}
feed := & feeds . Feed {
2017-05-05 06:24:58 +02:00
Title : "Nyaa Pantsu" ,
Link : & feeds . Link { Href : "https://nyaa.pantsu.cat/" } ,
Created : created_as_time ,
2017-05-04 21:48:40 +02:00
}
feed . Items = [ ] * feeds . Item { }
2017-05-05 06:24:58 +02:00
feed . Items = make ( [ ] * feeds . Item , len ( torrents ) )
2017-05-04 21:48:40 +02:00
for i , _ := range torrents {
2017-05-05 13:37:22 +02:00
timestamp_as_time := time . Unix ( torrents [ 0 ] . Date , 0 )
2017-05-05 14:51:19 +02:00
torrent_json := torrents [ i ] . ToJson ( )
2017-05-05 13:37:22 +02:00
feed . Items [ i ] = & feeds . Item {
2017-05-05 18:43:48 +02:00
Id : "https://nyaa.pantsu.cat/view/" + strconv . Itoa ( torrents [ i ] . Id ) ,
2017-05-05 13:37:22 +02:00
Title : torrents [ i ] . Name ,
Link : & feeds . Link { Href : string ( torrent_json . Magnet ) } ,
Description : "" ,
Created : timestamp_as_time ,
Updated : timestamp_as_time ,
2017-05-04 21:48:40 +02:00
}
}
rss , err := feed . ToRss ( )
if err == nil {
2017-05-05 06:24:58 +02:00
w . Write ( [ ] byte ( rss ) )
2017-05-04 21:48:40 +02:00
} else {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
}
}
2017-05-05 13:37:22 +02:00
2017-05-05 02:54:37 +02:00
func viewHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-05 05:04:04 +02:00
var templates = template . Must ( template . ParseFiles ( "templates/index.html" , "templates/view.html" ) )
2017-05-05 15:23:49 +02:00
templates . ParseGlob ( "templates/_*.html" ) // common
2017-05-05 02:54:37 +02:00
vars := mux . Vars ( r )
id := vars [ "id" ]
2017-05-05 14:20:51 +02:00
torrent , err := torrentService . GetTorrentById ( id )
b := torrent . ToJson ( )
2017-05-05 02:54:37 +02:00
2017-05-05 10:52:08 +02:00
htv := ViewTemplateVariables { b , NewSearchForm ( ) , Navigation { } , r . URL , mux . CurrentRoute ( r ) }
2017-05-05 02:54:37 +02:00
2017-05-05 05:04:04 +02:00
err = templates . ExecuteTemplate ( w , "index.html" , htv )
2017-05-04 01:15:20 +02:00
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
}
}
2017-05-02 12:39:53 +02:00
func rootHandler ( w http . ResponseWriter , r * http . Request ) {
2017-05-05 15:23:49 +02:00
var templates = template . Must ( template . New ( "home" ) . Funcs ( funcMap ) . ParseFiles ( "templates/index.html" , "templates/home.html" ) )
templates . ParseGlob ( "templates/_*.html" ) // common
vars := mux . Vars ( r )
2017-05-02 12:39:53 +02:00
page := vars [ "page" ]
2017-05-03 19:45:18 +02:00
2017-05-04 00:20:50 +02:00
// db params url
maxPerPage , errConv := strconv . Atoi ( r . URL . Query ( ) . Get ( "max" ) )
if errConv != nil {
2017-05-03 19:45:18 +02:00
maxPerPage = 50 // default Value maxPerPage
2017-05-04 00:20:50 +02:00
}
2017-05-03 19:45:18 +02:00
nbTorrents := 0
2017-05-02 12:39:53 +02:00
pagenum , _ := strconv . Atoi ( html . EscapeString ( page ) )
2017-05-05 06:07:45 +02:00
if pagenum == 0 {
pagenum = 1
}
2017-05-05 03:53:38 +02:00
2017-05-05 14:20:51 +02:00
b := [ ] model . TorrentsJson { }
torrents , nbTorrents := torrentService . GetAllTorrents ( maxPerPage , maxPerPage * ( pagenum - 1 ) )
2017-05-05 03:53:38 +02:00
2017-05-04 05:28:42 +02:00
for i , _ := range torrents {
2017-05-05 14:20:51 +02:00
res := torrents [ i ] . ToJson ( )
2017-05-04 05:28:42 +02:00
b = append ( b , res )
2017-05-02 12:39:53 +02:00
}
2017-05-04 05:28:42 +02:00
2017-05-05 03:53:38 +02:00
navigationTorrents := Navigation { nbTorrents , maxPerPage , pagenum , "search_page" }
2017-05-05 14:20:51 +02:00
htv := HomeTemplateVariables { b , torrentService . GetAllCategories ( false ) , NewSearchForm ( ) , navigationTorrents , r . URL , mux . CurrentRoute ( r ) }
2017-05-04 05:28:42 +02:00
err := templates . ExecuteTemplate ( w , "index.html" , htv )
2017-05-02 12:39:53 +02:00
if err != nil {
http . Error ( w , err . Error ( ) , http . StatusInternalServerError )
}
}
2017-05-05 15:08:02 +02:00
func RunServer ( conf * config . Config ) {
2017-05-05 03:53:38 +02:00
router = mux . NewRouter ( )
2017-05-02 12:39:53 +02:00
2017-05-03 19:45:18 +02:00
cssHandler := http . FileServer ( http . Dir ( "./css/" ) )
jsHandler := http . FileServer ( http . Dir ( "./js/" ) )
2017-05-05 03:53:38 +02:00
imgHandler := http . FileServer ( http . Dir ( "./img/" ) )
2017-05-04 00:20:50 +02:00
http . Handle ( "/css/" , http . StripPrefix ( "/css/" , cssHandler ) )
http . Handle ( "/js/" , http . StripPrefix ( "/js/" , jsHandler ) )
2017-05-05 03:53:38 +02:00
http . Handle ( "/img/" , http . StripPrefix ( "/img/" , imgHandler ) )
2017-05-03 19:45:18 +02:00
2017-05-02 12:39:53 +02:00
// Routes,
2017-05-05 03:53:38 +02:00
router . HandleFunc ( "/" , rootHandler ) . Name ( "home" )
router . HandleFunc ( "/page/{page:[0-9]+}" , rootHandler ) . Name ( "home_page" )
router . HandleFunc ( "/search" , searchHandler ) . Name ( "search" )
router . HandleFunc ( "/search/{page}" , searchHandler ) . Name ( "search_page" )
2017-05-02 12:39:53 +02:00
router . HandleFunc ( "/api/{page}" , apiHandler ) . Methods ( "GET" )
2017-05-05 02:54:37 +02:00
router . HandleFunc ( "/api/view/{id}" , apiViewHandler ) . Methods ( "GET" )
2017-05-05 03:53:38 +02:00
router . HandleFunc ( "/faq" , faqHandler ) . Name ( "faq" )
2017-05-04 21:48:40 +02:00
router . HandleFunc ( "/feed.xml" , rssHandler )
2017-05-05 05:04:04 +02:00
router . HandleFunc ( "/view/{id}" , viewHandler ) . Name ( "view_torrent" )
2017-05-03 19:45:18 +02:00
http . Handle ( "/" , router )
2017-05-02 12:39:53 +02:00
// Set up server,
srv := & http . Server {
2017-05-05 14:10:35 +02:00
Addr : fmt . Sprintf ( "%s:%d" , conf . Host , conf . Port ) ,
2017-05-02 12:39:53 +02:00
WriteTimeout : 15 * time . Second ,
ReadTimeout : 15 * time . Second ,
}
err := srv . ListenAndServe ( )
2017-05-05 14:20:51 +02:00
log . CheckError ( err )
2017-05-02 12:39:53 +02:00
}
2017-05-05 14:10:35 +02:00
func main ( ) {
2017-05-05 15:08:02 +02:00
conf := config . NewConfig ( )
2017-05-05 14:10:35 +02:00
conf_bind := conf . BindFlags ( )
defaults := flag . Bool ( "print-defaults" , false , "print the default configuration file on stdout" )
flag . Parse ( )
if * defaults {
stdout := bufio . NewWriter ( os . Stdout )
conf . Pretty ( stdout )
stdout . Flush ( )
os . Exit ( 0 )
} else {
conf_bind ( )
RunServer ( conf )
}
}