This repository has been archived on 2023-02-02. You can view files and clone it, but cannot push or open issues or pull requests.
barkshark-web/barkshark_web/database/rows.py
2022-04-16 06:23:04 -04:00

184 lines
3.7 KiB
Python

import re, traceback
from datetime import datetime, timedelta
from io import BytesIO
from izzylib_sql import Row
from mastodon import Mastodon
from PIL import Image
from urllib.parse import quote_plus
from urllib.request import urlopen, Request
from ..config import dirs
from ..functions import get_app
row_classes = {}
emojipatt = re.compile(r':.*?:')
def register_class(table):
def wrapper(cls):
row_classes[table] = cls
return cls
return wrapper
@register_class('search')
class Search(Row):
def compile(self, text):
if text.startswith(f'{self.keyword} '):
text = text[len(self.keyword)+1:]
search_text = quote_plus(text)
return self.url.format(q=search_text)
@register_class('accounts')
class Account(Row):
_api = None
_emojis = None
@property
def api(self):
if not self._api:
self._set_api()
return self._api
@property
def active(self):
with self._db.session as s:
return s.get_config('active_acct') == self.id
@property
def avatar(self):
return dirs.avatars.join(f'{self.id}.png')
@property
def bio(self):
try:
text = self.data['note'].replace('<p>', '<span class="bio-line">').replace('</p>', '</span>')
return self.replace_emojis(text)
except KeyError:
return
@property
def emojis(self):
if not self._emojis:
try:
self._emojis = self.fetch_emojis()
except:
traceback.print_exc()
self._emojis = {}
return self._emojis
@property
def fullhandle(self):
return f'{self.handle}@{self.domain}'
def _set_api(self):
self._api = Mastodon(access_token=self.token, api_base_url=f'https://{self.domain}')
logging.debug(f'logged into {self.fullhandle}')
def fetch_avatar(self):
byte = BytesIO()
http_client = get_app().http_client
with urlopen(Request(self.data.avatar_static, headers={'User-Agent': http_client.useragent})) as resp:
if resp.status != 200:
logging.error(f'Failed to download {self.data.avatar_static}:', resp.status)
return False
image = Image.open(resp)
image.thumbnail((256,256))
image.save(byte, format='png')
with dirs.avatars.join(f'{self.id}.png').open('wb') as fd:
fd.write(byte.getvalue())
return True
def fetch_emojis(self, refresh=False):
cache_path = dirs.emojis.join(self.domain + '.json')
emojis = DotDict()
try:
if cache_path.mtime + timedelta(days=7) < datetime.now():
raise FileNotFoundError('heck')
emojis.load_json(cache_path)
except FileNotFoundError:
refresh = True
if refresh:
for emoji in sorted(self.api.custom_emojis(), key=lambda x:x['shortcode']):
code = emoji.pop('shortcode')
emojis[code] = emoji
if len(emojis):
emojis.save_json(cache_path, indent=4)
return emojis
def fetch_post(self, url):
data = self.api.search_v2(url, resolve=True, result_type='statuses')['statuses']
return data[0] if len(data) else None
def refresh(self):
user_data = self.api.me()
instance = self.api.instance()
if not user_data:
logging.warning('Failed to fetch new user data')
return
with self._db.session as s:
try: toot_limit = instance['max_toot_chars']
except: toot_limit = 500
row = s.update_row(self,
username = user_data.display_name,
data = DotDict(user_data).to_json(),
toot_limit = toot_limit
)
for key, value in row.items():
self[key] = value
if not s.get_config('active_acct'):
s.put_config('active_acct', self.id)
self.fetch_avatar()
def replace_emojis(self, string):
for match in set(emojipatt.findall(string)):
try:
shortcode = match[1:-1]
url = self.emojis[shortcode].static_url
string = string.replace(match, f"<img class='emoji' src='{url}' title='{shortcode}' />")
except KeyError:
pass
return string
def set_active(self):
with self._db.session as s:
s.put_config('active_acct', self.id)