forked from sch/Slixfeed
Replace configuration file INI by TOML.
Fix ping functionality when activated as component (thank you Guus and MattJ). Add initial code for XEP-0060: Publish-Subscribe. Fix case-sensitivity with setting keys sent in-chat-command (Thank you mirux)
This commit is contained in:
parent
ba61250f84
commit
b1a1955545
22 changed files with 802 additions and 1168 deletions
|
@ -85,21 +85,24 @@ from slixfeed.version import __version__
|
||||||
# import socks
|
# import socks
|
||||||
# import socket
|
# import socket
|
||||||
|
|
||||||
xmpp_type = config.get_value('accounts', 'XMPP', 'type')
|
account = config.get_values('accounts.toml', 'xmpp')
|
||||||
|
|
||||||
|
if not 'mode' in account['settings']:
|
||||||
|
account_mode = 'client'
|
||||||
|
print('Key "mode" was not found.\nSetting value to "client".')
|
||||||
|
# raise Exception('Key type is missing from accounts.toml.')
|
||||||
|
else:
|
||||||
|
account_mode = 'component'
|
||||||
|
|
||||||
if not xmpp_type:
|
match account_mode:
|
||||||
raise Exception('Key type is missing from accounts.ini.')
|
|
||||||
|
|
||||||
match xmpp_type:
|
|
||||||
case 'client':
|
case 'client':
|
||||||
from slixfeed.xmpp.client import Slixfeed
|
from slixfeed.xmpp.client import Slixfeed
|
||||||
from slixfeed.config import ConfigClient as ConfigAccount
|
# from slixfeed.config import ConfigClient as ConfigAccount
|
||||||
case 'component':
|
case 'component':
|
||||||
from slixfeed.xmpp.component import SlixfeedComponent
|
from slixfeed.xmpp.component import SlixfeedComponent
|
||||||
from slixfeed.config import ConfigComponent as ConfigAccount
|
# from slixfeed.config import ConfigComponent as ConfigAccount
|
||||||
|
|
||||||
account = ConfigAccount() # TODO Delete as soon as posible after is no longer needed
|
# account = ConfigAccount() # TODO Delete as soon as posible after is no longer needed
|
||||||
|
|
||||||
class JabberComponent:
|
class JabberComponent:
|
||||||
def __init__(self, jid, secret, hostname, port, alias=None):
|
def __init__(self, jid, secret, hostname, port, alias=None):
|
||||||
|
@ -175,9 +178,8 @@ class JabberClient:
|
||||||
# xmpp.proxy = {'socks5': ('localhost', 9050)}
|
# xmpp.proxy = {'socks5': ('localhost', 9050)}
|
||||||
|
|
||||||
# Connect to the XMPP server and start processing XMPP stanzas.
|
# Connect to the XMPP server and start processing XMPP stanzas.
|
||||||
|
if hostname and port:
|
||||||
if account.setting['hostname'] and account.setting['port']:
|
xmpp.connect((hostname, port))
|
||||||
xmpp.connect((account.setting['hostname'], account.setting['port']))
|
|
||||||
else:
|
else:
|
||||||
xmpp.connect()
|
xmpp.connect()
|
||||||
xmpp.process()
|
xmpp.process()
|
||||||
|
@ -200,7 +202,7 @@ def main():
|
||||||
# # socket.socket = socks.socksocket
|
# # socket.socket = socks.socksocket
|
||||||
|
|
||||||
# Setup the command line arguments.
|
# Setup the command line arguments.
|
||||||
match xmpp_type:
|
match account_mode:
|
||||||
case 'client':
|
case 'client':
|
||||||
parser = ArgumentParser(description=Slixfeed.__doc__)
|
parser = ArgumentParser(description=Slixfeed.__doc__)
|
||||||
case 'component':
|
case 'component':
|
||||||
|
@ -242,11 +244,11 @@ def main():
|
||||||
# logwrn = logger.warning
|
# logwrn = logger.warning
|
||||||
|
|
||||||
# Try configuration file
|
# Try configuration file
|
||||||
alias = account.setting['alias']
|
jid = account[account_mode]['jid']
|
||||||
jid = account.setting['jid']
|
password = account[account_mode]['password']
|
||||||
password = account.setting['password']
|
alias = account[account_mode]['alias'] if 'alias' in account[account_mode] else None
|
||||||
hostname = account.setting['hostname']
|
hostname = account[account_mode]['hostname'] if 'hostname' in account[account_mode] else None
|
||||||
port = account.setting['port']
|
port = account[account_mode]['port'] if 'port' in account[account_mode] else None
|
||||||
|
|
||||||
# Use arguments if were given
|
# Use arguments if were given
|
||||||
if args.jid:
|
if args.jid:
|
||||||
|
@ -268,7 +270,7 @@ def main():
|
||||||
if not alias:
|
if not alias:
|
||||||
alias = (input('Alias: ')) or 'Slixfeed'
|
alias = (input('Alias: ')) or 'Slixfeed'
|
||||||
|
|
||||||
match xmpp_type:
|
match account_mode:
|
||||||
case 'client':
|
case 'client':
|
||||||
JabberClient(jid, password, hostname=hostname, port=port, alias=alias)
|
JabberClient(jid, password, hostname=hostname, port=port, alias=alias)
|
||||||
case 'component':
|
case 'component':
|
||||||
|
|
|
@ -113,6 +113,27 @@ async def export_feeds(self, jid, jid_file, ext):
|
||||||
# response = 'Not yet implemented.'
|
# response = 'Not yet implemented.'
|
||||||
return filename
|
return filename
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
TODO
|
||||||
|
|
||||||
|
Consider to append text to remind to share presence
|
||||||
|
'✒️ Share online status to receive updates'
|
||||||
|
|
||||||
|
# TODO Request for subscription
|
||||||
|
if (await get_chat_type(self, jid_bare) == 'chat' and
|
||||||
|
not self.client_roster[jid_bare]['to']):
|
||||||
|
XmppPresence.subscription(self, jid_bare, 'subscribe')
|
||||||
|
await XmppRoster.add(self, jid_bare)
|
||||||
|
status_message = '✒️ Share online status to receive updates'
|
||||||
|
XmppPresence.send(self, jid_bare, status_message)
|
||||||
|
message_subject = 'RSS News Bot'
|
||||||
|
message_body = 'Share online status to receive updates.'
|
||||||
|
XmppMessage.send_headline(self, jid_bare, message_subject,
|
||||||
|
message_body, 'chat')
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
async def xmpp_send_status(self, jid):
|
async def xmpp_send_status(self, jid):
|
||||||
"""
|
"""
|
||||||
Send status message.
|
Send status message.
|
||||||
|
@ -127,7 +148,7 @@ async def xmpp_send_status(self, jid):
|
||||||
status_text = '📜️ Slixfeed RSS News Bot'
|
status_text = '📜️ Slixfeed RSS News Bot'
|
||||||
jid_file = jid.replace('/', '_')
|
jid_file = jid.replace('/', '_')
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
enabled = self.settings[jid]['enabled'] or self.settings['default']['enabled']
|
enabled = Config.get_setting_value(self.settings, jid, 'enabled')
|
||||||
if not enabled:
|
if not enabled:
|
||||||
status_mode = 'xa'
|
status_mode = 'xa'
|
||||||
status_text = '📪️ Send "Start" to receive updates'
|
status_text = '📪️ Send "Start" to receive updates'
|
||||||
|
@ -179,11 +200,11 @@ async def xmpp_send_update(self, jid, num=None):
|
||||||
logger.debug('{}: jid: {} num: {}'.format(function_name, jid, num))
|
logger.debug('{}: jid: {} num: {}'.format(function_name, jid, num))
|
||||||
jid_file = jid.replace('/', '_')
|
jid_file = jid.replace('/', '_')
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
enabled = self.settings[jid]['enabled'] or self.settings['default']['enabled']
|
enabled = Config.get_setting_value(self.settings, jid, 'enabled')
|
||||||
if enabled:
|
if enabled:
|
||||||
show_media = self.settings[jid]['media'] or self.settings['default']['media']
|
show_media = Config.get_setting_value(self.settings, jid, 'media')
|
||||||
if not num:
|
if not num:
|
||||||
num = self.settings[jid]['quantum'] or self.settings['default']['quantum']
|
num = Config.get_setting_value(self.settings, jid, 'quantum')
|
||||||
else:
|
else:
|
||||||
num = int(num)
|
num = int(num)
|
||||||
results = sqlite.get_unread_entries(db_file, num)
|
results = sqlite.get_unread_entries(db_file, num)
|
||||||
|
@ -465,7 +486,7 @@ def list_unread_entries(self, result, feed_title, jid):
|
||||||
summary = summary.replace('\n', ' ')
|
summary = summary.replace('\n', ' ')
|
||||||
summary = summary.replace(' ', ' ')
|
summary = summary.replace(' ', ' ')
|
||||||
summary = summary.replace(' ', ' ')
|
summary = summary.replace(' ', ' ')
|
||||||
length = self.settings[jid]['length'] or self.settings['default']['length']
|
length = Config.get_setting_value(self.settings, jid, 'length')
|
||||||
length = int(length)
|
length = int(length)
|
||||||
summary = summary[:length] + " […]"
|
summary = summary[:length] + " […]"
|
||||||
# summary = summary.strip().split('\n')
|
# summary = summary.strip().split('\n')
|
||||||
|
@ -476,13 +497,13 @@ def list_unread_entries(self, result, feed_title, jid):
|
||||||
link = (replace_hostname(link, "link")) or link
|
link = (replace_hostname(link, "link")) or link
|
||||||
# news_item = ("\n{}\n{}\n{} [{}]\n").format(str(title), str(link),
|
# news_item = ("\n{}\n{}\n{} [{}]\n").format(str(title), str(link),
|
||||||
# str(feed_title), str(ix))
|
# str(feed_title), str(ix))
|
||||||
formatting = self.settings[jid]['formatting'] or self.settings['default']['formatting']
|
formatting = Config.get_setting_value(self.settings, jid, 'formatting')
|
||||||
news_item = formatting.format(feed_title=feed_title,
|
news_item = formatting.format(feed_title=feed_title,
|
||||||
title=title,
|
title=title,
|
||||||
summary=summary,
|
summary=summary,
|
||||||
link=link,
|
link=link,
|
||||||
ix=ix)
|
ix=ix)
|
||||||
news_item = news_item.replace('\\n', '\n')
|
# news_item = news_item.replace('\\n', '\n')
|
||||||
return news_item
|
return news_item
|
||||||
|
|
||||||
|
|
||||||
|
@ -502,11 +523,9 @@ def list_search_results(query, results):
|
||||||
return message
|
return message
|
||||||
|
|
||||||
|
|
||||||
def list_feeds_by_query(db_file, query):
|
def list_feeds_by_query(query, results):
|
||||||
function_name = sys._getframe().f_code.co_name
|
function_name = sys._getframe().f_code.co_name
|
||||||
logger.debug('{}: db_file: {} query: {}'
|
logger.debug('{}'.format(function_name))
|
||||||
.format(function_name, db_file, query))
|
|
||||||
results = sqlite.search_feeds(db_file, query)
|
|
||||||
message = ('Feeds containing "{}":\n\n```'
|
message = ('Feeds containing "{}":\n\n```'
|
||||||
.format(query))
|
.format(query))
|
||||||
for result in results:
|
for result in results:
|
||||||
|
@ -549,10 +568,10 @@ async def list_options(self, jid_bare):
|
||||||
# value = "Default"
|
# value = "Default"
|
||||||
# values.extend([value])
|
# values.extend([value])
|
||||||
|
|
||||||
value_archive = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
value_archive = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
value_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
value_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
value_quantum = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum']
|
value_quantum = Config.get_setting_value(self.settings, jid_bare, 'quantum')
|
||||||
value_enabled = self.settings[jid_bare]['archive'] or self.settings['default']['enabled']
|
value_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
|
|
||||||
message = ("Options:"
|
message = ("Options:"
|
||||||
"\n"
|
"\n"
|
||||||
|
@ -647,13 +666,10 @@ def list_feeds(results):
|
||||||
logger.debug('{}'.format(function_name))
|
logger.debug('{}'.format(function_name))
|
||||||
message = "\nList of subscriptions:\n\n```\n"
|
message = "\nList of subscriptions:\n\n```\n"
|
||||||
for result in results:
|
for result in results:
|
||||||
message += ("Name : {}\n"
|
message += ("{} [{}]\n"
|
||||||
"URL : {}\n"
|
"{}\n"
|
||||||
# "Updated : {}\n"
|
"\n\n"
|
||||||
# "Status : {}\n"
|
.format(str(result[1]), str(result[0]), str(result[2])))
|
||||||
"ID : {}\n"
|
|
||||||
"\n"
|
|
||||||
.format(str(result[0]), str(result[1]), str(result[2])))
|
|
||||||
if len(results):
|
if len(results):
|
||||||
message += ('```\nTotal of {} subscriptions.\n'
|
message += ('```\nTotal of {} subscriptions.\n'
|
||||||
.format(len(results)))
|
.format(len(results)))
|
||||||
|
@ -793,7 +809,7 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
status_code=status_code,
|
status_code=status_code,
|
||||||
updated=updated)
|
updated=updated)
|
||||||
await scan(self, jid_bare, db_file, url)
|
await scan(self, jid_bare, db_file, url)
|
||||||
old = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
old = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
feed_id = sqlite.get_feed_id(db_file, url)
|
feed_id = sqlite.get_feed_id(db_file, url)
|
||||||
feed_id = feed_id[0]
|
feed_id = feed_id[0]
|
||||||
if not old:
|
if not old:
|
||||||
|
@ -804,9 +820,6 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
'code' : status_code,
|
'code' : status_code,
|
||||||
'error' : False,
|
'error' : False,
|
||||||
'exist' : False}
|
'exist' : False}
|
||||||
response = ('> {}\nNews source "{}" has been '
|
|
||||||
'added to subscription list.'
|
|
||||||
.format(url, title))
|
|
||||||
break
|
break
|
||||||
# NOTE This elif statement be unnecessary
|
# NOTE This elif statement be unnecessary
|
||||||
# when feedparser be supporting json feed.
|
# when feedparser be supporting json feed.
|
||||||
|
@ -843,7 +856,7 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
status_code=status_code,
|
status_code=status_code,
|
||||||
updated=updated)
|
updated=updated)
|
||||||
await scan_json(self, jid_bare, db_file, url)
|
await scan_json(self, jid_bare, db_file, url)
|
||||||
old = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
old = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
if not old:
|
if not old:
|
||||||
feed_id = sqlite.get_feed_id(db_file, url)
|
feed_id = sqlite.get_feed_id(db_file, url)
|
||||||
feed_id = feed_id[0]
|
feed_id = feed_id[0]
|
||||||
|
@ -854,9 +867,6 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
'code' : status_code,
|
'code' : status_code,
|
||||||
'error' : False,
|
'error' : False,
|
||||||
'exist' : False}
|
'exist' : False}
|
||||||
response = ('> {}\nNews source "{}" has been '
|
|
||||||
'added to subscription list.'
|
|
||||||
.format(url, title))
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
# NOTE Do not be tempted to return a compact dictionary.
|
# NOTE Do not be tempted to return a compact dictionary.
|
||||||
|
@ -886,8 +896,6 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
'code' : status_code,
|
'code' : status_code,
|
||||||
'error' : True,
|
'error' : True,
|
||||||
'exist' : False}
|
'exist' : False}
|
||||||
response = ('> {}\nFailed to load URL. Reason: {}'
|
|
||||||
.format(url, status_code))
|
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
ix = exist[0]
|
ix = exist[0]
|
||||||
|
@ -898,9 +906,6 @@ async def add_feed(self, jid_bare, db_file, url):
|
||||||
'code' : None,
|
'code' : None,
|
||||||
'error' : False,
|
'error' : False,
|
||||||
'exist' : True}
|
'exist' : True}
|
||||||
response = ('> {}\nNews source "{}" is already '
|
|
||||||
'listed in the subscription list at '
|
|
||||||
'index {}'.format(url, name, ix))
|
|
||||||
break
|
break
|
||||||
return result_final
|
return result_final
|
||||||
|
|
||||||
|
@ -1254,7 +1259,7 @@ async def scan(self, jid_bare, db_file, url):
|
||||||
return
|
return
|
||||||
# new_entry = 0
|
# new_entry = 0
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
logger.debug('{}: entry: {}'.format(function_name, entry.title))
|
logger.debug('{}: entry: {}'.format(function_name, entry.link))
|
||||||
if entry.has_key("published"):
|
if entry.has_key("published"):
|
||||||
date = entry.published
|
date = entry.published
|
||||||
date = dt.rfc2822_to_iso8601(date)
|
date = dt.rfc2822_to_iso8601(date)
|
||||||
|
@ -1481,6 +1486,7 @@ async def extract_image_from_html(url):
|
||||||
'contains(@src, "emoji") or '
|
'contains(@src, "emoji") or '
|
||||||
'contains(@src, "icon") or '
|
'contains(@src, "icon") or '
|
||||||
'contains(@src, "logo") or '
|
'contains(@src, "logo") or '
|
||||||
|
'contains(@src, "letture") or '
|
||||||
'contains(@src, "search") or '
|
'contains(@src, "search") or '
|
||||||
'contains(@src, "share") or '
|
'contains(@src, "share") or '
|
||||||
'contains(@src, "smiley")'
|
'contains(@src, "smiley")'
|
||||||
|
@ -1614,7 +1620,7 @@ async def remove_nonexistent_entries(self, jid_bare, db_file, url, feed):
|
||||||
feed_id = feed_id[0]
|
feed_id = feed_id[0]
|
||||||
items = sqlite.get_entries_of_feed(db_file, feed_id)
|
items = sqlite.get_entries_of_feed(db_file, feed_id)
|
||||||
entries = feed.entries
|
entries = feed.entries
|
||||||
limit = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
limit = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
for item in items:
|
for item in items:
|
||||||
ix = item[0]
|
ix = item[0]
|
||||||
entry_title = item[1]
|
entry_title = item[1]
|
||||||
|
@ -1723,7 +1729,7 @@ async def remove_nonexistent_entries_json(self, jid_bare, db_file, url, feed):
|
||||||
feed_id = feed_id[0]
|
feed_id = feed_id[0]
|
||||||
items = sqlite.get_entries_of_feed(db_file, feed_id)
|
items = sqlite.get_entries_of_feed(db_file, feed_id)
|
||||||
entries = feed["items"]
|
entries = feed["items"]
|
||||||
limit = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
limit = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
for item in items:
|
for item in items:
|
||||||
ix = item[0]
|
ix = item[0]
|
||||||
entry_title = item[1]
|
entry_title = item[1]
|
||||||
|
|
|
@ -1,98 +0,0 @@
|
||||||
# Settings to tell the bot to which accounts to connect
|
|
||||||
# and also from which accounts it receives instructions.
|
|
||||||
|
|
||||||
[XMPP]
|
|
||||||
operator =
|
|
||||||
reconnect_timeout = 30
|
|
||||||
type = client
|
|
||||||
#type = component
|
|
||||||
|
|
||||||
[XMPP Client]
|
|
||||||
alias = Slixfeed
|
|
||||||
jid =
|
|
||||||
password =
|
|
||||||
#hostname =
|
|
||||||
#port =
|
|
||||||
|
|
||||||
[XMPP Component]
|
|
||||||
alias = Slixfeed
|
|
||||||
jid =
|
|
||||||
password =
|
|
||||||
hostname =
|
|
||||||
port =
|
|
||||||
|
|
||||||
[XMPP Profile]
|
|
||||||
name = Slixfeed
|
|
||||||
nickname = Slixfeed
|
|
||||||
role = Syndication News Bot
|
|
||||||
organization = RSS Task Force
|
|
||||||
url = https://gitgud.io/sjehuda/slixfeed
|
|
||||||
description = XMPP news bot (supports Atom, JSON, RDF and RSS).
|
|
||||||
note = This is a syndication news bot powered by Slixfeed.
|
|
||||||
birthday = 21 June 2022
|
|
||||||
|
|
||||||
[XMPP Proxy]
|
|
||||||
# NOTE You might want to consider support for socks4 too (this
|
|
||||||
# note was written when keys were proxy_host and proxy_port)
|
|
||||||
|
|
||||||
# NOTE Consider not to use a version number as it might give an
|
|
||||||
# impression of an archaic feature in the future.
|
|
||||||
|
|
||||||
#socks5_host =
|
|
||||||
#socks5_port =
|
|
||||||
#socks5_username =
|
|
||||||
#socks5_password =
|
|
||||||
|
|
||||||
[ActivityPub]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[Email]
|
|
||||||
recipient_emails =
|
|
||||||
sender_emails =
|
|
||||||
|
|
||||||
[IMAP]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
#port = 993
|
|
||||||
|
|
||||||
[SMTP]
|
|
||||||
host =
|
|
||||||
#port = 465
|
|
||||||
|
|
||||||
[IRC]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
#port = 6667
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[LXMF]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[Matrix]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[Nostr]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[Session]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[SIP]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
||||||
|
|
||||||
[TOX]
|
|
||||||
username =
|
|
||||||
password =
|
|
||||||
operator =
|
|
108
slixfeed/assets/accounts.toml
Normal file
108
slixfeed/assets/accounts.toml
Normal file
|
@ -0,0 +1,108 @@
|
||||||
|
# Settings to tell the bot to which accounts to connect
|
||||||
|
# and also from which accounts it receives instructions.
|
||||||
|
|
||||||
|
[xmpp.settings]
|
||||||
|
#mode = "component"
|
||||||
|
reconnect_timeout = 30
|
||||||
|
|
||||||
|
[[xmpp.operators]]
|
||||||
|
name = "Mr. Operator"
|
||||||
|
jid = ""
|
||||||
|
|
||||||
|
[[xmpp.operators]]
|
||||||
|
name = "Mrs. Operator"
|
||||||
|
jid = ""
|
||||||
|
|
||||||
|
[xmpp.proxy.socks5]
|
||||||
|
#host = "127.0.0.1"
|
||||||
|
#port = 9050
|
||||||
|
#username = ""
|
||||||
|
#password = ""
|
||||||
|
|
||||||
|
[xmpp.profile]
|
||||||
|
FN = "Slixfeed"
|
||||||
|
NICKNAME = "Slixfeed"
|
||||||
|
ROLE = "Syndication News Bot"
|
||||||
|
ORG = "RSS Task Force"
|
||||||
|
URL = "https://gitgud.io/sjehuda/slixfeed"
|
||||||
|
NOTE = """
|
||||||
|
This is a syndication news bot powered by Slixfeed.
|
||||||
|
This bot can read Atom, JSON, RDF and RSS feeds.
|
||||||
|
This bot can communicate to 1:1 chats and groupchats as one.
|
||||||
|
You are welcome to join our groupchat at:
|
||||||
|
xmpp:slixfeed@chat.woodpeckersnest.space?join
|
||||||
|
"""
|
||||||
|
BDAY = "21 June 2022"
|
||||||
|
TITLE = "XMPP News Bot"
|
||||||
|
DESC = "Syndication bot made for XMPP."
|
||||||
|
|
||||||
|
[xmpp.client]
|
||||||
|
alias = "Slixfeed"
|
||||||
|
jid = "slixfeed@your.server/slixfeed"
|
||||||
|
password = ""
|
||||||
|
#hostname =
|
||||||
|
#port =
|
||||||
|
|
||||||
|
[xmpp.component]
|
||||||
|
alias = "Slixfeed"
|
||||||
|
jid = "rss.your.server"
|
||||||
|
password = ""
|
||||||
|
hostname = "your.server"
|
||||||
|
#port =
|
||||||
|
|
||||||
|
[activitypub]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[activitypub.profile]
|
||||||
|
user_agent = "Slixfeed"
|
||||||
|
|
||||||
|
[email]
|
||||||
|
recipient_emails = ""
|
||||||
|
sender_emails = ""
|
||||||
|
|
||||||
|
[email.imap]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
#port = 993
|
||||||
|
|
||||||
|
[email.smtp]
|
||||||
|
host = ""
|
||||||
|
#port = 465
|
||||||
|
|
||||||
|
[irc]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
#port = 6667
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[deltachat]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[lxmf]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[nostr]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[session]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[sip]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
||||||
|
|
||||||
|
[tox]
|
||||||
|
username = ""
|
||||||
|
password = ""
|
||||||
|
operator = ""
|
|
@ -1,9 +1,5 @@
|
||||||
[[about]]
|
[about]
|
||||||
title = "About"
|
info = """
|
||||||
subtitle = "Slixfeed news bot"
|
|
||||||
|
|
||||||
[[about]]
|
|
||||||
info = ["""
|
|
||||||
Slixfeed is a news broker bot for syndicated news which aims to be \
|
Slixfeed is a news broker bot for syndicated news which aims to be \
|
||||||
an easy to use and fully-featured news aggregating bot.
|
an easy to use and fully-featured news aggregating bot.
|
||||||
|
|
||||||
|
@ -12,10 +8,13 @@ even Fediverse instances, along with filtering and other privacy \
|
||||||
driven functionalities.
|
driven functionalities.
|
||||||
|
|
||||||
Slixfeed is designed primarily for the XMPP communication network \
|
Slixfeed is designed primarily for the XMPP communication network \
|
||||||
(aka Jabber). Visit https://xmpp.org/software/ for more information.
|
(aka Jabber).
|
||||||
"""]
|
|
||||||
|
|
||||||
note = ["""
|
https://gitgud.io/sjehuda/slixfeed
|
||||||
|
"""
|
||||||
|
|
||||||
|
[note]
|
||||||
|
note = """
|
||||||
You can run your own Slixfeed instance as a client, from your own \
|
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, \
|
computer, server, and even from a Linux phone (i.e. Droidian, Kupfer, \
|
||||||
Mobian, NixOS, postmarketOS), as well as from Termux.
|
Mobian, NixOS, postmarketOS), as well as from Termux.
|
||||||
|
@ -24,107 +23,59 @@ All you need is one of the above and an XMPP account to connect \
|
||||||
Slixfeed with.
|
Slixfeed with.
|
||||||
|
|
||||||
Good luck!
|
Good luck!
|
||||||
"""]
|
|
||||||
|
|
||||||
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]]
|
[authors]
|
||||||
name = "err-rssreader"
|
info = """
|
||||||
info = ["A port of old Brutal's RSS Reader for Errbot"]
|
Schimon Zackary
|
||||||
url = "https://github.com/errbotters/err-rssreader"
|
Laura Lapina
|
||||||
|
"""
|
||||||
|
|
||||||
[[friends]]
|
[contributors]
|
||||||
name = "feed-to-muc"
|
info = """
|
||||||
info = ["""
|
Guus der Kinderen
|
||||||
An XMPP bot which posts to a MUC (groupchat) if there is an update in newsfeeds.
|
grym (from #python IRC channel)
|
||||||
"""]
|
Stephen Paul Weber
|
||||||
url = "https://salsa.debian.org/mdosch/feed-to-muc"
|
"""
|
||||||
|
|
||||||
[[friends]]
|
[bots]
|
||||||
name = "JabRSS (fork)"
|
info = """
|
||||||
info = ["""
|
Syndication bots made by our counterparts.
|
||||||
Never miss a headline again! JabRSS is a simple RSS (RDF Site Summary) \
|
|
||||||
headline notification service for Jabber.
|
|
||||||
|
|
||||||
It is based on jabrss@cmeerw.net from Christof.
|
Morbot
|
||||||
|
https://codeberg.org/TheCoffeMaker/Morbot
|
||||||
|
|
||||||
It was restructured and offers additional features (see help, help filter and \
|
feed-to-muc
|
||||||
show plugins).
|
https://salsa.debian.org/mdosch/feed-to-muc
|
||||||
"""]
|
|
||||||
url = "http://www.jotwewe.de/de/xmpp/jabrss/jabrss_en.htm"
|
|
||||||
|
|
||||||
[[friends]]
|
JabRSS
|
||||||
name = "JabRSS"
|
http://www.jotwewe.de/de/xmpp/jabrss/jabrss_en.htm
|
||||||
info = ["""
|
|
||||||
A simple RSS (RDF Site Summary) headline notification service for Jabber/XMPP.
|
|
||||||
|
|
||||||
A public instance of the bot is available via xmpp:jabrss@cmeerw.net
|
JabRSS
|
||||||
"""]
|
https://dev.cmeerw.org/Projects/jabrss
|
||||||
url = "https://dev.cmeerw.org/Projects/jabrss"
|
|
||||||
|
|
||||||
[[friends]]
|
err-rssreader"
|
||||||
name = "Morbot"
|
https://github.com/errbotters/err-rssreader
|
||||||
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]]
|
XMPP Bot
|
||||||
title = "Legal"
|
https://github.com/nioc/xmpp-bot
|
||||||
subtitle = "Legal Notice"
|
"""
|
||||||
|
|
||||||
[[legal]]
|
[legal]
|
||||||
info = ["""
|
info = """
|
||||||
Slixfeed is free software; you can redistribute it and/or modify it under the \
|
Slixfeed is free software; you can redistribute it and/or modify it under the \
|
||||||
terms of the MIT License.
|
terms of the MIT License.
|
||||||
|
|
||||||
Slixfeed is distributed in the hope that it will be useful, but WITHOUT ANY \
|
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 \
|
WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR \
|
||||||
A PARTICULAR PURPOSE. See the MIT License for more details.
|
A PARTICULAR PURPOSE. See the MIT License for more details.
|
||||||
"""]
|
|
||||||
link = "https://gitgud.io/sjehuda/slixfeed"
|
|
||||||
|
|
||||||
[[license]]
|
https://gitgud.io/sjehuda/slixfeed
|
||||||
title = "License"
|
"""
|
||||||
subtitle = "MIT License"
|
|
||||||
|
|
||||||
[[license]]
|
[license]
|
||||||
license = ["""
|
info = """
|
||||||
Copyright 2022 - 2024 Schimon Zackary Jehudah
|
Copyright 2022 - 2024 Schimon Jehudah Zackary
|
||||||
|
|
||||||
Permission is hereby granted, free of charge, to any person obtaining a copy \
|
Permission is hereby granted, free of charge, to any person obtaining a copy \
|
||||||
of this software and associated documentation files (the “Software”), to deal \
|
of this software and associated documentation files (the “Software”), to deal \
|
||||||
|
@ -143,558 +94,136 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER \
|
||||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING \
|
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 \
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS \
|
||||||
IN THE SOFTWARE.
|
IN THE SOFTWARE.
|
||||||
"""]
|
"""
|
||||||
owner = "Schimon Zackary"
|
|
||||||
|
|
||||||
[[support]]
|
[support]
|
||||||
title = "Support"
|
info = """
|
||||||
subtitle = "Slixfeed Support Groupchat"
|
Slixfeed Support Groupchat
|
||||||
|
xmpp:slixfeed@chat.woodpeckersnest.space?join
|
||||||
|
"""
|
||||||
|
|
||||||
[[support]]
|
[thanks]
|
||||||
jid = "xmpp:slixfeed@chat.woodpeckersnest.space?join"
|
info = """
|
||||||
|
|
||||||
[[thanks]]
|
|
||||||
title = "Thanks"
|
|
||||||
subtitle = """
|
|
||||||
From SalixOS to Gajim. A journey of 15 years. \
|
From SalixOS to Gajim. A journey of 15 years. \
|
||||||
The people who have made all this possible.
|
The people who have made all this possible.
|
||||||
|
|
||||||
|
Alixander Court (Utah), Arne-Brün Vogelsang (Germany), Chris Farrell (Oregon) \
|
||||||
|
Christian Dersch, Cyrille Pontvieux (France), Denis Fomin (Russia), Dimitris \
|
||||||
|
Tzemos (Greece), Emmanuel Gil Peyrot (France), Florent Le Coz (France), George \
|
||||||
|
Vlahavas (Greece), Guus der Kinderen (Netherlands), habnabit_ (#python), Imar \
|
||||||
|
van Erven Dorens (Netherlands), imattau (atomtopubsub), Jaussoin Timothée \
|
||||||
|
(France), Justin Karneges (California), Kevin Smith (Wales), Lars Windolf \
|
||||||
|
(Germany), Luis Henrique Mello (Brazil), magicfelix, Markus Muttilainen \
|
||||||
|
(SalixOS), Martin (Germany), Mathieu Pasquet (France), Maxime Buquet (France), \
|
||||||
|
mirux (Germany), Phillip Watkins (England), Pierrick Le Brun (France), Raphael \
|
||||||
|
Groner (Germany), Remko Tronçon (Belgium), Richard Lapointe (Connecticut), \
|
||||||
|
Simone "roughnecks" Canaletti (Italy), Strix from Loqi, Thibaud Guerin \
|
||||||
|
(SalixOS), Thorsten Fröhlich (France), Thorsten Mühlfelder (Germany), Tim \
|
||||||
|
Beech (Brazil), Tomoki Tsuchiya (SalixOS), Yann Leboulanger (France)
|
||||||
|
|
||||||
|
Thanks also to the friends of #python at irc.libera.chat
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[thanks]]
|
[operators]
|
||||||
name = "Alixander Court"
|
info = """
|
||||||
country = "Utah"
|
No operator was specified for this instance.
|
||||||
url = "https://alixandercourt.com"
|
"""
|
||||||
|
|
||||||
[[thanks]]
|
[terms]
|
||||||
name = "Arne-Brün Vogelsang"
|
info = """
|
||||||
country = "Germany"
|
|
||||||
project = "monocles"
|
|
||||||
url = "https://monocles.eu/more"
|
|
||||||
|
|
||||||
[[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.
|
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.
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
[[clients]]
|
[privacy]
|
||||||
name = "Cheogram"
|
info = """
|
||||||
info = "XMPP client for mobile"
|
All your data belongs to us.
|
||||||
url = "https://cheogram.com"
|
"""
|
||||||
|
|
||||||
# [[clients]]
|
[clients]
|
||||||
# name = "Conversations"
|
info = """
|
||||||
# info = "XMPP client for mobile"
|
Recommended Clients:
|
||||||
# url = "https://conversations.im"
|
|
||||||
|
|
||||||
[[clients]]
|
Cheogram
|
||||||
name = "Converse"
|
https://cheogram.com
|
||||||
info = "XMPP client for desktop and mobile"
|
|
||||||
url = "https://conversejs.org"
|
|
||||||
|
|
||||||
# [[clients]]
|
Converse
|
||||||
# name = "Gajim"
|
https://conversejs.org
|
||||||
# info = "XMPP client for desktop"
|
|
||||||
# url = "https://gajim.org"
|
|
||||||
|
|
||||||
# [[clients]]
|
Gajim
|
||||||
# name = "Monal IM"
|
https://gajim.org
|
||||||
# info = "XMPP client for desktop and mobile"
|
|
||||||
# url = "https://monal-im.org"
|
|
||||||
|
|
||||||
[[clients]]
|
monocles chat
|
||||||
name = "monocles chat"
|
https://monocles.chat
|
||||||
info = "XMPP client for mobile"
|
|
||||||
url = "https://monocles.chat"
|
|
||||||
|
|
||||||
[[clients]]
|
Movim
|
||||||
name = "Movim"
|
https://mov.im
|
||||||
info = "XMPP client for desktop and mobile"
|
|
||||||
url = "https://mov.im"
|
|
||||||
|
|
||||||
# [[clients]]
|
Poezio
|
||||||
# name = "Moxxy"
|
https://poez.io
|
||||||
# info = "XMPP client for mobile"
|
"""
|
||||||
# url = "https://moxxy.org"
|
|
||||||
|
|
||||||
[[clients]]
|
[services]
|
||||||
name = "Psi"
|
info = """
|
||||||
info = "XMPP client for desktop"
|
Recommended Syndication Services
|
||||||
url = "https://psi-im.org"
|
|
||||||
|
|
||||||
[[clients]]
|
Feed Creator
|
||||||
name = "Psi+"
|
https://www.fivefilters.org/feed-creator/"
|
||||||
info = "XMPP client for desktop"
|
|
||||||
url = "https://psi-plus.com"
|
|
||||||
|
|
||||||
# [[clients]]
|
Kill the Newsletter
|
||||||
# name = "Swift"
|
https://kill-the-newsletter.com
|
||||||
# info = "XMPP client for desktop"
|
|
||||||
# url = "https://swift.im"
|
|
||||||
|
|
||||||
# [[clients]]
|
Open RSS
|
||||||
# name = "yaxim"
|
https://openrss.org
|
||||||
# info = "XMPP client for mobile"
|
|
||||||
# url = "https://yaxim.org"
|
|
||||||
|
|
||||||
[[services]]
|
RSS-Bridge
|
||||||
title = "Recommended News Services"
|
https://rss-bridge.org/bridge01/
|
||||||
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]]
|
RSSHub
|
||||||
name = "Feed Creator"
|
https://docs.rsshub.app
|
||||||
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/"
|
|
||||||
|
|
||||||
[[services]]
|
[software]
|
||||||
name = "Kill the Newsletter"
|
info = """
|
||||||
info = "Kill the Newsletter converts email newsletters into Web feeds."
|
Recommended News Software
|
||||||
link = "https://kill-the-newsletter.com"
|
|
||||||
|
|
||||||
[[services]]
|
CommaFeed
|
||||||
name = "Open RSS"
|
https://commafeed.com
|
||||||
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.
|
|
||||||
"""]
|
|
||||||
link = "https://openrss.org"
|
|
||||||
|
|
||||||
[[services]]
|
FreshRSS
|
||||||
name = "RSS-Bridge"
|
https://freshrss.org
|
||||||
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/"
|
|
||||||
|
|
||||||
[[services]]
|
Liferea
|
||||||
name = "RSSHub"
|
https://lzone.de/liferea/
|
||||||
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"
|
|
||||||
|
|
||||||
[[software]]
|
NetNewsWire
|
||||||
title = "Recommended News Software"
|
https://netnewswire.com
|
||||||
subtitle = ["""
|
|
||||||
Take back control of your news. With free, quality, software for your \
|
|
||||||
desktop, home and mobile devices.
|
|
||||||
"""]
|
|
||||||
|
|
||||||
[[software]]
|
Newsboat
|
||||||
name = "CommaFeed"
|
https://newsboat.org
|
||||||
info = ["""
|
|
||||||
A self-hosted RSS reader, based on Dropwizard and React/TypeScript.
|
|
||||||
"""]
|
|
||||||
link = "https://commafeed.com"
|
|
||||||
os = "Any (HTML)"
|
|
||||||
|
|
||||||
[[software]]
|
Spot-On
|
||||||
name = "FreshRSS"
|
https://textbrowser.github.io/spot-on/
|
||||||
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)"
|
|
||||||
|
|
||||||
[[software]]
|
Vienna RSS
|
||||||
name = "Liferea"
|
https://vienna-rss.com
|
||||||
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]]
|
[resources]
|
||||||
name = "NetNewsWire"
|
info = """
|
||||||
info = ["""
|
Useful Resources:
|
||||||
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 \
|
feedparser
|
||||||
new articles to read. Do it the easy way instead: let NetNewsWire bring you \
|
https://pythonhosted.org/feedparser
|
||||||
the news.
|
|
||||||
|
|
||||||
And, if you’ve been getting your news via the commercial Social Networks — \
|
Slixmpp
|
||||||
with their ads, algorithms, user tracking, outrage, and misinformation — you \
|
https://slixmpp.readthedocs.io
|
||||||
can switch to NetNewsWire to get news directly and more reliably from the \
|
|
||||||
sites you trust.
|
|
||||||
"""]
|
|
||||||
link = "https://netnewswire.com"
|
|
||||||
os = "MacOS"
|
|
||||||
|
|
||||||
[[software]]
|
XMPP
|
||||||
name = "Newsboat"
|
https://xmpp.org/about
|
||||||
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]]
|
[rss-task-force]
|
||||||
name = "Spot-On"
|
info = """
|
||||||
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 \
|
The RSS Task Force (previously known as The Syndication Society) is an \
|
||||||
international organization headquartered in Switzerland.
|
international organization headquartered in Switzerland.
|
||||||
|
|
||||||
|
@ -706,44 +235,35 @@ 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.
|
expanded our cause towards all entities of all types and sorts.
|
||||||
|
|
||||||
The RSS Task Force was founded by two taxicab drivers in 2018.
|
The RSS Task Force was founded by two taxicab drivers in 2018.
|
||||||
"""]
|
"""
|
||||||
|
|
||||||
[[sleekxmpp]]
|
[sleekxmpp]
|
||||||
title = "About Project SleekXMPP"
|
info = """
|
||||||
subtitle = "SleekXMPP XMPP Library"
|
|
||||||
|
|
||||||
[[sleekxmpp]]
|
|
||||||
info = ["""
|
|
||||||
SleekXMPP is an MIT licensed XMPP library for Python 2.6/3.1+, and is \
|
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, \
|
featured in examples in the book XMPP: The Definitive Guide by Kevin Smith, \
|
||||||
Remko Tronçon, and Peter Saint-Andre.
|
Remko Tronçon, and Peter Saint-Andre.
|
||||||
"""]
|
|
||||||
url = "https://codeberg.org/fritzy/SleekXMPP"
|
|
||||||
|
|
||||||
[[slixmpp]]
|
https://codeberg.org/fritzy/SleekXMPP
|
||||||
title = "About Project Slixmpp"
|
"""
|
||||||
subtitle = "Slixmpp XMPP Library"
|
|
||||||
|
|
||||||
[[slixmpp]]
|
[slixmpp]
|
||||||
info = ["""
|
info = """
|
||||||
Slixmpp is an MIT licensed XMPP library for Python 3.7+. It is a fork of \
|
Slixmpp is an MIT licensed XMPP library for Python 3.7+. It is a fork of \
|
||||||
SleekXMPP.
|
SleekXMPP.
|
||||||
|
|
||||||
Slixmpp's goals is to only rewrite the core of the SleekXMPP library \
|
Slixmpp's goals is to only rewrite the core of the SleekXMPP library \
|
||||||
(the low level socket handling, the timers, the events dispatching) \
|
(the low level socket handling, the timers, the events dispatching) \
|
||||||
in order to remove all threads.
|
in order to remove all threads.
|
||||||
"""]
|
|
||||||
url = "https://codeberg.org/poezio/slixmpp"
|
|
||||||
|
|
||||||
[[xmpp]]
|
https://codeberg.org/poezio/slixmpp
|
||||||
title = "About XMPP"
|
"""
|
||||||
subtitle = "Previously known as Jabber"
|
|
||||||
|
|
||||||
[[xmpp]]
|
[xmpp]
|
||||||
info = ["""
|
info = """
|
||||||
XMPP is the Extensible Messaging and Presence Protocol, a set of open \
|
XMPP is the Extensible Messaging and Presence Protocol, a set of open \
|
||||||
technologies for instant messaging, presence, multi-party chat, voice and \
|
technologies for instant messaging, presence, multi-party chat, voice and \
|
||||||
video calls, collaboration, lightweight middleware, content syndication, and \
|
video calls, collaboration, lightweight middleware, content syndication, and \
|
||||||
generalized routing of XML data.
|
generalized routing of XML data.
|
||||||
"""]
|
|
||||||
link = "https://xmpp.org/about"
|
https://xmpp.org/about
|
||||||
|
"""
|
||||||
|
|
|
@ -1,77 +0,0 @@
|
||||||
# This file lists default settings per database.
|
|
||||||
# See file /usr/share/slixfeed/settings.ini
|
|
||||||
|
|
||||||
#[Bot Settings]
|
|
||||||
|
|
||||||
# Check interval
|
|
||||||
#interval = 90
|
|
||||||
|
|
||||||
[Settings]
|
|
||||||
#[Contact Settings]
|
|
||||||
|
|
||||||
# Maximum items to archive (0 - 500)
|
|
||||||
archive = 50
|
|
||||||
|
|
||||||
# Source check interval (recommended 90; minimum 10)
|
|
||||||
check = 120
|
|
||||||
|
|
||||||
# Work status (Value 0 to disable)
|
|
||||||
enabled = 1
|
|
||||||
|
|
||||||
# Enable filters (Value 1 to enable)
|
|
||||||
filter = 0
|
|
||||||
|
|
||||||
# Update interval in minutes (Minimum value 10)
|
|
||||||
interval = 300
|
|
||||||
|
|
||||||
# Maximum length of summary (Value 0 to disable)
|
|
||||||
length = 300
|
|
||||||
|
|
||||||
# Display media (audio, image, video) when available
|
|
||||||
media = 0
|
|
||||||
|
|
||||||
# Mark entries of newly added entries as unread
|
|
||||||
old = 0
|
|
||||||
|
|
||||||
# Amount of entries per update
|
|
||||||
quantum = 3
|
|
||||||
|
|
||||||
# Pick random item from database
|
|
||||||
random = 0
|
|
||||||
|
|
||||||
# Set message formatting
|
|
||||||
formatting = {title}\n> {summary}\n{link}\n{feed_title} [{ix}]\n\n
|
|
||||||
|
|
||||||
# Utilized in case of missing protocol support.
|
|
||||||
[Bridge]
|
|
||||||
gopher =
|
|
||||||
|
|
||||||
i2p =
|
|
||||||
|
|
||||||
nostr =
|
|
||||||
|
|
||||||
tor =
|
|
||||||
|
|
||||||
yggdrasil =
|
|
||||||
|
|
||||||
[Network]
|
|
||||||
# Example http://localhost:8118 (privoxy)
|
|
||||||
http_proxy =
|
|
||||||
|
|
||||||
# User Agent
|
|
||||||
user_agent = Slixfeed/0.1
|
|
||||||
|
|
||||||
# Enable policed DNS system (not recommended)
|
|
||||||
# clearnet = 1
|
|
||||||
|
|
||||||
# Enable I2P mixnet system (safer)
|
|
||||||
i2p = 1
|
|
||||||
|
|
||||||
# Enable Loki mixnet system (safer)
|
|
||||||
loki = 1
|
|
||||||
|
|
||||||
# Enable Tor semi-mixnet system (semi-safer)
|
|
||||||
tor = 1
|
|
||||||
|
|
||||||
# Enable Yggdrasil mixnet system (safer)
|
|
||||||
yggdrasil = 1
|
|
47
slixfeed/assets/settings.toml
Normal file
47
slixfeed/assets/settings.toml
Normal file
|
@ -0,0 +1,47 @@
|
||||||
|
# This file lists default settings per database.
|
||||||
|
# See file /usr/share/slixfeed/settings.toml
|
||||||
|
|
||||||
|
[default]
|
||||||
|
archive = 50 # Maximum items to archive (0 - 500)
|
||||||
|
check = 120 # Source check interval (recommended 90; minimum 10)
|
||||||
|
enabled = 1 # Work status (Value 0 to disable)
|
||||||
|
interval = 300 # Update interval (Minimum value 10)
|
||||||
|
length = 300 # Maximum length of summary (Value 0 to disable)
|
||||||
|
media = 0 # Display media (audio, image, video) when available
|
||||||
|
old = 0 # Mark entries of newly added entries as unread
|
||||||
|
quantum = 3 # Amount of entries per update
|
||||||
|
random = 0 # Pick random item from database
|
||||||
|
|
||||||
|
# Message styling is not to be modified from bot
|
||||||
|
# * title = Title of item
|
||||||
|
# * summary = Summary of item
|
||||||
|
# * link = Link of item
|
||||||
|
# * feed_title = Title of news source
|
||||||
|
# * ix = Index of item
|
||||||
|
formatting = """
|
||||||
|
{title}
|
||||||
|
> {summary}
|
||||||
|
{link}
|
||||||
|
{feed_title} [{ix}]
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# Utilized in case of missing protocol support.
|
||||||
|
[bridge]
|
||||||
|
gopher = ""
|
||||||
|
i2p = ""
|
||||||
|
ipfs = ""
|
||||||
|
nostr = ""
|
||||||
|
tor = ""
|
||||||
|
yggdrasil = ""
|
||||||
|
|
||||||
|
[network]
|
||||||
|
http_proxy = "http://localhost:8118"
|
||||||
|
user_agent = "Slixfeed/0.1"
|
||||||
|
clearnet = 0 # Enable policed DNS system (not recommended)
|
||||||
|
i2p = 1 # Enable I2P mixnet system (safer)
|
||||||
|
ipfs = 1 # Enable IPFS DHT system (safer)
|
||||||
|
loki = 1 # Enable Loki mixnet system (safer)
|
||||||
|
tor = 1 # Enable Tor semi-mixnet system (semi-safer)
|
||||||
|
yggdrasil = 1 # Enable Yggdrasil mixnet system (safer)
|
|
@ -50,26 +50,21 @@ except:
|
||||||
class Config:
|
class Config:
|
||||||
|
|
||||||
def add_settings_default(settings):
|
def add_settings_default(settings):
|
||||||
settings['default'] = {}
|
settings_default = get_values('settings.toml', 'settings')
|
||||||
for key in ('archive', 'check', 'enabled', 'filter', 'formatting',
|
settings['default'] = settings_default
|
||||||
'interval', 'length', 'media', 'old', 'quantum'):
|
|
||||||
value = get_value('settings', 'Settings', key)
|
|
||||||
settings['default'][key] = value
|
|
||||||
|
|
||||||
|
# TODO Open SQLite file once
|
||||||
def add_settings_jid(settings, jid_bare, db_file):
|
def add_settings_jid(settings, jid_bare, db_file):
|
||||||
settings[jid_bare] = {}
|
settings[jid_bare] = {}
|
||||||
for key in ('archive', 'enabled', 'filter', 'formatting', 'interval',
|
for key in ('archive', 'enabled', 'filter', 'formatting', 'interval',
|
||||||
'length', 'media', 'old', 'quantum'):
|
'length', 'media', 'old', 'quantum'):
|
||||||
value = sqlite.get_setting_value(db_file, key)
|
value = sqlite.get_setting_value(db_file, key)
|
||||||
if value: value = value[0]
|
if value: settings[jid_bare][key] = value[0]
|
||||||
settings[jid_bare][key] = value
|
|
||||||
|
|
||||||
def add_settings_xmpp(settings):
|
|
||||||
settings['xmpp'] = {}
|
|
||||||
for key in ('operator', 'reconnect_timeout', 'type'):
|
|
||||||
value = get_value('accounts', 'XMPP', key)
|
|
||||||
settings['xmpp'][key] = value
|
|
||||||
|
|
||||||
|
def get_settings_xmpp(key=None):
|
||||||
|
result = get_values('accounts.toml', 'xmpp')
|
||||||
|
result = result[key] if key else result
|
||||||
|
return result
|
||||||
|
|
||||||
async def set_setting_value(settings, jid_bare, db_file, key, val):
|
async def set_setting_value(settings, jid_bare, db_file, key, val):
|
||||||
key = key.lower()
|
key = key.lower()
|
||||||
|
@ -81,73 +76,12 @@ class Config:
|
||||||
await sqlite.set_setting_value(db_file, key_val)
|
await sqlite.set_setting_value(db_file, key_val)
|
||||||
|
|
||||||
def get_setting_value(settings, jid_bare, key):
|
def get_setting_value(settings, jid_bare, key):
|
||||||
if key in settings[jid_bare]:
|
if jid_bare in settings and key in settings[jid_bare]:
|
||||||
value = settings[jid_bare][key]
|
value = settings[jid_bare][key]
|
||||||
else:
|
else:
|
||||||
value = settings['default'][key]
|
value = settings['default'][key]
|
||||||
return value
|
return value
|
||||||
|
|
||||||
|
|
||||||
# self.settings = {}
|
|
||||||
# initiate an empty dict and the rest would be:
|
|
||||||
# settings['account'] = {}
|
|
||||||
# settings['default'] = {}
|
|
||||||
# settings['jabber@id'] = {}
|
|
||||||
# def __init__(self, db_file):
|
|
||||||
# self.archive = get_setting_value(db_file, 'archive')
|
|
||||||
# self.enabled = get_setting_value(db_file, 'enabled')
|
|
||||||
# self.formatting = get_setting_value(db_file, 'formatting')
|
|
||||||
# self.interval = get_setting_value(db_file, 'interval')
|
|
||||||
# self.length = get_setting_value(db_file, 'length')
|
|
||||||
# self.media = get_setting_value(db_file, 'media')
|
|
||||||
# self.old = get_setting_value(db_file, 'old')
|
|
||||||
# self.quantum = get_setting_value(db_file, 'quantum')
|
|
||||||
|
|
||||||
# def default():
|
|
||||||
# archive = get_value('settings', 'Settings', 'archive')
|
|
||||||
# enabled = get_value('settings', 'Settings', 'enabled')
|
|
||||||
# formatting = get_value('settings', 'Settings', 'formatting')
|
|
||||||
# interval = get_value('settings', 'Settings', 'interval')
|
|
||||||
# length = get_value('settings', 'Settings', 'length')
|
|
||||||
# media = get_value('settings', 'Settings', 'media')
|
|
||||||
# old = get_value('settings', 'Settings', 'old')
|
|
||||||
# quantum = get_value('settings', 'Settings', 'quantum')
|
|
||||||
|
|
||||||
# def jid(db_file):
|
|
||||||
# archive = sqlite.get_setting_value(db_file, 'archive')
|
|
||||||
# enabled = sqlite.get_setting_value(db_file, 'enabled')
|
|
||||||
# formatting = sqlite.get_setting_value(db_file, 'formatting')
|
|
||||||
# interval = sqlite.get_setting_value(db_file, 'interval')
|
|
||||||
# length = sqlite.get_setting_value(db_file, 'length')
|
|
||||||
# media = sqlite.get_setting_value(db_file, 'media')
|
|
||||||
# old = sqlite.get_setting_value(db_file, 'old')
|
|
||||||
# quantum = sqlite.get_setting_value(db_file, 'quantum')
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigXMPP:
|
|
||||||
def __init__(self):
|
|
||||||
self.setting = {}
|
|
||||||
for key in ('operator', 'reconnect_timeout', 'type'):
|
|
||||||
value = get_value('accounts', 'XMPP', key)
|
|
||||||
self.setting[key] = value
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigClient:
|
|
||||||
def __init__(self):
|
|
||||||
self.setting = {}
|
|
||||||
for key in ('alias', 'jid', 'operator', 'password', 'hostname', 'port'):
|
|
||||||
value = get_value('accounts', 'XMPP Client', key)
|
|
||||||
self.setting[key] = value
|
|
||||||
|
|
||||||
|
|
||||||
class ConfigDefault:
|
|
||||||
def __init__(self, settings):
|
|
||||||
settings['default'] = {}
|
|
||||||
for key in ('archive', 'check', 'enabled', 'filter', 'formatting',
|
|
||||||
'interval', 'length', 'media', 'old', 'quantum'):
|
|
||||||
value = get_value('settings', 'Settings', key)
|
|
||||||
settings['default'][key] = value
|
|
||||||
|
|
||||||
class ConfigNetwork:
|
class ConfigNetwork:
|
||||||
def __init__(self, settings):
|
def __init__(self, settings):
|
||||||
settings['network'] = {}
|
settings['network'] = {}
|
||||||
|
@ -167,6 +101,19 @@ class ConfigJabberID:
|
||||||
settings[jid_bare][key] = value
|
settings[jid_bare][key] = value
|
||||||
|
|
||||||
|
|
||||||
|
def get_values(filename, key=None):
|
||||||
|
config_dir = get_default_config_directory()
|
||||||
|
if not os.path.isdir(config_dir):
|
||||||
|
config_dir = '/usr/share/slixfeed/'
|
||||||
|
if not os.path.isdir(config_dir):
|
||||||
|
config_dir = os.path.dirname(__file__) + "/assets"
|
||||||
|
config_file = os.path.join(config_dir, filename)
|
||||||
|
with open(config_file, mode="rb") as defaults:
|
||||||
|
result = tomllib.load(defaults)
|
||||||
|
values = result[key] if key else result
|
||||||
|
return values
|
||||||
|
|
||||||
|
|
||||||
def get_setting_value(db_file, key):
|
def get_setting_value(db_file, key):
|
||||||
value = sqlite.get_setting_value(db_file, key)
|
value = sqlite.get_setting_value(db_file, key)
|
||||||
if value:
|
if value:
|
||||||
|
@ -299,9 +246,7 @@ def get_value(filename, section, keys):
|
||||||
for key in keys:
|
for key in keys:
|
||||||
if key in section_res:
|
if key in section_res:
|
||||||
value = section_res[key]
|
value = section_res[key]
|
||||||
logging.debug(
|
logging.debug("Found value {} for key {}".format(value, key))
|
||||||
"Found value {} for key {}".format(value, key)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
value = ''
|
value = ''
|
||||||
logging.debug("Missing key:", key)
|
logging.debug("Missing key:", key)
|
||||||
|
@ -310,9 +255,7 @@ def get_value(filename, section, keys):
|
||||||
key = keys
|
key = keys
|
||||||
if key in section_res:
|
if key in section_res:
|
||||||
result = section_res[key]
|
result = section_res[key]
|
||||||
logging.debug(
|
logging.debug("Found value {} for key {}".format(result, key))
|
||||||
"Found value {} for key {}".format(result, key)
|
|
||||||
)
|
|
||||||
else:
|
else:
|
||||||
result = ''
|
result = ''
|
||||||
# logging.error("Missing key:", key)
|
# logging.error("Missing key:", key)
|
||||||
|
|
|
@ -119,10 +119,11 @@ async def http(url):
|
||||||
msg: list or str
|
msg: list or str
|
||||||
Document or error message.
|
Document or error message.
|
||||||
"""
|
"""
|
||||||
user_agent = (config.get_value("settings", "Network", "user_agent")
|
user_agent = (config.get_values('settings.toml', 'network')['user_agent']
|
||||||
or 'Slixfeed/0.1')
|
or 'Slixfeed/0.1')
|
||||||
headers = {'User-Agent': user_agent}
|
headers = {'User-Agent': user_agent}
|
||||||
proxy = (config.get_value("settings", "Network", "http_proxy") or '')
|
proxy = (config.get_values('settings.toml', 'network')['http_proxy']
|
||||||
|
or '')
|
||||||
timeout = ClientTimeout(total=10)
|
timeout = ClientTimeout(total=10)
|
||||||
async with ClientSession(headers=headers) as session:
|
async with ClientSession(headers=headers) as session:
|
||||||
# async with ClientSession(trust_env=True) as session:
|
# async with ClientSession(trust_env=True) as session:
|
||||||
|
|
|
@ -2243,7 +2243,7 @@ def get_feeds(db_file):
|
||||||
cur = conn.cursor()
|
cur = conn.cursor()
|
||||||
sql = (
|
sql = (
|
||||||
"""
|
"""
|
||||||
SELECT name, url, id
|
SELECT id, name, url
|
||||||
FROM feeds
|
FROM feeds
|
||||||
"""
|
"""
|
||||||
)
|
)
|
||||||
|
|
|
@ -172,7 +172,7 @@ async def task_send(self, jid_bare):
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
if jid_bare not in self.settings:
|
if jid_bare not in self.settings:
|
||||||
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
||||||
update_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
update_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
update_interval = 60 * int(update_interval)
|
update_interval = 60 * int(update_interval)
|
||||||
last_update_time = sqlite.get_last_update_time(db_file)
|
last_update_time = sqlite.get_last_update_time(db_file)
|
||||||
if last_update_time:
|
if last_update_time:
|
||||||
|
@ -232,7 +232,7 @@ def refresh_task(self, jid_bare, callback, key, val=None):
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
if jid_bare not in self.settings:
|
if jid_bare not in self.settings:
|
||||||
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
||||||
val = self.settings[jid_bare][key] or self.settings['default'][key]
|
val = Config.get_setting_value(self.settings, jid_bare, key)
|
||||||
# if self.task_manager[jid][key]:
|
# if self.task_manager[jid][key]:
|
||||||
if jid_bare in self.task_manager:
|
if jid_bare in self.task_manager:
|
||||||
try:
|
try:
|
||||||
|
@ -268,7 +268,7 @@ async def wait_and_run(self, callback, jid_bare, val):
|
||||||
|
|
||||||
# TODO Take this function out of
|
# TODO Take this function out of
|
||||||
# <class 'slixmpp.clientxmpp.ClientXMPP'>
|
# <class 'slixmpp.clientxmpp.ClientXMPP'>
|
||||||
async def check_updates(self, jid):
|
async def check_updates(self, jid_bare):
|
||||||
"""
|
"""
|
||||||
Start calling for update check up.
|
Start calling for update check up.
|
||||||
|
|
||||||
|
@ -277,15 +277,15 @@ async def check_updates(self, jid):
|
||||||
jid : str
|
jid : str
|
||||||
Jabber ID.
|
Jabber ID.
|
||||||
"""
|
"""
|
||||||
logging.info('Scanning for updates for JID {}'.format(jid))
|
logging.info('Scanning for updates for JID {}'.format(jid_bare))
|
||||||
while True:
|
while True:
|
||||||
jid_file = jid.replace('/', '_')
|
jid_file = jid_bare.replace('/', '_')
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
urls = sqlite.get_active_feeds_url(db_file)
|
urls = sqlite.get_active_feeds_url(db_file)
|
||||||
for url in urls:
|
for url in urls:
|
||||||
await action.scan(self, jid, db_file, url)
|
await action.scan(self, jid_bare, db_file, url)
|
||||||
await asyncio.sleep(50)
|
await asyncio.sleep(50)
|
||||||
val = self.settings['default']['check']
|
val = Config.get_setting_value(self.settings, jid_bare, 'check')
|
||||||
await asyncio.sleep(60 * float(val))
|
await asyncio.sleep(60 * float(val))
|
||||||
# Schedule to call this function again in 90 minutes
|
# Schedule to call this function again in 90 minutes
|
||||||
# loop.call_at(
|
# loop.call_at(
|
||||||
|
|
|
@ -1,2 +1,2 @@
|
||||||
__version__ = '0.1.36'
|
__version__ = '0.1.37'
|
||||||
__version_info__ = (0, 1, 36)
|
__version_info__ = (0, 1, 37)
|
||||||
|
|
|
@ -55,7 +55,7 @@ import slixfeed.xmpp.profile as profile
|
||||||
from slixfeed.xmpp.roster import XmppRoster
|
from slixfeed.xmpp.roster import XmppRoster
|
||||||
# import slixfeed.xmpp.service as service
|
# import slixfeed.xmpp.service as service
|
||||||
from slixfeed.xmpp.presence import XmppPresence
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
from slixfeed.xmpp.utility import get_chat_type
|
from slixfeed.xmpp.utility import get_chat_type, is_operator
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -70,6 +70,7 @@ import logging
|
||||||
import os
|
import os
|
||||||
import slixfeed.action as action
|
import slixfeed.action as action
|
||||||
import slixfeed.config as config
|
import slixfeed.config as config
|
||||||
|
from slixfeed.config import Config
|
||||||
import slixfeed.crawl as crawl
|
import slixfeed.crawl as crawl
|
||||||
import slixfeed.dt as dt
|
import slixfeed.dt as dt
|
||||||
import slixfeed.fetch as fetch
|
import slixfeed.fetch as fetch
|
||||||
|
@ -123,14 +124,18 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
self.task_ping_instance = {}
|
self.task_ping_instance = {}
|
||||||
|
|
||||||
# Handler for configuration
|
# Handler for configuration
|
||||||
self.settings = {}
|
self.settings = config.get_values('settings.toml')
|
||||||
# Populate handler
|
# Handler for operators
|
||||||
Config.add_settings_default(self.settings)
|
self.operators = config.get_values('accounts.toml', 'xmpp')['operators']
|
||||||
Config.add_settings_xmpp(self.settings)
|
|
||||||
|
# self.settings = {}
|
||||||
|
# # Populate dict handler
|
||||||
|
# Config.add_settings_default(self.settings)
|
||||||
|
|
||||||
# Handlers for connection events
|
# Handlers for connection events
|
||||||
self.connection_attempts = 0
|
self.connection_attempts = 0
|
||||||
self.max_connection_attempts = 10
|
self.max_connection_attempts = 10
|
||||||
|
self.reconnect_timeout = config.get_values('accounts.toml', 'xmpp')['settings']['reconnect_timeout']
|
||||||
|
|
||||||
self.add_event_handler("session_start",
|
self.add_event_handler("session_start",
|
||||||
self.on_session_start)
|
self.on_session_start)
|
||||||
|
@ -261,16 +266,14 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
function_name = sys._getframe().f_code.co_name
|
function_name = sys._getframe().f_code.co_name
|
||||||
message_log = '{}'
|
message_log = '{}'
|
||||||
logger.debug(message_log.format(function_name))
|
logger.debug(message_log.format(function_name))
|
||||||
jid_operator = config.get_value('accounts', 'XMPP', 'operator')
|
status_message = 'Slixfeed version {}'.format(__version__)
|
||||||
if jid_operator:
|
for operator in self.operators:
|
||||||
status_message = ('Wait while Slixfeed {} is being loaded...'
|
XmppPresence.send(self, operator['jid'], status_message)
|
||||||
.format(__version__))
|
|
||||||
XmppPresence.send(self, jid_operator, status_message)
|
|
||||||
await profile.update(self)
|
await profile.update(self)
|
||||||
profile.set_identity(self, 'client')
|
profile.set_identity(self, 'client')
|
||||||
await self['xep_0115'].update_caps()
|
await self['xep_0115'].update_caps()
|
||||||
# self.send_presence()
|
# self.send_presence()
|
||||||
# await self.get_roster()
|
await self.get_roster()
|
||||||
bookmarks = await self.plugin['xep_0048'].get_bookmarks()
|
bookmarks = await self.plugin['xep_0048'].get_bookmarks()
|
||||||
XmppGroupchat.autojoin(self, bookmarks)
|
XmppGroupchat.autojoin(self, bookmarks)
|
||||||
# XmppCommand.adhoc_commands(self)
|
# XmppCommand.adhoc_commands(self)
|
||||||
|
@ -335,16 +338,16 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
XmppPresence.send(self, jid_bare, status_message)
|
XmppPresence.send(self, jid_bare, status_message)
|
||||||
else:
|
else:
|
||||||
# TODO Request for subscription
|
# TODO Request for subscription
|
||||||
if (await get_chat_type(self, jid_bare) == 'chat' and
|
# if (await get_chat_type(self, jid_bare) == 'chat' and
|
||||||
not self.client_roster[jid_bare]['to']):
|
# not self.client_roster[jid_bare]['to']):
|
||||||
XmppPresence.subscription(self, jid_bare, 'subscribe')
|
# XmppPresence.subscription(self, jid_bare, 'subscribe')
|
||||||
await XmppRoster.add(self, jid_bare)
|
# await XmppRoster.add(self, jid_bare)
|
||||||
status_message = '✒️ Share online status to receive updates'
|
# status_message = '✒️ Share online status to receive updates'
|
||||||
XmppPresence.send(self, jid_bare, status_message)
|
# XmppPresence.send(self, jid_bare, status_message)
|
||||||
message_subject = 'RSS News Bot'
|
# message_subject = 'RSS News Bot'
|
||||||
message_body = 'Share online status to receive updates.'
|
# message_body = 'Share online status to receive updates.'
|
||||||
XmppMessage.send_headline(self, jid_bare, message_subject,
|
# XmppMessage.send_headline(self, jid_bare, message_subject,
|
||||||
message_body, 'chat')
|
# message_body, 'chat')
|
||||||
await process.message(self, message)
|
await process.message(self, message)
|
||||||
# chat_type = message["type"]
|
# chat_type = message["type"]
|
||||||
# message_body = message["body"]
|
# message_body = message["body"]
|
||||||
|
@ -671,13 +674,16 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# NOTE https://codeberg.org/poezio/slixmpp/issues/3515
|
# NOTE https://codeberg.org/poezio/slixmpp/issues/3515
|
||||||
# if jid == self.settings['xmpp']['operator']:
|
# if is_operator(self, jid_bare):
|
||||||
self['xep_0050'].add_command(node='recent',
|
self['xep_0050'].add_command(node='recent',
|
||||||
name='📰️ Browse',
|
name='📰️ Browse',
|
||||||
handler=self._handle_recent)
|
handler=self._handle_recent)
|
||||||
self['xep_0050'].add_command(node='subscription',
|
self['xep_0050'].add_command(node='subscription',
|
||||||
name='🪶️ Subscribe',
|
name='🪶️ Subscribe',
|
||||||
handler=self._handle_subscription_add)
|
handler=self._handle_subscription_add)
|
||||||
|
self['xep_0050'].add_command(node='publish',
|
||||||
|
name='📣️ Publish',
|
||||||
|
handler=self._handle_publish)
|
||||||
self['xep_0050'].add_command(node='subscriptions',
|
self['xep_0050'].add_command(node='subscriptions',
|
||||||
name='🎫️ Subscriptions',
|
name='🎫️ Subscriptions',
|
||||||
handler=self._handle_subscriptions)
|
handler=self._handle_subscriptions)
|
||||||
|
@ -712,6 +718,42 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# Special interface
|
# Special interface
|
||||||
# http://jabber.org/protocol/commands#actions
|
# http://jabber.org/protocol/commands#actions
|
||||||
|
|
||||||
|
async def _handle_publish(self, iq, session):
|
||||||
|
form = self['xep_0004'].make_form('form', 'Publish')
|
||||||
|
form['instructions'] = ('In order to publish via Pubsub Social Feed '
|
||||||
|
'(XEP-0472), you will have to choose a '
|
||||||
|
'Publish-Subscribe (XEP-0060) hostname and '
|
||||||
|
'be permitted to publish into it.')
|
||||||
|
# TODO Select from list-multi
|
||||||
|
form.add_field(var='subscription',
|
||||||
|
ftype='text-single',
|
||||||
|
label='URL',
|
||||||
|
desc='Enter subscription URL.',
|
||||||
|
value='http://',
|
||||||
|
required=True)
|
||||||
|
form.add_field(var='subscription',
|
||||||
|
ftype='text-single',
|
||||||
|
label='PubSub',
|
||||||
|
desc='Enter a PubSub URL.',
|
||||||
|
value='pubsub.' + self.boundjid.host,
|
||||||
|
required=True)
|
||||||
|
session['allow_prev'] = False
|
||||||
|
session['has_next'] = True
|
||||||
|
session['next'] = self._handle_preview
|
||||||
|
session['prev'] = None
|
||||||
|
session['payload'] = form
|
||||||
|
return session
|
||||||
|
|
||||||
|
def _handle_preview(self, payload, session):
|
||||||
|
jid_full = str(session['from'])
|
||||||
|
function_name = sys._getframe().f_code.co_name
|
||||||
|
logger.debug('{}: jid_full: {}'
|
||||||
|
.format(function_name, jid_full))
|
||||||
|
text_note = ('XEP-0472: Pubsub Social Feed will be available soon.')
|
||||||
|
session['notes'] = [['info', text_note]]
|
||||||
|
session['payload'] = None
|
||||||
|
return session
|
||||||
|
|
||||||
async def _handle_profile(self, iq, session):
|
async def _handle_profile(self, iq, session):
|
||||||
jid_full = str(session['from'])
|
jid_full = str(session['from'])
|
||||||
function_name = sys._getframe().f_code.co_name
|
function_name = sys._getframe().f_code.co_name
|
||||||
|
@ -747,42 +789,42 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
value=unread)
|
value=unread)
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Options')
|
value='Options')
|
||||||
key_archive = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
key_archive = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
key_archive = str(key_archive)
|
key_archive = str(key_archive)
|
||||||
form.add_field(label='Archive',
|
form.add_field(label='Archive',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_archive)
|
value=key_archive)
|
||||||
key_enabled = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
key_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
key_enabled = str(key_enabled)
|
key_enabled = str(key_enabled)
|
||||||
form.add_field(label='Enabled',
|
form.add_field(label='Enabled',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_enabled)
|
value=key_enabled)
|
||||||
key_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
key_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
key_interval = str(key_interval)
|
key_interval = str(key_interval)
|
||||||
form.add_field(label='Interval',
|
form.add_field(label='Interval',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_interval)
|
value=key_interval)
|
||||||
key_length = self.settings[jid_bare]['length'] or self.settings['default']['length']
|
key_length = Config.get_setting_value(self.settings, jid_bare, 'length')
|
||||||
key_length = str(key_length)
|
key_length = str(key_length)
|
||||||
form.add_field(label='Length',
|
form.add_field(label='Length',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_length)
|
value=key_length)
|
||||||
key_media = self.settings[jid_bare]['media'] or self.settings['default']['media']
|
key_media = Config.get_setting_value(self.settings, jid_bare, 'media')
|
||||||
key_media = str(key_media)
|
key_media = str(key_media)
|
||||||
form.add_field(label='Media',
|
form.add_field(label='Media',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_media)
|
value=key_media)
|
||||||
key_old = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
key_old = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
key_old = str(key_old)
|
key_old = str(key_old)
|
||||||
form.add_field(label='Old',
|
form.add_field(label='Old',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_old)
|
value=key_old)
|
||||||
key_quantum = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum']
|
key_quantum = Config.get_setting_value(self.settings, jid_bare, 'quantum')
|
||||||
key_quantum = str(key_quantum)
|
key_quantum = str(key_quantum)
|
||||||
form.add_field(label='Quantum',
|
form.add_field(label='Quantum',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_quantum)
|
value=key_quantum)
|
||||||
update_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
update_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
update_interval = str(update_interval)
|
update_interval = str(update_interval)
|
||||||
update_interval = 60 * int(update_interval)
|
update_interval = 60 * int(update_interval)
|
||||||
last_update_time = sqlite.get_last_update_time(db_file)
|
last_update_time = sqlite.get_last_update_time(db_file)
|
||||||
|
@ -797,7 +839,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
else:
|
else:
|
||||||
next_update = 'n/a'
|
next_update = 'n/a'
|
||||||
else:
|
else:
|
||||||
last_update_time = 'n/a'
|
last_update = 'n/a'
|
||||||
next_update = 'n/a'
|
next_update = 'n/a'
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Schedule')
|
value='Schedule')
|
||||||
|
@ -1394,8 +1436,10 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
.format(function_name, jid_full))
|
.format(function_name, jid_full))
|
||||||
jid_bare = session['from'].bare
|
jid_bare = session['from'].bare
|
||||||
chat_type = await get_chat_type(self, jid_bare)
|
chat_type = await get_chat_type(self, jid_bare)
|
||||||
|
moderator = None
|
||||||
if chat_type == 'groupchat':
|
if chat_type == 'groupchat':
|
||||||
moderator = is_moderator(self, jid_bare, jid_full)
|
moderator = is_moderator(self, jid_bare, jid_full)
|
||||||
|
# moderator = moderator if moderator else None
|
||||||
if chat_type == 'chat' or moderator:
|
if chat_type == 'chat' or moderator:
|
||||||
form = self['xep_0004'].make_form('form', 'Discover & Search')
|
form = self['xep_0004'].make_form('form', 'Discover & Search')
|
||||||
form['instructions'] = 'Discover news subscriptions of all kinds'
|
form['instructions'] = 'Discover news subscriptions of all kinds'
|
||||||
|
@ -1557,10 +1601,10 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
desc=('Select a subscription to edit.'),
|
desc=('Select a subscription to edit.'),
|
||||||
required=True)
|
required=True)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
options.addOption(title, url)
|
options.addOption(title, url)
|
||||||
session['has_next'] = True
|
session['has_next'] = True
|
||||||
session['next'] = self._handle_subscription_editor
|
session['next'] = self._handle_subscription_editor
|
||||||
|
@ -1576,10 +1620,10 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
desc=('Select subscriptions to remove.'),
|
desc=('Select subscriptions to remove.'),
|
||||||
required=True)
|
required=True)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
ix = str(subscription[2])
|
ix = str(subscription[0])
|
||||||
options.addOption(title, ix)
|
options.addOption(title, ix)
|
||||||
session['cancel'] = self._handle_cancel
|
session['cancel'] = self._handle_cancel
|
||||||
session['has_next'] = False
|
session['has_next'] = False
|
||||||
|
@ -1693,8 +1737,8 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# subscriptions = set(subscriptions)
|
# subscriptions = set(subscriptions)
|
||||||
categorized_subscriptions = {}
|
categorized_subscriptions = {}
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
try:
|
try:
|
||||||
letter = title[0].capitalize()
|
letter = title[0].capitalize()
|
||||||
if letter not in categorized_subscriptions:
|
if letter not in categorized_subscriptions:
|
||||||
|
@ -1906,10 +1950,10 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
jid_file = jid_bare
|
jid_file = jid_bare
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
options.addOption(title, url)
|
options.addOption(title, url)
|
||||||
# options = form.add_field(var='action',
|
# options = form.add_field(var='action',
|
||||||
# ftype='list-single',
|
# ftype='list-single',
|
||||||
|
@ -1949,7 +1993,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
options.addOption('Import', 'import')
|
options.addOption('Import', 'import')
|
||||||
options.addOption('Export', 'export')
|
options.addOption('Export', 'export')
|
||||||
jid = session['from'].bare
|
jid = session['from'].bare
|
||||||
if jid == self.settings['xmpp']['operator']:
|
if is_operator(self, jid):
|
||||||
options.addOption('Administration', 'admin')
|
options.addOption('Administration', 'admin')
|
||||||
session['payload'] = form
|
session['payload'] = form
|
||||||
session['next'] = self._handle_advanced_result
|
session['next'] = self._handle_advanced_result
|
||||||
|
@ -1976,7 +2020,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# NOTE Even though this check is already conducted on previous
|
# NOTE Even though this check is already conducted on previous
|
||||||
# form, this check is being done just in case.
|
# form, this check is being done just in case.
|
||||||
jid_bare = session['from'].bare
|
jid_bare = session['from'].bare
|
||||||
if jid_bare == self.settings['xmpp']['operator']:
|
if is_operator(self, jid_bare):
|
||||||
if self.is_component:
|
if self.is_component:
|
||||||
# NOTE This will be changed with XEP-0222 XEP-0223
|
# NOTE This will be changed with XEP-0222 XEP-0223
|
||||||
text_info = ('Subscriber management options are '
|
text_info = ('Subscriber management options are '
|
||||||
|
@ -2076,9 +2120,10 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
options = form.add_field(var='option',
|
options = form.add_field(var='option',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
label='About',
|
label='About',
|
||||||
required=True)
|
required=True,
|
||||||
|
value='about')
|
||||||
config_dir = config.get_default_config_directory()
|
config_dir = config.get_default_config_directory()
|
||||||
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
with open(config_dir + '/' + 'about.toml', mode="rb") as information:
|
||||||
entries = tomllib.load(information)
|
entries = tomllib.load(information)
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
label = entries[entry][0]['title']
|
label = entries[entry][0]['title']
|
||||||
|
@ -2096,7 +2141,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
logger.debug('{}: jid_full: {}'
|
logger.debug('{}: jid_full: {}'
|
||||||
.format(function_name, jid_full))
|
.format(function_name, jid_full))
|
||||||
config_dir = config.get_default_config_directory()
|
config_dir = config.get_default_config_directory()
|
||||||
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
with open(config_dir + '/' + 'about.toml', mode="rb") as information:
|
||||||
entries = tomllib.load(information)
|
entries = tomllib.load(information)
|
||||||
entry_key = payload['values']['option']
|
entry_key = payload['values']['option']
|
||||||
# case 'terms':
|
# case 'terms':
|
||||||
|
@ -2174,7 +2219,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
cmds = tomllib.load(commands)
|
cmds = tomllib.load(commands)
|
||||||
|
|
||||||
form = self['xep_0004'].make_form('result', 'Manual')
|
form = self['xep_0004'].make_form('result', 'Manual')
|
||||||
form['instructions'] = '🛟️ Help manual for interactive chat'
|
form['instructions'] = 'Help manual for interactive chat'
|
||||||
|
|
||||||
# text = '🛟️ Help and Information about Slixfeed\n\n'
|
# text = '🛟️ Help and Information about Slixfeed\n\n'
|
||||||
# for cmd in cmds:
|
# for cmd in cmds:
|
||||||
|
@ -2350,7 +2395,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
jid_file = jid_bare
|
jid_file = jid_bare
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
form = self['xep_0004'].make_form('form', 'Subscriptions')
|
form = self['xep_0004'].make_form('form', 'Subscriptions')
|
||||||
match payload['values']['action']:
|
match payload['values']['action']:
|
||||||
case 'bookmarks':
|
case 'bookmarks':
|
||||||
|
@ -2680,7 +2725,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
||||||
form = self['xep_0004'].make_form('form', 'Settings')
|
form = self['xep_0004'].make_form('form', 'Settings')
|
||||||
form['instructions'] = 'Editing settings'
|
form['instructions'] = 'Editing settings'
|
||||||
value = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
value = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2692,7 +2737,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
label='Enabled',
|
label='Enabled',
|
||||||
desc='Enable news updates.',
|
desc='Enable news updates.',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['media'] or self.settings['default']['media']
|
value = Config.get_setting_value(self.settings, jid_bare, 'media')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2704,7 +2749,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
desc='Send audio, images or videos if found.',
|
desc='Send audio, images or videos if found.',
|
||||||
label='Display media',
|
label='Display media',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
value = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2717,7 +2762,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
# label='Send only new items',
|
# label='Send only new items',
|
||||||
label='Include old news',
|
label='Include old news',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
value = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
value = value/60
|
value = value/60
|
||||||
|
@ -2738,7 +2783,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
i += 6
|
i += 6
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
value = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum']
|
value = Config.get_setting_value(self.settings, jid_bare, 'quantum')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
options = form.add_field(var='quantum',
|
options = form.add_field(var='quantum',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
|
@ -2752,7 +2797,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
x = str(i)
|
x = str(i)
|
||||||
options.addOption(x, x)
|
options.addOption(x, x)
|
||||||
i += 1
|
i += 1
|
||||||
value = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
value = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
options = form.add_field(var='archive',
|
options = form.add_field(var='archive',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
|
@ -2807,7 +2852,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
||||||
if val < 1: val = 1
|
if val < 1: val = 1
|
||||||
val = val * 60
|
val = val * 60
|
||||||
|
|
||||||
is_enabled = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
is_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
|
|
||||||
if (key == 'enabled' and
|
if (key == 'enabled' and
|
||||||
val == 1 and
|
val == 1 and
|
||||||
|
|
|
@ -36,7 +36,7 @@ from slixfeed.log import Logger
|
||||||
from slixfeed.version import __version__
|
from slixfeed.version import __version__
|
||||||
from slixfeed.xmpp.connect import XmppConnect
|
from slixfeed.xmpp.connect import XmppConnect
|
||||||
# NOTE MUC is possible for component
|
# NOTE MUC is possible for component
|
||||||
# from slixfeed.xmpp.muc import XmppGroupchat
|
from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
from slixfeed.xmpp.message import XmppMessage
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
import slixfeed.xmpp.process as process
|
import slixfeed.xmpp.process as process
|
||||||
import slixfeed.xmpp.profile as profile
|
import slixfeed.xmpp.profile as profile
|
||||||
|
@ -46,7 +46,7 @@ from slixfeed.xmpp.presence import XmppPresence
|
||||||
# from slixmpp.xmlstream import ET
|
# from slixmpp.xmlstream import ET
|
||||||
# from slixmpp.xmlstream.handler import Callback
|
# from slixmpp.xmlstream.handler import Callback
|
||||||
# from slixmpp.xmlstream.matcher import MatchXPath
|
# from slixmpp.xmlstream.matcher import MatchXPath
|
||||||
from slixfeed.xmpp.utility import get_chat_type
|
from slixfeed.xmpp.utility import get_chat_type, is_operator
|
||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
@ -115,14 +115,18 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
self.task_ping_instance = {}
|
self.task_ping_instance = {}
|
||||||
|
|
||||||
# Handler for configuration
|
# Handler for configuration
|
||||||
self.settings = {}
|
self.settings = config.get_values('settings.toml')
|
||||||
# Populate handler
|
# Handler for operators
|
||||||
Config.add_settings_default(self.settings)
|
self.operators = config.get_values('accounts.toml', 'xmpp')['operators']
|
||||||
Config.add_settings_xmpp(self.settings)
|
|
||||||
|
# self.settings = {}
|
||||||
|
# # Populate dict handler
|
||||||
|
# Config.add_settings_default(self.settings)
|
||||||
|
|
||||||
# Handlers for connection events
|
# Handlers for connection events
|
||||||
self.connection_attempts = 0
|
self.connection_attempts = 0
|
||||||
self.max_connection_attempts = 10
|
self.max_connection_attempts = 10
|
||||||
|
self.reconnect_timeout = config.get_values('accounts.toml', 'xmpp')['settings']['reconnect_timeout']
|
||||||
|
|
||||||
self.add_event_handler("session_start",
|
self.add_event_handler("session_start",
|
||||||
self.on_session_start)
|
self.on_session_start)
|
||||||
|
@ -155,10 +159,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
self.add_event_handler("message",
|
self.add_event_handler("message",
|
||||||
self.on_message)
|
self.on_message)
|
||||||
|
|
||||||
# self.add_event_handler("groupchat_invite",
|
self.add_event_handler("groupchat_invite",
|
||||||
# self.on_groupchat_invite) # XEP_0045
|
self.on_groupchat_invite) # XEP_0045
|
||||||
# self.add_event_handler("groupchat_direct_invite",
|
self.add_event_handler("groupchat_direct_invite",
|
||||||
# self.on_groupchat_direct_invite) # XEP_0249
|
self.on_groupchat_direct_invite) # XEP_0249
|
||||||
# self.add_event_handler("groupchat_message", self.message)
|
# self.add_event_handler("groupchat_message", self.message)
|
||||||
|
|
||||||
# self.add_event_handler("disconnected", self.reconnect)
|
# self.add_event_handler("disconnected", self.reconnect)
|
||||||
|
@ -184,19 +188,19 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
self.on_session_end)
|
self.on_session_end)
|
||||||
|
|
||||||
|
|
||||||
# async def on_groupchat_invite(self, message):
|
async def on_groupchat_invite(self, message):
|
||||||
# logging.warning("on_groupchat_invite")
|
# logging.warning("on_groupchat_invite")
|
||||||
# inviter = message['from'].bare
|
inviter = message['from'].bare
|
||||||
# muc_jid = message['groupchat_invite']['jid']
|
muc_jid = message['groupchat_invite']['jid']
|
||||||
# await muc.join(self, inviter, muc_jid)
|
XmppGroupchat.join(self, inviter, muc_jid)
|
||||||
# await bookmark.add(self, muc_jid)
|
# await bookmark.add(self, muc_jid)
|
||||||
|
|
||||||
|
|
||||||
# NOTE Tested with Gajim and Psi
|
# NOTE Tested with Gajim and Psi
|
||||||
# async def on_groupchat_direct_invite(self, message):
|
async def on_groupchat_direct_invite(self, message):
|
||||||
# inviter = message['from'].bare
|
inviter = message['from'].bare
|
||||||
# muc_jid = message['groupchat_invite']['jid']
|
muc_jid = message['groupchat_invite']['jid']
|
||||||
# await muc.join(self, inviter, muc_jid)
|
XmppGroupchat.join(self, inviter, muc_jid)
|
||||||
# await bookmark.add(self, muc_jid)
|
# await bookmark.add(self, muc_jid)
|
||||||
|
|
||||||
|
|
||||||
|
@ -234,10 +238,9 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
task.task_ping(self)
|
task.task_ping(self)
|
||||||
# bookmarks = await self.plugin['xep_0048'].get_bookmarks()
|
# bookmarks = await self.plugin['xep_0048'].get_bookmarks()
|
||||||
# XmppGroupchat.autojoin(self, bookmarks)
|
# XmppGroupchat.autojoin(self, bookmarks)
|
||||||
jid_operator = config.get_value('accounts', 'XMPP', 'operator')
|
status_message = 'Slixfeed version {}'.format(__version__)
|
||||||
if jid_operator:
|
for operator in self.operators:
|
||||||
status_message = 'Slixfeed version {}'.format(__version__)
|
XmppPresence.send(self, operator['jid'], status_message)
|
||||||
XmppPresence.send(self, jid_operator, status_message)
|
|
||||||
time_end = time.time()
|
time_end = time.time()
|
||||||
difference = time_end - time_begin
|
difference = time_end - time_begin
|
||||||
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
|
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
|
||||||
|
@ -346,7 +349,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
if not self.client_roster[jid_bare]['to']:
|
if not self.client_roster[jid_bare]['to']:
|
||||||
# XmppPresence.subscription(self, jid, 'subscribe')
|
# XmppPresence.subscription(self, jid, 'subscribe')
|
||||||
XmppPresence.subscription(self, jid_bare, 'subscribed')
|
XmppPresence.subscription(self, jid_bare, 'subscribed')
|
||||||
await XmppRoster.add(self, jid_bare)
|
# await XmppRoster.add(self, jid_bare)
|
||||||
status_message = '✒️ Share online status to receive updates'
|
status_message = '✒️ Share online status to receive updates'
|
||||||
XmppPresence.send(self, jid_bare, status_message)
|
XmppPresence.send(self, jid_bare, status_message)
|
||||||
message_subject = 'RSS News Bot'
|
message_subject = 'RSS News Bot'
|
||||||
|
@ -418,9 +421,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# status_message = None
|
# status_message = None
|
||||||
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
XmppMessage.send(self, jid_bare, message_body, 'chat')
|
||||||
XmppPresence.subscription(self, jid_bare, 'unsubscribed')
|
XmppPresence.subscription(self, jid_bare, 'unsubscribed')
|
||||||
# XmppPresence.send(self, jid, status_message,
|
# status_message = '🖋️ You have been uubscribed'
|
||||||
|
# XmppPresence.send(self, jid_bare, status_message,
|
||||||
# presence_type='unsubscribed')
|
# presence_type='unsubscribed')
|
||||||
XmppRoster.remove(self, jid_bare)
|
# XmppRoster.remove(self, jid_bare)
|
||||||
time_end = time.time()
|
time_end = time.time()
|
||||||
difference = time_end - time_begin
|
difference = time_end - time_begin
|
||||||
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
|
if difference > 1: logger.warning('{} (time: {})'.format(function_name,
|
||||||
|
@ -631,13 +635,16 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# )
|
# )
|
||||||
|
|
||||||
# NOTE https://codeberg.org/poezio/slixmpp/issues/3515
|
# NOTE https://codeberg.org/poezio/slixmpp/issues/3515
|
||||||
# if jid == self.settings['xmpp']['operator']:
|
# if is_operator(self, jid_bare):
|
||||||
self['xep_0050'].add_command(node='recent',
|
self['xep_0050'].add_command(node='recent',
|
||||||
name='📰️ Browse',
|
name='📰️ Browse',
|
||||||
handler=self._handle_recent)
|
handler=self._handle_recent)
|
||||||
self['xep_0050'].add_command(node='subscription',
|
self['xep_0050'].add_command(node='subscription',
|
||||||
name='🪶️ Subscribe',
|
name='🪶️ Subscribe',
|
||||||
handler=self._handle_subscription_add)
|
handler=self._handle_subscription_add)
|
||||||
|
self['xep_0050'].add_command(node='publish',
|
||||||
|
name='📣️ Publish',
|
||||||
|
handler=self._handle_publish)
|
||||||
self['xep_0050'].add_command(node='subscriptions',
|
self['xep_0050'].add_command(node='subscriptions',
|
||||||
name='🎫️ Subscriptions',
|
name='🎫️ Subscriptions',
|
||||||
handler=self._handle_subscriptions)
|
handler=self._handle_subscriptions)
|
||||||
|
@ -672,6 +679,42 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# Special interface
|
# Special interface
|
||||||
# http://jabber.org/protocol/commands#actions
|
# http://jabber.org/protocol/commands#actions
|
||||||
|
|
||||||
|
async def _handle_publish(self, iq, session):
|
||||||
|
form = self['xep_0004'].make_form('form', 'Publish')
|
||||||
|
form['instructions'] = ('In order to publish via Pubsub Social Feed '
|
||||||
|
'(XEP-0472), you will have to choose a '
|
||||||
|
'Publish-Subscribe (XEP-0060) hostname and '
|
||||||
|
'be permitted to publish into it.')
|
||||||
|
# TODO Select from list-multi
|
||||||
|
form.add_field(var='subscription',
|
||||||
|
ftype='text-single',
|
||||||
|
label='URL',
|
||||||
|
desc='Enter subscription URL.',
|
||||||
|
value='http://',
|
||||||
|
required=True)
|
||||||
|
form.add_field(var='subscription',
|
||||||
|
ftype='text-single',
|
||||||
|
label='PubSub',
|
||||||
|
desc='Enter a PubSub URL.',
|
||||||
|
value='pubsub.' + self.boundjid.host,
|
||||||
|
required=True)
|
||||||
|
session['allow_prev'] = False
|
||||||
|
session['has_next'] = True
|
||||||
|
session['next'] = self._handle_preview
|
||||||
|
session['prev'] = None
|
||||||
|
session['payload'] = form
|
||||||
|
return session
|
||||||
|
|
||||||
|
def _handle_preview(self, payload, session):
|
||||||
|
jid_full = str(session['from'])
|
||||||
|
function_name = sys._getframe().f_code.co_name
|
||||||
|
logger.debug('{}: jid_full: {}'
|
||||||
|
.format(function_name, jid_full))
|
||||||
|
text_note = ('XEP-0472: Pubsub Social Feed will be available soon.')
|
||||||
|
session['notes'] = [['info', text_note]]
|
||||||
|
session['payload'] = None
|
||||||
|
return session
|
||||||
|
|
||||||
async def _handle_profile(self, iq, session):
|
async def _handle_profile(self, iq, session):
|
||||||
jid_full = str(session['from'])
|
jid_full = str(session['from'])
|
||||||
function_name = sys._getframe().f_code.co_name
|
function_name = sys._getframe().f_code.co_name
|
||||||
|
@ -707,42 +750,42 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
value=unread)
|
value=unread)
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Options')
|
value='Options')
|
||||||
key_archive = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
key_archive = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
key_archive = str(key_archive)
|
key_archive = str(key_archive)
|
||||||
form.add_field(label='Archive',
|
form.add_field(label='Archive',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_archive)
|
value=key_archive)
|
||||||
key_enabled = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
key_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
key_enabled = str(key_enabled)
|
key_enabled = str(key_enabled)
|
||||||
form.add_field(label='Enabled',
|
form.add_field(label='Enabled',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_enabled)
|
value=key_enabled)
|
||||||
key_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
key_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
key_interval = str(key_interval)
|
key_interval = str(key_interval)
|
||||||
form.add_field(label='Interval',
|
form.add_field(label='Interval',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_interval)
|
value=key_interval)
|
||||||
key_length = self.settings[jid_bare]['length'] or self.settings['default']['length']
|
key_length = Config.get_setting_value(self.settings, jid_bare, 'length')
|
||||||
key_length = str(key_length)
|
key_length = str(key_length)
|
||||||
form.add_field(label='Length',
|
form.add_field(label='Length',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_length)
|
value=key_length)
|
||||||
key_media = self.settings[jid_bare]['media'] or self.settings['default']['media']
|
key_media = Config.get_setting_value(self.settings, jid_bare, 'media')
|
||||||
key_media = str(key_media)
|
key_media = str(key_media)
|
||||||
form.add_field(label='Media',
|
form.add_field(label='Media',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_media)
|
value=key_media)
|
||||||
key_old = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
key_old = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
key_old = str(key_old)
|
key_old = str(key_old)
|
||||||
form.add_field(label='Old',
|
form.add_field(label='Old',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_old)
|
value=key_old)
|
||||||
key_quantum = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum']
|
key_quantum = Config.get_setting_value(self.settings, jid_bare, 'quantum')
|
||||||
key_quantum = str(key_quantum)
|
key_quantum = str(key_quantum)
|
||||||
form.add_field(label='Quantum',
|
form.add_field(label='Quantum',
|
||||||
ftype='text-single',
|
ftype='text-single',
|
||||||
value=key_quantum)
|
value=key_quantum)
|
||||||
update_interval = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
update_interval = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
update_interval = str(update_interval)
|
update_interval = str(update_interval)
|
||||||
update_interval = 60 * int(update_interval)
|
update_interval = 60 * int(update_interval)
|
||||||
last_update_time = sqlite.get_last_update_time(db_file)
|
last_update_time = sqlite.get_last_update_time(db_file)
|
||||||
|
@ -757,7 +800,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
else:
|
else:
|
||||||
next_update = 'n/a'
|
next_update = 'n/a'
|
||||||
else:
|
else:
|
||||||
last_update_time = 'n/a'
|
last_update = 'n/a'
|
||||||
next_update = 'n/a'
|
next_update = 'n/a'
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value='Schedule')
|
value='Schedule')
|
||||||
|
@ -1354,8 +1397,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
.format(function_name, jid_full))
|
.format(function_name, jid_full))
|
||||||
jid_bare = session['from'].bare
|
jid_bare = session['from'].bare
|
||||||
chat_type = await get_chat_type(self, jid_bare)
|
chat_type = await get_chat_type(self, jid_bare)
|
||||||
|
moderator = None
|
||||||
if chat_type == 'groupchat':
|
if chat_type == 'groupchat':
|
||||||
moderator = is_moderator(self, jid_bare, jid_full)
|
moderator = is_moderator(self, jid_bare, jid_full)
|
||||||
|
# moderator = moderator if moderator else None
|
||||||
if chat_type == 'chat' or moderator:
|
if chat_type == 'chat' or moderator:
|
||||||
form = self['xep_0004'].make_form('form', 'Discover & Search')
|
form = self['xep_0004'].make_form('form', 'Discover & Search')
|
||||||
form['instructions'] = 'Discover news subscriptions of all kinds'
|
form['instructions'] = 'Discover news subscriptions of all kinds'
|
||||||
|
@ -1517,10 +1562,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
desc=('Select a subscription to edit.'),
|
desc=('Select a subscription to edit.'),
|
||||||
required=True)
|
required=True)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
options.addOption(title, url)
|
options.addOption(title, url)
|
||||||
session['has_next'] = True
|
session['has_next'] = True
|
||||||
session['next'] = self._handle_subscription_editor
|
session['next'] = self._handle_subscription_editor
|
||||||
|
@ -1536,10 +1581,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
desc=('Select subscriptions to remove.'),
|
desc=('Select subscriptions to remove.'),
|
||||||
required=True)
|
required=True)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
ix = str(subscription[2])
|
ix = str(subscription[0])
|
||||||
options.addOption(title, ix)
|
options.addOption(title, ix)
|
||||||
session['cancel'] = self._handle_cancel
|
session['cancel'] = self._handle_cancel
|
||||||
session['has_next'] = False
|
session['has_next'] = False
|
||||||
|
@ -1653,8 +1698,8 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# subscriptions = set(subscriptions)
|
# subscriptions = set(subscriptions)
|
||||||
categorized_subscriptions = {}
|
categorized_subscriptions = {}
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
try:
|
try:
|
||||||
letter = title[0].capitalize()
|
letter = title[0].capitalize()
|
||||||
if letter not in categorized_subscriptions:
|
if letter not in categorized_subscriptions:
|
||||||
|
@ -1866,10 +1911,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
jid_file = jid_bare
|
jid_file = jid_bare
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
for subscription in subscriptions:
|
for subscription in subscriptions:
|
||||||
title = subscription[0]
|
title = subscription[1]
|
||||||
url = subscription[1]
|
url = subscription[2]
|
||||||
options.addOption(title, url)
|
options.addOption(title, url)
|
||||||
# options = form.add_field(var='action',
|
# options = form.add_field(var='action',
|
||||||
# ftype='list-single',
|
# ftype='list-single',
|
||||||
|
@ -1909,7 +1954,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
options.addOption('Import', 'import')
|
options.addOption('Import', 'import')
|
||||||
options.addOption('Export', 'export')
|
options.addOption('Export', 'export')
|
||||||
jid = session['from'].bare
|
jid = session['from'].bare
|
||||||
if jid == self.settings['xmpp']['operator']:
|
if is_operator(self, jid):
|
||||||
options.addOption('Administration', 'admin')
|
options.addOption('Administration', 'admin')
|
||||||
session['payload'] = form
|
session['payload'] = form
|
||||||
session['next'] = self._handle_advanced_result
|
session['next'] = self._handle_advanced_result
|
||||||
|
@ -1936,7 +1981,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# NOTE Even though this check is already conducted on previous
|
# NOTE Even though this check is already conducted on previous
|
||||||
# form, this check is being done just in case.
|
# form, this check is being done just in case.
|
||||||
jid_bare = session['from'].bare
|
jid_bare = session['from'].bare
|
||||||
if jid_bare == self.settings['xmpp']['operator']:
|
if is_operator(self, jid_bare):
|
||||||
if self.is_component:
|
if self.is_component:
|
||||||
# NOTE This will be changed with XEP-0222 XEP-0223
|
# NOTE This will be changed with XEP-0222 XEP-0223
|
||||||
text_info = ('Subscriber management options are '
|
text_info = ('Subscriber management options are '
|
||||||
|
@ -2036,9 +2081,10 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
options = form.add_field(var='option',
|
options = form.add_field(var='option',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
label='About',
|
label='About',
|
||||||
required=True)
|
required=True,
|
||||||
|
value='about')
|
||||||
config_dir = config.get_default_config_directory()
|
config_dir = config.get_default_config_directory()
|
||||||
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
with open(config_dir + '/' + 'about.toml', mode="rb") as information:
|
||||||
entries = tomllib.load(information)
|
entries = tomllib.load(information)
|
||||||
for entry in entries:
|
for entry in entries:
|
||||||
label = entries[entry][0]['title']
|
label = entries[entry][0]['title']
|
||||||
|
@ -2056,7 +2102,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
logger.debug('{}: jid_full: {}'
|
logger.debug('{}: jid_full: {}'
|
||||||
.format(function_name, jid_full))
|
.format(function_name, jid_full))
|
||||||
config_dir = config.get_default_config_directory()
|
config_dir = config.get_default_config_directory()
|
||||||
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
with open(config_dir + '/' + 'about.toml', mode="rb") as information:
|
||||||
entries = tomllib.load(information)
|
entries = tomllib.load(information)
|
||||||
entry_key = payload['values']['option']
|
entry_key = payload['values']['option']
|
||||||
# case 'terms':
|
# case 'terms':
|
||||||
|
@ -2086,7 +2132,6 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
e_key = e_key.capitalize()
|
e_key = e_key.capitalize()
|
||||||
# form.add_field(ftype='fixed',
|
# form.add_field(ftype='fixed',
|
||||||
# value=e_val)
|
# value=e_val)
|
||||||
print(type(e_val))
|
|
||||||
if e_key == 'Name':
|
if e_key == 'Name':
|
||||||
form.add_field(ftype='fixed',
|
form.add_field(ftype='fixed',
|
||||||
value=e_val)
|
value=e_val)
|
||||||
|
@ -2135,7 +2180,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
cmds = tomllib.load(commands)
|
cmds = tomllib.load(commands)
|
||||||
|
|
||||||
form = self['xep_0004'].make_form('result', 'Manual')
|
form = self['xep_0004'].make_form('result', 'Manual')
|
||||||
form['instructions'] = '🛟️ Help manual for interactive chat'
|
form['instructions'] = 'Help manual for interactive chat'
|
||||||
|
|
||||||
# text = '🛟️ Help and Information about Slixfeed\n\n'
|
# text = '🛟️ Help and Information about Slixfeed\n\n'
|
||||||
# for cmd in cmds:
|
# for cmd in cmds:
|
||||||
|
@ -2311,7 +2356,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
jid_file = jid_bare
|
jid_file = jid_bare
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
subscriptions = sqlite.get_feeds(db_file)
|
subscriptions = sqlite.get_feeds(db_file)
|
||||||
subscriptions = sorted(subscriptions, key=lambda x: x[0])
|
subscriptions = sorted(subscriptions, key=lambda x: x[1])
|
||||||
form = self['xep_0004'].make_form('form', 'Subscriptions')
|
form = self['xep_0004'].make_form('form', 'Subscriptions')
|
||||||
match payload['values']['action']:
|
match payload['values']['action']:
|
||||||
case 'bookmarks':
|
case 'bookmarks':
|
||||||
|
@ -2641,7 +2686,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
Config.add_settings_jid(self.settings, jid_bare, db_file)
|
||||||
form = self['xep_0004'].make_form('form', 'Settings')
|
form = self['xep_0004'].make_form('form', 'Settings')
|
||||||
form['instructions'] = 'Editing settings'
|
form['instructions'] = 'Editing settings'
|
||||||
value = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
value = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2653,7 +2698,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
label='Enabled',
|
label='Enabled',
|
||||||
desc='Enable news updates.',
|
desc='Enable news updates.',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['media'] or self.settings['default']['media']
|
value = Config.get_setting_value(self.settings, jid_bare, 'media')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2665,7 +2710,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
desc='Send audio, images or videos if found.',
|
desc='Send audio, images or videos if found.',
|
||||||
label='Display media',
|
label='Display media',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['old'] or self.settings['default']['old']
|
value = Config.get_setting_value(self.settings, jid_bare, 'old')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
if value:
|
if value:
|
||||||
|
@ -2678,7 +2723,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
# label='Send only new items',
|
# label='Send only new items',
|
||||||
label='Include old news',
|
label='Include old news',
|
||||||
value=value)
|
value=value)
|
||||||
value = self.settings[jid_bare]['interval'] or self.settings['default']['interval']
|
value = Config.get_setting_value(self.settings, jid_bare, 'interval')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
value = int(value)
|
value = int(value)
|
||||||
value = value/60
|
value = value/60
|
||||||
|
@ -2699,7 +2744,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
i += 6
|
i += 6
|
||||||
else:
|
else:
|
||||||
i += 1
|
i += 1
|
||||||
value = self.settings[jid_bare]['quantum'] or self.settings['default']['quantum']
|
value = Config.get_setting_value(self.settings, jid_bare, 'quantum')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
options = form.add_field(var='quantum',
|
options = form.add_field(var='quantum',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
|
@ -2713,7 +2758,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
x = str(i)
|
x = str(i)
|
||||||
options.addOption(x, x)
|
options.addOption(x, x)
|
||||||
i += 1
|
i += 1
|
||||||
value = self.settings[jid_bare]['archive'] or self.settings['default']['archive']
|
value = Config.get_setting_value(self.settings, jid_bare, 'archive')
|
||||||
value = str(value)
|
value = str(value)
|
||||||
options = form.add_field(var='archive',
|
options = form.add_field(var='archive',
|
||||||
ftype='list-single',
|
ftype='list-single',
|
||||||
|
@ -2768,7 +2813,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
||||||
if val < 1: val = 1
|
if val < 1: val = 1
|
||||||
val = val * 60
|
val = val * 60
|
||||||
|
|
||||||
is_enabled = self.settings[jid_bare]['enabled'] or self.settings['default']['enabled']
|
is_enabled = Config.get_setting_value(self.settings, jid_bare, 'enabled')
|
||||||
|
|
||||||
if (key == 'enabled' and
|
if (key == 'enabled' and
|
||||||
val == 1 and
|
val == 1 and
|
||||||
|
|
|
@ -3,6 +3,13 @@
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
FIXME
|
||||||
|
|
||||||
|
Message from OpenFire server log.
|
||||||
|
|
||||||
|
2024.03.12 14:21:22.518 ERROR [nioEventLoopGroup-3-2]: org.jivesoftware.openfire.IQRouter - Unable to process a stanza that has no 'from' attribute, addressed to a remote entity. Stanza is being dropped: <iq id="8e4e60ae0d894b40a2fc465268d46d0b" type="get" to="rss.simon.goodbytes.im"><ping xmlns="urn:xmpp:ping"></ping></iq>
|
||||||
|
|
||||||
|
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
1) Check interval, and if no connection is establish after 30 seconds
|
1) Check interval, and if no connection is establish after 30 seconds
|
||||||
|
@ -38,21 +45,23 @@ class XmppConnect:
|
||||||
None.
|
None.
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
if not jid:
|
if not jid:
|
||||||
jid = self.boundjid.bare
|
jid = self.boundjid.bare
|
||||||
while True:
|
while True:
|
||||||
rtt = None
|
rtt = None
|
||||||
try:
|
try:
|
||||||
rtt = await self['xep_0199'].ping(jid, timeout=10)
|
rtt = await self['xep_0199'].ping(jid,
|
||||||
|
ifrom=jid_from,
|
||||||
|
timeout=10)
|
||||||
logging.info('Success! RTT: %s', rtt)
|
logging.info('Success! RTT: %s', rtt)
|
||||||
except IqError as e:
|
except IqError as e:
|
||||||
logging.info('Error pinging %s: %s',
|
logging.error('Error pinging %s: %s', jid,
|
||||||
jid,
|
e.iq['error']['condition'])
|
||||||
e.iq['error']['condition'])
|
|
||||||
except IqTimeout:
|
except IqTimeout:
|
||||||
logging.info('No response from %s', jid)
|
logging.warning('No response from %s', jid)
|
||||||
if not rtt:
|
if not rtt:
|
||||||
logging.info('Disconnecting...')
|
logging.warning('Disconnecting...')
|
||||||
self.disconnect()
|
self.disconnect()
|
||||||
break
|
break
|
||||||
await asyncio.sleep(60 * 1)
|
await asyncio.sleep(60 * 1)
|
||||||
|
@ -68,7 +77,7 @@ class XmppConnect:
|
||||||
# print(current_time(),"Maximum connection attempts exceeded.")
|
# print(current_time(),"Maximum connection attempts exceeded.")
|
||||||
# logging.error("Maximum connection attempts exceeded.")
|
# logging.error("Maximum connection attempts exceeded.")
|
||||||
print(current_time(), 'Attempt number', self.connection_attempts)
|
print(current_time(), 'Attempt number', self.connection_attempts)
|
||||||
seconds = (get_value('accounts', 'XMPP', 'reconnect_timeout')) or 30
|
seconds = self.reconnect_timeout or 30
|
||||||
seconds = int(seconds)
|
seconds = int(seconds)
|
||||||
print(current_time(), 'Next attempt within', seconds, 'seconds')
|
print(current_time(), 'Next attempt within', seconds, 'seconds')
|
||||||
# NOTE asyncio.sleep doesn't interval as expected
|
# NOTE asyncio.sleep doesn't interval as expected
|
||||||
|
|
14
slixfeed/xmpp/iq.py
Normal file
14
slixfeed/xmpp/iq.py
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from slixmpp.exceptions import IqError
|
||||||
|
|
||||||
|
class XmppIQ:
|
||||||
|
|
||||||
|
async def send(self, iq):
|
||||||
|
try:
|
||||||
|
await iq.send(timeout=5)
|
||||||
|
except IqError as e:
|
||||||
|
if e.etype == 'cancel' and e.condition == 'conflict':
|
||||||
|
return
|
||||||
|
raise
|
|
@ -34,15 +34,17 @@ class XmppMessage:
|
||||||
|
|
||||||
|
|
||||||
def send(self, jid, message_body, chat_type):
|
def send(self, jid, message_body, chat_type):
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
self.send_message(mto=jid,
|
self.send_message(mto=jid,
|
||||||
mfrom=self.boundjid.bare,
|
mfrom=jid_from,
|
||||||
mbody=message_body,
|
mbody=message_body,
|
||||||
mtype=chat_type)
|
mtype=chat_type)
|
||||||
|
|
||||||
|
|
||||||
def send_headline(self, jid, message_subject, message_body, chat_type):
|
def send_headline(self, jid, message_subject, message_body, chat_type):
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
self.send_message(mto=jid,
|
self.send_message(mto=jid,
|
||||||
mfrom=self.boundjid.bare,
|
mfrom=jid_from,
|
||||||
# mtype='headline',
|
# mtype='headline',
|
||||||
msubject=message_subject,
|
msubject=message_subject,
|
||||||
mbody=message_body,
|
mbody=message_body,
|
||||||
|
@ -58,13 +60,14 @@ class XmppMessage:
|
||||||
# }
|
# }
|
||||||
# return saxutils.escape(raw_string, escape_map)
|
# return saxutils.escape(raw_string, escape_map)
|
||||||
def send_oob(self, jid, url, chat_type):
|
def send_oob(self, jid, url, chat_type):
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
url = saxutils.escape(url)
|
url = saxutils.escape(url)
|
||||||
# try:
|
# try:
|
||||||
html = (
|
html = (
|
||||||
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
||||||
f'<a href="{url}">{url}</a></body>')
|
f'<a href="{url}">{url}</a></body>')
|
||||||
message = self.make_message(mto=jid,
|
message = self.make_message(mto=jid,
|
||||||
mfrom=self.boundjid.bare,
|
mfrom=jid_from,
|
||||||
mbody=url,
|
mbody=url,
|
||||||
mhtml=html,
|
mhtml=html,
|
||||||
mtype=chat_type)
|
mtype=chat_type)
|
||||||
|
|
|
@ -42,8 +42,10 @@ class XmppGroupchat:
|
||||||
conference["nick"] = self.alias
|
conference["nick"] = self.alias
|
||||||
logging.error('Alias (i.e. Nicknname) is missing for '
|
logging.error('Alias (i.e. Nicknname) is missing for '
|
||||||
'bookmark {}'.format(conference['name']))
|
'bookmark {}'.format(conference['name']))
|
||||||
|
# jid_from = str(self.boundjid) if self.is_component else None
|
||||||
self.plugin['xep_0045'].join_muc(conference["jid"],
|
self.plugin['xep_0045'].join_muc(conference["jid"],
|
||||||
conference["nick"],
|
conference["nick"],
|
||||||
|
# pfrom=jid_from,
|
||||||
# If a room password is needed, use:
|
# If a room password is needed, use:
|
||||||
# password=the_room_password,
|
# password=the_room_password,
|
||||||
)
|
)
|
||||||
|
@ -83,8 +85,10 @@ class XmppGroupchat:
|
||||||
'JID : {}\n'
|
'JID : {}\n'
|
||||||
'Inviter : {}\n'
|
'Inviter : {}\n'
|
||||||
.format(jid, inviter))
|
.format(jid, inviter))
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
self.plugin['xep_0045'].join_muc(jid,
|
self.plugin['xep_0045'].join_muc(jid,
|
||||||
self.alias,
|
self.alias,
|
||||||
|
pfrom=jid_from
|
||||||
# If a room password is needed, use:
|
# If a room password is needed, use:
|
||||||
# password=the_room_password,
|
# password=the_room_password,
|
||||||
)
|
)
|
||||||
|
|
|
@ -23,6 +23,9 @@ TODO
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
from slixfeed.xmpp.publish import XmppPubsub
|
||||||
|
from slixfeed.xmpp.iq import XmppIQ
|
||||||
|
|
||||||
import asyncio
|
import asyncio
|
||||||
import logging
|
import logging
|
||||||
import os
|
import os
|
||||||
|
@ -40,9 +43,14 @@ from slixfeed.xmpp.muc import XmppGroupchat
|
||||||
from slixfeed.xmpp.message import XmppMessage
|
from slixfeed.xmpp.message import XmppMessage
|
||||||
from slixfeed.xmpp.presence import XmppPresence
|
from slixfeed.xmpp.presence import XmppPresence
|
||||||
from slixfeed.xmpp.upload import XmppUpload
|
from slixfeed.xmpp.upload import XmppUpload
|
||||||
from slixfeed.xmpp.utility import get_chat_type, is_moderator
|
from slixfeed.xmpp.utility import get_chat_type, is_moderator, is_operator
|
||||||
import time
|
import time
|
||||||
|
|
||||||
|
try:
|
||||||
|
import tomllib
|
||||||
|
except:
|
||||||
|
import tomli as tomllib
|
||||||
|
|
||||||
|
|
||||||
# for task in main_task:
|
# for task in main_task:
|
||||||
# task.cancel()
|
# task.cancel()
|
||||||
|
@ -181,7 +189,7 @@ async def message(self, message):
|
||||||
response = None
|
response = None
|
||||||
match message_lowercase:
|
match message_lowercase:
|
||||||
# case 'breakpoint':
|
# case 'breakpoint':
|
||||||
# if jid == get_value('accounts', 'XMPP', 'operator'):
|
# if is_operator(self, jid_bare):
|
||||||
# breakpoint()
|
# breakpoint()
|
||||||
# print('task_manager[jid]')
|
# print('task_manager[jid]')
|
||||||
# print(task_manager[jid])
|
# print(task_manager[jid])
|
||||||
|
@ -244,21 +252,25 @@ async def message(self, message):
|
||||||
'or command key & name')
|
'or command key & name')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'info':
|
case 'info':
|
||||||
command_list = action.manual('information.toml')
|
config_dir = config.get_default_config_directory()
|
||||||
|
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
||||||
|
entries = tomllib.load(information)
|
||||||
response = ('Available command options:\n'
|
response = ('Available command options:\n'
|
||||||
'```\n{}\n```\n'
|
'```\n{}\n```\n'
|
||||||
'Usage: `info <option>`'
|
'Usage: `info <option>`'
|
||||||
.format(command_list))
|
.format(', '.join(entries)))
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('info'):
|
case _ if message_lowercase.startswith('info'):
|
||||||
command = message_text[5:].lower()
|
entry = message_text[5:].lower()
|
||||||
command_list = action.manual('information.toml', command)
|
config_dir = config.get_default_config_directory()
|
||||||
if command_list:
|
with open(config_dir + '/' + 'information.toml', mode="rb") as information:
|
||||||
|
entries = tomllib.load(information)
|
||||||
|
if entry in entries:
|
||||||
# command_list = '\n'.join(command_list)
|
# command_list = '\n'.join(command_list)
|
||||||
response = (command_list)
|
response = (entries[entry]['info'])
|
||||||
else:
|
else:
|
||||||
response = ('KeyError for {}'
|
response = ('KeyError for {}'
|
||||||
.format(command))
|
.format(entry))
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase in ['greetings', 'hallo', 'hello',
|
case _ if message_lowercase in ['greetings', 'hallo', 'hello',
|
||||||
'hey', 'hi', 'hola', 'holla',
|
'hey', 'hi', 'hola', 'holla',
|
||||||
|
@ -293,7 +305,7 @@ async def message(self, message):
|
||||||
# response = 'Activation code is not valid.'
|
# response = 'Activation code is not valid.'
|
||||||
# else:
|
# else:
|
||||||
# response = 'This command is valid for groupchat only.'
|
# response = 'This command is valid for groupchat only.'
|
||||||
case _ if message_lowercase.startswith('add'):
|
case _ if message_lowercase.startswith('add '):
|
||||||
# Add given feed without validity check.
|
# Add given feed without validity check.
|
||||||
message_text = message_text[4:]
|
message_text = message_text[4:]
|
||||||
url = message_text.split(' ')[0]
|
url = message_text.split(' ')[0]
|
||||||
|
@ -338,7 +350,7 @@ async def message(self, message):
|
||||||
'Missing URL.')
|
'Missing URL.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('allow +'):
|
case _ if message_lowercase.startswith('allow +'):
|
||||||
key = message_text[:5]
|
key = message_text[:5].lower()
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
if val:
|
if val:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -359,7 +371,7 @@ async def message(self, message):
|
||||||
'Missing keywords.')
|
'Missing keywords.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('allow -'):
|
case _ if message_lowercase.startswith('allow -'):
|
||||||
key = message_text[:5]
|
key = message_text[:5].lower()
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
if val:
|
if val:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -379,8 +391,8 @@ async def message(self, message):
|
||||||
'\n'
|
'\n'
|
||||||
'Missing keywords.')
|
'Missing keywords.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('archive'):
|
case _ if message_lowercase.startswith('archive '):
|
||||||
key = message_text[:7]
|
key = message_text[:7].lower()
|
||||||
val = message_text[8:]
|
val = message_text[8:]
|
||||||
if val:
|
if val:
|
||||||
try:
|
try:
|
||||||
|
@ -406,7 +418,7 @@ async def message(self, message):
|
||||||
'Missing value.')
|
'Missing value.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('bookmark +'):
|
case _ if message_lowercase.startswith('bookmark +'):
|
||||||
if jid_bare == config.get_value('accounts', 'XMPP', 'operator'):
|
if is_operator(self, jid_bare):
|
||||||
muc_jid = message_text[11:]
|
muc_jid = message_text[11:]
|
||||||
await XmppBookmark.add(self, jid=muc_jid)
|
await XmppBookmark.add(self, jid=muc_jid)
|
||||||
response = ('Groupchat {} has been added to bookmarks.'
|
response = ('Groupchat {} has been added to bookmarks.'
|
||||||
|
@ -416,7 +428,7 @@ async def message(self, message):
|
||||||
'Type: adding bookmarks.')
|
'Type: adding bookmarks.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('bookmark -'):
|
case _ if message_lowercase.startswith('bookmark -'):
|
||||||
if jid_bare == config.get_value('accounts', 'XMPP', 'operator'):
|
if is_operator(self, jid_bare):
|
||||||
muc_jid = message_text[11:]
|
muc_jid = message_text[11:]
|
||||||
await XmppBookmark.remove(self, muc_jid)
|
await XmppBookmark.remove(self, muc_jid)
|
||||||
response = ('Groupchat {} has been removed from bookmarks.'
|
response = ('Groupchat {} has been removed from bookmarks.'
|
||||||
|
@ -446,14 +458,14 @@ async def message(self, message):
|
||||||
response = 'Filter {} has been purged.'.format(key)
|
response = 'Filter {} has been purged.'.format(key)
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case 'bookmarks':
|
case 'bookmarks':
|
||||||
if jid_bare == config.get_value('accounts', 'XMPP', 'operator'):
|
if is_operator(self, jid_bare):
|
||||||
response = await action.list_bookmarks(self)
|
response = await action.list_bookmarks(self)
|
||||||
else:
|
else:
|
||||||
response = ('This action is restricted. '
|
response = ('This action is restricted. '
|
||||||
'Type: viewing bookmarks.')
|
'Type: viewing bookmarks.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('deny +'):
|
case _ if message_lowercase.startswith('deny +'):
|
||||||
key = message_text[:4]
|
key = message_text[:4].lower()
|
||||||
val = message_text[6:]
|
val = message_text[6:]
|
||||||
if val:
|
if val:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -474,7 +486,7 @@ async def message(self, message):
|
||||||
'Missing keywords.')
|
'Missing keywords.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('deny -'):
|
case _ if message_lowercase.startswith('deny -'):
|
||||||
key = message_text[:4]
|
key = message_text[:4].lower()
|
||||||
val = message_text[6:]
|
val = message_text[6:]
|
||||||
if val:
|
if val:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
|
@ -494,7 +506,7 @@ async def message(self, message):
|
||||||
'\n'
|
'\n'
|
||||||
'Missing keywords.')
|
'Missing keywords.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('export'):
|
case _ if message_lowercase.startswith('export '):
|
||||||
ext = message_text[7:]
|
ext = message_text[7:]
|
||||||
if ext in ('md', 'opml'): # html xbel
|
if ext in ('md', 'opml'): # html xbel
|
||||||
status_type = 'dnd'
|
status_type = 'dnd'
|
||||||
|
@ -687,7 +699,8 @@ async def message(self, message):
|
||||||
if query:
|
if query:
|
||||||
if len(query) > 3:
|
if len(query) > 3:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
response = action.list_feeds_by_query(db_file, query)
|
result = sqlite.search_feeds(db_file, query)
|
||||||
|
response = action.list_feeds_by_query(query, result)
|
||||||
else:
|
else:
|
||||||
response = 'Enter at least 4 characters to search'
|
response = 'Enter at least 4 characters to search'
|
||||||
else:
|
else:
|
||||||
|
@ -702,8 +715,8 @@ async def message(self, message):
|
||||||
else:
|
else:
|
||||||
response = 'This command is valid in groupchat only.'
|
response = 'This command is valid in groupchat only.'
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('interval'):
|
case _ if message_lowercase.startswith('interval '):
|
||||||
key = message_text[:8]
|
key = message_text[:8].lower()
|
||||||
val = message_text[9:]
|
val = message_text[9:]
|
||||||
if val:
|
if val:
|
||||||
try:
|
try:
|
||||||
|
@ -738,8 +751,8 @@ async def message(self, message):
|
||||||
'XMPP URI is not valid.'
|
'XMPP URI is not valid.'
|
||||||
.format(message_text))
|
.format(message_text))
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('length'):
|
case _ if message_lowercase.startswith('length '):
|
||||||
key = message_text[:6]
|
key = message_text[:6].lower()
|
||||||
val = message_text[7:]
|
val = message_text[7:]
|
||||||
if val:
|
if val:
|
||||||
try:
|
try:
|
||||||
|
@ -832,7 +845,7 @@ async def message(self, message):
|
||||||
case 'options':
|
case 'options':
|
||||||
response = 'Options:\n```'
|
response = 'Options:\n```'
|
||||||
for key in self.settings[jid_bare]:
|
for key in self.settings[jid_bare]:
|
||||||
val = self.settings[jid_bare][key] or self.settings['default'][key]
|
val = Config.get_setting_value(self.settings, jid_bare, key)
|
||||||
# val = Config.get_setting_value(self.settings, jid_bare, key)
|
# val = Config.get_setting_value(self.settings, jid_bare, key)
|
||||||
steps = 11 - len(key)
|
steps = 11 - len(key)
|
||||||
pulse = ''
|
pulse = ''
|
||||||
|
@ -842,8 +855,8 @@ async def message(self, message):
|
||||||
print(response)
|
print(response)
|
||||||
response += '\n```'
|
response += '\n```'
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('quantum'):
|
case _ if message_lowercase.startswith('quantum '):
|
||||||
key = message_text[:7]
|
key = message_text[:7].lower()
|
||||||
val = message_text[8:]
|
val = message_text[8:]
|
||||||
if val:
|
if val:
|
||||||
try:
|
try:
|
||||||
|
@ -872,7 +885,7 @@ async def message(self, message):
|
||||||
# NOTE sqlitehandler.get_entry_unread
|
# NOTE sqlitehandler.get_entry_unread
|
||||||
response = 'Updates will be sent by random order.'
|
response = 'Updates will be sent by random order.'
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('read'):
|
case _ if message_lowercase.startswith('read '):
|
||||||
data = message_text[5:]
|
data = message_text[5:]
|
||||||
data = data.split()
|
data = data.split()
|
||||||
url = data[0]
|
url = data[0]
|
||||||
|
@ -914,7 +927,7 @@ async def message(self, message):
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
key_list = ['status']
|
key_list = ['status']
|
||||||
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
||||||
case _ if message_lowercase.startswith('recent'):
|
case _ if message_lowercase.startswith('recent '):
|
||||||
num = message_text[7:]
|
num = message_text[7:]
|
||||||
if num:
|
if num:
|
||||||
try:
|
try:
|
||||||
|
@ -934,50 +947,53 @@ async def message(self, message):
|
||||||
'\n'
|
'\n'
|
||||||
'Missing value.')
|
'Missing value.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('remove'):
|
case _ if message_lowercase.startswith('remove '):
|
||||||
ix_url = message_text[7:]
|
ix_url = message_text[7:]
|
||||||
|
ix_url = ix_url.split(' ')
|
||||||
if ix_url:
|
if ix_url:
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
for i in ix_url:
|
||||||
try:
|
if i:
|
||||||
ix = int(ix_url)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
url = sqlite.get_feed_url(db_file, ix)
|
try:
|
||||||
if url:
|
ix = int(i)
|
||||||
url = url[0]
|
url = sqlite.get_feed_url(db_file, ix)
|
||||||
name = sqlite.get_feed_title(db_file, ix)
|
if url:
|
||||||
name = name[0]
|
url = url[0]
|
||||||
await sqlite.remove_feed_by_index(db_file, ix)
|
name = sqlite.get_feed_title(db_file, ix)
|
||||||
response = ('> {}\n'
|
name = name[0]
|
||||||
'News source "{}" has been '
|
await sqlite.remove_feed_by_index(db_file, ix)
|
||||||
'removed from subscription list.'
|
response = ('> {}\n'
|
||||||
.format(url, name))
|
'News source "{}" has been '
|
||||||
else:
|
'removed from subscription list.'
|
||||||
response = ('No news source with index {}.'
|
.format(url, name))
|
||||||
.format(ix))
|
else:
|
||||||
except:
|
response = ('No news source with index {}.'
|
||||||
url = ix_url
|
.format(ix))
|
||||||
feed_id = sqlite.get_feed_id(db_file, url)
|
except:
|
||||||
if feed_id:
|
url = i
|
||||||
feed_id = feed_id[0]
|
feed_id = sqlite.get_feed_id(db_file, url)
|
||||||
await sqlite.remove_feed_by_url(db_file, url)
|
if feed_id:
|
||||||
response = ('> {}\n'
|
feed_id = feed_id[0]
|
||||||
'News source has been removed '
|
await sqlite.remove_feed_by_url(db_file, url)
|
||||||
'from subscription list.'
|
response = ('> {}\n'
|
||||||
.format(url))
|
'News source has been removed '
|
||||||
else:
|
'from subscription list.'
|
||||||
response = ('> {}\n'
|
.format(url))
|
||||||
# 'No action has been made.'
|
else:
|
||||||
'News source does not exist. '
|
response = ('> {}\n'
|
||||||
.format(url))
|
# 'No action has been made.'
|
||||||
# refresh_task(self, jid_bare, send_status, 'status', 20)
|
'News source does not exist. '
|
||||||
# task.clean_tasks_xmpp(self, jid_bare, ['status'])
|
.format(url))
|
||||||
key_list = ['status']
|
# refresh_task(self, jid_bare, send_status, 'status', 20)
|
||||||
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
# task.clean_tasks_xmpp(self, jid_bare, ['status'])
|
||||||
|
key_list = ['status']
|
||||||
|
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
||||||
|
XmppMessage.send_reply(self, message, response)
|
||||||
else:
|
else:
|
||||||
response = ('No action has been taken.'
|
response = ('No action has been taken.'
|
||||||
'\n'
|
'\n'
|
||||||
'Missing argument. '
|
'Missing argument. '
|
||||||
'Enter feed URL or index number.')
|
'Enter feed URL or index number.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
|
||||||
case _ if message_lowercase.startswith('reset'):
|
case _ if message_lowercase.startswith('reset'):
|
||||||
# TODO Reset also by ID
|
# TODO Reset also by ID
|
||||||
ix_url = message_text[6:]
|
ix_url = message_text[6:]
|
||||||
|
@ -1028,7 +1044,7 @@ async def message(self, message):
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
key_list = ['status']
|
key_list = ['status']
|
||||||
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
||||||
case _ if message_lowercase.startswith('search'):
|
case _ if message_lowercase.startswith('search '):
|
||||||
query = message_text[7:]
|
query = message_text[7:]
|
||||||
if query:
|
if query:
|
||||||
if len(query) > 1:
|
if len(query) > 1:
|
||||||
|
@ -1080,7 +1096,7 @@ async def message(self, message):
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
key_list = ['status']
|
key_list = ['status']
|
||||||
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
await task.start_tasks_xmpp(self, jid_bare, key_list)
|
||||||
case _ if message_lowercase.startswith('rename'):
|
case _ if message_lowercase.startswith('rename '):
|
||||||
message_text = message_text[7:]
|
message_text = message_text[7:]
|
||||||
feed_id = message_text.split(' ')[0]
|
feed_id = message_text.split(' ')[0]
|
||||||
name = ' '.join(message_text.split(' ')[1:])
|
name = ' '.join(message_text.split(' ')[1:])
|
||||||
|
@ -1117,7 +1133,7 @@ async def message(self, message):
|
||||||
'Missing argument. '
|
'Missing argument. '
|
||||||
'Enter subscription Id and name.')
|
'Enter subscription Id and name.')
|
||||||
XmppMessage.send_reply(self, message, response)
|
XmppMessage.send_reply(self, message, response)
|
||||||
case _ if message_lowercase.startswith('enable'):
|
case _ if message_lowercase.startswith('enable '):
|
||||||
feed_id = message_text[7:]
|
feed_id = message_text[7:]
|
||||||
db_file = config.get_pathname_to_database(jid_file)
|
db_file = config.get_pathname_to_database(jid_file)
|
||||||
try:
|
try:
|
||||||
|
|
|
@ -26,7 +26,8 @@ TODO
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import glob
|
import glob
|
||||||
from slixfeed.config import get_value, get_default_config_directory
|
from slixfeed.config import Config
|
||||||
|
import slixfeed.config as config
|
||||||
# from slixmpp.exceptions import IqTimeout, IqError
|
# from slixmpp.exceptions import IqTimeout, IqError
|
||||||
# import logging
|
# import logging
|
||||||
import os
|
import os
|
||||||
|
@ -42,7 +43,7 @@ async def update(self):
|
||||||
|
|
||||||
|
|
||||||
async def set_avatar(self):
|
async def set_avatar(self):
|
||||||
config_dir = get_default_config_directory()
|
config_dir = config.get_default_config_directory()
|
||||||
if not os.path.isdir(config_dir):
|
if not os.path.isdir(config_dir):
|
||||||
config_dir = '/usr/share/slixfeed/'
|
config_dir = '/usr/share/slixfeed/'
|
||||||
filename = glob.glob(config_dir + '/image.*')
|
filename = glob.glob(config_dir + '/image.*')
|
||||||
|
@ -89,18 +90,8 @@ def set_identity(self, category):
|
||||||
|
|
||||||
async def set_vcard(self):
|
async def set_vcard(self):
|
||||||
vcard = self.plugin['xep_0054'].make_vcard()
|
vcard = self.plugin['xep_0054'].make_vcard()
|
||||||
fields = {
|
profile = config.get_values('accounts.toml', 'xmpp')['profile']
|
||||||
'BDAY': 'birthday',
|
for key in profile:
|
||||||
'DESC': 'description',
|
vcard[key] = profile[key]
|
||||||
'FN': 'name',
|
|
||||||
'NICKNAME': 'nickname',
|
|
||||||
'NOTE': 'note',
|
|
||||||
'ORG': 'organization',
|
|
||||||
'ROLE': 'role',
|
|
||||||
'TITLE': 'title',
|
|
||||||
'URL': 'url',
|
|
||||||
}
|
|
||||||
for key in fields:
|
|
||||||
vcard[key] = get_value('accounts', 'XMPP Profile', fields[key])
|
|
||||||
await self.plugin['xep_0054'].publish_vcard(vcard)
|
await self.plugin['xep_0054'].publish_vcard(vcard)
|
||||||
|
|
||||||
|
|
44
slixfeed/xmpp/publish.py
Normal file
44
slixfeed/xmpp/publish.py
Normal file
|
@ -0,0 +1,44 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
# TODO Implement XEP-0472: Pubsub Social Feed
|
||||||
|
|
||||||
|
class XmppPubsub:
|
||||||
|
|
||||||
|
def create(self, title, summary, node, server):
|
||||||
|
jid_from = str(self.boundjid) if self.is_component else None
|
||||||
|
iq = self.Iq(stype="set",
|
||||||
|
sto=server,
|
||||||
|
sfrom=jid_from)
|
||||||
|
iq['pubsub']['create']['node'] = node
|
||||||
|
form = iq['pubsub']['configure']['form']
|
||||||
|
form['type'] = 'submit'
|
||||||
|
form.addField('pubsub#title',
|
||||||
|
ftype='text-single',
|
||||||
|
value=title)
|
||||||
|
form.addField('pubsub#description',
|
||||||
|
ftype='text-single',
|
||||||
|
value=summary)
|
||||||
|
form.addField('pubsub#notify_retract',
|
||||||
|
ftype='boolean',
|
||||||
|
value=1)
|
||||||
|
form.addField('pubsub#max_items',
|
||||||
|
ftype='text-single',
|
||||||
|
value='20')
|
||||||
|
form.addField('pubsub#persist_items',
|
||||||
|
ftype='boolean',
|
||||||
|
value=1)
|
||||||
|
form.addField('pubsub#send_last_published_item',
|
||||||
|
ftype='text-single',
|
||||||
|
value='never')
|
||||||
|
form.addField('pubsub#deliver_payloads',
|
||||||
|
ftype='boolean',
|
||||||
|
value=0)
|
||||||
|
|
||||||
|
# TODO
|
||||||
|
|
||||||
|
form.addField('pubsub#type',
|
||||||
|
ftype='text-single',
|
||||||
|
value='http://www.w3.org/2005/Atom')
|
||||||
|
|
||||||
|
return iq
|
|
@ -7,13 +7,24 @@ import logging
|
||||||
# class XmppChat
|
# class XmppChat
|
||||||
# class XmppUtility:
|
# class XmppUtility:
|
||||||
|
|
||||||
|
|
||||||
|
def is_operator(self, jid_bare):
|
||||||
|
result = False
|
||||||
|
for operator in self.operators:
|
||||||
|
if jid_bare == operator['jid']:
|
||||||
|
result = True
|
||||||
|
# operator_name = operator['name']
|
||||||
|
break
|
||||||
|
return result
|
||||||
|
|
||||||
def is_moderator(self, jid_bare, jid_full):
|
def is_moderator(self, jid_bare, jid_full):
|
||||||
alias = jid_full[jid_full.index('/')+1:]
|
alias = jid_full[jid_full.index('/')+1:]
|
||||||
role = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'role')
|
role = self.plugin['xep_0045'].get_jid_property(jid_bare, alias, 'role')
|
||||||
if role == 'moderator':
|
if role == 'moderator':
|
||||||
return True
|
result = True
|
||||||
else:
|
else:
|
||||||
return False
|
result = False
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
# TODO Rename to get_jid_type
|
# TODO Rename to get_jid_type
|
||||||
|
|
Loading…
Reference in a new issue