Albirew/nyaa-pantsu
Archivé
1
0
Bifurcation 0
Cette révision appartient à :
akuma06 2017-05-07 02:50:23 +02:00
révision 3c42b2bda0
32 fichiers modifiés avec 351 ajouts et 216 suppressions

5
.gitignore externe
Voir le fichier

@ -1,5 +1,6 @@
*.sqlite
*.db
*.sql
main
nyaa
nyaa.exe
@ -8,4 +9,6 @@ nyaa-master.exe
*.swp
.vscode
templates/*.html.go
*.bat
*.bat
*.backup
tags

Voir le fichier

@ -6,15 +6,13 @@ install:
- go get github.com/gorilla/mux
- go get github.com/mattn/go-sqlite3
- go get github.com/jinzhu/gorm
- go get github.com/lib/pq
- go get github.com/Sirupsen/logrus
- go get gopkg.in/natefinch/lumberjack.v2
- go get gopkg.in/gomail.v2
- go get github.com/gorilla/securecookie
- go get golang.org/x/crypto/bcrypt
- go get github.com/nicksnyder/go-i18n/i18n
- go get github.com/valyala/quicktemplate
- go get github.com/valyala/quicktemplate/qtc
- go generate ./...
- go build
deploy:
provider: releases

Voir le fichier

@ -21,8 +21,6 @@ that anyone will be able to deploy locally or remotely.
Type `./nyaa -h` for the list of options.
After modifying the files in `./templates`, run `go generate ./... && go build`.
## Systemd
* Edit the unit file `os/nyaa.service` to your liking
@ -37,6 +35,30 @@ The provided unit file uses options directly; if you prefer a config file, do th
* Edit `nyaa.conf` to your liking
* Replace in the unit file the options by `-conf /etc/nyaa.conf`
## Docker
We support docker for easy development and deployment. Simply install docker and
docker-compose by following the instructions [here](https://docs.docker.com/engine/installation/linux/ubuntu/#install-using-the-repository).
Once you've successfully installed docker, make sure you have the database file
in the project's directory as nyaa.db. Then, follow these steps to build and run
the application.
```sh
# Make sure the project is in here $GOPATH/src/github.com/ewhal/nyaa
$ cd deploy/
# You may choose another backend by pointing to the
# appropriate docker-compose file.
$ docker-compose -f docker-compose.sqlite.yml build
$ docker-compose -f docker-compose.sqlite.yml up
```
Access the website by going to [localhost:9999](http://localhost:9999).
> For postgres, place the dump in the toplevel directory and name it to
> nyaa_psql.backup.
## TODO
### Features until stable release

Voir le fichier

@ -6,6 +6,7 @@ import (
"github.com/ewhal/nyaa/util/log"
"github.com/jinzhu/gorm"
_ "github.com/jinzhu/gorm/dialects/sqlite"
_ "github.com/jinzhu/gorm/dialects/postgres"
// _ "github.com/go-sql-driver/mysql"
)

3
deploy/.env Fichier normal
Voir le fichier

@ -0,0 +1,3 @@
PANTSU_EXTERNAL_PORT=9999
PANTSU_INTERNAL_PORT=9999
PANTSU_POSTGRES_DBFILE=nyaa_psql.backup

5
deploy/Dockerfile Fichier normal
Voir le fichier

@ -0,0 +1,5 @@
FROM golang:1.8.1
RUN mkdir -p /nyaa
WORKDIR /nyaa

Voir le fichier

@ -0,0 +1,19 @@
version: '3'
services:
pantsu:
build:
context: ..
dockerfile: deploy/Dockerfile
command: ./deploy/init.sh
env_file:
- postgres-prod.env
environment:
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
ports:
# 0.0.0.0 makes it accessible to the network
# You may want to remove it to make pantsu available only
# to localhost
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
volumes:
- "${GOPATH}:/go/"
- "./..:/nyaa"

Voir le fichier

@ -0,0 +1,34 @@
version: '3'
services:
pantsu:
build:
context: ..
dockerfile: deploy/Dockerfile
command: ./deploy/init.sh
depends_on:
- pantsu_db
env_file:
- postgres.env
environment:
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
links:
- pantsu_db
ports:
# 0.0.0.0 makes it accessible to the network
# You may want to remove it to make pantsu available only
# to localhost
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
volumes:
- "${GOPATH}:/go/"
- "./..:/nyaa"
pantsu_db:
env_file:
- postgres.env
environment:
- PANTSU_POSTGRES_DBFILE=${PANTSU_POSTGRES_DBFILE}
image: postgres:9.6.2
volumes:
# restore.sh will be sourced after initial initdb
- "./restore.sh:/docker-entrypoint-initdb.d/restore.sh"
- "./../${PANTSU_POSTGRES_DBFILE}:/${PANTSU_POSTGRES_DBFILE}"

Voir le fichier

@ -0,0 +1,19 @@
version: '3'
services:
pantsu:
build:
context: ..
dockerfile: deploy/Dockerfile
command: ./deploy/init.sh
env_file:
- sqlite.env
environment:
- PANTSU_INTERNAL_PORT=${PANTSU_INTERNAL_PORT}
ports:
# 0.0.0.0 makes it accessible to the network
# You may want to remove it to make pantsu available only
# to localhost
- 0.0.0.0:${PANTSU_EXTERNAL_PORT}:${PANTSU_INTERNAL_PORT}
volumes:
- "${GOPATH}:/go/"
- "./..:/nyaa"

16
deploy/init.sh Fichier exécutable
Voir le fichier

@ -0,0 +1,16 @@
#!/bin/bash
set -eux
# TODO Doesn't scale, find another way to wait until db is ready
if [[ "${PANTSU_DBTYPE}" = "postgres" ]]; then
echo 'Waiting for the database to be ready...'
sleep 40
fi
go get github.com/ewhal/nyaa
go build
./nyaa -host 0.0.0.0 \
-port "${PANTSU_INTERNAL_PORT}" \
-dbtype "${PANTSU_DBTYPE}" \
-dbparams "${PANTSU_DBPARAMS}"

9
deploy/postgres-prod.env Fichier normal
Voir le fichier

@ -0,0 +1,9 @@
POSTGRES_USER=nyaapantsu
POSTGRES_PASSWORD=nyaapantsu
POSTGRES_DB=nyaapantsu
PANTSU_DBTYPE=postgres
# TODO Would prefer to use the line below but docker doesn't seem to accept
# that.
#PANTSU_DBPARAMS=host=pantsu_db user=${POSTGRES_USER} dbname=${POSTGRES_DB} sslmode=disable password=${POSTGRES_PASSWORD}
PANTSU_DBPARAMS=host=localhost user=nyaapantsu dbname=nyaapantsu sslmode=disable password=nyaapantsu

9
deploy/postgres.env Fichier normal
Voir le fichier

@ -0,0 +1,9 @@
POSTGRES_USER=nyaapantsu
POSTGRES_PASSWORD=nyaapantsu
POSTGRES_DB=nyaapantsu
PANTSU_DBTYPE=postgres
# TODO Would prefer to use the line below but docker doesn't seem to accept
# that.
#PANTSU_DBPARAMS=host=pantsu_db user=${POSTGRES_USER} dbname=${POSTGRES_DB} sslmode=disable password=${POSTGRES_PASSWORD}
PANTSU_DBPARAMS=host=pantsu_db user=nyaapantsu dbname=nyaapantsu sslmode=disable password=nyaapantsu

11
deploy/prune_docker.sh Fichier exécutable
Voir le fichier

@ -0,0 +1,11 @@
# Prune images and volumes
#
# Docker tends to take a lot of space. This will remove dangling images and
# volumes not used by at least container.
# WARNING: You might not want to run this if you have stuff that are dangling
# that you want to keep.
#
#!/bin/bash
docker image prune -f
docker volume prune -f

4
deploy/restore.sh Fichier exécutable
Voir le fichier

@ -0,0 +1,4 @@
#!/bin/bash
# Restore the database from a postgres dump
pg_restore --username "${POSTGRES_USER}" -d ${POSTGRES_DB} "/${PANTSU_POSTGRES_DBFILE}"

2
deploy/sqlite.env Fichier normal
Voir le fichier

@ -0,0 +1,2 @@
PANTSU_DBTYPE=sqlite3
PANTSU_DBPARAMS=./nyaa.db?cache_size=50

Voir le fichier

@ -25,11 +25,13 @@ func RunServer(conf *config.Config) {
http.Handle("/", router.Router)
// Set up server,
addr := fmt.Sprintf("%s:%d", conf.Host, conf.Port)
srv := &http.Server{
Addr: fmt.Sprintf("%s:%d", conf.Host, conf.Port),
Addr: addr,
WriteTimeout: 15 * time.Second,
ReadTimeout: 15 * time.Second,
}
log.Infof("listening on %s", addr)
err := srv.ListenAndServe()
log.CheckError(err)
@ -54,4 +56,4 @@ func main() {
initI18N()
RunServer(conf)
}
}
}

Voir le fichier

@ -75,7 +75,7 @@ type TorrentsJson struct {
func (t *Torrents) ToJson() TorrentsJson {
magnet := "magnet:?xt=urn:btih:" + strings.TrimSpace(t.Hash) + "&dn=" + t.Name + config.Trackers
b := []CommentsJson{}
_ = json.Unmarshal([]byte(util.UnZlib(t.Comments)), &b)
_ = json.Unmarshal([]byte(t.Comments), &b)
res := TorrentsJson{
Id: strconv.Itoa(t.Id),
Name: html.UnescapeString(t.Name),
@ -83,7 +83,7 @@ func (t *Torrents) ToJson() TorrentsJson {
Hash: t.Hash,
Date: time.Unix(t.Date, 0).Format(time.RFC3339),
Filesize: util.FormatFilesize(t.Filesize),
Description: template.HTML(util.UnZlib(t.Description)),
Description: template.HTML(t.Description),
Comments: b,
Sub_Category: strconv.Itoa(t.Sub_Category),
Category: strconv.Itoa(t.Category),

Fichier binaire non affiché.

Avant

Largeur:  |  Hauteur:  |  Taille: 4,6 Kio

Après

Largeur:  |  Hauteur:  |  Taille: 6,1 Kio

Voir le fichier

@ -4,16 +4,20 @@ import (
"html/template"
"net/http"
"github.com/ewhal/nyaa/templates"
"github.com/gorilla/mux"
)
var faqTemplate = template.Must(template.New("FAQ").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/FAQ.html"))
func init() {
// common
template.Must(faqTemplate.ParseGlob("templates/_*.html"))
}
func FaqHandler(w http.ResponseWriter, r *http.Request) {
searchForm := templates.NewSearchForm()
searchForm := NewSearchForm()
searchForm.HideAdvancedSearch = true
err := faqTemplate.ExecuteTemplate(w, "index.html", FaqTemplateVariables{templates.Navigation{}, searchForm, r.URL, mux.CurrentRoute(r)})
err := faqTemplate.ExecuteTemplate(w, "index.html", FaqTemplateVariables{Navigation{}, searchForm, r.URL, mux.CurrentRoute(r)})
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}

Voir le fichier

@ -1,19 +1,21 @@
package router
import (
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/gorilla/mux"
"html"
"html/template"
"net/http"
"strconv"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/templates"
"github.com/gorilla/mux"
)
var homeTemplate = template.Must(template.New("home").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/home.html"))
func init() {
template.Must(homeTemplate.ParseGlob("templates/_*.html")) // common
}
func HomeHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
page := vars["page"]
@ -38,8 +40,8 @@ func HomeHandler(w http.ResponseWriter, r *http.Request) {
b = append(b, res)
}
navigationTorrents := templates.Navigation{nbTorrents, maxPerPage, pagenum, "search_page"}
htv := HomeTemplateVariables{b, templates.NewSearchForm(), navigationTorrents, r.URL, mux.CurrentRoute(r)}
navigationTorrents := Navigation{nbTorrents, maxPerPage, pagenum, "search_page"}
htv := HomeTemplateVariables{b, NewSearchForm(), navigationTorrents, r.URL, mux.CurrentRoute(r)}
err := homeTemplate.ExecuteTemplate(w, "index.html", htv)
if err != nil {

Voir le fichier

@ -5,15 +5,17 @@ import (
"html/template"
"net/http"
"strconv"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/templates"
"github.com/ewhal/nyaa/util/search"
"github.com/gorilla/mux"
)
var searchTemplate = template.Must(template.New("home").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/home.html"))
func init() {
template.Must(searchTemplate.ParseGlob("templates/_*.html")) // common
}
func SearchHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
page := vars["page"]
@ -33,8 +35,8 @@ func SearchHandler(w http.ResponseWriter, r *http.Request) {
b = append(b, res)
}
navigationTorrents := templates.Navigation{nbTorrents, search_param.Max, pagenum, "search_page"}
searchForm := templates.SearchForm{
navigationTorrents := Navigation{nbTorrents, search_param.Max, pagenum, "search_page"}
searchForm := SearchForm{
search_param.Query,
search_param.Status,
search_param.Category,

Voir le fichier

@ -7,9 +7,7 @@ import (
"net/url"
"strconv"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/ewhal/nyaa/templates"
)
)
var FuncMap = template.FuncMap{
"min": math.Min,
@ -23,11 +21,11 @@ var FuncMap = template.FuncMap{
"genRouteWithQuery": func(name string, currentUrl *url.URL, params ...string) template.HTML {
url, err := Router.Get(name).URL(params...)
if err == nil {
return template.HTML(url.String() + "?" + currentUrl.RawQuery)
return template.HTML(url.String()+ "?" + currentUrl.RawQuery)
}
return "error"
},
"genNav": func(nav templates.Navigation, currentUrl *url.URL, pagesSelectable int) template.HTML {
"genNav": func(nav Navigation, currentUrl *url.URL, pagesSelectable int) template.HTML {
maxPages := math.Ceil(float64(nav.TotalItem) / float64(nav.MaxItemPerPage))
var ret = ""
@ -60,14 +58,5 @@ var FuncMap = template.FuncMap{
}
return template.HTML(ret)
},
"SearchCommon": func(s templates.SearchForm) template.HTML {
return template.HTML(templates.SearchCommon(s))
},
"SearchButton": func(s templates.SearchForm) template.HTML {
return template.HTML(templates.SearchButton(s))
},
"SearchAdvanced": func(nav templates.Navigation, s templates.SearchForm) template.HTML {
return template.HTML(templates.SearchAdvanced(nav, s))
},
"T": i18n.IdentityTfunc,
}

Voir le fichier

@ -4,7 +4,6 @@ import (
"net/url"
"github.com/ewhal/nyaa/model"
"github.com/ewhal/nyaa/templates"
userForms "github.com/ewhal/nyaa/service/user/form"
"github.com/gorilla/mux"
)
@ -16,40 +15,86 @@ import (
*/
type FaqTemplateVariables struct {
Navigation templates.Navigation
Search templates.SearchForm
Navigation Navigation
Search SearchForm
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type ViewTemplateVariables struct {
Torrent model.TorrentsJson
Search templates.SearchForm
Navigation templates.Navigation
Search SearchForm
Navigation Navigation
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type UserRegisterTemplateVariables struct {
RegistrationForm userForms.RegistrationForm
Search templates.SearchForm
Navigation templates.Navigation
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
RegistrationForm userForms.RegistrationForm
Search SearchForm
Navigation Navigation
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type HomeTemplateVariables struct {
ListTorrents []model.TorrentsJson
Search templates.SearchForm
Navigation templates.Navigation
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
ListTorrents []model.TorrentsJson
Search SearchForm
Navigation Navigation
URL *url.URL // For parsing Url in templates
Route *mux.Route // For getting current route in templates
}
type UploadTemplateVariables struct {
Upload UploadForm
Search templates.SearchForm
Navigation templates.Navigation
Search SearchForm
Navigation Navigation
URL *url.URL
Route *mux.Route
}
/*
* Variables used by the upper ones
*/
type Navigation struct {
TotalItem int
MaxItemPerPage int
CurrentPage int
Route string
}
type SearchForm struct {
Query string
Status string
Category string
Sort string
Order string
HideAdvancedSearch bool
}
// Some Default Values to ease things out
func NewSearchForm(params ...string) (searchForm SearchForm) {
if len(params) > 1 {
searchForm.Category = params[0]
} else {
searchForm.Category = "_"
}
if len(params) > 2 {
searchForm.Sort = params[1]
} else {
searchForm.Sort = "torrent_id"
}
if len(params) > 3 {
order := params[2]
if order == "DESC" {
searchForm.Order = order
} else if order == "ASC" {
searchForm.Order = order
} else {
// TODO: handle invalid value (?)
}
} else {
searchForm.Order = "DESC"
}
return
}

Voir le fichier

@ -4,12 +4,15 @@ import (
"html/template"
"net/http"
"github.com/ewhal/nyaa/templates"
"github.com/gorilla/mux"
)
var uploadTemplate = template.Must(template.New("upload").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/upload.html"))
func init() {
template.Must(uploadTemplate.ParseGlob("templates/_*.html")) // common
}
func UploadHandler(w http.ResponseWriter, r *http.Request) {
var err error
var uploadForm UploadForm
@ -21,7 +24,7 @@ func UploadHandler(w http.ResponseWriter, r *http.Request) {
//add to db and redirect depending on result
}
} else if r.Method == "GET" {
htv := UploadTemplateVariables{uploadForm, templates.NewSearchForm(), templates.Navigation{}, r.URL, mux.CurrentRoute(r)}
htv := UploadTemplateVariables{uploadForm, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
err = uploadTemplate.ExecuteTemplate(w, "index.html", htv)
} else {
w.WriteHeader(http.StatusMethodNotAllowed)

Voir le fichier

@ -1,10 +1,9 @@
package router
import(
import (
"html/template"
"net/http"
"github.com/ewhal/nyaa/templates"
"github.com/ewhal/nyaa/service/user/form"
"github.com/ewhal/nyaa/util/modelHelper"
"github.com/ewhal/nyaa/util/languages"
@ -15,14 +14,18 @@ var viewRegisterTemplate = template.Must(template.New("userRegister").Funcs(Func
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
//var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
func init() {
template.Must(viewRegisterTemplate.ParseGlob("templates/_*.html"))
}
// Getting View User Registration
func UserRegisterFormHandler(w http.ResponseWriter, r *http.Request) {
b := form.RegistrationForm{}
modelHelper.BindValueForm(&b, r)
languages.SetTranslation("en-us", viewRegisterTemplate)
htv := UserRegisterTemplateVariables{b, templates.NewSearchForm(), templates.Navigation{}, r.URL, mux.CurrentRoute(r)}
err := viewRegisterTemplate.ExecuteTemplate(w, "index.html", htv)
htv := UserRegisterTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
err := viewTemplate.ExecuteTemplate(w, "index.html", htv)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
}
@ -38,7 +41,7 @@ func UserProfileHandler(w http.ResponseWriter, r *http.Request) {
}
// Getting View User Profile Update
// Getting View User Profile Update
func UserProfileFormHandler(w http.ResponseWriter, r *http.Request) {
}
@ -57,4 +60,3 @@ func UserLoginPostHandler(w http.ResponseWriter, r *http.Request) {
func UserProfilePostHandler(w http.ResponseWriter, r *http.Request) {
}

Voir le fichier

@ -5,12 +5,15 @@ import (
"net/http"
"github.com/ewhal/nyaa/service/torrent"
"github.com/ewhal/nyaa/templates"
"github.com/gorilla/mux"
)
var viewTemplate = template.Must(template.New("view").Funcs(FuncMap).ParseFiles("templates/index.html", "templates/view.html"))
func init() {
template.Must(viewTemplate.ParseGlob("templates/_*.html")) // common
}
func ViewHandler(w http.ResponseWriter, r *http.Request) {
vars := mux.Vars(r)
id := vars["id"]
@ -18,7 +21,7 @@ func ViewHandler(w http.ResponseWriter, r *http.Request) {
torrent, err := torrentService.GetTorrentById(id)
b := torrent.ToJson()
htv := ViewTemplateVariables{b, templates.NewSearchForm(), templates.Navigation{}, r.URL, mux.CurrentRoute(r)}
htv := ViewTemplateVariables{b, NewSearchForm(), Navigation{}, r.URL, mux.CurrentRoute(r)}
err = viewTemplate.ExecuteTemplate(w, "index.html", htv)
if err != nil {

Voir le fichier

@ -71,7 +71,6 @@ func GetTorrentsOrderBy(parameters *WhereParams, orderBy string, limit int, offs
}
dbQuery.Order(orderBy).Find(&torrents)
return torrents, count
}
/* Functions to simplify the get parameters of the main function

73
templates/_search.html Fichier normal
Voir le fichier

@ -0,0 +1,73 @@
{{define "search_common"}}
<select name="c" class="form-control input-sm" value>
<option value="_">All categories</option>
<option value="3_" {{if eq .Search.Category "3_"}}selected{{end}}>Anime</option>
<option value="3_12" {{if eq .Search.Category "3_12"}}selected{{end}}>Anime - Anime Music Video</option>
<option value="3_5" {{if eq .Search.Category "3_5"}}selected{{end}}>Anime - English-translated</option>
<option value="3_13" {{if eq .Search.Category "3_13"}}selected{{end}}>Anime - Non-English-translated</option>
<option value="3_6" {{if eq .Search.Category "3_6"}}selected{{end}}>Anime - Raw</option>
<option value="2_" {{if eq .Search.Category "2_"}}selected{{end}}>Audio</option>
<option value="2_3" {{if eq .Search.Category "2_3"}}selected{{end}}>Audio - Lossless</option>
<option value="2_4" {{if eq .Search.Category "2_4"}}selected{{end}}>Audio - Lossy</option>
<option value="4_" {{if eq .Search.Category "4_"}}selected{{end}}>Literature</option>
<option value="4_7" {{if eq .Search.Category "4_7"}}selected{{end}}>Literature - English-translated</option>
<option value="4_8" {{if eq .Search.Category "4_8"}}selected{{end}}>Literature - Raw</option>
<option value="4_14" {{if eq .Search.Category "4_14"}}selected{{end}}>Literature - Non-English-translated</option>
<option value="5_" {{if eq .Search.Category "5_"}}selected{{end}}>Live Action</option>
<option value="5_9" {{if eq .Search.Category "5_9"}}selected{{end}}>Live Action - English-translated</option>
<option value="5_10" {{if eq .Search.Category "5_10"}}selected{{end}}>Live Action - Idol/Promotional Video</option>
<option value="5_18" {{if eq .Search.Category "5_18"}}selected{{end}}>Live Action - Non-English-translated</option>
<option value="5_11" {{if eq .Search.Category "5_11"}}selected{{end}}>Live Action - Raw</option>
<option value="6_" {{if eq .Search.Category "6_"}}selected{{end}}>Pictures</option>
<option value="6_15" {{if eq .Search.Category "6_15"}}selected{{end}}>Pictures - Graphics</option>
<option value="6_16" {{if eq .Search.Category "6_16"}}selected{{end}}>Pictures - Photos</option>
<option value="1_" {{if eq .Search.Category "1_"}}selected{{end}}>Software</option>
<option value="1_1" {{if eq .Search.Category "1_1"}}selected{{end}}>Software - Applications</option>
<option value="1_2" {{if eq .Search.Category "1_2"}}selected{{end}}>Software - Games</option>
</select>
<select name="s" class="form-control input-sm">
<option value="">Show all</option>
<option value="2" {{if eq .Search.Status "2"}}selected{{end}}>Filter Remakes</option>
<option value="3" {{if eq .Search.Status "3"}}selected{{end}}>Trusted</option>
<option value="4" {{if eq .Search.Status "4"}}selected{{end}}>A+</option>
</select>
{{end}}
{{define "search_advanced"}}
<select name="sort" class="form-control input-sm">
<option value="torrent_id" {{if eq .Search.Sort "torrent_id"}}selected{{end}}>ID</option>
<option value="torrent_name" {{if eq .Search.Sort "torrent_name"}}selected{{end}}>Name</option>
<option value="date" {{if eq .Search.Sort "date"}}selected{{end}}>Date</option>
<option value="downloads" {{if eq .Search.Sort "downloads"}}selected{{end}}>Downloads</option>
<option value="filesize" {{if eq .Search.Sort "filesize"}}selected{{end}}>Size</option>
</select>
<select name="order" class="form-control input-sm">
<option value="desc" {{if eq .Search.Order "desc"}}selected{{end}}>Descending</option>
<option value="asc" {{if eq .Search.Order "asc"}}selected{{end}}>Ascending</option>
</select>
<select name="max" class="form-control input-sm">
<option value="5" {{if eq .Navigation.MaxItemPerPage 5}}selected{{end}}>5</option>
<option value="10" {{if eq .Navigation.MaxItemPerPage 10}}selected{{end}}>10</option>
<option value="15" {{if eq .Navigation.MaxItemPerPage 15}}selected{{end}}>15</option>
<option value="20" {{if eq .Navigation.MaxItemPerPage 20}}selected{{end}}>20</option>
<option value="25" {{if eq .Navigation.MaxItemPerPage 25}}selected{{end}}>25</option>
<option value="30" {{if eq .Navigation.MaxItemPerPage 30}}selected{{end}}>30</option>
<option value="35" {{if eq .Navigation.MaxItemPerPage 35}}selected{{end}}>35</option>
<option value="40" {{if eq .Navigation.MaxItemPerPage 40}}selected{{end}}>40</option>
<option value="45" {{if eq .Navigation.MaxItemPerPage 45}}selected{{end}}>45</option>
<option value="50" {{if eq .Navigation.MaxItemPerPage 50}}selected{{end}}>50</option>
<option value="70" {{if eq .Navigation.MaxItemPerPage 70}}selected{{end}}>70</option>
<option value="100" {{if eq .Navigation.MaxItemPerPage 100}}selected{{end}}>100</option>
<option value="150" {{if eq .Navigation.MaxItemPerPage 150}}selected{{end}}>150</option>
<option value="200" {{if eq .Navigation.MaxItemPerPage 200}}selected{{end}}>200</option>
<option value="300" {{if eq .Navigation.MaxItemPerPage 300}}selected{{end}}>300</option>
</select>
{{end}}
{{define "search_button"}}
<div class="input-group">
<input name="q" class="form-control input-sm" placeholder="Search" type="text" value="{{.Search.Query}}">
<span class="input-group-btn">
<button type="submit" class="btn btn-sm btn-success"><span class="glyphicon glyphicon-search" aria-hidden="true"></span> Search</button>
</span>
</div>
{{end}}

Voir le fichier

@ -6,7 +6,7 @@
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Nyaa Pantsu - {{block "title" .}}Error 404{{end}}</title>
<link rel="icon" type="image/png" href="/img/favicon.png?v=2" />
<link rel="icon" type="image/png" href="/img/favicon.png?v=3" />
<!-- RSS Feed with Context -->
<link href="{{ genRouteWithQuery "feed" .URL }}" rel="alternate" type="application/rss+xml" title="Nyaa Pantsu - {{block "rsstitle" .}}Last torrents{{end}} RSS Feed" />
@ -50,8 +50,8 @@
</ul>
<form class="navbar-form navbar-right" role="search" action="/search" method="get">
<div class="form-group">
{{ SearchCommon .Search }}
{{ SearchAdvanced .Navigation .Search }}
{{block "search_common" .}}{{end}}
{{block "search_button" .}}{{end}}
</div>
</form>
</div>
@ -67,9 +67,9 @@
<font size="4.5">Advanced Search</font><br />
<form class="navbar-form" role="search" action="/search" method="get">
<div class="form-group">
{{ SearchCommon .Search }}
{{ SearchAdvanced .Navigation .Search }}
{{ SearchButton .Search }}
{{block "search_common" .}}{{end}}
{{block "search_advanced" .}}{{end}}
{{block "search_button" .}}{{end}}
</div>
</form>
<div style="clear:both"></div>

Voir le fichier

@ -1,94 +0,0 @@
{% import "strconv" %}
{% code type searchField struct{
id, name string
} %}
Common seatch part of many pages
{% func SearchCommon(search SearchForm) %}
<select name="c" class="form-control input-sm" value>
<option value="_">All categories</option>
{%= searchOptions(search.Category, []searchField{
{"3_", "Anime"},
{"3_12", "Anime - Anime Music Video"},
{"3_5", "Anime - English-translated"},
{"3_13", "Anime - Non-English-translated"},
{"3_6", "Anime - Raw"},
{"2_", "Audio"},
{"2_3", "Audio - Lossless"},
{"2_4", "Audio - Lossy"},
{"4_", "Literature"},
{"4_7", "Literature - English-translated"},
{"4_8", "Literature - Raw"},
{"4_14", "Literature - Non-English-translated"},
{"5_", "Live Action"},
{"5_9", "Live Action - English-translated"},
{"5_10", "Live Action - Idol/Promotional Video"},
{"5_18", "Live Action - Non-English-translated"},
{"5_11", "Live Action - Raw"},
{"6_", "Pictures"},
{"6_15", "Pictures - Graphics"},
{"6_16", "Pictures - Photos"},
{"1_", "Software"},
{"1_1", "Software - Applications"},
{"1_2", "Software - Games"},
}) %}
</select>
<select name="s" class="form-control input-sm">
<option value="">Show all</option>
{%= searchOptions(search.Status, []searchField{
{"2", "Filter Remakes"},
{"3", "Trusted"},
{"4", "A+"},
}) %}
</select>
{% endfunc %}
Options fields of a search <select> element
{% func searchOptions(selected string, s []searchField) %}
{% for _, s := range s %}
{%= searchOption(selected, s) %}
{% endfor %}
{% endfunc %}
Single search optiion field of a <select>
{% func searchOption(selected string, s searchField) %}
<option value="{%s= s.id %}" {% if selected == s.id %}selected{% endif %}>{%s= s.name %}</option>
{% endfunc %}
{% func SearchAdvanced(nav Navigation, search SearchForm) %}
<select name="sort" class="form-control input-sm">
{%= searchOptions(search.Sort, []searchField{
{"torrent_id", "ID"},
{"torrent_name", "Name"},
{"date", "Date"},
{"downloads", "Downloads"},
{"filesize", "Size"},
}) %}
</select>
<select name="order" class="form-control input-sm">
{%= searchOptions(search.Order, []searchField{
{"desc", "Descending"},
{"asc", "Ascending"},
}) %}
</select>
<select name="max" class="form-control input-sm">
{% code sel := strconv.Itoa(nav.MaxItemPerPage) %}
{% for _, m := range [...]int{5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 70, 100, 150, 200, 300} %}
{% code id := strconv.Itoa(m) %}
{%= searchOption(sel, searchField{id, id}) %}
{% endfor %}
</select>
{% endfunc %}
{% func SearchButton(search SearchForm) %}
<div class="input-group">
<input name="q" class="form-control input-sm" placeholder="Search" type="text" value="{%s search.Query %}">
<span class="input-group-btn">
<button type="submit" class="btn btn-sm btn-success">
<span class="glyphicon glyphicon-search" aria-hidden="true"></span>
Search
</button>
</span>
</div>
{% endfunc %}

Voir le fichier

@ -1,3 +0,0 @@
//go:generate qtc --file search.html
package templates

Voir le fichier

@ -1,47 +0,0 @@
package templates
/*
* Variables used by the upper ones
*/
type Navigation struct {
TotalItem int
MaxItemPerPage int
CurrentPage int
Route string
}
type SearchForm struct {
Query string
Status string
Category string
Sort string
Order string
HideAdvancedSearch bool
}
// Some Default Values to ease things out
func NewSearchForm(params ...string) (searchForm SearchForm) {
if len(params) > 1 {
searchForm.Category = params[0]
} else {
searchForm.Category = "_"
}
if len(params) > 2 {
searchForm.Sort = params[1]
} else {
searchForm.Sort = "torrent_id"
}
if len(params) > 3 {
order := params[2]
if order == "DESC" {
searchForm.Order = order
} else if order == "ASC" {
searchForm.Order = order
} else {
// TODO: handle invalid value (?)
}
} else {
searchForm.Order = "DESC"
}
return
}