daemon off;
user root;
worker_processes auto;

error_log /dev/stdout warn;
pid /var/run/nginx.pid;

events {
    worker_connections 1024;
}

http {
    map_hash_bucket_size 256;

    include mime.types;
    default_type application/octet-stream;

    log_format main '$remote_addr - $remote_user [$time_local] "$request" '
                        '$status $body_bytes_sent "$http_referer" '
                        '"$http_user_agent" "$http_x_forwarded_for" '
                        'request_time="$request_time" upstream_response_time="$upstream_response_time"';


    access_log /dev/stdout main;

    # send headers in one piece, it is better than sending them one by one
    tcp_nopush on;

    sendfile on;

    keepalive_timeout 65;

    gzip on;
    gzip_comp_level 6;
    gzip_types text/plain text/css application/json application/x-javascript application/javascript text/javascript image/svg+xml image/x-icon image/bmp;
    gzip_proxied no-cache no-store private expired auth;
    gzip_vary on;

    proxy_cache_path /dev/shm/nginx_cache levels=1:2 keys_zone=api_cache:10m max_size=10m inactive=1m use_temp_path=off;

    map $sent_http_content_type $should_not_cache {
        'application/json' 0;
        default 1;
    }

    upstream frigate_api {
        server 127.0.0.1:5001;
        keepalive 1024;
    }

    upstream mqtt_ws {
        server 127.0.0.1:5002;
        keepalive 1024;
    }

    upstream jsmpeg {
        server 127.0.0.1:8082;
        keepalive 1024;
    }

    include go2rtc_upstream.conf;

    server {
        include listen.conf;

        # vod settings
        vod_base_url '';
        vod_segments_base_url '';
        vod_mode mapped;
        vod_max_mapping_response_size 1m;
        vod_upstream_location /api;
        vod_align_segments_to_key_frames on;
        vod_manifest_segment_durations_mode accurate;
        vod_ignore_edit_list on;
        vod_segment_duration 10000;

        # MPEG-TS settings (not used when fMP4 is enabled, kept for reference)
        vod_hls_mpegts_align_frames off;
        vod_hls_mpegts_interleave_frames on;

        # file handle caching / aio
        open_file_cache max=1000 inactive=5m;
        open_file_cache_valid 2m;
        open_file_cache_min_uses 1;
        open_file_cache_errors on;
        aio on;

        # file upload size
        client_max_body_size 20M;

        # https://github.com/kaltura/nginx-vod-module#vod_open_file_thread_pool
        vod_open_file_thread_pool default;

        # vod caches
        vod_metadata_cache metadata_cache 512m;
        vod_mapping_cache mapping_cache 5m 10m;

        # gzip manifests
        gzip on;
        gzip_types application/vnd.apple.mpegurl;

        include auth_location.conf;
        include base_path.conf;

        location /vod/ {
            include auth_request.conf;
            aio threads;
            vod hls;

            # Use fMP4 (fragmented MP4) instead of MPEG-TS for better performance
            # Smaller segments, faster generation, better browser compatibility
            vod_hls_container_format fmp4;

            secure_token $args;
            secure_token_types application/vnd.apple.mpegurl;

            add_header Cache-Control "no-store";
            expires off;

            keepalive_disable safari;

            # vod module returns 502 for non-existent media
            # https://github.com/kaltura/nginx-vod-module/issues/468
            error_page 502 =404 /vod-not-found;
        }

        location = /vod-not-found {
            return 404;
        }

        location /stream/ {
            include auth_request.conf;
            add_header Cache-Control "no-store";
            expires off;

            types {
                application/dash+xml mpd;
                application/vnd.apple.mpegurl m3u8;
                video/mp2t ts;
                image/jpeg jpg;
            }

            root /tmp;
        }

        location /clips/ {
            include auth_request.conf;
            types {
                video/mp4 mp4;
                image/jpeg jpg;
            }

            expires 7d;
            add_header Cache-Control "public";
            autoindex on;
            root /media/frigate;
        }

        location /cache/ {
            internal; # This tells nginx it's not accessible from the outside
            alias /tmp/cache/;
        }

        location /recordings/ {
            include auth_request.conf;
            types {
                video/mp4 mp4;
            }

            autoindex on;
            autoindex_format json;
            root /media/frigate;
        }

        location /exports/ {
            include auth_request.conf;
            types {
                video/mp4 mp4;
            }

            autoindex on;
            autoindex_format json;
            root /media/frigate;
        }

        location /ws {
            include auth_request.conf;
            proxy_pass http://mqtt_ws/;
            include proxy.conf;
        }

        location /live/jsmpeg/ {
            include auth_request.conf;
            proxy_pass http://jsmpeg/;
            include proxy.conf;
        }

        # frigate lovelace card uses this path
        location /live/mse/api/ws {
            include auth_request.conf;
            limit_except GET {
                deny  all;
            }
            proxy_pass http://go2rtc/api/ws;
            include proxy.conf;
        }

        location /live/webrtc/api/ws {
            include auth_request.conf;
            limit_except GET {
                deny  all;
            }
            proxy_pass http://go2rtc/api/ws;
            include proxy.conf;
        }

        # pass through go2rtc player
        location /live/webrtc/webrtc.html {
            include auth_request.conf;
            limit_except GET {
                deny  all;
            }
            proxy_pass http://go2rtc/webrtc.html;
            include proxy.conf;
        }

        # frontend uses this to fetch the version
        location /api/go2rtc/api {
            include auth_request.conf;
            limit_except GET {
                deny  all;
            }
            proxy_pass http://go2rtc/api;
            include proxy.conf;
        }

        # integration uses this to add webrtc candidate
        location /api/go2rtc/webrtc {
            include auth_request.conf;
            limit_except POST {
                deny  all;
            }
            proxy_pass http://go2rtc/api/webrtc;
            include proxy.conf;
        }

        location ~* /api/.*\.(jpg|jpeg|png|webp|gif)$ {
            include auth_request.conf;
            rewrite ^/api/(.*)$ /$1 break;
            proxy_pass http://frigate_api;
            include proxy.conf;
        }

        location /api/ {
            include auth_request.conf;
            add_header Cache-Control "no-store";
            expires off;
            proxy_pass http://frigate_api/;
            include proxy.conf;

            proxy_cache api_cache;
            proxy_cache_lock on;
            proxy_cache_use_stale updating;
            proxy_cache_valid 200 5s;
            proxy_cache_bypass $http_x_cache_bypass;
            proxy_no_cache $should_not_cache;
            add_header X-Cache-Status $upstream_cache_status;

            location /api/vod/ {
                include auth_request.conf;
                proxy_pass http://frigate_api/vod/;
                include proxy.conf;
                proxy_cache off;
            }

            location /api/login {
                auth_request off;
                rewrite ^/api(/.*)$ $1 break;
                proxy_pass http://frigate_api;
                include proxy.conf;
            }

            # Allow unauthenticated access to the first_time_login endpoint
            # so the login page can load help text before authentication.
            location /api/auth/first_time_login {
                auth_request off;
                limit_except GET {
                    deny all;
                }
                rewrite ^/api(/.*)$ $1 break;
                proxy_pass http://frigate_api;
                include proxy.conf;
            }

            location /api/stats {
                include auth_request.conf;
                access_log off;
                rewrite ^/api(/.*)$ $1 break;
                proxy_pass http://frigate_api;
                include proxy.conf;
            }

            location /api/version {
                include auth_request.conf;
                access_log off;
                rewrite ^/api(/.*)$ $1 break;
                proxy_pass http://frigate_api;
                include proxy.conf;
            }
        }

        location / {
            # do not require auth for static assets
            add_header Cache-Control "no-store";
            expires off;

            location /assets/ {
                access_log off;
                expires 1y;
                add_header Cache-Control "public";
            }

            location /fonts/ {
                access_log off;
                expires 1y;
                add_header Cache-Control "public";
            }

            location /locales/ {
                access_log off;
                add_header Cache-Control "public";
            }

            location ~ ^/.*-([A-Za-z0-9]+)\.webmanifest$ {
                access_log off;
                expires 1y;
                add_header Cache-Control "public";
                default_type application/json;
                proxy_set_header Accept-Encoding "";
                sub_filter_once off;
                sub_filter_types application/json;
                sub_filter '"start_url": "/BASE_PATH/"' '"start_url" : "$http_x_ingress_path/"';
                sub_filter '"src": "/BASE_PATH/' '"src": "$http_x_ingress_path/';
            }

            sub_filter 'href="/BASE_PATH/' 'href="$http_x_ingress_path/';
            sub_filter 'url(/BASE_PATH/' 'url($http_x_ingress_path/';
            sub_filter '"/BASE_PATH/dist/' '"$http_x_ingress_path/dist/';
            sub_filter '"/BASE_PATH/js/' '"$http_x_ingress_path/js/';
            sub_filter '"/BASE_PATH/assets/' '"$http_x_ingress_path/assets/';
            sub_filter '"/BASE_PATH/locales/' '"$http_x_ingress_path/locales/';
            sub_filter '"/BASE_PATH/monacoeditorwork/' '"$http_x_ingress_path/assets/';
            sub_filter 'return"/BASE_PATH/"' 'return window.baseUrl';
            sub_filter '<body>' '<body><script>window.baseUrl="$http_x_ingress_path/";</script>';
            sub_filter_types text/css application/javascript;
            sub_filter_once off;

            root /opt/frigate/web;
            try_files $uri $uri.html $uri/ /index.html;
        }
    }
}
