Стала задача як форсувати отримання свіжої версії файлу playlist .m3u8 для застуванні у HLS (HTTP Live Streaming) медіа плеєру. Свіжу версію мається на увазі те що вона не буде зчитана з кешу браузера у будь-якому випадку незалежно від заголовків expire.
Вирішення задачі це додавати до імені файлу поточну дату у вигляді додаткового аргументу на кшталт: index.m3u8?m=202303191711.
Використовується Web сервер - nginx.
nginx
time_iso8601
Сформуємо змінну $formatted_date з датою у необхідному форматі. Є вбудована змінна у nginx для дати у форматі ISO8601 $time_iso8601.
Для формування дати у потрібному форматі застосовується послідовність map у контексті http.
map - nginx |
map $time_iso8601 $year {
default 'year';
'~^(?<yyyy>\d{4})-' $yyyy;
}
map $time_iso8601 $month {
default 'month';
'~^\d{4}-(?<mm>\d{2})-' $mm;
}
map $time_iso8601 $day {
default 'day';
'~^\d{4}-\d{2}-(?<dd>\d{2})' $dd;
}
map $time_iso8601 $hour {
default 'hour';
'~^\d{4}-\d{2}-\d{2}T(?<hh>\d{2})' $hh;
}
map $time_iso8601 $min {
default 'minute';
'~^\d{4}-\d{2}-\d{2}T\d{2}:(?<mn>\d{2})' $mn;
}
map $time_iso8601 $sec {
default 'seconds';
'~^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:(?<se>\d{2})' $se;
}
map $time_iso8601 $formatted_date {
default 'date-not-found';
'~^(?<year>\d{4})-(?<month>\d{2})-(?<day>\d{2})' $year$month$day$hour$min$sec;
}
Тепер ми маємо змінну $formatted_date у вигляді $year$month$day$hour$min$sec.
Але є одне але. Спільне використання змінної у регулярному виразі location.
location
Наприклад "location ~ ^(*.\.m3u8)$" і спробі використати результат пошуку змінної "$1" у location для rewrite.
location ~ ^/t/(.*\.m3u8)$ { rewrite ^ $1?m=$formatted_date&$args? permanent; }
Надасть ось такий результат: "http://lexxai.pp.ua/t/09?m=20230319083509&".
Тому що використана буде остання змінна "$1" з використання команди map, вже після location.
Для вирішення цієї проблеми використаємо таку конструкцію регулярного виразу:
location ~ ^/t/(?<filename>.+\.m3u8){ rewrite ^ $filename?m=$formatted_date&$args? permanent; }
Зараз все буде добре з заміною, але буде інша проблема - зациклювання:
"http://lexxai.pp.ua/t/index.m3u8?m=20230319084535&m=20230319084535&m=20230319084535&m=20230319084535&m=20230319084535&m=20230319084534&m=20230319084534&m=20230319084534&m=20230319084534&m=20230319084534&m=20230319084533&m=20230319084533&m=20230319084533&m=20230319084533&m=20230319084532&m=20230319084532&m=20230319084532&m=20230319084532&m=20230319084532&m=20230319084531&...."
Тому додаємо умову на наявність аргументу "m=":
location ~ ^/t/(?<filename>.+\.m3u8) { if ($args !~ m=){ rewrite ^ $filename?m=$formatted_date&$args? permanent; } }
Надасть ось такий результат: "http://lexxai.pp.ua/t/index.m3u8?m=20230319085241&".
Але є знову одне але. Використання "redirect 301" для HLS плеєра.
HLS плеєр.
master m3u8 playlist
return 200 "#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH\n$filename?m=$formatted_date&$args";І в результаті буде таке повернення від сервера на запит: http://lexxai.pp.ua/t/index.m3u8
#EXTM3U #EXT-X-STREAM-INF:BANDWIDTH /t/index.m3u8?m=20230319093225&
CORS
Не забуваємо про CORS заголовки для програвання HLS.
location ~ ^(?Де $cors_origin_header визначається через map для Ваших дозволенних доменів:.+\.m3u8)$ { if ($args !~ m=){ add_header Pragma "public"; add_header Cache-Control "public"; add_header Storm-Control "public"; add_header X-Cache $upstream_cache_status; # CORS setup add_header 'Access-Control-Allow-Origin' "$cors_origin_header" always; add_header 'Access-Control-Expose-Headers' 'Content-Length'; add_header 'Access-Control-Allow-Methods' 'GET, HEAD'; expires 1s; return 200 "#EXTM3U\n#EXT-X-STREAM-INF:BANDWIDTH\n$filename?m=$formatted_date"; } add_header Pragma "public"; add_header Cache-Control "public"; add_header Storm-Control "public"; add_header X-Cache $upstream_cache_status; # CORS setup add_header 'Access-Control-Allow-Origin' "$cors_origin_header" always; add_header 'Access-Control-Expose-Headers' 'Content-Length'; add_header 'Access-Control-Allow-Methods' 'GET, HEAD'; expires 5m; }
map $http_origin $cors_origin_header { default ''; # all your domains https://cdn1.domain1.com "$http_origin"; https://cdn2.domain1.com "$http_origin"; https://cdn.domain2.com "$http_origin"; }
location - nginx |
Приклад готового проєкту:
https://stormtracker.us |
Немає коментарів:
Дописати коментар