mirror of
				https://github.com/janeczku/calibre-web
				synced 2025-10-31 07:13:02 +00:00 
			
		
		
		
	Sorting for comics
Audiobook support
This commit is contained in:
		| @@ -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: | ||||
|   | ||||
							
								
								
									
										6
									
								
								cps/static/css/libs/bar-ui.css
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										6
									
								
								cps/static/css/libs/bar-ui.css
									
									
									
									
										vendored
									
									
								
							| @@ -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; | ||||
|   | ||||
| @@ -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() { | ||||
|  | ||||
|     // =========================================================================== | ||||
|   | ||||
| @@ -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; | ||||
|   | ||||
| @@ -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(); | ||||
|   | ||||
| @@ -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; | ||||
| }*/ | ||||
|  | ||||
|   | ||||
| @@ -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. | ||||
|   | ||||
| @@ -66,9 +66,8 @@ | ||||
|                     </ul> | ||||
|               </div> | ||||
|             {% endif %} | ||||
|               {% if reader_list  %} | ||||
|             {% if audioentries|length %} | ||||
|               <!--div class="btn-group" role="group"> | ||||
|             {% if audioentries|length > 0 %} | ||||
|               <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"> | ||||
|                   <span class="glyphicon glyphicon-music"></span> {{_('Listen in browser')}} | ||||
|                   <span class="caret"></span> | ||||
| @@ -86,9 +85,7 @@ | ||||
|                     {% endif %} | ||||
|               {% endfor %} | ||||
|                   </ul> | ||||
|               </div--> | ||||
|             {% endif %} | ||||
|  | ||||
|               </div> | ||||
|             {% endif %} | ||||
|         </div> | ||||
|       </div> | ||||
|   | ||||
| @@ -17,7 +17,7 @@ | ||||
|   <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 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/main.css') }}"> | ||||
| @@ -30,12 +30,12 @@ | ||||
| </head> | ||||
|  | ||||
| <body> | ||||
|   <div id="main"> | ||||
|   <!--div id="main"> | ||||
|     <div class="content"> | ||||
|       <h2>{{ entry.title }}</h2> | ||||
|  | ||||
|       <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> | ||||
|  | ||||
|       {% if entry.ratings.__len__() > 0 %} | ||||
| @@ -53,9 +53,74 @@ | ||||
|  | ||||
|       <h3>{{_('Description:')}}</h3> | ||||
|       {{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-bar-ui compact flat"> | ||||
|   <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)}}"><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"> | ||||
|  | ||||
| @@ -72,11 +137,7 @@ | ||||
|  | ||||
|    <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> | ||||
|      <noscript><p>JavaScript is required.</p></noscript> | ||||
|     </div> | ||||
|    </div> | ||||
|  | ||||
| @@ -86,14 +147,13 @@ | ||||
|      <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 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"> | ||||
| @@ -102,6 +162,31 @@ | ||||
|     <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"> | ||||
| @@ -114,15 +199,31 @@ | ||||
|  | ||||
|   <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> | ||||
|       <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/') }}", | ||||
|         cssPath: "{{ url_for('static', filename='css/') }}", | ||||
| @@ -132,7 +233,6 @@ | ||||
|         useBookmarks: "{{ g.user.is_authenticated | tojson }}" | ||||
|             }; | ||||
| </script> | ||||
|   </div> | ||||
| </body> | ||||
|  | ||||
| </html> | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Ozzieisaacs
					Ozzieisaacs