mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Set cover in MOBI files when saving to disk. Also update metadata in LRF, EPUB and MOBI files when sending to device.
This commit is contained in:
parent
2a474382d0
commit
f8aa3bf8de
@ -18,7 +18,7 @@ from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup
|
|||||||
from calibre.ebooks.metadata import get_parser, MetaInformation
|
from calibre.ebooks.metadata import get_parser, MetaInformation
|
||||||
from calibre.ebooks.metadata.opf2 import OPF
|
from calibre.ebooks.metadata.opf2 import OPF
|
||||||
from calibre.ptempfile import TemporaryDirectory
|
from calibre.ptempfile import TemporaryDirectory
|
||||||
from calibre import CurrentDir, fit_image
|
from calibre import CurrentDir
|
||||||
|
|
||||||
class EPubException(Exception):
|
class EPubException(Exception):
|
||||||
pass
|
pass
|
||||||
|
@ -23,8 +23,8 @@ class StreamSlicer(object):
|
|||||||
def __init__(self, stream, start=0, stop=None):
|
def __init__(self, stream, start=0, stop=None):
|
||||||
self._stream = stream
|
self._stream = stream
|
||||||
self.start = start
|
self.start = start
|
||||||
if stop is None:
|
if stop is None:
|
||||||
stream.seek(0, 2)
|
stream.seek(0, 2)
|
||||||
stop = stream.tell()
|
stop = stream.tell()
|
||||||
self.stop = stop
|
self.stop = stop
|
||||||
self._len = stop - start
|
self._len = stop - start
|
||||||
@ -74,7 +74,7 @@ class StreamSlicer(object):
|
|||||||
raise TypeError("stream indices must be integers")
|
raise TypeError("stream indices must be integers")
|
||||||
|
|
||||||
|
|
||||||
class MetadataUpdater(object):
|
class MetadataUpdater(object):
|
||||||
def __init__(self, stream):
|
def __init__(self, stream):
|
||||||
self.stream = stream
|
self.stream = stream
|
||||||
data = self.data = StreamSlicer(stream)
|
data = self.data = StreamSlicer(stream)
|
||||||
@ -151,18 +151,22 @@ class MetadataUpdater(object):
|
|||||||
self.exth[:] = ''.join([exth, title, '\0' * trail])
|
self.exth[:] = ''.join([exth, title, '\0' * trail])
|
||||||
self.record0[84:92] = pack('>II', title_off, title_len)
|
self.record0[84:92] = pack('>II', title_off, title_len)
|
||||||
self.record0[92:96] = iana2mobi(mi.language)
|
self.record0[92:96] = iana2mobi(mi.language)
|
||||||
if mi.cover_data[1]:
|
if mi.cover_data[1] or mi.cover:
|
||||||
data = mi.cover_data[1]
|
try:
|
||||||
if self.cover_record is not None:
|
data = mi.cover_data[1] if mi.cover_data[1] else open(mi.cover, 'rb').read()
|
||||||
size = len(self.cover_record)
|
except:
|
||||||
cover = rescale_image(data, size)
|
pass
|
||||||
cover += '\0' * (size - len(cover))
|
else:
|
||||||
self.cover_record[:] = cover
|
if self.cover_record is not None:
|
||||||
if self.thumbnail_record is not None:
|
size = len(self.cover_record)
|
||||||
size = len(self.thumbnail_record)
|
cover = rescale_image(data, size)
|
||||||
thumbnail = rescale_image(data, size, dimen=MAX_THUMB_DIMEN)
|
cover += '\0' * (size - len(cover))
|
||||||
thumbnail += '\0' * (size - len(thumbnail))
|
self.cover_record[:] = cover
|
||||||
self.thumbnail_record[:] = thumbnail
|
if self.thumbnail_record is not None:
|
||||||
|
size = len(self.thumbnail_record)
|
||||||
|
thumbnail = rescale_image(data, size, dimen=MAX_THUMB_DIMEN)
|
||||||
|
thumbnail += '\0' * (size - len(thumbnail))
|
||||||
|
self.thumbnail_record[:] = thumbnail
|
||||||
return
|
return
|
||||||
|
|
||||||
def set_metadata(stream, mi):
|
def set_metadata(stream, mi):
|
||||||
|
@ -306,13 +306,15 @@ IANA_MOBI = \
|
|||||||
'zu': {None: (53, 0)}}
|
'zu': {None: (53, 0)}}
|
||||||
|
|
||||||
def iana2mobi(icode):
|
def iana2mobi(icode):
|
||||||
subtags = list(icode.split('-'))
|
langdict, subtags = IANA_MOBI[None], []
|
||||||
langdict = IANA_MOBI[None]
|
if icode:
|
||||||
while len(subtags) > 0:
|
subtags = list(icode.split('-'))
|
||||||
lang = subtags.pop(0).lower()
|
while len(subtags) > 0:
|
||||||
if lang in IANA_MOBI:
|
lang = subtags.pop(0).lower()
|
||||||
langdict = IANA_MOBI[lang]
|
if lang in IANA_MOBI:
|
||||||
break
|
langdict = IANA_MOBI[lang]
|
||||||
|
break
|
||||||
|
|
||||||
mcode = langdict[None]
|
mcode = langdict[None]
|
||||||
while len(subtags) > 0:
|
while len(subtags) > 0:
|
||||||
subtag = subtags.pop(0)
|
subtag = subtags.pop(0)
|
||||||
|
@ -18,6 +18,7 @@ from calibre.library.database2 import FIELD_MAP
|
|||||||
from calibre.gui2 import NONE, TableView, qstring_to_unicode, config, \
|
from calibre.gui2 import NONE, TableView, qstring_to_unicode, config, \
|
||||||
error_dialog
|
error_dialog
|
||||||
from calibre.utils.search_query_parser import SearchQueryParser
|
from calibre.utils.search_query_parser import SearchQueryParser
|
||||||
|
from calibre.ebooks.metadata.meta import set_metadata as _set_metadata
|
||||||
|
|
||||||
class LibraryDelegate(QItemDelegate):
|
class LibraryDelegate(QItemDelegate):
|
||||||
COLOR = QColor("blue")
|
COLOR = QColor("blue")
|
||||||
@ -423,7 +424,7 @@ class BooksModel(QAbstractTableModel):
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
def get_preferred_formats(self, rows, formats, paths=False):
|
def get_preferred_formats(self, rows, formats, paths=False, set_metadata=False):
|
||||||
ans = []
|
ans = []
|
||||||
for row in (row.row() for row in rows):
|
for row in (row.row() for row in rows):
|
||||||
format = None
|
format = None
|
||||||
@ -441,6 +442,9 @@ class BooksModel(QAbstractTableModel):
|
|||||||
pt = PersistentTemporaryFile(suffix='.'+format)
|
pt = PersistentTemporaryFile(suffix='.'+format)
|
||||||
pt.write(self.db.format(row, format))
|
pt.write(self.db.format(row, format))
|
||||||
pt.flush()
|
pt.flush()
|
||||||
|
if set_metadata:
|
||||||
|
_set_metadata(pt, self.db.get_metadata(row, get_cover=True),
|
||||||
|
format)
|
||||||
pt.close() if paths else pt.seek(0)
|
pt.close() if paths else pt.seek(0)
|
||||||
ans.append(pt)
|
ans.append(pt)
|
||||||
else:
|
else:
|
||||||
|
@ -932,7 +932,8 @@ class Main(MainWindow, Ui_MainWindow):
|
|||||||
mi['cover'] = self.cover_to_thumbnail(cdata)
|
mi['cover'] = self.cover_to_thumbnail(cdata)
|
||||||
metadata = iter(metadata)
|
metadata = iter(metadata)
|
||||||
_files = self.library_view.model().get_preferred_formats(rows,
|
_files = self.library_view.model().get_preferred_formats(rows,
|
||||||
self.device_manager.device_class.FORMATS, paths=True)
|
self.device_manager.device_class.FORMATS,
|
||||||
|
paths=True, set_metadata=True)
|
||||||
files = [getattr(f, 'name', None) for f in _files]
|
files = [getattr(f, 'name', None) for f in _files]
|
||||||
bad, good, gf, names, remove_ids = [], [], [], [], []
|
bad, good, gf, names, remove_ids = [], [], [], [], []
|
||||||
for f in files:
|
for f in files:
|
||||||
|
@ -4,12 +4,11 @@ __copyright__ = '2008, Kovid Goyal <kovid at kovidgoyal.net>'
|
|||||||
Backend that implements storage of ebooks in an sqlite database.
|
Backend that implements storage of ebooks in an sqlite database.
|
||||||
'''
|
'''
|
||||||
import sqlite3 as sqlite
|
import sqlite3 as sqlite
|
||||||
import datetime, re, os, cPickle, traceback, sre_constants
|
import datetime, re, os, cPickle, sre_constants
|
||||||
from zlib import compress, decompress
|
from zlib import compress, decompress
|
||||||
|
|
||||||
from calibre import sanitize_file_name
|
from calibre import sanitize_file_name
|
||||||
from calibre.ebooks.metadata.meta import set_metadata, metadata_from_formats
|
from calibre.ebooks.metadata.meta import set_metadata, metadata_from_formats
|
||||||
from calibre.ebooks.metadata.opf2 import OPFCreator
|
|
||||||
from calibre.ebooks.metadata import MetaInformation
|
from calibre.ebooks.metadata import MetaInformation
|
||||||
from calibre.ebooks import BOOK_EXTENSIONS
|
from calibre.ebooks import BOOK_EXTENSIONS
|
||||||
from calibre.web.feeds.recipes import migrate_automatic_profile_to_automatic_recipe
|
from calibre.web.feeds.recipes import migrate_automatic_profile_to_automatic_recipe
|
||||||
@ -1389,77 +1388,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
def all_ids(self):
|
def all_ids(self):
|
||||||
return [i[0] for i in self.conn.get('SELECT id FROM books')]
|
return [i[0] for i in self.conn.get('SELECT id FROM books')]
|
||||||
|
|
||||||
def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
|
|
||||||
index_is_id=False, callback=None):
|
|
||||||
if not os.path.exists(dir):
|
|
||||||
raise IOError('Target directory does not exist: '+dir)
|
|
||||||
by_author = {}
|
|
||||||
count = 0
|
|
||||||
for index in indices:
|
|
||||||
id = index if index_is_id else self.id(index)
|
|
||||||
au = self.conn.get('SELECT author_sort FROM books WHERE id=?',
|
|
||||||
(id,), all=False)
|
|
||||||
if not au:
|
|
||||||
au = self.authors(index, index_is_id=index_is_id)
|
|
||||||
if not au:
|
|
||||||
au = _('Unknown')
|
|
||||||
au = au.split(',')[0]
|
|
||||||
if not by_author.has_key(au):
|
|
||||||
by_author[au] = []
|
|
||||||
by_author[au].append(index)
|
|
||||||
for au in by_author.keys():
|
|
||||||
apath = os.path.join(dir, sanitize_file_name(au))
|
|
||||||
if not single_dir and not os.path.exists(apath):
|
|
||||||
os.mkdir(apath)
|
|
||||||
for idx in by_author[au]:
|
|
||||||
title = re.sub(r'\s', ' ', self.title(idx, index_is_id=index_is_id))
|
|
||||||
tpath = os.path.join(apath, sanitize_file_name(title))
|
|
||||||
id = idx if index_is_id else self.id(idx)
|
|
||||||
id = str(id)
|
|
||||||
if not single_dir and not os.path.exists(tpath):
|
|
||||||
os.mkdir(tpath)
|
|
||||||
|
|
||||||
name = au + ' - ' + title if byauthor else title + ' - ' + au
|
|
||||||
name += '_'+id
|
|
||||||
base = dir if single_dir else tpath
|
|
||||||
mi = self.get_metadata(idx, index_is_id=index_is_id)
|
|
||||||
cover = self.cover(idx, index_is_id=index_is_id)
|
|
||||||
if cover is not None:
|
|
||||||
cname = sanitize_file_name(name) + '.jpg'
|
|
||||||
cpath = os.path.join(base, cname)
|
|
||||||
open(cpath, 'wb').write(cover)
|
|
||||||
mi.cover = cname
|
|
||||||
f = open(os.path.join(base, sanitize_file_name(name)+'.opf'), 'wb')
|
|
||||||
if not mi.authors:
|
|
||||||
mi.authors = [_('Unknown')]
|
|
||||||
opf = OPFCreator(base, mi)
|
|
||||||
opf.render(f)
|
|
||||||
f.close()
|
|
||||||
|
|
||||||
fmts = self.formats(idx, index_is_id=index_is_id)
|
|
||||||
if not fmts:
|
|
||||||
fmts = ''
|
|
||||||
for fmt in fmts.split(','):
|
|
||||||
data = self.format(idx, fmt, index_is_id=index_is_id)
|
|
||||||
if not data:
|
|
||||||
continue
|
|
||||||
fname = name +'.'+fmt.lower()
|
|
||||||
fname = sanitize_file_name(fname)
|
|
||||||
f = open(os.path.join(base, fname), 'w+b')
|
|
||||||
f.write(data)
|
|
||||||
f.flush()
|
|
||||||
f.seek(0)
|
|
||||||
try:
|
|
||||||
set_metadata(f, mi, fmt.lower())
|
|
||||||
except:
|
|
||||||
print 'Error setting metadata for book:', mi.title
|
|
||||||
traceback.print_exc()
|
|
||||||
f.close()
|
|
||||||
count += 1
|
|
||||||
if callable(callback):
|
|
||||||
if not callback(count, mi.title):
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
def import_book(self, mi, formats):
|
def import_book(self, mi, formats):
|
||||||
@ -1573,43 +1502,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
|||||||
|
|
||||||
return duplicates
|
return duplicates
|
||||||
|
|
||||||
def export_single_format_to_dir(self, dir, indices, format,
|
|
||||||
index_is_id=False, callback=None):
|
|
||||||
dir = os.path.abspath(dir)
|
|
||||||
if not index_is_id:
|
|
||||||
indices = map(self.id, indices)
|
|
||||||
failures = []
|
|
||||||
for count, id in enumerate(indices):
|
|
||||||
try:
|
|
||||||
data = self.format(id, format, index_is_id=True)
|
|
||||||
if not data:
|
|
||||||
failures.append((id, self.title(id, index_is_id=True)))
|
|
||||||
continue
|
|
||||||
except:
|
|
||||||
failures.append((id, self.title(id, index_is_id=True)))
|
|
||||||
continue
|
|
||||||
title = self.title(id, index_is_id=True)
|
|
||||||
au = self.authors(id, index_is_id=True)
|
|
||||||
if not au:
|
|
||||||
au = _('Unknown')
|
|
||||||
fname = '%s - %s.%s'%(title, au, format.lower())
|
|
||||||
fname = sanitize_file_name(fname)
|
|
||||||
if not os.path.exists(dir):
|
|
||||||
os.makedirs(dir)
|
|
||||||
f = open(os.path.join(dir, fname), 'w+b')
|
|
||||||
f.write(data)
|
|
||||||
f.seek(0)
|
|
||||||
try:
|
|
||||||
set_metadata(f, self.get_metadata(id, index_is_id=True), stream_type=format.lower())
|
|
||||||
except:
|
|
||||||
pass
|
|
||||||
f.close()
|
|
||||||
if callable(callback):
|
|
||||||
if not callback(count, title):
|
|
||||||
break
|
|
||||||
return failures
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class SearchToken(object):
|
class SearchToken(object):
|
||||||
|
|
||||||
|
@ -19,8 +19,9 @@ from calibre.library import title_sort
|
|||||||
from calibre.library.database import LibraryDatabase
|
from calibre.library.database import LibraryDatabase
|
||||||
from calibre.library.sqlite import connect, IntegrityError
|
from calibre.library.sqlite import connect, IntegrityError
|
||||||
from calibre.utils.search_query_parser import SearchQueryParser
|
from calibre.utils.search_query_parser import SearchQueryParser
|
||||||
from calibre.ebooks.metadata import string_to_authors, authors_to_string
|
from calibre.ebooks.metadata import string_to_authors, authors_to_string, MetaInformation
|
||||||
from calibre.ebooks.metadata.meta import get_metadata
|
from calibre.ebooks.metadata.meta import get_metadata, set_metadata
|
||||||
|
from calibre.ebooks.metadata.opf2 import OPFCreator
|
||||||
from calibre.constants import preferred_encoding, iswindows, isosx, filesystem_encoding
|
from calibre.constants import preferred_encoding, iswindows, isosx, filesystem_encoding
|
||||||
from calibre.ptempfile import PersistentTemporaryFile
|
from calibre.ptempfile import PersistentTemporaryFile
|
||||||
from calibre.customize.ui import run_plugins_on_import
|
from calibre.customize.ui import run_plugins_on_import
|
||||||
@ -556,7 +557,8 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
continue
|
continue
|
||||||
|
|
||||||
def cover(self, index, index_is_id=False, as_file=False, as_image=False):
|
def cover(self, index, index_is_id=False, as_file=False, as_image=False,
|
||||||
|
as_path=False):
|
||||||
'''
|
'''
|
||||||
Return the cover image as a bytestring (in JPEG format) or None.
|
Return the cover image as a bytestring (in JPEG format) or None.
|
||||||
|
|
||||||
@ -566,6 +568,8 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
id = index if index_is_id else self.id(index)
|
id = index if index_is_id else self.id(index)
|
||||||
path = os.path.join(self.library_path, self.path(id, index_is_id=True), 'cover.jpg')
|
path = os.path.join(self.library_path, self.path(id, index_is_id=True), 'cover.jpg')
|
||||||
if os.access(path, os.R_OK):
|
if os.access(path, os.R_OK):
|
||||||
|
if as_path:
|
||||||
|
return path
|
||||||
f = open(path, 'rb')
|
f = open(path, 'rb')
|
||||||
if as_image:
|
if as_image:
|
||||||
img = QImage()
|
img = QImage()
|
||||||
@ -573,6 +577,30 @@ class LibraryDatabase2(LibraryDatabase):
|
|||||||
return img
|
return img
|
||||||
return f if as_file else f.read()
|
return f if as_file else f.read()
|
||||||
|
|
||||||
|
def get_metadata(self, idx, index_is_id=False, get_cover=False):
|
||||||
|
'''
|
||||||
|
Convenience method to return metadata as a L{MetaInformation} object.
|
||||||
|
'''
|
||||||
|
aum = self.authors(idx, index_is_id=index_is_id)
|
||||||
|
if aum: aum = [a.strip().replace('|', ',') for a in aum.split(',')]
|
||||||
|
mi = MetaInformation(self.title(idx, index_is_id=index_is_id), aum)
|
||||||
|
mi.author_sort = self.author_sort(idx, index_is_id=index_is_id)
|
||||||
|
mi.comments = self.comments(idx, index_is_id=index_is_id)
|
||||||
|
mi.publisher = self.publisher(idx, index_is_id=index_is_id)
|
||||||
|
tags = self.tags(idx, index_is_id=index_is_id)
|
||||||
|
if tags:
|
||||||
|
mi.tags = [i.strip() for i in tags.split(',')]
|
||||||
|
mi.series = self.series(idx, index_is_id=index_is_id)
|
||||||
|
if mi.series:
|
||||||
|
mi.series_index = self.series_index(idx, index_is_id=index_is_id)
|
||||||
|
mi.rating = self.rating(idx, index_is_id=index_is_id)
|
||||||
|
mi.isbn = self.isbn(idx, index_is_id=index_is_id)
|
||||||
|
id = idx if index_is_id else self.id(idx)
|
||||||
|
mi.application_id = id
|
||||||
|
if get_cover:
|
||||||
|
mi.cover = self.cover(id, index_is_id=True, as_path=True)
|
||||||
|
return mi
|
||||||
|
|
||||||
def has_book(self, mi):
|
def has_book(self, mi):
|
||||||
title = mi.title
|
title = mi.title
|
||||||
if title:
|
if title:
|
||||||
@ -1322,5 +1350,107 @@ books_series_link feeds
|
|||||||
self.vacuum()
|
self.vacuum()
|
||||||
progress.reset()
|
progress.reset()
|
||||||
return len(books)
|
return len(books)
|
||||||
|
|
||||||
|
def export_to_dir(self, dir, indices, byauthor=False, single_dir=False,
|
||||||
|
index_is_id=False, callback=None):
|
||||||
|
if not os.path.exists(dir):
|
||||||
|
raise IOError('Target directory does not exist: '+dir)
|
||||||
|
by_author = {}
|
||||||
|
count = 0
|
||||||
|
for index in indices:
|
||||||
|
id = index if index_is_id else self.id(index)
|
||||||
|
au = self.conn.get('SELECT author_sort FROM books WHERE id=?',
|
||||||
|
(id,), all=False)
|
||||||
|
if not au:
|
||||||
|
au = self.authors(index, index_is_id=index_is_id)
|
||||||
|
if not au:
|
||||||
|
au = _('Unknown')
|
||||||
|
au = au.split(',')[0]
|
||||||
|
if not by_author.has_key(au):
|
||||||
|
by_author[au] = []
|
||||||
|
by_author[au].append(index)
|
||||||
|
for au in by_author.keys():
|
||||||
|
apath = os.path.join(dir, sanitize_file_name(au))
|
||||||
|
if not single_dir and not os.path.exists(apath):
|
||||||
|
os.mkdir(apath)
|
||||||
|
for idx in by_author[au]:
|
||||||
|
title = re.sub(r'\s', ' ', self.title(idx, index_is_id=index_is_id))
|
||||||
|
tpath = os.path.join(apath, sanitize_file_name(title))
|
||||||
|
id = idx if index_is_id else self.id(idx)
|
||||||
|
id = str(id)
|
||||||
|
if not single_dir and not os.path.exists(tpath):
|
||||||
|
os.mkdir(tpath)
|
||||||
|
|
||||||
|
name = au + ' - ' + title if byauthor else title + ' - ' + au
|
||||||
|
name += '_'+id
|
||||||
|
base = dir if single_dir else tpath
|
||||||
|
mi = self.get_metadata(idx, index_is_id=index_is_id, get_cover=True)
|
||||||
|
f = open(os.path.join(base, sanitize_file_name(name)+'.opf'), 'wb')
|
||||||
|
if not mi.authors:
|
||||||
|
mi.authors = [_('Unknown')]
|
||||||
|
opf = OPFCreator(base, mi)
|
||||||
|
opf.render(f)
|
||||||
|
f.close()
|
||||||
|
|
||||||
|
fmts = self.formats(idx, index_is_id=index_is_id)
|
||||||
|
if not fmts:
|
||||||
|
fmts = ''
|
||||||
|
for fmt in fmts.split(','):
|
||||||
|
data = self.format(idx, fmt, index_is_id=index_is_id)
|
||||||
|
if not data:
|
||||||
|
continue
|
||||||
|
fname = name +'.'+fmt.lower()
|
||||||
|
fname = sanitize_file_name(fname)
|
||||||
|
f = open(os.path.join(base, fname), 'w+b')
|
||||||
|
f.write(data)
|
||||||
|
f.flush()
|
||||||
|
f.seek(0)
|
||||||
|
try:
|
||||||
|
set_metadata(f, mi, fmt.lower())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
f.close()
|
||||||
|
count += 1
|
||||||
|
if callable(callback):
|
||||||
|
if not callback(count, mi.title):
|
||||||
|
return
|
||||||
|
|
||||||
|
def export_single_format_to_dir(self, dir, indices, format,
|
||||||
|
index_is_id=False, callback=None):
|
||||||
|
dir = os.path.abspath(dir)
|
||||||
|
if not index_is_id:
|
||||||
|
indices = map(self.id, indices)
|
||||||
|
failures = []
|
||||||
|
for count, id in enumerate(indices):
|
||||||
|
try:
|
||||||
|
data = self.format(id, format, index_is_id=True)
|
||||||
|
if not data:
|
||||||
|
failures.append((id, self.title(id, index_is_id=True)))
|
||||||
|
continue
|
||||||
|
except:
|
||||||
|
failures.append((id, self.title(id, index_is_id=True)))
|
||||||
|
continue
|
||||||
|
title = self.title(id, index_is_id=True)
|
||||||
|
au = self.authors(id, index_is_id=True)
|
||||||
|
if not au:
|
||||||
|
au = _('Unknown')
|
||||||
|
fname = '%s - %s.%s'%(title, au, format.lower())
|
||||||
|
fname = sanitize_file_name(fname)
|
||||||
|
if not os.path.exists(dir):
|
||||||
|
os.makedirs(dir)
|
||||||
|
f = open(os.path.join(dir, fname), 'w+b')
|
||||||
|
f.write(data)
|
||||||
|
f.seek(0)
|
||||||
|
try:
|
||||||
|
set_metadata(f, self.get_metadata(id, index_is_id=True, get_cover=True),
|
||||||
|
stream_type=format.lower())
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
f.close()
|
||||||
|
if callable(callback):
|
||||||
|
if not callback(count, title):
|
||||||
|
break
|
||||||
|
return failures
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user