diff --git a/cmd/magneticow/api.go b/cmd/magneticow/api.go index 69fd709..fb96634 100644 --- a/cmd/magneticow/api.go +++ b/cmd/magneticow/api.go @@ -13,7 +13,7 @@ import ( "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 // at all; and if that is NOT the case, then return an error. 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"` LastOrderedValue *float64 `schema:"lastOrderedValue"` LastID *uint64 `schema:"lastID"` + Limit *uint `schema:"limit"` } if err := decoder.Decode(&tq, r.URL.Query()); err != nil { 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( *tq.Query, *tq.Epoch, orderBy, - *tq.Ascending, N_TORRENTS, tq.LastOrderedValue, tq.LastID) + *tq.Ascending, *tq.Limit, tq.LastOrderedValue, tq.LastID) if err != nil { respondError(w, 400, "query error: %s", err.Error()) return } - // TODO: use plain Marshal - jm, err := json.MarshalIndent(torrents, "", " ") - if err != nil { - 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)) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if err = json.NewEncoder(w).Encode(torrents); err != nil { + zap.L().Warn("JSON encode error", zap.Error(err)) } } -func apiTorrentsInfohashHandler(w http.ResponseWriter, r *http.Request) { +func apiTorrent(w http.ResponseWriter, r *http.Request) { infohashHex := mux.Vars(r)["infohash"] infohash, err := hex.DecodeString(infohashHex) @@ -107,19 +107,13 @@ func apiTorrentsInfohashHandler(w http.ResponseWriter, r *http.Request) { return } - // TODO: use plain Marshal - jm, err := json.MarshalIndent(torrent, "", " ") - if err != nil { - 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)) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if err = json.NewEncoder(w).Encode(torrent); err != nil { + zap.L().Warn("JSON encode error", zap.Error(err)) } } -func apiFilesInfohashHandler(w http.ResponseWriter, r *http.Request) { +func apiFilelist(w http.ResponseWriter, r *http.Request) { infohashHex := mux.Vars(r)["infohash"] infohash, err := hex.DecodeString(infohashHex) @@ -137,19 +131,13 @@ func apiFilesInfohashHandler(w http.ResponseWriter, r *http.Request) { return } - // TODO: use plain Marshal - jm, err := json.MarshalIndent(files, "", " ") - if err != nil { - 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)) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if err = json.NewEncoder(w).Encode(files); err != nil { + zap.L().Warn("JSON encode error", 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") // TODO: use gorilla? @@ -175,15 +163,9 @@ func apiStatisticsHandler(w http.ResponseWriter, r *http.Request) { return } - // TODO: use plain Marshal - jm, err := json.MarshalIndent(stats, "", " ") - if err != nil { - 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)) + w.Header().Set("Content-Type", "application/json; charset=utf-8") + if err = json.NewEncoder(w).Encode(stats); err != nil { + zap.L().Warn("JSON encode error", zap.Error(err)) } } diff --git a/cmd/magneticow/data/static/scripts/common.js b/cmd/magneticow/data/static/scripts/common.js index f935705..7c7a0bf 100644 --- a/cmd/magneticow/data/static/scripts/common.js +++ b/cmd/magneticow/data/static/scripts/common.js @@ -24,6 +24,14 @@ function fileSize(fileSizeInBytes) { 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. * diff --git a/cmd/magneticow/data/static/scripts/torrent.js b/cmd/magneticow/data/static/scripts/torrent.js index 1c9cbc9..4be0c8d 100644 --- a/cmd/magneticow/data/static/scripts/torrent.js +++ b/cmd/magneticow/data/static/scripts/torrent.js @@ -9,52 +9,37 @@ 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"); -}; + let infoHash = window.location.pathname.split("/")[2]; + fetch("/api/v0.1/torrents/" + infoHash).then(x => x.json()).then(x => { + document.querySelector("title").innerText = x.name + " - magneticow"; -function structurise(paths) { - var items = []; - for(var i = 0, l = paths.length; i < l; i++) { - var path = paths[i]; - var name = path[0]; - var rest = path.slice(1); - var item = null; - for(var j = 0, m = items.length; j < m; j++) { - if(items[j].name === name) { - item = items[j]; - break; + const template = document.getElementById("main-template").innerHTML; + document.querySelector("main").innerHTML = Mustache.render(template, { + name: x.name, + infoHash: x.infoHash, + sizeHumanised: fileSize(x.size), + discoveredOnHumanised: humaniseDate(x.discoveredOn), + nFiles: x.nFiles, + }); + + fetch("/api/v0.1/torrents/" + infoHash + "/filelist").then(x => x.json()).then(x => { + 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 ? " " + fileSize(e.size) + "" : ""), + 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; -} + }); + }); +}; diff --git a/cmd/magneticow/data/static/scripts/torrents.js b/cmd/magneticow/data/static/scripts/torrents.js index 8ab5589..44f0bc8 100644 --- a/cmd/magneticow/data/static/scripts/torrents.js +++ b/cmd/magneticow/data/static/scripts/torrents.js @@ -104,11 +104,7 @@ function load() { for (let t of torrents) { t.size = fileSize(t.size); - t.discoveredOn = (new Date(t.discoveredOn * 1000)).toLocaleDateString("en-GB", { - day: "2-digit", - month: "2-digit", - year: "numeric" - }); + t.discoveredOn = humaniseDate(t.discoveredOn); ul.innerHTML += Mustache.render(template, t); } diff --git a/cmd/magneticow/data/static/scripts/vanillatree-v0.0.3.js b/cmd/magneticow/data/static/scripts/vanillatree-v0.0.3.js new file mode 100644 index 0000000..202ae07 --- /dev/null +++ b/cmd/magneticow/data/static/scripts/vanillatree-v0.0.3.js @@ -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?/' + this.placeholder + '' + } 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 +})); diff --git a/cmd/magneticow/data/static/styles/torrent.css b/cmd/magneticow/data/static/styles/torrent.css index 6527a40..610ac6c 100644 --- a/cmd/magneticow/data/static/styles/torrent.css +++ b/cmd/magneticow/data/static/styles/torrent.css @@ -37,7 +37,8 @@ header > div { } #title h2 { - margin-bottom: 0px; + margin-bottom: 0; + word-break: break-all; } #title { @@ -49,12 +50,6 @@ header > div { color: inherit; } -pre { - background-color: black; - color: white; - overflow: auto; -} - table { max-width: 700px; width: 700px; @@ -77,4 +72,9 @@ th { text-align: left; width: 1%; +} + +tt { + font-style: italic; + font-size: smaller; } \ No newline at end of file diff --git a/cmd/magneticow/data/static/styles/torrents.css b/cmd/magneticow/data/static/styles/torrents.css index 5485068..e0e2c86 100644 --- a/cmd/magneticow/data/static/styles/torrents.css +++ b/cmd/magneticow/data/static/styles/torrents.css @@ -79,6 +79,7 @@ ul li div { ul li div h3 { margin: 0; + word-break: break-all; } a { diff --git a/cmd/magneticow/data/static/styles/vanillatree-v0.0.3.css b/cmd/magneticow/data/static/styles/vanillatree-v0.0.3.css new file mode 100644 index 0000000..683c124 --- /dev/null +++ b/cmd/magneticow/data/static/styles/vanillatree-v0.0.3.css @@ -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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); +} diff --git a/cmd/magneticow/data/templates/torrent.html b/cmd/magneticow/data/templates/torrent.html index e0af377..102a2ee 100644 --- a/cmd/magneticow/data/templates/torrent.html +++ b/cmd/magneticow/data/templates/torrent.html @@ -3,12 +3,48 @@ - {{ .T.Name }} - magnetico + Loading... - magneticow + + - - + + + + + + + + +
@@ -18,33 +54,7 @@
-
-

{{ .T.Name }}

- - Magnet link - {{ bytesToHex .T.InfoHash }} - -
- - - - - - - - - - - - - -
Size{{ humanizeSize .T.Size }}
Discovered on{{ unixTimeToYearMonthDay .T.DiscoveredOn }}
Files{{ .T.NFiles }}
- -

Files

- -
{{ range .F }}{{ .Path }}{{ "\t" }}{{ humanizeSizeF .Size }}{{ "\n" }}{{ end }}
\ No newline at end of file diff --git a/cmd/magneticow/data/templates/torrents.html b/cmd/magneticow/data/templates/torrents.html index 8481de6..c80ed1e 100644 --- a/cmd/magneticow/data/templates/torrents.html +++ b/cmd/magneticow/data/templates/torrents.html @@ -5,13 +5,13 @@ Search - magneticow - - - + + + - - - + + +