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
27eb1a21b6
@ -31,3 +31,4 @@ nbproject/
|
|||||||
.pydevproject
|
.pydevproject
|
||||||
.settings/
|
.settings/
|
||||||
*.DS_Store
|
*.DS_Store
|
||||||
|
calibre_plugins/
|
55
recipes/dilemaveche.recipe
Normal file
55
recipes/dilemaveche.recipe
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
#!/usr/bin/env python
|
||||||
|
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = u'2011, Silviu Cotoar\u0103'
|
||||||
|
'''
|
||||||
|
dilemaveche.ro
|
||||||
|
'''
|
||||||
|
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
|
||||||
|
class DilemaVeche(BasicNewsRecipe):
|
||||||
|
title = u'Dilema Veche'
|
||||||
|
__author__ = u'Silviu Cotoar\u0103'
|
||||||
|
description = u'Sunt vechi, domnule!'
|
||||||
|
publisher = u'Dilema Veche'
|
||||||
|
oldest_article = 50
|
||||||
|
language = 'ro'
|
||||||
|
max_articles_per_feed = 100
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
category = 'Ziare'
|
||||||
|
encoding = 'utf-8'
|
||||||
|
cover_url = 'http://www.dilemaveche.ro/sites/all/themes/dilema/theme/dilema_two/layouter/dilema_two_homepage/logo.png'
|
||||||
|
|
||||||
|
conversion_options = {
|
||||||
|
'comments' : description
|
||||||
|
,'tags' : category
|
||||||
|
,'language' : language
|
||||||
|
,'publisher' : publisher
|
||||||
|
}
|
||||||
|
|
||||||
|
keep_only_tags = [
|
||||||
|
dict(name='h1', attrs={'class':'art_title'})
|
||||||
|
, dict(name='h1', attrs={'class':'art_title online'})
|
||||||
|
, dict(name='div', attrs={'class':'item'})
|
||||||
|
, dict(name='div', attrs={'class':'art_content'})
|
||||||
|
]
|
||||||
|
|
||||||
|
remove_tags = [
|
||||||
|
dict(name='div', attrs={'class':['article_details']})
|
||||||
|
, dict(name='div', attrs={'class':['controale']})
|
||||||
|
, dict(name='div', attrs={'class':['art_related_left']})
|
||||||
|
]
|
||||||
|
|
||||||
|
remove_tags_after = [
|
||||||
|
dict(name='div', attrs={'class':['article_details']})
|
||||||
|
]
|
||||||
|
|
||||||
|
feeds = [
|
||||||
|
(u'Feeds', u'http://www.dilemaveche.ro/rss.xml')
|
||||||
|
]
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
return self.adeify_images(soup)
|
@ -6,13 +6,13 @@ __copyright__ = 'Copyright 2010 Starson17'
|
|||||||
www.gocomics.com
|
www.gocomics.com
|
||||||
'''
|
'''
|
||||||
from calibre.web.feeds.news import BasicNewsRecipe
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
import mechanize
|
import mechanize, re
|
||||||
|
|
||||||
class GoComics(BasicNewsRecipe):
|
class GoComics(BasicNewsRecipe):
|
||||||
title = 'GoComics'
|
title = 'GoComics'
|
||||||
__author__ = 'Starson17'
|
__author__ = 'Starson17'
|
||||||
__version__ = '1.03'
|
__version__ = '1.05'
|
||||||
__date__ = '09 October 2010'
|
__date__ = '19 may 2011'
|
||||||
description = u'200+ Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
|
description = u'200+ Comics - Customize for more days/comics: Defaults to 7 days, 25 comics - 20 general, 5 editorial.'
|
||||||
category = 'news, comics'
|
category = 'news, comics'
|
||||||
language = 'en'
|
language = 'en'
|
||||||
@ -20,6 +20,7 @@ class GoComics(BasicNewsRecipe):
|
|||||||
no_stylesheets = True
|
no_stylesheets = True
|
||||||
remove_javascript = True
|
remove_javascript = True
|
||||||
cover_url = 'http://paulbuckley14059.files.wordpress.com/2008/06/calvin-and-hobbes.jpg'
|
cover_url = 'http://paulbuckley14059.files.wordpress.com/2008/06/calvin-and-hobbes.jpg'
|
||||||
|
remove_attributes = ['style']
|
||||||
|
|
||||||
####### USER PREFERENCES - COMICS, IMAGE SIZE AND NUMBER OF COMICS TO RETRIEVE ########
|
####### USER PREFERENCES - COMICS, IMAGE SIZE AND NUMBER OF COMICS TO RETRIEVE ########
|
||||||
# num_comics_to_get - I've tried up to 99 on Calvin&Hobbes
|
# num_comics_to_get - I've tried up to 99 on Calvin&Hobbes
|
||||||
@ -40,6 +41,8 @@ class GoComics(BasicNewsRecipe):
|
|||||||
|
|
||||||
remove_tags = [dict(name='a', attrs={'class':['beginning','prev','cal','next','newest']}),
|
remove_tags = [dict(name='a', attrs={'class':['beginning','prev','cal','next','newest']}),
|
||||||
dict(name='div', attrs={'class':['tag-wrapper']}),
|
dict(name='div', attrs={'class':['tag-wrapper']}),
|
||||||
|
dict(name='a', attrs={'href':re.compile(r'.*mutable_[0-9]+', re.IGNORECASE)}),
|
||||||
|
dict(name='img', attrs={'src':re.compile(r'.*mutable_[0-9]+', re.IGNORECASE)}),
|
||||||
dict(name='ul', attrs={'class':['share-nav','feature-nav']}),
|
dict(name='ul', attrs={'class':['share-nav','feature-nav']}),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
BIN
recipes/icons/dilemaveche.png
Normal file
BIN
recipes/icons/dilemaveche.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 558 B |
BIN
recipes/icons/natgeo.png
Normal file
BIN
recipes/icons/natgeo.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 247 B |
@ -3,8 +3,9 @@ from calibre.web.feeds.news import BasicNewsRecipe
|
|||||||
class AdvancedUserRecipe1295262156(BasicNewsRecipe):
|
class AdvancedUserRecipe1295262156(BasicNewsRecipe):
|
||||||
title = u'kath.net'
|
title = u'kath.net'
|
||||||
__author__ = 'Bobus'
|
__author__ = 'Bobus'
|
||||||
|
description = u'Katholische Nachrichten'
|
||||||
oldest_article = 7
|
oldest_article = 7
|
||||||
language = 'en'
|
language = 'de'
|
||||||
max_articles_per_feed = 100
|
max_articles_per_feed = 100
|
||||||
|
|
||||||
feeds = [(u'kath.net', u'http://www.kath.net/2005/xml/index.xml')]
|
feeds = [(u'kath.net', u'http://www.kath.net/2005/xml/index.xml')]
|
||||||
|
71
recipes/natgeo.recipe
Normal file
71
recipes/natgeo.recipe
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#!/usr/bin/env python
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
__license__ = 'GPL v3'
|
||||||
|
__copyright__ = '2011, gagsays <gagsays at gmail dot com>'
|
||||||
|
'''
|
||||||
|
nationalgeographic.com
|
||||||
|
'''
|
||||||
|
from calibre.web.feeds.news import BasicNewsRecipe
|
||||||
|
class NatGeo(BasicNewsRecipe):
|
||||||
|
title = u'National Geographic'
|
||||||
|
description = 'Daily news articles from The National Geographic'
|
||||||
|
language = 'en'
|
||||||
|
oldest_article = 20
|
||||||
|
max_articles_per_feed = 25
|
||||||
|
encoding = 'utf8'
|
||||||
|
publisher = 'nationalgeographic.com'
|
||||||
|
category = 'science, nat geo'
|
||||||
|
__author__ = 'gagsays'
|
||||||
|
masthead_url = 'http://s.ngeo.com/wpf/sites/themes/global/i/presentation/ng_logo_small.png'
|
||||||
|
description = 'Inspiring people to care about the planet since 1888'
|
||||||
|
timefmt = ' [%a, %d %b, %Y]'
|
||||||
|
no_stylesheets = True
|
||||||
|
use_embedded_content = False
|
||||||
|
|
||||||
|
extra_css = '''
|
||||||
|
body {color: #000000;font-size: medium;}
|
||||||
|
h1 {color: #222222; font-size: large; font-weight:lighter; text-decoration:none; text-align: center;font-family:Georgia,Times New Roman,Times,serif;}
|
||||||
|
h2 {color: #454545; font-size: small; font-weight:lighter; text-decoration:none; text-align: justify; font-style:italic;font-family :Georgia,Times New Roman,Times,serif;}
|
||||||
|
h3 {color: #555555; font-size: small; font-style:italic; margin-top: 10px;}
|
||||||
|
img{margin-bottom: 0.25em;display:block;margin-left: auto;margin-right: auto;}
|
||||||
|
a:link,a,.a,href {text-decoration: none;color: #000000;}
|
||||||
|
.caption{color: #000000;font-size: xx-small;text-align: justify;font-weight:normal;}
|
||||||
|
.credit{color: #555555;font-size: xx-small;text-align: left;font-weight:lighter;}
|
||||||
|
p.author,p.publication{color: #000000;font-size: xx-small;text-align: left;display:inline;}
|
||||||
|
p.publication_time{color: #000000;font-size: xx-small;text-align: right;text-decoration: underline;}
|
||||||
|
p {margin-bottom: 0;}
|
||||||
|
p + p {text-indent: 1.5em;margin-top: 0;}
|
||||||
|
.hidden{display:none;}
|
||||||
|
#page_head{text-transform:uppercase;}
|
||||||
|
'''
|
||||||
|
|
||||||
|
def parse_feeds (self):
|
||||||
|
feeds = BasicNewsRecipe.parse_feeds(self)
|
||||||
|
for feed in feeds:
|
||||||
|
for article in feed.articles[:]:
|
||||||
|
if 'Presented' in article.title or 'Pictures' in article.title:
|
||||||
|
feed.articles.remove(article)
|
||||||
|
return feeds
|
||||||
|
|
||||||
|
def preprocess_html(self, soup):
|
||||||
|
for alink in soup.findAll('a'):
|
||||||
|
if alink.string is not None:
|
||||||
|
tstr = alink.string
|
||||||
|
alink.replaceWith(tstr)
|
||||||
|
return soup
|
||||||
|
|
||||||
|
remove_tags_before = dict(id='page_head')
|
||||||
|
keep_only_tags = [
|
||||||
|
dict(name='div',attrs={'id':['page_head','content_mainA']})
|
||||||
|
]
|
||||||
|
remove_tags_after = [
|
||||||
|
dict(name='div',attrs={'class':['article_text','promo_collection']})
|
||||||
|
]
|
||||||
|
remove_tags = [
|
||||||
|
dict(name='div', attrs={'class':['aside','primary full_width']})
|
||||||
|
,dict(name='div', attrs={'id':['header_search','navigation_mainB_wrap']})
|
||||||
|
]
|
||||||
|
feeds = [
|
||||||
|
(u'Daily News', u'http://feeds.nationalgeographic.com/ng/News/News_Main')
|
||||||
|
]
|
||||||
|
|
@ -1199,6 +1199,11 @@ class StoreOpenLibraryStore(StoreBase):
|
|||||||
description = _('One web page for every book.')
|
description = _('One web page for every book.')
|
||||||
actual_plugin = 'calibre.gui2.store.open_library_plugin:OpenLibraryStore'
|
actual_plugin = 'calibre.gui2.store.open_library_plugin:OpenLibraryStore'
|
||||||
|
|
||||||
|
class StoreOReillyStore(StoreBase):
|
||||||
|
name = 'OReilly'
|
||||||
|
description = _('DRM-Free tech ebooks.')
|
||||||
|
actual_plugin = 'calibre.gui2.store.oreilly_plugin:OReillyStore'
|
||||||
|
|
||||||
class StoreSmashwordsStore(StoreBase):
|
class StoreSmashwordsStore(StoreBase):
|
||||||
name = 'Smashwords'
|
name = 'Smashwords'
|
||||||
description = _('Your ebook. Your way.')
|
description = _('Your ebook. Your way.')
|
||||||
@ -1226,7 +1231,8 @@ plugins += [StoreArchiveOrgStore, StoreAmazonKindleStore, StoreAmazonDEKindleSto
|
|||||||
StoreEHarlequinStore, StoreFeedbooksStore,
|
StoreEHarlequinStore, StoreFeedbooksStore,
|
||||||
StoreFoylesUKStore, StoreGoogleBooksStore, StoreGutenbergStore,
|
StoreFoylesUKStore, StoreGoogleBooksStore, StoreGutenbergStore,
|
||||||
StoreKoboStore, StoreManyBooksStore,
|
StoreKoboStore, StoreManyBooksStore,
|
||||||
StoreMobileReadStore, StoreNextoStore, StoreOpenLibraryStore, StoreSmashwordsStore,
|
StoreMobileReadStore, StoreNextoStore, StoreOpenLibraryStore,
|
||||||
|
StoreOReillyStore, StoreSmashwordsStore,
|
||||||
StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWizardsTowerBooksStore]
|
StoreWaterstonesUKStore, StoreWeightlessBooksStore, StoreWizardsTowerBooksStore]
|
||||||
|
|
||||||
# }}}
|
# }}}
|
||||||
|
@ -941,7 +941,7 @@ class ITUNES(DriverBase):
|
|||||||
# declared in use_plugboard_ext and a device name of ITUNES
|
# declared in use_plugboard_ext and a device name of ITUNES
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info("ITUNES.set_plugboard()")
|
self.log.info("ITUNES.set_plugboard()")
|
||||||
#self.log.info(' using plugboard %s' % plugboards)
|
#self.log.info(' plugboard: %s' % plugboards)
|
||||||
self.plugboards = plugboards
|
self.plugboards = plugboards
|
||||||
self.plugboard_func = pb_func
|
self.plugboard_func = pb_func
|
||||||
|
|
||||||
@ -1052,7 +1052,6 @@ class ITUNES(DriverBase):
|
|||||||
'title': metadata[i].title,
|
'title': metadata[i].title,
|
||||||
'uuid': metadata[i].uuid }
|
'uuid': metadata[i].uuid }
|
||||||
|
|
||||||
|
|
||||||
# Report progress
|
# Report progress
|
||||||
if self.report_progress is not None:
|
if self.report_progress is not None:
|
||||||
self.report_progress((i+1)/file_count, _('%d of %d') % (i+1, file_count))
|
self.report_progress((i+1)/file_count, _('%d of %d') % (i+1, file_count))
|
||||||
@ -2744,7 +2743,7 @@ class ITUNES(DriverBase):
|
|||||||
# Update metadata from plugboard
|
# Update metadata from plugboard
|
||||||
# If self.plugboard is None (no transforms), original metadata is returned intact
|
# If self.plugboard is None (no transforms), original metadata is returned intact
|
||||||
metadata_x = self._xform_metadata_via_plugboard(metadata, this_book.format)
|
metadata_x = self._xform_metadata_via_plugboard(metadata, this_book.format)
|
||||||
|
self.log("metadata.title_sort: %s metadata_x.title_sort: %s" % (metadata.title_sort, metadata_x.title_sort))
|
||||||
if isosx:
|
if isosx:
|
||||||
if lb_added:
|
if lb_added:
|
||||||
lb_added.name.set(metadata_x.title)
|
lb_added.name.set(metadata_x.title)
|
||||||
@ -2754,8 +2753,7 @@ class ITUNES(DriverBase):
|
|||||||
lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
lb_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||||
lb_added.enabled.set(True)
|
lb_added.enabled.set(True)
|
||||||
lb_added.sort_artist.set(icu_title(metadata_x.author_sort))
|
lb_added.sort_artist.set(icu_title(metadata_x.author_sort))
|
||||||
lb_added.sort_name.set(metadata.title_sort)
|
lb_added.sort_name.set(metadata_x.title_sort)
|
||||||
|
|
||||||
|
|
||||||
if db_added:
|
if db_added:
|
||||||
db_added.name.set(metadata_x.title)
|
db_added.name.set(metadata_x.title)
|
||||||
@ -2765,7 +2763,7 @@ class ITUNES(DriverBase):
|
|||||||
db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
db_added.description.set("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||||
db_added.enabled.set(True)
|
db_added.enabled.set(True)
|
||||||
db_added.sort_artist.set(icu_title(metadata_x.author_sort))
|
db_added.sort_artist.set(icu_title(metadata_x.author_sort))
|
||||||
db_added.sort_name.set(metadata.title_sort)
|
db_added.sort_name.set(metadata_x.title_sort)
|
||||||
|
|
||||||
if metadata_x.comments:
|
if metadata_x.comments:
|
||||||
if lb_added:
|
if lb_added:
|
||||||
@ -2785,6 +2783,7 @@ class ITUNES(DriverBase):
|
|||||||
|
|
||||||
# Set genre from series if available, else first alpha tag
|
# Set genre from series if available, else first alpha tag
|
||||||
# Otherwise iTunes grabs the first dc:subject from the opf metadata
|
# Otherwise iTunes grabs the first dc:subject from the opf metadata
|
||||||
|
# If title_sort applied in plugboard, that overrides using series/index as title_sort
|
||||||
if metadata_x.series and self.settings().extra_customization[self.USE_SERIES_AS_CATEGORY]:
|
if metadata_x.series and self.settings().extra_customization[self.USE_SERIES_AS_CATEGORY]:
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
self.log.info(" ITUNES._update_iTunes_metadata()")
|
self.log.info(" ITUNES._update_iTunes_metadata()")
|
||||||
@ -2796,7 +2795,9 @@ class ITUNES(DriverBase):
|
|||||||
fraction = index-integer
|
fraction = index-integer
|
||||||
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
|
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
|
||||||
if lb_added:
|
if lb_added:
|
||||||
lb_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
|
# If no title_sort plugboard tweak, create sort_name from series/index
|
||||||
|
if metadata.title_sort == metadata_x.title_sort:
|
||||||
|
lb_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
|
||||||
lb_added.episode_ID.set(metadata_x.series)
|
lb_added.episode_ID.set(metadata_x.series)
|
||||||
lb_added.episode_number.set(metadata_x.series_index)
|
lb_added.episode_number.set(metadata_x.series_index)
|
||||||
|
|
||||||
@ -2810,7 +2811,9 @@ class ITUNES(DriverBase):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if db_added:
|
if db_added:
|
||||||
db_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
|
# If no title_sort plugboard tweak, create sort_name from series/index
|
||||||
|
if metadata.title_sort == metadata_x.title_sort:
|
||||||
|
db_added.sort_name.set("%s %s" % (self.title_sorter(metadata_x.series), series_index))
|
||||||
db_added.episode_ID.set(metadata_x.series)
|
db_added.episode_ID.set(metadata_x.series)
|
||||||
db_added.episode_number.set(metadata_x.series_index)
|
db_added.episode_number.set(metadata_x.series_index)
|
||||||
|
|
||||||
@ -2845,7 +2848,7 @@ class ITUNES(DriverBase):
|
|||||||
lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
lb_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||||
lb_added.Enabled = True
|
lb_added.Enabled = True
|
||||||
lb_added.SortArtist = icu_title(metadata_x.author_sort)
|
lb_added.SortArtist = icu_title(metadata_x.author_sort)
|
||||||
lb_added.SortName = metadata.title_sort
|
lb_added.SortName = metadata_x.title_sort
|
||||||
|
|
||||||
if db_added:
|
if db_added:
|
||||||
db_added.Name = metadata_x.title
|
db_added.Name = metadata_x.title
|
||||||
@ -2855,7 +2858,7 @@ class ITUNES(DriverBase):
|
|||||||
db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
db_added.Description = ("%s %s" % (self.description_prefix,strftime('%Y-%m-%d %H:%M:%S')))
|
||||||
db_added.Enabled = True
|
db_added.Enabled = True
|
||||||
db_added.SortArtist = icu_title(metadata_x.author_sort)
|
db_added.SortArtist = icu_title(metadata_x.author_sort)
|
||||||
db_added.SortName = metadata.title_sort
|
db_added.SortName = metadata_x.title_sort
|
||||||
|
|
||||||
if metadata_x.comments:
|
if metadata_x.comments:
|
||||||
if lb_added:
|
if lb_added:
|
||||||
@ -2888,7 +2891,9 @@ class ITUNES(DriverBase):
|
|||||||
fraction = index-integer
|
fraction = index-integer
|
||||||
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
|
series_index = '%04d%s' % (integer, str('%0.4f' % fraction).lstrip('0'))
|
||||||
if lb_added:
|
if lb_added:
|
||||||
lb_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
|
# If no title_sort plugboard tweak, create sort_name from series/index
|
||||||
|
if metadata.title_sort == metadata_x.title_sort:
|
||||||
|
lb_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
|
||||||
lb_added.EpisodeID = metadata_x.series
|
lb_added.EpisodeID = metadata_x.series
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -2914,7 +2919,9 @@ class ITUNES(DriverBase):
|
|||||||
break
|
break
|
||||||
|
|
||||||
if db_added:
|
if db_added:
|
||||||
db_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
|
# If no title_sort plugboard tweak, create sort_name from series/index
|
||||||
|
if metadata.title_sort == metadata_x.title_sort:
|
||||||
|
db_added.SortName = "%s %s" % (self.title_sorter(metadata_x.series), series_index)
|
||||||
db_added.EpisodeID = metadata_x.series
|
db_added.EpisodeID = metadata_x.series
|
||||||
|
|
||||||
try:
|
try:
|
||||||
@ -2975,6 +2982,9 @@ class ITUNES(DriverBase):
|
|||||||
newmi.publisher if book.publisher != newmi.publisher else ''))
|
newmi.publisher if book.publisher != newmi.publisher else ''))
|
||||||
self.log.info(" tags: %s %s" % (book.tags, ">>> %s" %
|
self.log.info(" tags: %s %s" % (book.tags, ">>> %s" %
|
||||||
newmi.tags if book.tags != newmi.tags else ''))
|
newmi.tags if book.tags != newmi.tags else ''))
|
||||||
|
else:
|
||||||
|
self.log(" matching plugboard not found")
|
||||||
|
|
||||||
else:
|
else:
|
||||||
newmi = book
|
newmi = book
|
||||||
return newmi
|
return newmi
|
||||||
|
@ -9,11 +9,12 @@ from functools import partial
|
|||||||
|
|
||||||
from PyQt4.Qt import QMenu, QObject, QTimer
|
from PyQt4.Qt import QMenu, QObject, QTimer
|
||||||
|
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog, question_dialog
|
||||||
from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog
|
from calibre.gui2.dialogs.delete_matching_from_device import DeleteMatchingFromDeviceDialog
|
||||||
from calibre.gui2.dialogs.confirm_delete import confirm
|
from calibre.gui2.dialogs.confirm_delete import confirm
|
||||||
from calibre.gui2.dialogs.confirm_delete_location import confirm_location
|
from calibre.gui2.dialogs.confirm_delete_location import confirm_location
|
||||||
from calibre.gui2.actions import InterfaceAction
|
from calibre.gui2.actions import InterfaceAction
|
||||||
|
from calibre.utils.recycle_bin import can_recycle
|
||||||
|
|
||||||
single_shot = partial(QTimer.singleShot, 10)
|
single_shot = partial(QTimer.singleShot, 10)
|
||||||
|
|
||||||
@ -24,6 +25,15 @@ class MultiDeleter(QObject):
|
|||||||
QObject.__init__(self, gui)
|
QObject.__init__(self, gui)
|
||||||
self.model = gui.library_view.model()
|
self.model = gui.library_view.model()
|
||||||
self.ids = ids
|
self.ids = ids
|
||||||
|
self.permanent = False
|
||||||
|
if can_recycle and len(ids) > 100:
|
||||||
|
if question_dialog(gui, _('Are you sure?'), '<p>'+
|
||||||
|
_('You are trying to delete %d books. '
|
||||||
|
'Sending so many files to the Recycle'
|
||||||
|
' Bin <b>can be slow</b>. Should calibre skip the'
|
||||||
|
' Recycle Bin? If you click Yes the files'
|
||||||
|
' will be <b>permanently deleted</b>.')%len(ids)):
|
||||||
|
self.permanent = True
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
self.failures = []
|
self.failures = []
|
||||||
self.deleted_ids = []
|
self.deleted_ids = []
|
||||||
@ -44,7 +54,8 @@ class MultiDeleter(QObject):
|
|||||||
title_ = self.model.db.title(id_, index_is_id=True)
|
title_ = self.model.db.title(id_, index_is_id=True)
|
||||||
if title_:
|
if title_:
|
||||||
title = title_
|
title = title_
|
||||||
self.model.db.delete_book(id_, notify=False, commit=False)
|
self.model.db.delete_book(id_, notify=False, commit=False,
|
||||||
|
permanent=self.permanent)
|
||||||
self.deleted_ids.append(id_)
|
self.deleted_ids.append(id_)
|
||||||
except:
|
except:
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -246,6 +246,8 @@ class BarsManager(QObject):
|
|||||||
self.main_bars = tuple(bars[:2])
|
self.main_bars = tuple(bars[:2])
|
||||||
self.child_bars = tuple(bars[2:])
|
self.child_bars = tuple(bars[2:])
|
||||||
|
|
||||||
|
self.menu_bar = MenuBar(self.location_manager, self.parent())
|
||||||
|
self.parent().setMenuBar(self.menu_bar)
|
||||||
|
|
||||||
self.apply_settings()
|
self.apply_settings()
|
||||||
self.init_bars()
|
self.init_bars()
|
||||||
@ -295,11 +297,9 @@ class BarsManager(QObject):
|
|||||||
if child_bar.added_actions:
|
if child_bar.added_actions:
|
||||||
child_bar.setVisible(True)
|
child_bar.setVisible(True)
|
||||||
|
|
||||||
self.menu_bar = MenuBar(self.location_manager, self.parent())
|
|
||||||
self.menu_bar.init_bar(self.bar_actions[4 if showing_device else 3])
|
self.menu_bar.init_bar(self.bar_actions[4 if showing_device else 3])
|
||||||
self.menu_bar.update_lm_actions()
|
self.menu_bar.update_lm_actions()
|
||||||
self.menu_bar.setVisible(bool(self.menu_bar.added_actions))
|
self.menu_bar.setVisible(bool(self.menu_bar.added_actions))
|
||||||
self.parent().setMenuBar(self.menu_bar)
|
|
||||||
|
|
||||||
def apply_settings(self):
|
def apply_settings(self):
|
||||||
sz = gprefs['toolbar_icon_size']
|
sz = gprefs['toolbar_icon_size']
|
||||||
|
@ -78,22 +78,22 @@
|
|||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
<layout class="QGridLayout">
|
||||||
<item>
|
<item row="0" column="0">
|
||||||
<widget class="QPushButton" name="sort_by_author">
|
<widget class="QPushButton" name="sort_by_author">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sort by author</string>
|
<string>Sort by author</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="0" column="1">
|
||||||
<widget class="QPushButton" name="sort_by_author_sort">
|
<widget class="QPushButton" name="sort_by_author_sort">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Sort by author sort</string>
|
<string>Sort by author sort</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="0">
|
||||||
<widget class="QPushButton" name="recalc_author_sort">
|
<widget class="QPushButton" name="recalc_author_sort">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Reset all the author sort values to a value automatically
|
<string>Reset all the author sort values to a value automatically
|
||||||
@ -105,7 +105,7 @@ generated can be controlled via Preferences->Advanced->Tweaks</string>
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="1">
|
||||||
<widget class="QPushButton" name="auth_sort_to_author">
|
<widget class="QPushButton" name="auth_sort_to_author">
|
||||||
<property name="toolTip">
|
<property name="toolTip">
|
||||||
<string>Copy author sort to author for every author. You typically use this button
|
<string>Copy author sort to author for every author. You typically use this button
|
||||||
@ -116,20 +116,7 @@ after changing Preferences->Advanced->Tweaks->Author sort name algorith
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
<item>
|
<item row="1" column="2">
|
||||||
<spacer name="horizontalSpacer_3">
|
|
||||||
<property name="orientation">
|
|
||||||
<enum>Qt::Horizontal</enum>
|
|
||||||
</property>
|
|
||||||
<property name="sizeHint" stdset="0">
|
|
||||||
<size>
|
|
||||||
<width>40</width>
|
|
||||||
<height>20</height>
|
|
||||||
</size>
|
|
||||||
</property>
|
|
||||||
</spacer>
|
|
||||||
</item>
|
|
||||||
<item>
|
|
||||||
<widget class="QDialogButtonBox" name="buttonBox">
|
<widget class="QDialogButtonBox" name="buttonBox">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
<sizepolicy hsizetype="Minimum" vsizetype="Fixed">
|
||||||
|
@ -5,17 +5,20 @@ __license__ = 'GPL v3'
|
|||||||
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
|
||||||
__docformat__ = 'restructuredtext en'
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import copy
|
||||||
|
|
||||||
from PyQt4.Qt import Qt, QLineEdit, QComboBox, SIGNAL, QListWidgetItem
|
from PyQt4.Qt import Qt, QLineEdit, QComboBox, SIGNAL, QListWidgetItem
|
||||||
|
|
||||||
from calibre.customize.ui import is_disabled
|
from calibre.customize.ui import is_disabled
|
||||||
from calibre.gui2 import error_dialog
|
from calibre.gui2 import error_dialog, question_dialog
|
||||||
from calibre.gui2.device import device_name_for_plugboards
|
from calibre.gui2.device import device_name_for_plugboards
|
||||||
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
from calibre.gui2.dialogs.template_dialog import TemplateDialog
|
||||||
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
from calibre.gui2.preferences import ConfigWidgetBase, test_widget
|
||||||
from calibre.gui2.preferences.plugboard_ui import Ui_Form
|
from calibre.gui2.preferences.plugboard_ui import Ui_Form
|
||||||
from calibre.customize.ui import metadata_writers, device_plugins
|
from calibre.customize.ui import metadata_writers, device_plugins
|
||||||
from calibre.library.save_to_disk import plugboard_any_format_value, \
|
from calibre.library.save_to_disk import plugboard_any_format_value, \
|
||||||
plugboard_any_device_value, plugboard_save_to_disk_value
|
plugboard_any_device_value, plugboard_save_to_disk_value, \
|
||||||
|
find_plugboard
|
||||||
from calibre.library.server.content import plugboard_content_server_value, \
|
from calibre.library.server.content import plugboard_content_server_value, \
|
||||||
plugboard_content_server_formats
|
plugboard_content_server_formats
|
||||||
from calibre.utils.formatter import validation_formatter
|
from calibre.utils.formatter import validation_formatter
|
||||||
@ -46,9 +49,6 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
def genesis(self, gui):
|
def genesis(self, gui):
|
||||||
self.gui = gui
|
self.gui = gui
|
||||||
self.db = gui.library_view.model().db
|
self.db = gui.library_view.model().db
|
||||||
self.current_plugboards = self.db.prefs.get('plugboards',{})
|
|
||||||
self.current_device = None
|
|
||||||
self.current_format = None
|
|
||||||
|
|
||||||
def initialize(self):
|
def initialize(self):
|
||||||
def field_cmp(x, y):
|
def field_cmp(x, y):
|
||||||
@ -64,6 +64,10 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
|
|
||||||
ConfigWidgetBase.initialize(self)
|
ConfigWidgetBase.initialize(self)
|
||||||
|
|
||||||
|
self.current_plugboards = copy.deepcopy(self.db.prefs.get('plugboards',{}))
|
||||||
|
self.current_device = None
|
||||||
|
self.current_format = None
|
||||||
|
|
||||||
if self.gui.device_manager.connected_device is not None:
|
if self.gui.device_manager.connected_device is not None:
|
||||||
self.device_label.setText(_('Device currently connected: ') +
|
self.device_label.setText(_('Device currently connected: ') +
|
||||||
self.gui.device_manager.connected_device.__class__.__name__)
|
self.gui.device_manager.connected_device.__class__.__name__)
|
||||||
@ -196,51 +200,66 @@ class ConfigWidget(ConfigWidgetBase, Ui_Form):
|
|||||||
return
|
return
|
||||||
self.clear_fields(edit_boxes=True)
|
self.clear_fields(edit_boxes=True)
|
||||||
self.current_device = unicode(txt)
|
self.current_device = unicode(txt)
|
||||||
error = False
|
|
||||||
if self.current_format == plugboard_any_format_value:
|
|
||||||
# user specified any format.
|
|
||||||
for f in self.current_plugboards:
|
|
||||||
devs = set(self.current_plugboards[f])
|
|
||||||
if self.current_device != plugboard_save_to_disk_value and \
|
|
||||||
plugboard_any_device_value in devs:
|
|
||||||
# specific format/any device in list. conflict.
|
|
||||||
# note: any device does not match save_to_disk
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
if self.current_device in devs:
|
|
||||||
# specific format/current device in list. conflict
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
if self.current_device == plugboard_any_device_value:
|
|
||||||
# any device and a specific device already there. conflict
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
else:
|
|
||||||
# user specified specific format.
|
|
||||||
for f in self.current_plugboards:
|
|
||||||
devs = set(self.current_plugboards[f])
|
|
||||||
if f == plugboard_any_format_value and \
|
|
||||||
self.current_device in devs:
|
|
||||||
# any format/same device in list. conflict.
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
if f == self.current_format and self.current_device in devs:
|
|
||||||
# current format/current device in list. conflict
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
if f == self.current_format and plugboard_any_device_value in devs:
|
|
||||||
# current format/any device in list. conflict
|
|
||||||
error = True
|
|
||||||
break
|
|
||||||
|
|
||||||
if error:
|
if self.current_format in self.current_plugboards and \
|
||||||
|
self.current_device in self.current_plugboards[self.current_format]:
|
||||||
error_dialog(self, '',
|
error_dialog(self, '',
|
||||||
_('That format and device already has a plugboard or '
|
_('That format and device already has a plugboard.'),
|
||||||
'conflicts with another plugboard.'),
|
|
||||||
show=True)
|
show=True)
|
||||||
self.new_device.setCurrentIndex(0)
|
self.new_device.setCurrentIndex(0)
|
||||||
return
|
return
|
||||||
if self.current_device in self.device_to_formats_map:
|
|
||||||
|
# If we have a specific format/device combination, check if a more
|
||||||
|
# general combination matches.
|
||||||
|
if self.current_format != plugboard_any_format_value and \
|
||||||
|
self.current_device != plugboard_any_device_value:
|
||||||
|
if find_plugboard(self.current_device, self.current_format,
|
||||||
|
self.current_plugboards):
|
||||||
|
if not question_dialog(self.gui,
|
||||||
|
_('Possibly override plugboard?'),
|
||||||
|
_('A more general plugboard already exists for '
|
||||||
|
'that format and device. '
|
||||||
|
'Are you sure you want to add the new plugboard?')):
|
||||||
|
self.new_device.setCurrentIndex(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
# If we have a specific format, check if we are adding a possibly-
|
||||||
|
# covered plugboard
|
||||||
|
if self.current_format != plugboard_any_format_value:
|
||||||
|
if self.current_format in self.current_plugboards:
|
||||||
|
if self.current_device == plugboard_any_device_value:
|
||||||
|
if not question_dialog(self.gui,
|
||||||
|
_('Add possibly overridden plugboard?'),
|
||||||
|
_('More specific device plugboards exist for '
|
||||||
|
'that format. '
|
||||||
|
'Are you sure you want to add the new plugboard?')):
|
||||||
|
self.new_device.setCurrentIndex(0)
|
||||||
|
return
|
||||||
|
# We are adding an 'any format' entry. Check if we are adding a specific
|
||||||
|
# device and if so, does some other plugboard match that device.
|
||||||
|
elif self.current_device != plugboard_any_device_value:
|
||||||
|
for fmt in self.current_plugboards:
|
||||||
|
if find_plugboard(self.current_device, fmt, self.current_plugboards):
|
||||||
|
if not question_dialog(self.gui,
|
||||||
|
_('Really add plugboard?'),
|
||||||
|
_('A different plugboard matches that format and '
|
||||||
|
'device combination. '
|
||||||
|
'Are you sure you want to add the new plugboard?')):
|
||||||
|
self.new_device.setCurrentIndex(0)
|
||||||
|
return
|
||||||
|
# We are adding an any format/any device entry, which will be overridden
|
||||||
|
# by any other entry. Ask if such entries exist.
|
||||||
|
elif len(self.current_plugboards):
|
||||||
|
if not question_dialog(self.gui,
|
||||||
|
_('Add possibly overridden plugboard?'),
|
||||||
|
_('More specific format and device plugboards '
|
||||||
|
'already exist. '
|
||||||
|
'Are you sure you want to add the new plugboard?')):
|
||||||
|
self.new_device.setCurrentIndex(0)
|
||||||
|
return
|
||||||
|
|
||||||
|
if self.current_format != plugboard_any_format_value and \
|
||||||
|
self.current_device in self.device_to_formats_map:
|
||||||
allowable_formats = self.device_to_formats_map[self.current_device]
|
allowable_formats = self.device_to_formats_map[self.current_device]
|
||||||
if self.current_format not in allowable_formats:
|
if self.current_format not in allowable_formats:
|
||||||
error_dialog(self, '',
|
error_dialog(self, '',
|
||||||
|
78
src/calibre/gui2/store/oreilly_plugin.py
Normal file
78
src/calibre/gui2/store/oreilly_plugin.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from __future__ import (unicode_literals, division, absolute_import, print_function)
|
||||||
|
|
||||||
|
__license__ = 'GPL 3'
|
||||||
|
__copyright__ = '2011, John Schember <john@nachtimwald.com>'
|
||||||
|
__docformat__ = 'restructuredtext en'
|
||||||
|
|
||||||
|
import urllib
|
||||||
|
from contextlib import closing
|
||||||
|
|
||||||
|
from lxml import html
|
||||||
|
|
||||||
|
from PyQt4.Qt import QUrl
|
||||||
|
|
||||||
|
from calibre import browser, url_slash_cleaner
|
||||||
|
from calibre.gui2 import open_url
|
||||||
|
from calibre.gui2.store import StorePlugin
|
||||||
|
from calibre.gui2.store.basic_config import BasicStoreConfig
|
||||||
|
from calibre.gui2.store.search_result import SearchResult
|
||||||
|
from calibre.gui2.store.web_store_dialog import WebStoreDialog
|
||||||
|
|
||||||
|
class OReillyStore(BasicStoreConfig, StorePlugin):
|
||||||
|
|
||||||
|
def open(self, parent=None, detail_item=None, external=False):
|
||||||
|
url = 'http://oreilly.com/ebooks/'
|
||||||
|
|
||||||
|
if external or self.config.get('open_external', False):
|
||||||
|
open_url(QUrl(url_slash_cleaner(detail_item if detail_item else url)))
|
||||||
|
else:
|
||||||
|
d = WebStoreDialog(self.gui, url, parent, detail_item)
|
||||||
|
d.setWindowTitle(self.name)
|
||||||
|
d.set_tags(self.config.get('tags', ''))
|
||||||
|
d.exec_()
|
||||||
|
|
||||||
|
def search(self, query, max_results=10, timeout=60):
|
||||||
|
url = 'http://search.oreilly.com/?t1=Books&t2=Format&t3=Ebook&q=' + urllib.quote_plus(query)
|
||||||
|
|
||||||
|
br = browser()
|
||||||
|
|
||||||
|
counter = max_results
|
||||||
|
with closing(br.open(url, timeout=timeout)) as f:
|
||||||
|
doc = html.fromstring(f.read())
|
||||||
|
for data in doc.xpath('//div[@id="results"]/div[@class="result"]'):
|
||||||
|
if counter <= 0:
|
||||||
|
break
|
||||||
|
|
||||||
|
id = ''.join(data.xpath('.//div[@class="title"]/a/@href'))
|
||||||
|
if not id:
|
||||||
|
continue
|
||||||
|
|
||||||
|
cover_url = ''.join(data.xpath('.//div[@class="bigCover"]//img/@src'))
|
||||||
|
|
||||||
|
title = ''.join(data.xpath('.//div[@class="title"]/a/text()'))
|
||||||
|
author = ''.join(data.xpath('.//div[@class="author"]/text()'))
|
||||||
|
author = author.split('By ')[-1].strip()
|
||||||
|
|
||||||
|
counter -= 1
|
||||||
|
|
||||||
|
s = SearchResult()
|
||||||
|
s.cover_url = cover_url.strip()
|
||||||
|
s.title = title.strip()
|
||||||
|
s.author = author.strip()
|
||||||
|
s.detail_item = id.strip()
|
||||||
|
s.drm = SearchResult.DRM_UNLOCKED
|
||||||
|
|
||||||
|
yield s
|
||||||
|
|
||||||
|
def get_details(self, search_result, timeout):
|
||||||
|
br = browser()
|
||||||
|
with closing(br.open(search_result.detail_item, timeout=timeout)) as nf:
|
||||||
|
doc = html.fromstring(nf.read())
|
||||||
|
|
||||||
|
search_result.price = ''.join(doc.xpath('(//span[@class="price"])[1]/span//text()')).strip()
|
||||||
|
search_result.formats = ', '.join(doc.xpath('//div[@class="ebook_formats"]//a/text()')).upper()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
@ -1145,7 +1145,7 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
self.notify('metadata', [id])
|
self.notify('metadata', [id])
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def delete_book(self, id, notify=True, commit=True):
|
def delete_book(self, id, notify=True, commit=True, permanent=False):
|
||||||
'''
|
'''
|
||||||
Removes book from the result cache and the underlying database.
|
Removes book from the result cache and the underlying database.
|
||||||
If you set commit to False, you must call clean() manually afterwards
|
If you set commit to False, you must call clean() manually afterwards
|
||||||
@ -1155,10 +1155,10 @@ class LibraryDatabase2(LibraryDatabase, SchemaUpgrade, CustomColumns):
|
|||||||
except:
|
except:
|
||||||
path = None
|
path = None
|
||||||
if path and os.path.exists(path):
|
if path and os.path.exists(path):
|
||||||
self.rmtree(path)
|
self.rmtree(path, permanent=permanent)
|
||||||
parent = os.path.dirname(path)
|
parent = os.path.dirname(path)
|
||||||
if len(os.listdir(parent)) == 0:
|
if len(os.listdir(parent)) == 0:
|
||||||
self.rmtree(parent)
|
self.rmtree(parent, permanent=permanent)
|
||||||
self.conn.execute('DELETE FROM books WHERE id=?', (id,))
|
self.conn.execute('DELETE FROM books WHERE id=?', (id,))
|
||||||
if commit:
|
if commit:
|
||||||
self.conn.commit()
|
self.conn.commit()
|
||||||
|
@ -56,16 +56,17 @@ for x in FORMAT_ARG_DESCS:
|
|||||||
def find_plugboard(device_name, format, plugboards):
|
def find_plugboard(device_name, format, plugboards):
|
||||||
cpb = None
|
cpb = None
|
||||||
if format in plugboards:
|
if format in plugboards:
|
||||||
cpb = plugboards[format]
|
pb = plugboards[format]
|
||||||
elif plugboard_any_format_value in plugboards:
|
if device_name in pb:
|
||||||
cpb = plugboards[plugboard_any_format_value]
|
cpb = pb[device_name]
|
||||||
if cpb is not None:
|
elif plugboard_any_device_value in pb:
|
||||||
if device_name in cpb:
|
cpb = pb[plugboard_any_device_value]
|
||||||
cpb = cpb[device_name]
|
if not cpb and plugboard_any_format_value in plugboards:
|
||||||
elif plugboard_any_device_value in cpb:
|
pb = plugboards[plugboard_any_format_value]
|
||||||
cpb = cpb[plugboard_any_device_value]
|
if device_name in pb:
|
||||||
else:
|
cpb = pb[device_name]
|
||||||
cpb = None
|
elif plugboard_any_device_value in pb:
|
||||||
|
cpb = pb[plugboard_any_device_value]
|
||||||
if DEBUG:
|
if DEBUG:
|
||||||
prints('Device using plugboard', format, device_name, cpb)
|
prints('Device using plugboard', format, device_name, cpb)
|
||||||
return cpb
|
return cpb
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -24,6 +24,7 @@ elif isosx:
|
|||||||
path = path.decode(filesystem_encoding)
|
path = path.decode(filesystem_encoding)
|
||||||
u.send2trash(path)
|
u.send2trash(path)
|
||||||
|
|
||||||
|
can_recycle = callable(recycle)
|
||||||
|
|
||||||
def delete_file(path):
|
def delete_file(path):
|
||||||
if callable(recycle):
|
if callable(recycle):
|
||||||
|
Loading…
x
Reference in New Issue
Block a user