commit cce2b9bc39025c678f6806b9c2f0fbec466336d1 Author: Manuel Fehren Date: Mon Apr 20 08:26:37 2026 +0200 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..e95cca9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +venv +__pycache__ +data/* \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..219f6fe --- /dev/null +++ b/README.md @@ -0,0 +1,75 @@ +# CameraCrawler + +This is a flask website to display Images from Webcams and timelaps, dependen on a .yaml config. + + +## Sample cameras.yaml +```yaml +- name: "Dummy" # name of camera + url: "" # camera-image url + interval: 5 # Capture intervall in minutes + timelapse: True # create timelapse every night + website: + picture: True # display camera on website + timelapse: True # display timelapse on website + +- name: "Dummy" + url: "" + interval: 5 + timelapse: True + website: + picture: True + timelapse: True + +``` + +## Sample docker-compose.yml +```yaml +version: '3.4' + +services: + cam-flask: + build: ./website + restart: unless-stopped + + volumes: + - ./cam/logs:/logs:rw + - ./cam/output:/static/output:ro + - /etc/localtime:/etc/localtime:ro + environment: + - TZ="Europe/Berlin" + + command: gunicorn -w 1 + -b :8000 app:app \ + --access-logfile ./logs/log.txt \ + --log-level info \ + --timeout 90 \ + --workers 25 \ + --worker-class gevent + + labels: + - "traefik.enable=true" + - "traefik.http.routers.cam.rule=Host(`cam.domain.com`)" + - "traefik.http.routers.cam.entrypoints=websecure" + - "traefik.http.services.cam.loadbalancer.server.port=8000" + - "traefik.http.routers.cam.service=cam" + - "traefik.http.routers.cam.tls.certresolver=production" + networks: + - traefik_default + + + cam-crawler: + build: ./crawler + restart: unless-stopped + + volumes: + - ./cam/timelapse:/archive:rw + - ./cam/output:/output:rw + - ./cam/config:/config:ro + - /etc/localtime:/etc/localtime:ro + command: python app.py + +networks: + traefik_default: + external: true +``` \ No newline at end of file diff --git a/crawler/.gitignore b/crawler/.gitignore new file mode 100644 index 0000000..9e85c42 --- /dev/null +++ b/crawler/.gitignore @@ -0,0 +1,7 @@ +venv +__pycache__ +timelapse +static/output +archive +output +app/config/cameras.yaml diff --git a/crawler/README.md b/crawler/README.md new file mode 100644 index 0000000..f311998 --- /dev/null +++ b/crawler/README.md @@ -0,0 +1,74 @@ +# CameraCrawler + +This is a python script, to crawl images from network cameras and creat a timelapse every night. + +## Sample cameras.yaml +```yaml +- name: "Dummy" # name of camera + url: "" # camera-image url + interval: 5 # Capture intervall in minutes + timelapse: True # create timelapse every night + website: + picture: True # display camera on website + timelapse: True # display timelapse on website + +- name: "Dummy" + url: "" + interval: 5 + timelapse: True + website: + picture: True + timelapse: True + +``` + +## Sample docker-compose.yml +```yaml +version: '3.4' + +services: + cam-flask: + image: registry.mnl-fhrn.de/lsrg/camerawebsite:latest + restart: unless-stopped + + volumes: + - ./cam/logs:/logs:rw + - ./cam/output:/static/output:ro + - /etc/localtime:/etc/localtime:ro + environment: + - TZ="Europe/Berlin" + + command: gunicorn -w 1 + -b :8000 app:app \ + --access-logfile ./logs/log.txt \ + --log-level info \ + --timeout 90 \ + --workers 25 \ + --worker-class gevent + + labels: + - "traefik.enable=true" + - "traefik.http.routers.cam.rule=Host(`cam.domain.com`)" + - "traefik.http.routers.cam.entrypoints=websecure" + - "traefik.http.services.cam.loadbalancer.server.port=8000" + - "traefik.http.routers.cam.service=cam" + - "traefik.http.routers.cam.tls.certresolver=production" + networks: + - traefik_default + + + cam-crawler: + image: registry.mnl-fhrn.de/lsrg/cameracrawler:latest + restart: unless-stopped + + volumes: + - ./cam/timelapse:/archive:rw + - ./cam/output:/output:rw + - ./cam/config:/config:ro + - /etc/localtime:/etc/localtime:ro + command: python app.py + +networks: + traefik_default: + external: true +``` \ No newline at end of file diff --git a/crawler/app/app.py b/crawler/app/app.py new file mode 100644 index 0000000..91c5293 --- /dev/null +++ b/crawler/app/app.py @@ -0,0 +1,114 @@ +from apscheduler.schedulers.background import BackgroundScheduler +import datetime +import time +import os +from pathlib import Path +import shutil +from PIL import Image +import requests +import atexit +import yaml +import timelaps + +os.environ['TZ'] = "Europe/Berlin" +time.tzset() + +sched = BackgroundScheduler(daemonic=True) + +with open("config/cameras.yaml", "r") as yamlfile: + yaml = yaml.load(yamlfile, Loader=yaml.FullLoader) + print("camera config read successful") +#print(yaml) + +def compress(src,dst): + + filepath = os.path.join(os.getcwd(), src) + + image = Image.open(filepath) + + image = image.resize((image.width // 2, image.height // 2), Image.LANCZOS) + + image.save(src, + "JPEG", + optimize = True, + quality = 90) + + shutil.copyfile(src, dst) + + return + + + +def crawl_image(url, name): + ct = datetime.datetime.now() + + file_path = "archive/" + name + "/" + ct.strftime("%Y%m%d") + file_name = name + "_" + ct.strftime("%Y%m%d_%H%M%S") + ".jpg" + + staticPath = "output" + + print('Started Image Downloaded: ',url) + Path(file_path).mkdir(parents=True, exist_ok=True) + Path(staticPath).mkdir(parents=True, exist_ok=True) + + # Download image + try: + res = requests.get(url, stream = True, auth=('admin', 'hackerspace')) + if res.status_code == 200: + with open(os.path.join(file_path,file_name),'wb') as f: + shutil.copyfileobj(res.raw, f) + print('Image sucessfully Downloaded: ',os.path.join(file_path,file_name)) + compress(os.path.join(file_path,file_name), staticPath + "/" + name + ".jpg") + + original_size = os.path.getsize(os.path.join(file_path,file_name)) + compressed_size = os.path.getsize(staticPath + "/" + name + ".jpg") + + print("Original Size: ", original_size) + print("Compressed Size: ", compressed_size) + print("New image at:-", ct) + print() + + else: + print("URL - Error:", url) + return -1 + except Exception as e: + print(e) + + + +def createTimelapsYesterday(name): + yesterday = datetime.datetime.now()- datetime.timedelta(days=1) + timelaps.createTimelaps(name=name,date=yesterday.strftime("%Y%m%d")) + + +def addJob(name, url, minutes): + sched.start() + + #create backgroundTask for each camera + for camera in yaml: + sched.add_job(crawl_image,'interval',[camera["url"], camera["name"]],minutes=camera["interval"],max_instances=1, id=camera["name"] + " - crawler") + crawl_image(camera["url"], camera["name"]) + if camera["timelapse"]: + sched.add_job(createTimelapsYesterday,'cron',[camera["name"]], hour='01',max_instances=1, id=camera["name"] + " - timelapse") + createTimelapsYesterday(camera["name"]) + + #atexit.register(lambda: scheduler.shutdown()) + print(camera["name"], "--- was added with", camera["interval"], "minutes interval") + + +def initCrawler(): + atexit.register(stopCrawler) + url_kantine = "http://192.168.187.80/cgi-bin/api.cgi?cmd=Snap&channel=0&rs=wuuPhkmUCeI9WG7C&user=smart&password=DwyU8AfK2p2PKT" + addJob("kantine", url_kantine, 5) + + +def stopCrawler(): + sched.shutdown(wait=True) + +if __name__ == '__main__': + initCrawler() + while(True): + time.sleep(1) + pass + + diff --git a/crawler/app/config/cameras_sample.yaml b/crawler/app/config/cameras_sample.yaml new file mode 100644 index 0000000..3e41289 --- /dev/null +++ b/crawler/app/config/cameras_sample.yaml @@ -0,0 +1,15 @@ +- name: "Dummy" # name of camera + url: "" # camera-image url + interval: 5 # Capture intervall in minutes + timelapse: True # create timelapse every night + website: + picture: True # display camera on website + timelapse: True # display timelapse on website + +- name: "Dummy" + url: "" + interval: 5 + timelapse: True + website: + picture: True + timelapse: True diff --git a/crawler/app/requirements.txt b/crawler/app/requirements.txt new file mode 100644 index 0000000..ecb4495 --- /dev/null +++ b/crawler/app/requirements.txt @@ -0,0 +1,4 @@ +APScheduler +pillow +requests +pyyaml \ No newline at end of file diff --git a/crawler/app/timelaps.py b/crawler/app/timelaps.py new file mode 100644 index 0000000..e2d0e65 --- /dev/null +++ b/crawler/app/timelaps.py @@ -0,0 +1,61 @@ +#import numpy as np +import os +import shutil + + +def createTimelaps(name, date = None, path = None): + staticPath = "output" + if date: + path = 'archive/' + name + '/' + date + elif path == None: + print("Error-Timelapse-missing args for folder") + return -1 + + if not os.path.exists(path): + print("Error-Timelapse-can't finde folder", path) + return -2 + + ## Check if folder exists and is not empty + if os.path.exists(path) and not os.path.isfile(path): + if not os.listdir(path): + print("Error-Timelapse-Empty directory", path) + return -3 + + #print('creating writer') + #videoSize = ( + # img_array[0].shape[1], + # img_array[0].shape[0] + #) + #writer = cv2.VideoWriter( path + '/' + name + '.mp4', cv2.VideoWriter_fourcc(*"mp4v"), 10, videoSize) + #print('writer created') + #print() + + + print('creating video') + + if os.path.exists(path + "/" + name + ".mp4"): + print("video allready exists") + os.remove(path + "/" + name + ".mp4") + imgWidht = 2304 + imgHeight = 864 + os.system('ffmpeg -hide_banner -loglevel error -stats -framerate 10 -pattern_type glob -i "' + path + '/*.jpg" -s:v ' + str(imgWidht) + 'x' + str(imgHeight) + ' -c:v libx264 -crf 17 -pix_fmt yuv420p ' + path + '/' + name + '.mp4') + + shutil.copyfile(path + "/" + name + ".mp4", staticPath + "/" + name + ".mp4") + print('video created') + print() + + try: + shutil.make_archive(path, 'zip', path) + print('zip created') + except: + print('Error while creating .zip') + + try: + shutil.rmtree(path) + print('folder cleared') + except: + print('Error while removing folder') + + +if __name__ == "__main__": + createTimelaps("kantine", path="timelapse/kantine/20230828") \ No newline at end of file diff --git a/crawler/dockerfile b/crawler/dockerfile new file mode 100644 index 0000000..21b5ea0 --- /dev/null +++ b/crawler/dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:1 + +FROM python:3.11 + + +COPY app/ . + +#COPY requirements.txt requirements.txt +RUN apt-get update && apt-get install ffmpeg -y +RUN pip3 install -r requirements.txt + +CMD ["python", "app.py"] +#CMD ["gunicorn" , "-b", "0.0.0.0:8000" , "app:app"] diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..6d370ee --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,57 @@ +version: '3.4' + +services: + birdstalker-flask: + build: ./website + restart: unless-stopped + stdin_open: true # docker run -i + tty: true # docker run -t + + volumes: + - ./data/logs:/logs:rw + - ./data/config:/config:ro + - ./data/output:/static/output:ro + - /etc/localtime:/etc/localtime:ro + #ports: + # - 5020:8000 + environment: + - TZ="Europe/Berlin" + #command: python app.py + + command: gunicorn -w 1 + -b :8000 app:app \ + --access-logfile ./logs/log.txt \ + --log-level info \ + --timeout 90 \ + --workers 25 \ + --worker-class gevent \ + --debug=True + + + labels: + - "traefik.enable=true" + - "traefik.http.routers.cameraWebsite.rule=Host(`camera.manuel-fehren.de`)" + - "traefik.http.routers.cameraWebsite.entrypoints=websecure" + - "traefik.http.services.cameraWebsite.loadbalancer.server.port=8000" + - "traefik.http.routers.cameraWebsite.service=cameraWebsite" + - "traefik.http.routers.cameraWebsite.tls.certresolver=production" + networks: + - traefik-net + + + bird-stalker-crawler: + build: ./crawler + restart: unless-stopped + stdin_open: true # docker run -i + tty: true # docker run -t + + volumes: + - ./data/timelapse:/archive:rw + - ./data/output:/output:rw + - ./data/config:/config:ro + - /etc/localtime:/etc/localtime:ro + command: python app.py + +networks: + traefik-net: + external: true diff --git a/website/.gitignore b/website/.gitignore new file mode 100644 index 0000000..9e85c42 --- /dev/null +++ b/website/.gitignore @@ -0,0 +1,7 @@ +venv +__pycache__ +timelapse +static/output +archive +output +app/config/cameras.yaml diff --git a/website/README.md b/website/README.md new file mode 100644 index 0000000..219f6fe --- /dev/null +++ b/website/README.md @@ -0,0 +1,75 @@ +# CameraCrawler + +This is a flask website to display Images from Webcams and timelaps, dependen on a .yaml config. + + +## Sample cameras.yaml +```yaml +- name: "Dummy" # name of camera + url: "" # camera-image url + interval: 5 # Capture intervall in minutes + timelapse: True # create timelapse every night + website: + picture: True # display camera on website + timelapse: True # display timelapse on website + +- name: "Dummy" + url: "" + interval: 5 + timelapse: True + website: + picture: True + timelapse: True + +``` + +## Sample docker-compose.yml +```yaml +version: '3.4' + +services: + cam-flask: + build: ./website + restart: unless-stopped + + volumes: + - ./cam/logs:/logs:rw + - ./cam/output:/static/output:ro + - /etc/localtime:/etc/localtime:ro + environment: + - TZ="Europe/Berlin" + + command: gunicorn -w 1 + -b :8000 app:app \ + --access-logfile ./logs/log.txt \ + --log-level info \ + --timeout 90 \ + --workers 25 \ + --worker-class gevent + + labels: + - "traefik.enable=true" + - "traefik.http.routers.cam.rule=Host(`cam.domain.com`)" + - "traefik.http.routers.cam.entrypoints=websecure" + - "traefik.http.services.cam.loadbalancer.server.port=8000" + - "traefik.http.routers.cam.service=cam" + - "traefik.http.routers.cam.tls.certresolver=production" + networks: + - traefik_default + + + cam-crawler: + build: ./crawler + restart: unless-stopped + + volumes: + - ./cam/timelapse:/archive:rw + - ./cam/output:/output:rw + - ./cam/config:/config:ro + - /etc/localtime:/etc/localtime:ro + command: python app.py + +networks: + traefik_default: + external: true +``` \ No newline at end of file diff --git a/website/app/app.py b/website/app/app.py new file mode 100644 index 0000000..aff715b --- /dev/null +++ b/website/app/app.py @@ -0,0 +1,59 @@ +from flask import Flask, send_file, render_template, request, abort +from prometheus_flask_exporter import PrometheusMetrics + +import logging +import time +import os +import yaml + +os.environ['TZ'] = "Europe/Berlin" +time.tzset() + + +logging.basicConfig( + filename='logs/flask.log', + encoding='utf-8', + level=logging.INFO, + format='%(asctime)s %(levelname)s:%(message)s' + ) + +with open("config/cameras.yaml", "r") as yamlfile: + config = yaml.load(yamlfile, Loader=yaml.FullLoader) + print("camera config read successful") +#print(yaml) + +app = Flask(__name__) + +metrics = PrometheusMetrics(app) + +metrics.info('app_info', 'Application info', version='1.0.3') + +#@app.errorhandler(500) +#def internal_error(error): +# +# return "500 error" + +@app.errorhandler(404) +def not_found(error): + filename = 'static/404.jpg' + return send_file(filename, mimetype='image/jpg'), 404 + +@app.route('/error',methods = ['POST', 'GET']) +def errorTest(): + abort(500) + +@app.route('/',methods = ['POST', 'GET']) +def index(): + return render_template('index.html', config=config) + +#@app.route('/BirdStalker') +#def get_image(): +# filename = 'static/BirdStalker.jpg' +# return send_file(filename, mimetype='image/jpg') + + + +# main driver function +if __name__ == '__main__': + app.run() + diff --git a/website/app/config/cameras_sample.yaml b/website/app/config/cameras_sample.yaml new file mode 100644 index 0000000..3e41289 --- /dev/null +++ b/website/app/config/cameras_sample.yaml @@ -0,0 +1,15 @@ +- name: "Dummy" # name of camera + url: "" # camera-image url + interval: 5 # Capture intervall in minutes + timelapse: True # create timelapse every night + website: + picture: True # display camera on website + timelapse: True # display timelapse on website + +- name: "Dummy" + url: "" + interval: 5 + timelapse: True + website: + picture: True + timelapse: True diff --git a/website/app/requirements.txt b/website/app/requirements.txt new file mode 100644 index 0000000..d2778dc --- /dev/null +++ b/website/app/requirements.txt @@ -0,0 +1,5 @@ +Flask +gunicorn +pyyaml +requests +prometheus-flask-exporter \ No newline at end of file diff --git a/website/app/static/404.jpg b/website/app/static/404.jpg new file mode 100644 index 0000000..0331311 Binary files /dev/null and b/website/app/static/404.jpg differ diff --git a/website/app/static/favicon.ico b/website/app/static/favicon.ico new file mode 100644 index 0000000..8c359ab Binary files /dev/null and b/website/app/static/favicon.ico differ diff --git a/website/app/static/images/background.svg b/website/app/static/images/background.svg new file mode 100644 index 0000000..489ca9f --- /dev/null +++ b/website/app/static/images/background.svg @@ -0,0 +1,3997 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/app/static/images/gras.svg b/website/app/static/images/gras.svg new file mode 100644 index 0000000..34d9703 --- /dev/null +++ b/website/app/static/images/gras.svg @@ -0,0 +1,10272 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/website/app/templates/index.html b/website/app/templates/index.html new file mode 100644 index 0000000..a67442f --- /dev/null +++ b/website/app/templates/index.html @@ -0,0 +1,78 @@ + + + + + + {% block title %}Birdstalker{% endblock %} + + + + + + + + + + + + + {% for camera in config%} + {% if camera.website.picture %} +
+

{{ camera.name }}

+ + + {% if camera.website.timelapse and camera.timelapse %} +

Gestern:

+ + {% endif %} +
+ {% endif %} + {%endfor%} + + + + + \ No newline at end of file diff --git a/website/dockerfile b/website/dockerfile new file mode 100644 index 0000000..a645861 --- /dev/null +++ b/website/dockerfile @@ -0,0 +1,13 @@ +# syntax=docker/dockerfile:1 + +FROM python:3.10 + + +COPY app/ . + +#COPY requirements.txt requirements.txt +#RUN apt-get update && apt-get install ffmpeg -y +RUN pip3 install -r requirements.txt + +CMD ["python", "app.py"] +#CMD ["gunicorn" , "-b", "0.0.0.0:8000" , "app:app"] \ No newline at end of file