Skip to content

Commit

Permalink
Merge pull request #16 from rwxd/feat/tags
Browse files Browse the repository at this point in the history
feat(readwise): synchronizing wallabag entry tags to article
  • Loading branch information
rwxd authored Dec 25, 2022
2 parents 92abc5e + 24037b3 commit 8958691
Show file tree
Hide file tree
Showing 5 changed files with 110 additions and 29 deletions.
47 changes: 33 additions & 14 deletions wallabag2readwise/misc.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from wallabag2readwise.models import Annotation
from wallabag2readwise.models import WallabagAnnotation
from wallabag2readwise.readwise import ReadwiseConnector, new_highlights
from wallabag2readwise.wallabag import WallabagConnector
from datetime import datetime
Expand All @@ -11,10 +11,10 @@ def push_annotations(wallabag: WallabagConnector, readwise: ReadwiseConnector):
readwise.get_books('books')
)

for entry in wallabag.get_entries():
if len(entry.annotations) > 0:
for wallabag_entry in wallabag.get_entries():
if len(wallabag_entry.annotations) > 0:
annotations = [
Annotation(
WallabagAnnotation(
id=i['id'],
text=i['text'],
quote=i['quote'],
Expand All @@ -23,23 +23,42 @@ def push_annotations(wallabag: WallabagConnector, readwise: ReadwiseConnector):
),
ranges=i['ranges'],
)
for i in entry.annotations
for i in wallabag_entry.annotations
]
logger.info(f'Found {len(annotations)} for "{entry.title}"')
for article in readwise_articles:
if article.title == entry.title:
highlights = list(readwise.get_book_highlights(article.id))
logger.info(f'Found {len(annotations)} for "{wallabag_entry.title}"')
for readwise_article in readwise_articles:
if readwise_article.title == wallabag_entry.title:
highlights = list(readwise.get_book_highlights(readwise_article.id))
console.print(
f'=> Found {len(highlights)} wallabag highlights for "{entry.title}"'
f'=> Found {len(highlights)} wallabag highlights for "{wallabag_entry.title}"'
)
for annotation in annotations:
if annotation.quote not in [i.text for i in highlights]:
new_highlights(readwise, entry, [annotation])
new_highlights(readwise, wallabag_entry, [annotation])
else:
logger.debug('Annotation already present')

readwise_article_tags = list(
readwise.get_book_tags(readwise_article.id)
)
for tag in wallabag_entry.tags:
if tag.label not in [i.name for i in readwise_article_tags]:
console.print(
f'==> Adding tag "{tag.label}" to Readwise article'
)
readwise.add_tag(readwise_article.id, tag.label)

for tag in readwise_article_tags:
if tag.name not in [i.label for i in wallabag_entry.tags]:
console.print(
f'==> Deleting tag "{tag.name}" from Readwise article'
)
readwise.delete_tag(readwise_article.id, tag.id)

break
else:
logger.info(f'Entry "{entry.title}" not present in Readwise')
console.print(f'==> Adding article "{entry.title}" to Readwise')
new_highlights(readwise, entry, annotations)
logger.info(f'Entry "{wallabag_entry.title}" not present in Readwise')
console.print(
f'==> Adding article "{wallabag_entry.title}" to Readwise'
)
new_highlights(readwise, wallabag_entry, annotations)
18 changes: 16 additions & 2 deletions wallabag2readwise/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,25 @@


@dataclass
class Entry:
class WallabagTag:
id: str
label: str
slug: str


@dataclass
class WallabagEntry:
id: str
title: str
content: str
url: str
hashed_url: str
annotations: list
tags: list[WallabagTag]


@dataclass
class Annotation:
class WallabagAnnotation:
id: str
text: str
quote: str
Expand All @@ -28,6 +36,12 @@ class ReadwiseBook:
source: str


@dataclass
class ReadwiseTag:
id: str
name: str


@dataclass
class ReadwiseHighlight:
id: str
Expand Down
17 changes: 16 additions & 1 deletion wallabag2readwise/output.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,18 @@
from rich.console import Console

console = Console()

class CustomConsole(Console):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)

def print_lvl1(self, text: str):
self.print(f'[bold blue]=> {text}[/bold blue]')

def print_lvl2(self, text: str):
self.print(f'[bold green]==> {text}[/bold green]')

def print_lvl3(self, text: str):
self.print(f'[bold yellow]===> {text}[/bold yellow]')


console = CustomConsole()
44 changes: 37 additions & 7 deletions wallabag2readwise/readwise.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,13 @@
from backoff import on_exception, expo
from time import sleep

from wallabag2readwise.models import Annotation, Entry, ReadwiseBook, ReadwiseHighlight
from wallabag2readwise.models import (
WallabagAnnotation,
WallabagEntry,
ReadwiseTag,
ReadwiseBook,
ReadwiseHighlight,
)
from wallabag2readwise.output import console


Expand Down Expand Up @@ -47,21 +53,19 @@ def _request(
seconds = int(response.headers['Retry-After'])
logger.warning(f'Rate limited by Readwise, retrying in {seconds} seconds')
sleep(seconds)
response = self._session.request(method, url, params=params, json=data)
response = self._session.request(method, url, params=params, data=data)
response.raise_for_status()
return response

def get(self, endpoint: str, params: dict = {}) -> requests.Response:
logger.debug(f'Getting "{endpoint}" with params: {params}')
response = self._request('GET', endpoint, params=params)
return response
return self._request('GET', endpoint, params=params)

@on_exception(expo, RateLimitException, max_tries=8)
@sleep_and_retry
@limits(calls=20, period=60)
def get_with_limit_20(self, endpoint: str, params: dict = {}) -> requests.Response:
response = self.get(endpoint, params)
return response
return self.get(endpoint, params)

def post(self, endpoint: str, data: dict = {}) -> requests.Response:
url = self.url + endpoint
Expand All @@ -70,6 +74,10 @@ def post(self, endpoint: str, data: dict = {}) -> requests.Response:
response.raise_for_status()
return response

def delete(self, endpoint: str) -> requests.Response:
logger.debug(f'Deleting "{endpoint}"')
return self._request('DELETE', endpoint)

def get_books(self, category: str) -> Generator[ReadwiseBook, None, None]:
page = 1
page_size = 1000
Expand Down Expand Up @@ -128,9 +136,31 @@ def create_highlight(

self.post('/highlights/', {'highlights': [payload]})

def get_book_tags(self, book_id: str) -> Generator[ReadwiseTag, None, None]:
page = 1
page_size = 1000
data = self.get(
f'/books/{book_id}/tags',
{'page': page, 'page_size': page_size, 'book_id': book_id},
).json()

for tag in data:
yield ReadwiseTag(tag['id'], tag['name'])

def add_tag(self, book_id: str, tag: str):
logger.debug(f'Adding tag "{tag}" to book "{book_id}"')
payload = {'name': tag}
self.post(f'/books/{book_id}/tags/', payload)

def delete_tag(self, book_id: str, tag_id: str):
logger.debug(f'Deleting tag "{tag_id}"')
self.delete(f'/books/{book_id}/tags/{tag_id}')


def new_highlights(
readwise: ReadwiseConnector, entry: Entry, annotations: list[Annotation]
readwise: ReadwiseConnector,
entry: WallabagEntry,
annotations: list[WallabagAnnotation],
):
for item in annotations:
console.print(f'==> Adding highlight to Readwise')
Expand Down
13 changes: 8 additions & 5 deletions wallabag2readwise/wallabag.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
from typing import Generator
from datetime import datetime

from wallabag2readwise.models import Annotation, Entry
from wallabag2readwise.models import WallabagAnnotation, WallabagEntry, WallabagTag


class WallabagConnector:
Expand Down Expand Up @@ -58,31 +58,34 @@ def post(self, endpoint: str, data: dict = {}) -> requests.Response:
response.raise_for_status()
return response

def get_entries(self) -> Generator[Entry, None, None]:
def get_entries(self) -> Generator[WallabagEntry, None, None]:
page = 1
perPage = 100
while True:
data = self.get(
'/api/entries.json', {'page': page, 'perPage': perPage}
).json()
for entry in data['_embedded']['items']:
yield Entry(
yield WallabagEntry(
id=entry['id'],
title=entry['title'],
url=entry['url'],
hashed_url=entry['hashed_url'],
content=entry['content'],
annotations=entry['annotations'],
tags=[WallabagTag(**tag) for tag in entry['tags']],
)

if page == data['pages']:
break
page += 1

def get_annotations(self, entry_id: str) -> Generator[Annotation, None, None]:
def get_annotations(
self, entry_id: str
) -> Generator[WallabagAnnotation, None, None]:
data = self.get(f'/api/annotations/{entry_id}.json').json()
for item in data['rows']:
yield Annotation(
yield WallabagAnnotation(
id=item['id'],
text=item['text'],
quote=item['quote'],
Expand Down

0 comments on commit 8958691

Please sign in to comment.