Skip to content

shrimple 🇵🇱 🏳️‍⚧️

shrimple mind. shrimple problems. complex solutions. she/her

Subscription into list rather than tour — Offpunk draft feature patch

Posted on January[²⁰26], Thursday 29.January[²⁰26], Friday 30. By Shrimple 2 Comments on Subscription into list rather than tour — Offpunk draft feature patch

Offpunk has a feature where any updated links from a subscribed list will be added to tour on sync. I expanded on that feature by making it possible to parameterize #subscribe with a list name like #subscribe(some_list_name) to the result of the links getting added to that list, with just the one link to that list getting added to tour.

See also another patch for introducing slash-containing list names (as directory hierarchy underneath): Slash-hierarchical list names — my draft implementation for Offpunk

From a4df30bc796c6c8d197d6cc79f4d8e665e07f4a2 Mon Sep 17 00:00:00 2001
Date: Thu, 29 Jan 2026 19:28:37 +0100
Subject: [PATCH] feature: Subscribe into #subscribe(into-another-list)

If user specifies an additional parameter to the subscribe subcommand,
it will be mentioned as a reference to another list, to which on sync
the links are to be added instead. Then, list URI link is added to the
tour.
---
 offpunk.py | 112 +++++++++++++++++++++++++++++++++++++----------------
 1 file changed, 79 insertions(+), 33 deletions(-)

diff --git a/offpunk.py b/offpunk.py
index eeadc42..a03edbb 100755
--- a/offpunk.py
+++ b/offpunk.py
@@ -14,6 +14,7 @@ import os.path
 import shutil
 import sys
 import time
+import typing
 import urllib.parse
 import gettext
 
@@ -1889,9 +1890,9 @@ Use "view XX" where XX is a number to view information about link XX.
                             print(_("Removed from %s") % l)
                 self.list_add_line(args[0])
 
-    def list_lists(self):
+    def list_lists(self) -> list[str]:
         listdir = os.path.join(xdg("data"), "lists")
-        to_return = []
+        to_return: list[str] = []
         if os.path.exists(listdir):
             lists = os.listdir(listdir)
             if len(lists) > 0:
@@ -1904,13 +1905,26 @@ Use "view XX" where XX is a number to view information about link XX.
 
     def list_has_status(self, list, status):
         path = self.list_path(list)
-        toreturn = False
+        toreturn: str | bool = False
         if path:
             with open(path) as f:
                 line = f.readline().strip()
                 f.close()
-            if line.startswith("#") and status in line:
-                toreturn = True
+            toreturn = self._list_line_has_status(line, status)
+        return toreturn
+
+    @staticmethod
+    def _list_line_has_status(line: str, status: str) -> bool:
+        toreturn: str | bool = False
+        pos = line.find(status)
+        if line.startswith("#") and pos != -1:
+            toreturn = True
+            pos += len(status)
+            if line[pos] == "(":
+                pos += 1
+                end = line.find(")", pos)
+                if end != -1:
+                    toreturn = line[pos:end]
         return toreturn
 
     def list_is_subscribed(self, list):
@@ -1925,21 +1939,31 @@ Use "view XX" where XX is a number to view information about link XX.
     # This modify the status of a list to one of :
     # normal, frozen, subscribed
     # action is either #frozen, #subscribed or None
-    def list_modify(self, list, action=None):
-        path = self.list_path(list)
+    def list_modify(self, list_name, action=None,
+                    argument: str | None = None):
+        path = self.list_path(list_name)
         with open(path) as f:
             lines = f.readlines()
             f.close()
         if lines[0].strip().startswith("#"):
             first_line = lines.pop(0).strip("\n")
         else:
-            first_line = "# %s " % list
-        first_line = first_line.replace("#subscribed", "").replace("#frozen", "")
+            first_line = "# %s " % list_name
+        for such_status in ("#subscribed", "#frozen"):
+            haz_status = self._list_line_has_status(first_line, such_status)
+            if haz_status:
+                # noinspection PySimplifyBooleanCheck
+                if haz_status != True:
+                    first_line = first_line.replace(f"{such_status}({haz_status})", "")
+                else:
+                    first_line = first_line.replace(such_status, "")
         if action:
+            if argument:
+                action = f"{action}({argument})"
             first_line += " " + action
-            print(_("List %s has been marked as %s") % (list, action))
+            print(_("List %s has been marked as %s") % (list_name, action))
         else:
-            print(_("List %s is now a normal list") % list)
+            print(_("List %s is now a normal list") % list_name)
         first_line += "\n"
         lines.insert(0, first_line)
         with open(path, "w") as f:
@@ -2062,7 +2086,8 @@ Use "view XX" where XX is a number to view information about link XX.
                             action = "#frozen"
                         else:
                             action = None
-                        self.list_modify(args[1], action=action)
+                        self.list_modify(args[1], action=action,
+                            argument=(args[2] if len(args) > 2 else None))
                 else:
                     print(_("A valid list name is required after %s") % args[0])
             elif args[0] == "help":
@@ -2125,7 +2150,7 @@ Use "view XX" where XX is a number to view information about link XX.
             validity = 0
         self.call_sync(refresh_time=validity)
 
-    def call_sync(self, refresh_time=0, depth=1, lists=None):
+    def call_sync(self, refresh_time=0, depth=1, lists: list[str] | None = None):
         # fetch_url is the core of the sync algorithm.
         # It takes as input :
         # - an URL to be fetched
@@ -2134,26 +2159,40 @@ Use "view XX" where XX is a number to view information about link XX.
         #               being refreshed (0 = never refreshed if it already exists)
         # - savetotour : if True, newly cached items are added to tour
         def add_to_tour(url):
+            add_to_list(url, "tour")
+        def add_to_list(url, list_name: str):
             if url and netcache.is_cache_valid(url):
-                toprint = _("  -> adding to tour: %s") % url
+                toprint = _(f"  -> adding to %s: %s") % (list_name, url)
                 width = term_width() - 1
                 toprint = toprint[:width]
                 toprint += " " * (width - len(toprint))
                 print(toprint)
-                self.list_add_line("tour", url=url, verbose=False)
-                return True
-            else:
-                return False
+                return self.list_add_line(list_name, url=url, verbose=False)
+            return False
 
         def fetch_url(
-            url, depth=0, validity=0, savetotour=False, count=[0, 0], strin="",
+            url, depth=0, validity=0,
+            savetotour: str | bool = False,
+            count=[0, 0], strin="",
             force_large_download=False
-        ):
-            # savetotour = True will save to tour newly cached content
-            # else, do not save to tour
-            # regardless of valitidy
+        ) -> str | None:
+            """
+
+            :param url:
+            :param depth:
+            :param validity:
+            :param savetotour: savetotour = True will save to tour newly cached content
+            savetotour = <list name> will save to the list and return its name
+            else, do not save to tour
+            regardless of valitidy
+            :param count:
+            :param strin:
+            :param force_large_download:
+            :return: savetotour in case of savetotour being truthy but not true and something saved (implied: list name), else None
+            """
+            #
             if not url:
-                return
+                return None
             if not netcache.is_cache_valid(url, validity=validity):
                 if strin != "":
                     endline = "\r"
@@ -2173,7 +2212,11 @@ Use "view XX" where XX is a number to view information about link XX.
                 if savetotour and isnew and netcache.is_cache_valid(url):
                     # we add to the next tour only if we managed to cache
                     # the ressource
-                    add_to_tour(url)
+                    match savetotour:
+                        case True: add_to_tour(url)
+                        case _:
+                            add_to_list(url, savetotour)
+                            return savetotour
             # Now, recursive call, even if we didn’t refresh the cache
             # This recursive call is impacting performances a lot but is needed
             # For the case when you add a address to a list to read later
@@ -2206,6 +2249,7 @@ Use "view XX" where XX is a number to view information about link XX.
                             count=subcount,
                             strin=substri,
                         )
+            return None
 
         def fetch_list(
             list, validity=0, depth=1, tourandremove=False, tourchildren=False,
@@ -2218,14 +2262,15 @@ Use "view XX" where XX is a number to view information about link XX.
             for l in links:
                 counter += 1
                 # If cache for a link is newer than the list
-                fetch_url(
+                if fetch_url(
                     l,
                     depth=depth,
                     validity=validity,
                     savetotour=tourchildren,
                     count=[counter, end],
                     force_large_download=force_large_download
-                )
+                ):
+                    add_to_tour(f"list://{tourchildren}")
                 if tourandremove:
                     if add_to_tour(l):
                         self.list_rm_url(l, list)
@@ -2235,23 +2280,24 @@ Use "view XX" where XX is a number to view information about link XX.
             lists = self.list_lists()
         # We will fetch all the lists except "archives" and "history"
         # We keep tour for the last round
-        subscriptions = []
+        subscriptions: list[tuple[str, str | bool]] = []
         normal_lists = []
         fridge = []
         for l in lists:
             # only try existing lists
             if l in self.list_lists():
                 if not self.list_is_system(l):
-                    if self.list_is_frozen(l):
+                    sub: str | bool = self.list_is_subscribed(l)
+                    if sub:
+                        subscriptions.append((l, sub))
+                    elif self.list_is_frozen(l):
                         fridge.append(l)
-                    elif self.list_is_subscribed(l):
-                        subscriptions.append(l)
                     else:
                         normal_lists.append(l)
         # We start with the "subscribed" as we need to find new items
         starttime = int(time.time())
-        for l in subscriptions:
-            fetch_list(l, validity=refresh_time, depth=depth, tourchildren=True)
+        for (l, sub) in subscriptions:
+            fetch_list(l, validity=refresh_time, depth=depth, tourchildren=sub)
         # Then the to_fetch list (item are removed from the list after fetch)
         # We fetch regarless of the refresh_time
         if "to_fetch" in lists:
-- 
2.52.0
Wild Software Writing Tags:big.ugly.git.patch., offpunk, offpunk:lists, oss-contributing, subscribe

Post navigation

Previous Post: Slash-hierarchical list names — my draft implementation for Offpunk
Next Post: Distributed file version management in 15 minutes of Bash

Related Posts

  • Experimentally expanding Offpunk browser Part 1 (nightly) Wild Software Writing
  • Distributed file version management in 15 minutes of Bash Wild Software Writing
  • Slash-hierarchical list names — my draft implementation for Offpunk Wild Software Writing
  • Amending my Offpunk redirection implementation Wild Software Writing
  • Bugfix for list URI for my Offpunk redirections implementation draft Wild Software Writing
  • Simplistic reconciliation of mostly-append text files like Offpunk lists: draft involving Kahn’s algorithm Wild Software Writing

Comments (2) on “Subscription into list rather than tour — Offpunk draft feature patch”

  1. Pingback: Slash-hierarchical list names — my draft implementation for Offpunk – shrimple 🇵🇱 🏳️‍⚧️
  2. Pingback: Bugfix for list URI for my Offpunk redirections implementation draft – shrimple 🇵🇱 🏳️‍⚧️

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Atom feed for this page

Atom feed for this blog

against-messy-software bash big.ugly.git.patch. chromium-and-derivatives community fragment golang kde links2 linux microsoft-edge network offpunk offpunk:lists offpunk:redirections oss-contributing perl programming-tips scripting smolweb subscribe superuser window-decorations Wordpress_ActivityPub_plugin

  • February 2026 (4)
  • January 2026 (10)

Categories

  • Influencing Society

    (1)
  • Meta

    (2)
  • Oddities of alternate reality

    (1)
  • Programming Technologies

    (1)
  • Software Imposed On Us

    (1)
  • Wild Software Writing

    (8)
shrimple 🇵🇱  🏳️‍⚧️
shrimple 🇵🇱 🏳️‍⚧️
@shrimple@www.shrimple.pl
Follow

shrimple mind. shrimple problems. complex solutions. she/her

14 posts
5 followers

Follow shrimple 🇵🇱 🏳️‍⚧️

My Profile

Copy and paste my profile into the search field of your favorite fediverse app or server.

Your Profile

Or, if you know your own profile, we can start things that way!
  • Hello world! Meta
  • Forcing KWin decorations and MS Edge’s 1cm shadow gradient Software Imposed On Us
  • Simplistic reconciliation of mostly-append text files like Offpunk lists: draft involving Kahn’s algorithm Wild Software Writing
  • Experimentally expanding Offpunk browser Part 1 (nightly) Wild Software Writing
  • Slash-hierarchical list names — my draft implementation for Offpunk Wild Software Writing
  • Why follow requests here and can I even be followed Meta
  • Bugfix for list URI for my Offpunk redirections implementation draft Wild Software Writing
  • Links 2, a graphical browser I wanna build upon. And a quick look at how ELinks is doing. Wild Software Writing

shrimple@shrimple.pl

Copyright © 2026 shrimple 🇵🇱 🏳️‍⚧️.

Powered by PressBook News WordPress theme