forked from sch/Slixfeed
Restore support for disabling and enabling feeds.
Assign handlers to "self". Towards better handling of subscription and unsubscription. Minor fixes.
This commit is contained in:
parent
51e48c8389
commit
6c16fa4af1
11 changed files with 223 additions and 210 deletions
|
@ -143,7 +143,7 @@ async def xmpp_start_updates(self, message, jid, jid_file):
|
|||
else:
|
||||
await sqlite.set_settings_value(db_file, [key, val])
|
||||
status_type = 'available'
|
||||
status_message = '💡️ Welcome back!'
|
||||
status_message = '📫️ Welcome back!'
|
||||
XmppPresence.send(self, jid, status_message, status_type=status_type)
|
||||
message_body = 'Updates are enabled.'
|
||||
XmppMessage.send_reply(self, message, message_body)
|
||||
|
@ -159,11 +159,11 @@ async def xmpp_stop_updates(self, message, jid, jid_file):
|
|||
await sqlite.update_settings_value(db_file, [key, val])
|
||||
else:
|
||||
await sqlite.set_settings_value(db_file, [key, val])
|
||||
await task.clean_tasks_xmpp(jid, ['interval', 'status'])
|
||||
task.clean_tasks_xmpp(self, jid, ['interval', 'status'])
|
||||
message_body = 'Updates are disabled.'
|
||||
XmppMessage.send_reply(self, message, message_body)
|
||||
status_type = 'xa'
|
||||
status_message = '💡️ Send "Start" to receive Jabber updates'
|
||||
status_message = '📪️ Send "Start" to receive Jabber updates'
|
||||
XmppPresence.send(self, jid, status_message, status_type=status_type)
|
||||
|
||||
|
||||
|
@ -1098,8 +1098,7 @@ async def download_document(self, message, jid, jid_file, message_text, ix_url,
|
|||
url = None
|
||||
error = None
|
||||
response = None
|
||||
if ext in ('epub', 'html', 'markdown',
|
||||
'md', 'pdf', 'text', 'txt'):
|
||||
if ext in ('epub', 'html', 'markdown', 'md', 'pdf', 'text', 'txt'):
|
||||
match ext:
|
||||
case 'markdown':
|
||||
ext = 'md'
|
||||
|
|
|
@ -61,7 +61,7 @@ No operator was specified for this instance.
|
|||
|
||||
platforms = """
|
||||
Supported platforms: XMPP
|
||||
Platforms to be added in future: Briar, Email, IRC, Matrix, MQTT, Nostr, Tox.
|
||||
Platforms to be added in future: ActivityPub, Briar, Email, IRC, LXMF, Matrix, MQTT, Nostr, Tox.
|
||||
For ideal experience, we recommend using XMPP.
|
||||
"""
|
||||
|
||||
|
|
|
@ -628,7 +628,7 @@ async def get_number_of_feeds_active(db_file):
|
|||
|
||||
Returns
|
||||
-------
|
||||
count : ?
|
||||
count : str
|
||||
Number of rows.
|
||||
"""
|
||||
with create_connection(db_file) as conn:
|
||||
|
@ -1018,7 +1018,7 @@ async def update_statistics(cur):
|
|||
cur.execute(sql, par)
|
||||
|
||||
|
||||
async def set_enabled_status(db_file, ix, status):
|
||||
async def set_enabled_status(db_file, feed_id, status):
|
||||
"""
|
||||
Set status of feed to enabled or not enabled (i.e. disabled).
|
||||
|
||||
|
@ -1026,8 +1026,8 @@ async def set_enabled_status(db_file, ix, status):
|
|||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
ix : str
|
||||
Index of entry.
|
||||
feed_id : str
|
||||
Index of feed.
|
||||
status : int
|
||||
0 or 1.
|
||||
"""
|
||||
|
@ -1038,12 +1038,12 @@ async def set_enabled_status(db_file, ix, status):
|
|||
"""
|
||||
UPDATE feeds_state
|
||||
SET enabled = :status
|
||||
WHERE feed_id = :id
|
||||
WHERE feed_id = :feed_id
|
||||
"""
|
||||
)
|
||||
par = {
|
||||
"status": status,
|
||||
"id": ix
|
||||
"feed_id": feed_id
|
||||
}
|
||||
cur.execute(sql, par)
|
||||
|
||||
|
@ -1395,7 +1395,7 @@ async def get_entries_of_feed(db_file, feed_id):
|
|||
# "feed" urls that are enabled in table "status"
|
||||
async def get_feeds_url(db_file):
|
||||
"""
|
||||
Query active feeds for URLs.
|
||||
Query table feeds for URLs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
|
@ -1419,6 +1419,34 @@ async def get_feeds_url(db_file):
|
|||
return result
|
||||
|
||||
|
||||
async def get_active_feeds_url(db_file):
|
||||
"""
|
||||
Query table feeds for active URLs.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
db_file : str
|
||||
Path to database file.
|
||||
|
||||
Returns
|
||||
-------
|
||||
result : list
|
||||
URLs of active feeds.
|
||||
"""
|
||||
with create_connection(db_file) as conn:
|
||||
cur = conn.cursor()
|
||||
sql = (
|
||||
"""
|
||||
SELECT feeds.url
|
||||
FROM feeds
|
||||
INNER JOIN feeds_state ON feeds.id = feeds_state.feed_id
|
||||
WHERE feeds_state.enabled = 1
|
||||
"""
|
||||
)
|
||||
result = cur.execute(sql).fetchall()
|
||||
return result
|
||||
|
||||
|
||||
async def get_feeds(db_file):
|
||||
"""
|
||||
Query table feeds and list items.
|
||||
|
|
|
@ -53,9 +53,9 @@ from slixfeed.xmpp.connect import XmppConnect
|
|||
from slixfeed.xmpp.utility import get_chat_type
|
||||
import time
|
||||
|
||||
main_task = []
|
||||
jid_tasker = {}
|
||||
task_manager = {}
|
||||
# main_task = []
|
||||
# jid_tasker = {}
|
||||
# task_manager = {}
|
||||
loop = asyncio.get_event_loop()
|
||||
|
||||
|
||||
|
@ -71,12 +71,12 @@ loop = asyncio.get_event_loop()
|
|||
|
||||
|
||||
def ping_task(self):
|
||||
global ping_task_instance
|
||||
# global ping_task_instance
|
||||
try:
|
||||
ping_task_instance.cancel()
|
||||
self.ping_task_instance.cancel()
|
||||
except:
|
||||
logging.info('No ping task to cancel.')
|
||||
ping_task_instance = asyncio.create_task(XmppConnect.ping(self))
|
||||
self.ping_task_instance = asyncio.create_task(XmppConnect.ping(self))
|
||||
|
||||
|
||||
"""
|
||||
|
@ -94,21 +94,28 @@ await taskhandler.start_tasks(
|
|||
|
||||
"""
|
||||
async def start_tasks_xmpp(self, jid, tasks=None):
|
||||
"""
|
||||
NOTE
|
||||
|
||||
For proper activation of tasks involving task 'interval', it is essential
|
||||
to place task 'interval' as the last to start due to await asyncio.sleep()
|
||||
which otherwise would postpone tasks that would be set after task 'interval'
|
||||
"""
|
||||
if jid == self.boundjid.bare:
|
||||
return
|
||||
try:
|
||||
task_manager[jid]
|
||||
self.task_manager[jid]
|
||||
except KeyError as e:
|
||||
task_manager[jid] = {}
|
||||
self.task_manager[jid] = {}
|
||||
logging.debug('KeyError:', str(e))
|
||||
logging.info('Creating new task manager for JID {}'.format(jid))
|
||||
if not tasks:
|
||||
tasks = ['status', 'check', 'interval']
|
||||
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid))
|
||||
for task in tasks:
|
||||
# if task_manager[jid][task]:
|
||||
# if self.task_manager[jid][task]:
|
||||
try:
|
||||
task_manager[jid][task].cancel()
|
||||
self.task_manager[jid][task].cancel()
|
||||
except:
|
||||
logging.info('No task {} for JID {} (start_tasks_xmpp)'
|
||||
.format(task, jid))
|
||||
|
@ -120,10 +127,10 @@ async def start_tasks_xmpp(self, jid, tasks=None):
|
|||
# breakpoint()
|
||||
match task:
|
||||
case 'check':
|
||||
task_manager[jid]['check'] = asyncio.create_task(
|
||||
self.task_manager[jid]['check'] = asyncio.create_task(
|
||||
check_updates(jid))
|
||||
case 'status':
|
||||
task_manager[jid]['status'] = asyncio.create_task(
|
||||
self.task_manager[jid]['status'] = asyncio.create_task(
|
||||
send_status(self, jid))
|
||||
case 'interval':
|
||||
jid_file = jid.replace('/', '_')
|
||||
|
@ -152,11 +159,11 @@ async def start_tasks_xmpp(self, jid, tasks=None):
|
|||
await sqlite.update_last_update_time(db_file)
|
||||
else:
|
||||
await sqlite.set_last_update_time(db_file)
|
||||
task_manager[jid]['interval'] = asyncio.create_task(
|
||||
self.task_manager[jid]['interval'] = asyncio.create_task(
|
||||
send_update(self, jid))
|
||||
# for task in task_manager[jid].values():
|
||||
# for task in self.task_manager[jid].values():
|
||||
# print("task_manager[jid].values()")
|
||||
# print(task_manager[jid].values())
|
||||
# print(self.task_manager[jid].values())
|
||||
# print("task")
|
||||
# print(task)
|
||||
# print("jid")
|
||||
|
@ -165,14 +172,14 @@ async def start_tasks_xmpp(self, jid, tasks=None):
|
|||
# await task
|
||||
|
||||
|
||||
async def clean_tasks_xmpp(jid, tasks=None):
|
||||
def clean_tasks_xmpp(self, jid, tasks=None):
|
||||
if not tasks:
|
||||
tasks = ['interval', 'status', 'check']
|
||||
logging.info('Stopping tasks {} for JID {}'.format(tasks, jid))
|
||||
for task in tasks:
|
||||
# if task_manager[jid][task]:
|
||||
# if self.task_manager[jid][task]:
|
||||
try:
|
||||
task_manager[jid][task].cancel()
|
||||
self.task_manager[jid][task].cancel()
|
||||
except:
|
||||
logging.debug('No task {} for JID {} (clean_tasks_xmpp)'
|
||||
.format(task, jid))
|
||||
|
@ -230,6 +237,8 @@ async def send_update(self, jid, num=None):
|
|||
media = await action.extract_image_from_html(url)
|
||||
|
||||
if media and news_digest:
|
||||
print('SENDING MESSAGE (if media and news_digest)')
|
||||
print(news_digest)
|
||||
# Send textual message
|
||||
XmppMessage.send(self, jid, news_digest, chat_type)
|
||||
news_digest = ''
|
||||
|
@ -238,6 +247,8 @@ async def send_update(self, jid, num=None):
|
|||
media = None
|
||||
|
||||
if news_digest:
|
||||
print('SENDING MESSAGE (if news_digest)')
|
||||
print(news_digest)
|
||||
# TODO Add while loop to assure delivery.
|
||||
# print(await current_time(), ">>> ACT send_message",jid)
|
||||
# NOTE Do we need "if statement"? See NOTE at is_muc.
|
||||
|
@ -255,14 +266,13 @@ async def send_update(self, jid, num=None):
|
|||
|
||||
# TODO Do not refresh task before
|
||||
# verifying that it was completed.
|
||||
await refresh_task(
|
||||
self, jid, send_update, 'interval')
|
||||
await refresh_task(self, jid, send_update, 'interval')
|
||||
# interval = await initdb(
|
||||
# jid,
|
||||
# sqlite.get_settings_value,
|
||||
# "interval"
|
||||
# )
|
||||
# task_manager[jid]["interval"] = loop.call_at(
|
||||
# self.task_manager[jid]["interval"] = loop.call_at(
|
||||
# loop.time() + 60 * interval,
|
||||
# loop.create_task,
|
||||
# send_update(jid)
|
||||
|
@ -298,7 +308,7 @@ async def send_status(self, jid):
|
|||
enabled = await config.get_setting_value(db_file, 'enabled')
|
||||
if not enabled:
|
||||
status_mode = 'xa'
|
||||
status_text = '📫️ Send "Start" to receive updates'
|
||||
status_text = '📪️ Send "Start" to receive updates'
|
||||
else:
|
||||
feeds = await sqlite.get_number_of_items(db_file, 'feeds')
|
||||
# print(await current_time(), jid, "has", feeds, "feeds")
|
||||
|
@ -350,29 +360,29 @@ async def refresh_task(self, jid, callback, key, val=None):
|
|||
jid_file = jid.replace('/', '_')
|
||||
db_file = config.get_pathname_to_database(jid_file)
|
||||
val = await config.get_setting_value(db_file, key)
|
||||
# if task_manager[jid][key]:
|
||||
if jid in task_manager:
|
||||
# if self.task_manager[jid][key]:
|
||||
if jid in self.task_manager:
|
||||
try:
|
||||
task_manager[jid][key].cancel()
|
||||
self.task_manager[jid][key].cancel()
|
||||
except:
|
||||
logging.info('No task of type {} to cancel for '
|
||||
'JID {} (refresh_task)'.format(key, jid)
|
||||
)
|
||||
# task_manager[jid][key] = loop.call_at(
|
||||
# self.task_manager[jid][key] = loop.call_at(
|
||||
# loop.time() + 60 * float(val),
|
||||
# loop.create_task,
|
||||
# (callback(self, jid))
|
||||
# # send_update(jid)
|
||||
# )
|
||||
task_manager[jid][key] = loop.create_task(
|
||||
self.task_manager[jid][key] = loop.create_task(
|
||||
wait_and_run(self, callback, jid, val)
|
||||
)
|
||||
# task_manager[jid][key] = loop.call_later(
|
||||
# self.task_manager[jid][key] = loop.call_later(
|
||||
# 60 * float(val),
|
||||
# loop.create_task,
|
||||
# send_update(jid)
|
||||
# )
|
||||
# task_manager[jid][key] = send_update.loop.call_at(
|
||||
# self.task_manager[jid][key] = send_update.loop.call_at(
|
||||
# send_update.loop.time() + 60 * val,
|
||||
# send_update.loop.create_task,
|
||||
# send_update(jid)
|
||||
|
@ -399,7 +409,7 @@ async def check_updates(jid):
|
|||
while True:
|
||||
jid_file = jid.replace('/', '_')
|
||||
db_file = config.get_pathname_to_database(jid_file)
|
||||
urls = await sqlite.get_feeds_url(db_file)
|
||||
urls = await sqlite.get_active_feeds_url(db_file)
|
||||
for url in urls:
|
||||
await action.scan(db_file, url)
|
||||
val = config.get_value('settings', 'Settings', 'check')
|
||||
|
@ -416,7 +426,7 @@ async def check_updates(jid):
|
|||
NOTE
|
||||
This is an older system, utilizing local storage instead of XMPP presence.
|
||||
This function is good for use with protocols that might not have presence.
|
||||
ActivityPub, IRC, LXMF, Matrix, SMTP, Tox.
|
||||
ActivityPub, IRC, LXMF, Matrix, Nostr, SMTP, Tox.
|
||||
"""
|
||||
async def select_file(self):
|
||||
"""
|
||||
|
@ -446,10 +456,8 @@ async def select_file(self):
|
|||
if (file.endswith('.db') and
|
||||
not file.endswith('.db-jour.db')):
|
||||
jid = file[:-3]
|
||||
main_task.extend(
|
||||
[tg.create_task(self.task_jid(jid))]
|
||||
)
|
||||
main_task.extend([tg.create_task(self.task_jid(jid))])
|
||||
# main_task = [tg.create_task(self.task_jid(jid))]
|
||||
# task_manager.update({jid: tg})
|
||||
# self.task_manager.update({jid: tg})
|
||||
|
||||
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
__version__ = '0.1.1'
|
||||
__version_info__ = (0, 1, 1)
|
||||
__version__ = '0.1.2'
|
||||
__version_info__ = (0, 1, 2)
|
||||
|
|
|
@ -100,12 +100,20 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
# NOTE
|
||||
# The bot works fine when the nickname is hardcoded; or
|
||||
# The bot won't join some MUCs when its nickname has brackets
|
||||
|
||||
# Handler for nickname
|
||||
self.alias = alias
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
|
||||
# Handlers for tasks
|
||||
self.task_manager = {}
|
||||
|
||||
# Handlers for ping
|
||||
self.ping_task_instance = {}
|
||||
|
||||
# Handlers for connection events
|
||||
self.connection_attempts = 0
|
||||
self.max_connection_attempts = 10
|
||||
|
||||
self.add_event_handler("session_start",
|
||||
self.on_session_start)
|
||||
self.add_event_handler("session_resumed",
|
||||
|
@ -158,9 +166,6 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
# Initialize event loop
|
||||
# self.loop = asyncio.get_event_loop()
|
||||
|
||||
# handlers for connection events
|
||||
self.connection_attempts = 0
|
||||
self.max_connection_attempts = 10
|
||||
self.add_event_handler('connection_failed',
|
||||
self.on_connection_failed)
|
||||
self.add_event_handler('session_end',
|
||||
|
@ -174,8 +179,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
muc_jid = message['groupchat_invite']['jid']
|
||||
await XmppBookmark.add(self, muc_jid)
|
||||
await XmppGroupchat.join(self, inviter, muc_jid)
|
||||
message_body = ('Greetings!\n'
|
||||
'I am {}, the news anchor.\n'
|
||||
message_body = ('Greetings! I am {}, the news anchor.\n'
|
||||
'My job is to bring you the latest '
|
||||
'news from sources you provide me with.\n'
|
||||
'You may always reach me via xmpp:{}?message'
|
||||
|
@ -189,8 +193,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
muc_jid = message['groupchat_invite']['jid']
|
||||
await XmppBookmark.add(self, muc_jid)
|
||||
await XmppGroupchat.join(self, inviter, muc_jid)
|
||||
message_body = ('Greetings!\n'
|
||||
'I am {}, the news anchor.\n'
|
||||
message_body = ('Greetings! I am {}, the news anchor.\n'
|
||||
'My job is to bring you the latest '
|
||||
'news from sources you provide me with.\n'
|
||||
'You may always reach me via xmpp:{}?message'
|
||||
|
@ -260,14 +263,14 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
# await task.check_readiness(self, presence)
|
||||
jid = presence['from'].bare
|
||||
if presence['show'] in ('away', 'dnd', 'xa'):
|
||||
await task.clean_tasks_xmpp(jid, ['interval'])
|
||||
task.clean_tasks_xmpp(self, jid, ['interval'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status', 'check'])
|
||||
|
||||
|
||||
async def on_presence_subscribe(self, presence):
|
||||
jid = presence['from'].bare
|
||||
if not self.client_roster[jid]['to']:
|
||||
XmppPresence.subscribe(self, jid)
|
||||
XmppPresence.subscription(self, jid, 'subscribe')
|
||||
await XmppRoster.add(self, jid)
|
||||
status_message = '✒️ Share online status to receive updates'
|
||||
XmppPresence.send(self, jid, status_message)
|
||||
|
@ -280,8 +283,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
async def on_presence_subscribed(self, presence):
|
||||
jid = presence['from'].bare
|
||||
message_subject = 'RSS News Bot'
|
||||
message_body = ('Greetings!\n'
|
||||
'I am {}, the news anchor.\n'
|
||||
message_body = ('Greetings! I am {}, the news anchor.\n'
|
||||
'My job is to bring you the latest '
|
||||
'news from sources you provide me with.\n'
|
||||
'You may always reach me via xmpp:{}?message'
|
||||
|
@ -304,17 +306,19 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
async def on_presence_unsubscribed(self, presence):
|
||||
jid = presence['from'].bare
|
||||
message_body = 'You have been unsubscribed.'
|
||||
status_message = '🖋️ Subscribe to receive updates'
|
||||
# status_message = '🖋️ Subscribe to receive updates'
|
||||
# status_message = None
|
||||
XmppMessage.send(self, jid, message_body, 'chat')
|
||||
XmppPresence.send(self, jid, status_message,
|
||||
presence_type='unsubscribed')
|
||||
XmppPresence.subscription(self, jid, 'unsubscribe')
|
||||
# XmppPresence.send(self, jid, status_message,
|
||||
# presence_type='unsubscribed')
|
||||
await XmppRoster.remove(self, jid)
|
||||
|
||||
|
||||
async def on_presence_unavailable(self, presence):
|
||||
jid = presence['from'].bare
|
||||
# await task.stop_tasks(self, jid)
|
||||
await task.clean_tasks_xmpp(jid)
|
||||
task.clean_tasks_xmpp(self, jid)
|
||||
|
||||
|
||||
# TODO
|
||||
|
@ -326,7 +330,7 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
print("on_presence_error")
|
||||
print(presence)
|
||||
jid = presence["from"].bare
|
||||
await task.clean_tasks_xmpp(jid)
|
||||
task.clean_tasks_xmpp(self, jid)
|
||||
|
||||
|
||||
async def on_reactions(self, message):
|
||||
|
@ -337,36 +341,36 @@ class Slixfeed(slixmpp.ClientXMPP):
|
|||
async def on_chatstate_active(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_composing(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
status_message='Press "help" for manual, or "info" for information.'
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_message='💡 Press "help" for manual, or "info" for information.'
|
||||
XmppPresence.send(self, jid, status_message)
|
||||
|
||||
|
||||
async def on_chatstate_gone(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_inactive(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_paused(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
|
|
|
@ -3,44 +3,10 @@
|
|||
|
||||
"""
|
||||
|
||||
FIXME
|
||||
|
||||
1) Function check_readiness or event "changed_status" is causing for
|
||||
triple status messages and also false ones that indicate of lack
|
||||
of feeds.
|
||||
|
||||
TODO
|
||||
|
||||
1) Use loop (with gather) instead of TaskGroup.
|
||||
|
||||
2) Assure message delivery before calling a new task.
|
||||
See https://slixmpp.readthedocs.io/en/latest/event_index.html#term-marker_acknowledged
|
||||
|
||||
3) XHTTML-IM
|
||||
case _ if message_lowercase.startswith("html"):
|
||||
message['html']="
|
||||
Parse me!
|
||||
"
|
||||
self.send_message(
|
||||
mto=jid,
|
||||
mfrom=self.boundjid.bare,
|
||||
mhtml=message
|
||||
)
|
||||
|
||||
NOTE
|
||||
|
||||
1) Self presence
|
||||
Apparently, it is possible to view self presence.
|
||||
This means that there is no need to store presences in order to switch or restore presence.
|
||||
check_readiness
|
||||
📂 Send a URL from a blog or a news website.
|
||||
JID: self.boundjid.bare
|
||||
MUC: self.alias
|
||||
|
||||
2) Extracting attribute using xmltodict.
|
||||
import xmltodict
|
||||
message = xmltodict.parse(str(message))
|
||||
jid = message["message"]["x"]["@jid"]
|
||||
1) Look into self.set_jid in order to be able to join to groupchats
|
||||
https://slixmpp.readthedocs.io/en/latest/api/basexmpp.html#slixmpp.basexmpp.BaseXMPP.set_jid
|
||||
|
||||
"""
|
||||
|
||||
|
@ -97,11 +63,23 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
def __init__(self, jid, secret, hostname, port, alias=None):
|
||||
slixmpp.ComponentXMPP.__init__(self, jid, secret, hostname, port)
|
||||
|
||||
# The session_start event will be triggered when
|
||||
# the bot establishes its connection with the server
|
||||
# and the XML streams are ready for use. We want to
|
||||
# listen for this event so that we we can initialize
|
||||
# our roster.
|
||||
# NOTE
|
||||
# The bot works fine when the nickname is hardcoded; or
|
||||
# The bot won't join some MUCs when its nickname has brackets
|
||||
|
||||
# Handler for nickname
|
||||
self.alias = alias
|
||||
|
||||
# Handlers for tasks
|
||||
self.task_manager = {}
|
||||
|
||||
# Handlers for ping
|
||||
self.ping_task_instance = {}
|
||||
|
||||
# Handlers for connection events
|
||||
self.connection_attempts = 0
|
||||
self.max_connection_attempts = 10
|
||||
|
||||
self.add_event_handler("session_start",
|
||||
self.on_session_start)
|
||||
self.add_event_handler("session_resumed",
|
||||
|
@ -154,9 +132,6 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
# Initialize event loop
|
||||
# self.loop = asyncio.get_event_loop()
|
||||
|
||||
# handlers for connection events
|
||||
self.connection_attempts = 0
|
||||
self.max_connection_attempts = 10
|
||||
self.add_event_handler('connection_failed',
|
||||
self.on_connection_failed)
|
||||
self.add_event_handler('session_end',
|
||||
|
@ -241,21 +216,20 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
# await task.check_readiness(self, presence)
|
||||
jid = presence['from'].bare
|
||||
if presence['show'] in ('away', 'dnd', 'xa'):
|
||||
await task.clean_tasks_xmpp(jid, ['interval'])
|
||||
task.clean_tasks_xmpp(self, jid, ['interval'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status', 'check'])
|
||||
|
||||
|
||||
async def on_presence_subscribe(self, presence):
|
||||
jid = presence['from'].bare
|
||||
# XmppPresence.request(self, jid)
|
||||
XmppPresence.subscribe(self, jid)
|
||||
XmppPresence.subscription(self, jid, 'subscribe')
|
||||
|
||||
|
||||
async def on_presence_subscribed(self, presence):
|
||||
jid = presence['from'].bare
|
||||
message_subject = 'RSS News Bot'
|
||||
message_body = ('Greetings!\n'
|
||||
'I am {}, the news anchor.\n'
|
||||
message_body = ('Greetings! I am {}, the news anchor.\n'
|
||||
'My job is to bring you the latest '
|
||||
'news from sources you provide me with.\n'
|
||||
'You may always reach me via xmpp:{}?message'
|
||||
|
@ -278,16 +252,18 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
async def on_presence_unsubscribed(self, presence):
|
||||
jid = presence['from'].bare
|
||||
message_body = 'You have been unsubscribed.'
|
||||
status_message = '🖋️ Subscribe to receive updates'
|
||||
# status_message = '🖋️ Subscribe to receive updates'
|
||||
# status_message = None
|
||||
XmppMessage.send(self, jid, message_body, 'chat')
|
||||
XmppPresence.send(self, jid, status_message,
|
||||
presence_type='unsubscribed')
|
||||
XmppPresence.subscription(self, jid, 'unsubscribe')
|
||||
# XmppPresence.send(self, jid, status_message,
|
||||
# presence_type='unsubscribed')
|
||||
|
||||
|
||||
async def on_presence_unavailable(self, presence):
|
||||
jid = presence['from'].bare
|
||||
# await task.stop_tasks(self, jid)
|
||||
await task.clean_tasks_xmpp(jid)
|
||||
task.clean_tasks_xmpp(self, jid)
|
||||
|
||||
|
||||
# TODO
|
||||
|
@ -299,7 +275,7 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
print("on_presence_error")
|
||||
print(presence)
|
||||
jid = presence["from"].bare
|
||||
await task.clean_tasks_xmpp(jid)
|
||||
task.clean_tasks_xmpp(self, jid)
|
||||
|
||||
|
||||
async def on_reactions(self, message):
|
||||
|
@ -310,36 +286,36 @@ class SlixfeedComponent(slixmpp.ComponentXMPP):
|
|||
async def on_chatstate_active(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_composing(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
status_message='Press "help" for manual, or "info" for information.'
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_message='💡 Press "help" for manual, or "info" for information.'
|
||||
XmppPresence.send(self, jid, status_message)
|
||||
|
||||
|
||||
async def on_chatstate_gone(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_inactive(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
async def on_chatstate_paused(self, message):
|
||||
if message['type'] in ('chat', 'normal'):
|
||||
jid = message['from'].bare
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
|
||||
|
||||
|
|
|
@ -24,6 +24,28 @@ NOTE
|
|||
|
||||
See XEP-0367: Message Attaching
|
||||
|
||||
FIXME
|
||||
|
||||
ERROR:asyncio:Task exception was never retrieved
|
||||
future: <Task finished name='Task-3410' coro=<send_update() done, defined at /home/admin/.venv/lib/python3.11/site-packages/slixfeed/task.py:181> exception=ParseError('not well-formed (invalid token): line 1, column 198')>
|
||||
Traceback (most recent call last):
|
||||
File "/home/jojo/.venv/lib/python3.11/site-packages/slixfeed/task.py", line 237, in send_update
|
||||
XmppMessage.send_oob(self, jid, media, chat_type)
|
||||
File "/home/jojo/.venv/lib/python3.11/site-packages/slixfeed/xmpp/message.py", line 56, in send_oob
|
||||
message = self.make_message(mto=jid,
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/basexmpp.py", line 517, in make_message
|
||||
message['html']['body'] = mhtml
|
||||
~~~~~~~~~~~~~~~^^^^^^^^
|
||||
File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/xmlstream/stanzabase.py", line 792, in __setitem__
|
||||
getattr(self, set_method)(value, **kwargs)
|
||||
File "/home/jojo/.venv/lib/python3.11/site-packages/slixmpp/plugins/xep_0071/stanza.py", line 38, in set_body
|
||||
xhtml = ET.fromstring(content)
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
File "/usr/lib/python3.11/xml/etree/ElementTree.py", line 1338, in XML
|
||||
parser.feed(text)
|
||||
xml.etree.ElementTree.ParseError: not well-formed (invalid token): line 1, column 198
|
||||
|
||||
"""
|
||||
|
||||
class XmppMessage:
|
||||
|
@ -50,6 +72,7 @@ class XmppMessage:
|
|||
|
||||
|
||||
def send_oob(self, jid, url, chat_type):
|
||||
try:
|
||||
html = (
|
||||
f'<body xmlns="http://www.w3.org/1999/xhtml">'
|
||||
f'<a href="{url}">{url}</a></body>')
|
||||
|
@ -60,6 +83,9 @@ class XmppMessage:
|
|||
mtype=chat_type)
|
||||
message['oob']['url'] = url
|
||||
message.send()
|
||||
except:
|
||||
logging.error('ERROR!')
|
||||
logging.error(jid, url, chat_type, html)
|
||||
|
||||
|
||||
# FIXME Solve this function
|
||||
|
|
|
@ -17,8 +17,6 @@ FIXME
|
|||
|
||||
"""
|
||||
import logging
|
||||
from slixfeed.dt import current_time
|
||||
from slixfeed.xmpp.message import XmppMessage
|
||||
|
||||
class XmppGroupchat:
|
||||
|
||||
|
|
|
@ -7,6 +7,10 @@ NOTE
|
|||
|
||||
Accept symbols 🉑️ 👍️ ✍
|
||||
|
||||
TODO
|
||||
|
||||
Remove subscription from JID that do not (stopped) share presence.
|
||||
|
||||
"""
|
||||
|
||||
class XmppPresence:
|
||||
|
@ -20,18 +24,8 @@ class XmppPresence:
|
|||
ptype=presence_type)
|
||||
|
||||
|
||||
def subscribe(self, jid):
|
||||
def subscription(self, jid, presence_type):
|
||||
self.send_presence_subscription(pto=jid,
|
||||
pfrom=self.boundjid.bare,
|
||||
ptype='subscribe',
|
||||
ptype=presence_type,
|
||||
pnick=self.alias)
|
||||
|
||||
|
||||
def remove(self):
|
||||
"""
|
||||
Remove subscription from JID that do not (stopped) share presence.
|
||||
|
||||
Returns
|
||||
-------
|
||||
None.
|
||||
"""
|
||||
|
|
|
@ -86,7 +86,7 @@ async def message(self, message):
|
|||
if (message_text.lower().startswith('http') and
|
||||
message_text.lower().endswith('.opml')):
|
||||
url = message_text
|
||||
await task.clean_tasks_xmpp(jid, ['status'])
|
||||
task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_type = 'dnd'
|
||||
status_message = '📥️ Procesing request to import feeds...'
|
||||
XmppPresence.send(self, jid, status_message,
|
||||
|
@ -97,7 +97,7 @@ async def message(self, message):
|
|||
response = 'Successfully imported {} feeds.'.format(count)
|
||||
else:
|
||||
response = 'OPML file was not imported.'
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
XmppMessage.send_reply(self, message, response)
|
||||
return
|
||||
|
@ -296,7 +296,7 @@ async def message(self, message):
|
|||
await action.scan(db_file, url)
|
||||
old = await config.get_setting_value(db_file, "old")
|
||||
if old:
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
# await send_status(jid)
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
else:
|
||||
|
@ -489,33 +489,25 @@ async def message(self, message):
|
|||
# case _ if (message_lowercase.startswith('http')) and(
|
||||
# message_lowercase.endswith('.opml')):
|
||||
# url = message_text
|
||||
# await task.clean_tasks_xmpp(
|
||||
# jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
# status_type = 'dnd'
|
||||
# status_message = (
|
||||
# '📥️ Procesing request to import feeds...'
|
||||
# )
|
||||
# XmppPresence.send(
|
||||
# self, jid, status_message, status_type=status_type)
|
||||
# status_message = '📥️ Procesing request to import feeds...'
|
||||
# XmppPresence.send(self, jid, status_message,
|
||||
# status_type=status_type)
|
||||
# db_file = config.get_pathname_to_database(jid_file)
|
||||
# count = await action.import_opml(db_file, url)
|
||||
# if count:
|
||||
# response = (
|
||||
# 'Successfully imported {} feeds.'
|
||||
# ).format(count)
|
||||
# response = ('Successfully imported {} feeds.'
|
||||
# .format(count))
|
||||
# else:
|
||||
# response = (
|
||||
# 'OPML file was not imported.'
|
||||
# )
|
||||
# await task.clean_tasks_xmpp(
|
||||
# jid, ['status'])
|
||||
# await task.start_tasks_xmpp(
|
||||
# self, jid, ['status'])
|
||||
# response = 'OPML file was not imported.'
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
# await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
# XmppMessage.send_reply(self, message, response)
|
||||
case _ if (message_lowercase.startswith('http') or
|
||||
message_lowercase.startswith('feed:')):
|
||||
url = message_text
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_type = 'dnd'
|
||||
status_message = ('📫️ Processing request '
|
||||
'to fetch data from {}'
|
||||
|
@ -528,7 +520,7 @@ async def message(self, message):
|
|||
db_file = config.get_pathname_to_database(jid_file)
|
||||
# try:
|
||||
response = await action.add_feed(db_file, url)
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
# except:
|
||||
# response = (
|
||||
|
@ -641,25 +633,11 @@ async def message(self, message):
|
|||
|
||||
await task.send_update(self, jid)
|
||||
|
||||
# await task.clean_tasks_xmpp(
|
||||
# jid, ['interval', 'status'])
|
||||
# await task.start_tasks_xmpp(
|
||||
# self, jid, ['interval', 'status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['interval', 'status'])
|
||||
# await task.start_tasks_xmpp(self, jid, ['status', 'interval'])
|
||||
|
||||
# await refresh_task(
|
||||
# self,
|
||||
# jid,
|
||||
# send_update,
|
||||
# 'interval',
|
||||
# num
|
||||
# )
|
||||
# await refresh_task(
|
||||
# self,
|
||||
# jid,
|
||||
# send_status,
|
||||
# 'status',
|
||||
# 20
|
||||
# )
|
||||
# await refresh_task(self, jid, send_update, 'interval', num)
|
||||
# await refresh_task(self, jid, send_status, 'status', 20)
|
||||
# await refresh_task(jid, key, val)
|
||||
case 'old':
|
||||
db_file = config.get_pathname_to_database(jid_file)
|
||||
|
@ -703,7 +681,7 @@ async def message(self, message):
|
|||
data = message_text[5:]
|
||||
data = data.split()
|
||||
url = data[0]
|
||||
await task.clean_tasks_xmpp(jid, ['status'])
|
||||
task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_type = 'dnd'
|
||||
status_message = ('📫️ Processing request to fetch data from {}'
|
||||
.format(url))
|
||||
|
@ -787,7 +765,7 @@ async def message(self, message):
|
|||
# 'status',
|
||||
# 20
|
||||
# )
|
||||
# await task.clean_tasks_xmpp(jid, ['status'])
|
||||
# task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
else:
|
||||
response = 'Missing feed URL or index number.'
|
||||
|
@ -795,7 +773,7 @@ async def message(self, message):
|
|||
case _ if message_lowercase.startswith('reset'):
|
||||
# TODO Reset also by ID
|
||||
ix_url = message_text[6:]
|
||||
await task.clean_tasks_xmpp(jid, ['status'])
|
||||
task.clean_tasks_xmpp(self, jid, ['status'])
|
||||
status_type = 'dnd'
|
||||
status_message = '📫️ Marking entries as read...'
|
||||
XmppPresence.send(self, jid, status_message,
|
||||
|
@ -859,22 +837,24 @@ async def message(self, message):
|
|||
response = await action.list_statistics(db_file)
|
||||
XmppMessage.send_reply(self, message, response)
|
||||
case _ if message_lowercase.startswith('disable '):
|
||||
ix = message_text[8:]
|
||||
feed_id = message_text[8:]
|
||||
db_file = config.get_pathname_to_database(jid_file)
|
||||
try:
|
||||
await sqlite.set_enabled_status(db_file, ix, 0)
|
||||
await sqlite.set_enabled_status(db_file, feed_id, 0)
|
||||
await sqlite.mark_feed_as_read(db_file, feed_id)
|
||||
response = ('Updates are now disabled for news source {}.'
|
||||
.format(ix))
|
||||
.format(feed_id))
|
||||
except:
|
||||
response = 'No news source with index {}.'.format(ix)
|
||||
response = 'No news source with index {}.'.format(feed_id)
|
||||
XmppMessage.send_reply(self, message, response)
|
||||
await task.start_tasks_xmpp(self, jid, ['status'])
|
||||
case _ if message_lowercase.startswith('enable'):
|
||||
ix = message_text[7:]
|
||||
feed_id = message_text[7:]
|
||||
db_file = config.get_pathname_to_database(jid_file)
|
||||
try:
|
||||
await sqlite.set_enabled_status(db_file, ix, 1)
|
||||
await sqlite.set_enabled_status(db_file, feed_id, 1)
|
||||
response = ('Updates are now enabled for news source {}.'
|
||||
.format(ix))
|
||||
.format(feed_id))
|
||||
except:
|
||||
response = 'No news source with index {}.'.format(ix)
|
||||
XmppMessage.send_reply(self, message, response)
|
||||
|
|
Loading…
Reference in a new issue