[magneticow] fully client-side rendering + better file tree + API fixes
This commit is contained in:
parent
75abc0ee02
commit
2cc4c4930a
@ -13,7 +13,7 @@ import (
|
|||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
func apiTorrentsHandler(w http.ResponseWriter, r *http.Request) {
|
func apiTorrents(w http.ResponseWriter, r *http.Request) {
|
||||||
// @lastOrderedValue AND @lastID are either both supplied or neither of them should be supplied
|
// @lastOrderedValue AND @lastID are either both supplied or neither of them should be supplied
|
||||||
// at all; and if that is NOT the case, then return an error.
|
// at all; and if that is NOT the case, then return an error.
|
||||||
if q := r.URL.Query(); !((q.Get("lastOrderedValue") != "" && q.Get("lastID") != "") ||
|
if q := r.URL.Query(); !((q.Get("lastOrderedValue") != "" && q.Get("lastID") != "") ||
|
||||||
@ -29,6 +29,7 @@ func apiTorrentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
Ascending *bool `schema:"ascending"`
|
Ascending *bool `schema:"ascending"`
|
||||||
LastOrderedValue *float64 `schema:"lastOrderedValue"`
|
LastOrderedValue *float64 `schema:"lastOrderedValue"`
|
||||||
LastID *uint64 `schema:"lastID"`
|
LastID *uint64 `schema:"lastID"`
|
||||||
|
Limit *uint `schema:"limit"`
|
||||||
}
|
}
|
||||||
if err := decoder.Decode(&tq, r.URL.Query()); err != nil {
|
if err := decoder.Decode(&tq, r.URL.Query()); err != nil {
|
||||||
respondError(w, 400, "error while parsing the URL: %s", err.Error())
|
respondError(w, 400, "error while parsing the URL: %s", err.Error())
|
||||||
@ -69,27 +70,26 @@ func apiTorrentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tq.Limit == nil {
|
||||||
|
tq.Limit = new(uint)
|
||||||
|
*tq.Limit = 20
|
||||||
|
}
|
||||||
|
|
||||||
torrents, err := database.QueryTorrents(
|
torrents, err := database.QueryTorrents(
|
||||||
*tq.Query, *tq.Epoch, orderBy,
|
*tq.Query, *tq.Epoch, orderBy,
|
||||||
*tq.Ascending, N_TORRENTS, tq.LastOrderedValue, tq.LastID)
|
*tq.Ascending, *tq.Limit, tq.LastOrderedValue, tq.LastID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
respondError(w, 400, "query error: %s", err.Error())
|
respondError(w, 400, "query error: %s", err.Error())
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use plain Marshal
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
jm, err := json.MarshalIndent(torrents, "", " ")
|
if err = json.NewEncoder(w).Encode(torrents); err != nil {
|
||||||
if err != nil {
|
zap.L().Warn("JSON encode error", zap.Error(err))
|
||||||
respondError(w, 500, "json marshalling error: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = w.Write(jm); err != nil {
|
|
||||||
zap.L().Warn("couldn't write http.ResponseWriter", zap.Error(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiTorrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
func apiTorrent(w http.ResponseWriter, r *http.Request) {
|
||||||
infohashHex := mux.Vars(r)["infohash"]
|
infohashHex := mux.Vars(r)["infohash"]
|
||||||
|
|
||||||
infohash, err := hex.DecodeString(infohashHex)
|
infohash, err := hex.DecodeString(infohashHex)
|
||||||
@ -107,19 +107,13 @@ func apiTorrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use plain Marshal
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
jm, err := json.MarshalIndent(torrent, "", " ")
|
if err = json.NewEncoder(w).Encode(torrent); err != nil {
|
||||||
if err != nil {
|
zap.L().Warn("JSON encode error", zap.Error(err))
|
||||||
respondError(w, 500, "json marshalling error: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = w.Write(jm); err != nil {
|
|
||||||
zap.L().Warn("couldn't write http.ResponseWriter", zap.Error(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiFilesInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
func apiFilelist(w http.ResponseWriter, r *http.Request) {
|
||||||
infohashHex := mux.Vars(r)["infohash"]
|
infohashHex := mux.Vars(r)["infohash"]
|
||||||
|
|
||||||
infohash, err := hex.DecodeString(infohashHex)
|
infohash, err := hex.DecodeString(infohashHex)
|
||||||
@ -137,19 +131,13 @@ func apiFilesInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use plain Marshal
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
jm, err := json.MarshalIndent(files, "", " ")
|
if err = json.NewEncoder(w).Encode(files); err != nil {
|
||||||
if err != nil {
|
zap.L().Warn("JSON encode error", zap.Error(err))
|
||||||
respondError(w, 500, "json marshalling error: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = w.Write(jm); err != nil {
|
|
||||||
zap.L().Warn("couldn't write http.ResponseWriter", zap.Error(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func apiStatisticsHandler(w http.ResponseWriter, r *http.Request) {
|
func apiStatistics(w http.ResponseWriter, r *http.Request) {
|
||||||
from := r.URL.Query().Get("from")
|
from := r.URL.Query().Get("from")
|
||||||
|
|
||||||
// TODO: use gorilla?
|
// TODO: use gorilla?
|
||||||
@ -175,15 +163,9 @@ func apiStatisticsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use plain Marshal
|
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||||
jm, err := json.MarshalIndent(stats, "", " ")
|
if err = json.NewEncoder(w).Encode(stats); err != nil {
|
||||||
if err != nil {
|
zap.L().Warn("JSON encode error", zap.Error(err))
|
||||||
respondError(w, 500, "json marshalling error: %s", err.Error())
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
if _, err = w.Write(jm); err != nil {
|
|
||||||
zap.L().Warn("couldn't write http.ResponseWriter", zap.Error(err))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,6 +24,14 @@ function fileSize(fileSizeInBytes) {
|
|||||||
return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
|
return Math.max(fileSizeInBytes, 0.1).toFixed(1) + byteUnits[i];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function humaniseDate(unixTime) {
|
||||||
|
return (new Date(unixTime * 1000)).toLocaleDateString("en-GB", {
|
||||||
|
day: "2-digit",
|
||||||
|
month: "2-digit",
|
||||||
|
year: "numeric"
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the ISO 8601 week number for this date.
|
* Returns the ISO 8601 week number for this date.
|
||||||
*
|
*
|
||||||
|
@ -9,52 +9,37 @@
|
|||||||
|
|
||||||
|
|
||||||
window.onload = function() {
|
window.onload = function() {
|
||||||
var pre_element = document.getElementsByTagName("pre")[0];
|
let infoHash = window.location.pathname.split("/")[2];
|
||||||
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");
|
|
||||||
};
|
|
||||||
|
|
||||||
|
fetch("/api/v0.1/torrents/" + infoHash).then(x => x.json()).then(x => {
|
||||||
|
document.querySelector("title").innerText = x.name + " - magneticow";
|
||||||
|
|
||||||
function structurise(paths) {
|
const template = document.getElementById("main-template").innerHTML;
|
||||||
var items = [];
|
document.querySelector("main").innerHTML = Mustache.render(template, {
|
||||||
for(var i = 0, l = paths.length; i < l; i++) {
|
name: x.name,
|
||||||
var path = paths[i];
|
infoHash: x.infoHash,
|
||||||
var name = path[0];
|
sizeHumanised: fileSize(x.size),
|
||||||
var rest = path.slice(1);
|
discoveredOnHumanised: humaniseDate(x.discoveredOn),
|
||||||
var item = null;
|
nFiles: x.nFiles,
|
||||||
for(var j = 0, m = items.length; j < m; j++) {
|
});
|
||||||
if(items[j].name === name) {
|
|
||||||
item = items[j];
|
fetch("/api/v0.1/torrents/" + infoHash + "/filelist").then(x => x.json()).then(x => {
|
||||||
break;
|
const tree = new VanillaTree('#fileTree', {
|
||||||
|
placeholder: 'Loading...',
|
||||||
|
});
|
||||||
|
|
||||||
|
for (let e of x) {
|
||||||
|
let pathElems = e.path.split("/");
|
||||||
|
|
||||||
|
for (let i = 0; i < pathElems.length; i++) {
|
||||||
|
tree.add({
|
||||||
|
id: pathElems.slice(0, i + 1).join("/"),
|
||||||
|
parent: i >= 1 ? pathElems.slice(0, i).join("/") : undefined,
|
||||||
|
label: pathElems[i] + ( i === pathElems.length - 1 ? " <tt>" + fileSize(e.size) + "</tt>" : ""),
|
||||||
|
opened: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
if(item === null) {
|
});
|
||||||
item = {name: name, children: []};
|
};
|
||||||
items.push(item);
|
|
||||||
}
|
|
||||||
if(rest.length > 0) {
|
|
||||||
item.children.push(rest);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for(i = 0, l = items.length; i < l; i++) {
|
|
||||||
item = items[i];
|
|
||||||
item.children = structurise(item.children);
|
|
||||||
}
|
|
||||||
return items;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
function stringify(items) {
|
|
||||||
var lines = [];
|
|
||||||
for(var i = 0, l = items.length; i < l; i++) {
|
|
||||||
var item = items[i];
|
|
||||||
lines.push(item.name);
|
|
||||||
var subLines = stringify(item.children);
|
|
||||||
for(var j = 0, m = subLines.length; j < m; j++) {
|
|
||||||
lines.push(" " + subLines[j]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return lines;
|
|
||||||
}
|
|
||||||
|
@ -104,11 +104,7 @@ function load() {
|
|||||||
|
|
||||||
for (let t of torrents) {
|
for (let t of torrents) {
|
||||||
t.size = fileSize(t.size);
|
t.size = fileSize(t.size);
|
||||||
t.discoveredOn = (new Date(t.discoveredOn * 1000)).toLocaleDateString("en-GB", {
|
t.discoveredOn = humaniseDate(t.discoveredOn);
|
||||||
day: "2-digit",
|
|
||||||
month: "2-digit",
|
|
||||||
year: "numeric"
|
|
||||||
});
|
|
||||||
|
|
||||||
ul.innerHTML += Mustache.render(template, t);
|
ul.innerHTML += Mustache.render(template, t);
|
||||||
}
|
}
|
||||||
|
214
cmd/magneticow/data/static/scripts/vanillatree-v0.0.3.js
Normal file
214
cmd/magneticow/data/static/scripts/vanillatree-v0.0.3.js
Normal file
@ -0,0 +1,214 @@
|
|||||||
|
(function (root, factory) {
|
||||||
|
if (typeof define == 'function' && define.amd) {
|
||||||
|
define( factory );
|
||||||
|
} else if (typeof module === 'object' && module.exports) {
|
||||||
|
module.exports = factory();
|
||||||
|
} else {
|
||||||
|
root.VanillaTree = factory();
|
||||||
|
}
|
||||||
|
}(this, function () {
|
||||||
|
"use strict";
|
||||||
|
// Look at the Balalaika https://github.com/finom/balalaika
|
||||||
|
var $=function(n,e,k,h,p,m,l,b,d,g,f,c){c=function(a,b){return new c.i(a,b)};c.i=function(a,d){k.push.apply(this,a?a.nodeType||a==n?[a]:""+a===a?/</.test(a)?((b=e.createElement(d||"q")).innerHTML=a,b.children):(d&&c(d)[0]||e).querySelectorAll(a):/f/.test(typeof a)?/c/.test(e.readyState)?a():c(e).on("DOMContentLoaded",a):a:k)};c.i[f="prototype"]=(c.extend=function(a){g=arguments;for(b=1;b<g.length;b++)if(f=g[b])for(d in f)a[d]=f[d];return a})(c.fn=c[f]=k,{on:function(a,d){a=a.split(h);this.map(function(c){(h[b=a[0]+(c.b$=c.b$||++p)]=h[b]||[]).push([d,a[1]]);c["add"+m](a[0],d)});return this},off:function(a,c){a=a.split(h);f="remove"+m;this.map(function(e){if(b=(g=h[a[0]+e.b$])&&g.length)for(;d=g[--b];)c&&c!=d[0]||a[1]&&a[1]!=d[1]||(e[f](a[0],d[0]),g.splice(b,1));else!a[1]&&e[f](a[0],c)});return this},is:function(a){d=(b=this[0])&&(b.matches||b["webkit"+l]||b["moz"+l]||b["ms"+l]);return!!d&&d.call(b,a)}});return c}(window,document,[],/\.(.+)/,0,"EventListener","MatchesSelector");
|
||||||
|
|
||||||
|
var create = function( tagName, props ) {
|
||||||
|
return $.extend( document.createElement( tagName ), props );
|
||||||
|
},
|
||||||
|
Tree = function( s, options ) {
|
||||||
|
var _this = this,
|
||||||
|
container = _this.container = $( s )[ 0 ],
|
||||||
|
tree = _this.tree = container.appendChild( create( 'ul', {
|
||||||
|
className: 'vtree'
|
||||||
|
}) );
|
||||||
|
|
||||||
|
_this.placeholder = options && options.placeholder;
|
||||||
|
_this._placeholder();
|
||||||
|
_this.leafs = {};
|
||||||
|
tree.addEventListener( 'click', function( evt ) {
|
||||||
|
if( $( evt.target ).is( '.vtree-leaf-label' ) ) {
|
||||||
|
_this.select( evt.target.parentNode.getAttribute('data-vtree-id') );
|
||||||
|
} else if( $( evt.target ).is( '.vtree-toggle' ) ) {
|
||||||
|
_this.toggle( evt.target.parentNode.getAttribute('data-vtree-id') );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
if( options && options.contextmenu ) {
|
||||||
|
tree.addEventListener( 'contextmenu', function( evt ) {
|
||||||
|
var menu;
|
||||||
|
$( '.vtree-contextmenu' ).forEach( function( menu ) {
|
||||||
|
menu.parentNode.removeChild( menu );
|
||||||
|
});
|
||||||
|
if( $( evt.target ).is( '.vtree-leaf-label' ) ) {
|
||||||
|
evt.preventDefault();
|
||||||
|
evt.stopPropagation();
|
||||||
|
menu = create( 'menu', {
|
||||||
|
className: 'vtree-contextmenu'
|
||||||
|
});
|
||||||
|
|
||||||
|
var rect = evt.target.getBoundingClientRect();
|
||||||
|
$.extend(menu.style, {
|
||||||
|
top: (evt.target.offsetTop + rect.height).toString() + "px",
|
||||||
|
left: evt.target.offsetLeft.toString() + "px",
|
||||||
|
display: 'block'
|
||||||
|
});
|
||||||
|
|
||||||
|
options.contextmenu.forEach( function( item ) {
|
||||||
|
menu.appendChild( create( 'li', {
|
||||||
|
className: 'vtree-contextmenu-item',
|
||||||
|
innerHTML: item.label
|
||||||
|
}) ).addEventListener( 'click', item.action.bind( item, evt.target.parentNode.getAttribute('data-vtree-id') ) );
|
||||||
|
});
|
||||||
|
|
||||||
|
evt.target.parentNode.appendChild( menu );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener( 'click', function( evt ) {
|
||||||
|
if(evt.button === 2) return;
|
||||||
|
$( '.vtree-contextmenu' ).forEach( function( menu ) {
|
||||||
|
menu.parentNode.removeChild( menu );
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Tree.prototype = {
|
||||||
|
constructor: Tree,
|
||||||
|
_dispatch: function( name, id ) {
|
||||||
|
var event;
|
||||||
|
try {
|
||||||
|
event = new CustomEvent( 'vtree-' + name, {
|
||||||
|
bubbles: true,
|
||||||
|
cancelable: true,
|
||||||
|
detail: {
|
||||||
|
id: id
|
||||||
|
}
|
||||||
|
});
|
||||||
|
} catch(e) {
|
||||||
|
event = document.createEvent( 'CustomEvent' );
|
||||||
|
event.initCustomEvent( 'vtree-' + name, true, true, { id: id });
|
||||||
|
}
|
||||||
|
( this.getLeaf( id, true ) || this.tree )
|
||||||
|
.dispatchEvent( event );
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
_placeholder: function() {
|
||||||
|
var p;
|
||||||
|
if( !this.tree.children.length && this.placeholder ) {
|
||||||
|
this.tree.innerHTML = '<li class="vtree-placeholder">' + this.placeholder + '</li>'
|
||||||
|
} else if( p = this.tree.querySelector( '.vtree-placeholder' ) ) {
|
||||||
|
this.tree.removeChild( p );
|
||||||
|
}
|
||||||
|
return this;
|
||||||
|
},
|
||||||
|
getLeaf: function( id, notThrow ) {
|
||||||
|
var leaf = $( '[data-vtree-id="' + id + '"]', this.tree )[ 0 ];
|
||||||
|
if( !notThrow && !leaf ) throw Error( 'No VanillaTree leaf with id "' + id + '"' )
|
||||||
|
return leaf;
|
||||||
|
},
|
||||||
|
getChildList: function( id ) {
|
||||||
|
var list,
|
||||||
|
parent;
|
||||||
|
if( id ) {
|
||||||
|
parent = this.getLeaf( id );
|
||||||
|
if( !( list = $( 'ul', parent )[ 0 ] ) ) {
|
||||||
|
list = parent.appendChild( create( 'ul', {
|
||||||
|
className: 'vtree-subtree'
|
||||||
|
}) );
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
list = this.tree;
|
||||||
|
}
|
||||||
|
|
||||||
|
return list;
|
||||||
|
},
|
||||||
|
add: function( options ) {
|
||||||
|
// see https://github.com/finom/vanillatree/issues/8
|
||||||
|
if(this.getLeaf( options.id,true )){return;}// don't add leaves that already exist
|
||||||
|
var id,
|
||||||
|
leaf = create( 'li', {
|
||||||
|
className: 'vtree-leaf'
|
||||||
|
}),
|
||||||
|
parentList = this.getChildList( options.parent );
|
||||||
|
|
||||||
|
leaf.setAttribute( 'data-vtree-id', id = options.id || Math.random() );
|
||||||
|
|
||||||
|
leaf.appendChild( create( 'span', {
|
||||||
|
className: 'vtree-toggle'
|
||||||
|
}) );
|
||||||
|
|
||||||
|
leaf.appendChild( create( 'a', {
|
||||||
|
className: 'vtree-leaf-label',
|
||||||
|
innerHTML: options.label
|
||||||
|
}) );
|
||||||
|
|
||||||
|
parentList.appendChild( leaf );
|
||||||
|
|
||||||
|
if( parentList !== this.tree ) {
|
||||||
|
parentList.parentNode.classList.add( 'vtree-has-children' );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.leafs[ id ] = options;
|
||||||
|
|
||||||
|
if( !options.opened ) {
|
||||||
|
this.close( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
if( options.selected ) {
|
||||||
|
this.select( id );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this._placeholder()._dispatch( 'add', id );
|
||||||
|
},
|
||||||
|
move: function( id, parentId ) {
|
||||||
|
var leaf = this.getLeaf( id ),
|
||||||
|
oldParent = leaf.parentNode,
|
||||||
|
newParent = this.getLeaf( parentId, true );
|
||||||
|
|
||||||
|
if( newParent ) {
|
||||||
|
newParent.classList.add( 'vtree-has-children' );
|
||||||
|
}
|
||||||
|
|
||||||
|
this.getChildList( parentId ).appendChild( leaf );
|
||||||
|
oldParent.parentNode.classList.toggle( 'vtree-has-children', !!oldParent.children.length );
|
||||||
|
|
||||||
|
return this._dispatch( 'move', id );
|
||||||
|
},
|
||||||
|
remove: function( id ) {
|
||||||
|
var leaf = this.getLeaf( id ),
|
||||||
|
oldParent = leaf.parentNode;
|
||||||
|
oldParent.removeChild( leaf );
|
||||||
|
oldParent.parentNode.classList.toggle( 'vtree-has-children', !!oldParent.children.length );
|
||||||
|
|
||||||
|
return this._placeholder()._dispatch( 'remove', id );
|
||||||
|
},
|
||||||
|
open: function( id ) {
|
||||||
|
this.getLeaf( id ).classList.remove( 'closed' );
|
||||||
|
return this._dispatch( 'open', id );
|
||||||
|
},
|
||||||
|
close: function( id ) {
|
||||||
|
this.getLeaf( id ).classList.add( 'closed' );
|
||||||
|
return this._dispatch( 'close', id );
|
||||||
|
},
|
||||||
|
toggle: function( id ) {
|
||||||
|
return this[ this.getLeaf( id ).classList.contains( 'closed' ) ? 'open' : 'close' ]( id );
|
||||||
|
},
|
||||||
|
select: function( id ) {
|
||||||
|
var leaf = this.getLeaf( id );
|
||||||
|
|
||||||
|
if( !leaf.classList.contains( 'vtree-selected' ) ) {
|
||||||
|
$( 'li.vtree-leaf', this.tree ).forEach( function( leaf ) {
|
||||||
|
leaf.classList.remove( 'vtree-selected' );
|
||||||
|
});
|
||||||
|
|
||||||
|
leaf.classList.add( 'vtree-selected' );
|
||||||
|
this._dispatch( 'select', id );
|
||||||
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
return Tree;
|
||||||
|
// Look at the Balalaika https://github.com/finom/balalaika
|
||||||
|
}));
|
@ -37,7 +37,8 @@ header > div {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#title h2 {
|
#title h2 {
|
||||||
margin-bottom: 0px;
|
margin-bottom: 0;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
#title {
|
#title {
|
||||||
@ -49,12 +50,6 @@ header > div {
|
|||||||
color: inherit;
|
color: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
pre {
|
|
||||||
background-color: black;
|
|
||||||
color: white;
|
|
||||||
overflow: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
table {
|
table {
|
||||||
max-width: 700px;
|
max-width: 700px;
|
||||||
width: 700px;
|
width: 700px;
|
||||||
@ -77,4 +72,9 @@ th {
|
|||||||
text-align: left;
|
text-align: left;
|
||||||
|
|
||||||
width: 1%;
|
width: 1%;
|
||||||
|
}
|
||||||
|
|
||||||
|
tt {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: smaller;
|
||||||
}
|
}
|
@ -79,6 +79,7 @@ ul li div {
|
|||||||
|
|
||||||
ul li div h3 {
|
ul li div h3 {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
|
word-break: break-all;
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
96
cmd/magneticow/data/static/styles/vanillatree-v0.0.3.css
Normal file
96
cmd/magneticow/data/static/styles/vanillatree-v0.0.3.css
Normal file
@ -0,0 +1,96 @@
|
|||||||
|
.vtree ul.vtree-subtree, .vtree li.vtree-leaf {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
list-style-type: none;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf {
|
||||||
|
background-position: -90px 0;
|
||||||
|
background-repeat: repeat-y;
|
||||||
|
min-height: 18px;
|
||||||
|
line-height: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf::before {
|
||||||
|
content: '';
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
position: absolute;
|
||||||
|
background-position: -36px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf li.vtree-leaf {
|
||||||
|
margin-left: 18px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf:last-child {
|
||||||
|
background-image: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf.closed ul.vtree-subtree {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf.vtree-has-children > span.vtree-toggle {
|
||||||
|
display: block;
|
||||||
|
width: 18px;
|
||||||
|
height: 18px;
|
||||||
|
background-position: -72px 0;
|
||||||
|
position: absolute;
|
||||||
|
left: 0;
|
||||||
|
top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf.vtree-has-children.closed > span.vtree-toggle {
|
||||||
|
background-position: -54px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree a.vtree-leaf-label {
|
||||||
|
line-height: 18px;
|
||||||
|
display: inline-block;
|
||||||
|
vertical-align: top;
|
||||||
|
cursor: pointer;
|
||||||
|
max-width: 100%;
|
||||||
|
margin-left: 18px;
|
||||||
|
padding: 0 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf a.vtree-leaf-label:hover {
|
||||||
|
background-color: #e7f4f9;
|
||||||
|
outline: 1px solid #d8f0fa;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf.vtree-selected > a.vtree-leaf-label {
|
||||||
|
background-color: #beebff;
|
||||||
|
outline: 1px solid #99defd;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree-contextmenu {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 9999999;
|
||||||
|
border: solid 1px #ccc;
|
||||||
|
background: #eee;
|
||||||
|
padding: 0px;
|
||||||
|
margin: 0px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree-contextmenu li {
|
||||||
|
list-style: none;
|
||||||
|
padding: 1px 5px;
|
||||||
|
margin: 0px;
|
||||||
|
color: #333;
|
||||||
|
line-height: 20px;
|
||||||
|
height: 20px;
|
||||||
|
cursor: default;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree-contextmenu li:hover {
|
||||||
|
color: #fff;
|
||||||
|
background-color: #3399ff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.vtree li.vtree-leaf, .vtree li.vtree-leaf::before, .vtree li.vtree-leaf.vtree-has-children > span.vtree-toggle {
|
||||||
|
background-image: url(data:image/png;base64,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);
|
||||||
|
}
|
@ -3,12 +3,48 @@
|
|||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8">
|
<meta charset="utf-8">
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>{{ .T.Name }} - magnetico</title>
|
<title>Loading... - magneticow</title>
|
||||||
|
|
||||||
<link rel="stylesheet" href="/static/styles/reset.css">
|
<link rel="stylesheet" href="/static/styles/reset.css">
|
||||||
|
<link rel="stylesheet" href="/static/styles/vanillatree-v0.0.3.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/naturalSort-v0.8.1.js"></script>
|
|
||||||
<script defer src="/static/scripts/torrent.js"></script>
|
<script src="/static/scripts/naturalSort-v0.8.1.js"></script>
|
||||||
|
<script src="/static/scripts/mustache-v2.3.0.min.js"></script>
|
||||||
|
<script src="/static/scripts/vanillatree-v0.0.3.js"></script>
|
||||||
|
<script src="/static/scripts/common.js"></script>
|
||||||
|
<script src="/static/scripts/torrent.js"></script>
|
||||||
|
|
||||||
|
<!-- Goes into <main> -->
|
||||||
|
<script id="main-template" type="text/x-handlebars-template">
|
||||||
|
<div id="title">
|
||||||
|
<h2>{{ name }}</h2>
|
||||||
|
<a href="magnet:?xt=urn:btih:{{ infoHash }}&dn={{ name }}">
|
||||||
|
<img src="/static/assets/magnet.gif" alt="Magnet link"
|
||||||
|
title="Download this torrent using magnet" />
|
||||||
|
<small>{{ infoHash }}</small>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Size</th>
|
||||||
|
<td>{{ sizeHumanised }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Discovered on</th>
|
||||||
|
<td>{{ discoveredOnHumanised }}</td>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">Files</th>
|
||||||
|
<td>{{ nFiles }}</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<h3>Better Files</h3>
|
||||||
|
<div id="fileTree"></div>
|
||||||
|
</script>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<header>
|
<header>
|
||||||
@ -18,33 +54,7 @@
|
|||||||
</form>
|
</form>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<div id="title">
|
|
||||||
<h2>{{ .T.Name }}</h2>
|
|
||||||
<a href="magnet:?xt=urn:btih:{{ bytesToHex .T.InfoHash }}&dn={{ .T.Name }}">
|
|
||||||
<img src="/static/assets/magnet.gif" alt="Magnet link"
|
|
||||||
title="Download this torrent using magnet" />
|
|
||||||
<small>{{ bytesToHex .T.InfoHash }}</small>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<table>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Size</th>
|
|
||||||
<td>{{ humanizeSize .T.Size }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Discovered on</th>
|
|
||||||
<td>{{ unixTimeToYearMonthDay .T.DiscoveredOn }}</td>
|
|
||||||
</tr>
|
|
||||||
<tr>
|
|
||||||
<th scope="row">Files</th>
|
|
||||||
<td>{{ .T.NFiles }}</td>
|
|
||||||
</tr>
|
|
||||||
</table>
|
|
||||||
|
|
||||||
<h3>Files</h3>
|
|
||||||
<!-- Content of this element will be overwritten by the script -->
|
|
||||||
<pre>{{ range .F }}{{ .Path }}{{ "\t" }}{{ humanizeSizeF .Size }}{{ "\n" }}{{ end }}</pre>
|
|
||||||
</main>
|
</main>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
@ -5,13 +5,13 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Search - magneticow</title>
|
<title>Search - magneticow</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/torrents.css">
|
<link rel="stylesheet" href="/static/styles/torrents.css">
|
||||||
|
|
||||||
<script src="static/scripts/mustache-v2.3.0.min.js"></script>
|
<script src="/static/scripts/mustache-v2.3.0.min.js"></script>
|
||||||
<script src="static/scripts/common.js"></script>
|
<script src="/static/scripts/common.js"></script>
|
||||||
<script src="static/scripts/torrents.js"></script>
|
<script src="/static/scripts/torrents.js"></script>
|
||||||
|
|
||||||
<script id="item-template" type="text/x-handlebars-template">
|
<script id="item-template" type="text/x-handlebars-template">
|
||||||
<li>
|
<li>
|
||||||
|
@ -1,15 +1,13 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/hex"
|
|
||||||
"fmt"
|
|
||||||
"github.com/pkg/errors"
|
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/pkg/errors"
|
||||||
|
|
||||||
"github.com/boramalper/magnetico/pkg/persistence"
|
"github.com/boramalper/magnetico/pkg/persistence"
|
||||||
"github.com/gorilla/mux"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
// DONE
|
// DONE
|
||||||
@ -36,39 +34,12 @@ func torrentsHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
func torrentsInfohashHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
infoHash, err := hex.DecodeString(mux.Vars(r)["infohash"])
|
data := mustAsset("templates/torrent.html")
|
||||||
if err != nil {
|
w.Header().Set("Content-Type", "text/html; charset=utf-8")
|
||||||
handlerError(errors.Wrap(err, "cannot decode infohash"), w)
|
// Cache static resources for a day
|
||||||
return
|
w.Header().Set("Cache-Control", "max-age=86400")
|
||||||
}
|
_, _ = w.Write(data)
|
||||||
|
return
|
||||||
torrent, err := database.GetTorrent(infoHash)
|
|
||||||
if err != nil {
|
|
||||||
handlerError(errors.Wrap(err, "cannot get torrent"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if torrent == nil {
|
|
||||||
respondError(w, http.StatusNotFound, "torrent not found!")
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
files, err := database.GetFiles(infoHash)
|
|
||||||
if err != nil {
|
|
||||||
handlerError(errors.Wrap(err, "could not get files"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
if files == nil {
|
|
||||||
handlerError(fmt.Errorf("could not get files"), w)
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
_ = templates["torrent"].Execute(w, struct {
|
|
||||||
T *persistence.TorrentMetadata
|
|
||||||
F []persistence.File
|
|
||||||
}{
|
|
||||||
T: torrent,
|
|
||||||
F: files,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func statisticsHandler(w http.ResponseWriter, r *http.Request) {
|
func statisticsHandler(w http.ResponseWriter, r *http.Request) {
|
||||||
@ -102,7 +73,7 @@ func feedHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
time.Now().Unix(),
|
time.Now().Unix(),
|
||||||
persistence.ByDiscoveredOn,
|
persistence.ByDiscoveredOn,
|
||||||
false,
|
false,
|
||||||
N_TORRENTS,
|
20,
|
||||||
nil,
|
nil,
|
||||||
nil,
|
nil,
|
||||||
)
|
)
|
||||||
@ -137,6 +108,8 @@ func staticHandler(w http.ResponseWriter, r *http.Request) {
|
|||||||
var contentType string
|
var contentType string
|
||||||
if strings.HasSuffix(r.URL.Path, ".css") {
|
if strings.HasSuffix(r.URL.Path, ".css") {
|
||||||
contentType = "text/css; charset=utf-8"
|
contentType = "text/css; charset=utf-8"
|
||||||
|
} else if strings.HasSuffix(r.URL.Path, ".js") {
|
||||||
|
contentType = "text/javascript; charset=utf-8"
|
||||||
} else { // fallback option
|
} else { // fallback option
|
||||||
contentType = http.DetectContentType(data)
|
contentType = http.DetectContentType(data)
|
||||||
}
|
}
|
||||||
|
@ -29,8 +29,6 @@ import (
|
|||||||
"github.com/boramalper/magnetico/pkg/persistence"
|
"github.com/boramalper/magnetico/pkg/persistence"
|
||||||
)
|
)
|
||||||
|
|
||||||
const N_TORRENTS = 20
|
|
||||||
|
|
||||||
var compiledOn string
|
var compiledOn string
|
||||||
|
|
||||||
// Set a Decoder instance as a package global, because it caches
|
// Set a Decoder instance as a package global, because it caches
|
||||||
@ -106,14 +104,16 @@ func main() {
|
|||||||
router := mux.NewRouter()
|
router := mux.NewRouter()
|
||||||
router.HandleFunc("/",
|
router.HandleFunc("/",
|
||||||
BasicAuth(rootHandler, "magneticow"))
|
BasicAuth(rootHandler, "magneticow"))
|
||||||
router.HandleFunc("/api/v0.1/files/{infohash:[a-f0-9]{40}}",
|
|
||||||
BasicAuth(apiFilesInfohashHandler, "magneticow"))
|
|
||||||
router.HandleFunc("/api/v0.1/statistics",
|
router.HandleFunc("/api/v0.1/statistics",
|
||||||
BasicAuth(apiStatisticsHandler, "magneticow"))
|
BasicAuth(apiStatistics, "magneticow"))
|
||||||
router.HandleFunc("/api/v0.1/torrents",
|
router.HandleFunc("/api/v0.1/torrents",
|
||||||
BasicAuth(apiTorrentsHandler, "magneticow"))
|
BasicAuth(apiTorrents, "magneticow"))
|
||||||
router.HandleFunc("/api/v0.1/torrents/{infohash:[a-f0-9]{40}}",
|
router.HandleFunc("/api/v0.1/torrents/{infohash:[a-f0-9]{40}}",
|
||||||
BasicAuth(apiTorrentsInfohashHandler, "magneticow"))
|
BasicAuth(apiTorrent, "magneticow"))
|
||||||
|
router.HandleFunc("/api/v0.1/torrents/{infohash:[a-f0-9]{40}}/filelist",
|
||||||
|
BasicAuth(apiFilelist, "magneticow"))
|
||||||
|
|
||||||
router.HandleFunc("/feed",
|
router.HandleFunc("/feed",
|
||||||
BasicAuth(feedHandler, "magneticow"))
|
BasicAuth(feedHandler, "magneticow"))
|
||||||
router.PathPrefix("/static").HandlerFunc(
|
router.PathPrefix("/static").HandlerFunc(
|
||||||
@ -169,7 +169,6 @@ func main() {
|
|||||||
templates = make(map[string]*template.Template)
|
templates = make(map[string]*template.Template)
|
||||||
templates["feed"] = template.Must(template.New("feed").Funcs(templateFunctions).Parse(string(mustAsset("templates/feed.xml"))))
|
templates["feed"] = template.Must(template.New("feed").Funcs(templateFunctions).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["torrent"] = template.Must(template.New("torrent").Funcs(templateFunctions).Parse(string(mustAsset("templates/torrent.html"))))
|
|
||||||
|
|
||||||
var err error
|
var err error
|
||||||
database, err = persistence.MakeDatabase(opts.Database, logger)
|
database, err = persistence.MakeDatabase(opts.Database, logger)
|
||||||
|
Loading…
Reference in New Issue
Block a user