diff --git a/Dockerfile.live b/Dockerfile.live index 8f68b29abd..fc2532cfbb 100644 --- a/Dockerfile.live +++ b/Dockerfile.live @@ -53,7 +53,7 @@ RUN mkdir ~/build && \ git clone https://github.com/arut/nginx-rtmp-module.git && \ git clone https://github.com/nginx/nginx.git && \ cd nginx && \ - ./auto/configure --with-http_ssl_module --with-http_stub_status_module --add-module=../nginx-rtmp-module --with-cc-opt="-Wimplicit-fallthrough=0" && \ + ./auto/configure --with-http_ssl_module --with-http_stub_status_module --with-http_auth_request_module --add-module=../nginx-rtmp-module --with-cc-opt="-Wimplicit-fallthrough=0" && \ make && \ make install diff --git a/deploy/nginx/nginx.conf b/deploy/nginx/nginx.conf index df93a35a97..7fc0bc8db5 100644 --- a/deploy/nginx/nginx.conf +++ b/deploy/nginx/nginx.conf @@ -24,7 +24,10 @@ rtmp { hls_fragment 4s; drop_idle_publisher 30s; sync 500ms; - + + hls_keys on; + hls_fragments_per_key 20; + #Experimental. Force dropped stream, or ended stream from being watched. (idle_streams) #idle_streams off; on_publish http://avideo/plugin/Live/on_publish.php; @@ -32,7 +35,6 @@ rtmp { on_play http://avideo/plugin/Live/on_play.php; on_record_done http://avideo/plugin/Live/on_record_done.php; - #exec ffmpeg -re -i rtmp://localhost/live/$name -c:v libx264 -preset veryfast -c:a copy -f hls -hls_time 5 -hls_list_size 0 -f flv rtmp://localhost/adaptive/$name_hi; #exec ffmpeg -re -i rtmp://localhost/live/$name # -c:v libx264 -vf scale=-2:240 -r 20 -g 40 -keyint_min 40 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 400k -maxrate 700k -bufsize 1400k -c:a aac -strict -2 -b:a 96k -f flv rtmp://localhost/adaptive/$name_low # -c:v libx264 -vf scale=-2:480 -r 30 -g 60 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 1200k -maxrate 2100k -bufsize 4200k -c:a aac -strict -2 -b:a 128k -f flv rtmp://localhost/adaptive/$name_mid @@ -58,14 +60,16 @@ rtmp { #application adaptive { # live on; # hls on; - # hls_path /HLS/live; # hls_nested on; - # hls_playlist_length 10m; + # hls_playlist_length 60m; + # hls_fragment 4s; # allow play all; # allow publish 127.0.0.1; # deny publish all; - # hls_variant _hi BANDWIDTH=264000,RESOLUTION=1280x720; # this is for line 34 only, do not uncomment it + + # hls_keys on; + # hls_fragments_per_key 20; # hls_variant _low BANDWIDTH=900000; # hls_variant _mid BANDWIDTH=2400000; # hls_variant _hi BANDWIDTH=3500000; @@ -82,6 +86,9 @@ http { location /live { expires 60; add_header 'Cache-Control' 'public'; + + root /HLS; # Use root instead of alias + location ~ \.m3u8$ { expires -1; # Disable cache @@ -91,6 +98,19 @@ http { add_header 'Access-Control-Expose-Headers' 'Content-Length'; } + location ~ \.key$ { + # Call an external authorization service + auth_request /auth_key_check; + + # Only serve the key if the authorization service returns 200 + add_header 'Content-Type' 'application/octet-stream'; + # Disable cache + add_header 'Cache-Control' 'no-cache'; + # CORS setup + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length'; + } + # CORS setup add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Expose-Headers' 'Content-Length'; @@ -106,8 +126,22 @@ http { types { application/vnd.apple.mpegurl m3u8; } - alias /HLS/live; } + + + # Authorization endpoint + location = /auth_key_check { + internal; # Make this location internal so it cannot be accessed directly + proxy_pass http://avideo/plugin/Live/authorizeKeyAccess.php; + proxy_pass_request_body off; # Do not send the client request body to the auth service + proxy_set_header Content-Length ""; + + # Set headers to pass information to the PHP script + proxy_set_header X-Original-URI $request_uri; # Pass the original request URI + proxy_set_header X-Forwarded-For $remote_addr; # Pass the client IP address + proxy_set_header User-Agent $http_user_agent; # Pass the client User-Agent + } + #allows us to see how stats on viewers on our Nginx site using a URL like: "http://my-ip/stats" #location /stats { # stub_status; @@ -143,8 +177,8 @@ http { # fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; #} listen 8443 ssl; - ssl_certificate /etc/apache2/ssl/localhost.crt; - ssl_certificate_key /etc/apache2/ssl/localhost.key; + ssl_certificate /etc/apache2/ssl/localhost.crt; + ssl_certificate_key /etc/apache2/ssl/localhost.key; } } diff --git a/objects/Object.php b/objects/Object.php index f25208472e..dfe2babfb3 100644 --- a/objects/Object.php +++ b/objects/Object.php @@ -315,7 +315,8 @@ abstract class ObjectYPT implements ObjectInterface if ( !empty($this->created) && (User::isAdmin() || isCommandLineInterface() || - (class_exists('API') && API::isAPISecretValid()) + (class_exists('API') && API::isAPISecretValid()) || + !empty($global['allowModifyCreated']) ) ) { $this->created = preg_replace('/[^0-9: \/-]/', '', $this->created); diff --git a/plugin/BulkEmbed/save.json.php b/plugin/BulkEmbed/save.json.php index 80bd9ef8c4..4fa03b316b 100644 --- a/plugin/BulkEmbed/save.json.php +++ b/plugin/BulkEmbed/save.json.php @@ -82,6 +82,7 @@ if(!BulkEmbed::canBulkEmbed()){ // Set the original video date if available in the form data if (!empty($value['date']) && $objo->useOriginalYoutubeDate) { + $global['allowModifyCreated'] = 1; $videos->setCreated($value['date']); // Set the original creation date of the video } diff --git a/plugin/Live/authorizeKeyAccess.php b/plugin/Live/authorizeKeyAccess.php new file mode 100644 index 0000000000..535c4e3b57 --- /dev/null +++ b/plugin/Live/authorizeKeyAccess.php @@ -0,0 +1,50 @@ + diff --git a/plugin/Live/install/nginx.conf b/plugin/Live/install/nginx.conf index 5537c538fd..1d08f60a36 100644 --- a/plugin/Live/install/nginx.conf +++ b/plugin/Live/install/nginx.conf @@ -1,146 +1,176 @@ -user www-data; -worker_processes 1; - error_log logs/error.log debug; - events { - worker_connections 1024; - } - rtmp { - server { - listen 1935; - ping 5m; - ping_timeout 4m; - ### Use case option (max_streams; default is 32 ) - #max_streams 10; - allow play all; - #creates our "live" full-resolution HLS videostream from our incoming encoder stream and tells where to put the HLS video manifest and video fragments - application live { - allow play all; - live on; - hls on; - hls_nested on; - hls_path /HLS/live; - hls_playlist_length 60m; - hls_fragment 4s; - drop_idle_publisher 30s; - sync 500ms; - #Experimental. Force dropped stream, or ended stream from being watched. (idle_streams) - #idle_streams off; - on_publish http://localhost/AVideo/plugin/Live/on_publish.php; - on_publish_done http://localhost/AVideo/plugin/Live/on_publish_done.php; - on_play http://localhost/AVideo/plugin/Live/on_play.php; - on_record_done http://localhost/AVideo/plugin/Live/on_record_done.php; - - #exec ffmpeg -re -i rtmp://localhost/live/$name -c:v libx264 -preset veryfast -c:a copy -f hls -hls_time 5 -hls_list_size 0 -f flv rtmp://localhost/adaptive/$name_hi; - #exec ffmpeg -re -i rtmp://localhost/live/$name - # -c:v libx264 -vf scale=-2:240 -r 20 -g 40 -keyint_min 40 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 400k -maxrate 700k -bufsize 1400k -c:a aac -strict -2 -b:a 96k -f flv rtmp://localhost/adaptive/$name_low - # -c:v libx264 -vf scale=-2:480 -r 30 -g 60 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 1200k -maxrate 2100k -bufsize 4200k -c:a aac -strict -2 -b:a 128k -f flv rtmp://localhost/adaptive/$name_mid - # -c:v libx264 -vf scale=-2:720 -r 30 -g 60 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 2400k -maxrate 3000k -bufsize 6000k -c:a aac -strict -2 -b:a 128k -f flv rtmp://localhost/adaptive/$name_hi; +user www-data; +worker_processes 1; +error_log logs/error.log debug; +events { + worker_connections 1024; +} +rtmp { + server { + listen 1935; + ping 5m; + ping_timeout 4m; + ### Use case option (max_streams; default is 32 ) + #max_streams 10; + allow play all; + #creates our "live" full-resolution HLS videostream from our incoming encoder stream and tells where to put the HLS video manifest and video fragments + application live { + allow play all; + live on; + hls on; + hls_nested on; + hls_path /HLS/live; + hls_playlist_length 60m; + hls_fragment 4s; + drop_idle_publisher 30s; + sync 500ms; + hls_keys on; + hls_fragments_per_key 20; - #recorder video { - # record all manual; - # record_path /var/www/tmp; - # record_notify on; - # record_max_size 2048M; - # record_suffix -%d-%b-%y-%T.flv; - #} - - ### Record Audio Separately ( For podcast ) - #recorder audio { - # record audio; - # record_path /var/www/tmp; - # record_max_size 1024M; - # record_suffix -%d-%b-%y-%T.mp3; - #} - } + #Experimental. Force dropped stream, or ended stream from being watched. (idle_streams) + #idle_streams off; + on_publish http://localhost/AVideo/plugin/Live/on_publish.php; + on_publish_done http://localhost/AVideo/plugin/Live/on_publish_done.php; + on_play http://localhost/AVideo/plugin/Live/on_play.php; + on_record_done http://localhost/AVideo/plugin/Live/on_record_done.php; - #application adaptive { - # live on; - # hls on; - # hls_fragment 2s; - # hls_path /HLS/live; - # hls_nested on; - # hls_playlist_length 10m; - # allow play all; - # allow publish 127.0.0.1; - # deny publish all; + #exec ffmpeg -re -i rtmp://localhost/live/$name + # -c:v libx264 -vf scale=-2:240 -r 20 -g 40 -keyint_min 40 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 400k -maxrate 700k -bufsize 1400k -c:a aac -strict -2 -b:a 96k -f flv rtmp://localhost/adaptive/$name_low + # -c:v libx264 -vf scale=-2:480 -r 30 -g 60 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 1200k -maxrate 2100k -bufsize 4200k -c:a aac -strict -2 -b:a 128k -f flv rtmp://localhost/adaptive/$name_mid + # -c:v libx264 -vf scale=-2:720 -r 30 -g 60 -keyint_min 48 -sc_threshold 0 -bf 3 -b_strategy 2 -b:v 2400k -maxrate 3000k -bufsize 6000k -c:a aac -strict -2 -b:a 128k -f flv rtmp://localhost/adaptive/$name_hi; - # hls_variant _hi BANDWIDTH=264000,RESOLUTION=1280x720; # this is for line 34 only, do not uncomment it - # hls_variant _low BANDWIDTH=900000; - # hls_variant _mid BANDWIDTH=2400000; - # hls_variant _hi BANDWIDTH=3500000; - #} - } - } - http { - include mime.types; - default_type application/octet-stream; - server { - #listen 8443 ssl; - #listen [::]:8443 ssl; - #include /usr/local/nginx/snippets/self-signed.conf; - #include /usr/local/nginx/snippets/ssl-params.conf; - listen 8080; - server_name localhost; - #creates the http-location for our full-resolution (desktop) HLS stream - "http://my-ip/live/my-stream-key/index.m3u8" - location /live { - expires 60; - add_header 'Cache-Control' 'public'; + #recorder video { + # record all manual; + # record_path /var/www/tmp; + # record_notify on; + # record_max_size 2048M; + # record_suffix -%d-%b-%y-%T.flv; + #} + ### Record Audio Separately ( For podcast ) + #recorder audio { + # record audio; + # record_path /var/www/tmp; + # record_max_size 1024M; + # record_suffix -%d-%b-%y-%T.mp3; + #} + } - location ~ \.m3u8$ { + #application adaptive { + # live on; + # hls on; + # hls_path /HLS/live; + # hls_nested on; + # hls_playlist_length 60m; + # hls_fragment 4s; + # allow play all; + # allow publish 127.0.0.1; + # deny publish all; + + # hls_keys on; + # hls_fragments_per_key 20; + # hls_variant _low BANDWIDTH=900000; + # hls_variant _mid BANDWIDTH=2400000; + # hls_variant _hi BANDWIDTH=3500000; + #} + } +} +http { + include mime.types; + default_type application/octet-stream; + server { + #listen 8443 ssl; + #listen [::]:8443 ssl; + #include /usr/local/nginx/snippets/self-signed.conf; + #include /usr/local/nginx/snippets/ssl-params.conf; + listen 8080; + server_name localhost; + #creates the http-location for our full-resolution (desktop) HLS stream - "http://my-ip/live/my-stream-key/index.m3u8" + location /live { + expires 60; + add_header 'Cache-Control' 'public'; + + root /HLS; # Use root instead of alias + + location ~ \.m3u8$ { expires -1; # Disable cache add_header 'Cache-Control' 'no-cache'; - # CORS setup add_header 'Access-Control-Allow-Origin' '*' always; add_header 'Access-Control-Expose-Headers' 'Content-Length'; - } + } - # CORS setup - add_header 'Access-Control-Allow-Origin' '*' always; - add_header 'Access-Control-Expose-Headers' 'Content-Length'; + location ~ \.key$ { + # Call an external authorization service + auth_request /auth_key_check; - # allow CORS preflight requests - if ($request_method = 'OPTIONS') { - add_header 'Access-Control-Allow-Origin' '*'; - add_header 'Access-Control-Max-Age' 1728000; - add_header 'Content-Type' 'text/plain charset=UTF-8'; - add_header 'Content-Length' 0; - return 204; - } - types { - application/vnd.apple.mpegurl m3u8; - } - alias /HLS/live; - } - #allows us to see how stats on viewers on our Nginx site using a URL like: "http://my-ip/stats" - #location /stats { - # stub_status; - #} - location /stat { - rtmp_stat all; - rtmp_stat_stylesheet stat.xsl; - } - location /stat.xsl { - root html; - } - location /control { - # replace this with the IP of your AVideo site - allow 127.0.0.1; - deny all; - rtmp_control all; - } - #allows us to host some webpages which can show our videos: "http://my-ip/my-page.html" - location / { - root html; - index index.html index.htm; - } + # Only serve the key if the authorization service returns 200 + add_header 'Content-Type' 'application/octet-stream'; + # Disable cache + add_header 'Cache-Control' 'no-cache'; + # CORS setup + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length'; + } - #location ~ \.php$ { - # include /etc/nginx/snippets/fastcgi-php.conf; - # fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; - #} + # CORS setup + add_header 'Access-Control-Allow-Origin' '*' always; + add_header 'Access-Control-Expose-Headers' 'Content-Length'; - } - } + # allow CORS preflight requests + if ($request_method = 'OPTIONS') { + add_header 'Access-Control-Allow-Origin' '*'; + add_header 'Access-Control-Max-Age' 1728000; + add_header 'Content-Type' 'text/plain charset=UTF-8'; + add_header 'Content-Length' 0; + return 204; + } + types { + application/vnd.apple.mpegurl m3u8; + } + } + + + # Authorization endpoint + location = /auth_key_check { + internal; # Make this location internal so it cannot be accessed directly + proxy_pass http://localhost/AVideo/plugin/Live/authorizeKeyAccess.php; + proxy_pass_request_body off; # Do not send the client request body to the auth service + proxy_set_header Content-Length ""; + + # Set headers to pass information to the PHP script + proxy_set_header X-Original-URI $request_uri; # Pass the original request URI + proxy_set_header X-Forwarded-For $remote_addr; # Pass the client IP address + proxy_set_header User-Agent $http_user_agent; # Pass the client User-Agent + } + + #allows us to see how stats on viewers on our Nginx site using a URL like: "http://my-ip/stats" + #location /stats { + # stub_status; + #} + location /stat { + rtmp_stat all; + rtmp_stat_stylesheet stat.xsl; + } + location /stat.xsl { + root html; + } + location /control { + # replace this with the IP of your AVideo site + allow 127.0.0.1; + deny all; + rtmp_control all; + } + #allows us to host some webpages which can show our videos: "http://my-ip/my-page.html" + location / { + root html; + index index.html index.htm; + } + + #location ~ \.php$ { + # include /etc/nginx/snippets/fastcgi-php.conf; + # fastcgi_pass unix:/var/run/php/php7.2-fpm.sock; + #} + + } +} diff --git a/plugin/UserNotifications/script.js b/plugin/UserNotifications/script.js index 3be97662d2..2c7e61b3db 100644 --- a/plugin/UserNotifications/script.js +++ b/plugin/UserNotifications/script.js @@ -16,7 +16,7 @@ function getTemplateFromArray(itemsArray) { replace = webSiteRootURL + replace; } else if (search == 'element_class' && !empty(itemsArray.id)) { replace += " UserNotificationsJS_" + itemsArray.id; - } else if (search == 'created' && typeof _serverSystemTimezone !== 'undefined') { + } else if (search == 'created' && typeof _serverSystemTimezone !== 'undefined' && typeof moment != 'undefined') { try { m = moment.tz(itemsArray.created, _serverSystemTimezone).local(); replace = m.fromNow();