Exemple #1
0
    def add_profile(self, clicked):
        if self.stacks.currentIndex() == 0:
            src, title = self.options_to_profile()

            try:
                compile_recipe(src)
            except Exception as err:
                error_dialog(self, _('Invalid input'),
                        _('<p>Could not create recipe. Error:<br>%s')%str(err)).exec_()
                return
            profile = src
        else:
            src = unicode(self.source_code.toPlainText())
            try:
                title = compile_recipe(src).title
            except Exception as err:
                error_dialog(self, _('Invalid input'),
                        _('<p>Could not create recipe. Error:<br>%s')%str(err)).exec_()
                return
            profile = src.replace('BasicUserRecipe', 'AdvancedUserRecipe')
        if self._model.has_title(title):
            if question_dialog(self, _('Replace recipe?'),
                _('A custom recipe named %s already exists. Do you want to '
                    'replace it?')%title):
                self._model.replace_by_title(title, profile)
            else:
                return
        else:
            self.model.add(title, profile)
        self.clear()
Exemple #2
0
 def validate(self):
     src = self.recipe_source
     try:
         compile_recipe(src)
     except Exception as err:
         error_dialog(self, _('Invalid recipe'), _(
             'Failed to compile the recipe, with syntax error: %s' % err), show=True)
         return False
     return True
Exemple #3
0
 def load(self):
     files = choose_files(
         self,
         "recipe loader dialog",
         _("Choose a recipe file"),
         filters=[(_("Recipes"), [".py", ".recipe"])],
         all_files=False,
         select_only_single_file=True,
     )
     if files:
         file = files[0]
         try:
             profile = open(file, "rb").read().decode("utf-8")
             title = compile_recipe(profile).title
         except Exception as err:
             error_dialog(self, _("Invalid input"), _("<p>Could not create recipe. Error:<br>%s") % str(err)).exec_()
             return
         if self._model.has_title(title):
             if question_dialog(
                 self,
                 _("Replace recipe?"),
                 _("A custom recipe named %s already exists. Do you want to " "replace it?") % title,
             ):
                 self._model.replace_by_title(title, profile)
             else:
                 return
         else:
             self.model.add(title, profile)
         self.clear()
Exemple #4
0
 def validate(self):
     title = self.title.text().strip()
     if not title:
         error_dialog(self, _('Title required'), _(
             'You must give your news source a title'), show=True)
         return False
     if self.feeds.count() < 1:
         error_dialog(self, _('Feed required'), _(
             'You must add at least one feed to your news source'), show=True)
         return False
     try:
         compile_recipe(self.recipe_source)
     except Exception as err:
         error_dialog(self, _('Invalid recipe'), _(
             'Failed to compile the recipe, with syntax error: %s' % err), show=True)
         return False
     return True
Exemple #5
0
    def opml_import(self):
        from calibre.gui2.dialogs.opml import ImportOPML
        d = ImportOPML(parent=self)
        if d.exec_() != d.Accepted:
            return
        oldest_article, max_articles_per_feed, replace_existing = d.oldest_article, d.articles_per_feed, d.replace_existing
        failed_recipes, replace_recipes, add_recipes = {}, {}, {}

        for group in d.recipes:
            title = base_title = group.title or _('Unknown')
            if not replace_existing:
                c = 0
                while self._model.has_title(title):
                    c += 1
                    title = u'%s %d' % (base_title, c)
            src, title = self.options_to_profile(**{
                    'title':title,
                    'feeds':group.feeds,
                    'oldest_article':oldest_article,
                    'max_articles':max_articles_per_feed,
                })
            try:
                compile_recipe(src)
            except Exception:
                import traceback
                failed_recipes[title] = traceback.format_exc()
                continue

            if replace_existing and self._model.has_title(title):
                replace_recipes[title] = src
            else:
                add_recipes[title] = src

        if add_recipes:
            self.model.add_many(add_recipes)
        if replace_recipes:
            self.model.replace_many_by_title(replace_recipes)
        if failed_recipes:
            det_msg = '\n'.join('%s\n%s\n' % (title, tb) for title, tb in failed_recipes.iteritems())
            error_dialog(self, _('Failed to create recipes'), _(
                'Failed to create some recipes, click "Show details" for details'), show=True,
                         det_msg=det_msg)
        self.clear()
Exemple #6
0
 def import_recipes(self, outlines):
     nr = 0
     #recipe_model = CustomRecipeModel(RecipeModel())
     for outline in outlines:
         src, title = self.options_to_profile(dict(
             nr=nr,
             title=unicode(outline.get('title')),
             feeds=outline.get('xmlUrl'),
             oldest_article=self.oldest_article,
             max_articles=self.max_articles,
             base_class='AutomaticNewsRecipe'
         ))
         try:
             compile_recipe(src)
             add_custom_recipe(title, src)
         except Exception as err:
             # error dialog should be placed somewhere where it can have a parent
             # Left it here as this way only failing feeds will silently fail
             error_dialog(None, _('Invalid input'),
                 _('<p>Could not create recipe. Error:<br>%s')%str(err)).exec_()
         nr+=1
Exemple #7
0
def download_builtin_recipe(urn):
    from calibre.utils.config_base import prefs
    from calibre.utils.https import get_https_resource_securely
    import bz2
    recipe_source = bz2.decompress(get_https_resource_securely(
        'https://code.calibre-ebook.com/recipe-compressed/'+urn, headers={'CALIBRE-INSTALL-UUID':prefs['installation_uuid']}))
    from calibre.web.feeds.recipes import compile_recipe
    recipe = compile_recipe(recipe_source)  # ensure the downloaded recipe is at least compile-able
    if recipe is None:
        raise ValueError('Failed to find recipe object in downloaded recipe: ' + urn)
    if recipe.requires_version > numeric_version:
        raise ValueError('Downloaded recipe for {} requires calibre >= {}'.format(urn, recipe.requires_version))
    return recipe_source
Exemple #8
0
def serialize_builtin_recipes():
    from calibre.web.feeds.recipes import compile_recipe
    recipe_mapping = {}
    for rid, f in iterate_over_builtin_recipe_files():
        with open(f, 'rb') as stream:
            try:
                recipe_class = compile_recipe(stream.read())
            except:
                print ('Failed to compile: %s'%f)
                raise
        if recipe_class is not None:
            recipe_mapping['builtin:'+rid] = recipe_class

    return serialize_collection(recipe_mapping)
Exemple #9
0
    def import_opml(self):
        from calibre.gui2.dialogs.opml import ImportOPML
        d = ImportOPML(parent=self)
        if d.exec_() != d.Accepted:
            return
        oldest_article, max_articles_per_feed, replace_existing = d.oldest_article, d.articles_per_feed, d.replace_existing
        failed_recipes, replace_recipes, add_recipes = {}, {}, {}

        for group in d.recipes:
            title = base_title = group.title or _('Unknown')
            if not replace_existing:
                c = 0
                while self.recipe_list.has_title(title):
                    c += 1
                    title = '%s %d' % (base_title, c)
            try:
                src = options_to_recipe_source(title, oldest_article, max_articles_per_feed, group.feeds)
                compile_recipe(src)
            except Exception:
                import traceback
                failed_recipes[title] = traceback.format_exc()
                continue

            if replace_existing and self.recipe_list.has_title(title):
                replace_recipes[title] = src
            else:
                add_recipes[title] = src

        if add_recipes:
            self.recipe_list.add_many(add_recipes)
        if replace_recipes:
            self.recipe_list.replace_many_by_title(replace_recipes)
        if failed_recipes:
            det_msg = '\n'.join('%s\n%s\n' % (title, tb) for title, tb in iteritems(failed_recipes))
            error_dialog(self, _('Failed to create recipes'), _(
                'Failed to create some recipes, click "Show details" for details'), show=True,
                         det_msg=det_msg)
Exemple #10
0
 def editing_finished(self):
     w = self.stack.currentWidget()
     if not w.validate():
         return
     src = w.recipe_source
     if not isinstance(src, bytes):
         src = src.encode('utf-8')
     recipe = compile_recipe(src)
     row = self.editing_row
     if row is None:
         # Adding a new recipe
         self.recipe_list.add(recipe.title, src)
     else:
         self.recipe_list.update(row, recipe.title, src)
     self.stack.setCurrentIndex(0)
Exemple #11
0
 def fset(self, src):
     self.feeds.clear()
     self.feed_title.clear()
     self.feed_url.clear()
     if src is None:
         self.title.setText(_('My News Source'))
         self.oldest_article.setValue(7)
         self.max_articles.setValue(100)
     else:
         recipe = compile_recipe(src)
         self.title.setText(recipe.title)
         self.oldest_article.setValue(recipe.oldest_article)
         self.max_articles.setValue(recipe.max_articles_per_feed)
         for x in (recipe.feeds or ()):
             title, url = ('', x) if len(x) == 1 else x
             QListWidgetItem('%s - %s' % (title, url), self.feeds).setData(Qt.UserRole, (title, url))
Exemple #12
0
 def current_changed(self, current, previous):
     if not current.isValid():
         return
     src = self._model.script(current)
     if src is None:
         return
     if 'class BasicUserRecipe' in src:
         recipe = compile_recipe(src)
         self.populate_options(recipe)
         self.stacks.setCurrentIndex(0)
         self.toggle_mode_button.setText(_('Switch to Advanced mode'))
         self.source_code.setPlainText('')
     else:
         self.source_code.setPlainText(src)
         self.highlighter = PythonHighlighter(self.source_code.document())
         self.stacks.setCurrentIndex(1)
         self.toggle_mode_button.setText(_('Switch to Basic mode'))
Exemple #13
0
def get_custom_recipe_collection(*args):
    from calibre.web.feeds.recipes import compile_recipe, \
            custom_recipes
    bdir = os.path.dirname(custom_recipes.file_path)
    rmap = {}
    for id_, x in custom_recipes.iteritems():
        title, fname = x
        recipe = os.path.join(bdir, fname)
        try:
            recipe = open(recipe, 'rb').read().decode('utf-8')
            recipe_class = compile_recipe(recipe)
            if recipe_class is not None:
                rmap['custom:%s'%id_] = recipe_class
        except:
            print 'Failed to load recipe from: %r'%fname
            import traceback
            traceback.print_exc()
            continue
    return etree.fromstring(serialize_collection(rmap))
Exemple #14
0
 def load(self):
     files = choose_files(self, 'recipe loader dialog',
         _('Choose a recipe file'),
         filters=[(_('Recipes'), ['.py', '.recipe'])],
         all_files=False, select_only_single_file=True)
     if files:
         file = files[0]
         try:
             profile = open(file, 'rb').read().decode('utf-8')
             title = compile_recipe(profile).title
         except Exception as err:
             error_dialog(self, _('Invalid input'),
                     _('<p>Could not create recipe. Error:<br>%s')%str(err)).exec_()
             return
         if self._model.has_title(title):
             if question_dialog(self, _('Replace recipe?'),
                 _('A custom recipe named %s already exists. Do you want to '
                     'replace it?')%title):
                 self._model.replace_by_title(title, profile)
             else:
                 return
         else:
             self.model.add(title, profile)
         self.clear()
Exemple #15
0
    def convert(self, recipe_or_file, opts, file_ext, log,
            accelerators):
        from calibre.web.feeds.recipes import compile_recipe
        opts.output_profile.flow_size = 0
        if file_ext == 'downloaded_recipe':
            from calibre.utils.zipfile import ZipFile
            zf = ZipFile(recipe_or_file, 'r')
            zf.extractall()
            zf.close()
            self.recipe_source = open(u'download.recipe', 'rb').read()
            recipe = compile_recipe(self.recipe_source)
            recipe.needs_subscription = False
            self.recipe_object = recipe(opts, log, self.report_progress)
        else:
            if os.access(recipe_or_file, os.R_OK):
                self.recipe_source = open(recipe_or_file, 'rb').read()
                recipe = compile_recipe(self.recipe_source)
                log('Using custom recipe')
            else:
                from calibre.web.feeds.recipes.collection import \
                        get_builtin_recipe_by_title
                title = getattr(opts, 'original_recipe_input_arg', recipe_or_file)
                title = os.path.basename(title).rpartition('.')[0]
                raw = get_builtin_recipe_by_title(title, log=log,
                        download_recipe=not opts.dont_download_recipe)
                builtin = False
                try:
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                    if recipe.requires_version > numeric_version:
                        log.warn(
                        'Downloaded recipe needs calibre version at least: %s' % \
                        ('.'.join(recipe.requires_version)))
                        builtin = True
                except:
                    log.exception('Failed to compile downloaded recipe. Falling '
                            'back to builtin one')
                    builtin = True
                if builtin:
                    log('Using bundled builtin recipe')
                    raw = get_builtin_recipe_by_title(title, log=log,
                            download_recipe=False)
                    if raw is None:
                        raise ValueError('Failed to find builtin recipe: '+title)
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                else:
                    log('Using downloaded builtin recipe')

            if recipe is None:
                raise ValueError('%r is not a valid recipe file or builtin recipe' %
                        recipe_or_file)

            disabled = getattr(recipe, 'recipe_disabled', None)
            if disabled is not None:
                raise RecipeDisabled(disabled)
            ro = recipe(opts, log, self.report_progress)
            ro.download()
            self.recipe_object = ro

        for key, val in self.recipe_object.conversion_options.items():
            setattr(opts, key, val)

        for f in os.listdir(u'.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)

        for f in walk(u'.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)
Exemple #16
0
    def convert(self, recipe_or_file, opts, file_ext, log, accelerators):
        from calibre.web.feeds.recipes import compile_recipe
        opts.output_profile.flow_size = 0
        if file_ext == 'downloaded_recipe':
            from calibre.utils.zipfile import ZipFile
            zf = ZipFile(recipe_or_file, 'r')
            zf.extractall()
            zf.close()
            self.recipe_source = open(u'download.recipe', 'rb').read()
            recipe = compile_recipe(self.recipe_source)
            recipe.needs_subscription = False
            self.recipe_object = recipe(opts, log, self.report_progress)
        else:
            if os.access(recipe_or_file, os.R_OK):
                self.recipe_source = open(recipe_or_file, 'rb').read()
                recipe = compile_recipe(self.recipe_source)
                log('Using custom recipe')
            else:
                from calibre.web.feeds.recipes.collection import (
                    get_builtin_recipe_by_title, get_builtin_recipe_titles)
                title = getattr(opts, 'original_recipe_input_arg',
                                recipe_or_file)
                title = os.path.basename(title).rpartition('.')[0]
                titles = frozenset(get_builtin_recipe_titles())
                if title not in titles:
                    title = getattr(opts, 'original_recipe_input_arg',
                                    recipe_or_file)
                    title = title.rpartition('.')[0]

                raw = get_builtin_recipe_by_title(
                    title,
                    log=log,
                    download_recipe=not opts.dont_download_recipe)
                builtin = False
                try:
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                    if recipe.requires_version > numeric_version:
                        log.warn(
                            'Downloaded recipe needs calibre version at least: %s'
                            % ('.'.join(recipe.requires_version)))
                        builtin = True
                except:
                    log.exception(
                        'Failed to compile downloaded recipe. Falling '
                        'back to builtin one')
                    builtin = True
                if builtin:
                    log('Using bundled builtin recipe')
                    raw = get_builtin_recipe_by_title(title,
                                                      log=log,
                                                      download_recipe=False)
                    if raw is None:
                        raise ValueError('Failed to find builtin recipe: ' +
                                         title)
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                else:
                    log('Using downloaded builtin recipe')

            if recipe is None:
                raise ValueError(
                    '%r is not a valid recipe file or builtin recipe' %
                    recipe_or_file)

            disabled = getattr(recipe, 'recipe_disabled', None)
            if disabled is not None:
                raise RecipeDisabled(disabled)
            ro = recipe(opts, log, self.report_progress)
            ro.download()
            self.recipe_object = ro

        for key, val in self.recipe_object.conversion_options.items():
            setattr(opts, key, val)

        for f in os.listdir(u'.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)

        for f in walk(u'.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)
Exemple #17
0
    def convert(self, recipe_or_file, opts, file_ext, log,
            accelerators):
        from calibre.web.feeds.recipes import compile_recipe
        opts.output_profile.flow_size = 0
        if file_ext == 'downloaded_recipe':
            from calibre.utils.zipfile import ZipFile
            zf = ZipFile(recipe_or_file, 'r')
            zf.extractall()
            zf.close()
            with lopen('download.recipe', 'rb') as f:
                self.recipe_source = f.read()
            recipe = compile_recipe(self.recipe_source)
            recipe.needs_subscription = False
            self.recipe_object = recipe(opts, log, self.report_progress)
        else:
            if os.environ.get('CALIBRE_RECIPE_URN'):
                from calibre.web.feeds.recipes.collection import get_custom_recipe, get_builtin_recipe_by_id
                urn = os.environ['CALIBRE_RECIPE_URN']
                log('Downloading recipe urn: ' + urn)
                rtype, recipe_id = urn.partition(':')[::2]
                if not recipe_id:
                    raise ValueError('Invalid recipe urn: ' + urn)
                if rtype == 'custom':
                    self.recipe_source = get_custom_recipe(recipe_id)
                else:
                    self.recipe_source = get_builtin_recipe_by_id(urn, log=log, download_recipe=True)
                if not self.recipe_source:
                    raise ValueError('Could not find recipe with urn: ' + urn)
                if not isinstance(self.recipe_source, bytes):
                    self.recipe_source = self.recipe_source.encode('utf-8')
                recipe = compile_recipe(self.recipe_source)
            elif os.access(recipe_or_file, os.R_OK):
                with lopen(recipe_or_file, 'rb') as f:
                    self.recipe_source = f.read()
                recipe = compile_recipe(self.recipe_source)
                log('Using custom recipe')
            else:
                from calibre.web.feeds.recipes.collection import (
                        get_builtin_recipe_by_title, get_builtin_recipe_titles)
                title = getattr(opts, 'original_recipe_input_arg', recipe_or_file)
                title = os.path.basename(title).rpartition('.')[0]
                titles = frozenset(get_builtin_recipe_titles())
                if title not in titles:
                    title = getattr(opts, 'original_recipe_input_arg', recipe_or_file)
                    title = title.rpartition('.')[0]

                raw = get_builtin_recipe_by_title(title, log=log,
                        download_recipe=not opts.dont_download_recipe)
                builtin = False
                try:
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                    if recipe.requires_version > numeric_version:
                        log.warn(
                        'Downloaded recipe needs calibre version at least: %s' %
                        ('.'.join(recipe.requires_version)))
                        builtin = True
                except:
                    log.exception('Failed to compile downloaded recipe. Falling '
                            'back to builtin one')
                    builtin = True
                if builtin:
                    log('Using bundled builtin recipe')
                    raw = get_builtin_recipe_by_title(title, log=log,
                            download_recipe=False)
                    if raw is None:
                        raise ValueError('Failed to find builtin recipe: '+title)
                    recipe = compile_recipe(raw)
                    self.recipe_source = raw
                else:
                    log('Using downloaded builtin recipe')

            if recipe is None:
                raise ValueError('%r is not a valid recipe file or builtin recipe' %
                        recipe_or_file)

            disabled = getattr(recipe, 'recipe_disabled', None)
            if disabled is not None:
                raise RecipeDisabled(disabled)
            ro = recipe(opts, log, self.report_progress)
            ro.download()
            self.recipe_object = ro

        for key, val in self.recipe_object.conversion_options.items():
            setattr(opts, key, val)

        for f in os.listdir('.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)

        for f in walk('.'):
            if f.endswith('.opf'):
                return os.path.abspath(f)