105 lines
3.6 KiB
Python
105 lines
3.6 KiB
Python
import random
|
|
import favicon
|
|
import requests
|
|
from django.db import models
|
|
from django.db.models.options import override
|
|
from django.utils.translation import gettext as _
|
|
from django.core.files import File
|
|
|
|
from django.conf import settings
|
|
|
|
import logging
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
class Keyword(models.Model):
|
|
"""
|
|
this is the model that should contain searchable keywords
|
|
"""
|
|
slug = models.SlugField(unique=True)
|
|
text_de = models.CharField(max_length=40)
|
|
text_en = models.CharField(max_length=40)
|
|
|
|
def __str__(self):
|
|
return f"{{<{self.__class__.__name__}>\"{self.slug}\"}}"
|
|
|
|
class Meta:
|
|
verbose_name = _("Keyword")
|
|
verbose_name_plural = _("keywords")
|
|
|
|
class Link(models.Model):
|
|
"""
|
|
contains all my interesting links
|
|
"""
|
|
|
|
FAVICON_DIR: str = "img/links/favicons"
|
|
|
|
# the actual link
|
|
url = models.URLField(unique=True, null=False, primary_key=True)
|
|
favicon = models.ImageField(blank=True, upload_to=FAVICON_DIR, null=True)
|
|
personal = models.BooleanField(default=False)
|
|
title_de = models.CharField(max_length=50, default="Nicht übersetzt")
|
|
title_en = models.CharField(max_length=50, default="Not translated")
|
|
desc_de = models.TextField(
|
|
blank=True, max_length=250, unique=False, default="Keine Beschreibung")
|
|
desc_en = models.TextField(
|
|
blank=True, max_length=250, unique=False, default="no description")
|
|
keywords = models.ManyToManyField(Keyword, blank=True)
|
|
public = models.BooleanField(default=False)
|
|
|
|
def __str__(self):
|
|
return f"{{<{self.__class__.__name__}>\"{self.title_en}\"}}"
|
|
|
|
def regenerate(self):
|
|
"""
|
|
regenerate a object
|
|
|
|
Implements the abstract method of Searchable
|
|
|
|
Searches for a favicon in the urr, if one is found, it will be stored in MEDIA_ROOT
|
|
|
|
TODO filepathings here suck and are too error prone
|
|
"""
|
|
logger.info(f"regenerating {self.__class__.__name__} object: {self}")
|
|
self.suburl = f"/links#{self.title_en}"
|
|
logger.info(f"getting favicon for link object {self}: '{self.url}'")
|
|
try:
|
|
icons = favicon.get(self.url, timeout=2)
|
|
except (ConnectionError) as ce:
|
|
# just keep whatever was stored if we cant get a new favicon
|
|
logger.warn(
|
|
f"unable to download favicon for {self}: {ce.with_traceback(None)}")
|
|
self.status = False
|
|
|
|
except Exception as e:
|
|
logger.warn(
|
|
f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
|
self.status = False
|
|
|
|
else:
|
|
response = requests.get(icons[0].url, stream=True)
|
|
filename: str = f"favicon-{random.randint(0x1000, 0xffff)}.{icons[0].format}"
|
|
try:
|
|
with open(f"/tmp/{filename}", 'wb') as image:
|
|
for chunk in response.iter_content(1024):
|
|
image.write(chunk)
|
|
logger.debug(image)
|
|
with open(f"/tmp/{filename}", 'rb') as image:
|
|
self.favicon.save(filename, File(image))
|
|
logger.info(f"downloaded favicon for {self}")
|
|
self.status = True
|
|
|
|
except FileNotFoundError as fe:
|
|
logger.error(f"cant write favicon to file for {self}: {fe}")
|
|
self.favicon = None
|
|
|
|
except Exception as e:
|
|
logger.warn(
|
|
f"Unexpected Exception while downloading {self}: {e.with_traceback(None)}")
|
|
self.favicon = None
|
|
|
|
self.save()
|
|
|
|
class Meta:
|
|
verbose_name = _("Link")
|
|
verbose_name_plural = _("Links")
|