mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Allow import of KFX files from MTP Kindle devices rev 2
This commit is contained in:
parent
ea4aebf878
commit
45d7c87462
@ -114,8 +114,9 @@ class MTP_DEVICE(BASE):
|
||||
'pictures', 'ringtones', 'samsung', 'sony', 'htc', 'bluetooth', 'fonts',
|
||||
'games', 'lost.dir', 'video', 'whatsapp', 'image', 'com.zinio.mobile.android.reader'}:
|
||||
return True
|
||||
if lpath[0].startswith('.') and lpath[0] != '.tolino':
|
||||
if lpath[0].startswith('.') and lpath[0] != '.tolino' and lpath[0] != '.notebooks':
|
||||
# apparently the Tolino for some reason uses a hidden folder for its library, sigh.
|
||||
# Kindle Scribe stores user notebooks in subfolders of '.notebooks'
|
||||
return True
|
||||
if lpath[0] == 'system' and not self.is_kindle:
|
||||
# on Kindles we need the system/thumbnails folder for the amazon cover bug workaround
|
||||
@ -349,6 +350,21 @@ class MTP_DEVICE(BASE):
|
||||
from calibre.customize.ui import quick_metadata
|
||||
from calibre.ebooks.metadata.meta import get_metadata
|
||||
ext = mtp_file.name.rpartition('.')[-1].lower()
|
||||
if self.is_kindle and ext == 'kfx' and mtp_file.name != 'metadata.kfx':
|
||||
# locate the actual file containing KFX book metadata
|
||||
stream = BytesIO()
|
||||
try:
|
||||
self.get_file_by_name(stream, mtp_file.parent, *(mtp_file.name[:-4] + '.sdr', 'assets', 'metadata.kfx'))
|
||||
except Exception:
|
||||
pass # expect failure for sideloaded books and personal documents
|
||||
else:
|
||||
stream.name = 'metadata.kfx'
|
||||
with quick_metadata:
|
||||
metadata = get_metadata(stream, stream_type=ext,
|
||||
force_read_metadata=True,
|
||||
pattern=self.build_template_regexp())
|
||||
if metadata.title != 'metadata' and metadata.title != 'Unknown':
|
||||
return metadata
|
||||
stream = self.get_mtp_file(mtp_file)
|
||||
with quick_metadata:
|
||||
return get_metadata(stream, stream_type=ext,
|
||||
@ -417,7 +433,26 @@ class MTP_DEVICE(BASE):
|
||||
ans.append((path, e, traceback.format_exc()))
|
||||
else:
|
||||
ans.append(out.name)
|
||||
if self.is_kindle and path.endswith('.kfx'):
|
||||
# copy additional KFX files from the associated .sdr folder
|
||||
try:
|
||||
sdr_folder_name = f.name[:-4] + '.sdr'
|
||||
new_sdr_path = os.path.join(os.path.split(out.name)[0], sdr_folder_name)
|
||||
os.mkdir(new_sdr_path)
|
||||
self.scan_sdr_for_kfx_files(f.parent, (sdr_folder_name, 'assets'), new_sdr_path)
|
||||
except Exception:
|
||||
traceback.print_exc()
|
||||
return ans
|
||||
|
||||
def scan_sdr_for_kfx_files(self, parent, folders, new_sdr_path):
|
||||
for ff in self.list_folder_by_name(parent, *folders):
|
||||
if ff.is_folder:
|
||||
self.scan_sdr_for_kfx_files(parent, folders + (ff.name,), new_sdr_path)
|
||||
elif ff.name.endswith('.kfx') or ff.name == 'voucher':
|
||||
name = ''.join(shorten_components_to(245 - len(new_sdr_path), [ff.name])) if iswindows else ff.name
|
||||
with open(os.path.join(new_sdr_path, name), 'wb') as out:
|
||||
self.get_file_by_name(out, parent, *(folders + (ff.name,)))
|
||||
|
||||
# }}}
|
||||
|
||||
# Sending files to the device {{{
|
||||
|
@ -97,6 +97,13 @@ class FileOrFolder:
|
||||
self.is_ebook = (not self.is_folder and not self.is_storage and
|
||||
self.name.rpartition('.')[-1].lower() in bexts and not self.name.startswith('._'))
|
||||
|
||||
# allow Kindle Scribe notebooks to be imported and preserve the notebook name
|
||||
if self.name == 'nbk' and not (self.is_folder or self.is_storage):
|
||||
if len(self.full_path) >= 3 and self.full_path[-3] == '.notebooks':
|
||||
nbk_name = self.full_path[-2].replace('!!notebook', '').replace('!!', ' ')
|
||||
self.name = f'Scribe {nbk_name} Notebook.kfx'
|
||||
self.is_ebook = True
|
||||
|
||||
def __repr__(self):
|
||||
if self.is_storage:
|
||||
name = 'Storage'
|
||||
|
Loading…
x
Reference in New Issue
Block a user