now torrent pages work too!
- Changed the URL structure of torrent pages: Before: /torrents/{{infoHash}}/{{name}} After: /torrents/{{infoHash}}
This commit is contained in:
parent
0501fc3e3c
commit
3a45f17647
@ -56,6 +56,7 @@ func apiTorrentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: use plain Marshal
|
||||||
jm, err := json.MarshalIndent(torrents, "", " ")
|
jm, err := json.MarshalIndent(torrents, "", " ")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondError(w, 500, "json marshalling error: %s", err.Error())
|
respondError(w, 500, "json marshalling error: %s", err.Error())
|
||||||
|
73
cmd/magneticow/data/static/scripts/naturalSort-v0.8.1.js
Normal file
73
cmd/magneticow/data/static/scripts/naturalSort-v0.8.1.js
Normal 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; }
|
||||||
|
}
|
||||||
|
}
|
@ -11,6 +11,7 @@
|
|||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
var pre_element = document.getElementsByTagName("pre")[0];
|
var pre_element = document.getElementsByTagName("pre")[0];
|
||||||
var paths = pre_element.textContent.replace(/\s+$/, "").split("\n");
|
var paths = pre_element.textContent.replace(/\s+$/, "").split("\n");
|
||||||
|
paths.sort(naturalSort);
|
||||||
paths = paths.map(function(path) { return path.split('/'); });
|
paths = paths.map(function(path) { return path.split('/'); });
|
||||||
pre_element.textContent = stringify(structurise(paths)).join("\n");
|
pre_element.textContent = stringify(structurise(paths)).join("\n");
|
||||||
};
|
};
|
||||||
|
@ -122,7 +122,7 @@ function encodeQueryData(data) {
|
|||||||
// https://stackoverflow.com/q/10420352/4466589
|
// https://stackoverflow.com/q/10420352/4466589
|
||||||
function fileSize(fileSizeInBytes) {
|
function fileSize(fileSizeInBytes) {
|
||||||
let i = -1;
|
let i = -1;
|
||||||
let byteUnits = [' kB', ' MB', ' GB', ' TB', ' PB', ' EB', ' ZB', ' YB'];
|
let byteUnits = [' KiB', ' MiB', ' GiB', ' TiB', ' PiB', ' EiB', ' ZiB', ' YiB'];
|
||||||
do {
|
do {
|
||||||
fileSizeInBytes = fileSizeInBytes / 1024;
|
fileSizeInBytes = fileSizeInBytes / 1024;
|
||||||
i++;
|
i++;
|
||||||
|
@ -2,11 +2,12 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<title>{{ torrent.name }} - magnetico</title>
|
<title>{{ .T.Name }} - magnetico</title>
|
||||||
<link rel="stylesheet" href="static/styles/reset.css">
|
<link rel="stylesheet" href="/static/styles/reset.css">
|
||||||
<link rel="stylesheet" href="static/styles/essential.css">
|
<link rel="stylesheet" href="/static/styles/essential.css">
|
||||||
<link rel="stylesheet" href="static/styles/torrent.css">
|
<link rel="stylesheet" href="/static/styles/torrent.css">
|
||||||
<script defer src="static/scripts/torrent.js"></script>
|
<script defer src="/static/scripts/naturalSort-v0.8.1.js"></script>
|
||||||
|
<script defer src="/static/scripts/torrent.js"></script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
@ -17,39 +18,32 @@
|
|||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<div id="title">
|
<div id="title">
|
||||||
<h2>{{ torrent.name }}</h2>
|
<h2>{{ .T.Name }}</h2>
|
||||||
<a href="magnet:?xt=urn:btih:{{ torrent.info_hash }}&dn={{ torrent.name }}">
|
<a href="magnet:?xt=urn:btih:{{ bytesToHex .T.InfoHash }}&dn={{ .T.Name }}">
|
||||||
<img src="static/assets/magnet.gif" alt="Magnet link"
|
<img src="/static/assets/magnet.gif" alt="Magnet link"
|
||||||
title="Download this torrent using magnet" />
|
title="Download this torrent using magnet" />
|
||||||
<small>{{ torrent.info_hash }}</small>
|
<small>{{ bytesToHex .T.InfoHash }}</small>
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<table>
|
<table>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Size</th>
|
<th scope="row">Size</th>
|
||||||
<td>{{ torrent.size }}</td>
|
<td>{{ humanizeSize .T.Size }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Discovered on</th>
|
<th scope="row">Discovered on</th>
|
||||||
<td>{{ torrent.discovered_on }}</td>
|
<td>{{ unixTimeToYearMonthDay .T.DiscoveredOn }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Files</th>
|
<th scope="row">Files</th>
|
||||||
<td>{{ torrent.files|length }}</td>
|
<td>{{ .T.NFiles }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
</table>
|
</table>
|
||||||
|
|
||||||
<h3>Contents</h3>
|
<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 -->
|
<!-- 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>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -16,7 +16,7 @@
|
|||||||
<td><a href="magnet:?xt=urn:btih:{{infoHash}}&dn={{name}}">
|
<td><a href="magnet:?xt=urn:btih:{{infoHash}}&dn={{name}}">
|
||||||
<img src="static/assets/magnet.gif" alt="Magnet link"
|
<img src="static/assets/magnet.gif" alt="Magnet link"
|
||||||
title="Download this torrent using magnet" /></a></td>
|
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>{{size}}</td>
|
||||||
<td>{{discoveredOn}}</td>
|
<td>{{discoveredOn}}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
@ -126,6 +126,13 @@ func main() {
|
|||||||
return humanize.IBytes(s)
|
return humanize.IBytes(s)
|
||||||
},
|
},
|
||||||
|
|
||||||
|
"humanizeSizeF": func(s int64) string {
|
||||||
|
if s < 0 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return humanize.IBytes(uint64(s))
|
||||||
|
},
|
||||||
|
|
||||||
"comma": func(s uint) string {
|
"comma": func(s uint) string {
|
||||||
return humanize.Comma(int64(s))
|
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["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["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["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"))))
|
// templates["torrents"] = template.Must(template.New("torrents").Funcs(templateFunctions).Parse(string(mustAsset("templates/torrents.html"))))
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
@ -182,6 +189,7 @@ func torrentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
w.Write(data)
|
w.Write(data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we might as well move torrent.html into static...
|
||||||
func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
// show torrents/{infohash}
|
// show torrents/{infohash}
|
||||||
infoHash, err := hex.DecodeString(mux.Vars(r)["infohash"])
|
infoHash, err := hex.DecodeString(mux.Vars(r)["infohash"])
|
||||||
@ -193,8 +201,32 @@ func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err.Error())
|
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) {
|
func statisticsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
|
@ -330,7 +330,9 @@ func (db *sqlite3Database) GetTorrent(infoHash []byte) (*TorrentMetadata, error)
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (db *sqlite3Database) GetFiles(infoHash []byte) ([]File, 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user