From ad44e58c7a83e5d4914be23d94ed41f2a724f11d Mon Sep 17 00:00:00 2001 From: Ozzieisaacs Date: Sat, 29 Jun 2019 14:23:39 +0200 Subject: [PATCH] Sorting for comics Audiobook support --- cps/logger.py | 2 +- cps/static/css/libs/bar-ui.css | 6 +- cps/static/js/archive/archive.js | 16 +++ cps/static/js/archive/unrar.js | 5 +- cps/static/js/archive/untar.js | 18 ++- cps/static/js/archive/unzip.js | 112 +++++++++++---- cps/static/js/io/bytestream.js | 29 ++++ cps/templates/detail.html | 9 +- cps/templates/listenmp3.html | 234 ++++++++++++++++++++++--------- 9 files changed, 317 insertions(+), 114 deletions(-) diff --git a/cps/logger.py b/cps/logger.py index 6b13f50d..6baefa14 100644 --- a/cps/logger.py +++ b/cps/logger.py @@ -107,7 +107,7 @@ def setup(log_file, log_level=None): return r.debug("logging to %s level %s", log_file, r.level) - if log_file == LOG_TO_STDERR: + if 1 == 1: # log_file == LOG_TO_STDERR: file_handler = StreamHandler() file_handler.baseFilename = LOG_TO_STDERR else: diff --git a/cps/static/css/libs/bar-ui.css b/cps/static/css/libs/bar-ui.css index 34e39649..e2e9f44a 100644 --- a/cps/static/css/libs/bar-ui.css +++ b/cps/static/css/libs/bar-ui.css @@ -135,7 +135,7 @@ width: 100%; height: 100%; /* for example */ - /* background-image: url(../images/wood_pattern_dark.png); */ + /* background-image: url(../image/wood_pattern_dark.png); */ /* additional opacity effects can be applied here. */ opacity: 0.75; @@ -143,7 +143,7 @@ .sm2-bar-ui.textured.dark-text .sm2-inline-texture { /* dark text + textured case: use light wood background (for example.) */ - /* background-image: url(../images/patterns/wood_pattern.png); */ + /* background-image: url(../image/patterns/wood_pattern.png); */ } .sm2-bar-ui.textured.dark-text .sm2-playlist-wrapper { @@ -704,7 +704,7 @@ height: 100%; top: 0px; left: 0px; - background: none, url(../images/icomoon/free-25px-000000/SVG/spinner.svg); + background: none, url(../image/icomoon/free-25px-000000/SVG/spinner.svg); background-size: 72%; background-position: 50%; background-repeat: no-repeat; diff --git a/cps/static/js/archive/archive.js b/cps/static/js/archive/archive.js index 331997d9..b7c38cb0 100644 --- a/cps/static/js/archive/archive.js +++ b/cps/static/js/archive/archive.js @@ -13,6 +13,22 @@ var bitjs = bitjs || {}; bitjs.archive = bitjs.archive || {}; +function naturalCompare(a, b) { + var ax = [], bx = []; + + a.filename.toLowerCase().replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); + b.filename.toLowerCase().replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); + + while(ax.length && bx.length) { + var an = ax.shift(); + var bn = bx.shift(); + var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]); + if(nn) return nn; + } + + return ax.length - bx.length; +} + (function() { // =========================================================================== diff --git a/cps/static/js/archive/unrar.js b/cps/static/js/archive/unrar.js index 89263b83..4c97b4dc 100644 --- a/cps/static/js/archive/unrar.js +++ b/cps/static/js/archive/unrar.js @@ -1333,11 +1333,12 @@ var unrar = function(arrayBuffer) { // now we have all information but things are unpacked // TODO: unpack - localFiles = localFiles.sort(function(a, b) { + localFiles.sort(naturalCompare); + /*localFiles = localFiles.sort(function(a, b) { var aname = a.filename.toLowerCase(); var bname = b.filename.toLowerCase(); return aname > bname ? 1 : -1; - }); + });*/ info(localFiles.map(function(a) { return a.filename; diff --git a/cps/static/js/archive/untar.js b/cps/static/js/archive/untar.js index d9a1fdfd..e3a2c079 100644 --- a/cps/static/js/archive/untar.js +++ b/cps/static/js/archive/untar.js @@ -115,6 +115,7 @@ var TarLocalFile = function(bstream) { } }; + var untar = function(arrayBuffer) { postMessage(new bitjs.archive.UnarchiveStartEvent()); currentFilename = ""; @@ -127,14 +128,21 @@ var untar = function(arrayBuffer) { var bstream = new bitjs.io.ByteStream(arrayBuffer); postProgress(); - // While we don't encounter an empty block, keep making TarLocalFiles. + /* + // go through whole file, read header of each block and memorize, filepointer + */ while (bstream.peekNumber(4) !== 0) { - var oneLocalFile = new TarLocalFile(bstream); + var localFile = new TarLocalFile(bstream); + allLocalFiles.push(localFile); + postProgress(); + } + allLocalFiles.sort(naturalCompare); + + allLocalFiles.forEach(function(oneLocalFile) { + // While we don't encounter an empty block, keep making TarLocalFiles. if (oneLocalFile && oneLocalFile.isValid) { // If we make it to this point and haven't thrown an error, we have successfully // read in the data for a local file, so we can update the actual bytestream. - - allLocalFiles.push(oneLocalFile); totalUncompressedBytesInArchive += oneLocalFile.size; // update progress @@ -145,7 +153,7 @@ var untar = function(arrayBuffer) { postMessage(new bitjs.archive.UnarchiveExtractEvent(oneLocalFile)); postProgress(); } - } + }); totalFilesInArchive = allLocalFiles.length; postProgress(); diff --git a/cps/static/js/archive/unzip.js b/cps/static/js/archive/unzip.js index f8de27f7..46e6ec11 100644 --- a/cps/static/js/archive/unzip.js +++ b/cps/static/js/archive/unzip.js @@ -72,19 +72,6 @@ var ZipLocalFile = function(bstream) { this.filename = bstream.readString(this.fileNameLength); } - info("Zip Local File Header:"); - info(" version=" + this.version); - info(" general purpose=" + this.generalPurpose); - info(" compression method=" + this.compressionMethod); - info(" last mod file time=" + this.lastModFileTime); - info(" last mod file date=" + this.lastModFileDate); - info(" crc32=" + this.crc32); - info(" compressed size=" + this.compressedSize); - info(" uncompressed size=" + this.uncompressedSize); - info(" file name length=" + this.fileNameLength); - info(" extra field length=" + this.extraFieldLength); - info(" filename = '" + this.filename + "'"); - this.extraField = null; if (this.extraFieldLength > 0) { this.extraField = bstream.readString(this.extraFieldLength); @@ -107,6 +94,21 @@ var ZipLocalFile = function(bstream) { this.compressedSize = bstream.readNumber(4); this.uncompressedSize = bstream.readNumber(4); } + + // Now that we have all the bytes for this file, we can print out some information. + info("Zip Local File Header:"); + info(" version=" + this.version); + info(" general purpose=" + this.generalPurpose); + info(" compression method=" + this.compressionMethod); + info(" last mod file time=" + this.lastModFileTime); + info(" last mod file date=" + this.lastModFileDate); + info(" crc32=" + this.crc32); + info(" compressed size=" + this.compressedSize); + info(" uncompressed size=" + this.uncompressedSize); + info(" file name length=" + this.fileNameLength); + info(" extra field length=" + this.extraFieldLength); + info(" filename = '" + this.filename + "'"); + }; // determine what kind of compressed data we have and decompress @@ -132,6 +134,7 @@ ZipLocalFile.prototype.unzip = function() { // Takes an ArrayBuffer of a zip file in // returns null on error // returns an array of DecompressedFile objects on success +// ToDo This function differs var unzip = function(arrayBuffer) { postMessage(new bitjs.archive.UnarchiveStartEvent()); @@ -159,11 +162,12 @@ var unzip = function(arrayBuffer) { totalFilesInArchive = localFiles.length; // got all local files, now sort them - localFiles.sort(function(a, b) { + localFiles.sort(naturalCompare); + /*localFiles.sort(function(a, b) { var aname = a.filename.toLowerCase(); var bname = b.filename.toLowerCase(); return aname > bname ? 1 : -1; - }); + });*/ // archive extra data record if (bstream.peekNumber(4) === zArchiveExtraDataSignature) { @@ -253,9 +257,9 @@ function getHuffmanCodes(bitLengths) { } // Reference: http://tools.ietf.org/html/rfc1951#page-8 - var numLengths = bitLengths.length, - blCount = [], - MAX_BITS = 1; + var numLengths = bitLengths.length; + var blCount = []; + var MAX_BITS = 1; // Step 1: count up how many codes of each length we have for (var i = 0; i < numLengths; ++i) { @@ -274,8 +278,8 @@ function getHuffmanCodes(bitLengths) { } // Step 2: Find the numerical value of the smallest code for each code length - var nextCode = [], - code = 0; + var nextCode = []; + var code = 0; for (var bits = 1; bits <= MAX_BITS; ++bits) { var length2 = bits - 1; // ensure undefined lengths are zero @@ -285,8 +289,8 @@ function getHuffmanCodes(bitLengths) { } // Step 3: Assign numerical values to all codes - var table = {}, - tableLength = 0; + var table = {}; + var tableLength = 0; for (var n = 0; n < numLengths; ++n) { var len = bitLengths[n]; if (len !== 0) { @@ -353,7 +357,8 @@ function getFixedDistanceTable() { // extract one bit at a time until we find a matching Huffman Code // then return that symbol function decodeSymbol(bstream, hcTable) { - var code = 0, len = 0; + var code = 0; + var len = 0; // loop until we match for (;;) { @@ -364,7 +369,6 @@ function decodeSymbol(bstream, hcTable) { // check against Huffman Code table and break if found if (hcTable.hasOwnProperty(code) && hcTable[code].length === len) { - break; } if (len > hcTable.maxLength) { @@ -500,10 +504,10 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) { if (symbol === 256) { break; } else { - var lengthLookup = LengthLookupTable[symbol - 257], - length = lengthLookup[1] + bstream.readBits(lengthLookup[0]), - distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)], - distance = distLookup[1] + bstream.readBits(distLookup[0]); + var lengthLookup = LengthLookupTable[symbol - 257]; + var length = lengthLookup[1] + bstream.readBits(lengthLookup[0]); + var distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)]; + var distance = distLookup[1] + bstream.readBits(distLookup[0]); // now apply length and distance appropriately and copy to output @@ -634,8 +638,8 @@ function inflate(compressedData, numDecompressedBytes) { var distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes); // now generate the true Huffman Code tables using these code lengths - var hcLiteralTable = getHuffmanCodes(literalCodeLengths), - hcDistanceTable = getHuffmanCodes(distanceCodeLengths); + var hcLiteralTable = getHuffmanCodes(literalCodeLengths); + var hcDistanceTable = getHuffmanCodes(distanceCodeLengths); blockSize = inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer); } else { // error @@ -659,3 +663,51 @@ function inflate(compressedData, numDecompressedBytes) { onmessage = function(event) { unzip(event.data.file, true); }; + +/* +function naturalCompare(a, b) { + var ax = [], bx = []; + + a.filename.toLowerCase().replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); + b.filename.toLowerCase().replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); + + while(ax.length && bx.length) { + var an = ax.shift(); + var bn = bx.shift(); + var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]); + if(nn) return nn; + } + + return ax.length - bx.length; +}*/ + + +/*var re = /([a-z]+)(\d+)(.+)/i; +function naturalCompare(a, b) { + var ma = a.match(re), + mb = b.match(re), + a_str = ma[1], + b_str = mb[1], + a_num = parseInt(ma[2],10), + b_num = parseInt(mb[2],10), + a_rem = ma[3], + b_rem = mb[3]; + return a_str > b_str ? 1 : a_str < b_str ? -1 : a_num > b_num ? 1 : a_num < b_num ? -1 : a_rem > b_rem; +}*/ + +/*function naturalCompare(a, b) { + var ax = [], bx = []; + + a.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { ax.push([$1 || Infinity, $2 || ""]) }); + b.replace(/(\d+)|(\D+)/g, function(_, $1, $2) { bx.push([$1 || Infinity, $2 || ""]) }); + + while(ax.length && bx.length) { + var an = ax.shift(); + var bn = bx.shift(); + var nn = (an[0] - bn[0]) || an[1].localeCompare(bn[1]); + if(nn) return nn; + } + + return ax.length - bx.length; +}*/ + diff --git a/cps/static/js/io/bytestream.js b/cps/static/js/io/bytestream.js index 55b14005..9372f648 100644 --- a/cps/static/js/io/bytestream.js +++ b/cps/static/js/io/bytestream.js @@ -101,6 +101,35 @@ bitjs.io = bitjs.io || {}; }; + /** + * ToDo: Returns the next n bytes as a signed number and advances the stream pointer. + * @param {number} n The number of bytes to read. + * @return {number} The bytes interpreted as a signed number. + */ + bitjs.io.ByteStream.prototype.movePointer = function(n) { + this.ptr += n; + // end of buffer reached + if ((this.bytes.byteLength - this.ptr) < 0 ) { + this.ptr = this.bytes.byteLength; + } + } + + /** + * ToDo: Returns the next n bytes as a signed number and advances the stream pointer. + * @param {number} n The number of bytes to read. + * @return {number} The bytes interpreted as a signed number. + */ + bitjs.io.ByteStream.prototype.moveTo = function(n) { + if ( n < 0 ) { + n = 0; + } + this.ptr = n; + // end of buffer reached + if ((this.bytes.byteLength - this.ptr) < 0 ) { + this.ptr = this.bytes.byteLength; + } + } + /** * This returns n bytes as a sub-array, advancing the pointer if movePointers * is true. diff --git a/cps/templates/detail.html b/cps/templates/detail.html index 8c1c9d69..b76a8afa 100644 --- a/cps/templates/detail.html +++ b/cps/templates/detail.html @@ -66,9 +66,8 @@ {% endif %} - {% if reader_list %} - {% if audioentries|length %} - + {% endif %} - - {% endif %}

{{entry.title|shortentitle(40)}}

diff --git a/cps/templates/listenmp3.html b/cps/templates/listenmp3.html index 5b07485c..0abc289d 100644 --- a/cps/templates/listenmp3.html +++ b/cps/templates/listenmp3.html @@ -17,7 +17,7 @@ - + + - - - - - -
-
-
0:00
-
-
-
-
-
-
-
-
-
0:00
-
-
- - -
-
- - volume -
-
+
+
+ + + +
+
+
+ + + + + +
+ +
+ +
+
+ +
+ +
-
-
    -
  • - -
  • -
-
+
+ +
+
+ +
+
+ +
+
+
0:00
+
+
+
+
+
+
0:00
+
+ +
+ +
+
+ + volume +
+
+ +
+ +
+ +
+
+ > next +
+
+ +
+ +
+ +
+
+ menu +
+
- -
+