add class ReadingPosition

This commit is contained in:
Daniel Langbein 2022-12-14 12:13:25 +01:00
parent abd03d9154
commit ef52f66af8
5 changed files with 63 additions and 37 deletions

View File

@ -2,31 +2,37 @@ from feedgen.feed import FeedGenerator
from flask import url_for from flask import url_for
from mastodon_toot_follower import path_util from mastodon_toot_follower import path_util
from mastodon_toot_follower.conversation.reading_position import ReadingPosition
from mastodon_toot_follower.mastodon_factory import MastodonFactory from mastodon_toot_follower.mastodon_factory import MastodonFactory
from mastodon_toot_follower.conversation.update import Update as ConversationUpdate from mastodon_toot_follower.conversation.update import Update as ConversationUpdate
class Conversation: class Conversation:
def __init__(self, mastodon_factory: MastodonFactory, mastodon_instance: str, toot_id: str, seed: str = ''): def __init__(self, mastodon_factory: MastodonFactory, mastodon_instance: str, toot_id: str):
self.mastodon = mastodon_factory.get_mastodon(mastodon_instance) self.mastodon = mastodon_factory.get_mastodon(mastodon_instance)
self.toot_id = toot_id self.toot_id = toot_id
self.toot = self.mastodon.status(id=self.toot_id) self.toot = self.mastodon.status(id=self.toot_id)
escaped_uri = path_util.escape(self.toot["uri"]) escaped_uri = path_util.escape(self.toot["uri"])
if len(seed) > 0: self.file = mastodon_factory.toot_cache_dir().joinpath(f'{escaped_uri}.json')
escaped_seed = path_util.escape(seed)
self.file = mastodon_factory.toot_cache_dir().joinpath(f'{escaped_uri}_{escaped_seed}.json')
else:
self.file = mastodon_factory.toot_cache_dir().joinpath(f'{escaped_uri}.json')
# List of replies to initial toot. # List of replies to initial toot.
self.replies = self.mastodon.status_context(id=self.toot_id)['descendants'] self.replies = self.mastodon.status_context(id=self.toot_id)['descendants']
self.previous_updates: list[ConversationUpdate] = ConversationUpdate.load(self.file) previous_updates: list[ConversationUpdate] = ConversationUpdate.load(file=self.file)
self.new_updates = ConversationUpdate.get_new_updates(self.previous_updates, self.toots()) new_updates = ConversationUpdate.get_new_updates(previous_updates, self.toots())
self._updates = previous_updates + new_updates
if len(new_updates) > 0:
ConversationUpdate.save(updates=self._updates, file=self.file)
self._changes_saved = False def get_and_update_reading_position(self, user_id: str):
filename = self.file.stem + '_ReadingPosition.json'
file = self.file.parent.joinpath(filename)
rp = ReadingPosition(file=file, user_id=user_id)
new_reading_position = len(self.toots())
return rp.get_and_set(pos=new_reading_position)
def as_feed(self, feed_url) -> FeedGenerator: def as_feed(self, feed_url) -> FeedGenerator:
""" """
@ -47,7 +53,7 @@ class Conversation:
fg.language('en') fg.language('en')
update: ConversationUpdate update: ConversationUpdate
for update in self.updates(): for update in self._updates:
fe = fg.add_entry() fe = fg.add_entry()
fe.id(update.dict['uri']) fe.id(update.dict['uri'])
acct = update.dict['acct'] acct = update.dict['acct']
@ -65,17 +71,14 @@ class Conversation:
def conversation_length(self) -> int: def conversation_length(self) -> int:
return len(self.toots()) return len(self.toots())
def toots(self) -> list: def updates(self, reading_position: int = 0) -> list:
"""
:param: reading_position: If given, returns only conversation updates after the reading position.
"""
return self._updates[reading_position:]
def toots(self, reading_position: int = 0) -> list:
""" """
:return: List of initial toot and it's replies. :return: List of initial toot and it's replies.
""" """
return [self.toot] + self.replies return [self.toot] + self.replies
def updates(self) -> list[ConversationUpdate]:
return self.previous_updates + self.new_updates
def save_changes(self) -> None:
if self._changes_saved:
return
ConversationUpdate.save(self.updates(), self.file)
self._changes_saved = True

View File

@ -0,0 +1,26 @@
import json
from pathlib import Path
class ReadingPosition:
def __init__(self, file: Path, user_id: str):
self.file = file
self.user_id = user_id
if file.exists():
self.dict = json.loads(self.file.read_text())
else:
self.dict = {}
def get(self) -> int:
return self.dict.get(self.user_id, 0)
def set(self, pos: int):
self.dict[self.user_id] = pos
with self.file.open('w') as f:
f.write(json.dumps(self.dict))
def get_and_set(self, pos: int) -> int:
old_pos = self.get()
self.set(pos)
return old_pos

View File

@ -24,11 +24,16 @@ def main():
conversation = Conversation(mastodon_factory=mastodon_factory, conversation = Conversation(mastodon_factory=mastodon_factory,
mastodon_instance=instance_url, mastodon_instance=instance_url,
toot_id=toot_id) toot_id=toot_id)
conversation.save_changes() reading_position = conversation.get_and_update_reading_position('local_user')
print(f'Reading position: {reading_position}')
print(f'Conversation length: {conversation.conversation_length()}') print(f'Conversation length: {conversation.conversation_length()}')
print(f'Conversation updates:\n') new_updates = conversation.updates(reading_position=reading_position)
print('\n'.join([str(update) for update in conversation.new_updates])) if len(new_updates) == 0:
print('No new updates.')
else:
print(f'New updates:\n')
print('\n'.join([str(update) for update in new_updates]))
def usage(): def usage():

View File

@ -36,7 +36,6 @@ def rss():
instance_url, username, toot_id = mastodon_util.parse_toot_url(url=url) instance_url, username, toot_id = mastodon_util.parse_toot_url(url=url)
conversation = Conversation(mastodon_factory=mastodon_factory, mastodon_instance=instance_url, toot_id=toot_id) conversation = Conversation(mastodon_factory=mastodon_factory, mastodon_instance=instance_url, toot_id=toot_id)
conversation.save_changes()
fg = conversation.as_feed(request.url) fg = conversation.as_feed(request.url)
return Response(fg.rss_str(), mimetype='application/rss+xml') return Response(fg.rss_str(), mimetype='application/rss+xml')
@ -49,10 +48,10 @@ def html(seed: str):
conversation = Conversation(mastodon_factory=mastodon_factory, conversation = Conversation(mastodon_factory=mastodon_factory,
mastodon_instance=instance_url, mastodon_instance=instance_url,
toot_id=toot_id, seed=seed) toot_id=toot_id)
conversation.save_changes() reading_position = conversation.get_and_update_reading_position(user_id=seed)
return render_template(Templates.updates.value, updates=conversation.new_updates) return render_template(Templates.updates.value, updates=conversation.updates(reading_position=reading_position))
@app.route('/json/<string:seed>/') @app.route('/json/<string:seed>/')
@ -62,12 +61,11 @@ def json(seed: str):
conversation = Conversation(mastodon_factory=mastodon_factory, conversation = Conversation(mastodon_factory=mastodon_factory,
mastodon_instance=instance_url, mastodon_instance=instance_url,
toot_id=toot_id, toot_id=toot_id)
seed=seed) reading_position = conversation.get_and_update_reading_position(user_id=seed)
conversation.save_changes()
# If you return a dict or list from a view, it will be converted to a JSON response. # If you return a dict or list from a view, it will be converted to a JSON response.
return [update.dict for update in conversation.new_updates] return [update.dict for update in conversation.updates(reading_position=reading_position)]
if __name__ == '__main__': if __name__ == '__main__':

View File

@ -42,9 +42,3 @@
.styled-table tbody tr:last-of-type { .styled-table tbody tr:last-of-type {
border-bottom: medium solid #009879; border-bottom: medium solid #009879;
} }
/* Make the active row look different */
.styled-table tbody tr.active-row {
font-weight: bold;
color: #009879;
}