Fix duplicate user and email (now case insensitive #948)
Fix sorting in comics (#950) Fix log error on Calibre converter error (#953) Fix long running tasks (#954)
This commit is contained in:
parent
66283c542f
commit
f79d549910
|
@ -34,7 +34,8 @@ from flask import send_from_directory, make_response, redirect, abort
|
||||||
from flask_babel import gettext as _
|
from flask_babel import gettext as _
|
||||||
from flask_login import current_user
|
from flask_login import current_user
|
||||||
from babel.dates import format_datetime
|
from babel.dates import format_datetime
|
||||||
from datetime import datetime
|
from babel.units import format_unit
|
||||||
|
from datetime import datetime, timedelta
|
||||||
import shutil
|
import shutil
|
||||||
import requests
|
import requests
|
||||||
try:
|
try:
|
||||||
|
@ -566,8 +567,33 @@ def json_serial(obj):
|
||||||
|
|
||||||
if isinstance(obj, (datetime)):
|
if isinstance(obj, (datetime)):
|
||||||
return obj.isoformat()
|
return obj.isoformat()
|
||||||
|
if isinstance(obj, (timedelta)):
|
||||||
|
return {
|
||||||
|
'__type__': 'timedelta',
|
||||||
|
'days': obj.days,
|
||||||
|
'seconds': obj.seconds,
|
||||||
|
'microseconds': obj.microseconds,
|
||||||
|
}
|
||||||
raise TypeError ("Type %s not serializable" % type(obj))
|
raise TypeError ("Type %s not serializable" % type(obj))
|
||||||
|
|
||||||
|
|
||||||
|
# helper function for displaying the runtime of tasks
|
||||||
|
def format_runtime(runtime):
|
||||||
|
retVal = ""
|
||||||
|
if runtime.days:
|
||||||
|
retVal = format_unit(runtime.days, 'duration-day', length="long", locale=web.get_locale()) + ', '
|
||||||
|
mins, seconds = divmod(runtime.seconds, 60)
|
||||||
|
hours, minutes = divmod(mins, 60)
|
||||||
|
# ToDo: locale.number_symbols._data['timeSeparator'] -> localize time separator ?
|
||||||
|
if hours:
|
||||||
|
retVal += '{:d}:{:02d}:{:02d}s'.format(hours, minutes, seconds)
|
||||||
|
elif minutes:
|
||||||
|
retVal += '{:2d}:{:02d}s'.format(minutes, seconds)
|
||||||
|
else:
|
||||||
|
retVal += '{:2d}s'.format(seconds)
|
||||||
|
return retVal
|
||||||
|
|
||||||
|
|
||||||
# helper function to apply localize status information in tasklist entries
|
# helper function to apply localize status information in tasklist entries
|
||||||
def render_task_status(tasklist):
|
def render_task_status(tasklist):
|
||||||
renderedtasklist=list()
|
renderedtasklist=list()
|
||||||
|
@ -579,6 +605,8 @@ def render_task_status(tasklist):
|
||||||
if 'starttime' not in task:
|
if 'starttime' not in task:
|
||||||
task['starttime'] = ""
|
task['starttime'] = ""
|
||||||
|
|
||||||
|
task['runtime'] = format_runtime(task['formRuntime'])
|
||||||
|
|
||||||
# localize the task status
|
# localize the task status
|
||||||
if isinstance( task['stat'], int ):
|
if isinstance( task['stat'], int ):
|
||||||
if task['stat'] == worker.STAT_WAITING:
|
if task['stat'] == worker.STAT_WAITING:
|
||||||
|
|
|
@ -1,3 +1,67 @@
|
||||||
|
/* alphanum.js (C) Brian Huisman
|
||||||
|
* Based on the Alphanum Algorithm by David Koelle
|
||||||
|
* The Alphanum Algorithm is discussed at http://www.DaveKoelle.com
|
||||||
|
*
|
||||||
|
* Distributed under same license as original
|
||||||
|
*
|
||||||
|
* Released under the MIT License - https://opensource.org/licenses/MIT
|
||||||
|
*
|
||||||
|
* Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
* a copy of this software and associated documentation files (the "Software"),
|
||||||
|
* to deal in the Software without restriction, including without limitation
|
||||||
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
* and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
* Software is furnished to do so, subject to the following conditions:
|
||||||
|
*
|
||||||
|
* The above copyright notice and this permission notice shall be included
|
||||||
|
* in all copies or substantial portions of the Software.
|
||||||
|
*
|
||||||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
|
||||||
|
* DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||||
|
* OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
|
||||||
|
* USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
*/
|
||||||
|
/* ********************************************************************
|
||||||
|
* Alphanum sort() function version - case insensitive
|
||||||
|
* - Slower, but easier to modify for arrays of objects which contain
|
||||||
|
* string properties
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
function alphanumCase(a, b) {
|
||||||
|
function chunkify(t) {
|
||||||
|
var tz = new Array();
|
||||||
|
var x = 0, y = -1, n = 0, i, j;
|
||||||
|
|
||||||
|
while (i = (j = t.charAt(x++)).charCodeAt(0)) {
|
||||||
|
var m = (i == 46 || (i >=48 && i <= 57));
|
||||||
|
if (m !== n) {
|
||||||
|
tz[++y] = "";
|
||||||
|
n = m;
|
||||||
|
}
|
||||||
|
tz[y] += j;
|
||||||
|
}
|
||||||
|
return tz;
|
||||||
|
}
|
||||||
|
|
||||||
|
var aa = chunkify(a.filename.toLowerCase());
|
||||||
|
var bb = chunkify(b.filename.toLowerCase());
|
||||||
|
|
||||||
|
for (x = 0; aa[x] && bb[x]; x++) {
|
||||||
|
if (aa[x] !== bb[x]) {
|
||||||
|
var c = Number(aa[x]), d = Number(bb[x]);
|
||||||
|
if (c == aa[x] && d == bb[x]) {
|
||||||
|
return c - d;
|
||||||
|
} else return (aa[x] > bb[x]) ? 1 : -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return aa.length - bb.length;
|
||||||
|
}
|
||||||
|
// ===========================================================================
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* archive.js
|
* archive.js
|
||||||
*
|
*
|
||||||
|
|
|
@ -1332,12 +1332,7 @@ var unrar = function(arrayBuffer) {
|
||||||
totalFilesInArchive = localFiles.length;
|
totalFilesInArchive = localFiles.length;
|
||||||
|
|
||||||
// now we have all information but things are unpacked
|
// now we have all information but things are unpacked
|
||||||
// TODO: unpack
|
localFiles.sort(alphanumCase);
|
||||||
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) {
|
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,22 @@ 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();
|
||||||
|
}
|
||||||
|
// got all local files, now sort them
|
||||||
|
allLocalFiles.sort(alphanumCase);
|
||||||
|
|
||||||
|
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 +154,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,23 +72,10 @@ 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);
|
||||||
info(" extra field=" + this.extraField);
|
info(" extra field=" + this.extraField);
|
||||||
}
|
}
|
||||||
|
|
||||||
// read in the compressed data
|
// read in the compressed data
|
||||||
|
@ -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,7 @@ 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(alphanumCase);
|
||||||
var aname = a.filename.toLowerCase();
|
|
||||||
var bname = b.filename.toLowerCase();
|
|
||||||
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 +252,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 +273,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 +284,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 +352,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 +364,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 +499,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 +633,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
|
||||||
|
|
|
@ -1,483 +0,0 @@
|
||||||
/*
|
|
||||||
* io.js
|
|
||||||
*
|
|
||||||
* Provides readers for bit/byte streams (reading) and a byte buffer (writing).
|
|
||||||
*
|
|
||||||
* Licensed under the MIT License
|
|
||||||
*
|
|
||||||
* Copyright(c) 2011 Google Inc.
|
|
||||||
* Copyright(c) 2011 antimatter15
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* global bitjs, Uint8Array */
|
|
||||||
|
|
||||||
var bitjs = bitjs || {};
|
|
||||||
bitjs.io = bitjs.io || {};
|
|
||||||
|
|
||||||
(function() {
|
|
||||||
|
|
||||||
// mask for getting the Nth bit (zero-based)
|
|
||||||
bitjs.BIT = [ 0x01, 0x02, 0x04, 0x08,
|
|
||||||
0x10, 0x20, 0x40, 0x80,
|
|
||||||
0x100, 0x200, 0x400, 0x800,
|
|
||||||
0x1000, 0x2000, 0x4000, 0x8000];
|
|
||||||
|
|
||||||
// mask for getting N number of bits (0-8)
|
|
||||||
var BITMASK = [0, 0x01, 0x03, 0x07, 0x0F, 0x1F, 0x3F, 0x7F, 0xFF ];
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This bit stream peeks and consumes bits out of a binary stream.
|
|
||||||
*
|
|
||||||
* @param {ArrayBuffer} ab An ArrayBuffer object or a Uint8Array.
|
|
||||||
* @param {boolean} rtl Whether the stream reads bits from the byte starting
|
|
||||||
* from bit 7 to 0 (true) or bit 0 to 7 (false).
|
|
||||||
* @param {Number} optOffset The offset into the ArrayBuffer
|
|
||||||
* @param {Number} optLength The length of this BitStream
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream = function(ab, rtl, optOffset, optLength) {
|
|
||||||
if (!ab || !ab.toString || ab.toString() !== "[object ArrayBuffer]") {
|
|
||||||
throw "Error! BitArray constructed with an invalid ArrayBuffer object";
|
|
||||||
}
|
|
||||||
|
|
||||||
var offset = optOffset || 0;
|
|
||||||
var length = optLength || ab.byteLength;
|
|
||||||
this.bytes = new Uint8Array(ab, offset, length);
|
|
||||||
this.bytePtr = 0; // tracks which byte we are on
|
|
||||||
this.bitPtr = 0; // tracks which bit we are on (can have values 0 through 7)
|
|
||||||
this.peekBits = rtl ? this.peekBitsRtl : this.peekBitsLtr;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* byte0 byte1 byte2 byte3
|
|
||||||
* 7......0 | 7......0 | 7......0 | 7......0
|
|
||||||
*
|
|
||||||
* The bit pointer starts at bit0 of byte0 and moves left until it reaches
|
|
||||||
* bit7 of byte0, then jumps to bit0 of byte1, etc.
|
|
||||||
* @param {number} n The number of bits to peek.
|
|
||||||
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
|
|
||||||
* @return {number} The peeked bits, as an unsigned number.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.peekBitsLtr = function(n, movePointers) {
|
|
||||||
if (n <= 0 || typeof n !== typeof 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var movePointers = movePointers || false;
|
|
||||||
var bytePtr = this.bytePtr;
|
|
||||||
var bitPtr = this.bitPtr;
|
|
||||||
var result = 0;
|
|
||||||
var bitsIn = 0;
|
|
||||||
var bytes = this.bytes;
|
|
||||||
|
|
||||||
// keep going until we have no more bits left to peek at
|
|
||||||
// TODO: Consider putting all bits from bytes we will need into a variable and then
|
|
||||||
// shifting/masking it to just extract the bits we want.
|
|
||||||
// This could be considerably faster when reading more than 3 or 4 bits at a time.
|
|
||||||
while (n > 0) {
|
|
||||||
if (bytePtr >= bytes.length) {
|
|
||||||
throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" +
|
|
||||||
bytes.length + ", bitPtr=" + bitPtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
var numBitsLeftInThisByte = (8 - bitPtr);
|
|
||||||
var mask;
|
|
||||||
if (n >= numBitsLeftInThisByte) {
|
|
||||||
mask = (BITMASK[numBitsLeftInThisByte] << bitPtr);
|
|
||||||
result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn);
|
|
||||||
|
|
||||||
bytePtr++;
|
|
||||||
bitPtr = 0;
|
|
||||||
bitsIn += numBitsLeftInThisByte;
|
|
||||||
n -= numBitsLeftInThisByte;
|
|
||||||
} else {
|
|
||||||
mask = (BITMASK[n] << bitPtr);
|
|
||||||
result |= (((bytes[bytePtr] & mask) >> bitPtr) << bitsIn);
|
|
||||||
|
|
||||||
bitPtr += n;
|
|
||||||
bitsIn += n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (movePointers) {
|
|
||||||
this.bitPtr = bitPtr;
|
|
||||||
this.bytePtr = bytePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* byte0 byte1 byte2 byte3
|
|
||||||
* 7......0 | 7......0 | 7......0 | 7......0
|
|
||||||
*
|
|
||||||
* The bit pointer starts at bit7 of byte0 and moves right until it reaches
|
|
||||||
* bit0 of byte0, then goes to bit7 of byte1, etc.
|
|
||||||
* @param {number} n The number of bits to peek.
|
|
||||||
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
|
|
||||||
* @return {number} The peeked bits, as an unsigned number.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.peekBitsRtl = function(n, movePointers) {
|
|
||||||
if (n <= 0 || typeof n !== typeof 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
var movePointers = movePointers || false;
|
|
||||||
var bytePtr = this.bytePtr;
|
|
||||||
var bitPtr = this.bitPtr;
|
|
||||||
var result = 0;
|
|
||||||
var bytes = this.bytes;
|
|
||||||
|
|
||||||
// keep going until we have no more bits left to peek at
|
|
||||||
// TODO: Consider putting all bits from bytes we will need into a variable and then
|
|
||||||
// shifting/masking it to just extract the bits we want.
|
|
||||||
// This could be considerably faster when reading more than 3 or 4 bits at a time.
|
|
||||||
while (n > 0) {
|
|
||||||
|
|
||||||
if (bytePtr >= bytes.length) {
|
|
||||||
throw "Error! Overflowed the bit stream! n=" + n + ", bytePtr=" + bytePtr + ", bytes.length=" +
|
|
||||||
bytes.length + ", bitPtr=" + bitPtr;
|
|
||||||
// return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var numBitsLeftInThisByte = (8 - bitPtr);
|
|
||||||
if (n >= numBitsLeftInThisByte) {
|
|
||||||
result <<= numBitsLeftInThisByte;
|
|
||||||
result |= (BITMASK[numBitsLeftInThisByte] & bytes[bytePtr]);
|
|
||||||
bytePtr++;
|
|
||||||
bitPtr = 0;
|
|
||||||
n -= numBitsLeftInThisByte;
|
|
||||||
} else {
|
|
||||||
result <<= n;
|
|
||||||
result |= ((bytes[bytePtr] & (BITMASK[n] << (8 - n - bitPtr))) >> (8 - n - bitPtr));
|
|
||||||
|
|
||||||
bitPtr += n;
|
|
||||||
n = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (movePointers) {
|
|
||||||
this.bitPtr = bitPtr;
|
|
||||||
this.bytePtr = bytePtr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Some voodoo magic.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.getBits = function() {
|
|
||||||
return (((((this.bytes[this.bytePtr] & 0xff) << 16) +
|
|
||||||
((this.bytes[this.bytePtr + 1] & 0xff) << 8) +
|
|
||||||
((this.bytes[this.bytePtr + 2] & 0xff))) >>> (8 - this.bitPtr)) & 0xffff);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads n bits out of the stream, consuming them (moving the bit pointer).
|
|
||||||
* @param {number} n The number of bits to read.
|
|
||||||
* @return {number} The read bits, as an unsigned number.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.readBits = function(n) {
|
|
||||||
return this.peekBits(n, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This returns n bytes as a sub-array, advancing the pointer if movePointers
|
|
||||||
* is true. Only use this for uncompressed blocks as this throws away remaining
|
|
||||||
* bits in the current byte.
|
|
||||||
* @param {number} n The number of bytes to peek.
|
|
||||||
* @param {boolean=} movePointers Whether to move the pointer, defaults false.
|
|
||||||
* @return {Uint8Array} The subarray.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.peekBytes = function(n, movePointers) {
|
|
||||||
if (n <= 0 || typeof n != typeof 1) {
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// from http://tools.ietf.org/html/rfc1951#page-11
|
|
||||||
// "Any bits of input up to the next byte boundary are ignored."
|
|
||||||
while (this.bitPtr !== 0) {
|
|
||||||
this.readBits(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
movePointers = movePointers || false;
|
|
||||||
var bytePtr = this.bytePtr;
|
|
||||||
// var bitPtr = this.bitPtr;
|
|
||||||
|
|
||||||
var result = this.bytes.subarray(bytePtr, bytePtr + n);
|
|
||||||
|
|
||||||
if (movePointers) {
|
|
||||||
this.bytePtr += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @return {Uint8Array} The subarray.
|
|
||||||
*/
|
|
||||||
bitjs.io.BitStream.prototype.readBytes = function(n) {
|
|
||||||
return this.peekBytes(n, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This object allows you to peek and consume bytes as numbers and strings
|
|
||||||
* out of an ArrayBuffer. In this buffer, everything must be byte-aligned.
|
|
||||||
*
|
|
||||||
* @param {ArrayBuffer} ab The ArrayBuffer object.
|
|
||||||
* @param {number=} optOffset The offset into the ArrayBuffer
|
|
||||||
* @param {number=} optLength The length of this BitStream
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream = function(ab, optOffset, optLength) {
|
|
||||||
var offset = optOffset || 0;
|
|
||||||
var length = optLength || ab.byteLength;
|
|
||||||
this.bytes = new Uint8Array(ab, offset, length);
|
|
||||||
this.ptr = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Peeks at the next n bytes as an unsigned number but does not advance the
|
|
||||||
* pointer
|
|
||||||
* TODO: This apparently cannot read more than 4 bytes as a number?
|
|
||||||
* @param {number} n The number of bytes to peek at.
|
|
||||||
* @return {number} The n bytes interpreted as an unsigned number.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.peekNumber = function(n) {
|
|
||||||
// TODO: return error if n would go past the end of the stream?
|
|
||||||
if (n <= 0 || typeof n !== typeof 1) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = 0;
|
|
||||||
// read from last byte to first byte and roll them in
|
|
||||||
var curByte = this.ptr + n - 1;
|
|
||||||
while (curByte >= this.ptr) {
|
|
||||||
result <<= 8;
|
|
||||||
result |= this.bytes[curByte];
|
|
||||||
--curByte;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next n bytes as an unsigned number (or -1 on error)
|
|
||||||
* and advances the stream pointer n bytes.
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @return {number} The n bytes interpreted as an unsigned number.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.readNumber = function(n) {
|
|
||||||
var num = this.peekNumber( n );
|
|
||||||
this.ptr += n;
|
|
||||||
return num;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next n bytes as a signed number but does not advance the
|
|
||||||
* pointer.
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @return {number} The bytes interpreted as a signed number.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.peekSignedNumber = function(n) {
|
|
||||||
var num = this.peekNumber(n);
|
|
||||||
var HALF = Math.pow(2, (n * 8) - 1);
|
|
||||||
var FULL = HALF * 2;
|
|
||||||
|
|
||||||
if (num >= HALF) num -= FULL;
|
|
||||||
|
|
||||||
return num;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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.readSignedNumber = function(n) {
|
|
||||||
var num = this.peekSignedNumber(n);
|
|
||||||
this.ptr += n;
|
|
||||||
return num;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This returns n bytes as a sub-array, advancing the pointer if movePointers
|
|
||||||
* is true.
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @param {boolean} movePointers Whether to move the pointers.
|
|
||||||
* @return {Uint8Array} The subarray.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.peekBytes = function(n, movePointers) {
|
|
||||||
if (n <= 0 || typeof n != typeof 1) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = this.bytes.subarray(this.ptr, this.ptr + n);
|
|
||||||
|
|
||||||
if (movePointers) {
|
|
||||||
this.ptr += n;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reads the next n bytes as a sub-array.
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @return {Uint8Array} The subarray.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.readBytes = function(n) {
|
|
||||||
return this.peekBytes(n, true);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Peeks at the next n bytes as a string but does not advance the pointer.
|
|
||||||
* @param {number} n The number of bytes to peek at.
|
|
||||||
* @return {string} The next n bytes as a string.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.peekString = function(n) {
|
|
||||||
if (n <= 0 || typeof n != typeof 1) {
|
|
||||||
return "";
|
|
||||||
}
|
|
||||||
|
|
||||||
var result = "";
|
|
||||||
for (var p = this.ptr, end = this.ptr + n; p < end; ++p) {
|
|
||||||
result += String.fromCharCode(this.bytes[p]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns the next n bytes as an ASCII string and advances the stream pointer
|
|
||||||
* n bytes.
|
|
||||||
* @param {number} n The number of bytes to read.
|
|
||||||
* @return {string} The next n bytes as a string.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteStream.prototype.readString = function(n) {
|
|
||||||
var strToReturn = this.peekString(n);
|
|
||||||
this.ptr += n;
|
|
||||||
return strToReturn;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A write-only Byte buffer which uses a Uint8 Typed Array as a backing store.
|
|
||||||
* @param {number} numBytes The number of bytes to allocate.
|
|
||||||
* @constructor
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer = function(numBytes) {
|
|
||||||
if (typeof numBytes !== typeof 1 || numBytes <= 0) {
|
|
||||||
throw "Error! ByteBuffer initialized with '" + numBytes + "'";
|
|
||||||
}
|
|
||||||
this.data = new Uint8Array(numBytes);
|
|
||||||
this.ptr = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {number} b The byte to insert.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer.prototype.insertByte = function(b) {
|
|
||||||
// TODO: throw if byte is invalid?
|
|
||||||
this.data[this.ptr++] = b;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {Array.<number>|Uint8Array|Int8Array} bytes The bytes to insert.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer.prototype.insertBytes = function(bytes) {
|
|
||||||
// TODO: throw if bytes is invalid?
|
|
||||||
this.data.set(bytes, this.ptr);
|
|
||||||
this.ptr += bytes.length;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes an unsigned number into the next n bytes. If the number is too large
|
|
||||||
* to fit into n bytes or is negative, an error is thrown.
|
|
||||||
* @param {number} num The unsigned number to write.
|
|
||||||
* @param {number} numBytes The number of bytes to write the number into.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer.prototype.writeNumber = function(num, numBytes) {
|
|
||||||
if (numBytes < 1) {
|
|
||||||
throw "Trying to write into too few bytes: " + numBytes;
|
|
||||||
}
|
|
||||||
if (num < 0) {
|
|
||||||
throw "Trying to write a negative number (" + num +
|
|
||||||
") as an unsigned number to an ArrayBuffer";
|
|
||||||
}
|
|
||||||
if (num > (Math.pow(2, numBytes * 8) - 1)) {
|
|
||||||
throw "Trying to write " + num + " into only " + numBytes + " bytes";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roll 8-bits at a time into an array of bytes.
|
|
||||||
var bytes = [];
|
|
||||||
while (numBytes-- > 0) {
|
|
||||||
var eightBits = num & 255;
|
|
||||||
bytes.push(eightBits);
|
|
||||||
num >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.insertBytes(bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Writes a signed number into the next n bytes. If the number is too large
|
|
||||||
* to fit into n bytes, an error is thrown.
|
|
||||||
* @param {number} num The signed number to write.
|
|
||||||
* @param {number} numBytes The number of bytes to write the number into.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer.prototype.writeSignedNumber = function(num, numBytes) {
|
|
||||||
if (numBytes < 1) {
|
|
||||||
throw "Trying to write into too few bytes: " + numBytes;
|
|
||||||
}
|
|
||||||
|
|
||||||
var HALF = Math.pow(2, (numBytes * 8) - 1);
|
|
||||||
if (num >= HALF || num < -HALF) {
|
|
||||||
throw "Trying to write " + num + " into only " + numBytes + " bytes";
|
|
||||||
}
|
|
||||||
|
|
||||||
// Roll 8-bits at a time into an array of bytes.
|
|
||||||
var bytes = [];
|
|
||||||
while (numBytes-- > 0) {
|
|
||||||
var eightBits = num & 255;
|
|
||||||
bytes.push(eightBits);
|
|
||||||
num >>= 8;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.insertBytes(bytes);
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @param {string} str The ASCII string to write.
|
|
||||||
*/
|
|
||||||
bitjs.io.ByteBuffer.prototype.writeASCIIString = function(str) {
|
|
||||||
for (var i = 0; i < str.length; ++i) {
|
|
||||||
var curByte = str.charCodeAt(i);
|
|
||||||
if (curByte < 0 || curByte > 255) {
|
|
||||||
throw "Trying to write a non-ASCII string!";
|
|
||||||
}
|
|
||||||
this.insertByte(curByte);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
35
cps/web.py
35
cps/web.py
|
@ -3171,13 +3171,22 @@ def new_user():
|
||||||
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||||
title=_(u"Add new user"))
|
title=_(u"Add new user"))
|
||||||
content.password = generate_password_hash(to_save["password"])
|
content.password = generate_password_hash(to_save["password"])
|
||||||
content.nickname = to_save["nickname"]
|
existing_user = ub.session.query(ub.User).filter(func.lower(ub.User.nickname) == to_save["nickname"].lower())\
|
||||||
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
.first()
|
||||||
flash(_(u"E-mail is not from valid domain"), category="error")
|
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"].lower())\
|
||||||
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
.first()
|
||||||
title=_(u"Add new user"))
|
if not existing_user and not existing_email:
|
||||||
|
content.nickname = to_save["nickname"]
|
||||||
|
if config.config_public_reg and not check_valid_domain(to_save["email"]):
|
||||||
|
flash(_(u"E-mail is not from valid domain"), category="error")
|
||||||
|
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||||
|
title=_(u"Add new user"))
|
||||||
|
else:
|
||||||
|
content.email = to_save["email"]
|
||||||
else:
|
else:
|
||||||
content.email = to_save["email"]
|
flash(_(u"Found an existing account for this e-mail address or nickname."), category="error")
|
||||||
|
return render_title_template("user_edit.html", new_user=1, content=content, translations=translations,
|
||||||
|
languages=languages, title=_(u"Add new user"), page="newuser")
|
||||||
try:
|
try:
|
||||||
ub.session.add(content)
|
ub.session.add(content)
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
|
@ -3362,14 +3371,24 @@ def edit_user(user_id):
|
||||||
if "locale" in to_save and to_save["locale"]:
|
if "locale" in to_save and to_save["locale"]:
|
||||||
content.locale = to_save["locale"]
|
content.locale = to_save["locale"]
|
||||||
if to_save["email"] and to_save["email"] != content.email:
|
if to_save["email"] and to_save["email"] != content.email:
|
||||||
content.email = to_save["email"]
|
existing_email = ub.session.query(ub.User).filter(ub.User.email == to_save["email"].lower()) \
|
||||||
|
.first()
|
||||||
|
if not existing_email:
|
||||||
|
content.email = to_save["email"]
|
||||||
|
else:
|
||||||
|
flash(_(u"Found an existing account for this e-mail address."), category="error")
|
||||||
|
return render_title_template("user_edit.html", translations=translations, languages=languages,
|
||||||
|
new_user=0, content=content, downloads=downloads,
|
||||||
|
title=_(u"Edit User %(nick)s", nick=content.nickname), page="edituser")
|
||||||
|
|
||||||
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
|
if "kindle_mail" in to_save and to_save["kindle_mail"] != content.kindle_mail:
|
||||||
content.kindle_mail = to_save["kindle_mail"]
|
content.kindle_mail = to_save["kindle_mail"]
|
||||||
try:
|
try:
|
||||||
ub.session.commit()
|
ub.session.commit()
|
||||||
flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success")
|
flash(_(u"User '%(nick)s' updated", nick=content.nickname), category="success")
|
||||||
except IntegrityError:
|
except IntegrityError as e:
|
||||||
ub.session.rollback()
|
ub.session.rollback()
|
||||||
|
print(e)
|
||||||
flash(_(u"An unknown error occured."), category="error")
|
flash(_(u"An unknown error occured."), category="error")
|
||||||
return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0,
|
return render_title_template("user_edit.html", translations=translations, languages=languages, new_user=0,
|
||||||
content=content, downloads=downloads, title=_(u"Edit User %(nick)s",
|
content=content, downloads=downloads, title=_(u"Edit User %(nick)s",
|
||||||
|
|
|
@ -20,7 +20,7 @@
|
||||||
from __future__ import print_function
|
from __future__ import print_function
|
||||||
import smtplib
|
import smtplib
|
||||||
import threading
|
import threading
|
||||||
from datetime import datetime
|
from datetime import datetime, timedelta
|
||||||
import logging
|
import logging
|
||||||
import time
|
import time
|
||||||
import socket
|
import socket
|
||||||
|
@ -221,8 +221,10 @@ class WorkerThread(threading.Thread):
|
||||||
if self.UIqueue[self.current]['stat'] == STAT_STARTED:
|
if self.UIqueue[self.current]['stat'] == STAT_STARTED:
|
||||||
if self.queue[self.current]['taskType'] == TASK_EMAIL:
|
if self.queue[self.current]['taskType'] == TASK_EMAIL:
|
||||||
self.UIqueue[self.current]['progress'] = self.get_send_status()
|
self.UIqueue[self.current]['progress'] = self.get_send_status()
|
||||||
self.UIqueue[self.current]['runtime'] = self._formatRuntime(
|
self.UIqueue[self.current]['formRuntime'] = datetime.now() - self.queue[self.current]['starttime']
|
||||||
datetime.now() - self.queue[self.current]['starttime'])
|
self.UIqueue[self.current]['rt'] = self.UIqueue[self.current]['formRuntime'].days*24*60 \
|
||||||
|
+ self.UIqueue[self.current]['formRuntime'].seconds \
|
||||||
|
+ self.UIqueue[self.current]['formRuntime'].microseconds
|
||||||
return self.UIqueue
|
return self.UIqueue
|
||||||
|
|
||||||
def _convert_any_format(self):
|
def _convert_any_format(self):
|
||||||
|
@ -259,7 +261,8 @@ class WorkerThread(threading.Thread):
|
||||||
self._handleSuccess()
|
self._handleSuccess()
|
||||||
return file_path + format_new_ext
|
return file_path + format_new_ext
|
||||||
else:
|
else:
|
||||||
web.app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.", bookid, format_new_ext)
|
web.app.logger.info("Book id %d - target format of %s does not exist. Moving forward with convert.",
|
||||||
|
bookid, format_new_ext)
|
||||||
|
|
||||||
# check if converter-executable is existing
|
# check if converter-executable is existing
|
||||||
if not os.path.exists(web.ub.config.config_converterpath):
|
if not os.path.exists(web.ub.config.config_converterpath):
|
||||||
|
@ -300,7 +303,7 @@ class WorkerThread(threading.Thread):
|
||||||
if sys.version_info < (3, 0):
|
if sys.version_info < (3, 0):
|
||||||
command = [x.encode(sys.getfilesystemencoding()) for x in command]
|
command = [x.encode(sys.getfilesystemencoding()) for x in command]
|
||||||
|
|
||||||
p = subprocess.Popen(command, stdout=subprocess.PIPE, universal_newlines=True)
|
p = subprocess.Popen(command, stdout=subprocess.PIPE, stderr=subprocess.PIPE, universal_newlines=True)
|
||||||
except OSError as e:
|
except OSError as e:
|
||||||
self._handleError(_(u"Ebook-converter failed: %(error)s", error=e))
|
self._handleError(_(u"Ebook-converter failed: %(error)s", error=e))
|
||||||
return
|
return
|
||||||
|
@ -328,6 +331,11 @@ class WorkerThread(threading.Thread):
|
||||||
|
|
||||||
# process returncode
|
# process returncode
|
||||||
check = p.returncode
|
check = p.returncode
|
||||||
|
calibre_traceback = p.stderr.readlines()
|
||||||
|
for ele in calibre_traceback:
|
||||||
|
web.app.logger.debug(ele.strip('\n'))
|
||||||
|
if not ele.startswith('Traceback') and not ele.startswith(' File'):
|
||||||
|
error_message = "Calibre failed with error: %s" % ele.strip('\n')
|
||||||
|
|
||||||
# kindlegen returncodes
|
# kindlegen returncodes
|
||||||
# 0 = Info(prcgen):I1036: Mobi file built successfully
|
# 0 = Info(prcgen):I1036: Mobi file built successfully
|
||||||
|
@ -481,31 +489,17 @@ class WorkerThread(threading.Thread):
|
||||||
self._handleError(u'Error sending email: ' + e.strerror)
|
self._handleError(u'Error sending email: ' + e.strerror)
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def _formatRuntime(self, runtime):
|
|
||||||
self.UIqueue[self.current]['rt'] = runtime.total_seconds()
|
|
||||||
val = re.split('\:|\.', str(runtime))[0:3]
|
|
||||||
erg = list()
|
|
||||||
for v in val:
|
|
||||||
if int(v) > 0:
|
|
||||||
erg.append(v)
|
|
||||||
retVal = (':'.join(erg)).lstrip('0') + ' s'
|
|
||||||
if retVal == ' s':
|
|
||||||
retVal = '0 s'
|
|
||||||
return retVal
|
|
||||||
|
|
||||||
def _handleError(self, error_message):
|
def _handleError(self, error_message):
|
||||||
web.app.logger.error(error_message)
|
web.app.logger.error(error_message)
|
||||||
self.UIqueue[self.current]['stat'] = STAT_FAIL
|
self.UIqueue[self.current]['stat'] = STAT_FAIL
|
||||||
self.UIqueue[self.current]['progress'] = "100 %"
|
self.UIqueue[self.current]['progress'] = "100 %"
|
||||||
self.UIqueue[self.current]['runtime'] = self._formatRuntime(
|
self.UIqueue[self.current]['formRuntime'] = datetime.now() - self.queue[self.current]['starttime']
|
||||||
datetime.now() - self.queue[self.current]['starttime'])
|
|
||||||
self.UIqueue[self.current]['message'] = error_message
|
self.UIqueue[self.current]['message'] = error_message
|
||||||
|
|
||||||
def _handleSuccess(self):
|
def _handleSuccess(self):
|
||||||
self.UIqueue[self.current]['stat'] = STAT_FINISH_SUCCESS
|
self.UIqueue[self.current]['stat'] = STAT_FINISH_SUCCESS
|
||||||
self.UIqueue[self.current]['progress'] = "100 %"
|
self.UIqueue[self.current]['progress'] = "100 %"
|
||||||
self.UIqueue[self.current]['runtime'] = self._formatRuntime(
|
self.UIqueue[self.current]['formRuntime'] = datetime.now() - self.queue[self.current]['starttime']
|
||||||
datetime.now() - self.queue[self.current]['starttime'])
|
|
||||||
|
|
||||||
|
|
||||||
# Enable logging of smtp lib debug output
|
# Enable logging of smtp lib debug output
|
||||||
|
|
Loading…
Reference in New Issue
Block a user