Skip to content

Commit be1db4c

Browse files
authored
📃 #12 — We should only bring down the statuses that don't exist in the SQLite database (#24)
1 parent af57c30 commit be1db4c

File tree

5 files changed

+73
-10
lines changed

5 files changed

+73
-10
lines changed

‎mastodon_to_sqlite/cli.py‎

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -165,7 +165,15 @@ def followings(db_path, auth):
165165
default="auth.json",
166166
help="Path to auth.json token file",
167167
)
168-
def statuses(db_path, auth):
168+
@click.option(
169+
"-u",
170+
"--update",
171+
is_flag=True,
172+
show_default=True,
173+
default=False,
174+
help="Update existing statuses",
175+
)
176+
def statuses(db_path, auth, update):
169177
"""
170178
Save statuses for the authenticated user.
171179
"""
@@ -177,8 +185,12 @@ def statuses(db_path, auth):
177185

178186
service.save_accounts(db, [authenticated_account])
179187

188+
since_id = None
189+
if update:
190+
since_id = service.get_most_recent_status_id(db)
191+
180192
with click.progressbar(
181-
service.get_statuses(account_id, client),
193+
service.get_statuses(account_id, client, since_id=since_id),
182194
label="Importing statuses",
183195
show_pos=True,
184196
) as bar:

‎mastodon_to_sqlite/client.py‎

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import datetime
22
from time import sleep
3-
from typing import Generator, Optional, Tuple
3+
from typing import Dict, Generator, Optional, Tuple
44

55
from requests import PreparedRequest, Request, Response, Session
66
from requests.auth import AuthBase
@@ -37,12 +37,15 @@ def request(
3737
self,
3838
method: str,
3939
path: str,
40+
params: Optional[Dict[str, str]] = None,
4041
timeout: Optional[Tuple[int, int]] = None,
4142
**kwargs,
4243
) -> Tuple[PreparedRequest, Response]:
4344
full_url = f"{self.api_url}/{path}"
4445

45-
request = Request(method=method.upper(), url=full_url, **kwargs)
46+
request = Request(
47+
method=method.upper(), url=full_url, params=params, **kwargs
48+
)
4649
prepped = self.session.prepare_request(request)
4750
response = self.session.send(prepped, timeout=timeout)
4851

@@ -52,14 +55,19 @@ def request_paginated(
5255
self,
5356
method: str,
5457
path: str,
58+
params: Optional[Dict[str, str]] = None,
5559
timeout: Optional[Tuple[int, int]] = None,
5660
**kwargs,
5761
) -> Generator[Tuple[PreparedRequest, Response], None, None]:
5862
next_path: Optional[str] = path
5963

6064
while next_path is not None:
6165
request, response = self.request(
62-
method=method, path=next_path, timeout=timeout, **kwargs
66+
method=method,
67+
path=next_path,
68+
timeout=timeout,
69+
params=params,
70+
**kwargs,
6371
)
6472
yield request, response
6573

@@ -82,6 +90,10 @@ def request_paginated(
8290
next_url = response.links["next"]["url"]
8391
next_path = next_url.replace(f"{self.api_url}/", "")
8492

93+
# Resetting the params because the next_path will provide the query
94+
# parameters.
95+
params = {}
96+
8597
def accounts_verify_credentials(self) -> Tuple[PreparedRequest, Response]:
8698
return self.request("GET", "accounts/verify_credentials")
8799

@@ -100,10 +112,17 @@ def accounts_following(
100112
)
101113

102114
def accounts_statuses(
103-
self, account_id: str
115+
self,
116+
account_id: str,
117+
since_id: Optional[str] = None,
104118
) -> Generator[Tuple[PreparedRequest, Response], None, None]:
119+
params = {"limit": "40"}
120+
121+
if since_id is not None:
122+
params["since_id"] = since_id
123+
105124
return self.request_paginated(
106-
"GET", f"accounts/{account_id}/statuses", params={"limit": "40"}
125+
"GET", f"accounts/{account_id}/statuses", params=params
107126
)
108127

109128
def bookmarks(

‎mastodon_to_sqlite/service.py‎

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -217,12 +217,14 @@ def save_accounts(
217217

218218

219219
def get_statuses(
220-
account_id: str, client: MastodonClient
220+
account_id: str, client: MastodonClient, since_id: Optional[str] = None
221221
) -> Generator[List[Dict[str, Any]], None, None]:
222222
"""
223223
Get authenticated account's statuses.
224224
"""
225-
for request, response in client.accounts_statuses(account_id):
225+
for request, response in client.accounts_statuses(
226+
account_id, since_id=since_id
227+
):
226228
yield response.json()
227229

228230

@@ -307,3 +309,20 @@ def save_activities(
307309
),
308310
pk=("account_id", "activity", "status_id"),
309311
)
312+
313+
314+
def get_most_recent_status_id(db: Database) -> Optional[int]:
315+
"""
316+
Get the most recent status ID from the SQLite database.
317+
"""
318+
table = get_table("statuses", db=db)
319+
320+
row = next(
321+
table.rows_where(order_by="created_at desc", select="id", limit=1),
322+
None,
323+
)
324+
325+
if row is None:
326+
return None
327+
328+
return row["id"]

‎tests/fixtures.py‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434

3535
STATUS_TWO = {
3636
"id": "2",
37-
"created_at": "2021-12-20T19:46:29.073Z",
37+
"created_at": "2021-12-20T20:46:29.073Z",
3838
"content": "Sleds are for suckers! Just ride on my gut!",
3939
"account": ACCOUNT_TWO,
4040
"bookmarked": True,

‎tests/test_services.py‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,16 @@ def test_save_multiple_activity_types(mock_db):
111111
assert mock_db["status_activities"].count == 4
112112
for row in mock_db["status_activities"].rows:
113113
assert row["account_id"] == 42
114+
115+
116+
def test_get_most_recent_status_id(mock_db):
117+
result = service.get_most_recent_status_id(mock_db)
118+
assert result is None
119+
120+
status_one = fixtures.STATUS_ONE.copy()
121+
status_two = fixtures.STATUS_TWO.copy()
122+
123+
service.save_statuses(mock_db, [status_one, status_two])
124+
125+
result = service.get_most_recent_status_id(mock_db)
126+
assert result == int(status_two["id"])

0 commit comments

Comments
 (0)