mirror of
https://github.com/kovidgoyal/calibre.git
synced 2025-07-09 03:04:10 -04:00
Factor out code to make a unique name
This commit is contained in:
parent
f1cfe3cb29
commit
de114b91f0
@ -1,50 +1,63 @@
|
||||
#!/usr/bin/env python2
|
||||
# vim:fileencoding=UTF-8:ts=4:sw=4:sta:et:sts=4:fdm=marker:ai
|
||||
from __future__ import (unicode_literals, division, absolute_import,
|
||||
print_function)
|
||||
# License: GPLv3 Copyright: 2013, Kovid Goyal <kovid at kovidgoyal.net>
|
||||
from __future__ import absolute_import, division, print_function, unicode_literals
|
||||
|
||||
__license__ = 'GPL v3'
|
||||
__copyright__ = '2013, Kovid Goyal <kovid at kovidgoyal.net>'
|
||||
__docformat__ = 'restructuredtext en'
|
||||
|
||||
import os, logging, sys, hashlib, uuid, re, shutil, unicodedata, errno, time
|
||||
import errno
|
||||
import hashlib
|
||||
import logging
|
||||
import os
|
||||
import re
|
||||
import shutil
|
||||
import sys
|
||||
import time
|
||||
import unicodedata
|
||||
import uuid
|
||||
from collections import defaultdict
|
||||
from io import BytesIO
|
||||
from urlparse import urlparse
|
||||
from future_builtins import zip
|
||||
from io import BytesIO
|
||||
from itertools import count
|
||||
from urlparse import urlparse
|
||||
|
||||
from cssutils import getUrls, replaceUrls
|
||||
from lxml import etree
|
||||
from cssutils import replaceUrls, getUrls
|
||||
|
||||
from calibre import CurrentDir
|
||||
from calibre.constants import iswindows
|
||||
from calibre.customize.ui import (plugin_for_input_format, plugin_for_output_format)
|
||||
from calibre.customize.ui import plugin_for_input_format, plugin_for_output_format
|
||||
from calibre.ebooks import escape_xpath_attr
|
||||
from calibre.ebooks.chardet import xml_to_unicode
|
||||
from calibre.ebooks.conversion.plugins.epub_input import (
|
||||
ADOBE_OBFUSCATION, IDPF_OBFUSCATION, decrypt_font_data)
|
||||
from calibre.ebooks.conversion.preprocess import HTMLPreProcessor, CSSPreProcessor as cssp
|
||||
from calibre.ebooks.metadata.opf3 import read_prefixes, items_with_property, ensure_prefix, CALIBRE_PREFIX
|
||||
ADOBE_OBFUSCATION, IDPF_OBFUSCATION, decrypt_font_data
|
||||
)
|
||||
from calibre.ebooks.conversion.preprocess import (
|
||||
CSSPreProcessor as cssp, HTMLPreProcessor
|
||||
)
|
||||
from calibre.ebooks.metadata.opf3 import (
|
||||
CALIBRE_PREFIX, ensure_prefix, items_with_property, read_prefixes
|
||||
)
|
||||
from calibre.ebooks.metadata.utils import parse_opf_version
|
||||
from calibre.ebooks.mobi import MobiError
|
||||
from calibre.ebooks.mobi.reader.headers import MetadataHeader
|
||||
from calibre.ebooks.mobi.tweak import set_cover
|
||||
from calibre.ebooks.oeb.base import (
|
||||
serialize, OEB_DOCS, OEB_STYLES, OPF2_NS, DC11_NS, OPF, Manifest,
|
||||
rewrite_links, iterlinks, itercsslinks, urlquote, urlunquote)
|
||||
from calibre.ebooks.oeb.polish.errors import InvalidBook, DRMError
|
||||
DC11_NS, OEB_DOCS, OEB_STYLES, OPF, OPF2_NS, Manifest, itercsslinks, iterlinks,
|
||||
rewrite_links, serialize, urlquote, urlunquote
|
||||
)
|
||||
from calibre.ebooks.oeb.parse_utils import RECOVER_PARSER, NotHTML, parse_html
|
||||
from calibre.ebooks.oeb.polish.errors import DRMError, InvalidBook
|
||||
from calibre.ebooks.oeb.polish.parsing import parse as parse_html_tweak
|
||||
from calibre.ebooks.oeb.polish.utils import PositionFinder, CommentFinder, guess_type, parse_css
|
||||
from calibre.ebooks.oeb.parse_utils import NotHTML, parse_html, RECOVER_PARSER
|
||||
from calibre.ebooks.oeb.polish.utils import (
|
||||
CommentFinder, PositionFinder, guess_type, parse_css
|
||||
)
|
||||
from calibre.ptempfile import PersistentTemporaryDirectory, PersistentTemporaryFile
|
||||
from calibre.utils.filenames import nlinks_file, hardlink_file
|
||||
from calibre.utils.ipc.simple_worker import fork_job, WorkerError
|
||||
from calibre.utils.filenames import hardlink_file, nlinks_file
|
||||
from calibre.utils.ipc.simple_worker import WorkerError, fork_job
|
||||
from calibre.utils.logging import default_log
|
||||
from calibre.utils.zipfile import ZipFile
|
||||
|
||||
exists, join, relpath = os.path.exists, os.path.join, os.path.relpath
|
||||
|
||||
|
||||
OEB_FONTS = {guess_type('a.ttf'), guess_type('b.otf'), guess_type('a.woff'), 'application/x-font-ttf', 'application/x-font-otf', 'application/font-sfnt'}
|
||||
OPF_NAMESPACES = {'opf':OPF2_NS, 'dc':DC11_NS}
|
||||
|
||||
@ -319,6 +332,16 @@ class Container(ContainerBase): # {{{
|
||||
all_names = {self.href_to_name(x.get('href'), self.opf_name) for x in self.opf_xpath('//opf:manifest/opf:item[@href]')}
|
||||
return name in all_names
|
||||
|
||||
def make_name_unique(self, name):
|
||||
counter = count()
|
||||
while self.has_name_case_insensitive(name) or self.manifest_has_name(name):
|
||||
c = next(counter) + 1
|
||||
base, ext = name.rpartition('.')[::2]
|
||||
if c > 1:
|
||||
base = base.rpartition('-')[0]
|
||||
name = '%s-%d.%s' % (base, c, ext)
|
||||
return name
|
||||
|
||||
def add_file(self, name, data, media_type=None, spine_index=None, modify_name_if_needed=False, process_manifest_item=None):
|
||||
''' Add a file to this container. Entries for the file are
|
||||
automatically created in the OPF manifest and spine
|
||||
@ -330,15 +353,8 @@ class Container(ContainerBase): # {{{
|
||||
if not modify_name_if_needed:
|
||||
raise ValueError(('A file with the name %s already exists' % name) if self.has_name_case_insensitive(name) else
|
||||
('An item with the href %s already exists in the manifest' % href))
|
||||
base, ext = name.rpartition('.')[::2]
|
||||
c = 0
|
||||
while True:
|
||||
c += 1
|
||||
q = '%s-%d.%s' % (base, c, ext)
|
||||
href = self.name_to_href(q, self.opf_name)
|
||||
if not self.has_name_case_insensitive(q) and not self.manifest_has_name(q):
|
||||
name = q
|
||||
break
|
||||
name = self.make_name_unique(name)
|
||||
href = self.name_to_href(name, self.opf_name)
|
||||
path = self.name_to_abspath(name)
|
||||
base = os.path.dirname(path)
|
||||
if not os.path.exists(base):
|
||||
@ -871,6 +887,8 @@ class Container(ContainerBase): # {{{
|
||||
generated item.'''
|
||||
id_prefix = id_prefix or 'id'
|
||||
media_type = media_type or guess_type(name)
|
||||
if unique_href:
|
||||
name = self.make_name_unique(name)
|
||||
href = self.name_to_href(name, self.opf_name)
|
||||
base, ext = href.rpartition('.')[0::2]
|
||||
all_ids = {x.get('id') for x in self.opf_xpath('//*[@id]')}
|
||||
@ -880,15 +898,6 @@ class Container(ContainerBase): # {{{
|
||||
c += 1
|
||||
item_id = id_prefix + '%d'%c
|
||||
|
||||
def exists(h):
|
||||
n = self.href_to_name(h, self.opf_name)
|
||||
return self.exists(n) or self.manifest_has_name(n)
|
||||
|
||||
if unique_href:
|
||||
c = 0
|
||||
while exists(href):
|
||||
c += 1
|
||||
href = '%s_%d.%s'%(base, c, ext)
|
||||
manifest = self.opf_xpath('//opf:manifest')[0]
|
||||
item = manifest.makeelement(OPF('item'),
|
||||
id=item_id, href=href)
|
||||
|
@ -186,6 +186,9 @@ class ContainerTests(BaseTest):
|
||||
self.assertEqual('xxx', c.raw_data(name))
|
||||
self.assertIn(name, set(c.manifest_id_map.itervalues()))
|
||||
self.assertNotIn(name, {x[0] for x in c.spine_names})
|
||||
self.assertEqual(c.make_name_unique(name), 'added-1.css')
|
||||
c.add_file('added-1.css', b'xxx')
|
||||
self.assertEqual(c.make_name_unique(name.upper()), 'added-2.css'.upper())
|
||||
|
||||
self.check_links(c)
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user