Adding favicon API+test

pull/3196/head
dgtlmoon 2025-07-09 13:34:27 +02:00
rodzic 7b86ebd8ad
commit 82e0e63f7b
4 zmienionych plików z 48 dodań i 7 usunięć

Wyświetl plik

@ -5,7 +5,7 @@ from flask_expects_json import expects_json
from changedetectionio import queuedWatchMetaData
from changedetectionio import worker_handler
from flask_restful import abort, Resource
from flask import request, make_response
from flask import request, make_response, send_from_directory
import validators
from . import auth
import copy
@ -191,6 +191,38 @@ class WatchSingleHistory(Resource):
return response
class WatchFavicon(Resource):
def __init__(self, **kwargs):
# datastore is a black box dependency
self.datastore = kwargs['datastore']
@auth.check_token
def get(self, uuid):
"""
@api {get} /api/v1/watch/<string:uuid>/favicon Get Favicon for a watch
@apiDescription Requires watch `uuid`
@apiExample {curl} Example usage:
curl http://localhost:5000/api/v1/watch/cc0cfffa-f449-477b-83ea-0caafd1dc091/favicon -H"x-api-key:813031b16330fe25e3780cf0325daa45"
@apiName Get latest Favicon
@apiGroup Watch History
@apiSuccess (200) {String} OK
@apiSuccess (404) {String} ERR Not found
"""
watch = self.datastore.data['watching'].get(uuid)
if not watch:
abort(404, message=f"No watch exists with the UUID of {uuid}")
favicon_filename = watch.get_favicon_filename()
if favicon_filename:
import mimetypes
mime, encoding = mimetypes.guess_type(favicon_filename)
response = make_response(send_from_directory(watch.watch_data_dir, favicon_filename))
response.headers['Content-type'] = mime
response.headers['Cache-Control'] = 'max-age=300, must-revalidate' # Cache for 5 minutes, then revalidate
return response
abort(404, message=f'No Favicon available for {uuid}')
class CreateWatch(Resource):
def __init__(self, **kwargs):

Wyświetl plik

@ -26,7 +26,7 @@ schema_delete_notification_urls = copy.deepcopy(schema_notification_urls)
schema_delete_notification_urls['required'] = ['notification_urls']
# Import all API resources
from .Watch import Watch, WatchHistory, WatchSingleHistory, CreateWatch
from .Watch import Watch, WatchHistory, WatchSingleHistory, CreateWatch, WatchFavicon
from .Tags import Tags, Tag
from .Import import Import
from .SystemInfo import SystemInfo

Wyświetl plik

@ -19,12 +19,10 @@ from flask import (
Flask,
abort,
flash,
make_response,
redirect,
render_template,
request,
send_from_directory,
session,
url_for,
)
from flask_compress import Compress as FlaskCompress
@ -40,7 +38,7 @@ from loguru import logger
from changedetectionio import __version__
from changedetectionio import queuedWatchMetaData
from changedetectionio.api import Watch, WatchHistory, WatchSingleHistory, CreateWatch, Import, SystemInfo, Tag, Tags, Notifications
from changedetectionio.api import Watch, WatchHistory, WatchSingleHistory, CreateWatch, Import, SystemInfo, Tag, Tags, Notifications, WatchFavicon
from changedetectionio.api.Search import Search
from .time_handler import is_within_schedule
@ -307,7 +305,9 @@ def changedetection_app(config=None, datastore_o=None):
watch_api.add_resource(WatchSingleHistory,
'/api/v1/watch/<string:uuid>/history/<string:timestamp>',
resource_class_kwargs={'datastore': datastore, 'update_q': update_q})
watch_api.add_resource(WatchFavicon,
'/api/v1/watch/<string:uuid>/favicon',
resource_class_kwargs={'datastore': datastore})
watch_api.add_resource(WatchHistory,
'/api/v1/watch/<string:uuid>/history',
resource_class_kwargs={'datastore': datastore})
@ -436,7 +436,6 @@ def changedetection_app(config=None, datastore_o=None):
if not watch:
abort(404)
favicon_filename = watch.get_favicon_filename()
if favicon_filename:
import mimetypes

Wyświetl plik

@ -45,9 +45,19 @@ def test_fetch_webdriver_content(client, live_server, measure_memory_usage):
res = client.get(
url_for("watchlist.index"),
)
# The UI can access it here
assert f'src="/static/favicon/{uuid}'.encode('utf8') in res.data
# Attempt to fetch it, make sure that works
res = client.get(url_for('static_content', group='favicon', filename=uuid))
assert res.status_code == 200
assert len(res.data) > 10
# Check the API also returns it
api_key = live_server.app.config['DATASTORE'].data['settings']['application'].get('api_access_token')
res = client.get(
url_for("watchfavicon"),
headers={'x-api-key': api_key}
)
assert res.status_code == 200
assert len(res.data) > 10