From e553166954251e239fe09e3dd5bc7a30cf441477 Mon Sep 17 00:00:00 2001 From: Schimon Jehudah Date: Sat, 9 Mar 2024 19:03:18 +0000 Subject: [PATCH] Improve About form. Improve handling of setting change. --- slixfeed/action.py | 16 +- slixfeed/assets/feeds.toml | 38 +- slixfeed/assets/information.toml | 976 +++++++++++++++++++++---------- slixfeed/config.py | 8 + slixfeed/version.py | 4 +- slixfeed/xmpp/client.py | 133 ++--- slixfeed/xmpp/command.py | 181 +++--- slixfeed/xmpp/component.py | 157 +++-- slixfeed/xmpp/process.py | 109 ++-- 9 files changed, 1008 insertions(+), 614 deletions(-) diff --git a/slixfeed/action.py b/slixfeed/action.py index f681b77..8a5416e 100644 --- a/slixfeed/action.py +++ b/slixfeed/action.py @@ -54,11 +54,15 @@ from slixfeed.xmpp.presence import XmppPresence from slixfeed.xmpp.upload import XmppUpload from slixfeed.xmpp.utility import get_chat_type import sys -import tomllib from urllib import error from urllib.parse import parse_qs, urlsplit import xml.etree.ElementTree as ET +try: + import tomllib +except: + import tomli as tomllib + logger = Logger(__name__) try: @@ -655,10 +659,12 @@ def list_feeds(results): .format(len(results))) else: url = pick_a_feed() - message = ('List of subscriptions is empty. To add a feed, send a URL.' - 'Featured feed:\n*{}*\n{}' - .format(url['name'], - url['link'])) + message = ('List of subscriptions is empty.' + '\n' + 'To add a feed, send a URL.' + '\n' + 'Featured news:\n*{}*\n{}' + .format(url['name'], url['link'])) return message diff --git a/slixfeed/assets/feeds.toml b/slixfeed/assets/feeds.toml index 36c71b8..ff87098 100644 --- a/slixfeed/assets/feeds.toml +++ b/slixfeed/assets/feeds.toml @@ -76,6 +76,12 @@ name = "classless Kulla" link = "https://www.classless.org/feed/atom/" tags = ["europe ,germany ,history ,literature ,war"] +[[feeds]] +lang = "de-de" +name = "Die Unbestechlichen" +link = "https://dieunbestechlichen.com/feed/" +tags = ["culture", "germany", "local", "news"] + [[feeds]] lang = "de-de" name = "Digitalcourage" @@ -286,6 +292,12 @@ name = "Ctrl blog" link = "https://feed.ctrl.blog/latest.atom" tags = ["computer", "technology"] +[[feeds]] +lang = "en-us" +name = "Delta Chat - Messenger based on e-mail" +link = "https://delta.chat/feed.xml" +tags = ["email", "telecommunication"] + [[feeds]] lang = "en-us" name = "Disroot Blog" @@ -478,6 +490,12 @@ name = "Project Gemini news" link = "https://gemini.circumlunar.space/news/atom.xml" tags = ["gemini", "internet"] +[[feeds]] +lang = "en-us" +name = "Public Intelligence Blog" +link = "https://phibetaiota.net/feed/" +tags = ["cia", "conspiracy", "health", "government", "war"] + [[feeds]] lang = "en-us" name = "PUNCH" @@ -578,13 +596,7 @@ tags = ["3d", "architecture", "design", "game"] lang = "en-us" name = "Take Back Our Tech" link = "https://takebackourtech.org/rss/" -tags = ["internet", "privacy", "surveillance"] - -[[feeds]] -lang = "en-us" -name = "The Bald Brothers" -link = "https://thebaldbrothers.com/feed/" -tags = ["lifestyle", "men"] +tags = ["computer", "internet", "privacy", "surveillance"] [[feeds]] lang = "en-us" @@ -592,12 +604,24 @@ name = "The 250kb Club" link = "https://250kb.club/rss.xml" tags = ["webring"] +[[feeds]] +lang = "en-us" +name = "The Bald Brothers" +link = "https://thebaldbrothers.com/feed/" +tags = ["lifestyle", "men"] + [[feeds]] lang = "en-us" name = "The Conscious Resistance Network" link = "https://theconsciousresistance.com/feed/" tags = ["culture", "government", "podcast", "politics", "privacy", "surveillance", "usa"] +[[feeds]] +lang = "en-us" +name = "Lazy Reading | The Cyber Vanguard" +link = "https://cyber.dabamos.de/blog/feed.rss" +tags = ["computer", "internet", "linux", "software", "telecommunication"] + [[feeds]] lang = "en-us" name = "The Corbett Report" diff --git a/slixfeed/assets/information.toml b/slixfeed/assets/information.toml index 50803d1..093fe43 100644 --- a/slixfeed/assets/information.toml +++ b/slixfeed/assets/information.toml @@ -1,5 +1,9 @@ -about = [ -""" +[[about]] +title = "About" +subtitle = "Slixfeed news bot" + +[[about]] +info = [""" Slixfeed is a news broker bot for syndicated news which aims to be \ an easy to use and fully-featured news aggregating bot. @@ -9,349 +13,723 @@ driven functionalities. Slixfeed is designed primarily for the XMPP communication network \ (aka Jabber). Visit https://xmpp.org/software/ for more information. +"""] -https://gitgud.io/sjehuda/slixfeed -""" -] +note = [""" +You can run your own Slixfeed instance as a client, from your own \ +computer, server, and even from a Linux phone (i.e. Droidian, Kupfer, \ +Mobian, NixOS, postmarketOS), as well as from Termux. -authors = [ - "Laura Lapina ", - "(Co-Author, Instructor and Mentor), ", - "Schimon Zackary ", - "(Author)." -] +All you need is one of the above and an XMPP account to connect \ +Slixfeed with. -filetypes = [ -""" -Supported filetypes: Atom, JSON, RDF, RSS and XML. -""" -] +Good luck! +"""] -license = [ +filetypes = "Atom, JSON, RDF, RSS, XML." +platforms = "XMPP" +# platforms = "ActivityPub, Briar, Email, IRC, LXMF, MQTT, Nostr, Session, Tox." +comment = "For ideal experience, we recommend using XMPP." +url = "https://gitgud.io/sjehuda/slixfeed" + +[[authors]] +title = "Authors" +subtitle = "The people who have made Slixfeed" + +[[authors]] +name = "Laura Lapina" +role = "Co-Author, Instructor and Mentor" +type = "AsyncIO, SQLite" + +[[authors]] +name = "Schimon Zackary" +role = "Creator and Author" + +[[contributors]] +title = "Contributors" +subtitle = "The people who have contributed to Slixfeed" + +[[contributors]] +name = "Stephen Paul Weber" +role = "Contributor and forms coordinator" +type = "XEP-0004, XEP-0050, XEP-0122" +project = "Cheogram" + +[[friends]] +title = "Similar Projects" +subtitle = """ +From Argentina to Germany. Syndication bots made by our counterparts. """ + +[[friends]] +name = "err-rssreader" +info = ["A port of old Brutal's RSS Reader for Errbot"] +url = "https://github.com/errbotters/err-rssreader" + +[[friends]] +name = "feed-to-muc" +info = [""" +An XMPP bot which posts to a MUC (groupchat) if there is an update in newsfeeds. +"""] +url = "https://salsa.debian.org/mdosch/feed-to-muc" + +[[friends]] +name = "JabRSS" +info = [""" +Never miss a headline again! JabRSS is a simple RSS (RDF Site Summary) \ +headline notification service for Jabber. +"""] +url = "http://www.jotwewe.de/de/xmpp/jabrss/jabrss_en.htm" + +[[friends]] +name = "Morbot" +info = [""" +Morbo is a simple Slixmpp bot that will take new articles from listed RSS \ +feeds and send them to assigned XMPP MUCs (groupchats). +"""] +url = "https://codeberg.org/TheCoffeMaker/Morbot" + +[[legal]] +title = "Legal" +subtitle = "Legal Notice" + +[[legal]] +info = [""" +Slixfeed is free software; you can redistribute it and/or modify it under the \ +terms of the MIT License. + +Slixfeed is distributed in the hope that it will be useful, but WITHOUT ANY \ +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR \ +A PARTICULAR PURPOSE. See the MIT License for more details. +"""] +link = "https://gitgud.io/sjehuda/slixfeed" + +[[license]] +title = "License" +subtitle = "MIT License" + +[[license]] +license = [""" Copyright 2022 - 2024 Schimon Zackary Jehudah -Permission is hereby granted, free of charge, to any person obtaining \ -a copy of this software and associated documentation files (the \ -“Software”), to deal in the Software without restriction, including \ -without limitation the rights to use, copy, modify, merge, publish, \ -distribute, sublicense, and/or sell copies of the Software, and to \ -permit persons to whom the Software is furnished to do so, subject to \ -the following conditions: +Permission is hereby granted, free of charge, to any person obtaining a copy \ +of this software and associated documentation files (the “Software”), to deal \ +in the Software without restriction, including without limitation the rights \ +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell \ +copies of the Software, and to permit persons to whom the Software is \ +furnished to do so, subject to the following conditions: -The above copyright notice and this permission notice shall be included \ -in all copies or substantial portions of the Software. +The above copyright notice and this permission notice shall be included in \ +all copies or substantial portions of the Software. -THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS \ -OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \ -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL \ -THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR \ -OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, \ -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER \ -DEALINGS IN THE SOFTWARE. -""" -] +THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR \ +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, \ +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE \ +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \ +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \ +FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS \ +IN THE SOFTWARE. +"""] +owner = "Schimon Zackary" -note = [ -""" -You can run Slixfeed as a client, from your own computer, server, \ -and even from a Linux phone (i.e. Droidian, Kupfer, Mobian, NixOS, \ -postmarketOS), and even from Termux. -All you need is one of the above and an XMPP account to connect \ -Slixfeed to. Good luck! -""" -] +[[support]] +title = "Support" +subtitle = "Slixfeed Support Groupchat" -operators = [ -""" -No operator was specified for this instance. -""" -] +[[support]] +jid = "xmpp:slixfeed@chat.woodpeckersnest.space?join" -platforms = [ +[[thanks]] +title = "Thanks" +subtitle = """ +From SalixOS to Gajim. A journey of 15 years. \ +The people who have made all this possible. """ -Supported platforms: XMPP -Platforms to be added in future: ActivityPub, Briar, Email, IRC, LXMF, \ -Matrix, MQTT, Nostr, Session, Tox. -For ideal experience, we recommend using XMPP. -""" -] -privacy = [ -""" +[[thanks]] +name = "Alixander Court" +country = "Utah" +url = "https://alixandercourt.com" + +[[thanks]] +name = "Arne-Brün Vogelsang" +country = "Germany" +project = "monocles" +url = "https://monocles.de" + +[[thanks]] +name = "Chris Farrell" +alias = "timcowchip" +country = "Oregon" +project = "SalixOS" + +[[thanks]] +name = "Christian Dersch" +alias = "christian" +project = "SalixOS" + +[[thanks]] +name = "Cyrille Pontvieux" +alias = "JRD" +country = "France" +project = "SalixOS" +url = "http://animeka.com http://enialis.net" +jabber = "xmpp:jrd@jabber.cz?message" + +[[thanks]] +name = "Denis Fomin" +alias = "Dicson" +country = "Russia" +project = "Gajim" +url = "https://juick.com/dicson" + +[[thanks]] +name = "Dimitris Tzemos" +alias = "djemos" +country = "Greece" +projects = "SalixOS, Slackel" +url = "http://slackel.gr" +jabber = "xmpp:djemos@jabber.org?message" + +[[thanks]] +name = "Emmanuel Gil Peyrot" +alias = "Link mauve" +country = "France" +projects = "Poezio, slixmpp" +jabber = "xmpp:linkmauve@linkmauve.fr?message" +url = "https://linkmauve.fr" + +[[thanks]] +name = "Florent Le Coz" +alias = "louiz" +country = "France" +projects = "Poezio, slixmpp" +jabber = "xmpp:louiz@louiz.org?message" +url = "https://louiz.org" + +[[thanks]] +name = "George Vlahavas" +alias = "gapan" +country = "Greece" +project = "SalixOS" +url = "https://salixos.org https://vlahavas.com" + +[[thanks]] +name = "Guus der Kinderen" +country = "Netherlands" +project = "Openfire" +url = "https://igniterealtime.org" + +[[thanks]] +name = "habnabit_" +alias = "habnabit_" +irc = "irc://irc.libera.chat/#python" + +[[thanks]] +name = "Imar van Erven Dorens" +country = "Netherlands" +project = "SalixOS" +url = "https://simplicit.nl" + +[[thanks]] +name = "imattau" +alias = "imattau" +project = "atomtopubsub" + +[[thanks]] +name = "Jaussoin Timothée" +alias = "edhelas" +country = "France" +projects = "atomtopubsub, Movim" +url = "https://mov.im" + +[[thanks]] +name = "Justin Karneges" +country = "California" +project = "Psi" +url = "https://jblog.andbit.net https://psi-im.org" + +[[thanks]] +name = "Kevin Smith" +alias = "Kev" +country = "Wales" +projects = "Psi, SleekXMPP, Swift IM" +url = "http://kismith.co.uk https://isode.com https://swift.im" + +[[thanks]] +name = "Lars Windolf" +alias = "lwindolf" +country = "Germany" +project = "Liferea" +url = "https://lzone.de" + +[[thanks]] +name = "Luis Henrique Mello" +alias = "lmello" +country = "Brazil" +project = "SalixOS" + +[[thanks]] +name = "magicfelix" +alias = "magicfelix" + +[[thanks]] +name = "Markus Muttilainen" +alias = "stillborn" +project = "SalixOS" + +[[thanks]] +name = "Martin" +alias = "debacle" +country = "Germany" +projects = "Debian, sms4you" +email = "mailto:debacle@debian.org" + +[[thanks]] +name = "Mathieu Pasquet" +alias = "mathieui" +country = "France" +project = "slixmpp" +jabber = "xmpp:mathieui@mathieui.net?message" +url = "https://blog.mathieui.net" + +[[thanks]] +name = "Maxime Buquet" +alias = "pep" +country = "France" +project = "slixmpp" +jabber = "xmpp:pep@bouah.net?message" +url = "https://bouah.net" + +[[thanks]] +name = "mirux" +alias = "mirux" +country = "Germany" + +[[thanks]] +name = "Phillip Watkins" +alias = "pwatk" +country = "England" +project = "SalixOS" + +[[thanks]] +name = "Pierrick Le Brun" +alias = "akuna" +country = "France" +project = "SalixOS" +url = "https://mossieur-ballon.com" + +[[thanks]] +name = "Raphael Groner" +alias = "rapgro" +country = "Germany" +project = "Fedora" + +[[thanks]] +name = "Remko Tronçon" +country = "Belgium" +projects = "Psi, SleekXMPP, Swift IM" +url = "http://el-tramo.be https://mko.re https://psi-im.org" + +[[thanks]] +name = "Richard Lapointe" +alias = "laprjns" +country = "Connecticut" +projects = "SalixOS, Zenwalk" + +[[thanks]] +name = "Simone Canaletti" +alias = "roughnecks" +country = "Italy" +url = "https://woodpeckersnest.space" + +[[thanks]] +name = "Stephen Paul Weber" +alias = "singpolyma" +projects = "Cheogram, JMP, Sopranica" +url = "https://singpolyma.net" + +[[thanks]] +name = "Strix from Loqi" +alias = "Strix" + +[[thanks]] +name = "Thibaud Guerin" +alias = "guth" +project = "SalixOS" + +[[thanks]] +name = "Thorsten Fröhlich" +country = "France" + +[[thanks]] +name = "Thorsten Mühlfelder" +alias = "thenktor" +country = "Germany" +project = "SalixOS" + +[[thanks]] +name = "Tim Beech" +alias = "mimosa" +country = "Brazil" +project = "SalixOS" +url = "https://apipucos.wordpress.com" + +[[thanks]] +name = "Tomoki Tsuchiya" +alias = "tsuren" +project = "SalixOS" + +[[thanks]] +name = "Yann Leboulanger" +alias = "asterix" +country = "France" +project = "Gajim" +jabber = "xmpp:asterix@jabber.lagaule.org?message" +url = "https://gajim.org" + +[[thanks]] +name = "#python (IRC Channel)" +irc = "irc://irc.libera.chat/#python" + +[[thanks]] +name = "The Salix Team" +about = [""" +Previously part of the Zenwalk team. + +The stubbornness of the Salix OS team members, and their determination to the \ +cause, no matter whether popular or else, you are the people who have lead \ +the creator of this software to the XMPP network. + +It may well be said, that without you, gentlemen, and without your kind \ +honesty, sincerity and even the arguments however difficult these arguments \ +were, Slixfeed would have never been existed today. + +All this from an XMPP groupchat that started out from 5 to 8 participants, \ +fifteen years ago (2009). + +Thank you. +"""] +irc = "irc://irc.libera.chat/#salix" +jabber = "xmpp:salix@chat.meticul.eu?join" +url = "https://docs.salixos.org/wiki/Salix_OS:Team" + +[[thanks]] +name = "The XMPP Community" +about = [""" +For over a couple of decades, the people of XMPP form a strong community \ +which strives to provide you and your loved ones, private, secure and \ +stable communication experience. + +While we are for private property and high standard of living, in the XMPP \ +realm we cooperate and we compete together to provide you with the best \ +communication platform in the world. + +With governments and intelligence agencies around the world making an \ +extensive - and sometimes exclusive - use of XMPP, you can be rest assured \ +that you can never be wrong by making XMPP your prime and premier choice \ +for communications. + +We are XMPP. +Join us! +"""] + +[[operators]] +title = "Operators" +subtitle = "Slixfeed Operators" + +[[operators]] +name = "Mr. Operator" +jid = "No operator was specified for this instance." + +[[policies]] +title = "Policies" +subtitle = "Terms of service" + +[[policies]] +name = "Terms and Conditions" +info = [""" +You are bound to these terms. +"""] + +[[policies]] +name = "Privacy Policy" +info = [""" All your data belongs to us. +"""] + +[[clients]] +title = "Recommended Clients" +subtitle = """ +As a chat bot, Slixfeed works with any XMPP messenger, yet we have deemed it \ +appropriate to list the software that work best with Slixfeed, namely those \ +that provide support for XEP-0050: Ad-Hoc Commands. """ -] -protocols = [ -""" -Supported protocols: HTTP -Protocols to be added in future: Dat, FTP, Gemini, Gopher, IPFS. -""" -] -# Supported protocols: Dat, FTP, Gemini, Gopher, HTTP and IPFS. +[[clients]] +name = "Cheogram" +info = "XMPP client for mobile" +url = "https://cheogram.com" -rtf = [ -""" -The RSS Task Force is an international organization headquartered in Switzerland. +# [[clients]] +# name = "Conversations" +# info = "XMPP client for mobile" +# url = "https://conversations.im" -It was originally formed to maintain, serve and improve data flow to and from \ -small and medium enterprises, namely rural farms and long distance taxi drivers. +[[clients]] +name = "Converse" +info = "XMPP client for desktop and mobile" +url = "https://conversejs.org" -Thanks to a joint effort of several taxi and travel companies, in 2021 we have \ -expanded our cause towards all entities of all types and sorts. +# [[clients]] +# name = "Gajim" +# info = "XMPP client for desktop" +# url = "https://gajim.org" -The RSS Task Force was founded in 2018. -""" -] +# [[clients]] +# name = "Monal IM" +# info = "XMPP client for desktop and mobile" +# url = "https://monal-im.org" -resources = [ -""" -Slixfeed -https://gitgud.io/sjehuda/slixfeed +[[clients]] +name = "monocles chat" +info = "XMPP client for mobile" +url = "https://monocles.eu" -Slixmpp -https://slixmpp.readthedocs.io/ +[[clients]] +name = "Movim" +info = "XMPP client for desktop and mobile" +url = "https://mov.im" -feedparser -https://pythonhosted.org/feedparser +# [[clients]] +# name = "Moxxy" +# info = "XMPP client for mobile" +# url = "https://moxxy.org" -XMPP -https://xmpp.org/about/ -""" -] +[[clients]] +name = "Psi" +info = "XMPP client for desktop" +url = "https://psi-im.org" -services = [ -""" -Feed Creator +[[clients]] +name = "Psi+" +info = "XMPP client for desktop" +url = "https://psi-plus.com" +# [[clients]] +# name = "Swift" +# info = "XMPP client for desktop" +# url = "https://swift.im" + +# [[clients]] +# name = "yaxim" +# info = "XMPP client for mobile" +# url = "https://yaxim.org" + +[[services]] +title = "Recommended News Services" +subtitle = [""" +Below are online services that extend the syndication experience by means \ +of bookmarking and multimedia, and also enhance it by restoring access to \ +news web feeds. +"""] + +[[services]] +name = "Feed Creator" +info = [""" Feed Creator is a service that creates feeds from HTML pages. \ It generates RSS and JSON feeds from a set of links or other HTML elements. +"""] +link = "https://www.fivefilters.org/feed-creator/" -https://www.fivefilters.org/feed-creator/ - - -Kill the Newsletter - -Kill the Newsletter converts email newsletters into Web feeds. - -https://kill-the-newsletter.com/ - - -Open RSS +[[services]] +name = "Kill the Newsletter" +info = "Kill the Newsletter converts email newsletters into Web feeds." +link = "https://kill-the-newsletter.com" +[[services]] +name = "Open RSS" +info = [""" Open RSS is a nonprofit organization that provides free RSS feeds for \ -websites and applications that don't already provide them, so RSS feeds \ -can continue to be a reliable way for people to stay up-to-date with \ -content anywhere on the internet. - -https://openrss.org/ - - -RSS-Bridge +websites and applications that don't already provide them, so RSS feeds can \ +continue to be a reliable way for people to stay up-to-date with content \ +anywhere on the internet. +"""] +link = "https://openrss.org" +[[services]] +name = "RSS-Bridge" +info = [""" RSS-Bridge is free and open source software for generating Atom or RSS \ feeds from websites which don’t have one. It is written in PHP and intended \ to run on a Web server. +"""] +link = "https://rss-bridge.org/bridge01/" -https://rss-bridge.org/bridge01/ - - -RSSHub - +[[services]] +name = "RSSHub" +info = [""" RSSHub is an open source, easy to use, and extensible RSS feed generator. \ It's capable of generating RSS feeds from pretty much everything. +"""] +link = "https://docs.rsshub.app" -https://docs.rsshub.app/ -""" -] +[[software]] +title = "Recommended News Software" +subtitle = [""" +Take back control of your news. With free, quality, software for your \ +desktop, home and mobile devices. +"""] -sleekxmpp = [ -""" -SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+, and is featured \ -in examples in the book XMPP: The Definitive Guide by Kevin Smith, Remko Tronçon, \ -and Peter Saint-Andre. +[[software]] +name = "CommaFeed" +info = [""" +A self-hosted RSS reader, based on Dropwizard and React/TypeScript. +"""] +link = "https://commafeed.com" +os = "Any (HTML)" -https://codeberg.org/fritzy/SleekXMPP -""" -] +[[software]] +name = "FreshRSS" +info = [""" +FreshRSS is a self-hosted RSS and Atom feed aggregator. +It is lightweight, easy to work with, powerful, and customizable. +"""] +link = "https://freshrss.org" +os = "Any (HTML)" -slixmpp = [ -""" -Slixmpp is an MIT licensed XMPP library for Python 3.7+. It is a fork of SleekXMPP. +[[software]] +name = "Liferea" +info = [""" +Liferea is a feed reader/news aggregator that brings together all of the \ +content from your favorite subscriptions into a simple interface that makes \ +it easy to organize and browse feeds. Its GUI is similar to a desktop \ +mail/news client, with an embedded web browser. +"""] +link = "https://lzone.de/liferea/" +os = "FreeBSD and Linux" + +[[software]] +name = "NetNewsWire" +info = [""" +NetNewsWire shows you articles from your favorite blogs and news sites and \ +keeps track of what you’ve read. + +This means you can stop going from page to page in your browser looking for \ +new articles to read. Do it the easy way instead: let NetNewsWire bring you \ +the news. + +And, if you’ve been getting your news via the commercial Social Networks — \ +with their ads, algorithms, user tracking, outrage, and misinformation — you \ +can switch to NetNewsWire to get news directly and more reliably from the \ +sites you trust. +"""] +link = "https://netnewswire.com" +os = "MacOS" + +[[software]] +name = "Newsboat" +info = [""" +Newsboat is an RSS/Atom feed reader for the text console. It’s an actively \ +maintained fork of Newsbeuter +"""] +link = "https://newsboat.org" +os = "Any" + +[[software]] +name = "Spot-On" +info = [""" +Spot-On is a software carnival which brings chat, email, news, newsgroups, \ +search and other forms of communications into a single communications \ +orchestra. +"""] +link = "https://textbrowser.github.io/spot-on/" +os = "Any" + +[[software]] +name = "Vienna RSS" +info = [""" +Vienna is an RSS/Atom reader for macOS, packed with powerful features that \ +help you make sense of the flood of information that is distributed via \ +these formats today. +"""] +link = "https://vienna-rss.com" +os = "MacOS" + +[[resources]] +title = "Useful Resources" +subtitle = "Technologies which Slixfeed is based upon" + +[[resources]] +name = "feedparser" +info = "Syndication Library" +url = "https://pythonhosted.org/feedparser" + +[[resources]] +name = "Slixmpp" +info = "XMPP Library" +url = "https://slixmpp.readthedocs.io" + +[[resources]] +name = "XMPP" +info = "Messaging Protocol" +url = "https://xmpp.org/about" + +[[rss_task_force]] +title = "About RSS Task Force" +subtitle = "Swiss Organization" + +[[rss_task_force]] +info = [""" +The RSS Task Force (previously known as The Syndication Society) is an \ +international organization headquartered in Switzerland. + +It was originally formed to maintain, serve and improve data flow to and \ +from small and medium enterprises, namely rural farms and long distance \ +taxi drivers from Austria, Germany, Italy and Switzerland. + +Thanks to a joint effort of transport and travel companies, in 2021 we have \ +expanded our cause towards all entities of all types and sorts. + +The RSS Task Force was founded by two taxicab drivers in 2018. +"""] + +[[sleekxmpp]] +title = "About Project SleekXMPP" +subtitle = "SleekXMPP XMPP Library" + +[[sleekxmpp]] +info = [""" +SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+, and is \ +featured in examples in the book XMPP: The Definitive Guide by Kevin Smith, \ +Remko Tronçon, and Peter Saint-Andre. +"""] +url = "https://codeberg.org/fritzy/SleekXMPP" + +[[slixmpp]] +title = "About Project Slixmpp" +subtitle = "Slixmpp XMPP Library" + +[[slixmpp]] +info = [""" +Slixmpp is an MIT licensed XMPP library for Python 3.7+. It is a fork of \ +SleekXMPP. Slixmpp's goals is to only rewrite the core of the SleekXMPP library \ (the low level socket handling, the timers, the events dispatching) \ in order to remove all threads. +"""] +url = "https://codeberg.org/poezio/slixmpp" -https://codeberg.org/poezio/slixmpp -""" -] +[[xmpp]] +title = "About XMPP" +subtitle = "Previously known as Jabber" -software = [ -""" -Canto - -Canto is an Atom/RSS feed reader for the console that is meant to \ -be quick, concise, and colorful. It’s meant to provide a minimal, yet \ -information packed interface. No navigating menus. No dense blocks of \ -unreadable white text. An interface with almost infinite customization \ -and extensibility using the excellent Python programming language. - -https://codezen.org/canto-ng/ - - -CommaFeed - -A self-hosted RSS reader, based on Dropwizard and React/TypeScript. - -https://commafeed.com/ - - -FreshRSS - -FreshRSS is a self-hosted RSS and Atom feed aggregator. -It is lightweight, easy to work with, powerful, and customizable. - -https://freshrss.org/ - - -Liferea - -Liferea is a feed reader/news aggregator that brings together \ -all of the content from your favorite subscriptions into a simple \ -interface that makes it easy to organize and browse feeds. Its \ -GUI is similar to a desktop mail/news client, with an embedded \ -web browser. - -https://lzone.de/liferea/ - - -NetNewsWire - -NetNewsWire shows you articles from your favorite blogs and news \ -sites and keeps track of what you’ve read. - -This means you can stop going from page to page in your browser \ -looking for new articles to read. Do it the easy way instead: let \ -NetNewsWire bring you the news. - -And, if you’ve been getting your news via the commercial Social \ -Networks — with their ads, algorithms, user tracking, outrage, and \ -misinformation — you can switch to NetNewsWire to get news directly \ -and more reliably from the sites you trust. - -https://netnewswire.com/ - - -QuiteRSS - -QuiteRSS is a free and convenient program for reading RSS/Atom news \ -feeds. - -http://quiterss.org/ - - -Raven Reader - -Raven is a open source desktop news reader with flexible settings to \ -optimize your experience. No login is required, and no personal data \ -is collected. Just select the websites you want to curate articles \ -from and enjoy! - -https://ravenreader.app/ - - -Spot-On - -Spot-On is a software carnival which brings chat, email, news, \ -newsgroups, search and other forms of communications into a single \ -communications orchestra. - -https://textbrowser.github.io/spot-on/ - - -Vienna RSS - -Vienna is an RSS/Atom reader for macOS, packed with powerful \ -features that help you make sense of the flood of information \ -that is distributed via these formats today. - -https://vienna-rss.com/ - - -""" -] - -support = [ -""" -xmpp:slixfeed@chat.woodpeckersnest.space?join -""" -] - -terms = [ -""" -Slixfeed is free software; you can redistribute it and/or \ -modify it under the terms of the MIT License. - -Slixfeed is distributed in the hope that it will be useful, \ -but WITHOUT ANY WARRANTY; without even the implied warranty of \ -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the \ -MIT License for more details. - -https://gitgud.io/sjehuda/slixfeed -""" -] - -thanks = [ - "Alixander Court <alixandercourt.com> (Utah), ", - "Arne-Brün Vogelsang <monocles.de> (monocles, Germany), ", - "Chriss Farrell (SalixOS, Oregon), ", - "Christian Dersch (SalixOS), ", - "Cyrille Pontvieux <enialis.net> (SalixOS, France), ", - "Denis Fomin (Gajim, Russia), ", - "Dimitris Tzemos (SalixOS, Greece), ", - "Emmanuel Gil Peyrot (Poezio, France), ", - "Florent Le Coz (Poezio, France), ", - "George Vlahavas <vlahavas.com> (SalixOS, Greece), ", - "Guus der Kinderen <igniterealtime.org> (Openfire, Netherlands), ", - "habnabit_ from #python on irc.libera.chat, ", - "Imar van Erven Dorens <simplicit.nl> (SalixOS, Netherlands), ", - "imattau (atomtopubsub), ", - "Jaussoin Timothée <mov.im> (Movim, France), ", - "Justin Karneges <jblog.andbit.net> (Psi, California), ", - "Kevin Smith <isode.com> (Swift IM, Wales), ", - "Lars Windolf (Liferea, Germany), ", - "Luis Henrique Mello (SalixOS, Brazil), ", - "magicfelix, ", - "Markus Muttilainen (SalixOS), ", - "Martin <debacle@debian.org> (Debian, Germany), ", - "Mathieu Pasquet (slixmpp, France), ", - "Maxime Buquet (slixmpp, France), ", - "mirux (Germany), ", - "Phillip Watkins (SalixOS, United Kingdom), ", - "Pierrick Le Brun (SalixOS, France), ", - "Raphael Groner (Fedora, Germany), ", - "Remko Tronçon <mko.re> (Psi , Belgium), ", - "Simone "roughnecks" Canaletti <woodpeckersnest.space> (Italy), ", - "Richard Lapointe (SalixOS, Connecticut), ", - "Stephen Paul Weber <singpolyma.net>, ", - "Strix from Loqi, ", - "Thibaud Guerin (SalixOS), ", - "Thorsten Fröhlich (France), ", - "Thorsten Mühlfelder (SalixOS, Germany), ", - "Tim Beech (SalixOS, Brazil), ", - "Yann Leboulanger (Gajim, France)" -] - -xmpp = [ -""" -XMPP is the Extensible Messaging and Presence Protocol, a set \ -of open technologies for instant messaging, presence, multi-party \ -chat, voice and video calls, collaboration, lightweight \ -middleware, content syndication, and generalized routing of XML \ -data. - -https://xmpp.org/about/ -""" -] +[[xmpp]] +info = [""" +XMPP is the Extensible Messaging and Presence Protocol, a set of open \ +technologies for instant messaging, presence, multi-party chat, voice and \ +video calls, collaboration, lightweight middleware, content syndication, and \ +generalized routing of XML data. +"""] +link = "https://xmpp.org/about" diff --git a/slixfeed/config.py b/slixfeed/config.py index e7ac7ae..3d79a99 100644 --- a/slixfeed/config.py +++ b/slixfeed/config.py @@ -80,6 +80,14 @@ class Config: else: await sqlite.set_setting_value(db_file, key_val) + def get_setting_value(settings, jid_bare, key): + if key in settings[jid_bare]: + value = settings[jid_bare][key] + else: + value = settings['default'][key] + return value + + # self.settings = {} # initiate an empty dict and the rest would be: # settings['account'] = {} diff --git a/slixfeed/version.py b/slixfeed/version.py index 67586a2..f5f6007 100644 --- a/slixfeed/version.py +++ b/slixfeed/version.py @@ -1,2 +1,2 @@ -__version__ = '0.1.34' -__version_info__ = (0, 1, 34) +__version__ = '0.1.35' +__version_info__ = (0, 1, 35) diff --git a/slixfeed/xmpp/client.py b/slixfeed/xmpp/client.py index 36817c2..9ae511f 100644 --- a/slixfeed/xmpp/client.py +++ b/slixfeed/xmpp/client.py @@ -59,6 +59,11 @@ from slixfeed.xmpp.utility import get_chat_type import sys import time +try: + import tomllib +except: + import tomli as tomllib + import asyncio from datetime import datetime import logging @@ -2072,18 +2077,13 @@ class Slixfeed(slixmpp.ClientXMPP): ftype='list-single', label='About', required=True) - options.addOption('Slixfeed', 'about') - options.addOption('RSS Task Force', 'rtf') - # options.addOption('Manual', 'manual') - options.addOption('Tips', 'tips') - options.addOption('Services for syndication', 'services') - options.addOption('Software for syndication', 'software') - options.addOption('Terms and conditions', 'terms') - options.addOption('Privacy policy', 'policy') - options.addOption('License', 'license') - options.addOption('Authors', 'author') - options.addOption('Translators', 'translators') - options.addOption('Thanks', 'thanks') + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + for entry in entries: + label = entries[entry][0]['title'] + options.addOption(label, entry) + # options.addOption('Tips', 'tips') session['payload'] = form session['next'] = self._handle_about_result session['has_next'] = True @@ -2095,71 +2095,49 @@ class Slixfeed(slixmpp.ClientXMPP): function_name = sys._getframe().f_code.co_name logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - match payload['values']['option']: - case 'about': - title = 'About' - subtitle = 'Slixfeed {}\n\n'.format(__version__) - content = action.manual('information.toml', 'about') - content += ['\nslixmpp\n'] - content += action.manual('information.toml', 'slixmpp') - content += ['\nSleekXMPP\n'] - content += action.manual('information.toml', 'sleekxmpp') - content += ['\nXMPP\n'] - content += action.manual('information.toml', 'xmpp') - case 'rtf': - title = 'About' - subtitle = 'RSS Task Force' - content = action.manual('information.toml', 'rtf') - case 'author': - title = 'Authors' - subtitle = 'The People Who Made This To Happen' - content = action.manual('information.toml', 'authors') - # case 'manual': - # title = 'Manual' - # subtitle = 'Slixfeed Manual' - # content = action.manual('information.toml', 'manual') - case 'license': - title = 'License' - subtitle = 'Slixfeed Software License' - content = action.manual('information.toml', 'license') - case 'policy': - title = 'Policies' - subtitle = 'Privacy Policy' - content = action.manual('information.toml', 'privacy') - case 'services': - title = 'Services' - subtitle = ('Below are online services that extend the ' - 'syndication experience by means of bookmarking ' - 'and multimedia, and also enhance it by restoring ' - 'access to news web feeds.') - content = action.manual('information.toml', 'services') - case 'software': - title = 'Software' - subtitle = ('Take back control of your news. With free, high-' - 'quality, software for your desktop, home and ' - 'mobile devices.') - content = action.manual('information.toml', 'software') - case 'terms': - title = 'Policies' - subtitle = 'Terms and Conditions' - content = action.manual('information.toml', 'terms') - case 'thanks': - title = 'Thanks' - subtitle = 'We are XMPP' - content = action.manual('information.toml', 'thanks') - case 'tips': - # Tips and tricks you might have not known about Slixfeed and XMPP! - title = 'Help' - subtitle = 'Tips & Tricks' - content = 'This page is not yet available.' - case 'translators': - title = 'Translators' - subtitle = 'From all across the world' - content = action.manual('information.toml', 'translators') - form = self['xep_0004'].make_form('result', title) - form['instructions'] = subtitle - form.add_field(ftype="text-multi", - value=content) + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + entry_key = payload['values']['option'] + # case 'terms': + # title = 'Policies' + # subtitle = 'Terms and Conditions' + # content = action.manual('information.toml', 'terms') + # case 'tips': + # # Tips and tricks you might have not known about Slixfeed and XMPP! + # title = 'Help' + # subtitle = 'Tips & Tricks' + # content = 'This page is not yet available.' + # case 'translators': + # title = 'Translators' + # subtitle = 'From all across the world' + # content = action.manual('information.toml', 'translators') + # title = entry_key.capitalize() + # form = self['xep_0004'].make_form('result', title) + for entry in entries[entry_key]: + if 'title' in entry: + title = entry['title'] + form = self['xep_0004'].make_form('result', title) + subtitle = entry['subtitle'] + form['instructions'] = subtitle + continue + for e_key in entry: + e_val = entry[e_key] + e_key = e_key.capitalize() + # form.add_field(ftype='fixed', + # value=e_val) + print(type(e_val)) + if e_key == 'Name': + form.add_field(ftype='fixed', + value=e_val) + continue + if isinstance(e_val, list): + form_type = 'text-multi' + else: + form_type = 'text-single' + form.add_field(label=e_key, + ftype=form_type, + value=e_val) # Gajim displays all form['instructions'] on top # Psi ignore the latter form['instructions'] # form['instructions'] = 'YOU!\n🫵️\n- Join us -' @@ -2192,7 +2170,6 @@ class Slixfeed(slixmpp.ClientXMPP): logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - import tomllib config_dir = config.get_default_config_directory() with open(config_dir + '/' + 'commands.toml', mode="rb") as commands: cmds = tomllib.load(commands) diff --git a/slixfeed/xmpp/command.py b/slixfeed/xmpp/command.py index dd7f693..2f94950 100644 --- a/slixfeed/xmpp/command.py +++ b/slixfeed/xmpp/command.py @@ -333,7 +333,7 @@ class XmppCommand: options.addOption('All news', 'all') # options.addOption('News by subscription', 'feed') # options.addOption('News by tag', 'tag') - options.addOption('Rejected news', 'rejected') + options.addOption('Rejected news', 'reject') options.addOption('Unread news', 'unread') session['allow_prev'] = False # Cheogram changes style if that button - which should not be on this form - is present session['has_next'] = True @@ -354,14 +354,20 @@ class XmppCommand: num = 100 match payload['values']['action']: case 'all': - results = sqlite.get_entries(db_file, num) # FIXME - case 'rejected': - results = sqlite.get_entries_rejected(db_file, num) # FIXME + results = sqlite.get_entries(db_file, num) + subtitle = 'Recent {} updates'.format(num) + message = 'There are no news' + case 'reject': + results = sqlite.get_entries_rejected(db_file, num) + subtitle = 'Recent {} updates (rejected)'.format(num) + message = 'There are no rejected news' case 'unread': results = sqlite.get_unread_entries(db_file, num) + subtitle = 'Recent {} updates (unread)'.format(num) + message = 'There are no unread news.' if results: form = self['xep_0004'].make_form('form', 'Updates') - form['instructions'] = 'Recent {} updates'.format(num) + form['instructions'] = subtitle options = form.add_field(var='update', ftype='list-single', label='News', @@ -377,8 +383,13 @@ class XmppCommand: session['payload'] = form session['prev'] = None # Cheogram works as expected with 'allow_prev' set to False Just in case else: - text_info = 'There are no unread news.' + text_info = message + session['allow_prev'] = True + session['has_next'] = False + session['next'] = None session['notes'] = [['info', text_info]] + session['payload'] = None + session['prev'] = self._handle_recent return session @@ -520,7 +531,7 @@ class XmppCommand: error_count = 0 exist_count = 0 for url in urls: - result = await action.add_feed(db_file, url) + result = await action.add_feed(self, jid_bare, db_file, url) if result['error']: error_count += 1 elif result['exist']: @@ -544,7 +555,7 @@ class XmppCommand: else: if isinstance(url, list): url = url[0] - result = await action.add_feed(db_file, url) + result = await action.add_feed(self, jid_bare, db_file, url) if isinstance(result, list): results = result form = self['xep_0004'].make_form('form', 'Subscriptions') @@ -1435,18 +1446,13 @@ class XmppCommand: ftype='list-single', label='About', required=True) - options.addOption('Slixfeed', 'about') - options.addOption('RSS Task Force', 'rtf') - # options.addOption('Manual', 'manual') - options.addOption('Tips', 'tips') - options.addOption('Services for syndication', 'services') - options.addOption('Software for syndication', 'software') - options.addOption('Terms and conditions', 'terms') - options.addOption('Privacy policy', 'policy') - options.addOption('License', 'license') - options.addOption('Authors', 'author') - options.addOption('Translators', 'translators') - options.addOption('Thanks', 'thanks') + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + for entry in entries: + label = entries[entry][0]['title'] + options.addOption(label, entry) + # options.addOption('Tips', 'tips') session['payload'] = form session['next'] = self._handle_about_result session['has_next'] = True @@ -1458,71 +1464,49 @@ class XmppCommand: function_name = sys._getframe().f_code.co_name logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - match payload['values']['option']: - case 'about': - title = 'About' - subtitle = 'Slixfeed {}\n\n'.format(__version__) - content = action.manual('information.toml', 'about') - content += ['\nslixmpp\n'] - content += action.manual('information.toml', 'slixmpp') - content += ['\nSleekXMPP\n'] - content += action.manual('information.toml', 'sleekxmpp') - content += ['\nXMPP\n'] - content += action.manual('information.toml', 'xmpp') - case 'rtf': - title = 'About' - subtitle = 'RSS Task Force' - content = action.manual('information.toml', 'rtf') - case 'author': - title = 'Authors' - subtitle = 'The People Who Made This To Happen' - content = action.manual('information.toml', 'authors') - # case 'manual': - # title = 'Manual' - # subtitle = 'Slixfeed Manual' - # content = action.manual('information.toml', 'manual') - case 'license': - title = 'License' - subtitle = 'Slixfeed Software License' - content = action.manual('information.toml', 'license') - case 'policy': - title = 'Policies' - subtitle = 'Privacy Policy' - content = action.manual('information.toml', 'privacy') - case 'services': - title = 'Services' - subtitle = ('Below are online services that extend the ' - 'syndication experience by means of bookmarking ' - 'and multimedia, and also enhance it by restoring ' - 'access to news web feeds.') - content = action.manual('information.toml', 'services') - case 'software': - title = 'Software' - subtitle = ('Take back control of your news. With free, high-' - 'quality, software for your desktop, home and ' - 'mobile devices.') - content = action.manual('information.toml', 'software') - case 'terms': - title = 'Policies' - subtitle = 'Terms and Conditions' - content = action.manual('information.toml', 'terms') - case 'thanks': - title = 'Thanks' - subtitle = 'We are XMPP' - content = action.manual('information.toml', 'thanks') - case 'tips': - # Tips and tricks you might have not known about Slixfeed and XMPP! - title = 'Help' - subtitle = 'Tips & Tricks' - content = 'This page is not yet available.' - case 'translators': - title = 'Translators' - subtitle = 'From all across the world' - content = action.manual('information.toml', 'translators') - form = self['xep_0004'].make_form('result', title) - form['instructions'] = subtitle - form.add_field(ftype="text-multi", - value=content) + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + entry_key = payload['values']['option'] + # case 'terms': + # title = 'Policies' + # subtitle = 'Terms and Conditions' + # content = action.manual('information.toml', 'terms') + # case 'tips': + # # Tips and tricks you might have not known about Slixfeed and XMPP! + # title = 'Help' + # subtitle = 'Tips & Tricks' + # content = 'This page is not yet available.' + # case 'translators': + # title = 'Translators' + # subtitle = 'From all across the world' + # content = action.manual('information.toml', 'translators') + # title = entry_key.capitalize() + # form = self['xep_0004'].make_form('result', title) + for entry in entries[entry_key]: + if 'title' in entry: + title = entry['title'] + form = self['xep_0004'].make_form('result', title) + subtitle = entry['subtitle'] + form['instructions'] = subtitle + continue + for e_key in entry: + e_val = entry[e_key] + e_key = e_key.capitalize() + # form.add_field(ftype='fixed', + # value=e_val) + print(type(e_val)) + if e_key == 'Name': + form.add_field(ftype='fixed', + value=e_val) + continue + if isinstance(e_val, list): + form_type = 'text-multi' + else: + form_type = 'text-single' + form.add_field(label=e_key, + ftype=form_type, + value=e_val) # Gajim displays all form['instructions'] on top # Psi ignore the latter form['instructions'] # form['instructions'] = 'YOU!\n🫵️\n- Join us -' @@ -1555,7 +1539,6 @@ class XmppCommand: logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - import tomllib config_dir = config.get_default_config_directory() with open(config_dir + '/' + 'commands.toml', mode="rb") as commands: cmds = tomllib.load(commands) @@ -2127,7 +2110,6 @@ class XmppCommand: i += 1 value = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum'] value = str(value) - value = str(value) options = form.add_field(var='quantum', ftype='list-single', label='Amount', @@ -2142,7 +2124,6 @@ class XmppCommand: i += 1 value = self.settings[jid_bare]['archive'] or self.settings['default']['archive'] value = str(value) - value = str(value) options = form.add_field(var='archive', ftype='list-single', label='Archive', @@ -2170,7 +2151,7 @@ class XmppCommand: jid_full = str(session['from']) function_name = sys._getframe().f_code.co_name logger.debug('{}: jid_full: {}' - .format(function_name, jid_full)) + .format(function_name, jid_full)) jid_bare = session['from'].bare form = payload jid_file = jid_bare @@ -2183,14 +2164,23 @@ class XmppCommand: key = value val = values[value] - if key == 'interval': + if key in ('enabled', 'media', 'old'): + if val == True: + val = 1 + elif val == False: + val = 0 + + if key in ('archive', 'interval', 'quantum'): val = int(val) + + if key == 'interval': if val < 1: val = 1 val = val * 60 is_enabled = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled'] - if (key == 'enabled' and val == 1 and + if (key == 'enabled' and + val == 1 and str(is_enabled) == 0): logger.info('Slixfeed has been enabled for {}'.format(jid_bare)) status_type = 'available' @@ -2201,7 +2191,8 @@ class XmppCommand: key_list = ['check', 'status', 'interval'] await task.start_tasks_xmpp(self, jid_bare, key_list) - if (key == 'enabled' and val == 0 and + if (key == 'enabled' and + val == 0 and str(is_enabled) == 1): logger.info('Slixfeed has been disabled for {}'.format(jid_bare)) key_list = ['interval', 'status'] @@ -2211,10 +2202,8 @@ class XmppCommand: XmppPresence.send(self, jid_bare, status_message, status_type=status_type) - # These three ilnes (getting value after setting it) might be removed - await config.set_setting_value(db_file, key, val) - val = sqlite.get_setting_value(db_file, key) - val = val[0] + await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + val = self.settings[jid_bare][key] # if key == 'enabled': # if str(setting.enabled) == 0: diff --git a/slixfeed/xmpp/component.py b/slixfeed/xmpp/component.py index ead6bba..dfdab5b 100644 --- a/slixfeed/xmpp/component.py +++ b/slixfeed/xmpp/component.py @@ -31,6 +31,7 @@ import slixfeed.task as task # from lxml import etree import slixfeed.config as config +from slixfeed.config import Config from slixfeed.log import Logger from slixfeed.version import __version__ from slixfeed.xmpp.connect import XmppConnect @@ -49,6 +50,11 @@ from slixfeed.xmpp.utility import get_chat_type import sys import time +try: + import tomllib +except: + import tomli as tomllib + import asyncio from datetime import datetime import logging @@ -918,7 +924,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): options.addOption('All news', 'all') # options.addOption('News by subscription', 'feed') # options.addOption('News by tag', 'tag') - options.addOption('Rejected news', 'rejected') + options.addOption('Rejected news', 'reject') options.addOption('Unread news', 'unread') session['allow_prev'] = False # Cheogram changes style if that button - which should not be on this form - is present session['has_next'] = True @@ -939,14 +945,20 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): num = 100 match payload['values']['action']: case 'all': - results = sqlite.get_entries(db_file, num) # FIXME - case 'rejected': - results = sqlite.get_entries_rejected(db_file, num) # FIXME + results = sqlite.get_entries(db_file, num) + subtitle = 'Recent {} updates'.format(num) + message = 'There are no news' + case 'reject': + results = sqlite.get_entries_rejected(db_file, num) + subtitle = 'Recent {} updates (rejected)'.format(num) + message = 'There are no rejected news' case 'unread': results = sqlite.get_unread_entries(db_file, num) + subtitle = 'Recent {} updates (unread)'.format(num) + message = 'There are no unread news.' if results: form = self['xep_0004'].make_form('form', 'Updates') - form['instructions'] = 'Recent {} updates'.format(num) + form['instructions'] = subtitle options = form.add_field(var='update', ftype='list-single', label='News', @@ -962,8 +974,13 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): session['payload'] = form session['prev'] = None # Cheogram works as expected with 'allow_prev' set to False Just in case else: - text_info = 'There are no unread news.' + text_info = message + session['allow_prev'] = True + session['has_next'] = False + session['next'] = None session['notes'] = [['info', text_info]] + session['payload'] = None + session['prev'] = self._handle_recent return session @@ -2020,18 +2037,13 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): ftype='list-single', label='About', required=True) - options.addOption('Slixfeed', 'about') - options.addOption('RSS Task Force', 'rtf') - # options.addOption('Manual', 'manual') - options.addOption('Tips', 'tips') - options.addOption('Services for syndication', 'services') - options.addOption('Software for syndication', 'software') - options.addOption('Terms and conditions', 'terms') - options.addOption('Privacy policy', 'policy') - options.addOption('License', 'license') - options.addOption('Authors', 'author') - options.addOption('Translators', 'translators') - options.addOption('Thanks', 'thanks') + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + for entry in entries: + label = entries[entry][0]['title'] + options.addOption(label, entry) + # options.addOption('Tips', 'tips') session['payload'] = form session['next'] = self._handle_about_result session['has_next'] = True @@ -2043,71 +2055,49 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): function_name = sys._getframe().f_code.co_name logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - match payload['values']['option']: - case 'about': - title = 'About' - subtitle = 'Slixfeed {}\n\n'.format(__version__) - content = action.manual('information.toml', 'about') - content += ['\nslixmpp\n'] - content += action.manual('information.toml', 'slixmpp') - content += ['\nSleekXMPP\n'] - content += action.manual('information.toml', 'sleekxmpp') - content += ['\nXMPP\n'] - content += action.manual('information.toml', 'xmpp') - case 'rtf': - title = 'About' - subtitle = 'RSS Task Force' - content = action.manual('information.toml', 'rtf') - case 'author': - title = 'Authors' - subtitle = 'The People Who Made This To Happen' - content = action.manual('information.toml', 'authors') - # case 'manual': - # title = 'Manual' - # subtitle = 'Slixfeed Manual' - # content = action.manual('information.toml', 'manual') - case 'license': - title = 'License' - subtitle = 'Slixfeed Software License' - content = action.manual('information.toml', 'license') - case 'policy': - title = 'Policies' - subtitle = 'Privacy Policy' - content = action.manual('information.toml', 'privacy') - case 'services': - title = 'Services' - subtitle = ('Below are online services that extend the ' - 'syndication experience by means of bookmarking ' - 'and multimedia, and also enhance it by restoring ' - 'access to news web feeds.') - content = action.manual('information.toml', 'services') - case 'software': - title = 'Software' - subtitle = ('Take back control of your news. With free, high-' - 'quality, software for your desktop, home and ' - 'mobile devices.') - content = action.manual('information.toml', 'software') - case 'terms': - title = 'Policies' - subtitle = 'Terms and Conditions' - content = action.manual('information.toml', 'terms') - case 'thanks': - title = 'Thanks' - subtitle = 'We are XMPP' - content = action.manual('information.toml', 'thanks') - case 'tips': - # Tips and tricks you might have not known about Slixfeed and XMPP! - title = 'Help' - subtitle = 'Tips & Tricks' - content = 'This page is not yet available.' - case 'translators': - title = 'Translators' - subtitle = 'From all across the world' - content = action.manual('information.toml', 'translators') - form = self['xep_0004'].make_form('result', title) - form['instructions'] = subtitle - form.add_field(ftype="text-multi", - value=content) + config_dir = config.get_default_config_directory() + with open(config_dir + '/' + 'information.toml', mode="rb") as information: + entries = tomllib.load(information) + entry_key = payload['values']['option'] + # case 'terms': + # title = 'Policies' + # subtitle = 'Terms and Conditions' + # content = action.manual('information.toml', 'terms') + # case 'tips': + # # Tips and tricks you might have not known about Slixfeed and XMPP! + # title = 'Help' + # subtitle = 'Tips & Tricks' + # content = 'This page is not yet available.' + # case 'translators': + # title = 'Translators' + # subtitle = 'From all across the world' + # content = action.manual('information.toml', 'translators') + # title = entry_key.capitalize() + # form = self['xep_0004'].make_form('result', title) + for entry in entries[entry_key]: + if 'title' in entry: + title = entry['title'] + form = self['xep_0004'].make_form('result', title) + subtitle = entry['subtitle'] + form['instructions'] = subtitle + continue + for e_key in entry: + e_val = entry[e_key] + e_key = e_key.capitalize() + # form.add_field(ftype='fixed', + # value=e_val) + print(type(e_val)) + if e_key == 'Name': + form.add_field(ftype='fixed', + value=e_val) + continue + if isinstance(e_val, list): + form_type = 'text-multi' + else: + form_type = 'text-single' + form.add_field(label=e_key, + ftype=form_type, + value=e_val) # Gajim displays all form['instructions'] on top # Psi ignore the latter form['instructions'] # form['instructions'] = 'YOU!\n🫵️\n- Join us -' @@ -2140,7 +2130,6 @@ class SlixfeedComponent(slixmpp.ComponentXMPP): logger.debug('{}: jid_full: {}' .format(function_name, jid_full)) - import tomllib config_dir = config.get_default_config_directory() with open(config_dir + '/' + 'commands.toml', mode="rb") as commands: cmds = tomllib.load(commands) diff --git a/slixfeed/xmpp/process.py b/slixfeed/xmpp/process.py index ac6e1d8..0709067 100644 --- a/slixfeed/xmpp/process.py +++ b/slixfeed/xmpp/process.py @@ -307,8 +307,10 @@ async def message(self, message): await sqlite.insert_feed(db_file, url, title) await action.scan(self, jid_bare, db_file, url) if jid_bare not in self.settings: - Config.add_settings_jid(self.settings, jid_bare, db_file) - old = self.settings[jid_bare]['old'] or self.settings['default']['old'] + Config.add_settings_jid(self.settings, jid_bare, + db_file) + old = Config.get_setting_value(self.settings, jid_bare, + 'old') if old: # task.clean_tasks_xmpp(self, jid_bare, ['status']) # await send_status(jid) @@ -382,14 +384,18 @@ async def message(self, message): val = message_text[8:] if val: try: - if int(val) > 500: + val_new = int(val) + if val_new > 500: response = 'Value may not be greater than 500.' else: + val_old = Config.get_setting_value( + self.settings, jid_bare, key) db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value( + self.settings, jid_bare, db_file, key, val_new) response = ('Maximum archived items has ' - 'been set to {}.' - .format(val)) + 'been set to {} (was: {}).' + .format(val_new, val_old)) except: response = ('No action has been taken.' '\n' @@ -581,12 +587,11 @@ async def message(self, message): if error: response = ('> {}\n' 'Failed to export {}. ' - 'Reason: {}'.format(url, - ext.upper(), - error)) + 'Reason: {}'.format( + url, ext.upper(), error)) else: - url = await XmppUpload.start(self, jid_bare, - filename) + url = await XmppUpload.start( + self, jid_bare, filename) chat_type = await get_chat_type(self, jid_bare) XmppMessage.send_oob(self, jid_bare, url, @@ -661,8 +666,8 @@ async def message(self, message): result['name'], result['index'])) elif result['error']: - response = ('> {}\nFailed to find subscriptions. Reason: {}' - .format(url, result['code'])) + response = ('> {}\nFailed to find subscriptions. ' + 'Reason: {}'.format(url, result['code'])) else: response = ('> {}\nNews source "{}" has been ' 'added to subscription list.' @@ -702,15 +707,17 @@ async def message(self, message): val = message_text[9:] if val: try: - val = int(val) + val_new = int(val) + val_old = Config.get_setting_value(self.settings, jid_bare, key) db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value( + self.settings, jid_bare, db_file, key, val_new) # NOTE Perhaps this should be replaced by functions # clean and start task.refresh_task(self, jid_bare, task.task_send, key, - val) - response = ('Updates will be sent every {} minutes.' - .format(val)) + val_new) + response = ('Updates will be sent every {} minutes ' + '(was: {}).'.format(val_new, val_old)) except: response = ('No action has been taken.' '\n' @@ -736,15 +743,19 @@ async def message(self, message): val = message_text[7:] if val: try: - val = int(val) + val_new = int(val) + val_old = Config.get_setting_value( + self.settings, jid_bare, key) db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) - if val == 0: # if not val: - response = 'Summary length limit is disabled.' + await Config.set_setting_value( + self.settings, jid_bare, db_file, key, val_new) + if val_new == 0: # if not val: + response = ('Summary length limit is disabled ' + '(was: {}).'.format(val_old)) else: - response = ('Summary maximum length ' - 'is set to {} characters.' - .format(val)) + response = ('Summary maximum length is set to ' + '{} characters (was: {}).' + .format(val_new, val_old)) except: response = ('No action has been taken.' '\n' @@ -782,21 +793,24 @@ async def message(self, message): db_file = config.get_pathname_to_database(jid_file) key = 'media' val = 0 - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value( + self.settings, jid_bare, db_file, key, val) response = 'Media is disabled.' XmppMessage.send_reply(self, message, response) case 'media on': db_file = config.get_pathname_to_database(jid_file) key = 'media' val = 1 - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value(self.settings, jid_bare, + db_file, key, val) response = 'Media is enabled.' XmppMessage.send_reply(self, message, response) case 'new': db_file = config.get_pathname_to_database(jid_file) key = 'old' val = 0 - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value(self.settings, jid_bare, + db_file, key, val) response = 'Only new items of newly added feeds be delivered.' XmppMessage.send_reply(self, message, response) case _ if message_lowercase.startswith('next'): @@ -811,7 +825,8 @@ async def message(self, message): db_file = config.get_pathname_to_database(jid_file) key = 'old' val = 1 - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value(self.settings, jid_bare, + db_file, key, val) response = 'All items of newly added feeds be delivered.' XmppMessage.send_reply(self, message, response) case _ if message_lowercase.startswith('quantum'): @@ -819,14 +834,17 @@ async def message(self, message): val = message_text[8:] if val: try: - val = int(val) + val_new = int(val) + val_old = Config.get_setting_value(self.settings, + jid_bare, key) # response = ( # 'Every update will contain {} news items.' # ).format(response) db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) - response = ('Next update will contain {} news items.' - .format(val)) + await Config.set_setting_value(self.settings, jid_bare, + db_file, key, val_new) + response = ('Next update will contain {} news items ' + '(was: {}).'.format(val_new, val_old)) except: response = ('No action has been taken.' '\n' @@ -849,8 +867,8 @@ async def message(self, message): key_list = ['status'] task.clean_tasks_xmpp(self, jid_bare, key_list) status_type = 'dnd' - status_message = ('📫️ Processing request to fetch data from {}' - .format(url)) + status_message = ('📫️ Processing request to fetch data ' + 'from {}'.format(url)) XmppPresence.send(self, jid_bare, status_message, status_type=status_type) if url.startswith('feed:'): @@ -1015,10 +1033,12 @@ async def message(self, message): key = 'enabled' val = 1 db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value(self.settings, jid_bare, + db_file, key, val) status_type = 'available' status_message = '📫️ Welcome back!' - XmppPresence.send(self, jid_bare, status_message, status_type=status_type) + XmppPresence.send(self, jid_bare, status_message, + status_type=status_type) await asyncio.sleep(5) key_list = ['check', 'status', 'interval'] await task.start_tasks_xmpp(self, jid_bare, key_list) @@ -1064,14 +1084,16 @@ async def message(self, message): 'Input name is identical to the ' 'existing name.') else: - await sqlite.set_feed_title(db_file, feed_id, name) + await sqlite.set_feed_title(db_file, feed_id, + name) response = ('> {}' '\n' - 'Subscription #{} has been renamed to "{}".' - .format(name_old, feed_id, name)) + 'Subscription #{} has been ' + 'renamed to "{}".'.format( + name_old,feed_id, name)) else: - response = ('Subscription with Id {} does not exist.' - .format(feed_id)) + response = ('Subscription with Id {} does not ' + 'exist.'.format(feed_id)) except: response = ('No action has been taken.' '\n' @@ -1101,7 +1123,8 @@ async def message(self, message): key = 'enabled' val = 0 db_file = config.get_pathname_to_database(jid_file) - await Config.set_setting_value(self.settings, jid_bare, db_file, key, val) + await Config.set_setting_value( + self.settings, jid_bare, db_file, key, val) key_list = ['interval', 'status'] task.clean_tasks_xmpp(self, jid_bare, key_list) status_type = 'xa'