From f519eed268c6ba1ccfd2dceb372830ca7221272d Mon Sep 17 00:00:00 2001 From: Filip Balos Date: Mon, 13 Jun 2016 02:32:20 -0400 Subject: [PATCH 1/8] Completion support and stricter argument parsing Adds shell completion support for arguments and feed names through 'argcomplete' (https://github.com/kislyuk/argcomplete) and lets argparse handle more of the argument validation. -Specified 'nargs' explicitly for the arguments that call the custom action. For options with one argument, nargs, if unspecified, will return a string, for options with more than one argument it will return a list. It seems simpler just to make it always return a list. For this reason some calls to args['names'] in greg.py were changed to args['names'][0]. --- README.md | 19 +++++++++++++++ greg/greg.py | 55 +++++++++++++++++++++++------------------- greg/gregparser.py | 52 ++++++++++++++++++++++++++++----------- pkgbuilds/git/PKGBUILD | 3 ++- 4 files changed, 89 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index 413343b..dcf7b27 100755 --- a/README.md +++ b/README.md @@ -31,6 +31,25 @@ Save `~/.profile` and run the following command in a terminal to refresh the sys Now run `greg` and you should see the greg help text displayed in your terminal. +### Completion support + +To enable support for command line completion in bash or zsh, install the python module [argcomplete](https://pypi.python.org/pypi/argcomplete). + +For bash, add the following line to `~/.bashrc`: + +`eval "$(register-python-argcomplete greg)"` + +Zsh support requires adding the following lines to `~/.zshrc`: + +``` +autoload -U bashcompinit && bashcompinit +eval "$(register-python-argcomplete greg)" +``` + +Then load the changes by running `source ~/.bashrc` or `source ~/.zshrc`. + +See the [argcomplete](https://pypi.python.org/pypi/argcomplete) documentation for further details. + ### Installing via homebrew python3 The normal pip `install --user` is disabled for homebrew Python 3, so you cannot follow the above instructions. You have 2 options: diff --git a/greg/greg.py b/greg/greg.py index ffe0fb9..ef1fb22 100755 --- a/greg/greg.py +++ b/greg/greg.py @@ -643,12 +643,13 @@ def add(args): # Adds a new feed def edit(args): # Edits the information associated with a certain feed session = Session(args) - feed_info = os.path.join(session.data_dir, args["name"]) - if not(args["name"] in session.feeds): + name = args["name"][0] + feed_info = os.path.join(session.data_dir, name) + if not(name in session.feeds): sys.exit("You don't have a feed with that name.") for key, value in args.items(): if value is not None and key == "url": - session.feeds[args["name"]][key] = str(value) + session.feeds[name][key] = str(value[0]) with open(session.data_filename, 'w') as configfile: session.feeds.write(configfile) if value is not None and key == "downloadfrom": @@ -666,7 +667,7 @@ def edit(args): # Edits the information associated with a certain feed "Using --downloadfrom might not have the" "results that you expect."). format(args["name"]), file=sys.stderr, flush=True) - line = ' '.join(["currentdate", str(value), "\n"]) + line = ' '.join(["currentdate", str(value[0]), "\n"]) # A dummy entry with the new downloadfrom date. try: # Remove from the feed file all entries @@ -689,27 +690,31 @@ def remove(args): Remove the feed given in """ session = Session(args) - if not args["name"] in session.feeds: - sys.exit("You don't have a feed with that name.") - inputtext = ("Are you sure you want to remove the {} " - " feed? (y/N) ").format(args["name"]) - reply = input(inputtext) - if reply != "y" and reply != "Y": - return 0 - else: - session.feeds.remove_section(args["name"]) - with open(session.data_filename, 'w') as configfile: - session.feeds.write(configfile) - try: - os.remove(os.path.join(session.data_dir, args["name"])) - except FileNotFoundError: - pass + for name in args["name"]: + if not name in session.feeds: + sys.exit("You don't have a feed with that name.") + inputtext = ("Are you sure you want to remove the {} " + "feed? (y/N) ").format(name) + reply = input(inputtext) + if reply != "y" and reply != "Y": + print('Not removed') + else: + session.feeds.remove_section(name) + with open(session.data_filename, 'w') as configfile: + session.feeds.write(configfile) + try: + os.remove(os.path.join(session.data_dir, name)) + except FileNotFoundError: + pass +def get_feeds(args): # Returns a list of feeds + session = Session(args) + return session.list_feeds() def info(args): # Provides information of a number of feeds session = Session(args) if "all" in args["names"]: - feeds = session.list_feeds() + feeds = get_feeds(args) else: feeds = args["names"] for feed in feeds: @@ -731,7 +736,7 @@ def pretty_print(session, feed): def list_for_user(args): session = Session(args) - for feed in session.list_feeds(): + for feed in sorted(session.list_feeds()): print(feed) print() @@ -789,15 +794,15 @@ def check(args): """ session = Session(args) if str(args["url"]) != 'None': - url = args["url"] + url = args["url"][0] name = "DEFAULT" else: try: - url = session.feeds[args["feed"]]["url"] - name = args["feed"] + name = args["feed"][0] + url = session.feeds[name]["url"] except KeyError: sys.exit("You don't appear to have a feed with that name.") - podcast = parse_podcast(url) + podcast = parse_podcast(str(url)) for entry in enumerate(podcast.entries): listentry = list(entry) print(listentry[0], end=": ") diff --git a/greg/gregparser.py b/greg/gregparser.py index 6ca72c8..a145730 100755 --- a/greg/gregparser.py +++ b/greg/gregparser.py @@ -20,6 +20,12 @@ import greg.greg +try: # argcomplete is an optional dependency + import argcomplete + argcompleteexists = True +except ImportError: + argcompleteexists = False + # defining the from_date type def from_date(string): try: @@ -37,7 +43,23 @@ def url(string): raise argparse.ArgumentTypeError(msg) return string -# create the top-level parser +class customActionGetFeeds(argparse.Action): + def __call__(self, parser, namespace, values, option_string=None): + if values == self.default: + setattr(namespace, self.dest, values) + else: + self.choices=greg.greg.get_feeds(vars(namespace)) + for value in values: + if value not in self.choices: + msg = "%r is not a valid feed" % value + raise argparse.ArgumentError(self, msg) + setattr(namespace, self.dest, values) + +def FeedsCompleter(parsed_args, **kwargs): + feeds=greg.greg.get_feeds(vars(parsed_args)) + return feeds + +#Create the top-level parser parser = argparse.ArgumentParser() parser.add_argument('--configfile', '-cf', help='specifies the config file that greg should use') @@ -49,41 +71,41 @@ def url(string): parser_add = subparsers.add_parser('add', help='adds a new feed') parser_add.add_argument('name', help='the name of the new feed') parser_add.add_argument('url', type = url, help='the url of the new feed') -parser_add.add_argument('--downloadfrom', '-d', type=from_date, +parser_add.add_argument('--downloadfrom', '-d', type=from_date, help='the date from which files should be downloaded (YYYY-MM-DD)') parser_add.set_defaults(func=greg.greg.add) # create the parser for the "edit" command parser_edit = subparsers.add_parser('edit', help='edits a feed') -parser_edit.add_argument('name', help='the name of the feed to be edited') +parser_edit.add_argument('name', action=customActionGetFeeds, help='the name of the feed to be edited', nargs=1, metavar='FEEDNAME').completer = FeedsCompleter group = parser_edit.add_mutually_exclusive_group(required = True) -group.add_argument('--url', '-u', type = url, help='the new url of the feed') +group.add_argument('--url', '-u', type = url, help='the new url of the feed', nargs=1) group.add_argument('--downloadfrom', '-d', - type=from_date, help='the date from which files should be downloaded (YYYY-MM-DD)') + type=from_date, help='the date from which files should be downloaded (YYYY-MM-DD)', nargs=1) parser_edit.set_defaults(func=greg.greg.edit) # create the parser for the "info" command parser_info = subparsers.add_parser('info', help='provides information about a feed') -parser_info.add_argument('names', help='the name(s) of the feed(s) you want to know about', nargs='*', default='all') +parser_info.add_argument('names', action=customActionGetFeeds, help='the name(s) of the feed(s) you want to know about', nargs='*', default=['all'], metavar='FEEDNAME').completer = FeedsCompleter parser_info.set_defaults(func=greg.greg.info) # create the parser for the "list" command -parser_info = subparsers.add_parser('list', help='lists all feeds') -parser_info.set_defaults(func=greg.greg.list_for_user) +parser_list = subparsers.add_parser('list', help='lists all feeds') +parser_list.set_defaults(func=greg.greg.list_for_user) # create the parser for the "sync" command parser_sync = subparsers.add_parser('sync', help='syncs feed(s)') -parser_sync.add_argument('names', help='the name(s) of the feed(s) you want to sync', nargs='*', default='all') +parser_sync.add_argument('names', action=customActionGetFeeds, help='the name(s) of the feed(s) you want to sync', nargs='*', default=['all'], metavar='FEEDNAME').completer = FeedsCompleter parser_sync.add_argument('--downloadhandler', '-dh', help='whatever you want greg to do with the enclosure') parser_sync.add_argument('--downloaddirectory', '-dd', help='the directory to which you want to save your downloads') parser_sync.add_argument('--firstsync', '-fs', help='the number of files to download (if this is the first sync)') parser_sync.set_defaults(func=greg.greg.sync) # create the parser for the "check" command -parser_check = subparsers.add_parser('check', help='checks feed(s)') -group = parser_check.add_mutually_exclusive_group(required = True) -group.add_argument('--url', '-u', type = url, help='the url that you want to check') -group.add_argument('--feed', '-f', help='the feed that you want to check') +parser_check = subparsers.add_parser('check', help='checks feed') +group = parser_check.add_mutually_exclusive_group(required=True) +group.add_argument('--url', '-u', type = url, help='the url that you want to check', nargs=1) +group.add_argument('--feed', '-f', action=customActionGetFeeds, help='the feed that you want to check', nargs=1, metavar='FEEDNAME').completer = FeedsCompleter parser_check.set_defaults(func=greg.greg.check) # create the parser for the "download" command @@ -96,7 +118,7 @@ def url(string): # create the parser for the "remove" command parser_remove = subparsers.add_parser('remove', help='removes feed(s)') -parser_remove.add_argument('name', help='the name of the feed you want to remove') +parser_remove.add_argument('name', action=customActionGetFeeds, help='the name of the feed(s) you want to remove', nargs='+', metavar='FEEDNAME').completer = FeedsCompleter parser_remove.set_defaults(func=greg.greg.remove) # create the parser for the 'retrieveglobalconf' command @@ -109,6 +131,8 @@ def main(): """ Parse the args and call whatever function was selected """ + if argcompleteexists: + argcomplete.autocomplete(parser) args = parser.parse_args() try: function = args.func diff --git a/pkgbuilds/git/PKGBUILD b/pkgbuilds/git/PKGBUILD index 5ff034a..0c33b5f 100644 --- a/pkgbuilds/git/PKGBUILD +++ b/pkgbuilds/git/PKGBUILD @@ -12,7 +12,8 @@ depends=('python-feedparser') optdepends=('python3-stagger-svn: writing metadata' 'wget: alternative downloadhandler' 'aria2: alternative downloadhandler' - 'python-beautifulsoup4: convert html to text for tagging') + 'python-beautifulsoup4: convert html to text for tagging' + 'python-argcomplete: tab completion') makedepends=('git') provides=('greg') conflicts=('greg') From b7a874da76fbc7e40ed3ed4c24c1362157c7c371 Mon Sep 17 00:00:00 2001 From: Filip Balos Date: Wed, 15 Jun 2016 19:27:07 -0400 Subject: [PATCH 2/8] Fixes choices, adds opml, removes completion -Fixed setting argument choices for arguments that take feed names as input. -Adds opml import/export using the 'opml' argument. -Argcomplete is not working with the custom argparse action used to set choices. Need to figure out why not. Removed completion support for now. --- README.md | 19 -------- greg/greg.py | 102 ++++++++++++++++++++++++++++++++--------- greg/gregparser.py | 72 +++++++++++++++++------------ pkgbuilds/git/PKGBUILD | 3 +- 4 files changed, 123 insertions(+), 73 deletions(-) diff --git a/README.md b/README.md index dcf7b27..413343b 100755 --- a/README.md +++ b/README.md @@ -31,25 +31,6 @@ Save `~/.profile` and run the following command in a terminal to refresh the sys Now run `greg` and you should see the greg help text displayed in your terminal. -### Completion support - -To enable support for command line completion in bash or zsh, install the python module [argcomplete](https://pypi.python.org/pypi/argcomplete). - -For bash, add the following line to `~/.bashrc`: - -`eval "$(register-python-argcomplete greg)"` - -Zsh support requires adding the following lines to `~/.zshrc`: - -``` -autoload -U bashcompinit && bashcompinit -eval "$(register-python-argcomplete greg)" -``` - -Then load the changes by running `source ~/.bashrc` or `source ~/.zshrc`. - -See the [argcomplete](https://pypi.python.org/pypi/argcomplete) documentation for further details. - ### Installing via homebrew python3 The normal pip `install --user` is disabled for homebrew Python 3, so you cannot follow the above instructions. You have 2 options: diff --git a/greg/greg.py b/greg/greg.py index ef1fb22..a59e41d 100755 --- a/greg/greg.py +++ b/greg/greg.py @@ -25,9 +25,10 @@ import unicodedata import string from itertools import filterfalse -from urllib.request import urlretrieve +import urllib.request from urllib.parse import urlparse from urllib.error import URLError +from lxml import etree as ET from pkg_resources import resource_filename import feedparser @@ -86,16 +87,16 @@ def retrieve_data_directory(self): """ args = self.args try: - if args['datadirectory']: - ensure_dir(args['datadirectory']) - return args['datadirectory'] + if args["datadirectory"]: + ensure_dir(args["datadirectory"]) + return args["datadirectory"] except KeyError: pass config = configparser.ConfigParser() config.read([config_filename_global, self.config_filename_user]) section = config.default_section - data_path = config.get(section, 'Data directory', - fallback='~/.local/share/greg') + data_path = config.get(section, "Data directory", + fallback="~/.local/share/greg") data_path_expanded = os.path.expanduser(data_path) ensure_dir(data_path_expanded) return os.path.expanduser(data_path_expanded) @@ -162,9 +163,9 @@ def retrieve_download_path(self): section = self.name if self.config.has_section( self.name) else self.config.default_section download_path = self.config.get( - section, 'Download directory', fallback='~/Podcasts') + section, "Download directory", fallback="~/Podcasts") subdirectory = self.config.get( - section, 'Create subdirectories', fallback='no') + section, "Create subdirectories", fallback="no") return [os.path.expanduser(download_path), subdirectory] def has_date(self): @@ -626,19 +627,28 @@ def retrieveglobalconf(args): def add(args): # Adds a new feed session = Session(args) - if args["name"] in session.feeds.sections(): - sys.exit("You already have a feed with that name.") - if args["name"] in ["all", "DEFAULT"]: - sys.exit( - ("greg uses ""{}"" for a special purpose." - "Please choose another name for your feed.").format(args["name"])) - entry = {} - for key, value in args.items(): - if value is not None and key != "func" and key != "name": - entry[key] = value - session.feeds[args["name"]] = entry - with open(session.data_filename, 'w') as configfile: - session.feeds.write(configfile) + isduplicate = False + for feed in session.list_feeds(): + if session.feeds.has_option(feed, "url") and args["url"] == session.feeds.get(feed, "url"): + print("You are already subscribed to %r as %r." % (args["url"], str(feed))) + isduplicate = True + elif args["name"] in feed: + print("You already have a feed called %r." % args["name"]) + isduplicate = True + elif args["name"] in ["all", "DEFAULT"]: + print( + ("greg uses ""{}"" for a special purpose." + "Please choose another name for your feed.").format(args["name"])) + isduplicate = True + if not isduplicate: + entry = {} + for key, value in args.items(): + if value is not None and key != "func" and key != "name" and key != "import": + entry[key] = value + session.feeds[args["name"]] = entry + with open(session.data_filename, 'w') as configfile: + session.feeds.write(configfile) + print("Added %r." % args["name"]) def edit(args): # Edits the information associated with a certain feed @@ -707,7 +717,7 @@ def remove(args): except FileNotFoundError: pass -def get_feeds(args): # Returns a list of feeds +def get_feeds(args): # Returns a list of feed names session = Session(args) return session.list_feeds() @@ -849,3 +859,51 @@ def download(args): feed.entrylinks = [] feed.fix_linkdate(entry) feed.download_entry(entry) + +def opml(args): + """ + Implement the 'greg opml' command + """ + if args["import"]: + opmlfile = args["import"][0] + try: + opmltree = ET.parse(opmlfile) + except ET.ParseError: + sys.exit("%r does not appear to be a valid opml file." % opmlfile) + for element in opmltree.iterfind('.//*[@type="rss"]'): + if element.get('xmlUrl'): + args["url"] = element.get('xmlUrl') + elif element.get('url'): + args["url"] = element.get('url') + if element.get('title'): + args["name"] = element.get('title') + elif element.get('text'): + args["name"] = element.get('text') + else: + print("No title found for this feed, using url as title.") + args["name"] = args["url"] + add(args) + if args["export"]: + session = Session(args) + filename = args["export"][0] + toplevel = ET.Element("opml") + toplevel.set("version", "2.0") + head = ET.SubElement(toplevel, "head") + title = ET.SubElement(head, "title") + title.text = "Podcasts" + dateCreated = ET.SubElement(head, "dateCreated") + dateCreated.text = time.strftime("%c %Z") + body = ET.SubElement(toplevel, "body") + for feedname in session.list_feeds(): + if session.feeds.has_option(feedname, "url"): + outline = ET.SubElement(body, "outline") + outline.set("text", feedname) + outline.set("title", feedname) + outline.set("xmlUrl", session.feeds.get(feedname, "url")) + outline.set("type", "rss") + opmlfile = open(filename, 'wb') + opmlfile.write(('\n' \ + + '\n\n').encode()) + opmlfile.write(ET.tostring(toplevel, encoding="utf-8", pretty_print=True)) + opmlfile.close() diff --git a/greg/gregparser.py b/greg/gregparser.py index a145730..877d32f 100755 --- a/greg/gregparser.py +++ b/greg/gregparser.py @@ -20,12 +20,6 @@ import greg.greg -try: # argcomplete is an optional dependency - import argcomplete - argcompleteexists = True -except ImportError: - argcompleteexists = False - # defining the from_date type def from_date(string): try: @@ -43,28 +37,42 @@ def url(string): raise argparse.ArgumentTypeError(msg) return string -class customActionGetFeeds(argparse.Action): +# get list of feed names and pass to global var +def set_FeedChoices(value): + global feednames + feednames=greg.greg.get_feeds(value) + +# set possible choices to list of feed names for appropriate data dir or configfile +class customActionSetFeedChoices(argparse.Action): def __call__(self, parser, namespace, values, option_string=None): - if values == self.default: + if "datadirectory" in self.dest: + set_FeedChoices({"datadirectory" : values}) setattr(namespace, self.dest, values) - else: - self.choices=greg.greg.get_feeds(vars(namespace)) - for value in values: - if value not in self.choices: - msg = "%r is not a valid feed" % value - raise argparse.ArgumentError(self, msg) + elif "configfile" in self.dest: + set_FeedChoices({"configfile" : values}) setattr(namespace, self.dest, values) - -def FeedsCompleter(parsed_args, **kwargs): - feeds=greg.greg.get_feeds(vars(parsed_args)) - return feeds + else: + if values == self.default: + setattr(namespace, self.dest, values) + else: + try: + self.choices = feednames + except NameError: + set_FeedChoices(vars(namespace)) + self.choices = feednames + for value in values: + if value not in self.choices: + msg = "%r is not a valid feed" % value + raise argparse.ArgumentError(self, msg) + setattr(namespace, self.dest, values) #Create the top-level parser parser = argparse.ArgumentParser() parser.add_argument('--configfile', '-cf', - help='specifies the config file that greg should use') + help='specifies the config file that greg should use', action=customActionSetFeedChoices, metavar='CONFIGFILE') parser.add_argument('--datadirectory', '-dtd', - help='specifies the directory where greg keeps its data') + help='specifies the directory where greg keeps its data', action=customActionSetFeedChoices, metavar='DATADIRECTORY') + subparsers = parser.add_subparsers() # create the parser for the "add" command @@ -77,7 +85,7 @@ def FeedsCompleter(parsed_args, **kwargs): # create the parser for the "edit" command parser_edit = subparsers.add_parser('edit', help='edits a feed') -parser_edit.add_argument('name', action=customActionGetFeeds, help='the name of the feed to be edited', nargs=1, metavar='FEEDNAME').completer = FeedsCompleter +parser_edit.add_argument('name', action=customActionSetFeedChoices, help='the name of the feed to be edited', nargs=1, metavar='FEEDNAME') group = parser_edit.add_mutually_exclusive_group(required = True) group.add_argument('--url', '-u', type = url, help='the new url of the feed', nargs=1) group.add_argument('--downloadfrom', '-d', @@ -86,7 +94,7 @@ def FeedsCompleter(parsed_args, **kwargs): # create the parser for the "info" command parser_info = subparsers.add_parser('info', help='provides information about a feed') -parser_info.add_argument('names', action=customActionGetFeeds, help='the name(s) of the feed(s) you want to know about', nargs='*', default=['all'], metavar='FEEDNAME').completer = FeedsCompleter +parser_info.add_argument('names', action=customActionSetFeedChoices, help='the name(s) of the feed(s) you want to know about', nargs='*', default=['all'], metavar='FEEDNAME') parser_info.set_defaults(func=greg.greg.info) # create the parser for the "list" command @@ -95,7 +103,7 @@ def FeedsCompleter(parsed_args, **kwargs): # create the parser for the "sync" command parser_sync = subparsers.add_parser('sync', help='syncs feed(s)') -parser_sync.add_argument('names', action=customActionGetFeeds, help='the name(s) of the feed(s) you want to sync', nargs='*', default=['all'], metavar='FEEDNAME').completer = FeedsCompleter +parser_sync.add_argument('names', help='the name(s) of the feed(s) you want to sync', action=customActionSetFeedChoices, nargs='*', default=['all'], metavar='FEEDNAME') parser_sync.add_argument('--downloadhandler', '-dh', help='whatever you want greg to do with the enclosure') parser_sync.add_argument('--downloaddirectory', '-dd', help='the directory to which you want to save your downloads') parser_sync.add_argument('--firstsync', '-fs', help='the number of files to download (if this is the first sync)') @@ -103,9 +111,9 @@ def FeedsCompleter(parsed_args, **kwargs): # create the parser for the "check" command parser_check = subparsers.add_parser('check', help='checks feed') -group = parser_check.add_mutually_exclusive_group(required=True) -group.add_argument('--url', '-u', type = url, help='the url that you want to check', nargs=1) -group.add_argument('--feed', '-f', action=customActionGetFeeds, help='the feed that you want to check', nargs=1, metavar='FEEDNAME').completer = FeedsCompleter +check_group = parser_check.add_mutually_exclusive_group(required=True) +check_group.add_argument('--url', '-u', type = url, help='the url that you want to check', nargs=1) +check_group.add_argument('--feed', '-f', help='the feed that you want to check', action=customActionSetFeedChoices, nargs=1, metavar='FEEDNAME') parser_check.set_defaults(func=greg.greg.check) # create the parser for the "download" command @@ -118,21 +126,25 @@ def FeedsCompleter(parsed_args, **kwargs): # create the parser for the "remove" command parser_remove = subparsers.add_parser('remove', help='removes feed(s)') -parser_remove.add_argument('name', action=customActionGetFeeds, help='the name of the feed(s) you want to remove', nargs='+', metavar='FEEDNAME').completer = FeedsCompleter +parser_remove.add_argument('name', help='the name of the feed(s) you want to remove', action=customActionSetFeedChoices, nargs='+', metavar='FEEDNAME') parser_remove.set_defaults(func=greg.greg.remove) +# create the parser for the 'opml' command +parser_opml = subparsers.add_parser('opml', help='import/export an opml feed list') +opml_group = parser_opml.add_mutually_exclusive_group(required=True) +opml_group.add_argument('--import', '-i', help='import an opml feed', nargs=1, metavar='FILENAME') +opml_group.add_argument('--export', '-e', help='export an opml feed', nargs=1, metavar='FILENAME') +parser_opml.set_defaults(func=greg.greg.opml) + # create the parser for the 'retrieveglobalconf' command parser_rgc = subparsers.add_parser('retrieveglobalconf', aliases=['rgc'], help='retrieves the path to the global config file') parser_rgc.set_defaults(func=greg.greg.retrieveglobalconf) - def main(): """ Parse the args and call whatever function was selected """ - if argcompleteexists: - argcomplete.autocomplete(parser) args = parser.parse_args() try: function = args.func diff --git a/pkgbuilds/git/PKGBUILD b/pkgbuilds/git/PKGBUILD index 0c33b5f..5ff034a 100644 --- a/pkgbuilds/git/PKGBUILD +++ b/pkgbuilds/git/PKGBUILD @@ -12,8 +12,7 @@ depends=('python-feedparser') optdepends=('python3-stagger-svn: writing metadata' 'wget: alternative downloadhandler' 'aria2: alternative downloadhandler' - 'python-beautifulsoup4: convert html to text for tagging' - 'python-argcomplete: tab completion') + 'python-beautifulsoup4: convert html to text for tagging') makedepends=('git') provides=('greg') conflicts=('greg') From 49ab65b6a3d5e295c3c7eed599586e60c973eac3 Mon Sep 17 00:00:00 2001 From: Filip Balos Date: Wed, 15 Jun 2016 19:54:05 -0400 Subject: [PATCH 3/8] Reverts an 'include' change that wasn't needed --- greg/greg.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/greg/greg.py b/greg/greg.py index a59e41d..6d8062f 100755 --- a/greg/greg.py +++ b/greg/greg.py @@ -25,7 +25,7 @@ import unicodedata import string from itertools import filterfalse -import urllib.request +from urllib.request import urlretrieve from urllib.parse import urlparse from urllib.error import URLError from lxml import etree as ET From e029995e999325ec67f4fdca4d158ac39f3953dc Mon Sep 17 00:00:00 2001 From: Filip Balos Date: Wed, 15 Jun 2016 20:58:23 -0400 Subject: [PATCH 4/8] Check feed type and sort before exporting to OPML --- greg/greg.py | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/greg/greg.py b/greg/greg.py index 6d8062f..a63472f 100755 --- a/greg/greg.py +++ b/greg/greg.py @@ -894,13 +894,22 @@ def opml(args): dateCreated = ET.SubElement(head, "dateCreated") dateCreated.text = time.strftime("%c %Z") body = ET.SubElement(toplevel, "body") - for feedname in session.list_feeds(): + for feedname in sorted(session.list_feeds()): if session.feeds.has_option(feedname, "url"): - outline = ET.SubElement(body, "outline") - outline.set("text", feedname) - outline.set("title", feedname) - outline.set("xmlUrl", session.feeds.get(feedname, "url")) - outline.set("type", "rss") + feedurl = session.feeds.get(feedname, "url") + feedtype = feedparser.parse(feedurl).version + if "rss" in feedtype: feedtype = "rss" + elif "atom" in feedtype: feedtype = "atom" + else: + feedtype = False + print("%r is not a valid feed, skipping." % feedname) + if feedtype: + print("Exporting %r..." % (feedname)) + outline = ET.SubElement(body, "outline") + outline.set("text", feedname) + outline.set("title", feedname) + outline.set("xmlUrl", feedurl) + outline.set("type", feedtype) opmlfile = open(filename, 'wb') opmlfile.write(('\n' \ + '\n\n').encode()) - opmlfile.write(ET.tostring(toplevel, encoding="utf-8", pretty_print=True)) + if lxmlexists: + opmlfile.write(ET.tostring(toplevel, encoding="utf-8", pretty_print=True)) + else: + opmlfile.write(ET.tostring(toplevel, encoding="utf-8")) opmlfile.close() diff --git a/pkgbuilds/git/PKGBUILD b/pkgbuilds/git/PKGBUILD index 0c33b5f..091d3b1 100644 --- a/pkgbuilds/git/PKGBUILD +++ b/pkgbuilds/git/PKGBUILD @@ -13,7 +13,8 @@ optdepends=('python3-stagger-svn: writing metadata' 'wget: alternative downloadhandler' 'aria2: alternative downloadhandler' 'python-beautifulsoup4: convert html to text for tagging' - 'python-argcomplete: tab completion') + 'python-argcomplete: tab completion' + 'python-lxml: nicer opml formatting') makedepends=('git') provides=('greg') conflicts=('greg')