gpodder-configured: add --no-sync flag to bypass feed list synchronization, for faster init

This commit is contained in:
2024-10-26 02:24:56 +00:00
parent 929dbc706b
commit b79c9749c0
3 changed files with 121 additions and 82 deletions

View File

@@ -0,0 +1,118 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p gpodder -p listparser -p python3
from dataclasses import dataclass, field
import argparse
import listparser
import subprocess
import sys
@dataclass(repr=True)
class Feed:
url: str
title: str # Optional
def __init__(self, url: str, title: str):
self.url = url
self.title = title if title else None
def __eq__(self, other: "Feed") -> bool:
return self.url == other.url and \
(self.title == other.title or None in [self.title, other.title])
@dataclass(init=True)
class Partitioned:
has_not_wanted: list[Feed] = field(default_factory=list)
wanted_not_has: list[Feed] = field(default_factory=list)
intersection: list[Feed] = field(default_factory=list)
def wanted_feeds(opml_file: str):
parsed = listparser.parse(open(opml_file).read())
return [Feed(url=p["url"], title=p["title"]) for p in parsed.feeds]
def has_feeds():
listing = subprocess.check_output(["gpo", "list"]).decode()
feeds = []
title = None
for line in listing.split("\n"):
if line.startswith("# "): # title
title = line[2:].strip()
elif line.startswith("http"): # feed URL:
feeds.append(Feed(url=line, title=title))
title = None
return feeds
def partition_feeds(wanted: list[Feed], has: list[Feed]) -> Partitioned:
p = Partitioned()
for f in wanted + has:
w, h = f in wanted, f in has
if h and not w:
p.has_not_wanted.append(f)
elif w and not h:
p.wanted_not_has.append(f)
else:
assert w and h
p.intersection.append(f)
return p
def remove_feed(feed: Feed):
subprocess.check_output(["gpo", "unsubscribe", feed.url])
def remove_feeds(feeds: list[str]):
if not feeds:
print("removing extra feeds: (none)")
return
print("removing extra feeds:\n", "\n ".join(repr(f) for f in feeds), "\n")
for f in feeds:
remove_feed(f)
def add_feeds(opml_path: str, feeds: list[str]):
if not feeds:
print("adding missing feeds: (none)")
return
print("adding missing feeds:\n", "\n ".join(repr(f) for f in feeds), "\n")
# i *think* it's about as fast to import the whole OPML as it is just one file?
subprocess.check_output(["gpo", "import", opml_path])
def sync_feeds(opml_path: str, do_remove: bool, do_add: bool):
wanted = wanted_feeds(opml_path)
has = has_feeds()
partitioned = partition_feeds(wanted, has)
if do_remove:
remove_feeds(partitioned.has_not_wanted)
if do_add:
add_feeds(opml_path, partitioned.wanted_not_has)
def main():
parser = argparse.ArgumentParser(usage="remove gpodder feeds which have been removed from nix config since last launch, and add missing feeds")
parser.add_argument("opml_path", help="path to the OPML feeds definition")
parser.add_argument("--no-sync", action="store_true", help="don't add or remove any feeds")
parser.add_argument("--no-remove", action="store_true", help="don't remove old feeds")
parser.add_argument("--no-add", action="store_true", help="don't add new feeds")
# ignore everything at/after an optional `--`.
# seemingly no way to do this with `argparse` proper, since for it `--` means "all following arguments are positionals"
argv = []
for i in sys.argv[1:]:
if i == "--": break
argv.append(i)
args = parser.parse_args(argv)
do_remove = not (args.no_sync or args.no_remove)
do_add = not (args.no_sync or args.no_add)
if do_remove or do_add:
sync_feeds(args.opml_path, do_remove, do_add)
if __name__ == "__main__":
main()

View File

@@ -1,79 +0,0 @@
#!/usr/bin/env nix-shell
#!nix-shell -i python3 -p gpodder -p listparser -p python3
from dataclasses import dataclass, field
import listparser
import subprocess
import sys
@dataclass(repr=True)
class Feed:
url: str
title: str # Optional
def __init__(self, url: str, title: str):
self.url = url
self.title = title if title else None
def __eq__(self, other: 'Feed') -> bool:
return self.url == other.url and \
(self.title == other.title or None in [self.title, other.title])
@dataclass(init=True)
class Partitioned:
has_not_wanted: list[Feed] = field(default_factory=list)
wanted_not_has: list[Feed] = field(default_factory=list)
intersection: list[Feed] = field(default_factory=list)
def wanted_feeds(opml_file: str):
parsed = listparser.parse(open(opml_file).read())
return [Feed(url=p['url'], title=p['title']) for p in parsed.feeds]
def has_feeds():
listing = subprocess.check_output(["gpo", "list"]).decode()
feeds = []
title = None
for line in listing.split("\n"):
if line.startswith("# "): # title
title = line[2:].strip()
elif line.startswith("http"): # feed URL:
feeds.append(Feed(url=line, title=title))
title = None
return feeds
def partition_feeds(wanted: list[Feed], has: list[Feed]) -> Partitioned:
p = Partitioned()
for f in wanted + has:
w, h = f in wanted, f in has
if h and not w:
p.has_not_wanted.append(f)
elif w and not h:
p.wanted_not_has.append(f)
else:
assert w and h
p.intersection.append(f)
return p
def remove_feed(feed: Feed):
subprocess.check_output(['gpo', 'unsubscribe', feed.url])
def rationalize_feeds(opml_file: str):
wanted = wanted_feeds(opml_file)
has = has_feeds()
partitioned = partition_feeds(wanted, has)
print("extra feeds:", "" if partitioned.has_not_wanted else "(none)")
for f in partitioned.has_not_wanted:
print(" ", f)
print()
for f in partitioned.has_not_wanted:
remove_feed(f)
if __name__ == "__main__":
wanted_opml, = sys.argv[1:]
rationalize_feeds(wanted_opml)

View File

@@ -8,7 +8,7 @@
let
remove-extra = static-nix-shell.mkPython3 {
pname = "gpodder-remove-extra";
pname = "gpodder-ensure-feeds";
srcRoot = ./.;
pkgs = {
# important for this to explicitly use `gpodder` here, because it may be overriden/different from the toplevel `gpodder`!
@@ -31,8 +31,8 @@ in
postBuild = ''
wrapProgram $out/bin/gpodder \
$extraMakeWrapperArgs \
--run "$out/bin/gpodder-remove-extra ~/.config/gpodderFeeds.opml || true" \
--run "$out/bin/gpo import ~/.config/gpodderFeeds.opml || true" \
--run "$out/bin/gpodder-ensure-feeds"' ~/.config/gpodderFeeds.opml "$@" || true' \
--run 'while [[ -n "$1" && "$1" != -- && "$1" != --help ]]; do shift; done ; if [[ "$1" == --help ]]; then exit; elif [[ "$1" == -- ]]; then shift; fi'
# fix up the .desktop file to invoke our wrapped application
# (rather, invoke `gpodder` by PATH, which could be this, or an outer layer of wrapping)