mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Auto-adding: Do not add incomplete files when files are downloaded directly into the auto add folder. Fixes #926578 (Automatic adding produces duplicate entries for downloaded files)
This commit is contained in:
parent
c8c3bbb76f
commit
4297aa3c86
@ -222,6 +222,11 @@ def forked_read_metadata(path, tdir):
|
|||||||
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
||||||
with open(path, 'rb') as f:
|
with open(path, 'rb') as f:
|
||||||
fmt = os.path.splitext(path)[1][1:].lower()
|
fmt = os.path.splitext(path)[1][1:].lower()
|
||||||
|
f.seek(0, 2)
|
||||||
|
sz = f.tell()
|
||||||
|
with open(os.path.join(tdir, 'size.txt'), 'wb') as s:
|
||||||
|
s.write(str(sz).encode('ascii'))
|
||||||
|
f.seek(0)
|
||||||
mi = get_metadata(f, fmt)
|
mi = get_metadata(f, fmt)
|
||||||
if mi.cover_data and mi.cover_data[1]:
|
if mi.cover_data and mi.cover_data[1]:
|
||||||
with open(os.path.join(tdir, 'cover.jpg'), 'wb') as f:
|
with open(os.path.join(tdir, 'cover.jpg'), 'wb') as f:
|
||||||
|
@ -7,7 +7,7 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2012, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
import os, tempfile, shutil
|
import os, tempfile, shutil, time
|
||||||
from threading import Thread, Event
|
from threading import Thread, Event
|
||||||
|
|
||||||
from PyQt4.Qt import (QFileSystemWatcher, QObject, Qt, pyqtSignal, QTimer)
|
from PyQt4.Qt import (QFileSystemWatcher, QObject, Qt, pyqtSignal, QTimer)
|
||||||
@ -41,25 +41,58 @@ class Worker(Thread):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
def auto_add(self):
|
def auto_add(self):
|
||||||
from calibre.utils.ipc.simple_worker import fork_job
|
from calibre.utils.ipc.simple_worker import fork_job, WorkerError
|
||||||
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
from calibre.ebooks.metadata.opf2 import metadata_to_opf
|
||||||
from calibre.ebooks.metadata.meta import metadata_from_filename
|
from calibre.ebooks.metadata.meta import metadata_from_filename
|
||||||
|
|
||||||
files = [x for x in os.listdir(self.path) if x not in self.staging
|
files = [x for x in os.listdir(self.path) if
|
||||||
and os.path.isfile(os.path.join(self.path, x)) and
|
# Must not be in the process of being added to the db
|
||||||
os.access(os.path.join(self.path, x), os.R_OK|os.W_OK) and
|
x not in self.staging
|
||||||
os.path.splitext(x)[1][1:].lower() in self.be]
|
# Firefox creates 0 byte placeholder files when downloading
|
||||||
|
and os.stat(os.path.join(self.path, x)).st_size > 0
|
||||||
|
# Must be a file
|
||||||
|
and os.path.isfile(os.path.join(self.path, x))
|
||||||
|
# Must have read and write permissions
|
||||||
|
and os.access(os.path.join(self.path, x), os.R_OK|os.W_OK)
|
||||||
|
# Must be a known ebook file type
|
||||||
|
and os.path.splitext(x)[1][1:].lower() in self.be
|
||||||
|
]
|
||||||
data = {}
|
data = {}
|
||||||
|
# Give any in progress copies time to complete
|
||||||
|
time.sleep(2)
|
||||||
|
|
||||||
for fname in files:
|
for fname in files:
|
||||||
f = os.path.join(self.path, fname)
|
f = os.path.join(self.path, fname)
|
||||||
|
|
||||||
|
# Try opening the file for reading, if the OS prevents us, then at
|
||||||
|
# least on windows, it means the file is open in another
|
||||||
|
# application for writing. We will get notified by
|
||||||
|
# QFileSystemWatcher when writing is completed, so ignore for now.
|
||||||
|
try:
|
||||||
|
open(f, 'rb').close()
|
||||||
|
except:
|
||||||
|
continue
|
||||||
tdir = tempfile.mkdtemp(dir=self.tdir)
|
tdir = tempfile.mkdtemp(dir=self.tdir)
|
||||||
try:
|
try:
|
||||||
fork_job('calibre.ebooks.metadata.meta',
|
fork_job('calibre.ebooks.metadata.meta',
|
||||||
'forked_read_metadata', (f, tdir), no_output=True)
|
'forked_read_metadata', (f, tdir), no_output=True)
|
||||||
|
except WorkerError as e:
|
||||||
|
prints('Failed to read metadata from:', fname)
|
||||||
|
prints(e.orig_tb)
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
|
# Ensure that the pre-metadata file size is present. If it isn't,
|
||||||
|
# write 0 so that the file is rescanned
|
||||||
|
szpath = os.path.join(tdir, 'size.txt')
|
||||||
|
try:
|
||||||
|
with open(szpath, 'rb') as f:
|
||||||
|
int(f.read())
|
||||||
|
except:
|
||||||
|
with open(szpath, 'wb') as f:
|
||||||
|
f.write(b'0')
|
||||||
|
|
||||||
opfpath = os.path.join(tdir, 'metadata.opf')
|
opfpath = os.path.join(tdir, 'metadata.opf')
|
||||||
try:
|
try:
|
||||||
if os.stat(opfpath).st_size < 30:
|
if os.stat(opfpath).st_size < 30:
|
||||||
@ -125,8 +158,23 @@ class AutoAdder(QObject):
|
|||||||
m = gui.library_view.model()
|
m = gui.library_view.model()
|
||||||
count = 0
|
count = 0
|
||||||
|
|
||||||
|
needs_rescan = False
|
||||||
|
|
||||||
for fname, tdir in data.iteritems():
|
for fname, tdir in data.iteritems():
|
||||||
paths = [os.path.join(self.worker.path, fname)]
|
paths = [os.path.join(self.worker.path, fname)]
|
||||||
|
sz = os.path.join(tdir, 'size.txt')
|
||||||
|
if not os.access(sz, os.R_OK):
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
with open(sz, 'rb') as f:
|
||||||
|
sz = int(f.read())
|
||||||
|
if sz != os.stat(paths[0]).st_size:
|
||||||
|
raise Exception('Looks like the file was written to after'
|
||||||
|
' we tried to read metadata')
|
||||||
|
except:
|
||||||
|
needs_rescan = True
|
||||||
|
continue
|
||||||
|
|
||||||
mi = os.path.join(tdir, 'metadata.opf')
|
mi = os.path.join(tdir, 'metadata.opf')
|
||||||
if not os.access(mi, os.R_OK):
|
if not os.access(mi, os.R_OK):
|
||||||
continue
|
continue
|
||||||
@ -135,7 +183,7 @@ class AutoAdder(QObject):
|
|||||||
m.add_books(paths, [os.path.splitext(fname)[1][1:].upper()], mi,
|
m.add_books(paths, [os.path.splitext(fname)[1][1:].upper()], mi,
|
||||||
add_duplicates=True)
|
add_duplicates=True)
|
||||||
try:
|
try:
|
||||||
os.remove(os.path.join(self.worker.path, fname))
|
os.remove(paths[0])
|
||||||
try:
|
try:
|
||||||
self.worker.staging.remove(fname)
|
self.worker.staging.remove(fname)
|
||||||
except KeyError:
|
except KeyError:
|
||||||
@ -153,4 +201,7 @@ class AutoAdder(QObject):
|
|||||||
if hasattr(gui, 'db_images'):
|
if hasattr(gui, 'db_images'):
|
||||||
gui.db_images.reset()
|
gui.db_images.reset()
|
||||||
|
|
||||||
|
if needs_rescan:
|
||||||
|
QTimer.singleShot(2000, self.dir_changed)
|
||||||
|
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from calibre.utils.ipc.launch import Worker
|
|||||||
class WorkerError(Exception):
|
class WorkerError(Exception):
|
||||||
def __init__(self, msg, orig_tb=''):
|
def __init__(self, msg, orig_tb=''):
|
||||||
Exception.__init__(self, msg)
|
Exception.__init__(self, msg)
|
||||||
self.org_tb = orig_tb
|
self.orig_tb = orig_tb
|
||||||
|
|
||||||
class ConnectedWorker(Thread):
|
class ConnectedWorker(Thread):
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user