now torrent pages work too!

- Changed the URL structure of torrent pages:
  Before:
    /torrents/{{infoHash}}/{{name}}
  After:
    /torrents/{{infoHash}}
This commit is contained in:
Bora Alper 2018-06-29 18:58:57 +03:00
parent 0501fc3e3c
commit 3a45f17647
8 changed files with 128 additions and 25 deletions

View File

@ -56,6 +56,7 @@ func apiTorrentsHandler(w http.ResponseWriter, r *http.Request) {
return
}
// TODO: use plain Marshal
jm, err := json.MarshalIndent(torrents, "", " ")
if err != nil {
respondError(w, 500, "json marshalling error: %s", err.Error())

View File

@ -0,0 +1,73 @@
/*
* Natural Sort algorithm for Javascript - Version 0.8.1 - Released under MIT license
* Author: Jim Palmer (based on chunking idea from Dave Koelle)
*
* https://github.com/overset/javascript-natural-sort
*
* Modified by Mert Bora ALPER <bora@boramalper.org> for magnetico.
*/
function naturalSort (a, b) {
/* The following modification makes sure that paths with less levels (i.e. less directories) are
* smaller than (or, "comes before") the directories with more levels (i.e. more directories).
*
* Without Bora's Modification:
* >>> ["/aaaa/aaa/aa.html", "/aaaa/bbb.txt"].sort(naturalSort)
* ["/aaaa/aaa/aa.html", "/aaaa/bbb.txt"]
*
* With Bora's Modification:
* >>> ["/aaaa/aaa/aa.html", "/aaaa/bbb.txt"].sort(naturalSort)
* ["/aaaa/bbb.txt", "/aaaa/aaa/aa.html"]
*
* <Bora's Modification>
*/
let aSlashes = a.split("/").length,
bSlashes = b.split("/").length;
if (aSlashes !== bSlashes)
return aSlashes - bSlashes;
// </Bora's Modification>
var re = /(^([+\-]?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?(?=\D|\s|$))|^0x[\da-fA-F]+$|\d+)/g,
sre = /^\s+|\s+$/g, // trim pre-post whitespace
snre = /\s+/g, // normalize all whitespace to single ' ' character
dre = /(^([\w ]+,?[\w ]+)?[\w ]+,?[\w ]+\d+:\d+(:\d+)?[\w ]?|^\d{1,4}[\/\-]\d{1,4}[\/\-]\d{1,4}|^\w+, \w+ \d+, \d{4})/,
hre = /^0x[0-9a-f]+$/i,
ore = /^0/,
i = function(s) {
return (naturalSort.insensitive && ('' + s).toLowerCase() || '' + s).replace(sre, '');
},
// convert all to strings strip whitespace
x = i(a),
y = i(b),
// chunk/tokenize
xN = x.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
yN = y.replace(re, '\0$1\0').replace(/\0$/,'').replace(/^\0/,'').split('\0'),
// numeric, hex or date detection
xD = parseInt(x.match(hre), 16) || (xN.length !== 1 && Date.parse(x)),
yD = parseInt(y.match(hre), 16) || xD && y.match(dre) && Date.parse(y) || null,
normChunk = function(s, l) {
// normalize spaces; find floats not starting with '0', string or 0 if not defined (Clint Priest)
return (!s.match(ore) || l == 1) && parseFloat(s) || s.replace(snre, ' ').replace(sre, '') || 0;
},
oFxNcL, oFyNcL;
// first try and sort Hex codes or Dates
if (yD) {
if (xD < yD) { return -1; }
else if (xD > yD) { return 1; }
}
// natural sorting through split numeric strings and default strings
for(var cLoc = 0, xNl = xN.length, yNl = yN.length, numS = Math.max(xNl, yNl); cLoc < numS; cLoc++) {
oFxNcL = normChunk(xN[cLoc] || '', xNl);
oFyNcL = normChunk(yN[cLoc] || '', yNl);
// handle numeric vs string comparison - number < string - (Kyle Adams)
if (isNaN(oFxNcL) !== isNaN(oFyNcL)) {
return isNaN(oFxNcL) ? 1 : -1;
}
// if unicode use locale comparison
if (/[^\x00-\x80]/.test(oFxNcL + oFyNcL) && oFxNcL.localeCompare) {
var comp = oFxNcL.localeCompare(oFyNcL);
return comp / Math.abs(comp);
}
if (oFxNcL < oFyNcL) { return -1; }
else if (oFxNcL > oFyNcL) { return 1; }
}
}

View File

@ -11,6 +11,7 @@
window.onload = function() {
var pre_element = document.getElementsByTagName("pre")[0];
var paths = pre_element.textContent.replace(/\s+$/, "").split("\n");
paths.sort(naturalSort);
paths = paths.map(function(path) { return path.split('/'); });
pre_element.textContent = stringify(structurise(paths)).join("\n");
};

View File

@ -122,7 +122,7 @@ function encodeQueryData(data) {
// https://stackoverflow.com/q/10420352/4466589
function fileSize(fileSizeInBytes) {
let i = -1;
let byteUnits = [' kB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'];
let byteUnits = [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB'];
do {
fileSizeInBytes = fileSizeInBytes / 1024;
i++;

View File

@ -2,11 +2,12 @@
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ torrent.name }} - magnetico</title>
<link rel="stylesheet" href="static/styles/reset.css">
<link rel="stylesheet" href="static/styles/essential.css">
<link rel="stylesheet" href="static/styles/torrent.css">
<script defer src="static/scripts/torrent.js"></script>
<title>{{ .T.Name }} - magnetico</title>
<link rel="stylesheet" href="/static/styles/reset.css">
<link rel="stylesheet" href="/static/styles/essential.css">
<link rel="stylesheet" href="/static/styles/torrent.css">
<script defer src="/static/scripts/naturalSort-v0.8.1.js"></script>
<script defer src="/static/scripts/torrent.js"></script>
</head>
<body>
<header>
@ -17,39 +18,32 @@
</header>
<main>
<div id="title">
<h2>{{ torrent.name }}</h2>
<a href="magnet:?xt=urn:btih:{{ torrent.info_hash }}&dn={{ torrent.name }}">
<img src="static/assets/magnet.gif" alt="Magnet link"
<h2>{{ .T.Name }}</h2>
<a href="magnet:?xt=urn:btih:{{ bytesToHex .T.InfoHash }}&amp;dn={{ .T.Name }}">
<img src="/static/assets/magnet.gif" alt="Magnet link"
title="Download this torrent using magnet" />
<small>{{ torrent.info_hash }}</small>
<small>{{ bytesToHex .T.InfoHash }}</small>
</a>
</div>
<table>
<tr>
<th scope="row">Size</th>
<td>{{ torrent.size }}</td>
<td>{{ humanizeSize .T.Size }}</td>
</tr>
<tr>
<th scope="row">Discovered on</th>
<td>{{ torrent.discovered_on }}</td>
<td>{{ unixTimeToYearMonthDay .T.DiscoveredOn }}</td>
</tr>
<tr>
<th scope="row">Files</th>
<td>{{ torrent.files|length }}</td>
<td>{{ .T.NFiles }}</td>
</tr>
</table>
<h3>Contents</h3>
<noscript>
<pre>
{% for file in torrent.files -%}
{{ file.path }}{{ "\n" }}
{%- endfor %}
</pre>
</noscript>
<!-- Content of this element will be overwritten by the script -->
<pre>{% for file in torrent.files -%}{{ file.path }}{{ "\t" + file.size }}{{ "\n" }}{%- endfor %}</pre>
<pre>{{ range .F }}{{ .Path }}{{ "\t" }}{{ humanizeSizeF .Size }}{{ "\n" }}{{ end }}</pre>
</main>
</body>
</html>

View File

@ -16,7 +16,7 @@
<td><a href="magnet:?xt=urn:btih:{{infoHash}}&dn={{name}}">
<img src="static/assets/magnet.gif" alt="Magnet link"
title="Download this torrent using magnet" /></a></td>
<td><a href="/torrents/{{infoHash}}/{{name}}">{{name}}</a></td>
<td><a href="/torrents/{{infoHash}}">{{name}}</a></td>
<td>{{size}}</td>
<td>{{discoveredOn}}</td>
</tr>

View File

@ -126,6 +126,13 @@ func main() {
return humanize.IBytes(s)
},
"humanizeSizeF": func(s int64) string {
if s < 0 {
return ""
}
return humanize.IBytes(uint64(s))
},
"comma": func(s uint) string {
return humanize.Comma(int64(s))
},
@ -135,7 +142,7 @@ func main() {
// templates["feed"] = template.Must(template.New("feed").Parse(string(mustAsset("templates/feed.xml"))))
templates["homepage"] = template.Must(template.New("homepage").Funcs(templateFunctions).Parse(string(mustAsset("templates/homepage.html"))))
// templates["statistics"] = template.Must(template.New("statistics").Parse(string(mustAsset("templates/statistics.html"))))
// templates["torrent"] = template.Must(template.New("torrent").Funcs(templateFunctions).Parse(string(mustAsset("templates/torrent.html"))))
templates["torrent"] = template.Must(template.New("torrent").Funcs(templateFunctions).Parse(string(mustAsset("templates/torrent.html"))))
// templates["torrents"] = template.Must(template.New("torrents").Funcs(templateFunctions).Parse(string(mustAsset("templates/torrents.html"))))
var err error
@ -182,6 +189,7 @@ func torrentsHandler(w http.ResponseWriter, r *http.Request) {
w.Write(data)
}
// TODO: we might as well move torrent.html into static...
func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
// show torrents/{infohash}
infoHash, err := hex.DecodeString(mux.Vars(r)["infohash"])
@ -193,8 +201,32 @@ func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
if err != nil {
panic(err.Error())
}
if torrent == nil {
w.WriteHeader(404)
w.Write([]byte("torrent not found!"))
return
}
templates["torrent"].Execute(w, torrent)
files, err := database.GetFiles(infoHash)
if err != nil {
panic(err.Error())
}
if files == nil {
w.WriteHeader(500)
w.Write([]byte("files not found what!!!"))
return
}
err = templates["torrent"].Execute(w, struct {
T *persistence.TorrentMetadata
F []persistence.File
}{
T: torrent,
F: files,
})
if err != nil {
panic("error while executing template!")
}
}
func statisticsHandler(w http.ResponseWriter, r *http.Request) {

View File

@ -330,7 +330,9 @@ func (db *sqlite3Database) GetTorrent(infoHash []byte) (*TorrentMetadata, error)
}
func (db *sqlite3Database) GetFiles(infoHash []byte) ([]File, error) {
rows, err := db.conn.Query("SELECT size, path FROM files WHERE torrent_id = ?;", infoHash)
rows, err := db.conn.Query(
"SELECT size, path FROM files, torrents WHERE files.torrent_id = torrents.id AND torrents.info_hash = ?;",
infoHash)
if err != nil {
return nil, err
}