Releasing 0.4
This commit is contained in:
parent
aa8e0cdb3e
commit
3b809c4146
|
@ -1,6 +1,6 @@
|
||||||
# Offpunk History
|
# 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.
|
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"
|
- New list command : "list freeze" and "list suscribe"
|
||||||
- Pictures are now displayed directely in terminal (suggested by kelbot)
|
- 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
|
- "version" will now display info about your system installation
|
||||||
- "info" command will display technical information about current page
|
- "info" command will display technical information about current page
|
||||||
- "sync" allows you to do the sync from within Offpunk
|
- "sync" allows you to do the sync from within Offpunk
|
||||||
|
=> gemini://rawtext.club/~ploum/2022-02-21-offpunk04.gmi
|
||||||
|
|
||||||
## 0.3 - Feb 11th 2022
|
## 0.3 - Feb 11th 2022
|
||||||
New Features:
|
New Features:
|
||||||
|
|
17
README.md
17
README.md
|
@ -1,6 +1,6 @@
|
||||||
# OFFPUNK
|
# 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.
|
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:
|
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.
|
* 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.
|
* TODO1: Easy - Update blackbox to reflect cache hits.
|
||||||
* TODO2: Hard - "pdf" - Implement retrieving PDF version of pages
|
* TODO2: Medium - Rendering themes to allow customizing of colors ? (if any interest in the feature)
|
||||||
* TODO3: Medium - Transparent privacy redirects (twitter->nitter, etc)
|
* TODO3: Hard - "search" - Offline search engine to search in the cache (hard, no idea on how to do that)
|
||||||
* 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
|
|
||||||
|
|
||||||
## More
|
## More
|
||||||
|
|
||||||
|
@ -61,16 +58,17 @@ Announces about Offpunk will be made on Ploum’s Gemlog => gemini://rawtext.cl
|
||||||
|
|
||||||
## Dependencies
|
## 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
|
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
|
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.
|
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.
|
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.
|
* [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
|
* [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)
|
* [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)
|
* [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.
|
* 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.
|
* 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.
|
* 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.
|
* 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.
|
* 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`)
|
* 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.
|
* Non-interactive cache-building with configurable depth through the --sync command. The cache can easily be used by other software.
|
||||||
|
|
33
offpunk.py
33
offpunk.py
|
@ -68,6 +68,7 @@ except ModuleNotFoundError:
|
||||||
|
|
||||||
_HAS_CHAFA = shutil.which('chafa')
|
_HAS_CHAFA = shutil.which('chafa')
|
||||||
_HAS_XSEL = shutil.which('xsel')
|
_HAS_XSEL = shutil.which('xsel')
|
||||||
|
_HAS_XDGOPEN = shutil.which('xdg-open')
|
||||||
try:
|
try:
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
_HAS_PIL = True
|
_HAS_PIL = True
|
||||||
|
@ -300,7 +301,9 @@ class AbstractRenderer():
|
||||||
return self.validity
|
return self.validity
|
||||||
def get_links(self):
|
def get_links(self):
|
||||||
if self.links == None :
|
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
|
return self.links
|
||||||
def get_title(self):
|
def get_title(self):
|
||||||
return "Abstract title"
|
return "Abstract title"
|
||||||
|
@ -318,7 +321,10 @@ class AbstractRenderer():
|
||||||
else :
|
else :
|
||||||
mode = "full"
|
mode = "full"
|
||||||
prepared_body = self.prepare(self.body,mode=mode)
|
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
|
return self.rendered_text
|
||||||
# An instance of AbstractRenderer should have a self.render(body,width,mode) method.
|
# 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
|
# 3 modes are used : readable (by default), full and links_only (the fastest, when
|
||||||
|
@ -651,6 +657,10 @@ class ImageRenderer(AbstractRenderer):
|
||||||
class HtmlRenderer(AbstractRenderer):
|
class HtmlRenderer(AbstractRenderer):
|
||||||
def get_mime(self):
|
def get_mime(self):
|
||||||
return "text/html"
|
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):
|
def get_subscribe_links(self):
|
||||||
subs = [[self.url,self.get_mime(),self.get_title()]]
|
subs = [[self.url,self.get_mime(),self.get_title()]]
|
||||||
soup = BeautifulSoup(self.body, 'html.parser')
|
soup = BeautifulSoup(self.body, 'html.parser')
|
||||||
|
@ -1165,7 +1175,7 @@ class GeminiItem():
|
||||||
def get_rendered_body(self,readable=True):
|
def get_rendered_body(self,readable=True):
|
||||||
if not self.renderer:
|
if not self.renderer:
|
||||||
self._set_renderer()
|
self._set_renderer()
|
||||||
if self.renderer:
|
if self.renderer and self.renderer.is_valid():
|
||||||
body = self.renderer.get_body(readable=readable)
|
body = self.renderer.get_body(readable=readable)
|
||||||
self.__make_links(self.renderer.get_links())
|
self.__make_links(self.renderer.get_links())
|
||||||
to_return = self._make_terminal_title() + body
|
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)
|
resp = input("Send an email to %s Y/N? " %gi.path)
|
||||||
self.gi = gi
|
self.gi = gi
|
||||||
if resp.strip().lower() in ("y", "yes"):
|
if resp.strip().lower() in ("y", "yes"):
|
||||||
cmd = "xdg-open mailto:%s" %gi.path
|
if _HAS_XDGOPEN :
|
||||||
subprocess.call(shlex.split(cmd))
|
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
|
return
|
||||||
elif gi.scheme not in ("file","gemini", "gopher", "http", "https") and not self.sync_only:
|
elif gi.scheme not in ("file","gemini", "gopher", "http", "https") and not self.sync_only:
|
||||||
print("Sorry, no support for {} links.".format(gi.scheme))
|
print("Sorry, no support for {} links.".format(gi.scheme))
|
||||||
|
@ -2103,7 +2117,11 @@ class GeminiClient(cmd.Cmd):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# Use "xdg-open" as a last resort.
|
# 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)
|
self._debug("Using handler: %s" % cmd_str)
|
||||||
return 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-readability : " + has(_HAS_READABILITY)
|
||||||
output += " - python-xdg : " + has(_HAS_XDG)
|
output += " - python-xdg : " + has(_HAS_XDG)
|
||||||
output += " - python-setproctitle : " + has(_HAS_SETPROCTITLE)
|
output += " - python-setproctitle : " + has(_HAS_SETPROCTITLE)
|
||||||
|
output += " - xdg-open : " + has(_HAS_XDGOPEN)
|
||||||
output += " - chafa : " + has(_HAS_CHAFA)
|
output += " - chafa : " + has(_HAS_CHAFA)
|
||||||
output += " - xsel : " + has(_HAS_XSEL)
|
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 += "\n"
|
||||||
output += "Config directory : " + _CONFIG_DIR + "\n"
|
output += "Config directory : " + _CONFIG_DIR + "\n"
|
||||||
output += "User Data directory : " + _DATA_DIR + "\n"
|
output += "User Data directory : " + _DATA_DIR + "\n"
|
||||||
output += "CACHE : " + _CACHE_PATH
|
output += "Cache directoy : " + _CACHE_PATH
|
||||||
|
|
||||||
print(output)
|
print(output)
|
||||||
|
|
||||||
|
|
2
setup.py
2
setup.py
|
@ -2,7 +2,7 @@ from setuptools import setup
|
||||||
|
|
||||||
setup(
|
setup(
|
||||||
name='offpunk',
|
name='offpunk',
|
||||||
version='0.3',
|
version='0.4',
|
||||||
description="Offline Command line Gemini client forked from AV-98.",
|
description="Offline Command line Gemini client forked from AV-98.",
|
||||||
author="Ploum",
|
author="Ploum",
|
||||||
author_email="offpunk@ploum.eu",
|
author_email="offpunk@ploum.eu",
|
||||||
|
|
Loading…
Reference in New Issue