Skip to content

Commit

Permalink
New screenshot. Made raindrop call async. Removed a couple columns fr…
Browse files Browse the repository at this point in the history
…om models.
  • Loading branch information
JoshuaOliphant committed Aug 26, 2023
1 parent 37d7244 commit f2bff2f
Show file tree
Hide file tree
Showing 6 changed files with 87 additions and 81 deletions.
6 changes: 5 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ coverage.xml
*.py,cover
.hypothesis/
.pytest_cache/
__pycache__

# Translations
*.mo
Expand Down Expand Up @@ -133,4 +134,7 @@ dmypy.json
.DS_Store

# database
avocet.sqlite
avocet.sqlite

# vs code
.vscode
61 changes: 37 additions & 24 deletions avocet/app.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import time
import webbrowser
from textual import on
from textual import on, work, log
from textual.app import App, ComposeResult
from textual.widgets import OptionList
from textual.widgets.option_list import Option
Expand All @@ -15,44 +16,56 @@ def compose(self) -> ComposeResult:
yield OptionList(id="collection_option_list", )
yield OptionList(id="raindrop_option_list")

def on_mount(self) -> None:
self.initialize_collections()
self.initialize_raindrops(self.collections[0].id)
async def on_mount(self) -> None:
self.startup()

def initialize_collections(self):
@work
async def startup(self):
# Check if the database exists
start_time = time.time()
db_name = os.environ.get("DB_NAME", "avocet")
self.engine = create_engine(f'sqlite:///{db_name}.sqlite')
self.database_manager = DatabaseManager(self.engine)
if not os.path.exists(f"{db_name}.sqlite"):
db_path = f'{db_name}.sqlite'

if not os.path.exists(db_path):
self.engine = create_engine(f'sqlite:///{db_path}')
self.database_manager = DatabaseManager(self.engine)
self.database_manager.create_tables()
self.database_manager.add_collections()
await self.database_manager.add_collections()
else:
self.database_manager.update_collections()
self.collections = self.database_manager.getCollections()
options = [Option(prompt=collection.title, id=collection.id) for collection in self.collections]
option_list = self.query_one("#collection_option_list")
option_list.add_options(options)
self.engine = create_engine(f'sqlite:///{db_path}')
self.database_manager = DatabaseManager(self.engine)
await self.initialize_view()
end_time = time.time()
log(f"Startup time: {start_time-end_time}")

async def initialize_view(self):
collections = await self.database_manager.get_collections()
for collection in collections:
collection_options = [Option(prompt=collection.title, id=collection.id)]
collection_option_list = self.query_one("#collection_option_list")
collection_option_list.add_options(collection_options)
if collections:
raindrops = await self.database_manager.get_raindrops_by_collection_id(collections[0].id)
else:
raindrops = []
raindrop_options = [Option(prompt=raindrop.title, id=raindrop.id) for raindrop in raindrops]
raindrop_option_list = self.query_one("#raindrop_option_list")
raindrop_option_list.add_options(raindrop_options)

def initialize_raindrops(self, collection_id=None):
self.raindrops = self.database_manager.getRaindropsByCollectionID(collection_id)
options = [Option(prompt=raindrop.title, id=raindrop.id) for raindrop in self.raindrops]
option_list = self.query_one("#raindrop_option_list")
option_list.add_options(options)

@on(OptionList.OptionSelected, selector="#collection_option_list")
def select_collection(self, event: OptionList.OptionSelected):
async def select_collection(self, event: OptionList.OptionSelected):
collection_id = event.option.id
raindrops = self.database_manager.getRaindropsByCollectionID(collection_id)
raindrops = await self.database_manager.get_raindrops_by_collection_id(collection_id)
options = [Option(prompt=raindrop.title, id=raindrop.id) for raindrop in raindrops]
option_list = self.query_one("#raindrop_option_list")
option_list.clear_options()
option_list.add_options(options)

@on(OptionList.OptionSelected, selector="#raindrop_option_list")
def select_raidrop(self, event: OptionList.OptionSelected):
log("selected")
raindrop_id = event.option.id
raindrop = self.database_manager.getRaindropByRaindropID(raindrop_id)
raindrop = self.database_manager.get_raindrop_by_raindrop_id(raindrop_id)
webbrowser.open(raindrop.link)


Expand Down
64 changes: 29 additions & 35 deletions avocet/database_manager.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import time
from datetime import datetime
from sqlalchemy.orm import sessionmaker
from models import Collection, Base, Raindrop
from raindrop_api import RaindropAPI
from textual import log

class DatabaseManager:
def __init__(self, engine):
Expand All @@ -13,51 +12,46 @@ def __init__(self, engine):
def create_tables(self):
Base.metadata.create_all(self.engine)

def add_collections(self):
start_time = time.time()
async def add_collections(self):
session = self.Session()
raindrop_api = RaindropAPI()
collections = raindrop_api.getCollections()
for collection_data in collections:
collection = Collection(id=collection_data['_id'], title=collection_data['title'])

collection_data_list = await raindrop_api.get_collections()
for collection_data in collection_data_list:
collection = Collection(id=collection_data['_id'],
title=collection_data['title'],
description=collection_data["description"],
count=collection_data['count'],
created=datetime.strptime(collection_data['created'], "%Y-%m-%dT%H:%M:%S.%fZ"),
last_update=datetime.strptime(collection_data['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ"))
session.add(collection)
raindrops = raindrop_api.getRaindropsByCollectionID(collection_data['_id'])
for raindrop_data in raindrops:
raindrop = Raindrop(id=raindrop_data['_id'], excerpt=raindrop_data['excerpt'], title=raindrop_data['title'], link=raindrop_data['link'], collection_id=collection.id)
session.add(raindrop)
await self.add_raindrops(collection_data=collection, session=session, raindrop_api=raindrop_api)
session.commit()
end_time = time.time()
log(f"Added in {end_time - start_time} seconds")

def getCollections(self):
async def add_raindrops(self, collection_data, session, raindrop_api):
raindrop_data_list = await raindrop_api.get_raindrops_by_collection_id(collection_data.id)
for raindrop_data in raindrop_data_list:
raindrop = Raindrop(id=raindrop_data['_id'],
excerpt=raindrop_data['excerpt'],
note=raindrop_data['note'],
title=raindrop_data['title'],
link=raindrop_data['link'],
created=datetime.strptime(raindrop_data['created'], "%Y-%m-%dT%H:%M:%S.%fZ"),
last_update=datetime.strptime(raindrop_data['lastUpdate'], "%Y-%m-%dT%H:%M:%S.%fZ"),
collection_id=collection_data.id)
session.add(raindrop)

async def get_collections(self):
session = self.Session()
collections = session.query(Collection).all()
return collections

def getRaindropsByCollectionID(self, collection_id):
async def get_raindrops_by_collection_id(self, collection_id):
session = self.Session()
raindrops = session.query(Raindrop).filter(Raindrop.collection_id == collection_id).all()
return raindrops
def getRaindropByRaindropID(self, raindrop_id):

def get_raindrop_by_raindrop_id(self, raindrop_id):
session = self.Session()
raindrop = session.query(Raindrop).filter(Raindrop.id == raindrop_id).first()
return raindrop

def update_collections(self):
start_time = time.time()
session = self.Session()
raindrop_api = RaindropAPI()
collections = raindrop_api.getCollections()
existing_collections = self.getCollections()
not_existing_collections = [Collection(id=collection_data['_id'], title=collection_data['title']) for collection_data in collections if collection_data['_id'] not in [c.id for c in existing_collections]]
session.add_all(not_existing_collections)
session.commit()
for collection_data in collections:
raindrops = raindrop_api.getRaindropsByCollectionID(collection_data['_id'])
existing_raindrops = self.getRaindropsByCollectionID(collection_data['_id'])
not_existing_raindrops = [Raindrop(id=raindrop_data['_id'], excerpt=raindrop_data['excerpt'], title=raindrop_data['title'], link=raindrop_data['link'], collection_id=collection_data['_id']) for raindrop_data in raindrops if raindrop_data['_id'] not in [r.id for r in existing_raindrops]]
session.add_all(not_existing_raindrops)
session.commit()
end_time = time.time()
log(f"Updated in {end_time - start_time} seconds")
2 changes: 0 additions & 2 deletions avocet/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ class Collection(Base):
title = Column(String)
description = Column(String)
count = Column(Integer)
last_action = Column(DateTime)
created = Column(DateTime)
last_update = Column(DateTime)
raindrops = relationship("Raindrop", backref=backref("collection"))
Expand All @@ -20,7 +19,6 @@ class Raindrop(Base):
id = Column(Integer, primary_key=True)
excerpt = Column(String)
note = Column(String)
type = Column(String)
title = Column(String)
link = Column(String)
created = Column(DateTime)
Expand Down
35 changes: 16 additions & 19 deletions avocet/raindrop_api.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
from typing import Dict
import httpx
import os
import json
from datetime import datetime
from sqlalchemy import create_engine
from sqlalchemy.orm import sessionmaker
from models import Collection, Base
from textual import log

class RaindropAPI:
Expand All @@ -14,16 +9,23 @@ def __init__(self) -> None:
token = os.environ["RAINDROP"]
self._headers = {"Authorization": f"Bearer {token}"}

def getCollections(self) -> Dict:
r = httpx.get("https://api.raindrop.io/rest/v1/collections", headers=self._headers)
async def get_collections(self) -> Dict:
async with httpx.AsyncClient() as client:
r = await client.get("https://api.raindrop.io/rest/v1/collections", headers=self._headers)
return r.json()['items']

def getRaindropsByCollectionID(self, collection_id: str) -> Dict:
r = httpx.get(f"https://api.raindrop.io/rest/v1/raindrops/{collection_id}", headers=self._headers)
async def get_raindrops_by_collection_id(self, collection_id: str, search: str = None) -> Dict:
async with httpx.AsyncClient() as client:
if search:
params = {"search": search}
r = await client.get(f"https://api.raindrop.io/rest/v1/raindrops/{collection_id}", headers=self._headers, params=params)
else:
r = await client.get(f"https://api.raindrop.io/rest/v1/raindrops/{collection_id}", headers=self._headers)
return r.json()['items']

def getRaindropByRaindropId(self, raindrop_id: str) -> Dict:
r = httpx.get(f"https://api.raindrop.io/rest/v1/raindrop/{raindrop_id}", headers=self._headers)
async def get_raindrop_by_raindrop_id(self, raindrop_id: str) -> Dict:
async with httpx.AsyncClient() as client:
r = await client.get(f"https://api.raindrop.io/rest/v1/raindrop/{raindrop_id}", headers=self._headers)
item = r.json()['item']
raindrop = dict()
raindrop[item['_id']] = {
Expand All @@ -36,19 +38,14 @@ def getRaindropByRaindropId(self, raindrop_id: str) -> Dict:
r.close()
return raindrop

def postRaindrop(self, url: str, collection: str, tags: list) -> None:
async def post_raindrop(self, url: str, collection: str, tags: list) -> None:
raindrop = {
"link": url,
"collectionId": self.collections[collection]['id'],
"tags": tags
}
log(f"Posting raindrop: {raindrop}")
r = httpx.post("https://api.raindrop.io/rest/v1/raindrop", headers=self._headers, json=raindrop)
async with httpx.AsyncClient() as client:
r = await client.post("https://api.raindrop.io/rest/v1/raindrop", headers=self._headers, json=raindrop)
log(f"Raindrop posted: {r.json()}")
r.close()


if __name__ == "__main__":
raindrop = Raindrop()
collections = raindrop.getRaindropsBy('30350988')
print(collections)
Binary file modified media/Screenshot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit f2bff2f

Please sign in to comment.