mirror of
https://github.com/evilhero/mylar
synced 2025-03-09 05:13:35 +00:00
FIX:(#1198) Updated py-unrar2 to latest version + patched to fix date format errors which was causing problems with ComicTagger and converting cbr-to-cbz, FIX: small typos in Config and Manage pages.
This commit is contained in:
parent
52d0b29702
commit
81f8a4b76d
8 changed files with 166 additions and 34 deletions
|
@ -312,8 +312,8 @@
|
|||
</div>
|
||||
|
||||
<div class="row checkbox left clearfix">
|
||||
<input id="sab_to_mylar" type="checkbox" onclick="initConfigCheckbox($(this));" name="sab_to_mylar" value="1" ${config['sab_to_mylar']} /><label>Are Mylar / SABnzbd on seperate machines</label>
|
||||
<small class="heading"><span style="float: left; margin-right: .3em; margin-top: 4px;" class="ui-icon ui-icon-info"></span>This is *ONLY* required if Mylar and SABnzbd are on seperate machines, otherwise don't touch it</small>
|
||||
<input id="sab_to_mylar" type="checkbox" onclick="initConfigCheckbox($(this));" name="sab_to_mylar" value="1" ${config['sab_to_mylar']} /><label>Are Mylar / SABnzbd on separate machines</label>
|
||||
<small class="heading"><span style="float: left; margin-right: .3em; margin-top: 4px;" class="ui-icon ui-icon-info"></span>This is *ONLY* required if Mylar and SABnzbd are on separate machines, otherwise don't touch it</small>
|
||||
</div>
|
||||
<div class="config">
|
||||
<div class="row">
|
||||
|
|
|
@ -116,7 +116,7 @@
|
|||
<legend>Force Options</legend>
|
||||
<a href="#" onclick="doAjaxCall('forceSearch',$(this))" data-success="Checking for wanted issues successful" data-error="Error checking wanted issues"><span class="ui-icon ui-icon-search"></span>Force Check for Wanted Issues</a>
|
||||
<a href="#" onclick="doAjaxCall('forceUpdate',$(this))" data-success="Update active comics successful" data-error="Error forcing update Comics"><span class="ui-icon ui-icon-heart"></span>Force Update Active Comics</a>
|
||||
<a href="#" onclick="doAjaxCall('checkGithub',$(this))" data-success="Checking for update successful" data-error="Error checking for update"><span class="ui-icon ui-icon-refresh"></span>Check for mylar Updates</a>
|
||||
<a href="#" onclick="doAjaxCall('checkGithub',$(this))" data-success="Checking for update successful" data-error="Error checking for update"><span class="ui-icon ui-icon-refresh"></span>Check for Mylar Updates</a>
|
||||
</div>
|
||||
</fieldset>
|
||||
</td>
|
||||
|
|
11
lib/comictaggerlib/UnRAR2/README.md
Normal file
11
lib/comictaggerlib/UnRAR2/README.md
Normal file
|
@ -0,0 +1,11 @@
|
|||
pyUnRAR2 is a Python (ctypes-based) wrapper around the free UnRAR.dll (Windows) or command-line unrar binary (Unix).
|
||||
|
||||
It is an modified version of Jimmy Retzlaff's pyUnRAR - more simple,
|
||||
stable and foolproof, with Unix support added.
|
||||
Notice that it has INCOMPATIBLE interface.
|
||||
|
||||
It enables reading and unpacking of archives created with the RAR/WinRAR archivers.
|
||||
|
||||
Downloads:
|
||||
https://drive.google.com/folderview?id=0B6L2WW4Bg4jvMnFtbjRKOUtDQTQ&usp=sharing#list
|
||||
|
|
@ -33,7 +33,7 @@ similar to the C interface provided by UnRAR. There is also a
|
|||
higher level interface which makes some common operations easier.
|
||||
"""
|
||||
|
||||
__version__ = '0.99.3'
|
||||
__version__ = '0.99.6'
|
||||
|
||||
try:
|
||||
WindowsError
|
||||
|
@ -74,8 +74,6 @@ class RarInfo(object):
|
|||
self.size = data['size']
|
||||
self.datetime = data['datetime']
|
||||
self.comment = data['comment']
|
||||
|
||||
|
||||
|
||||
def __str__(self):
|
||||
try :
|
||||
|
@ -159,6 +157,11 @@ class RarFile(RarFileImplementation):
|
|||
checker = condition2checker(condition)
|
||||
return RarFileImplementation.extract(self, checker, path, withSubpath, overwrite)
|
||||
|
||||
def get_volume(self):
|
||||
"""Determine which volume is it in a multi-volume archive. Returns None if it's not a
|
||||
multi-volume archive, 0-based volume number otherwise."""
|
||||
return RarFileImplementation.get_volume(self)
|
||||
|
||||
def condition2checker(condition):
|
||||
"""Converts different condition types to callback"""
|
||||
if type(condition) in [str, unicode]:
|
||||
|
|
|
@ -15,6 +15,7 @@ def cleanup(dir='test'):
|
|||
# basic test
|
||||
cleanup()
|
||||
rarc = UnRAR2.RarFile('test.rar')
|
||||
assert rarc.get_volume() == None
|
||||
rarc.infolist()
|
||||
assert rarc.comment == "This is a test."
|
||||
for info in rarc.infoiter():
|
||||
|
@ -28,6 +29,21 @@ del rarc
|
|||
assert (str(saveinfo)=="""<RarInfo "test" in "[ARCHIVE_NO_LONGER_LOADED]">""")
|
||||
cleanup()
|
||||
|
||||
# shell-unsafe-name test
|
||||
cleanup()
|
||||
rarc = UnRAR2.RarFile('[test].rar')
|
||||
rarc.infolist()
|
||||
for info in rarc.infoiter():
|
||||
saveinfo = info
|
||||
assert (str(info)=="""<RarInfo "[test].txt" in "[test].rar">""")
|
||||
break
|
||||
rarc.extract()
|
||||
assert os.path.exists('[test].txt')
|
||||
del rarc
|
||||
assert (str(saveinfo)=="""<RarInfo "[test].txt" in "[ARCHIVE_NO_LONGER_LOADED]">""")
|
||||
cleanup()
|
||||
|
||||
|
||||
# extract all the files in test.rar
|
||||
cleanup()
|
||||
UnRAR2.RarFile('test.rar').extract()
|
||||
|
@ -108,6 +124,15 @@ except IncorrectRARPassword:
|
|||
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||
assert errored
|
||||
cleanup()
|
||||
errored = False
|
||||
try:
|
||||
UnRAR2.RarFile('test_protected_files.rar').extract()
|
||||
except IncorrectRARPassword:
|
||||
errored = True
|
||||
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||
assert errored
|
||||
cleanup()
|
||||
|
||||
|
||||
# extract files from an archive with protected headers
|
||||
cleanup()
|
||||
|
@ -122,6 +147,27 @@ except IncorrectRARPassword:
|
|||
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||
assert errored
|
||||
cleanup()
|
||||
errored = False
|
||||
try:
|
||||
UnRAR2.RarFile('test_protected_headers.rar').extract()
|
||||
except IncorrectRARPassword:
|
||||
errored = True
|
||||
assert not os.path.exists('test'+os.sep+'top_secret_xxx_file.txt')
|
||||
assert errored
|
||||
cleanup()
|
||||
|
||||
# check volume number
|
||||
cleanup()
|
||||
rarc1 = UnRAR2.RarFile('test_volumes.part1.rar')
|
||||
assert rarc1.get_volume() == 0
|
||||
rarc2 = UnRAR2.RarFile('test_volumes.part2.rar')
|
||||
assert rarc2.get_volume() == 1
|
||||
cleanup()
|
||||
rarc1 = UnRAR2.RarFile('test_volumes_old.rar')
|
||||
assert rarc1.get_volume() == 0
|
||||
rarc2 = UnRAR2.RarFile('test_volumes_old.r00')
|
||||
assert rarc2.get_volume() == 1
|
||||
cleanup()
|
||||
|
||||
# make sure docstring examples are working
|
||||
import doctest
|
||||
|
|
|
@ -48,7 +48,7 @@ def call_unrar(params):
|
|||
pass
|
||||
if rar_executable_cached is None:
|
||||
raise UnpackerNotInstalled("No suitable RAR unpacker installed")
|
||||
|
||||
|
||||
assert type(params) == list, "params must be list"
|
||||
args = [rar_executable_cached] + params
|
||||
try:
|
||||
|
@ -62,25 +62,25 @@ class RarFileImplementation(object):
|
|||
def init(self, password=None):
|
||||
global rar_executable_version
|
||||
self.password = password
|
||||
|
||||
|
||||
|
||||
|
||||
stdoutdata, stderrdata = self.call('v', []).communicate()
|
||||
|
||||
|
||||
for line in stderrdata.splitlines():
|
||||
if line.strip().startswith("Cannot open"):
|
||||
raise FileOpenError
|
||||
if line.find("CRC failed")>=0:
|
||||
raise IncorrectRARPassword
|
||||
raise IncorrectRARPassword
|
||||
accum = []
|
||||
source = iter(stdoutdata.splitlines())
|
||||
line = ''
|
||||
while not (line.startswith('UNRAR')):
|
||||
while (line.find('RAR ') == -1):
|
||||
line = source.next()
|
||||
signature = line
|
||||
# The code below is mighty flaky
|
||||
# and will probably crash on localized versions of RAR
|
||||
# but I see no safe way to rewrite it using a CLI tool
|
||||
if signature.startswith("UNRAR 4"):
|
||||
if signature.find("RAR 4") > -1:
|
||||
rar_executable_version = 4
|
||||
while not (line.startswith('Comment:') or line.startswith('Pathname/Comment')):
|
||||
if line.strip().endswith('is not RAR archive'):
|
||||
|
@ -94,7 +94,7 @@ class RarFileImplementation(object):
|
|||
self.comment = '\n'.join(accum[:-1])
|
||||
else:
|
||||
self.comment = None
|
||||
elif signature.startswith("UNRAR 5"):
|
||||
elif signature.find("RAR 5") > -1:
|
||||
rar_executable_version = 5
|
||||
line = source.next()
|
||||
while not line.startswith('Archive:'):
|
||||
|
@ -107,14 +107,14 @@ class RarFileImplementation(object):
|
|||
else:
|
||||
self.comment = None
|
||||
else:
|
||||
raise UnpackerNotInstalled("Unsupported RAR version, expected 4.x or 5.x, found: "
|
||||
raise UnpackerNotInstalled("Unsupported RAR version, expected 4.x or 5.x, found: "
|
||||
+ signature.split(" ")[1])
|
||||
|
||||
|
||||
|
||||
|
||||
def escaped_password(self):
|
||||
return '-' if self.password == None else self.password
|
||||
|
||||
|
||||
|
||||
|
||||
def call(self, cmd, options=[], files=[]):
|
||||
options2 = options + ['p'+self.escaped_password()]
|
||||
soptions = ['-'+x for x in options2]
|
||||
|
@ -136,7 +136,7 @@ class RarFileImplementation(object):
|
|||
if line.strip().endswith('is not RAR archive'):
|
||||
raise InvalidRARArchive
|
||||
if line.startswith("CRC failed") or line.startswith("Checksum error"):
|
||||
raise IncorrectRARPassword
|
||||
raise IncorrectRARPassword
|
||||
line = source.next()
|
||||
line = source.next()
|
||||
i = 0
|
||||
|
@ -153,8 +153,13 @@ class RarFileImplementation(object):
|
|||
data['size'] = int(fields[0])
|
||||
attr = fields[5]
|
||||
data['isdir'] = 'd' in attr.lower()
|
||||
data['datetime'] = time.strptime(fields[3]+" "+fields[4], '%d-%m-%y %H:%M')
|
||||
try:
|
||||
data['datetime'] = time.strptime(fields[3]+" "+fields[4], '%d-%m-%y %H:%M')
|
||||
except ValueError:
|
||||
data['datetime'] = time.strptime(fields[3]+" "+fields[4], '%Y-%m-%d %H:%M')
|
||||
|
||||
data['comment'] = None
|
||||
data['volume'] = None
|
||||
yield data
|
||||
accum = []
|
||||
i += 1
|
||||
|
@ -168,12 +173,17 @@ class RarFileImplementation(object):
|
|||
data['size'] = int(fields[1])
|
||||
attr = fields[0]
|
||||
data['isdir'] = 'd' in attr.lower()
|
||||
data['datetime'] = time.strptime(fields[2]+" "+fields[3], '%d-%m-%y %H:%M')
|
||||
try:
|
||||
data['datetime'] = time.strptime(fields[2]+" "+fields[3], '%d-%m-%y %H:%M')
|
||||
except ValueError:
|
||||
data['datetime'] = time.strptime(fields[2]+" "+fields[3], '%Y-%m-%d %H:%M')
|
||||
|
||||
data['comment'] = None
|
||||
data['volume'] = None
|
||||
yield data
|
||||
i += 1
|
||||
line = source.next()
|
||||
|
||||
|
||||
|
||||
def read_files(self, checker):
|
||||
res = []
|
||||
|
@ -184,7 +194,7 @@ class RarFileImplementation(object):
|
|||
res.append((info, pipe.read()))
|
||||
return res
|
||||
|
||||
|
||||
|
||||
def extract(self, checker, path, withSubpath, overwrite):
|
||||
res = []
|
||||
command = 'x'
|
||||
|
@ -209,10 +219,45 @@ class RarFileImplementation(object):
|
|||
proc = self.call(command, options, names)
|
||||
stdoutdata, stderrdata = proc.communicate()
|
||||
if stderrdata.find("CRC failed")>=0 or stderrdata.find("Checksum error")>=0:
|
||||
raise IncorrectRARPassword
|
||||
return res
|
||||
|
||||
raise IncorrectRARPassword
|
||||
return res
|
||||
|
||||
def destruct(self):
|
||||
pass
|
||||
|
||||
|
||||
def get_volume(self):
|
||||
command = "v" if rar_executable_version == 4 else "l"
|
||||
stdoutdata, stderrdata = self.call(command, ['c-']).communicate()
|
||||
|
||||
for line in stderrdata.splitlines():
|
||||
if line.strip().startswith("Cannot open"):
|
||||
raise FileOpenError
|
||||
|
||||
source = iter(stdoutdata.splitlines())
|
||||
line = ''
|
||||
while not line.startswith('-----------'):
|
||||
if line.strip().endswith('is not RAR archive'):
|
||||
raise InvalidRARArchive
|
||||
if line.startswith("CRC failed") or line.startswith("Checksum error"):
|
||||
raise IncorrectRARPassword
|
||||
line = source.next()
|
||||
line = source.next()
|
||||
if rar_executable_version == 4:
|
||||
while not line.startswith('-----------'):
|
||||
line = source.next()
|
||||
line = source.next()
|
||||
items = line.strip().split()
|
||||
if len(items)>4 and items[4]=="volume":
|
||||
return int(items[5]) - 1
|
||||
else:
|
||||
return None
|
||||
|
||||
elif rar_executable_version == 5:
|
||||
while not line.startswith('-----------'):
|
||||
line = source.next()
|
||||
line = source.next()
|
||||
items = line.strip().split()
|
||||
if items[1]=="volume":
|
||||
return int(items[2]) - 1
|
||||
else:
|
||||
return None
|
||||
|
|
|
@ -25,7 +25,7 @@
|
|||
from __future__ import generators
|
||||
|
||||
import ctypes, ctypes.wintypes
|
||||
import os, os.path, sys
|
||||
import os, os.path, sys, re
|
||||
import Queue
|
||||
import time
|
||||
|
||||
|
@ -43,6 +43,7 @@ ERAR_EREAD = 18
|
|||
ERAR_EWRITE = 19
|
||||
ERAR_SMALL_BUF = 20
|
||||
ERAR_UNKNOWN = 21
|
||||
ERAR_MISSING_PASSWORD = 22
|
||||
|
||||
RAR_OM_LIST = 0
|
||||
RAR_OM_EXTRACT = 1
|
||||
|
@ -66,6 +67,9 @@ dll_name = "unrar.dll"
|
|||
if architecture_bits == 64:
|
||||
dll_name = "x64\\unrar64.dll"
|
||||
|
||||
volume_naming1 = re.compile("\.r([0-9]{2})$")
|
||||
volume_naming2 = re.compile("\.([0-9]{3}).rar$")
|
||||
volume_naming3 = re.compile("\.part([0-9]+).rar$")
|
||||
|
||||
try:
|
||||
unrar = ctypes.WinDLL(os.path.join(os.path.split(__file__)[0], 'UnRARDLL', dll_name))
|
||||
|
@ -188,7 +192,7 @@ class RarInfoIterator(object):
|
|||
self.index = 0
|
||||
self.headerData = RARHeaderDataEx()
|
||||
self.res = RARReadHeaderEx(self.arc._handle, ctypes.byref(self.headerData))
|
||||
if self.res==ERAR_BAD_DATA:
|
||||
if self.res in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
|
||||
raise IncorrectRARPassword
|
||||
self.arc.lockStatus = "locked"
|
||||
self.arc.needskip = False
|
||||
|
@ -208,7 +212,7 @@ class RarInfoIterator(object):
|
|||
|
||||
data = {}
|
||||
data['index'] = self.index
|
||||
data['filename'] = self.headerData.FileName
|
||||
data['filename'] = self.headerData.FileNameW
|
||||
data['datetime'] = DosDateTimeToTimeTuple(self.headerData.FileTime)
|
||||
data['isdir'] = ((self.headerData.Flags & 0xE0) == 0xE0)
|
||||
data['size'] = self.headerData.UnpSize + (self.headerData.UnpSizeHigh << 32)
|
||||
|
@ -251,7 +255,8 @@ class RarFileImplementation(object):
|
|||
RARSetPassword(self._handle, password)
|
||||
|
||||
self.lockStatus = "ready"
|
||||
|
||||
|
||||
self.isVolume = archiveData.Flags & 1
|
||||
|
||||
|
||||
def destruct(self):
|
||||
|
@ -277,7 +282,7 @@ class RarFileImplementation(object):
|
|||
c_callback = UNRARCALLBACK(reader._callback)
|
||||
RARSetCallback(self._handle, c_callback, 1)
|
||||
tmpres = RARProcessFile(self._handle, RAR_TEST, None, None)
|
||||
if tmpres==ERAR_BAD_DATA:
|
||||
if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
|
||||
raise IncorrectRARPassword
|
||||
self.needskip = False
|
||||
res.append((info, reader.get_result()))
|
||||
|
@ -299,11 +304,29 @@ class RarFileImplementation(object):
|
|||
target = checkres
|
||||
if overwrite or (not os.path.exists(target)):
|
||||
tmpres = RARProcessFile(self._handle, RAR_EXTRACT, None, target)
|
||||
if tmpres==ERAR_BAD_DATA:
|
||||
if tmpres in [ERAR_BAD_DATA, ERAR_MISSING_PASSWORD]:
|
||||
raise IncorrectRARPassword
|
||||
|
||||
self.needskip = False
|
||||
res.append(info)
|
||||
return res
|
||||
|
||||
def get_volume(self):
|
||||
if not self.isVolume:
|
||||
return None
|
||||
headerData = RARHeaderDataEx()
|
||||
res = RARReadHeaderEx(self._handle, ctypes.byref(headerData))
|
||||
arcName = headerData.ArcNameW
|
||||
match3 = volume_naming3.search(arcName)
|
||||
if match3 != None:
|
||||
return int(match3.group(1)) - 1
|
||||
match2 = volume_naming3.search(arcName)
|
||||
if match2 != None:
|
||||
return int(match2.group(1))
|
||||
match1 = volume_naming1.search(arcName)
|
||||
if match1 != None:
|
||||
return int(match1.group(1)) + 1
|
||||
return 0
|
||||
|
||||
|
||||
|
||||
|
|
|
@ -238,6 +238,10 @@ def run(dirName, nzbName=None, issueid=None, comversion=None, manual=None, filen
|
|||
initial_ctrun = False
|
||||
elif initial_ctrun and 'Archive is not a RAR' in out:
|
||||
initial_ctrun = False
|
||||
elif initial_ctrun:
|
||||
logger.warn(module + '[COMIC-TAGGER][CBR-TO-CBZ] Failed to convert cbr to cbz - check permissions on folder : ' + mylar.CACHE_DIR + ' and/or the location where Mylar is trying to tag the files from.')
|
||||
initial_ctrun = False
|
||||
return 'fail'
|
||||
elif 'Cannot find' in out:
|
||||
logger.warn(module + '[COMIC-TAGGER] Unable to locate file: ' + filename)
|
||||
file_error = 'file not found||' + filename
|
||||
|
|
Loading…
Add table
Reference in a new issue