mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Sync to trunk.
This commit is contained in:
commit
12bce0197b
@ -9,6 +9,7 @@ from itertools import cycle
|
||||
|
||||
from calibre.devices.usbms.driver import USBMS
|
||||
from calibre import sanitize_file_name as sanitize
|
||||
from calibre.ebooks.metadata import string_to_authors
|
||||
|
||||
class JETBOOK(USBMS):
|
||||
name = 'Ectaco JetBook Device Interface'
|
||||
@ -118,7 +119,7 @@ class JETBOOK(USBMS):
|
||||
match = cls.JETBOOK_FILE_NAME_PATTERN.match(fn)
|
||||
if match is not None:
|
||||
mi.title = check_unicode(match.group('title'))
|
||||
authors = match.group('authors').split('&')
|
||||
authors = string_to_authors(match.group('authors'))
|
||||
mi.authors = map(check_unicode, authors)
|
||||
|
||||
return mi
|
||||
|
@ -70,6 +70,8 @@ def option_recommendation_to_cli_option(add_option, rec):
|
||||
switches.append('--'+opt.long_switch)
|
||||
attrs = dict(dest=opt.name, help=opt.help,
|
||||
choices=opt.choices, default=rec.recommended_value)
|
||||
if opt.long_switch == 'verbose':
|
||||
attrs['action'] = 'count'
|
||||
if isinstance(rec.recommended_value, type(True)):
|
||||
attrs['action'] = 'store_false' if rec.recommended_value else \
|
||||
'store_true'
|
||||
|
@ -19,7 +19,7 @@ import xml.dom.minidom as dom
|
||||
from functools import wraps
|
||||
|
||||
from calibre.devices.prs500.prstypes import field
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
BYTE = "<B" #: Unsigned char little endian encoded in 1 byte
|
||||
WORD = "<H" #: Unsigned short little endian encoded in 2 bytes
|
||||
@ -221,10 +221,7 @@ def get_metadata(stream):
|
||||
@param stream: A file like object or an instance of L{LRFMetaFile}
|
||||
"""
|
||||
lrf = stream if isinstance(stream, LRFMetaFile) else LRFMetaFile(stream)
|
||||
au = lrf.author.strip().split(',')
|
||||
authors = []
|
||||
for i in au:
|
||||
authors.extend(i.split('&'))
|
||||
authors = string_to_authors(lrf.author)
|
||||
mi = MetaInformation(lrf.title.strip(), authors)
|
||||
mi.author = lrf.author.strip()
|
||||
mi.comments = lrf.free_text.strip()
|
||||
|
@ -13,7 +13,9 @@ from urlparse import urlparse
|
||||
|
||||
from calibre import relpath
|
||||
|
||||
_author_pat = re.compile(',?\s+and\s+', re.IGNORECASE)
|
||||
def string_to_authors(raw):
|
||||
raw = _author_pat.sub('&', raw)
|
||||
raw = raw.replace('&&', u'\uffff')
|
||||
authors = [a.strip().replace(u'\uffff', '&') for a in raw.split('&')]
|
||||
return authors
|
||||
|
@ -4,7 +4,7 @@ __copyright__ = '2008, Ashish Kulkarni <kulkarni.ashish@gmail.com>'
|
||||
|
||||
import sys, os
|
||||
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
MAGIC = ['\x00\x01BOOKDOUG', '\x00\x02BOOKDOUG']
|
||||
|
||||
@ -34,11 +34,7 @@ def get_metadata(stream):
|
||||
if title:
|
||||
mi.title = title
|
||||
if author:
|
||||
src = author.split('&')
|
||||
authors = []
|
||||
for au in src:
|
||||
authors += au.split(',')
|
||||
mi.authors = authors
|
||||
mi.authors = string_to_authors(author)
|
||||
mi.author = author
|
||||
if category:
|
||||
mi.category = category
|
||||
|
@ -49,7 +49,7 @@ class ISBNDBMetadata(MetaInformation):
|
||||
def __init__(self, book):
|
||||
MetaInformation.__init__(self, None, [])
|
||||
|
||||
self.isbn = book['isbn']
|
||||
self.isbn = book.get('isbn13', book.get('isbn'))
|
||||
self.title = book.find('titlelong').string
|
||||
if not self.title:
|
||||
self.title = book.find('title').string
|
||||
@ -74,7 +74,6 @@ class ISBNDBMetadata(MetaInformation):
|
||||
self.comments = 'SUMMARY:\n'+summ.string
|
||||
|
||||
|
||||
|
||||
def build_isbn(base_url, opts):
|
||||
return base_url + 'index1=isbn&value1='+opts.isbn
|
||||
|
||||
|
@ -9,7 +9,7 @@ from calibre.utils.config import prefs
|
||||
from calibre.ebooks.metadata.opf2 import OPF
|
||||
|
||||
from calibre.customize.ui import get_file_type_metadata, set_file_type_metadata
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
_METADATA_PRIORITIES = [
|
||||
'html', 'htm', 'xhtml', 'xhtm',
|
||||
@ -132,10 +132,7 @@ def metadata_from_filename(name, pat=None):
|
||||
pass
|
||||
try:
|
||||
au = match.group('authors')
|
||||
aus = au.split(',')
|
||||
authors = []
|
||||
for a in aus:
|
||||
authors.extend(a.split('&'))
|
||||
aus = string_to_authors(au)
|
||||
mi.authors = authors
|
||||
except IndexError:
|
||||
pass
|
||||
|
@ -7,7 +7,7 @@ import uuid
|
||||
from urllib import unquote, quote
|
||||
|
||||
from calibre.constants import __appname__, __version__
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
from calibre.ebooks.BeautifulSoup import BeautifulStoneSoup, BeautifulSoup
|
||||
from calibre.ebooks.lrf import entity_to_unicode
|
||||
from calibre.ebooks.metadata import Resource, ResourceCollection
|
||||
@ -270,11 +270,7 @@ class OPF(MetaInformation):
|
||||
role = 'aut'
|
||||
if role == 'aut' and elem.string:
|
||||
raw = self.ENTITY_PATTERN.sub(entity_to_unicode, elem.string)
|
||||
au = raw.split(',')
|
||||
ans = []
|
||||
for i in au:
|
||||
ans.extend(i.split('&'))
|
||||
return [a.strip() for a in ans]
|
||||
return string_to_authors(raw)
|
||||
return []
|
||||
|
||||
def get_author_sort(self):
|
||||
|
@ -15,7 +15,7 @@ try:
|
||||
_imagemagick_loaded = True
|
||||
except:
|
||||
_imagemagick_loaded = False
|
||||
from calibre.ebooks.metadata import MetaInformation, authors_to_string
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors, authors_to_string
|
||||
from calibre.utils.pdftk import set_metadata as pdftk_set_metadata
|
||||
from calibre.utils.podofo import get_metadata as podofo_get_metadata, \
|
||||
set_metadata as podofo_set_metadata, Unavailable, get_metadata_quick
|
||||
@ -69,12 +69,8 @@ def get_metadata_pypdf(stream):
|
||||
if info.title:
|
||||
mi.title = info.title
|
||||
if info.author:
|
||||
src = info.author.split('&')
|
||||
authors = []
|
||||
for au in src:
|
||||
authors += au.split(',')
|
||||
mi.authors = authors
|
||||
mi.author = info.author
|
||||
mi.authors = string_to_authors(info.author)
|
||||
if info.subject:
|
||||
mi.category = info.subject
|
||||
except Exception, err:
|
||||
|
@ -4,7 +4,7 @@ __copyright__ = '2008, Ashish Kulkarni <kulkarni.ashish@gmail.com>'
|
||||
|
||||
import sys, struct
|
||||
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
MAGIC = '\xb0\x0c\xb0\x0c\x02\x00NUVO\x00\x00\x00\x00'
|
||||
|
||||
@ -41,12 +41,8 @@ def get_metadata(stream):
|
||||
if key.strip() == 'TITLE':
|
||||
mi.title = value.strip()
|
||||
elif key.strip() == 'AUTHOR':
|
||||
src = value.split('&')
|
||||
authors = []
|
||||
for au in src:
|
||||
authors += au.split(',')
|
||||
mi.authors = authors
|
||||
mi.author = value
|
||||
mi.authors = string_to_authors(value)
|
||||
except Exception, err:
|
||||
msg = u'Couldn\'t read metadata from rb: %s with error %s'%(mi.title, unicode(err))
|
||||
print >>sys.stderr, msg.encode('utf8')
|
||||
|
@ -5,7 +5,7 @@ Edit metadata in RTF files.
|
||||
"""
|
||||
import re, cStringIO, sys
|
||||
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.ebooks.metadata import MetaInformation, string_to_authors
|
||||
|
||||
title_pat = re.compile(r'\{\\info.*?\{\\title(.*?)(?<!\\)\}', re.DOTALL)
|
||||
author_pat = re.compile(r'\{\\info.*?\{\\author(.*?)(?<!\\)\}', re.DOTALL)
|
||||
@ -76,10 +76,7 @@ def get_metadata(stream):
|
||||
category = category_match.group(1).strip()
|
||||
mi = MetaInformation(title, author)
|
||||
if author:
|
||||
au = author.split(',')
|
||||
mi.authors = []
|
||||
for i in au:
|
||||
mi.authors.extend(i.split('&'))
|
||||
mi.authors = string_to_authors(author)
|
||||
mi.comments = comment
|
||||
mi.category = category
|
||||
return mi
|
||||
|
@ -41,11 +41,14 @@ SVG_NS = 'http://www.w3.org/2000/svg'
|
||||
XLINK_NS = 'http://www.w3.org/1999/xlink'
|
||||
CALIBRE_NS = 'http://calibre.kovidgoyal.net/2009/metadata'
|
||||
RE_NS = 'http://exslt.org/regular-expressions'
|
||||
MBP_NS = 'http://www.mobipocket.com'
|
||||
|
||||
XPNSMAP = {'h' : XHTML_NS, 'o1' : OPF1_NS, 'o2' : OPF2_NS,
|
||||
'd09': DC09_NS, 'd10': DC10_NS, 'd11': DC11_NS,
|
||||
'xsi': XSI_NS, 'dt' : DCTERMS_NS, 'ncx': NCX_NS,
|
||||
'svg': SVG_NS, 'xl' : XLINK_NS, 're': RE_NS}
|
||||
'svg': SVG_NS, 'xl' : XLINK_NS, 're': RE_NS,
|
||||
'mbp': MBP_NS }
|
||||
|
||||
OPF1_NSMAP = {'dc': DC11_NS, 'oebpackage': OPF1_NS}
|
||||
OPF2_NSMAP = {'opf': OPF2_NS, 'dc': DC11_NS, 'dcterms': DCTERMS_NS,
|
||||
'xsi': XSI_NS, 'calibre': CALIBRE_NS}
|
||||
@ -785,10 +788,12 @@ class Manifest(object):
|
||||
data = first_pass(data)
|
||||
# Force into the XHTML namespace
|
||||
if barename(data.tag) != 'html':
|
||||
data = first_pass('<html>'+data+'</html>')
|
||||
if barename(data.tag) != 'html':
|
||||
raise NotHTML(
|
||||
'File %r does not appear to be (X)HTML' % self.href)
|
||||
self.log.warn('File %r does not appear to be (X)HTML'%self.href)
|
||||
nroot = etree.fromstring('<html></html>')
|
||||
for child in list(data):
|
||||
child.getparent.remove(child)
|
||||
nroot.append(child)
|
||||
data = nroot
|
||||
elif not namespace(data.tag):
|
||||
data.attrib['xmlns'] = XHTML_NS
|
||||
data = etree.tostring(data, encoding=unicode)
|
||||
@ -799,10 +804,11 @@ class Manifest(object):
|
||||
try:
|
||||
data = etree.fromstring(data)
|
||||
except etree.XMLSyntaxError:
|
||||
self.oeb.logger.warn('Stripping comments from %s'%
|
||||
self.oeb.logger.warn('Stripping comments and meta tags from %s'%
|
||||
self.href)
|
||||
data = re.compile(r'<!--.*?-->', re.DOTALL).sub('',
|
||||
data)
|
||||
data = re.sub(r'<meta\s+[^>]+?>', '', data)
|
||||
data = etree.fromstring(data)
|
||||
elif namespace(data.tag) != XHTML_NS:
|
||||
# OEB_DOC_NS, but possibly others
|
||||
@ -1371,9 +1377,11 @@ class TOC(object):
|
||||
:attr:`href`: Book-internal URL referenced by this node.
|
||||
:attr:`klass`: Optional semantic class referenced by this node.
|
||||
:attr:`id`: Option unique identifier for this node.
|
||||
:attr:`author`: Optional author attribution for periodicals <mbp:>
|
||||
:attr:`description`: Optional description attribute for periodicals <mbp:>
|
||||
"""
|
||||
def __init__(self, title=None, href=None, klass=None, id=None,
|
||||
play_order=None):
|
||||
play_order=None, author=None, description=None):
|
||||
self.title = title
|
||||
self.href = urlnormalize(href) if href else href
|
||||
self.klass = klass
|
||||
@ -1383,10 +1391,12 @@ class TOC(object):
|
||||
if play_order is None:
|
||||
play_order = self.next_play_order()
|
||||
self.play_order = play_order
|
||||
self.author = author
|
||||
self.description = description
|
||||
|
||||
def add(self, title, href, klass=None, id=None, play_order=0):
|
||||
def add(self, title, href, klass=None, id=None, play_order=0, author=None, description=None):
|
||||
"""Create and return a new sub-node of this node."""
|
||||
node = TOC(title, href, klass, id, play_order)
|
||||
node = TOC(title, href, klass, id, play_order, author, description)
|
||||
self.nodes.append(node)
|
||||
return node
|
||||
|
||||
|
@ -351,9 +351,27 @@ class OEBReader(object):
|
||||
self.logger.warn('TOC reference %r not found' % href)
|
||||
continue
|
||||
id = child.get('id')
|
||||
klass = child.get('class')
|
||||
klass = child.get('class', 'chapter')
|
||||
|
||||
po = int(child.get('playOrder', self.oeb.toc.next_play_order()))
|
||||
node = toc.add(title, href, id=id, klass=klass, play_order=po)
|
||||
|
||||
authorElement = xpath(child,
|
||||
'descendant::mbp:meta[@name = "author"]')
|
||||
if authorElement :
|
||||
author = authorElement[0].text
|
||||
else :
|
||||
author = None
|
||||
|
||||
descriptionElement = xpath(child,
|
||||
'descendant::mbp:meta[@name = "description"]')
|
||||
if descriptionElement :
|
||||
description = descriptionElement[0].text
|
||||
else :
|
||||
description = None
|
||||
|
||||
node = toc.add(title, href, id=id, klass=klass,
|
||||
play_order=po, description=description, author=author)
|
||||
|
||||
self._toc_from_navpoint(item, node, child)
|
||||
|
||||
def _toc_from_ncx(self, item):
|
||||
|
@ -10,7 +10,7 @@ import textwrap
|
||||
|
||||
from lxml import etree
|
||||
|
||||
from calibre.ebooks.oeb.base import XPNSMAP
|
||||
from calibre.ebooks.oeb.base import XPath, XPNSMAP
|
||||
from calibre import guess_type
|
||||
|
||||
class Jacket(object):
|
||||
@ -41,9 +41,10 @@ class Jacket(object):
|
||||
''')
|
||||
|
||||
def remove_first_image(self):
|
||||
path = XPath('//h:img[@src]')
|
||||
for i, item in enumerate(self.oeb.spine):
|
||||
if i > 2: break
|
||||
for img in item.data.xpath('//h:img[@src]', namespace=XPNSMAP):
|
||||
for img in path(item.data):
|
||||
href = item.abshref(img.get('src'))
|
||||
image = self.oeb.manifest.hrefs.get(href, None)
|
||||
if image is not None:
|
||||
|
@ -31,6 +31,8 @@ class WizardWidget(QWidget, Ui_Form):
|
||||
q = '[re:test(@%s, "%s", "i")]'%(attr, val)
|
||||
else:
|
||||
q = '[@%s]'%attr
|
||||
elif val:
|
||||
q = '[re:test(., "%s", "i")]'%(val)
|
||||
expr = '//'+tag + q
|
||||
return expr
|
||||
|
||||
|
@ -14,6 +14,7 @@ from calibre.gui2.dialogs.fetch_metadata_ui import Ui_FetchMetadata
|
||||
from calibre.gui2 import error_dialog, NONE, info_dialog
|
||||
from calibre.gui2.widgets import ProgressIndicator
|
||||
from calibre.utils.config import prefs
|
||||
from calibre import strftime
|
||||
|
||||
class Fetcher(QThread):
|
||||
|
||||
@ -45,7 +46,7 @@ class Matches(QAbstractTableModel):
|
||||
return len(self.matches)
|
||||
|
||||
def columnCount(self, *args):
|
||||
return 5
|
||||
return 6
|
||||
|
||||
def headerData(self, section, orientation, role):
|
||||
if role != Qt.DisplayRole:
|
||||
@ -57,6 +58,7 @@ class Matches(QAbstractTableModel):
|
||||
elif section == 2: text = _("Author Sort")
|
||||
elif section == 3: text = _("Publisher")
|
||||
elif section == 4: text = _("ISBN")
|
||||
elif section == 5: text = _("Published")
|
||||
|
||||
return QVariant(text)
|
||||
else:
|
||||
@ -80,6 +82,9 @@ class Matches(QAbstractTableModel):
|
||||
res = book.publisher
|
||||
elif col == 4:
|
||||
res = book.isbn
|
||||
elif col == 5:
|
||||
if hasattr(book.pubdate, 'timetuple'):
|
||||
res = strftime('%b %Y', book.pubdate.timetuple())
|
||||
if not res:
|
||||
return NONE
|
||||
return QVariant(res)
|
||||
@ -126,7 +131,7 @@ class FetchMetadata(QDialog, Ui_FetchMetadata):
|
||||
prefs['isbndb_com_key'] = key
|
||||
else:
|
||||
key = None
|
||||
title = author = publisher = isbn = None
|
||||
title = author = publisher = isbn = pubdate = None
|
||||
if self.isbn:
|
||||
isbn = self.isbn
|
||||
if self.title:
|
||||
|
@ -10,8 +10,9 @@ import os
|
||||
import re
|
||||
import time
|
||||
import traceback
|
||||
from datetime import datetime
|
||||
|
||||
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread
|
||||
from PyQt4.QtCore import SIGNAL, QObject, QCoreApplication, Qt, QTimer, QThread, QDate
|
||||
from PyQt4.QtGui import QPixmap, QListWidgetItem, QErrorMessage, QDialog, QCompleter
|
||||
|
||||
from calibre.gui2 import qstring_to_unicode, error_dialog, file_icon_provider, \
|
||||
@ -234,6 +235,7 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.cover.setAcceptDrops(True)
|
||||
self._author_completer = AuthorCompleter(self.db)
|
||||
self.authors.setCompleter(self._author_completer)
|
||||
self.pubdate.setMinimumDate(QDate(100,1,1))
|
||||
self.connect(self.cover, SIGNAL('cover_changed()'), self.cover_dropped)
|
||||
QObject.connect(self.cover_button, SIGNAL("clicked(bool)"), \
|
||||
self.select_cover)
|
||||
@ -279,6 +281,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
comments = self.db.comments(row)
|
||||
self.comments.setPlainText(comments if comments else '')
|
||||
cover = self.db.cover(row)
|
||||
pubdate = db.pubdate(self.id, index_is_id=True)
|
||||
self.pubdate.setDate(QDate(pubdate.year, pubdate.month,
|
||||
pubdate.day))
|
||||
|
||||
exts = self.db.formats(row)
|
||||
if exts:
|
||||
@ -441,6 +446,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
if book.author_sort: self.author_sort.setText(book.author_sort)
|
||||
if book.publisher: self.publisher.setEditText(book.publisher)
|
||||
if book.isbn: self.isbn.setText(book.isbn)
|
||||
if book.pubdate:
|
||||
d = book.pubdate
|
||||
self.pubdate.setDate(QDate(d.year, d.month, d.day))
|
||||
summ = book.comments
|
||||
if summ:
|
||||
prefix = qstring_to_unicode(self.comments.toPlainText())
|
||||
@ -485,6 +493,9 @@ class MetadataSingleDialog(ResizableDialog, Ui_MetadataSingleDialog):
|
||||
self.db.set_series(self.id, qstring_to_unicode(self.series.currentText()), notify=False)
|
||||
self.db.set_series_index(self.id, self.series_index.value(), notify=False)
|
||||
self.db.set_comment(self.id, qstring_to_unicode(self.comments.toPlainText()), notify=False)
|
||||
d = self.pubdate.date()
|
||||
self.db.set_pubdate(self.id, datetime(d.year(), d.month(), d.day()))
|
||||
|
||||
if self.cover_changed:
|
||||
self.db.set_cover(self.id, pixmap_to_data(self.cover.pixmap()))
|
||||
QDialog.accept(self)
|
||||
|
@ -325,6 +325,19 @@
|
||||
<item row="8" column="1" colspan="2">
|
||||
<widget class="QLineEdit" name="isbn"/>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>Publishe&d:</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>pubdate</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QComboBox" name="publisher">
|
||||
<property name="editable">
|
||||
@ -348,6 +361,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="1">
|
||||
<widget class="QDateEdit" name="pubdate">
|
||||
<property name="displayFormat">
|
||||
<string>MMM yyyy</string>
|
||||
</property>
|
||||
<property name="calendarPopup">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
@ -632,6 +655,7 @@
|
||||
<tabstop>tag_editor_button</tabstop>
|
||||
<tabstop>remove_series_button</tabstop>
|
||||
<tabstop>isbn</tabstop>
|
||||
<tabstop>pubdate</tabstop>
|
||||
<tabstop>comments</tabstop>
|
||||
<tabstop>fetch_metadata_button</tabstop>
|
||||
<tabstop>fetch_cover_button</tabstop>
|
||||
|
@ -314,7 +314,10 @@ class Main(MainWindow, Ui_MainWindow, DeviceGUI):
|
||||
QObject.connect(self.action_convert,
|
||||
SIGNAL('triggered(bool)'), self.convert_single)
|
||||
self.convert_menu = cm
|
||||
|
||||
pm = QMenu()
|
||||
ap = self.action_preferences
|
||||
pm.addAction(ap.icon(), ap.text())
|
||||
pm.addAction(self.preferences_action)
|
||||
pm.addAction(_('Run welcome wizard'))
|
||||
self.connect(pm.actions()[1], SIGNAL('triggered(bool)'),
|
||||
|
@ -9,6 +9,7 @@ from zlib import compress, decompress
|
||||
|
||||
from calibre.ebooks.metadata import MetaInformation
|
||||
from calibre.web.feeds.recipes import migrate_automatic_profile_to_automatic_recipe
|
||||
from calibre.ebooks.metadata import string_to_authors
|
||||
|
||||
class Concatenate(object):
|
||||
'''String concatenation aggregator for sqlite'''
|
||||
@ -97,7 +98,7 @@ class LibraryDatabase(object):
|
||||
obj = conn.execute('INSERT INTO books(title, timestamp, author_sort) VALUES (?,?,?)',
|
||||
(book['title'], book['timestamp'], authors))
|
||||
id = obj.lastrowid
|
||||
authors = authors.split('&')
|
||||
authors = string_to_authors(authors)
|
||||
for a in authors:
|
||||
author = conn.execute('SELECT id from authors WHERE name=?', (a,)).fetchone()
|
||||
if author:
|
||||
@ -1103,7 +1104,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
||||
item[col] = val
|
||||
break
|
||||
if column == 'authors':
|
||||
val = val.split('&,')
|
||||
val = string_to_authors(val)
|
||||
self.set_authors(id, val)
|
||||
elif column == 'title':
|
||||
self.set_title(id, val)
|
||||
@ -1266,7 +1267,7 @@ ALTER TABLE books ADD COLUMN isbn TEXT DEFAULT "" COLLATE NOCASE;
|
||||
mi.authors = ['Unknown']
|
||||
authors = []
|
||||
for a in mi.authors:
|
||||
authors += a.split('&')
|
||||
authors += string_to_authors(a)
|
||||
self.set_authors(id, authors)
|
||||
if mi.author_sort:
|
||||
self.set_author_sort(id, mi.author_sort)
|
||||
|
@ -993,7 +993,7 @@ class LibraryDatabase2(LibraryDatabase):
|
||||
mi.authors = [_('Unknown')]
|
||||
authors = []
|
||||
for a in mi.authors:
|
||||
authors += a.split('&')
|
||||
authors += string_to_authors(a)
|
||||
self.set_authors(id, authors, notify=False)
|
||||
if mi.author_sort:
|
||||
self.set_author_sort(id, mi.author_sort, notify=False)
|
||||
|
@ -1,5 +1,6 @@
|
||||
#!/usr/bin/env python
|
||||
__license__ = 'GPL v3'
|
||||
|
||||
__copyright__ = '2008, Kovid Goyal kovid@kovidgoyal.net'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
@ -10,35 +11,59 @@ globeandmail.com
|
||||
from calibre.web.feeds.news import BasicNewsRecipe
|
||||
|
||||
class GlobeAndMail(BasicNewsRecipe):
|
||||
|
||||
title = 'Globe and Mail'
|
||||
__author__ = 'Kovid Goyal'
|
||||
title = u'Globe and Mail'
|
||||
language = _('English')
|
||||
oldest_article = 2.0
|
||||
__author__ = 'Kovid Goyal'
|
||||
oldest_article = 2
|
||||
max_articles_per_feed = 10
|
||||
no_stylesheets = True
|
||||
extra_css = '''
|
||||
h3 {font-size: 22pt; font-weight:bold; margin:0px; padding:0px 0px 8pt 0px;}
|
||||
h4 {margin-top: 0px;}
|
||||
#byline { font-family: monospace; font-weight:bold; }
|
||||
#placeline {font-weight:bold;}
|
||||
#credit {margin-top:0px;}
|
||||
.tag {font-size: 22pt;}'''
|
||||
description = 'Canada\'s national newspaper'
|
||||
remove_tags_before = dict(id="article-top")
|
||||
remove_tags = [
|
||||
{'id':['util', 'article-tabs', 'comments', 'article-relations',
|
||||
'gallery-controls', 'video', 'galleryLoading']},
|
||||
'gallery-controls', 'video', 'galleryLoading','deck','header'] },
|
||||
{'class':['credit','inline-img-caption','tab-pointer'] },
|
||||
dict(name='div', attrs={'id':'lead-photo'}),
|
||||
dict(name='div', attrs={'class':'right'}),
|
||||
dict(name='div', attrs={'id':'footer'}),
|
||||
dict(name='div', attrs={'id':'beta-msg'}),
|
||||
dict(name='img', attrs={'class':'headshot'}),
|
||||
dict(name='div', attrs={'class':'brand'}),
|
||||
dict(name='div', attrs={'id':'nav-wrap'}),
|
||||
dict(name='div', attrs={'id':'featureTopics'}),
|
||||
dict(name='div', attrs={'id':'videoNav'}),
|
||||
dict(name='div', attrs={'id':'blog-header'}),
|
||||
dict(name='div', attrs={'id':'right-rail'}),
|
||||
dict(name='div', attrs={'id':'group-footer-container'}),
|
||||
dict(name=['iframe','img'])
|
||||
]
|
||||
remove_tags_after = [{'id':['article-content']},
|
||||
{'class':['pull','inline-img'] },
|
||||
dict(name='img', attrs={'class':'inline-media-embed'}),
|
||||
]
|
||||
remove_tags_after = dict(id='article-content')
|
||||
|
||||
feeds = [
|
||||
('Latest headlines', 'http://www.theglobeandmail.com/?service=rss'),
|
||||
('Top stories', 'http://www.theglobeandmail.com/?service=rss&feed=topstories'),
|
||||
('National', 'http://www.theglobeandmail.com/news/national/?service=rss'),
|
||||
('Politics', 'http://www.theglobeandmail.com/news/politics/?service=rss'),
|
||||
('World', 'http://www.theglobeandmail.com/news/world/?service=rss'),
|
||||
('Business', 'http://www.theglobeandmail.com/report-on-business/?service=rss'),
|
||||
('Opinions', 'http://www.theglobeandmail.com/news/opinions/?service=rss'),
|
||||
('Columnists', 'http://www.theglobeandmail.com/news/opinions/columnists/?service=rss'),
|
||||
('Globe Investor', 'http://www.theglobeandmail.com/globe-investor/?service=rss'),
|
||||
('Sports', 'http://www.theglobeandmail.com/sports/?service=rss'),
|
||||
('Technology', 'http://www.theglobeandmail.com/news/technology/?service=rss'),
|
||||
('Arts', 'http://www.theglobeandmail.com/news/arts/?service=rss'),
|
||||
('Life', 'http://www.theglobeandmail.com/life/?service=rss'),
|
||||
('Blogs', 'http://www.theglobeandmail.com/blogs/?service=rss'),
|
||||
('Real Estate', 'http://www.theglobeandmail.com/real-estate/?service=rss'),
|
||||
('Auto', 'http://www.theglobeandmail.com/auto/?service=rss'),
|
||||
(u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'),
|
||||
(u'Top stories', u'http://www.theglobeandmail.com/?service=rss&feed=topstories'),
|
||||
(u'National', u'http://www.theglobeandmail.com/news/national/?service=rss'),
|
||||
(u'Politics', u'http://www.theglobeandmail.com/news/politics/?service=rss'),
|
||||
(u'World', u'http://www.theglobeandmail.com/news/world/?service=rss'),
|
||||
(u'Business', u'http://www.theglobeandmail.com/report-on-business/?service=rss'),
|
||||
(u'Opinions', u'http://www.theglobeandmail.com/news/opinions/?service=rss'),
|
||||
(u'Columnists', u'http://www.theglobeandmail.com/news/opinions/columnists/?service=rss'),
|
||||
(u'Globe Investor', u'http://www.theglobeandmail.com/globe-investor/?service=rss'),
|
||||
(u'Sports', u'http://www.theglobeandmail.com/sports/?service=rss'),
|
||||
(u'Technology', u'http://www.theglobeandmail.com/news/technology/?service=rss'),
|
||||
(u'Arts', u'http://www.theglobeandmail.com/news/arts/?service=rss'),
|
||||
(u'Life', u'http://www.theglobeandmail.com/life/?service=rss'),
|
||||
(u'Blogs', u'http://www.theglobeandmail.com/blogs/?service=rss'),
|
||||
(u'Real Estate', u'http://www.theglobeandmail.com/real-estate/?service=rss'),
|
||||
(u'Auto', u'http://www.theglobeandmail.com/auto/?service=rss')
|
||||
]
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user