mirror of
https://github.com/janeczku/calibre-web
synced 2024-11-28 20:39:59 +00:00
Sorting for comics
Audiobook support
This commit is contained in:
parent
572b5427c7
commit
ad44e58c7a
@ -107,7 +107,7 @@ def setup(log_file, log_level=None):
|
|||||||
return
|
return
|
||||||
r.debug("logging to %s level %s", log_file, r.level)
|
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 = StreamHandler()
|
||||||
file_handler.baseFilename = LOG_TO_STDERR
|
file_handler.baseFilename = LOG_TO_STDERR
|
||||||
else:
|
else:
|
||||||
|
6
cps/static/css/libs/bar-ui.css
vendored
6
cps/static/css/libs/bar-ui.css
vendored
@ -135,7 +135,7 @@
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
height: 100%;
|
height: 100%;
|
||||||
/* for example */
|
/* 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. */
|
/* additional opacity effects can be applied here. */
|
||||||
opacity: 0.75;
|
opacity: 0.75;
|
||||||
|
|
||||||
@ -143,7 +143,7 @@
|
|||||||
|
|
||||||
.sm2-bar-ui.textured.dark-text .sm2-inline-texture {
|
.sm2-bar-ui.textured.dark-text .sm2-inline-texture {
|
||||||
/* dark text + textured case: use light wood background (for example.) */
|
/* 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 {
|
.sm2-bar-ui.textured.dark-text .sm2-playlist-wrapper {
|
||||||
@ -704,7 +704,7 @@
|
|||||||
height: 100%;
|
height: 100%;
|
||||||
top: 0px;
|
top: 0px;
|
||||||
left: 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-size: 72%;
|
||||||
background-position: 50%;
|
background-position: 50%;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
@ -13,6 +13,22 @@
|
|||||||
var bitjs = bitjs || {};
|
var bitjs = bitjs || {};
|
||||||
bitjs.archive = bitjs.archive || {};
|
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() {
|
(function() {
|
||||||
|
|
||||||
// ===========================================================================
|
// ===========================================================================
|
||||||
|
@ -1333,11 +1333,12 @@ var unrar = function(arrayBuffer) {
|
|||||||
|
|
||||||
// now we have all information but things are unpacked
|
// now we have all information but things are unpacked
|
||||||
// TODO: unpack
|
// TODO: unpack
|
||||||
localFiles = localFiles.sort(function(a, b) {
|
localFiles.sort(naturalCompare);
|
||||||
|
/*localFiles = localFiles.sort(function(a, b) {
|
||||||
var aname = a.filename.toLowerCase();
|
var aname = a.filename.toLowerCase();
|
||||||
var bname = b.filename.toLowerCase();
|
var bname = b.filename.toLowerCase();
|
||||||
return aname > bname ? 1 : -1;
|
return aname > bname ? 1 : -1;
|
||||||
});
|
});*/
|
||||||
|
|
||||||
info(localFiles.map(function(a) {
|
info(localFiles.map(function(a) {
|
||||||
return a.filename;
|
return a.filename;
|
||||||
|
@ -115,6 +115,7 @@ var TarLocalFile = function(bstream) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
var untar = function(arrayBuffer) {
|
var untar = function(arrayBuffer) {
|
||||||
postMessage(new bitjs.archive.UnarchiveStartEvent());
|
postMessage(new bitjs.archive.UnarchiveStartEvent());
|
||||||
currentFilename = "";
|
currentFilename = "";
|
||||||
@ -127,14 +128,21 @@ var untar = function(arrayBuffer) {
|
|||||||
|
|
||||||
var bstream = new bitjs.io.ByteStream(arrayBuffer);
|
var bstream = new bitjs.io.ByteStream(arrayBuffer);
|
||||||
postProgress();
|
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) {
|
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 (oneLocalFile && oneLocalFile.isValid) {
|
||||||
// If we make it to this point and haven't thrown an error, we have successfully
|
// 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.
|
// read in the data for a local file, so we can update the actual bytestream.
|
||||||
|
|
||||||
allLocalFiles.push(oneLocalFile);
|
|
||||||
totalUncompressedBytesInArchive += oneLocalFile.size;
|
totalUncompressedBytesInArchive += oneLocalFile.size;
|
||||||
|
|
||||||
// update progress
|
// update progress
|
||||||
@ -145,7 +153,7 @@ var untar = function(arrayBuffer) {
|
|||||||
postMessage(new bitjs.archive.UnarchiveExtractEvent(oneLocalFile));
|
postMessage(new bitjs.archive.UnarchiveExtractEvent(oneLocalFile));
|
||||||
postProgress();
|
postProgress();
|
||||||
}
|
}
|
||||||
}
|
});
|
||||||
totalFilesInArchive = allLocalFiles.length;
|
totalFilesInArchive = allLocalFiles.length;
|
||||||
|
|
||||||
postProgress();
|
postProgress();
|
||||||
|
@ -72,19 +72,6 @@ var ZipLocalFile = function(bstream) {
|
|||||||
this.filename = bstream.readString(this.fileNameLength);
|
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;
|
this.extraField = null;
|
||||||
if (this.extraFieldLength > 0) {
|
if (this.extraFieldLength > 0) {
|
||||||
this.extraField = bstream.readString(this.extraFieldLength);
|
this.extraField = bstream.readString(this.extraFieldLength);
|
||||||
@ -107,6 +94,21 @@ var ZipLocalFile = function(bstream) {
|
|||||||
this.compressedSize = bstream.readNumber(4);
|
this.compressedSize = bstream.readNumber(4);
|
||||||
this.uncompressedSize = 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
|
// 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
|
// Takes an ArrayBuffer of a zip file in
|
||||||
// returns null on error
|
// returns null on error
|
||||||
// returns an array of DecompressedFile objects on success
|
// returns an array of DecompressedFile objects on success
|
||||||
|
// ToDo This function differs
|
||||||
var unzip = function(arrayBuffer) {
|
var unzip = function(arrayBuffer) {
|
||||||
postMessage(new bitjs.archive.UnarchiveStartEvent());
|
postMessage(new bitjs.archive.UnarchiveStartEvent());
|
||||||
|
|
||||||
@ -159,11 +162,12 @@ var unzip = function(arrayBuffer) {
|
|||||||
totalFilesInArchive = localFiles.length;
|
totalFilesInArchive = localFiles.length;
|
||||||
|
|
||||||
// got all local files, now sort them
|
// 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 aname = a.filename.toLowerCase();
|
||||||
var bname = b.filename.toLowerCase();
|
var bname = b.filename.toLowerCase();
|
||||||
return aname > bname ? 1 : -1;
|
return aname > bname ? 1 : -1;
|
||||||
});
|
});*/
|
||||||
|
|
||||||
// archive extra data record
|
// archive extra data record
|
||||||
if (bstream.peekNumber(4) === zArchiveExtraDataSignature) {
|
if (bstream.peekNumber(4) === zArchiveExtraDataSignature) {
|
||||||
@ -253,9 +257,9 @@ function getHuffmanCodes(bitLengths) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Reference: http://tools.ietf.org/html/rfc1951#page-8
|
// Reference: http://tools.ietf.org/html/rfc1951#page-8
|
||||||
var numLengths = bitLengths.length,
|
var numLengths = bitLengths.length;
|
||||||
blCount = [],
|
var blCount = [];
|
||||||
MAX_BITS = 1;
|
var MAX_BITS = 1;
|
||||||
|
|
||||||
// Step 1: count up how many codes of each length we have
|
// Step 1: count up how many codes of each length we have
|
||||||
for (var i = 0; i < numLengths; ++i) {
|
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
|
// Step 2: Find the numerical value of the smallest code for each code length
|
||||||
var nextCode = [],
|
var nextCode = [];
|
||||||
code = 0;
|
var code = 0;
|
||||||
for (var bits = 1; bits <= MAX_BITS; ++bits) {
|
for (var bits = 1; bits <= MAX_BITS; ++bits) {
|
||||||
var length2 = bits - 1;
|
var length2 = bits - 1;
|
||||||
// ensure undefined lengths are zero
|
// ensure undefined lengths are zero
|
||||||
@ -285,8 +289,8 @@ function getHuffmanCodes(bitLengths) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Assign numerical values to all codes
|
// Step 3: Assign numerical values to all codes
|
||||||
var table = {},
|
var table = {};
|
||||||
tableLength = 0;
|
var tableLength = 0;
|
||||||
for (var n = 0; n < numLengths; ++n) {
|
for (var n = 0; n < numLengths; ++n) {
|
||||||
var len = bitLengths[n];
|
var len = bitLengths[n];
|
||||||
if (len !== 0) {
|
if (len !== 0) {
|
||||||
@ -353,7 +357,8 @@ function getFixedDistanceTable() {
|
|||||||
// extract one bit at a time until we find a matching Huffman Code
|
// extract one bit at a time until we find a matching Huffman Code
|
||||||
// then return that symbol
|
// then return that symbol
|
||||||
function decodeSymbol(bstream, hcTable) {
|
function decodeSymbol(bstream, hcTable) {
|
||||||
var code = 0, len = 0;
|
var code = 0;
|
||||||
|
var len = 0;
|
||||||
|
|
||||||
// loop until we match
|
// loop until we match
|
||||||
for (;;) {
|
for (;;) {
|
||||||
@ -364,7 +369,6 @@ function decodeSymbol(bstream, hcTable) {
|
|||||||
|
|
||||||
// check against Huffman Code table and break if found
|
// check against Huffman Code table and break if found
|
||||||
if (hcTable.hasOwnProperty(code) && hcTable[code].length === len) {
|
if (hcTable.hasOwnProperty(code) && hcTable[code].length === len) {
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (len > hcTable.maxLength) {
|
if (len > hcTable.maxLength) {
|
||||||
@ -500,10 +504,10 @@ function inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer) {
|
|||||||
if (symbol === 256) {
|
if (symbol === 256) {
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
var lengthLookup = LengthLookupTable[symbol - 257],
|
var lengthLookup = LengthLookupTable[symbol - 257];
|
||||||
length = lengthLookup[1] + bstream.readBits(lengthLookup[0]),
|
var length = lengthLookup[1] + bstream.readBits(lengthLookup[0]);
|
||||||
distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)],
|
var distLookup = DistLookupTable[decodeSymbol(bstream, hcDistanceTable)];
|
||||||
distance = distLookup[1] + bstream.readBits(distLookup[0]);
|
var distance = distLookup[1] + bstream.readBits(distLookup[0]);
|
||||||
|
|
||||||
// now apply length and distance appropriately and copy to output
|
// now apply length and distance appropriately and copy to output
|
||||||
|
|
||||||
@ -634,8 +638,8 @@ function inflate(compressedData, numDecompressedBytes) {
|
|||||||
var distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes);
|
var distanceCodeLengths = literalCodeLengths.splice(numLiteralLengthCodes, numDistanceCodes);
|
||||||
|
|
||||||
// now generate the true Huffman Code tables using these code lengths
|
// now generate the true Huffman Code tables using these code lengths
|
||||||
var hcLiteralTable = getHuffmanCodes(literalCodeLengths),
|
var hcLiteralTable = getHuffmanCodes(literalCodeLengths);
|
||||||
hcDistanceTable = getHuffmanCodes(distanceCodeLengths);
|
var hcDistanceTable = getHuffmanCodes(distanceCodeLengths);
|
||||||
blockSize = inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer);
|
blockSize = inflateBlockData(bstream, hcLiteralTable, hcDistanceTable, buffer);
|
||||||
} else {
|
} else {
|
||||||
// error
|
// error
|
||||||
@ -659,3 +663,51 @@ function inflate(compressedData, numDecompressedBytes) {
|
|||||||
onmessage = function(event) {
|
onmessage = function(event) {
|
||||||
unzip(event.data.file, true);
|
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;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
@ -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
|
* This returns n bytes as a sub-array, advancing the pointer if movePointers
|
||||||
* is true.
|
* is true.
|
||||||
|
@ -66,9 +66,8 @@
|
|||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% if reader_list %}
|
{% if audioentries|length > 0 %}
|
||||||
{% if audioentries|length %}
|
<div class="btn-group" role="group">
|
||||||
<!--div class="btn-group" role="group">
|
|
||||||
<button id="listen-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
<button id="listen-in-browser" type="button" class="btn btn-primary dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||||
<span class="glyphicon glyphicon-music"></span> {{_('Listen in browser')}}
|
<span class="glyphicon glyphicon-music"></span> {{_('Listen in browser')}}
|
||||||
<span class="caret"></span>
|
<span class="caret"></span>
|
||||||
@ -86,10 +85,8 @@
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% endfor %}
|
{% endfor %}
|
||||||
</ul>
|
</ul>
|
||||||
</div-->
|
</div>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<h2 id="title">{{entry.title|shortentitle(40)}}</h2>
|
<h2 id="title">{{entry.title|shortentitle(40)}}</h2>
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||||
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
<link href="{{ url_for('static', filename='css/libs/bootstrap.min.css') }}" rel="stylesheet" media="screen">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/libs/bar-ui.css') }}" />
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/libs/bar-ui.css') }}" />
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/listen.css') }}" />
|
<!--link rel="stylesheet" href="{{ url_for('static', filename='css/listen.css') }}" /-->
|
||||||
|
|
||||||
<!-- <link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}">
|
<!-- <link rel="stylesheet" href="{{ url_for('static', filename='css/libs/normalize.css') }}">
|
||||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/main.css') }}">
|
||||||
@ -30,12 +30,12 @@
|
|||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body>
|
<body>
|
||||||
<div id="main">
|
<!--div id="main">
|
||||||
<div class="content">
|
<div class="content">
|
||||||
<h2>{{ entry.title }}</h2>
|
<h2>{{ entry.title }}</h2>
|
||||||
|
|
||||||
<div class="cover">
|
<div class="cover">
|
||||||
<img src="{{ url_for('web.get_cover', cover_path=entry.path.replace('\\','/')) }}" alt="{{ entry.title }}" />
|
<img src="{{ url_for('web.get_cover', book_id=entry.id) }}" alt="{{ entry.title }}" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{% if entry.ratings.__len__() > 0 %}
|
{% if entry.ratings.__len__() > 0 %}
|
||||||
@ -53,77 +53,178 @@
|
|||||||
|
|
||||||
<h3>{{_('Description:')}}</h3>
|
<h3>{{_('Description:')}}</h3>
|
||||||
{{entry.comments[0].text|safe}}
|
{{entry.comments[0].text|safe}}
|
||||||
|
</div-->
|
||||||
|
<!--div class="sm2-bar-ui compact full-width">
|
||||||
|
|
||||||
|
<div class="bd sm2-main-controls">
|
||||||
|
|
||||||
|
<div class="sm2-inline-texture"></div>
|
||||||
|
<div class="sm2-inline-gradient"></div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#play" class="sm2-inline-button sm2-icon-play-pause">{{_('Play / pause')}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-inline-status">
|
||||||
|
|
||||||
|
<div class="sm2-playlist">
|
||||||
|
<div class="sm2-playlist-target">
|
||||||
|
<!-- playlist <ul> + <li> markup will be injected here -->
|
||||||
|
<!-- if you want default / non-JS content, you can put that here. -->
|
||||||
|
<!--noscript><p>JavaScript is required.</p></noscript>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="sm2-bar-ui compact flat">
|
<div class="sm2-progress">
|
||||||
|
<div class="sm2-row">
|
||||||
<div class="bd sm2-main-controls">
|
<div class="sm2-inline-time">0:00</div>
|
||||||
|
<div class="sm2-progress-bd">
|
||||||
<div class="sm2-inline-texture"></div>
|
<div class="sm2-progress-track">
|
||||||
<div class="sm2-inline-gradient"></div>
|
<div class="sm2-progress-bar"></div>
|
||||||
|
<div class="sm2-progress-ball"><div class="icon-overlay"></div></div>
|
||||||
<div class="sm2-inline-element sm2-button-element">
|
|
||||||
<div class="sm2-button-bd">
|
|
||||||
<a href="#play" class="sm2-inline-button sm2-icon-play-pause">Play / pause</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sm2-inline-element sm2-inline-status">
|
|
||||||
|
|
||||||
<div class="sm2-playlist">
|
|
||||||
<div class="sm2-playlist-target">
|
|
||||||
<!-- playlist <ul> + <li> markup will be injected here -->
|
|
||||||
<!-- if you want default / non-JS content, you can put that here. -->
|
|
||||||
<noscript>
|
|
||||||
<p>JavaScript is required.</p>
|
|
||||||
</noscript>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sm2-progress">
|
|
||||||
<div class="sm2-row">
|
|
||||||
<div class="sm2-inline-time">0:00</div>
|
|
||||||
<div class="sm2-progress-bd">
|
|
||||||
<div class="sm2-progress-track">
|
|
||||||
<div class="sm2-progress-bar"></div>
|
|
||||||
<div class="sm2-progress-ball">
|
|
||||||
<div class="icon-overlay"></div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="sm2-inline-duration">0:00</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="sm2-inline-element sm2-button-element sm2-volume">
|
|
||||||
<div class="sm2-button-bd">
|
|
||||||
<span class="sm2-inline-button sm2-volume-control volume-shade"></span>
|
|
||||||
<a href="#volume" class="sm2-inline-button sm2-volume-control">volume</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="bd sm2-playlist-drawer sm2-element">
|
|
||||||
|
|
||||||
<div class="sm2-inline-texture">
|
|
||||||
<div class="sm2-box-shadow"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- playlist content is mirrored here -->
|
|
||||||
|
|
||||||
<div class="sm2-playlist-wrapper">
|
|
||||||
<ul class="sm2-playlist-bd">
|
|
||||||
<li>
|
|
||||||
<a href="{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}"></a>
|
|
||||||
</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sm2-inline-duration">0:00</div>
|
||||||
</div>
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<script>
|
</div>
|
||||||
window.calibre = {
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element sm2-volume">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<span class="sm2-inline-button sm2-volume-control volume-shade"></span>
|
||||||
|
<a href="#volume" class="sm2-inline-button sm2-volume-control">{{_('volume')}}</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bd sm2-playlist-drawer sm2-element">
|
||||||
|
|
||||||
|
<div class="sm2-inline-texture">
|
||||||
|
<div class="sm2-box-shadow"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- playlist content is mirrored here -->
|
||||||
|
|
||||||
|
<!--div class="sm2-playlist-wrapper">
|
||||||
|
<ul class="sm2-playlist-bd">
|
||||||
|
<li><a href="{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}"><b>{% for author in entry.authors %}{{author.name.replace('|',',')}}
|
||||||
|
{% if not loop.last %} & {% endif %} {% endfor %}</b> - {{entry.title}}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div-->
|
||||||
|
|
||||||
|
<div class="sm2-bar-ui full-width fixed">
|
||||||
|
|
||||||
|
<div class="bd sm2-main-controls">
|
||||||
|
|
||||||
|
<div class="sm2-inline-texture"></div>
|
||||||
|
<div class="sm2-inline-gradient"></div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#play" class="sm2-inline-button sm2-icon-play-pause">Play / pause</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-inline-status">
|
||||||
|
|
||||||
|
<div class="sm2-playlist">
|
||||||
|
<div class="sm2-playlist-target">
|
||||||
|
<noscript><p>JavaScript is required.</p></noscript>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-progress">
|
||||||
|
<div class="sm2-row">
|
||||||
|
<div class="sm2-inline-time">0:00</div>
|
||||||
|
<div class="sm2-progress-bd">
|
||||||
|
<div class="sm2-progress-track">
|
||||||
|
<div class="sm2-progress-bar"></div>
|
||||||
|
<div class="sm2-progress-ball"><div class="icon-overlay"></div></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="sm2-inline-duration">0:00</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element sm2-volume">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<span class="sm2-inline-button sm2-volume-control volume-shade"></span>
|
||||||
|
<a href="#volume" class="sm2-inline-button sm2-volume-control">volume</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#prev" title="Previous" class="sm2-inline-button sm2-icon-previous">< previous</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#next" title="Next" class="sm2-inline-button sm2-icon-next">> next</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#repeat" title="Repeat playlist" class="sm2-inline-button sm2-icon-repeat">∞ repeat</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="sm2-inline-element sm2-button-element sm2-menu">
|
||||||
|
<div class="sm2-button-bd">
|
||||||
|
<a href="#menu" class="sm2-inline-button sm2-icon-menu">menu</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="bd sm2-playlist-drawer sm2-element">
|
||||||
|
|
||||||
|
<div class="sm2-inline-texture">
|
||||||
|
<div class="sm2-box-shadow"></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- playlist content is mirrored here -->
|
||||||
|
|
||||||
|
<div class="sm2-playlist-wrapper">
|
||||||
|
<ul class="sm2-playlist-bd">
|
||||||
|
<li><a href="{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}"><b>{% for author in entry.authors %}{{author.name.replace('|',',')}}
|
||||||
|
{% if not loop.last %} & {% endif %} {% endfor %}</b> - {{entry.title}}</a></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
soundManager.setup({
|
||||||
|
useHTML5Audio: true,
|
||||||
|
preferFlash: false,
|
||||||
|
url: '/path/to/swf-files/',
|
||||||
|
onready: function() {
|
||||||
|
var mySound = soundManager.createSound({
|
||||||
|
// id: 'aSound',
|
||||||
|
// url: "{{ url_for('web.serve_book', book_id=mp3file,book_format=audioformat)}}"
|
||||||
|
});
|
||||||
|
mySound.play();
|
||||||
|
},
|
||||||
|
ontimeout: function() {
|
||||||
|
// Hrmm, SM2 could not start. Missing SWF? Flash blocked? Show an error, etc.?
|
||||||
|
}
|
||||||
|
});
|
||||||
|
window.calibre = {
|
||||||
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
filePath: "{{ url_for('static', filename='js/libs/') }}",
|
||||||
cssPath: "{{ url_for('static', filename='css/') }}",
|
cssPath: "{{ url_for('static', filename='css/') }}",
|
||||||
bookUrl: "{{ url_for('static', filename=mp3file) }}/",
|
bookUrl: "{{ url_for('static', filename=mp3file) }}/",
|
||||||
@ -131,8 +232,7 @@
|
|||||||
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
bookmark: "{{ bookmark.bookmark_key if bookmark != None }}",
|
||||||
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
useBookmarks: "{{ g.user.is_authenticated | tojson }}"
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
</div>
|
|
||||||
</body>
|
</body>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
Loading…
Reference in New Issue
Block a user