Merge pull request #49413 from midchildan/add-epgstation
epgstation: init at 1.7.4
This commit is contained in:
commit
8e13daea7b
@ -838,6 +838,7 @@
|
|||||||
./services/ttys/gpm.nix
|
./services/ttys/gpm.nix
|
||||||
./services/ttys/kmscon.nix
|
./services/ttys/kmscon.nix
|
||||||
./services/wayland/cage.nix
|
./services/wayland/cage.nix
|
||||||
|
./services/video/epgstation/default.nix
|
||||||
./services/video/mirakurun.nix
|
./services/video/mirakurun.nix
|
||||||
./services/web-apps/atlassian/confluence.nix
|
./services/web-apps/atlassian/confluence.nix
|
||||||
./services/web-apps/atlassian/crowd.nix
|
./services/web-apps/atlassian/crowd.nix
|
||||||
|
295
nixos/modules/services/video/epgstation/default.nix
Normal file
295
nixos/modules/services/video/epgstation/default.nix
Normal file
@ -0,0 +1,295 @@
|
|||||||
|
{ config, lib, pkgs, ... }:
|
||||||
|
|
||||||
|
with lib;
|
||||||
|
|
||||||
|
let
|
||||||
|
cfg = config.services.epgstation;
|
||||||
|
|
||||||
|
username = config.users.users.epgstation.name;
|
||||||
|
groupname = config.users.users.epgstation.group;
|
||||||
|
|
||||||
|
settingsFmt = pkgs.formats.json {};
|
||||||
|
settingsTemplate = settingsFmt.generate "config.json" cfg.settings;
|
||||||
|
preStartScript = pkgs.writeScript "epgstation-prestart" ''
|
||||||
|
#!${pkgs.runtimeShell}
|
||||||
|
|
||||||
|
PASSWORD="$(head -n1 "${cfg.basicAuth.passwordFile}")"
|
||||||
|
DB_PASSWORD="$(head -n1 "${cfg.database.passwordFile}")"
|
||||||
|
|
||||||
|
# setup configuration
|
||||||
|
touch /etc/epgstation/config.json
|
||||||
|
chmod 640 /etc/epgstation/config.json
|
||||||
|
sed \
|
||||||
|
-e "s,@password@,$PASSWORD,g" \
|
||||||
|
-e "s,@dbPassword@,$DB_PASSWORD,g" \
|
||||||
|
${settingsTemplate} > /etc/epgstation/config.json
|
||||||
|
chown "${username}:${groupname}" /etc/epgstation/config.json
|
||||||
|
|
||||||
|
# NOTE: Use password authentication, since mysqljs does not yet support auth_socket
|
||||||
|
if [ ! -e /var/lib/epgstation/db-created ]; then
|
||||||
|
${pkgs.mysql}/bin/mysql -e \
|
||||||
|
"GRANT ALL ON \`${cfg.database.name}\`.* TO '${username}'@'localhost' IDENTIFIED by '$DB_PASSWORD';"
|
||||||
|
touch /var/lib/epgstation/db-created
|
||||||
|
fi
|
||||||
|
'';
|
||||||
|
|
||||||
|
streamingConfig = builtins.fromJSON (builtins.readFile ./streaming.json);
|
||||||
|
logConfig = {
|
||||||
|
appenders.stdout.type = "stdout";
|
||||||
|
categories = {
|
||||||
|
default = { appenders = [ "stdout" ]; level = "info"; };
|
||||||
|
system = { appenders = [ "stdout" ]; level = "info"; };
|
||||||
|
access = { appenders = [ "stdout" ]; level = "info"; };
|
||||||
|
stream = { appenders = [ "stdout" ]; level = "info"; };
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
defaultPassword = "INSECURE_GO_CHECK_CONFIGURATION_NIX\n";
|
||||||
|
in
|
||||||
|
{
|
||||||
|
options.services.epgstation = {
|
||||||
|
enable = mkEnableOption pkgs.epgstation.meta.description;
|
||||||
|
|
||||||
|
usePreconfiguredStreaming = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = true;
|
||||||
|
description = ''
|
||||||
|
Use preconfigured default streaming options.
|
||||||
|
|
||||||
|
Upstream defaults:
|
||||||
|
<link xlink:href="https://github.com/l3tnun/EPGStation/blob/master/config/config.sample.json"/>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
port = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = 20772;
|
||||||
|
description = ''
|
||||||
|
HTTP port for EPGStation to listen on.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
socketioPort = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = cfg.port + 1;
|
||||||
|
description = ''
|
||||||
|
Socket.io port for EPGStation to listen on.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
clientSocketioPort = mkOption {
|
||||||
|
type = types.port;
|
||||||
|
default = cfg.socketioPort;
|
||||||
|
description = ''
|
||||||
|
Socket.io port that the web client is going to connect to. This may be
|
||||||
|
different from <option>socketioPort</option> if EPGStation is hidden
|
||||||
|
behind a reverse proxy.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
openFirewall = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = ''
|
||||||
|
Open ports in the firewall for the EPGStation web interface.
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
Exposing EPGStation to the open internet is generally advised
|
||||||
|
against. Only use it inside a trusted local network, or consider
|
||||||
|
putting it behind a VPN if you want remote access.
|
||||||
|
</para>
|
||||||
|
</warning>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
basicAuth = {
|
||||||
|
user = mkOption {
|
||||||
|
type = with types; nullOr str;
|
||||||
|
default = null;
|
||||||
|
example = "epgstation";
|
||||||
|
description = ''
|
||||||
|
Basic auth username for EPGStation. If <literal>null</literal>, basic
|
||||||
|
auth will be disabled.
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
Basic authentication has known weaknesses, the most critical being
|
||||||
|
that it sends passwords over the network in clear text. Use this
|
||||||
|
feature to control access to EPGStation within your family and
|
||||||
|
friends, but don't rely on it for security.
|
||||||
|
</para>
|
||||||
|
</warning>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = pkgs.writeText "epgstation-password" defaultPassword;
|
||||||
|
example = "/run/keys/epgstation-password";
|
||||||
|
description = ''
|
||||||
|
A file containing the password for <option>basicAuth.user</option>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
database = {
|
||||||
|
name = mkOption {
|
||||||
|
type = types.str;
|
||||||
|
default = "epgstation";
|
||||||
|
description = ''
|
||||||
|
Name of the MySQL database that holds EPGStation's data.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
passwordFile = mkOption {
|
||||||
|
type = types.path;
|
||||||
|
default = pkgs.writeText "epgstation-db-password" defaultPassword;
|
||||||
|
example = "/run/keys/epgstation-db-password";
|
||||||
|
description = ''
|
||||||
|
A file containing the password for the database named
|
||||||
|
<option>database.name</option>.
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
settings = mkOption {
|
||||||
|
description = ''
|
||||||
|
Options to add to config.json.
|
||||||
|
|
||||||
|
Documentation:
|
||||||
|
<link xlink:href="https://github.com/l3tnun/EPGStation/blob/master/doc/conf-manual.md"/>
|
||||||
|
'';
|
||||||
|
|
||||||
|
default = {};
|
||||||
|
example = {
|
||||||
|
recPriority = 20;
|
||||||
|
conflictPriority = 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
type = types.submodule {
|
||||||
|
freeformType = settingsFmt.type;
|
||||||
|
|
||||||
|
options.readOnlyOnce = mkOption {
|
||||||
|
type = types.bool;
|
||||||
|
default = false;
|
||||||
|
description = "Don't reload configuration files at runtime.";
|
||||||
|
};
|
||||||
|
|
||||||
|
options.mirakurunPath = mkOption (let
|
||||||
|
sockPath = config.services.mirakurun.unixSocket;
|
||||||
|
in {
|
||||||
|
type = types.str;
|
||||||
|
default = "http+unix://${replaceStrings ["/"] ["%2F"] sockPath}";
|
||||||
|
example = "http://localhost:40772";
|
||||||
|
description = "URL to connect to Mirakurun.";
|
||||||
|
});
|
||||||
|
|
||||||
|
options.encode = mkOption {
|
||||||
|
type = with types; listOf attrs;
|
||||||
|
description = "Encoding presets for recorded videos.";
|
||||||
|
default = [
|
||||||
|
{ name = "H264";
|
||||||
|
cmd = "${pkgs.epgstation}/libexec/enc.sh main";
|
||||||
|
suffix = ".mp4";
|
||||||
|
default = true; }
|
||||||
|
{ name = "H264-sub";
|
||||||
|
cmd = "${pkgs.epgstation}/libexec/enc.sh sub";
|
||||||
|
suffix = "-sub.mp4"; }
|
||||||
|
];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
config = mkIf cfg.enable {
|
||||||
|
environment.etc = {
|
||||||
|
"epgstation/operatorLogConfig.json".text = builtins.toJSON logConfig;
|
||||||
|
"epgstation/serviceLogConfig.json".text = builtins.toJSON logConfig;
|
||||||
|
};
|
||||||
|
|
||||||
|
networking.firewall = mkIf cfg.openFirewall {
|
||||||
|
allowedTCPPorts = with cfg; [ port socketioPort ];
|
||||||
|
};
|
||||||
|
|
||||||
|
users.users.epgstation = {
|
||||||
|
description = "EPGStation user";
|
||||||
|
group = config.users.groups.epgstation.name;
|
||||||
|
isSystemUser = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
users.groups.epgstation = {};
|
||||||
|
|
||||||
|
services.mirakurun.enable = mkDefault true;
|
||||||
|
|
||||||
|
services.mysql = {
|
||||||
|
enable = mkDefault true;
|
||||||
|
package = mkDefault pkgs.mysql;
|
||||||
|
ensureDatabases = [ cfg.database.name ];
|
||||||
|
# FIXME: enable once mysqljs supports auth_socket
|
||||||
|
# ensureUsers = [ {
|
||||||
|
# name = username;
|
||||||
|
# ensurePermissions = { "${cfg.database.name}.*" = "ALL PRIVILEGES"; };
|
||||||
|
# } ];
|
||||||
|
};
|
||||||
|
|
||||||
|
services.epgstation.settings = let
|
||||||
|
defaultSettings = {
|
||||||
|
serverPort = cfg.port;
|
||||||
|
socketioPort = cfg.socketioPort;
|
||||||
|
clientSocketioPort = cfg.clientSocketioPort;
|
||||||
|
|
||||||
|
dbType = mkDefault "mysql";
|
||||||
|
mysql = {
|
||||||
|
user = username;
|
||||||
|
database = cfg.database.name;
|
||||||
|
socketPath = mkDefault "/run/mysqld/mysqld.sock";
|
||||||
|
password = mkDefault "@dbPassword@";
|
||||||
|
connectTimeout = mkDefault 1000;
|
||||||
|
connectionLimit = mkDefault 10;
|
||||||
|
};
|
||||||
|
|
||||||
|
basicAuth = mkIf (cfg.basicAuth.user != null) {
|
||||||
|
user = mkDefault cfg.basicAuth.user;
|
||||||
|
password = mkDefault "@password@";
|
||||||
|
};
|
||||||
|
|
||||||
|
ffmpeg = mkDefault "${pkgs.ffmpeg-full}/bin/ffmpeg";
|
||||||
|
ffprobe = mkDefault "${pkgs.ffmpeg-full}/bin/ffprobe";
|
||||||
|
|
||||||
|
fileExtension = mkDefault ".m2ts";
|
||||||
|
maxEncode = mkDefault 2;
|
||||||
|
maxStreaming = mkDefault 2;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
mkMerge [
|
||||||
|
defaultSettings
|
||||||
|
(mkIf cfg.usePreconfiguredStreaming streamingConfig)
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.tmpfiles.rules = [
|
||||||
|
"d '/var/lib/epgstation/streamfiles' - ${username} ${groupname} - -"
|
||||||
|
"d '/var/lib/epgstation/recorded' - ${username} ${groupname} - -"
|
||||||
|
"d '/var/lib/epgstation/thumbnail' - ${username} ${groupname} - -"
|
||||||
|
];
|
||||||
|
|
||||||
|
systemd.services.epgstation = {
|
||||||
|
description = pkgs.epgstation.meta.description;
|
||||||
|
wantedBy = [ "multi-user.target" ];
|
||||||
|
after = [
|
||||||
|
"network.target"
|
||||||
|
] ++ optional config.services.mirakurun.enable "mirakurun.service"
|
||||||
|
++ optional config.services.mysql.enable "mysql.service";
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
ExecStart = "${pkgs.epgstation}/bin/epgstation start";
|
||||||
|
ExecStartPre = "+${preStartScript}";
|
||||||
|
User = username;
|
||||||
|
Group = groupname;
|
||||||
|
StateDirectory = "epgstation";
|
||||||
|
LogsDirectory = "epgstation";
|
||||||
|
ConfigurationDirectory = "epgstation";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
31
nixos/modules/services/video/epgstation/generate
Executable file
31
nixos/modules/services/video/epgstation/generate
Executable file
@ -0,0 +1,31 @@
|
|||||||
|
#!/usr/bin/env -S nix-build --no-out-link
|
||||||
|
|
||||||
|
# Script to generate default streaming configurations for EPGStation. There's
|
||||||
|
# no need to run this script directly since generate.sh in the EPGStation
|
||||||
|
# package directory would run this script for you.
|
||||||
|
#
|
||||||
|
# Usage: ./generate | xargs cat > streaming.json
|
||||||
|
|
||||||
|
{ pkgs ? (import ../../../../.. {}) }:
|
||||||
|
|
||||||
|
let
|
||||||
|
sampleConfigPath = "${pkgs.epgstation.src}/config/config.sample.json";
|
||||||
|
sampleConfig = builtins.fromJSON (builtins.readFile sampleConfigPath);
|
||||||
|
streamingConfig = {
|
||||||
|
inherit (sampleConfig)
|
||||||
|
mpegTsStreaming
|
||||||
|
mpegTsViewer
|
||||||
|
liveHLS
|
||||||
|
liveMP4
|
||||||
|
liveWebM
|
||||||
|
recordedDownloader
|
||||||
|
recordedStreaming
|
||||||
|
recordedViewer
|
||||||
|
recordedHLS;
|
||||||
|
};
|
||||||
|
in
|
||||||
|
pkgs.runCommand "streaming.json" { nativeBuildInputs = [ pkgs.jq ]; } ''
|
||||||
|
jq . <<<'${builtins.toJSON streamingConfig}' > $out
|
||||||
|
''
|
||||||
|
|
||||||
|
# vim:set ft=nix:
|
119
nixos/modules/services/video/epgstation/streaming.json
Normal file
119
nixos/modules/services/video/epgstation/streaming.json
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
{
|
||||||
|
"liveHLS": [
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%",
|
||||||
|
"name": "720p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%",
|
||||||
|
"name": "480p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 17 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 48k -ac 2 -c:v libx264 -vf yadif,scale=-2:180 -b:v 100k -preset veryfast -maxrate 110k -bufsize 1000k -flags +loop-global_header %OUTPUT%",
|
||||||
|
"name": "180p"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"liveMP4": [
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
|
||||||
|
"name": "720p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
|
||||||
|
"name": "480p"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"liveWebM": [
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -b:a 192k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 -b:v 3000k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
|
||||||
|
"name": "720p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -b:a 128k -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:480 -b:v 1500k -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
|
||||||
|
"name": "480p"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mpegTsStreaming": [
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -y -f mpegts pipe:1",
|
||||||
|
"name": "720p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -re -dual_mono_mode main -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -y -f mpegts pipe:1",
|
||||||
|
"name": "480p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Original"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mpegTsViewer": {
|
||||||
|
"android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end",
|
||||||
|
"ios": "vlc-x-callback://x-callback-url/stream?url=http://ADDRESS"
|
||||||
|
},
|
||||||
|
"recordedDownloader": {
|
||||||
|
"android": "intent://ADDRESS#Intent;package=com.dv.adm;type=video;scheme=http;end",
|
||||||
|
"ios": "vlc-x-callback://x-callback-url/download?url=http://ADDRESS&filename=FILENAME"
|
||||||
|
},
|
||||||
|
"recordedHLS": [
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 192k -ac 2 -c:v libx264 -vf yadif,scale=-2:720 -b:v 3000k -preset veryfast -flags +loop-global_header %OUTPUT%",
|
||||||
|
"name": "720p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -threads 0 -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_filename %streamFileDir%/stream%streamNum%-%09d.ts -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx264 -vf yadif,scale=-2:480 -b:v 1500k -preset veryfast -flags +loop-global_header %OUTPUT%",
|
||||||
|
"name": "480p"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main -i %INPUT% -sn -map 0 -ignore_unknown -max_muxing_queue_size 1024 -f hls -hls_time 3 -hls_list_size 0 -hls_allow_cache 1 -hls_segment_type fmp4 -hls_fmp4_init_filename stream%streamNum%-init.mp4 -hls_segment_filename stream%streamNum%-%09d.m4s -c:a aac -ar 48000 -b:a 128k -ac 2 -c:v libx265 -vf yadif,scale=-2:480 -b:v 350k -preset veryfast -tag:v hvc1 %OUTPUT%",
|
||||||
|
"name": "480p(h265)"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"recordedStreaming": {
|
||||||
|
"mp4": [
|
||||||
|
{
|
||||||
|
"ab": "192k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
|
||||||
|
"name": "720p",
|
||||||
|
"vb": "3000k"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ab": "128k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -movflags frag_keyframe+empty_moov+faststart+default_base_moof -y -f mp4 pipe:1",
|
||||||
|
"name": "360p",
|
||||||
|
"vb": "1500k"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"mpegTs": [
|
||||||
|
{
|
||||||
|
"ab": "192k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
|
||||||
|
"name": "720p (H.264)",
|
||||||
|
"vb": "3000k"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ab": "128k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 0 -c:a aac -ar 48000 -ac 2 -c:v libx264 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -profile:v baseline -preset veryfast -tune fastdecode,zerolatency -y -f mpegts pipe:1",
|
||||||
|
"name": "360p (H.264)",
|
||||||
|
"vb": "1500k"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"webm": [
|
||||||
|
{
|
||||||
|
"ab": "192k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 3 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:720 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
|
||||||
|
"name": "720p",
|
||||||
|
"vb": "3000k"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ab": "128k",
|
||||||
|
"cmd": "%FFMPEG% -dual_mono_mode main %RE% -i pipe:0 -sn -threads 2 -c:a libvorbis -ar 48000 -ac 2 -c:v libvpx-vp9 -vf yadif,scale=-2:360 %VB% %VBUFFER% %AB% %ABUFFER% -deadline realtime -speed 4 -cpu-used -8 -y -f webm pipe:1",
|
||||||
|
"name": "360p",
|
||||||
|
"vb": "1500k"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"recordedViewer": {
|
||||||
|
"android": "intent://ADDRESS#Intent;package=com.mxtech.videoplayer.ad;type=video;scheme=http;end",
|
||||||
|
"ios": "infuse://x-callback-url/play?url=http://ADDRESS"
|
||||||
|
}
|
||||||
|
}
|
@ -18,7 +18,8 @@ in
|
|||||||
type = with types; nullOr port;
|
type = with types; nullOr port;
|
||||||
default = 40772;
|
default = 40772;
|
||||||
description = ''
|
description = ''
|
||||||
Port to listen on. If null, it won't listen on any port.
|
Port to listen on. If <literal>null</literal>, it won't listen on
|
||||||
|
any port.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -27,6 +28,23 @@ in
|
|||||||
default = false;
|
default = false;
|
||||||
description = ''
|
description = ''
|
||||||
Open ports in the firewall for Mirakurun.
|
Open ports in the firewall for Mirakurun.
|
||||||
|
|
||||||
|
<warning>
|
||||||
|
<para>
|
||||||
|
Exposing Mirakurun to the open internet is generally advised
|
||||||
|
against. Only use it inside a trusted local network, or
|
||||||
|
consider putting it behind a VPN if you want remote access.
|
||||||
|
</para>
|
||||||
|
</warning>
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
|
||||||
|
unixSocket = mkOption {
|
||||||
|
type = with types; nullOr path;
|
||||||
|
default = "/var/run/mirakurun/mirakurun.sock";
|
||||||
|
description = ''
|
||||||
|
Path to unix socket to listen on. If <literal>null</literal>, it
|
||||||
|
won't listen on any unix sockets.
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -121,8 +139,8 @@ in
|
|||||||
|
|
||||||
services.mirakurun.serverSettings = {
|
services.mirakurun.serverSettings = {
|
||||||
logLevel = mkDefault 2;
|
logLevel = mkDefault 2;
|
||||||
path = mkDefault "/var/run/mirakurun/mirakurun.sock";
|
path = mkIf (cfg.unixSocket != null) cfg.unixSocket;
|
||||||
port = mkIf (cfg.port != null) (mkDefault cfg.port);
|
port = mkIf (cfg.port != null) cfg.port;
|
||||||
};
|
};
|
||||||
|
|
||||||
systemd.tmpfiles.rules = [
|
systemd.tmpfiles.rules = [
|
||||||
|
85
pkgs/applications/video/epgstation/default.nix
Normal file
85
pkgs/applications/video/epgstation/default.nix
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
{ stdenv, fetchFromGitHub, makeWrapper, bash, nodejs, nodePackages, gzip }:
|
||||||
|
|
||||||
|
let
|
||||||
|
workaround-opencollective-buildfailures = stdenv.mkDerivation {
|
||||||
|
# FIXME: This should be removed when a complete fix is available
|
||||||
|
# https://github.com/svanderburg/node2nix/issues/145
|
||||||
|
name = "workaround-opencollective-buildfailures";
|
||||||
|
phases = [ "installPhase" ];
|
||||||
|
installPhase = ''
|
||||||
|
mkdir -p $out/bin
|
||||||
|
touch $out/bin/opencollective-postinstall
|
||||||
|
chmod +x $out/bin/opencollective-postinstall
|
||||||
|
'';
|
||||||
|
};
|
||||||
|
in
|
||||||
|
nodePackages.epgstation.override (drv: {
|
||||||
|
src = fetchFromGitHub {
|
||||||
|
owner = "l3tnun";
|
||||||
|
repo = "EPGStation";
|
||||||
|
rev = "v${drv.version}"; # version specified in ./generate.sh
|
||||||
|
sha256 = "15z1kdbamj97frp3dfnbm0h8krihmv2xdab4id0rxin29ibrw1k2";
|
||||||
|
};
|
||||||
|
|
||||||
|
buildInputs = [ bash ];
|
||||||
|
nativeBuildInputs = [
|
||||||
|
workaround-opencollective-buildfailures
|
||||||
|
makeWrapper
|
||||||
|
nodePackages.node-pre-gyp
|
||||||
|
];
|
||||||
|
|
||||||
|
preRebuild = ''
|
||||||
|
# Fix for not being able to connect to mysql using domain sockets.
|
||||||
|
patch -p1 ${./use-mysql-over-domain-socket.patch}
|
||||||
|
'';
|
||||||
|
|
||||||
|
postInstall = let
|
||||||
|
runtimeDeps = [ nodejs bash ];
|
||||||
|
in
|
||||||
|
''
|
||||||
|
mkdir -p $out/{bin,libexec,share/doc/epgstation,share/man/man1}
|
||||||
|
|
||||||
|
pushd $out/lib/node_modules/EPGStation
|
||||||
|
|
||||||
|
npm run build
|
||||||
|
npm prune --production
|
||||||
|
|
||||||
|
mv config/{enc.sh,enc.js} $out/libexec
|
||||||
|
mv LICENSE Readme.md $out/share/doc/epgstation
|
||||||
|
mv doc/* $out/share/doc/epgstation
|
||||||
|
sed 's/@DESCRIPTION@/${drv.meta.description}/g' ${./epgstation.1} \
|
||||||
|
| ${gzip}/bin/gzip > $out/share/man/man1/epgstation.1.gz
|
||||||
|
rm -rf doc
|
||||||
|
|
||||||
|
# just log to stdout and let journald do its job
|
||||||
|
rm -rf logs
|
||||||
|
|
||||||
|
# Replace the existing configuration and runtime state directories with
|
||||||
|
# symlinks. Without this, they would all be non-writable because they reside
|
||||||
|
# in the Nix store. Note that the source path won't be accessible at build
|
||||||
|
# time.
|
||||||
|
rm -r config data recorded thumbnail
|
||||||
|
ln -sfT /etc/epgstation config
|
||||||
|
ln -sfT /var/lib/epgstation data
|
||||||
|
ln -sfT /var/lib/epgstation/recorded recorded
|
||||||
|
ln -sfT /var/lib/epgstation/thumbnail thumbnail
|
||||||
|
|
||||||
|
makeWrapper ${nodejs}/bin/npm $out/bin/epgstation \
|
||||||
|
--run "cd $out/lib/node_modules/EPGStation" \
|
||||||
|
--prefix PATH : ${stdenv.lib.makeBinPath runtimeDeps}
|
||||||
|
|
||||||
|
popd
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with stdenv.lib; drv.meta // {
|
||||||
|
maintainers = with maintainers; [ midchildan ];
|
||||||
|
|
||||||
|
# nodePackages.epgstation is a stub package to fetch npm dependencies and
|
||||||
|
# is marked as broken to prevent users from installing it directly. This
|
||||||
|
# technique ensures epgstation can share npm packages with the rest of
|
||||||
|
# nixpkgs while still allowing us to heavily customize the build. It also
|
||||||
|
# allows us to provide devDependencies for the epgstation build process
|
||||||
|
# without doing the same for all the other node packages.
|
||||||
|
broken = false;
|
||||||
|
};
|
||||||
|
})
|
52
pkgs/applications/video/epgstation/epgstation.1
Normal file
52
pkgs/applications/video/epgstation/epgstation.1
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
.Dd $Mdocdate$
|
||||||
|
.Dt EPGSTATION 1
|
||||||
|
.Os
|
||||||
|
.Sh NAME
|
||||||
|
.Nm epgstation
|
||||||
|
.Nd @DESCRIPTION@
|
||||||
|
.Sh SYNOPSIS
|
||||||
|
.Nm
|
||||||
|
.Bk -words
|
||||||
|
.Op Ar command Op Ar args
|
||||||
|
.Ek
|
||||||
|
.Sh DESCRIPTION
|
||||||
|
.Nm
|
||||||
|
is a wrapper command for EPGStation provided by Nix. It's actually a thin
|
||||||
|
wrapper around the
|
||||||
|
.Xr npm 1
|
||||||
|
command line tool which you can use to invoke npm commands from the EPGStation
|
||||||
|
project directory. The command line arguments are simply passed as-is to
|
||||||
|
.Xr npm 1 .
|
||||||
|
.Pp
|
||||||
|
On NixOS, it is strongly recommended that you enable the epgstation module
|
||||||
|
instead of invoking this command directly to launch EPGStation. On other
|
||||||
|
platforms, run
|
||||||
|
.Pp
|
||||||
|
.Dl $ epgstation start
|
||||||
|
.Pp
|
||||||
|
to start EPGStation.
|
||||||
|
.Sh FILES
|
||||||
|
.Bl -tag -width Ds -compact
|
||||||
|
.It Pa /etc/epgstation/config.json
|
||||||
|
.Nm
|
||||||
|
configuration file.
|
||||||
|
.El
|
||||||
|
.Sh EXAMPLES
|
||||||
|
Start EPGStation.
|
||||||
|
.Pp
|
||||||
|
.Dl $ epgstation start
|
||||||
|
.Pp
|
||||||
|
Start EPGStation in development mode.
|
||||||
|
.Pp
|
||||||
|
.Dl $ epgstation run dev-start
|
||||||
|
.Pp
|
||||||
|
Backup the EPGstation database.
|
||||||
|
.Pp
|
||||||
|
.Dl $ epgstation run backup /path/to/dst
|
||||||
|
.Pp
|
||||||
|
Restore the EPGstation database.
|
||||||
|
.Pp
|
||||||
|
.Dl $ epgstation run restore /path/to/src
|
||||||
|
.Pp
|
||||||
|
.Sh SEE ALSO
|
||||||
|
.Xr npm 1
|
34
pkgs/applications/video/epgstation/generate.sh
Executable file
34
pkgs/applications/video/epgstation/generate.sh
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# Script to generate the Nix package definition for EPGStation. Run this script
|
||||||
|
# when bumping the package version.
|
||||||
|
|
||||||
|
VERSION="1.7.4"
|
||||||
|
URL="https://raw.githubusercontent.com/l3tnun/EPGStation/v$VERSION/package.json"
|
||||||
|
JQ_BIN="$(nix-build ../../../.. --no-out-link -A jq)/bin/jq"
|
||||||
|
|
||||||
|
set -eu -o pipefail
|
||||||
|
cd "$(dirname "${BASH_SOURCE[0]}")"
|
||||||
|
|
||||||
|
main() {
|
||||||
|
# update package.json
|
||||||
|
curl -sSfL "$URL" \
|
||||||
|
| jq '. + {"dependencies": (.devDependencies + .dependencies)} | del(.devDependencies)' \
|
||||||
|
> package.json
|
||||||
|
|
||||||
|
# regenerate node packages to update the actual Nix package
|
||||||
|
pushd ../../../development/node-packages \
|
||||||
|
&& ./generate.sh
|
||||||
|
popd
|
||||||
|
|
||||||
|
# generate default streaming settings for EPGStation
|
||||||
|
pushd ../../../../nixos/modules/services/video/epgstation \
|
||||||
|
&& cat "$(./generate)" > streaming.json
|
||||||
|
popd
|
||||||
|
}
|
||||||
|
|
||||||
|
jq() {
|
||||||
|
"$JQ_BIN" "$@"
|
||||||
|
}
|
||||||
|
|
||||||
|
main "@"
|
101
pkgs/applications/video/epgstation/package.json
Normal file
101
pkgs/applications/video/epgstation/package.json
Normal file
@ -0,0 +1,101 @@
|
|||||||
|
{
|
||||||
|
"name": "EPGStation",
|
||||||
|
"version": "1.7.4",
|
||||||
|
"description": "DTV Software in Japan.",
|
||||||
|
"main": "dist/server/index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "node dist/server/index.js",
|
||||||
|
"dev-start": "node dist/server/index.js --env development",
|
||||||
|
"clean": "gulp clean",
|
||||||
|
"build": "gulp build --max_old_space_size=768 --env production",
|
||||||
|
"dev-build": "gulp build --max_old_space_size=512 --env development",
|
||||||
|
"test": "echo \"Error: no test specified\" && exit 1",
|
||||||
|
"task": "gulp --max_old_space_size=512",
|
||||||
|
"install-win-service": "winser -i -a",
|
||||||
|
"uninstall-win-service": "winser -r -x",
|
||||||
|
"backup": "node dist/server/DBTools.js -m backup -o",
|
||||||
|
"restore": "node dist/server/DBTools.js -m restore -o",
|
||||||
|
"move-log": "node dist/server/LogFileMoveTools.js",
|
||||||
|
"convert-str": "node dist/server/ConvertDBStrTools.js"
|
||||||
|
},
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "https://github.com/l3tnun/EPGStation.git"
|
||||||
|
},
|
||||||
|
"author": "l3tnun",
|
||||||
|
"license": "MIT",
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/l3tnun/EPGStation/issues"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/l3tnun/EPGStation#readme",
|
||||||
|
"engines": {
|
||||||
|
"node": "^10.x.x < 11 || ^12.14.0 < 13 || ^14.5.0 < 15"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@types/basic-auth": "1.1.3",
|
||||||
|
"@types/body-parser": "1.19.0",
|
||||||
|
"@types/chart.js": "2.9.23",
|
||||||
|
"@types/express": "4.17.7",
|
||||||
|
"@types/hls.js": "0.13.0",
|
||||||
|
"@types/js-yaml": "3.12.5",
|
||||||
|
"@types/lodash": "4.14.158",
|
||||||
|
"@types/material-design-lite": "1.1.16",
|
||||||
|
"@types/minimist": "1.2.0",
|
||||||
|
"@types/mithril": "2.0.3",
|
||||||
|
"@types/mkdirp": "1.0.1",
|
||||||
|
"@types/multer": "1.4.3",
|
||||||
|
"@types/mysql": "2.15.15",
|
||||||
|
"@types/node": "14.0.26",
|
||||||
|
"@types/pg": "7.14.4",
|
||||||
|
"@types/request": "2.48.5",
|
||||||
|
"@types/socket.io": "2.1.10",
|
||||||
|
"@types/socket.io-client": "1.4.33",
|
||||||
|
"@types/sqlite3": "3.1.6",
|
||||||
|
"@types/url-join": "4.0.0",
|
||||||
|
"del": "5.1.0",
|
||||||
|
"gulp": "4.0.2",
|
||||||
|
"gulp-clean-css": "4.3.0",
|
||||||
|
"gulp-concat": "2.6.1",
|
||||||
|
"gulp-dart-sass": "1.0.2",
|
||||||
|
"gulp-plumber": "1.2.1",
|
||||||
|
"gulp-sourcemaps": "2.6.5",
|
||||||
|
"gulp-tslint": "8.1.4",
|
||||||
|
"gulp-typescript": "5.0.1",
|
||||||
|
"terser-webpack-plugin": "3.0.7",
|
||||||
|
"ts-loader": "8.0.1",
|
||||||
|
"tslint": "6.1.2",
|
||||||
|
"typescript": "3.9.7",
|
||||||
|
"webpack": "4.44.0",
|
||||||
|
"webpack-stream": "5.2.1",
|
||||||
|
"aribts": "^2.1.12",
|
||||||
|
"b24.js": "1.0.3",
|
||||||
|
"basic-auth": "2.0.1",
|
||||||
|
"body-parser": "1.19.0",
|
||||||
|
"chart.js": "2.9.3",
|
||||||
|
"css-ripple-effect": "1.0.5",
|
||||||
|
"diskusage": "1.1.3",
|
||||||
|
"express": "4.17.1",
|
||||||
|
"express-openapi": "7.0.0",
|
||||||
|
"fs-extra": "9.0.1",
|
||||||
|
"hls-b24.js": "0.12.3",
|
||||||
|
"js-yaml": "3.14.0",
|
||||||
|
"lodash": "4.17.19",
|
||||||
|
"log4js": "6.3.0",
|
||||||
|
"material-design-icons": "3.0.1",
|
||||||
|
"material-design-lite": "1.3.0",
|
||||||
|
"minimist": "1.2.5",
|
||||||
|
"mirakurun": "3.2.0",
|
||||||
|
"mithril": "2.0.4",
|
||||||
|
"mkdirp": "1.0.4",
|
||||||
|
"multer": "1.4.2",
|
||||||
|
"mysql": "2.18.1",
|
||||||
|
"openapi-types": "7.0.0",
|
||||||
|
"pg": "8.3.0",
|
||||||
|
"request": "2.88.2",
|
||||||
|
"socket.io": "2.3.0",
|
||||||
|
"socket.io-client": "2.3.0",
|
||||||
|
"sqlite3": "5.0.0",
|
||||||
|
"swagger-ui-dist": "3.30.2",
|
||||||
|
"url-join": "4.0.1"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
diff --git a/src/server/ConfigInterface.ts b/src/server/ConfigInterface.ts
|
||||||
|
index d23badd..1dd2b98 100644
|
||||||
|
--- a/src/server/ConfigInterface.ts
|
||||||
|
+++ b/src/server/ConfigInterface.ts
|
||||||
|
@@ -11,9 +11,10 @@ interface ConfigInterface {
|
||||||
|
dbPath: string;
|
||||||
|
dbInfoPath: string;
|
||||||
|
mysql: {
|
||||||
|
- host: string;
|
||||||
|
+ host?: string;
|
||||||
|
+ socketPath?: string;
|
||||||
|
user: string;
|
||||||
|
- password: string;
|
||||||
|
+ password?: string;
|
||||||
|
database: string;
|
||||||
|
connectTimeout: number;
|
||||||
|
connectionLimit: number;
|
@ -39,6 +39,14 @@ let
|
|||||||
meta.broken = since "12";
|
meta.broken = since "12";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
# NOTE: this is a stub package to fetch npm dependencies for
|
||||||
|
# ../../applications/video/epgstation
|
||||||
|
epgstation = super."epgstation-../../applications/video/epgstation".override (drv: {
|
||||||
|
meta = drv.meta // {
|
||||||
|
broken = true; # not really broken, see the comment above
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
bitwarden-cli = pkgs.lib.overrideDerivation super."@bitwarden/cli" (drv: {
|
bitwarden-cli = pkgs.lib.overrideDerivation super."@bitwarden/cli" (drv: {
|
||||||
name = "bitwarden-cli-${drv.version}";
|
name = "bitwarden-cli-${drv.version}";
|
||||||
});
|
});
|
||||||
|
@ -66,6 +66,7 @@
|
|||||||
, "elm-oracle"
|
, "elm-oracle"
|
||||||
, "emoj"
|
, "emoj"
|
||||||
, "emojione"
|
, "emojione"
|
||||||
|
, {"epgstation": "../../applications/video/epgstation"}
|
||||||
, "escape-string-regexp"
|
, "escape-string-regexp"
|
||||||
, "eslint"
|
, "eslint"
|
||||||
, "eslint_d"
|
, "eslint_d"
|
||||||
|
4384
pkgs/development/node-packages/node-packages.nix
generated
4384
pkgs/development/node-packages/node-packages.nix
generated
File diff suppressed because it is too large
Load Diff
@ -20251,6 +20251,8 @@ in
|
|||||||
|
|
||||||
epeg = callPackage ../applications/graphics/epeg { };
|
epeg = callPackage ../applications/graphics/epeg { };
|
||||||
|
|
||||||
|
epgstation = callPackage ../applications/video/epgstation { };
|
||||||
|
|
||||||
inherit (gnome3) epiphany;
|
inherit (gnome3) epiphany;
|
||||||
|
|
||||||
ephemeral = callPackage ../applications/networking/browsers/ephemeral { };
|
ephemeral = callPackage ../applications/networking/browsers/ephemeral { };
|
||||||
|
Loading…
Reference in New Issue
Block a user