Albirew/nyaa-pantsu
Albirew
/
nyaa-pantsu
Archivé
1
0
Bifurcation 0

Merge branch 'dev' into dev

Cette révision appartient à :
akuma06 2017-05-14 00:55:17 +02:00 révisé par GitHub
révision ed26ee81eb
31 fichiers modifiés avec 402 ajouts et 100 suppressions

Voir le fichier

@ -21,7 +21,7 @@ type Config struct {
DBType string `json:"db_type"`
// DBParams will be directly passed to Gorm, and its internal
// structure depends on the dialect for each db type
DBParams string `json:"db_params"`
DBParams string `json:"db_params"`
DBLogMode string `json:"db_logmode"`
// tracker scraper config (required)
Scrape ScraperConfig `json:"scraper"`
@ -33,9 +33,12 @@ type Config struct {
I2P *I2PConfig `json:"i2p"`
// filesize fetcher config
FilesizeFetcher FilesizeFetcherConfig `json:"filesize_fetcher"`
// internationalization config
I18n I18nConfig `json:"i18n"`
}
var Defaults = Config{"localhost", 9999, "sqlite3", "./nyaa.db?cache_size=50", "default", DefaultScraperConfig, DefaultCacheConfig, DefaultSearchConfig, nil, DefaultFilesizeFetcherConfig}
var Defaults = Config{"localhost", 9999, "sqlite3", "./nyaa.db?cache_size=50", "default", DefaultScraperConfig, DefaultCacheConfig, DefaultSearchConfig, nil, DefaultFilesizeFetcherConfig, DefaultI18nConfig}
var allowedDatabaseTypes = map[string]bool{
"sqlite3": true,
@ -60,6 +63,7 @@ func New() *Config {
config.Scrape = Defaults.Scrape
config.Cache = Defaults.Cache
config.FilesizeFetcher = Defaults.FilesizeFetcher
config.I18n = Defaults.I18n
return &config
}

11
config/i18n.go Fichier normal
Voir le fichier

@ -0,0 +1,11 @@
package config
type I18nConfig struct {
TranslationsDirectory string `json:"translations_directory"`
DefaultLanguage string `json:"default_language"`
}
var DefaultI18nConfig = I18nConfig{
TranslationsDirectory: "translations",
DefaultLanguage: "en-us", // TODO: Remove refs to "en-us" from the code and templates
}

19
main.go
Voir le fichier

@ -6,7 +6,6 @@ import (
"net/http"
"os"
"path/filepath"
"time"
"github.com/ewhal/nyaa/cache"
@ -16,23 +15,12 @@ import (
"github.com/ewhal/nyaa/router"
"github.com/ewhal/nyaa/service/scraper"
"github.com/ewhal/nyaa/service/torrent/filesizeFetcher"
"github.com/ewhal/nyaa/util/languages"
"github.com/ewhal/nyaa/util/log"
"github.com/ewhal/nyaa/util/search"
"github.com/ewhal/nyaa/util/signals"
"github.com/nicksnyder/go-i18n/i18n"
)
func initI18N() {
/* Initialize the languages translation */
i18n.MustLoadTranslationFile("translations/en-us.all.json")
paths, err := filepath.Glob("translations/*.json")
if err == nil {
for _, path := range paths {
i18n.LoadTranslationFile(path)
}
}
}
// RunServer runs webapp mainloop
func RunServer(conf *config.Config) {
http.Handle("/", router.Router)
@ -136,7 +124,10 @@ func main() {
if err != nil {
log.Fatal(err.Error())
}
initI18N()
err = languages.InitI18n(conf.I18n)
if err != nil {
log.Fatal(err.Error())
}
err = cache.Configure(&conf.Cache)
if err != nil {
log.Fatal(err.Error())

Voir le fichier

@ -202,6 +202,10 @@ div.container div.blockBody:nth-of-type(2) table tr:first-of-type th:last-of-typ
{
width: 12rem;
}
#mainmenu .navbar-form select.form-control#max
{
width: 8rem;
}
.special-img
{
position: relative;

Voir le fichier

@ -2,9 +2,9 @@ var night = localStorage.getItem("night");
function toggleNightMode() {
var night = localStorage.getItem("night");
if(night == "true") {
document.getElementById("style-dark").remove()
document.getElementsByTagName("head")[0].removeChild(darkStyleLink);
} else {
document.getElementsByTagName("head")[0].append(darkStyleLink);
document.getElementsByTagName("head")[0].appendChild(darkStyleLink);
}
localStorage.setItem("night", (night == "true") ? "false" : "true");
}
@ -78,5 +78,4 @@ function loadLanguages() {
xhr.send()
}
loadLanguages();
loadLanguages();

Voir le fichier

@ -5,6 +5,7 @@ import (
"html"
"net/http"
"strconv"
"strings"
"github.com/ewhal/nyaa/db"
"github.com/ewhal/nyaa/model"
@ -21,6 +22,83 @@ import (
"github.com/gorilla/mux"
)
type ReassignForm struct {
AssignTo uint
By string
Data string
Torrents []uint
}
func (f *ReassignForm) ExtractInfo(r *http.Request) error {
f.By = r.FormValue("by")
if f.By != "olduser" && f.By != "torrentid" {
return fmt.Errorf("what?")
}
f.Data = strings.Trim(r.FormValue("data"), " \r\n")
if f.By == "olduser" {
if f.Data == "" {
return fmt.Errorf("No username given")
} else if strings.Contains(f.Data, "\n") {
return fmt.Errorf("More than one username given")
}
} else if f.By == "torrentid" {
if f.Data == "" {
return fmt.Errorf("No IDs given")
}
splitData := strings.Split(f.Data, "\n")
for i, tmp := range splitData {
tmp = strings.Trim(tmp, " \r")
torrent_id, err := strconv.ParseUint(tmp, 10, 0)
if err != nil {
return fmt.Errorf("Couldn't parse number on line %d", i+1)
}
f.Torrents = append(f.Torrents, uint(torrent_id))
}
}
tmp := r.FormValue("to")
parsed, err := strconv.ParseUint(tmp, 10, 0)
if err != nil {
return err
}
f.AssignTo = uint(parsed)
_, _, _, _, err = userService.RetrieveUser(r, tmp)
if err != nil {
return fmt.Errorf("User to assign to doesn't exist")
}
return nil
}
func (f *ReassignForm) ExecuteAction() (int, error) {
var toBeChanged []uint
var err error
if f.By == "olduser" {
toBeChanged, err = userService.RetrieveOldUploadsByUsername(f.Data)
if err != nil {
return 0, err
}
} else if f.By == "torrentid" {
toBeChanged = f.Torrents
}
num := 0
for _, torrent_id := range toBeChanged {
torrent, err2 := torrentService.GetRawTorrentById(torrent_id)
if err2 == nil {
torrent.UploaderID = f.AssignTo
db.ORM.Save(&torrent)
num += 1
}
}
// TODO: clean shit from user_uploads_old if needed
return num, nil
}
func IndexModPanel(w http.ResponseWriter, r *http.Request) {
currentUser := GetUser(r)
if userPermission.HasAdmin(currentUser) {
@ -271,3 +349,43 @@ func TorrentReportDeleteModPanel(w http.ResponseWriter, r *http.Request) {
http.Error(w, "admins only", http.StatusForbidden)
}
}
func TorrentReassignModPanel(w http.ResponseWriter, r *http.Request) {
currentUser := GetUser(r)
if !userPermission.HasAdmin(currentUser) {
http.Error(w, "admins only", http.StatusForbidden)
return
}
languages.SetTranslationFromRequest(panelTorrentReassign, r, "en-us")
htv := PanelTorrentReassignVbs{ReassignForm{}, NewSearchForm(), currentUser, form.NewErrors(), form.NewInfos(), r.URL}
err := panelTorrentReassign.ExecuteTemplate(w, "admin_index.html", htv)
log.CheckError(err)
}
func TorrentPostReassignModPanel(w http.ResponseWriter, r *http.Request) {
currentUser := GetUser(r)
if !userPermission.HasAdmin(currentUser) {
http.Error(w, "admins only", http.StatusForbidden)
return
}
var rForm ReassignForm
err := form.NewErrors()
infos := form.NewInfos()
err2 := rForm.ExtractInfo(r)
if err2 != nil {
err["errors"] = append(err["errors"], err2.Error())
} else {
count, err2 := rForm.ExecuteAction()
if err2 != nil {
err["errors"] = append(err["errors"], "Something went wrong")
} else {
infos["infos"] = append(infos["infos"], fmt.Sprintf("%d torrents updated.", count))
}
}
htv := PanelTorrentReassignVbs{rForm, NewSearchForm(), currentUser, err, infos, r.URL}
err_ := panelTorrentReassign.ExecuteTemplate(w, "admin_index.html", htv)
log.CheckError(err_)
}

Voir le fichier

@ -101,17 +101,14 @@ func init() {
Router.HandleFunc("/mod/torrent/delete", TorrentDeleteModPanel).Name("mod_tdelete")
Router.HandleFunc("/mod/report/delete", TorrentReportDeleteModPanel).Name("mod_trdelete")
Router.HandleFunc("/mod/comment/delete", CommentDeleteModPanel).Name("mod_cdelete")
Router.HandleFunc("/mod/reassign", TorrentReassignModPanel).Name("mod_treassign").Methods("GET")
Router.HandleFunc("/mod/reassign", TorrentPostReassignModPanel).Name("mod_treassign").Methods("POST")
//reporting a torrent
Router.HandleFunc("/report/{id}", ReportTorrentHandler).Methods("POST").Name("post_comment")
Router.PathPrefix("/captcha").Methods("GET").HandlerFunc(captcha.ServeFiles)
//Router.HandleFunc("/report/create", gzipTorrentReportCreateHandler).Name("torrent_report_create").Methods("POST")
// TODO Allow only moderators to access /moderation/*
//Router.HandleFunc("/moderation/report/delete", gzipTorrentReportDeleteHandler).Name("torrent_report_delete").Methods("POST")
//Router.HandleFunc("/moderation/torrent/delete", gzipTorrentDeleteHandler).Name("torrent_delete").Methods("POST")
Router.HandleFunc("/language", SeeLanguagesHandler).Methods("GET").Name("see_languages")
Router.HandleFunc("/language", ChangeLanguageHandler).Methods("POST").Name("change_language")

Voir le fichier

@ -9,7 +9,7 @@ var TemplateDir = "templates"
var homeTemplate, searchTemplate, faqTemplate, uploadTemplate, viewTemplate, viewRegisterTemplate, viewLoginTemplate, viewRegisterSuccessTemplate, viewVerifySuccessTemplate, viewProfileTemplate, viewProfileEditTemplate, viewUserDeleteTemplate, notFoundTemplate, changeLanguageTemplate *template.Template
var panelIndex, panelTorrentList, panelUserList, panelCommentList, panelTorrentEd, panelTorrentReportList *template.Template
var panelIndex, panelTorrentList, panelUserList, panelCommentList, panelTorrentEd, panelTorrentReportList, panelTorrentReassign *template.Template
type templateLoader struct {
templ **template.Template
@ -127,6 +127,11 @@ func ReloadTemplates() {
name: "torrent_report",
file: filepath.Join("admin", "torrent_report.html"),
},
templateLoader{
templ: &panelTorrentReassign,
name: "torrent_reassign",
file: filepath.Join("admin", "reassign.html"),
},
}
for idx := range modTempls {

Voir le fichier

@ -36,6 +36,24 @@ var FuncMap = template.FuncMap{
}
return "error"
},
"genSearchWithOrdering": func(currentUrl url.URL, sortBy string) template.URL {
values := currentUrl.Query()
order := false
if _, ok := values["order"]; ok {
order, _ = strconv.ParseBool(values["order"][0])
if values["sort"][0]==sortBy {
order=!order //Flip order by repeat-clicking
} else {
order=false //Default to descending when sorting by something new
}
}
values.Set("sort", sortBy)
values.Set("order", strconv.FormatBool(order))
currentUrl.RawQuery=values.Encode()
return template.URL(currentUrl.String())
},
"genNav": func(nav Navigation, currentUrl *url.URL, pagesSelectable int) template.HTML {
var ret = ""
if (nav.TotalItem > 0) {

Voir le fichier

@ -157,6 +157,7 @@ type PanelCommentListVbs struct {
User *model.User
URL *url.URL // For parsing Url in templates
}
type PanelTorrentEdVbs struct {
Upload UploadForm
Search SearchForm
@ -174,6 +175,15 @@ type PanelTorrentReportListVbs struct {
URL *url.URL // For parsing Url in templates
}
type PanelTorrentReassignVbs struct {
Reassign ReassignForm
Search SearchForm // unused?
User *model.User // unused?
FormErrors map[string][]string
FormInfos map[string][]string
URL *url.URL // For parsing Url in templates
}
/*
* Variables used by the upper ones
*/

Voir le fichier

@ -71,7 +71,7 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
torrent.Uploader = new(model.User)
db.ORM.Where("user_id = ?", torrent.UploaderID).Find(torrent.Uploader)
torrent.OldUploader = ""
if torrent.ID <= config.LastOldTorrentID {
if torrent.ID <= config.LastOldTorrentID && torrent.UploaderID == 0 {
var tmp model.UserUploadsOld
if !db.ORM.Where("torrent_id = ?", torrent.ID).Find(&tmp).RecordNotFound() {
torrent.OldUploader = tmp.Username
@ -88,6 +88,15 @@ func GetTorrentById(id string) (torrent model.Torrent, err error) {
return
}
// won't fetch user or comments
func GetRawTorrentById(id uint) (torrent model.Torrent, err error) {
err = nil
if db.ORM.Where("torrent_id = ?", id).Find(&torrent).RecordNotFound() {
err = errors.New("Article is not found.")
}
return
}
func GetTorrentsOrderByNoCount(parameters *serviceBase.WhereParams, orderBy string, limit int, offset int) (torrents []model.Torrent, err error) {
torrents, _, err = getTorrentsOrderBy(parameters, orderBy, limit, offset, false)
return

Voir le fichier

@ -50,7 +50,7 @@ func IsAgreed(termsAndConditions string) bool { // TODO: Inline function
type RegistrationForm struct {
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email"`
Password string `form:"password" needed:"true" len_min:"6" len_max:"25" equalInput:"ConfirmPassword"`
Password string `form:"password" needed:"true" len_min:"6" len_max:"72" equalInput:"ConfirmPassword"`
ConfirmPassword string `form:"password_confirmation" omit:"true" needed:"true"`
CaptchaID string `form:"captchaID" omit:"true" needed:"true"`
TermsAndConditions bool `form:"t_and_c" omit:"true" needed:"true" equal:"true" hum_name:"Terms and Conditions"`
@ -67,8 +67,8 @@ type UserForm struct {
Username string `form:"username" needed:"true" len_min:"3" len_max:"20"`
Email string `form:"email"`
Language string `form:"language" default:"en-us"`
CurrentPassword string `form:"current_password" len_min:"6" len_max:"25" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"25" equalInput:"Confirm_Password"`
CurrentPassword string `form:"current_password" len_min:"6" len_max:"72" omit:"true"`
Password string `form:"password" len_min:"6" len_max:"72" equalInput:"Confirm_Password"`
Confirm_Password string `form:"password_confirmation" omit:"true"`
Status int `form:"status" default:"0"`
}

Voir le fichier

@ -253,6 +253,19 @@ func RetrieveUserByUsername(username string) (*model.PublicUser, string, int, er
return &model.PublicUser{User: &user}, username, http.StatusOK, nil
}
func RetrieveOldUploadsByUsername(username string) ([]uint, error) {
var ret []uint
var tmp []*model.UserUploadsOld
err := db.ORM.Where("username = ?", username).Find(&tmp).Error
if err != nil {
return ret, err
}
for _, tmp2 := range tmp {
ret = append(ret, tmp2.TorrentId)
}
return ret, nil
}
// RetrieveUserForAdmin retrieves a user for an administrator.
func RetrieveUserForAdmin(id string) (model.User, int, error) {
var user model.User

Voir le fichier

@ -39,14 +39,15 @@
<h2 id="trackers">{{T "which_trackers_do_you_recommend"}}</h2>
<p>{{T "answer_which_trackers_do_you_recommend"}}</p>
<pre>udp://tracker.coppersurfer.tk:6969
udp://zer0day.to:1337/announce
udp://tracker.leechers-paradise.org:6969
udp://explodie.org:6969
udp://tracker.opentrackr.org:1337
udp://tracker.internetwarriors.net:1337/announce
http://mgtracker.org:6969/announce
http://tracker.baka-sub.cf/announce</pre>
<pre>udp://tracker.doko.moe:6969</pre>
<p>{{T "other_trackers"}}</p>
<pre>udp://zer0day.to:1337/announce
udp://tracker.leechers-paradise.org:6969
udp://explodie.org:6969
udp://tracker.opentrackr.org:1337
udp://tracker.internetwarriors.net:1337/announce
http://mgtracker.org:6969/announce
http://tracker.baka-sub.cf/announce</pre>
<h2>{{T "how_can_i_help"}}</h2>
<p>{{T "answer_how_can_i_help"}}</p>

Voir le fichier

@ -5,7 +5,7 @@
<label for="solution">Captcha</label>
<input type="text" name="captchaID" value="{{.CaptchaID}}" hidden>
<img src="/captcha/{{.CaptchaID}}.png">
<input type="text" name="solution" class="form-control" placeholder="Captcha" autocomplete="off" required>
<input type="text" name="solution" id="solution" class="form-control" placeholder="Captcha" autocomplete="off" required>
</div>
{{end}}
{{end}}

Voir le fichier

@ -8,7 +8,7 @@
darkStyleLink.type = "text/css";
darkStyleLink.href = "/css/style-night.css"
if (night == "true") {
document.getElementsByTagName("head")[0].append(darkStyleLink);
document.getElementsByTagName("head")[0].appendChild(darkStyleLink);
}
</script>
{{end}}

Voir le fichier

@ -31,24 +31,7 @@
<option value="2" {{if eq .Search.Status 2}}selected{{end}}>{{T "trusted"}}</option>
<option value="3" {{if eq .Search.Status 3}}selected{{end}}>A+</option>
</select>
<input type="hidden" name="userID" value="{{ .Search.UserID }}">
{{end}}
{{define "search_advanced"}}
<select name="sort" class="form-control input-sm">
<option value="0" {{if eq .Search.Sort 0}}selected{{end}}>{{T "id"}}</option>
<option value="1" {{if eq .Search.Sort 1}}selected{{end}}>{{T "name"}}</option>
<option value="2" {{if eq .Search.Sort 2}}selected{{end}}>{{T "date"}}</option>
<option value="3" {{if eq .Search.Sort 3}}selected{{end}}>{{T "downloads"}}</option>
<option value="4" {{if eq .Search.Sort 4}}selected{{end}}>{{T "size"}}</option>
<option value="5" {{if eq .Search.Sort 4}}selected{{end}}>{{T "seeders"}}</option>
<option value="6" {{if eq .Search.Sort 4}}selected{{end}}>{{T "leechers"}}</option>
<option value="7" {{if eq .Search.Sort 4}}selected{{end}}>{{T "completed"}}</option>
</select>
<select name="order" class="form-control input-sm">
<option value="false" {{if eq .Search.Order false}}selected{{end}}>{{T "descending"}}</option>
<option value="true" {{if eq .Search.Order true}}selected{{end}}>{{T "ascending"}}</option>
</select>
<select name="max" class="form-control input-sm">
<select id="max" 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>
@ -65,6 +48,7 @@
<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>
<input type="hidden" name="userID" value="{{ .Search.UserID }}">
{{end}}
{{define "search_button"}}

32
templates/admin/reassign.html Fichier normal
Voir le fichier

@ -0,0 +1,32 @@
{{define "title"}}Torrent Reassign{{end}}
{{define "content"}}
<form enctype="multipart/form-data" method="POST">
{{ range (index $.FormInfos "infos")}}
<div class="alert alert-info"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-info-sign"></i> {{ . }}</div>
{{end}}
{{ range (index $.FormErrors "errors")}}
<div class="alert alert-danger"><a class="panel-close close" data-dismiss="alert">×</a><i class="glyphicon glyphicon-exclamation-sign"></i> {{ . }}</div>
{{end}}
<p>Reassigning torrents to a new user is not easily reverted and should be done with care.</p>
{{with .Reassign}}
<div class="form-group">
<label for="name">Reassign to:</label>
<input type="text" name="to" class="form-control" placeholder="User ID" {{if ne .AssignTo 0}}value="{{.AssignTo}}"{{end}} required>
</div>
<div class="form-group">
<label for="by">Reassign based on:</label><br />
<input type="radio" name="by" value="olduser" {{if eq .By "olduser"}}selected{{end}} required> Old Username<br />
<input type="radio" name="by" value="torrentid" {{if eq .By "torrentid"}}selected{{end}} required> Torrent ID
</div>
<div class="form-group">
<p>One ID per line <b>or</b> a single username</p>
<textarea rows="20" cols="40" name="data">{{.Data}}</textarea>
</div>
{{end}}
<p>Might take a long time, do <b>NOT</b> abort the request.</p>
<button type="submit" class="btn btn-success">{{T "save_changes"}}</button>
</form>
{{end}}

Voir le fichier

@ -47,7 +47,13 @@
<li><a href="{{ genRoute "mod_tlist"}}">{{T "Torrents"}}</a></li>
<li><a href="{{ genRoute "mod_ulist"}}">{{T "Users"}}</a></li>
<li><a href="{{ genRoute "mod_clist"}}">{{T "Comments"}}</a></li>
<li><a href="{{ genRoute "mod_trlist"}}">{{T "Torrent Reports"}}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Other<span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="{{ genRoute "mod_trlist"}}">{{T "Torrent Reports"}}</a></li>
<li><a href="{{ genRoute "mod_treassign" }}">Torrent Reassign</a></li>
</ul>
</li>
</ul>
{{block "badge_user" .}}{{end}}

Voir le fichier

@ -1,7 +1,7 @@
{{define "title"}}{{T "home"}}{{end}}
{{define "contclass"}}cont-home{{end}}
{{define "content"}}
<div class="blockBody">
<div class="blockBody">
<ul class="list-inline" aria-label="Page navigation">
<li><img id="mascot" src="/img/renchon.png" /></li>
<li style="padding-top: 7%;" class="pull-right"><ul class="pagination">
@ -13,10 +13,16 @@
<table class="table custom-table-hover">
<tr>
<th class="col-xs-1 hidden-xs">{{T "category"}}</th>
<th class="col-xs-8">{{T "name"}}</th>
<th class="col-xs-1 hidden-xs">{{T "S"}} / {{T "L"}} / {{T "D"}}</th>
<th class="col-xs-1 hidden-xs">{{T "date"}}</th>
<th class="col-xs-1 hidden-xs">{{T "size"}}</th>
<th class="col-xs-8">
<a href="{{ genSearchWithOrdering .URL "1" }}">{{T "name"}}</a>
</th>
<th class="col-xs-1 hidden-xs">
<a href="{{ genSearchWithOrdering .URL "4" }}">{{T "S"}}</a> /
<a href="{{ genSearchWithOrdering .URL "4" }}">{{T "L"}}</a> /
<a href="{{ genSearchWithOrdering .URL "3" }}">{{T "D"}}</a>
</th>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "2" }}">{{T "date"}}</th></a>
<th class="col-xs-1 hidden-xs"><a href="{{ genSearchWithOrdering .URL "4" }}">{{T "size"}}</a></th>
<th class="col-xs-1 hidden-xs">{{T "links"}}</th>
</tr>
{{ range .ListTorrents}}

Voir le fichier

@ -72,21 +72,6 @@
<div style="padding-top: 10rem"></div>
<div class="container {{block "contclass" .}}generic{{end}}" id="container">
{{if not .Search.HideAdvancedSearch}}
<div class="blockBody" style="text-align:center">
<a href="#advanced-search" data-toggle="collapse">{{T "advanced_search"}}</a><br />
<form id="advanced-search" class="navbar-form collapse" role="search" action="/search" method="get">
<div class="form-group">
{{block "search_common" .}}{{end}}
{{block "search_advanced" .}}{{end}}
{{block "search_button" .}}{{end}}
</div>
</form>
<div style="clear:both"></div>
</div>
<div style="margin:0.5em"></div>
{{end}}
{{block "content" .}}{{T "nothing_here"}}{{end}}
</div>
@ -96,6 +81,7 @@
Powered by NyaaPantsu
</footer>
{{if eq .User.ID 0}}
<form method="POST" action="{{ .URL.Parse "/language" }}" id="bottom_language_selector_form">
<select id="bottom_language_selector" name="language" onchange="javascript:document.getElementById('bottom_language_selector_form').submit()" hidden class="form-control"></select>

Voir le fichier

@ -7,7 +7,7 @@
<div class="form-group">
<label for="name">{{T "name"}}</label>
<input type="text" name="name" class="form-control" placeholder="File Name" value="{{.Name}}" required>
<input type="text" name="name" id="name" class="form-control" placeholder="File Name" value="{{.Name}}" autofocus required>
</div>
<div class="form-group">
<label for="torrent">{{T "torrent_file"}}</label>
@ -16,12 +16,12 @@
</div>
<div class="form-group">
<label for="magnet">{{T "magnet_link"}}</label>
<input type="text" name="magnet" class="form-control"
<input type="text" name="magnet" id="magnet" class="form-control"
style="width:60rem" placeholder="{{T "magnet_link"}}" value="{{.Magnet}}">
</div>
<div class="form-group">
<label for="c">{{T "category"}}</label>
<select name="c" class="form-control input-sm" required>
<select name="c" id="c" class="form-control input-sm" required>
<option value="">{{T "select_a_torrent_category"}}</option>
<option value="3_12" {{if eq .Category "3_12"}}selected{{end}}>{{T "anime_amv"}}</option>
<option value="3_5" {{if eq .Category "3_5"}}selected{{end}}>{{T "anime_english_translated"}}</option>
@ -43,14 +43,14 @@
</select>
</div>
<div class="form-group">
<input type="checkbox" name="remake">
<input type="checkbox" name="remake" id="remake" >
<label for="remake">{{T "mark_as_remake"}}</label>
</div>
<div class="form-group">
<label for="desc">{{T "torrent_description"}}</label>
<p class="help-block">{{T "description_markdown_notice"}}</p>
<textarea name="desc" class="form-control" rows="10">{{.Description}}</textarea>
<textarea name="desc" id="desc" class="form-control" rows="10">{{.Description}}</textarea>
</div>
{{block "captcha" .}}{{end}}

Voir le fichier

@ -12,7 +12,7 @@
<div class="alert alert-danger">{{ . }}</div>
{{end}}
<div class="form-group">
<input type="text" name="username" id="username" class="form-control input-lg" autofocus="" placeholder="{{ T "email_address_or_username"}}">
<input type="text" name="username" id="username" class="form-control input-lg" autofocus placeholder="{{ T "email_address_or_username"}}">
{{ range (index $.FormErrors "username")}}
<p class="text-error">{{ . }}</p>
{{end}}

Voir le fichier

@ -12,13 +12,13 @@
<div class="alert alert-danger">{{ . }}</div>
{{end}}
<div class="form-group">
<input type="text" name="username" id="display_name" class="form-control input-lg" placeholder="{{T "username" }}" tabindex="1" value="{{ .Username }}">
<input type="text" name="username" id="display_name" class="form-control input-lg" placeholder="{{T "username" }}" value="{{ .Username }}" autofocus>
{{ range (index $.FormErrors "username")}}
<p class="text-error">{{ . }}</p>
{{end}}
</div>
<div class="form-group">
<input type="email" name="email" id="email" class="form-control input-lg" placeholder="{{T "email_address" }}" tabindex="2" value="{{ .Email }}">
<input type="email" name="email" id="email" class="form-control input-lg" placeholder="{{T "email_address" }}" value="{{ .Email }}">
{{ range (index $.FormErrors "email")}}
<p class="text-error">{{ . }}</p>
{{end}}
@ -26,7 +26,7 @@
<div class="row">
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="form-group">
<input type="password" name="password" id="password" class="form-control input-lg" placeholder="{{T "password" }}" tabindex="3" value="{{ .Password }}">
<input type="password" name="password" id="password" class="form-control input-lg" placeholder="{{T "password" }}" value="{{ .Password }}">
{{ range (index $.FormErrors "password")}}
<p class="text-error">{{ . }}</p>
{{end}}
@ -34,7 +34,7 @@
</div>
<div class="col-xs-12 col-sm-6 col-md-6">
<div class="form-group">
<input type="password" name="password_confirmation" id="password_confirmation" class="form-control input-lg" placeholder="{{T "confirm_password" }}" tabindex="4">
<input type="password" name="password_confirmation" id="password_confirmation" class="form-control input-lg" placeholder="{{T "confirm_password" }}">
{{ range (index $.FormErrors "password_confirmation")}}
<p class="text-error">{{ . }}</p>
{{end}}
@ -44,7 +44,7 @@
<div class="row">
<div class="col-xs-4 col-sm-3 col-md-3">
<span class="button-checkbox">
<button type="button" class="btn hidden" data-color="info" tabindex="5">{{T "i_agree" }}</button>
<button type="button" class="btn hidden" data-color="info">{{T "i_agree" }}</button>
<input type="checkbox" name="t_and_c" id="t_and_c" value="1">
{{ range (index $.FormErrors "t_and_c")}}
<p class="text-error">{{ . }}</p>
@ -60,7 +60,7 @@
<hr class="colorgraph">
<div class="row">
<div class="col-xs-12 col-md-6"><input type="submit" value="{{T "register" }}" class="btn btn-primary btn-block btn-lg" tabindex="7"></div>
<div class="col-xs-12 col-md-6"><input type="submit" value="{{T "register" }}" class="btn btn-primary btn-block btn-lg"></div>
<div class="col-xs-12 col-md-6">or <a href="{{ genRoute "user_login" }}" class="">{{T "signin" }}</a></div>
</div>
</form>

Voir le fichier

@ -249,7 +249,7 @@
},
{
"id": "future_not_looking_good",
"translation": "Future prospects for nyaa are not looking good. (It's dead)"
"translation": "Future prospects for nyaa are not looking good. (It's dead, Jim)"
},
{
"id": "recovery_effort",
@ -309,7 +309,11 @@
},
{
"id": "answer_which_trackers_do_you_recommend",
"translation": "If your torrent upload is denied because of trackers you'll need to add some of these:"
"translation": "We now have our own Tracker!, add it to the top of the list before uploading:"
},
{
"id": "other_trackers",
"translation": "But you should also add these, just in case something goes wrong"
},
{
"id": "how_can_i_help",

Voir le fichier

@ -352,7 +352,7 @@
"translation": "Todas las Categorías"
},
{
"id:": "select_a_torrent_category",
"id": "select_a_torrent_category",
"translation": "Selecciona una Categoría para el Torrent"
},
{

Voir le fichier

@ -229,7 +229,7 @@
},
{
"id": "nyaa_se_went_offline",
"translation": "nyaa.se és a vele kapcsolatos domain-ek (pl. nyaatorrents.info) elérhetetlenné vált 2017. Május 1-én."
"translation": "nyaa.se és a vele kapcsolatos domain-ek (pl. nyaatorrents.info) elérhetetlenné váltak 2017. május 1-én."
},
{
"id": "its_not_a_ddos",
@ -547,6 +547,66 @@
"id": "delete_success",
"translation": "A fiók törlésre került."
},
{
"id": "moderation",
"translation": "Moderáció"
},
{
"id": "who_is_renchon",
"translation": "Ki a fasz az a れんちょん?"
},
{
"id": "renchon_anon_explanation",
"translation": "れんちょん nevet az kapja, aki névtelenül ír kommentet vagy tölt fel valamit. Ezt a nevet kapják az eredeti nyaa-ról átimportált torrentek is, viszont az eredeti feltöltő neve megjelenhet mellette."
},
{
"id": "mark_as_remake",
"translation": "Remake-ként jelölés"
},
{
"id": "email_changed",
"translation": "Az email megváltoztatása sikeres volt, viszont még meg kell erősítened a(z) %s címre küldött linkkel."
},
{
"id": "torrent_status",
"translation": "Torrent állapota"
},
{
"id": "torrent_status_hidden",
"translation": "Eltüntetett"
},
{
"id": "torrent_status_normal",
"translation": "Normál"
},
{
"id": "torrent_status_remake",
"translation": "Remake"
},
{
"id": "profile_edit_page",
"translation": "%s profiljának szerkesztése."
},
{
"id":"date_format",
"translation": "2006-01-02 15:04"
},
{
"id": "seeders",
"translation": "Seederek"
},
{
"id": "leechers",
"translation": "Leecherek"
},
{
"id": "completed",
"translation": "Befejezett"
},
{
"id": "change_language",
"translation": "Nyelv megváltoztatása"
},
{
"id": "language_name",
"translation": "Magyar"

Voir le fichier

@ -569,7 +569,7 @@
},
{
"id": "renchon_anon_explanation",
"translation": "れんちょん é o nome atribuído a uploads e comentários feitos anonimamente. Também é usado para torrents importados do nyaa original, embora o uploader original seja mostrado ao lado."
"translation": "れんちょん (Ren-chon) é o nome atribuído a uploads e comentários feitos anonimamente. Também é usado para torrents importados do nyaa original, embora o uploader original seja mostrado ao lado."
},
{
"id": "mark_as_remake",

Voir le fichier

@ -352,7 +352,7 @@
"translation": "所有分类"
},
{
"id:": "select_a_torrent_category",
"id": "select_a_torrent_category",
"translation": "请选择种子分类"
},
{

Voir le fichier

@ -2,13 +2,40 @@ package languages
import (
"fmt"
"html/template"
"net/http"
"path"
"path/filepath"
"github.com/ewhal/nyaa/config"
"github.com/ewhal/nyaa/service/user"
"github.com/nicksnyder/go-i18n/i18n"
"github.com/nicksnyder/go-i18n/i18n/language"
"html/template"
"net/http"
)
// Initialize the languages translation
func InitI18n(conf config.I18nConfig) error {
defaultFilepath := path.Join(conf.TranslationsDirectory, conf.DefaultLanguage+".all.json")
err := i18n.LoadTranslationFile(defaultFilepath)
if err != nil {
panic(fmt.Sprintf("failed to load default translation file '%s': %v", defaultFilepath, err))
}
paths, err := filepath.Glob(path.Join(conf.TranslationsDirectory, "*.json"))
if err != nil {
return fmt.Errorf("failed to get translation files: %v", err)
}
for _, path := range paths {
err := i18n.LoadTranslationFile(path)
if err != nil {
return fmt.Errorf("failed to load translation file '%s': %v", path, err)
}
}
return nil
}
// When go-i18n finds a language with >0 translations, it uses it as the Tfunc
// However, if said language has a missing translation, it won't fallback to the "main" language
func TfuncAndLanguageWithFallback(language string, languages ...string) (i18n.TranslateFunc, *language.Language, error) {
@ -81,7 +108,6 @@ func GetTfuncAndLanguageFromRequest(r *http.Request, defaultLanguage string) (T
return
}
func SetTranslationFromRequest(tmpl *template.Template, r *http.Request, defaultLanguage string) i18n.TranslateFunc {
r.Header.Add("Vary", "Accept-Encoding")
T, _ := GetTfuncAndLanguageFromRequest(r, defaultLanguage)

Voir le fichier

@ -0,0 +1,18 @@
package languages
import (
"path"
"testing"
"github.com/ewhal/nyaa/config"
)
func TestInitI18n(t *testing.T) {
conf := config.DefaultI18nConfig
conf.TranslationsDirectory = path.Join("..", "..", conf.TranslationsDirectory)
err := InitI18n(conf)
if err != nil {
t.Errorf("failed to initialize language translations: %v", err)
}
}