Don't use string formatting and handle timeout and minor changes

Thank you habnabit_
This commit is contained in:
Schimon Jehudah 2022-12-11 13:45:42 +00:00
parent 10735697ce
commit fe00073380

View file

@ -1,6 +1,13 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# TODO
#
# 0) sql prepared statements
# 1) Autodetect feed:
# if page is not feed (or HTML) and contains <link rel="alternate">
# 2) OPML import/export
# vars and their meanings: # vars and their meanings:
# cur = Cursor (SQL) # cur = Cursor (SQL)
# jid = Jabber ID (XMPP) # jid = Jabber ID (XMPP)
@ -181,7 +188,7 @@ def print_help():
" disable \n" " disable \n"
" Stop sending updates. \n" " Stop sending updates. \n"
" feed list \n" " feed list \n"
" List subscriptions list. \n" " List subscriptions. \n"
"\n" "\n"
"EDIT OPTIONS: \n" "EDIT OPTIONS: \n"
" feed add URL \n" " feed add URL \n"
@ -308,6 +315,8 @@ def create_connection(db_file):
return conn return conn
# NOTE I don't think there should be "return"
# because then we might stop scanning next URLs
async def download_updates(db_file): async def download_updates(db_file):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
urls = await get_subscriptions(conn) urls = await get_subscriptions(conn)
@ -316,6 +325,13 @@ async def download_updates(db_file):
source = url[0] source = url[0]
res = await download_feed(source) res = await download_feed(source)
# TypeError: 'NoneType' object is not subscriptable
if res is None:
# Skip to next feed
# urls.next()
# next(urls)
continue
sql = "UPDATE feeds SET status = :status, scanned = :scanned WHERE address = :url" sql = "UPDATE feeds SET status = :status, scanned = :scanned WHERE address = :url"
async with DBLOCK: async with DBLOCK:
with conn: with conn:
@ -341,7 +357,7 @@ async def download_updates(db_file):
cur.execute(sql, {"validity": valid, "url": source}) cur.execute(sql, {"validity": valid, "url": source})
except (IncompleteReadError, IncompleteRead, error.URLError) as e: except (IncompleteReadError, IncompleteRead, error.URLError) as e:
print(e) print(e)
return # return
# TODO Place these couple of lines back down # TODO Place these couple of lines back down
# NOTE Need to correct the SQL statement to do so # NOTE Need to correct the SQL statement to do so
# NOT SURE WHETHER I MEANT THE LINES ABOVE OR BELOW # NOT SURE WHETHER I MEANT THE LINES ABOVE OR BELOW
@ -377,20 +393,33 @@ async def download_updates(db_file):
#print('~~~~~~summary not in entry') #print('~~~~~~summary not in entry')
entry = (title, summary, link, source, 0); entry = (title, summary, link, source, 0);
async with DBLOCK: async with DBLOCK:
# print("add entry:", entry)
with conn: with conn:
await add_entry(conn, entry) await add_entry(conn, entry)
await set_date(conn, source) await set_date(conn, source)
#del length
#entries = 0
async def download_feed(url): async def download_feed(url):
timeout = aiohttp.ClientTimeout(total=10)
async with aiohttp.ClientSession() as session: async with aiohttp.ClientSession() as session:
async with session.get(url) as response: # async with aiohttp.ClientSession(trust_env=True) as session:
status = response.status try:
if response.status == 200: async with session.get(url, timeout=timeout) as response:
doc = await response.text() status = response.status
return [doc, status] if response.status == 200:
else: doc = await response.text()
return [False, status] return [doc, status]
else:
return [False, status]
except aiohttp.ClientError as e:
print('Error', str(e))
return [False, "error"]
except asyncio.TimeoutError as e:
print('Timeout', str(e))
return [False, "timeout"]
async def check_feed(conn, url): async def check_feed(conn, url):
@ -425,7 +454,7 @@ async def add_feed(db_file, url):
return "News source is already listed in the subscription list" return "News source is already listed in the subscription list"
async with DBLOCK: async with DBLOCK:
with create_connection(db_file) as conn: with conn:
cur = conn.cursor() cur = conn.cursor()
if res[0]: if res[0]:
feed = feedparser.parse(res[0]) feed = feedparser.parse(res[0])
@ -450,7 +479,7 @@ async def add_feed(db_file, url):
return "Failed to get URL. HTTP Error {}".format(res[1]) return "Failed to get URL. HTTP Error {}".format(res[1])
source = title if title else '<' + url + '>' source = title if title else '<' + url + '>'
msg = 'News source "{}" has been added to subscriptions list'.format(source) msg = 'News source "{}" has been added to subscription list'.format(source)
return msg return msg
@ -471,7 +500,7 @@ async def remove_feed(db_file, ix):
cur.execute(sql, (url,)) cur.execute(sql, (url,))
sql = "DELETE FROM feeds WHERE id = ?" sql = "DELETE FROM feeds WHERE id = ?"
cur.execute(sql, (ix,)) cur.execute(sql, (ix,))
return """News source <{}> has been removed from subscriptions list return """News source <{}> has been removed from subscription list
""".format(url) """.format(url)
@ -482,40 +511,42 @@ async def get_unread(db_file):
:param id: id of the entry :param id: id of the entry
:return: string :return: string
""" """
async with DBLOCK: with create_connection(db_file) as conn:
with create_connection(db_file) as conn: entry = []
entry = [] cur = conn.cursor()
cur = conn.cursor() sql = "SELECT id FROM entries WHERE read = 0"
sql = "SELECT id FROM entries WHERE read = 0" ix = cur.execute(sql).fetchone()
ix = cur.execute(sql).fetchone() if ix is None:
if ix is None: return False
return False ix = ix[0]
ix = ix[0] sql = "SELECT title FROM entries WHERE id = :id"
sql = "SELECT title FROM entries WHERE id = :id" cur.execute(sql, (ix,))
cur.execute(sql, (ix,)) title = cur.fetchone()[0]
title = cur.fetchone()[0] entry.append(title)
entry.append(title) sql = "SELECT summary FROM entries WHERE id = :id"
sql = "SELECT summary FROM entries WHERE id = :id" cur.execute(sql, (ix,))
cur.execute(sql, (ix,)) summary = cur.fetchone()[0]
summary = cur.fetchone()[0] entry.append(summary)
entry.append(summary) sql = "SELECT link FROM entries WHERE id = :id"
sql = "SELECT link FROM entries WHERE id = :id" cur.execute(sql, (ix,))
cur.execute(sql, (ix,)) link = cur.fetchone()[0]
link = cur.fetchone()[0] entry.append(link)
entry.append(link) entry = "{}\n\n{}\n\nLink to article:\n{}".format(entry[0], entry[1], entry[2])
entry = "{}\n\n{}\n\nLink to article:\n{}".format(entry[0], entry[1], entry[2]) print(entry)
await mark_as_read(cur, ix) await mark_as_read(conn, ix)
return entry return entry
async def mark_as_read(cur, ix): async def mark_as_read(conn, ix):
""" """
Set read status of entry Set read status of entry
:param cur: :param cur:
:param ix: index of the entry :param ix: index of the entry
""" """
sql = "UPDATE entries SET summary = '', read = 1 WHERE id = ?" async with DBLOCK:
cur.execute(sql, (ix,)) sql = "UPDATE entries SET summary = '', read = 1 WHERE id = ?"
cur = conn.cursor()
cur.execute(sql, (ix,))
# TODO mark_all_read for entries of feed # TODO mark_all_read for entries of feed
@ -582,8 +613,8 @@ async def set_date(conn, url):
:return: :return:
""" """
today = date.today() today = date.today()
cur = conn.cursor()
sql = "UPDATE feeds SET updated = :today WHERE address = :url" sql = "UPDATE feeds SET updated = :today WHERE address = :url"
cur = conn.cursor()
cur.execute(sql, {"today": today, "url": url}) cur.execute(sql, {"today": today, "url": url})
@ -642,8 +673,9 @@ async def last_entries(db_file, num):
num = 1 num = 1
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT title, link FROM entries ORDER BY ROWID DESC LIMIT {}".format(num) sql = "SELECT title, link FROM entries ORDER BY ROWID DESC LIMIT :num"
results = cur.execute(sql) results = cur.execute(sql, (num,))
titles_list = "Recent {} titles: \n".format(num) titles_list = "Recent {} titles: \n".format(num)
for result in results: for result in results:
@ -663,8 +695,8 @@ async def search_entries(db_file, query):
with create_connection(db_file) as conn: with create_connection(db_file) as conn:
cur = conn.cursor() cur = conn.cursor()
sql = "SELECT title, link FROM entries WHERE title LIKE '%{}%' LIMIT 50".format(query) sql = "SELECT title, link FROM entries WHERE title LIKE ? LIMIT 50"
results = cur.execute(sql) results = cur.execute(sql, [f'%{query}%'])
results_list = "Search results for '{}': \n".format(query) results_list = "Search results for '{}': \n".format(query)
counter = 0 counter = 0
@ -679,6 +711,8 @@ async def search_entries(db_file, query):
async def check_entry(conn, title, link): async def check_entry(conn, title, link):
#print("check_entry")
#time.sleep(1)
""" """
Check whether an entry exists Check whether an entry exists
Query entries by title and link Query entries by title and link
@ -687,8 +721,8 @@ async def check_entry(conn, title, link):
:param title: :param title:
:return: row :return: row
""" """
cur = conn.cursor()
sql = "SELECT id FROM entries WHERE title = :title and link = :link" sql = "SELECT id FROM entries WHERE title = :title and link = :link"
cur = conn.cursor()
cur.execute(sql, {"title": title, "link": link}) cur.execute(sql, {"title": title, "link": link})
return cur.fetchone() return cur.fetchone()