diff --git a/CHANGELOG b/CHANGELOG index a549320..92bc9f7 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,6 @@ # Offpunk History -## 0.4 - Unreleased +## 0.4 - Feb 21st 2022 UPGRADE: Users who subscribed to pages before 0.4 should run once the command "list subscribe subscribed". Without that, the subscribed list will be seen as a normal list by sync. - New list command : "list freeze" and "list suscribe" - Pictures are now displayed directely in terminal (suggested by kelbot) @@ -13,6 +13,7 @@ UPGRADE: Users who subscribed to pages before 0.4 should run once the command "l - "version" will now display info about your system installation - "info" command will display technical information about current page - "sync" allows you to do the sync from within Offpunk +=> gemini://rawtext.club/~ploum/2022-02-21-offpunk04.gmi ## 0.3 - Feb 11th 2022 New Features: diff --git a/README.md b/README.md index 694fb68..33ac37f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # OFFPUNK -A command-line, text-based and offline-first Gemini, Gopher and Web browser by [Ploum](https://ploum.net). +A command-line and offline-first smolnet browser/feed reader for Gemini, Gopher and Web by [Ploum](https://ploum.net). The goal of Offpunk is to be able to synchronise your content once (a day, a week, a month) and then browse/organise it while staying disconnected. @@ -46,11 +46,8 @@ Known issues in the code: I would happily mentor anyone willing to implement those: * TODO0: Hard - Make a manual within the git repository and have it automatically deployed as a website. * TODO1: Easy - Update blackbox to reflect cache hits. -* TODO2: Hard - "pdf" - Implement retrieving PDF version of pages -* TODO3: Medium - Transparent privacy redirects (twitter->nitter, etc) -* TODO4: Medium - Rendering themes to allow customizing of colors ? (if any interest in the feature) -* TODO6: Hard - "search" - Offline search engine to search in the cache (hard, no idea on how to do that) -* TODO7: Easy - "share" - send a page by email +* TODO2: Medium - Rendering themes to allow customizing of colors ? (if any interest in the feature) +* TODO3: Hard - "search" - Offline search engine to search in the cache (hard, no idea on how to do that) ## More @@ -61,16 +58,17 @@ Announces about Offpunk will be made on Ploum’s Gemlog => gemini://rawtext.cl ## Dependencies -Offpunk has no "strict dependencies", i.e. it will run and work without anything +Offpunk has no "strict dependencies", i.e. it should run and work without anything else beyond the Python standard library and the "less" pager. However, it will "opportunistically import" a few other libraries if they are available to offer an improved experience or some other features. Python libraries requests, bs4 and readabliity are required for http/html support. -To avoid using unstable or too recent libraries, the rule of thumb is that a library should be packaged in Debian/Ubuntu. +To avoid using unstable or too recent libraries, the rule of thumb is that a library should be packaged in Debian/Ubuntu. Keep in mind that Offpunk is mainly tested will all libraries installed. If you encounter a crash without one optional dependencies, please report it. Run command `version` in offpunk to see if you are missing some dependencies. * [Python-xdg](https://www.freedesktop.org/wiki/Software/pyxdg) will place your data, config and cache in place recommended by the XDG specs (usually it’s .local/share/offpunk, .config/offpunk and .cache/offpunk). Without it, look for ~/.offpunk or ~/.config/offpunk while the cache will be in ~/.cache/offpunk/. If installation is done later, some config files may need to be migrated by hand. +* [xdg-utils](https://www.freedesktop.org/wiki/Software/xdg-utils/) provides xdg-open which is highly recommended to open files without a renderer or a handler. It is also used for mailto: command. * [Python-requests](http://python-requests.org) is needed to handle http/https requests natively (apt-get install python3-requests). Without it, http links will be opened in an external browser * [BeautifulSoup4](https://www.crummy.com/software/BeautifulSoup) and [Readability](https://github.com/buriy/python-readability) are both needed to render HTML. Without them, HTML will not be rendered or be sent to an external parser like Lynx. (apt-get install python3-bs4 python3-readability or pip3 install readability-lxml) * [Python-feedparser](https://github.com/kurtmckee/feedparser) will allow parsing of RSS/Atom feeds and thus subscriptions to them. (apt-get install python3-feedparser) @@ -92,8 +90,9 @@ Run command `version` in offpunk to see if you are missing some dependencies. * Built-in documentation: type `help` to get the list of command or a specific help about a command. * Offline mode to browse cached content without a connection. Requested elements are automatically fetched during the next synchronization and are added to your tour. * HTML pages are prettified to focus on content. Read without being disturbed. +* RSS/Atom feeds are automatically discovered by `subscribe` and rendered as gemlogs. * Support "subscriptions" to a page. New content seen in subscribed pages are automatically added to your next tour. -* Complex bookmarks management through multiple lists, built-in edition and archiving. +* Complex bookmarks management through multiple lists, built-in edition, subscribing/freezing and archiving. * Advanced navigation tools like `tour` and `mark` (as per VF-1). Unlike AV-98, tour is saved on disk accross sessions. * Ability to specify external handler programs for different MIME types (use `handler`) * Non-interactive cache-building with configurable depth through the --sync command. The cache can easily be used by other software. diff --git a/offpunk.py b/offpunk.py index e212776..aa462fa 100755 --- a/offpunk.py +++ b/offpunk.py @@ -68,6 +68,7 @@ except ModuleNotFoundError: _HAS_CHAFA = shutil.which('chafa') _HAS_XSEL = shutil.which('xsel') +_HAS_XDGOPEN = shutil.which('xdg-open') try: from PIL import Image _HAS_PIL = True @@ -300,7 +301,9 @@ class AbstractRenderer(): return self.validity def get_links(self): if self.links == None : - rendered_text, self.links = self.render(self.body,mode="links_only") + results = self.render(self.body,mode="links_only") + if results: + self.links = results[1] return self.links def get_title(self): return "Abstract title" @@ -318,7 +321,10 @@ class AbstractRenderer(): else : mode = "full" prepared_body = self.prepare(self.body,mode=mode) - self.rendered_text, self.links = self.render(prepared_body,width=width,mode=mode) + result = self.render(prepared_body,width=width,mode=mode) + if result: + self.rendered_text = result[0] + self.links = result[1] return self.rendered_text # An instance of AbstractRenderer should have a self.render(body,width,mode) method. # 3 modes are used : readable (by default), full and links_only (the fastest, when @@ -651,6 +657,10 @@ class ImageRenderer(AbstractRenderer): class HtmlRenderer(AbstractRenderer): def get_mime(self): return "text/html" + def is_valid(self): + if not _DO_HTML: + print("HTML document detected. Please install python-bs4 and python-readability.") + return _DO_HTML and self.validity def get_subscribe_links(self): subs = [[self.url,self.get_mime(),self.get_title()]] soup = BeautifulSoup(self.body, 'html.parser') @@ -1165,7 +1175,7 @@ class GeminiItem(): def get_rendered_body(self,readable=True): if not self.renderer: self._set_renderer() - if self.renderer: + if self.renderer and self.renderer.is_valid(): body = self.renderer.get_body(readable=readable) self.__make_links(self.renderer.get_links()) to_return = self._make_terminal_title() + body @@ -1472,8 +1482,12 @@ class GeminiClient(cmd.Cmd): resp = input("Send an email to %s Y/N? " %gi.path) self.gi = gi if resp.strip().lower() in ("y", "yes"): - cmd = "xdg-open mailto:%s" %gi.path - subprocess.call(shlex.split(cmd)) + if _HAS_XDGOPEN : + cmd = "xdg-open mailto:%s" %gi.path + subprocess.call(shlex.split(cmd)) + else: + print("Cannot find a mail client to send mail to %s" %gi.path) + print("Please install xdg-open (usually from xdg-util package)") return elif gi.scheme not in ("file","gemini", "gopher", "http", "https") and not self.sync_only: print("Sorry, no support for {} links.".format(gi.scheme)) @@ -2103,7 +2117,11 @@ class GeminiClient(cmd.Cmd): break else: # Use "xdg-open" as a last resort. - cmd_str = "xdg-open %s" + if _HAS_XDGOPEN: + cmd_str = "xdg-open %s" + else: + cmd_str = "echo ""Can’t find how to open %s""" + print("Please install xdg-open (usually from xdg-util package)") self._debug("Using handler: %s" % cmd_str) return cmd_str @@ -2661,6 +2679,7 @@ Think of it like marks in vi: 'mark a'='ma' and 'go a'=''a'.""" output += " - python-readability : " + has(_HAS_READABILITY) output += " - python-xdg : " + has(_HAS_XDG) output += " - python-setproctitle : " + has(_HAS_SETPROCTITLE) + output += " - xdg-open : " + has(_HAS_XDGOPEN) output += " - chafa : " + has(_HAS_CHAFA) output += " - xsel : " + has(_HAS_XSEL) @@ -2674,7 +2693,7 @@ Think of it like marks in vi: 'mark a'='ma' and 'go a'=''a'.""" output += "\n" output += "Config directory : " + _CONFIG_DIR + "\n" output += "User Data directory : " + _DATA_DIR + "\n" - output += "CACHE : " + _CACHE_PATH + output += "Cache directoy : " + _CACHE_PATH print(output) diff --git a/setup.py b/setup.py index cf17456..972ef16 100755 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import setup setup( name='offpunk', - version='0.3', + version='0.4', description="Offline Command line Gemini client forked from AV-98.", author="Ploum", author_email="offpunk@ploum.eu",