diff --git a/README.md b/README.md index db09818..6ef2c7f 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,14 @@ opening an article Delete -See read articles in the trash can +#### Handling read articles + +See read articles in the trash can. + +Or ask feather to keep read articles: + +`server.only_sync_unread_articles = false` +`html.filename_template = "{% if unread %}☐{% else %}☑{% endif %} [{{ feed_title }}]\t{{ title }} ({{ published_formatted }}).html"` ### Updating with the server diff --git a/src/feather/client.py b/src/feather/client.py index 80218ca..c515bc1 100644 --- a/src/feather/client.py +++ b/src/feather/client.py @@ -14,8 +14,8 @@ class ClientSession(ABC): config: Config @abstractmethod - def mark_as_read(self, articles_ids: list[ArticleId]): - """Mark all the given articles as read.""" + def set_read_flag(self, article_ids: list[ArticleId], read: bool = True): + """Mark all the given articles as read or unread.""" pass @abstractmethod @@ -40,9 +40,12 @@ class GReaderSession(ClientSession): self.greader = google_reader.Client(config.server_url) self.auth_token = self.greader.login(config.server_user, config.server_password) self.csrf_token = self.greader.get_token(self.auth_token) - - def mark_as_read(self, articles_ids: list[ArticleId]): - self.greader.edit_tags(self.auth_token, self.csrf_token, item_ids=articles_ids, add_tags=[google_reader.STREAM_READ]) + + def set_read_flag(self, article_ids: list[ArticleId], read: bool = True): + if read: + self.greader.edit_tags(self.auth_token, self.csrf_token, item_ids=article_ids, add_tags=[google_reader.STREAM_READ]) + else: + self.greader.edit_tags(self.auth_token, self.csrf_token, item_ids=article_ids, remove_tags=[google_reader.STREAM_READ]) def list_categories(self) -> list[Category]: categories = [tag for tag in self.greader.list_tags(self.auth_token) if tag.type == "folder"] @@ -101,8 +104,11 @@ class TTRSession(ClientSession): self.ttrss.login() self.feeds = {} - def mark_as_read(self, articles_ids: list[ArticleId]): - self.ttrss.mark_read(articles_ids) + def set_unread(self, article_ids: list[ArticleId], read: bool = True): + if read: + self.ttrss.mark_read(article_ids) + else: + self.ttrss.mark_unread(article_ids) def list_categories(self) -> list[Category]: self.feeds = {} diff --git a/src/feather/feather.py b/src/feather/feather.py index 78d637a..703fe20 100755 --- a/src/feather/feather.py +++ b/src/feather/feather.py @@ -45,28 +45,35 @@ class FeatherApp: dirpath.rmdir() removed_directories.add(dirpath) - def mark_deleted_as_read(self): - """Mark articles that are in the JSON directory but with missing HTML file as read on the server""" + def toggle_read_flag_for_deleted(self): + """Mark articles that are in the JSON directory but with missing HTML file as read/unread on the server""" config = self.config client_session = self.get_client_session() if config.update_lock.exists(): - print("The previous synchronization was aborted, not marking any article as read in order to avoid collateral damage") + print("The previous synchronization was aborted, not marking any article as read/unread in order to avoid collateral damage") return - marked_as_read = 0 + marked_as_read, marked_as_unread = 0, 0 to_mark_as_read = [] + to_mark_as_unread = [] for json_path in config.json_root.glob("*.json"): article = FileArticle(config, json_path) html_path = config.html_root / article.html_path if not html_path.exists(): - to_mark_as_read.append(article.id) - marked_as_read += 1 + if article.unread: + to_mark_as_read.append(article.id) + marked_as_read += 1 + else: + to_mark_as_unread.append(article.id) + marked_as_unread += 1 for i in range(0, len(to_mark_as_read), config.articles_per_query): - client_session.mark_as_read(to_mark_as_read[i:i+config.articles_per_query]) + client_session.set_read_flag(to_mark_as_read[i:i+config.articles_per_query], True) + for i in range(0, len(to_mark_as_unread), config.articles_per_query): + client_session.set_read_flag(to_mark_as_unread[i : i + config.articles_per_query], False) - print(f"Marked {marked_as_read} articles as read") + print(f"Marked {marked_as_read} articles as read, {marked_as_unread} unread") def synchronize_with_server(self): """Synchronize articles from the server, generating and deleting JSON and HTML files accordingly""" @@ -81,7 +88,7 @@ class FeatherApp: categories = client_session.list_categories() for category in categories: - print(f" Updating category {category.title}") + print(f" Synchronizing category {category.title}") remaining, continuation = True, 0 while remaining: @@ -116,14 +123,14 @@ class FeatherApp: def synchronize(self): """Do a full feather update""" - self.mark_deleted_as_read() + self.toggle_read_flag_for_deleted() self.synchronize_with_server() if self.config.hide_empty_categories: self.remove_empty_categories() def synchronize_local_changes(self): """Upload local changes (read articles) to the server""" - self.mark_deleted_as_read() + self.toggle_read_flag_for_deleted() if self.config.hide_empty_categories: self.remove_empty_categories()