diff --git a/setup.py b/setup.py
index 35a2ae176d..37d54c4317 100644
--- a/setup.py
+++ b/setup.py
@@ -174,6 +174,16 @@ if __name__ == '__main__':
max = mtime if mtime > max else max
return resources, max
+ def get_recipes(self):
+ sdir = os.path.join('src', 'calibre', 'web', 'feeds', 'recipes')
+ resources, max = {}, 0
+ for f in os.listdir(sdir):
+ if f.endswith('.py') and f != '__init__.py':
+ resources[f.replace('.py', '')] = open(os.path.join(sdir, f), 'rb').read()
+ mtime = os.stat(os.path.join(sdir, f)).st_mtime
+ max = mtime if mtime > max else max
+ return resources, max
+
def run(self):
data, dest, RESOURCES = {}, self.DEST, self.RESOURCES
for key in RESOURCES:
@@ -183,13 +193,16 @@ if __name__ == '__main__':
translations = self.get_qt_translations()
RESOURCES.update(translations)
static, smax = self.get_static_resources()
- if newer([dest], RESOURCES.values()) or os.stat(dest).st_mtime < smax:
+ recipes, rmax = self.get_recipes()
+ amax = max(rmax, smax)
+ if newer([dest], RESOURCES.values()) or os.stat(dest).st_mtime < amax:
print 'Compiling resources...'
with open(dest, 'wb') as f:
for key in RESOURCES:
data = open(RESOURCES[key], 'rb').read()
f.write(key + ' = ' + repr(data)+'\n\n')
f.write('server_resources = %s\n\n'%repr(static))
+ f.write('recipes = %s\n\n'%repr(recipes))
f.write('build_time = "%s"\n\n'%time.strftime('%d %m %Y %H%M%S'))
else:
print 'Resources are up to date'
diff --git a/src/calibre/gui2/dialogs/user_profiles.py b/src/calibre/gui2/dialogs/user_profiles.py
index a06191e48c..efb34239c0 100644
--- a/src/calibre/gui2/dialogs/user_profiles.py
+++ b/src/calibre/gui2/dialogs/user_profiles.py
@@ -10,8 +10,7 @@ from calibre.web.feeds.news import AutomaticNewsRecipe
from calibre.gui2.dialogs.user_profiles_ui import Ui_Dialog
from calibre.gui2 import qstring_to_unicode, error_dialog, question_dialog, choose_files
from calibre.gui2.widgets import PythonHighlighter
-from calibre.ptempfile import PersistentTemporaryFile
-from calibre import isosx
+from calibre.ptempfile import PersistentTemporaryFile
class UserProfiles(QDialog, Ui_Dialog):
@@ -27,6 +26,7 @@ class UserProfiles(QDialog, Ui_Dialog):
self.connect(self.add_feed_button, SIGNAL('clicked(bool)'),
self.add_feed)
self.connect(self.load_button, SIGNAL('clicked()'), self.load)
+ self.connect(self.builtin_recipe_button, SIGNAL('clicked()'), self.add_builtin_recipe)
self.connect(self.share_button, SIGNAL('clicked()'), self.share)
self.connect(self.down_button, SIGNAL('clicked()'), self.down)
self.connect(self.up_button, SIGNAL('clicked()'), self.up)
@@ -184,6 +184,39 @@ class %(classname)s(%(base_class)s):
return
self.clear()
+ def add_builtin_recipe(self):
+ from calibre.web.feeds.recipes import recipes, recipe_modules, english_sort
+ from calibre.resources import recipes as rdat
+ from PyQt4.Qt import QInputDialog
+
+ class Recipe(object):
+ def __init__(self, title, id, recipes):
+ self.title = title
+ self.id = id
+ self.text = recipes[id]
+ def __cmp__(self, other):
+ return english_sort(self.title, other.title)
+
+ recipes = sorted([Recipe(r.title, i, rdat) for r, i in zip(recipes, recipe_modules)])
+ items = [r.title for r in recipes]
+ title, ok = QInputDialog.getItem(self, _('Pick recipe'), _('Pick the recipe to customize'),
+ items, 0, False)
+ if ok:
+ for r in recipes:
+ if r.title == unicode(title):
+ try:
+ self.available_profiles.add_item(title, (title, r.text), replace=False)
+ except ValueError:
+ d = question_dialog(self, _('Replace recipe?'),
+ _('A custom recipe named %s already exists. Do you want to replace it?')%title)
+ if d.exec_() == QMessageBox.Yes:
+ self.available_profiles.add_item(title, (title, r.text), replace=True)
+ else:
+ return
+ self.clear()
+ break
+
+
def load(self):
files = choose_files(self, 'recipe loader dialog', _('Choose a recipe file'), filters=[(_('Recipes'), '*.py')], all_files=False, select_only_single_file=True)
if files:
diff --git a/src/calibre/gui2/dialogs/user_profiles.ui b/src/calibre/gui2/dialogs/user_profiles.ui
index b41c9c0165..74a9891caf 100644
--- a/src/calibre/gui2/dialogs/user_profiles.ui
+++ b/src/calibre/gui2/dialogs/user_profiles.ui
@@ -5,7 +5,7 @@
0
0
- 703
+ 744
633
@@ -13,7 +13,8 @@
Add custom news source
- :/images/user_profile.svg
+
+ :/images/user_profile.svg:/images/user_profile.svg
-
@@ -22,7 +23,7 @@
Qt::Horizontal
- QDialogButtonBox::Cancel|QDialogButtonBox::NoButton|QDialogButtonBox::Ok
+ QDialogButtonBox::Cancel|QDialogButtonBox::Ok
@@ -64,7 +65,8 @@
Add/Update &recipe
- :/images/plus.svg
+
+ :/images/plus.svg:/images/plus.svg
@@ -74,7 +76,8 @@
&Remove recipe
- :/images/list_remove.svg
+
+ :/images/list_remove.svg:/images/list_remove.svg
@@ -84,7 +87,19 @@
&Share recipe
- :/images/forward.svg
+
+ :/images/forward.svg:/images/forward.svg
+
+
+
+ -
+
+
+ Customize &builtin recipe
+
+
+
+ :/images/news.svg:/images/news.svg
@@ -94,7 +109,8 @@
&Load recipe from file
- :/images/chapters.svg
+
+ :/images/chapters.svg:/images/chapters.svg
@@ -232,7 +248,8 @@ p, li { white-space: pre-wrap; }
...
- :/images/arrow-up.svg
+
+ :/images/arrow-up.svg:/images/arrow-up.svg
@@ -245,7 +262,8 @@ p, li { white-space: pre-wrap; }
...
- :/images/list_remove.svg
+
+ :/images/list_remove.svg:/images/list_remove.svg
@@ -255,7 +273,8 @@ p, li { white-space: pre-wrap; }
...
- :/images/arrow-down.svg
+
+ :/images/arrow-down.svg:/images/arrow-down.svg
@@ -305,7 +324,8 @@ p, li { white-space: pre-wrap; }
&Add feed
- :/images/plus.svg
+
+ :/images/plus.svg:/images/plus.svg