diff --git a/.drone.yaml b/.drone.yaml new file mode 100644 index 0000000..4550482 --- /dev/null +++ b/.drone.yaml @@ -0,0 +1,38 @@ +kind: pipeline +name: jellyfin-library-count-prometheus-exporter +type: docker + +platform: + os: linux + arch: arm64 + +steps: + - name: push-built-image + image: plugins/docker + settings: + context: app/ + dockerfile: app/Dockerfile + registry: gitea.scubbo.org + repo: gitea.scubbo.org/scubbo/jellyfin-library-count-prometheus-exporter + # https://laszlo.cloud/how-using-cache-from-can-speed-up-your-docker-builds-in-droneci + cache_from: + - "gitea.scubbo.org/scubbo/jellyfin-library-count-prometheus-exporter:latest" + tags: + - ${DRONE_COMMIT_SHA:0:10} + - latest + debug: true + launch_debug: true + username: scubbo + mtu: 1450 + password: + from_secret: gitea_password + - name: telegram_notification + image: appleboy/drone-telegram + settings: + token: + from_secret: telegram_token + to: + from_secret: telegram_convo_id + +image_pull_secrets: + - dockerconfigjson diff --git a/app/Dockerfile b/app/Dockerfile new file mode 100644 index 0000000..2c6d6f0 --- /dev/null +++ b/app/Dockerfile @@ -0,0 +1,13 @@ +FROM debian + +RUN apt update +RUN apt upgrade -y +RUN apt install -y python3 python3-pip + +ADD requirements.txt / +RUN pip3 install -r /requirements.txt + +ADD main.py /bin +RUN chmod +x /bin/main.py + +CMD /bin/main.py diff --git a/app/main.py b/app/main.py new file mode 100755 index 0000000..8fc29ff --- /dev/null +++ b/app/main.py @@ -0,0 +1,71 @@ +#!/usr/bin/env python3 + +import datetime +import json +import logging +import os +import sys +import time + +import requests +from functools import partial + +from prometheus_client import start_http_server, Gauge, REGISTRY, GC_COLLECTOR, PLATFORM_COLLECTOR, PROCESS_COLLECTOR + +REGISTRY.unregister(GC_COLLECTOR) +REGISTRY.unregister(PLATFORM_COLLECTOR) +REGISTRY.unregister(PROCESS_COLLECTOR) + + +MEDIA_TYPES = ['Movie', 'Series', 'Episode', 'Artist', 'Program', 'Trailer', 'Song', 'Album', 'MusicVideo','BoxSet', 'Book', 'Item'] + +CACHE_LAST_QUERIED = datetime.datetime.fromtimestamp(0) +CACHE = {} + +logging.basicConfig( + level=getattr(logging, os.environ.get('LOG_LEVEL', 'INFO')), + stream=sys.stdout, + format='%(asctime)s %(levelname)s %(message)s') +LOGGER = logging.getLogger(__name__) + + +def _refresh_cache(): + LOGGER.info('Refreshing cache') + full_url = f'{os.environ["API_URL"]}/Items/Counts?api_key={os.environ["API_KEY"]}' + LOGGER.debug(f'{full_url=}') + global CACHE + CACHE = requests.get(full_url).json() + LOGGER.debug(f'Refreshed cache with {CACHE}') + global CACHE_LAST_QUERIED + CACHE_LAST_QUERIED = datetime.datetime.now() + +def _fetch_value_from_cache(media_type): + # Should refresh? + if (not CACHE) or ((datetime.datetime.now()-CACHE_LAST_QUERIED).seconds >= os.environ.get('REFRESH_RATE', 60)): + _refresh_cache() + return CACHE[media_type+'Count'] + + +def _get_value(media_type): + return _fetch_value_from_cache(media_type) + return [media_type+'Count'] + + +def _gauge_update(media_type): + return partial(_get_value, media_type=media_type) + + +def main(): + gauges = {media_type: Gauge(f'jellyfin_{media_type}Count', f'Count of {media_type}') for media_type in MEDIA_TYPES} + for media_type, gauge in gauges.items(): + # Slightly inefficient that each Gauge will query + # independently rather than updating a + gauge.set_function(_gauge_update(media_type)) + start_http_server(8555) + LOGGER.info('Starting up!') + while True: + time.sleep(1) + + +if __name__ == '__main__': + main() \ No newline at end of file diff --git a/app/requirements.txt b/app/requirements.txt new file mode 100644 index 0000000..89fc49a --- /dev/null +++ b/app/requirements.txt @@ -0,0 +1 @@ +prometheus-client