This repository has no description
0

Configure Feed

Select the types of activity you want to include in your feed.

superconfig / configs / services / radio / default.nix
10 kB 319 lines
1{ 2 self, 3 pkgs, 4 lib, 5 ... 6}: 7 8let 9 name = "radio"; 10 11 stockholmPkgs = self.inputs.stockholm.packages.${pkgs.stdenv.hostPlatform.system}; 12 13 music_dir = "/var/music"; 14 15 # dash 0.5.13 has a regression where `read` builtin discards input when stdin is a socket 16 # This breaks htgen which uses tcpserver. Pin htgen's dash to 0.5.12 until upstream fixes it. 17 # See: https://git.kernel.org/pub/scm/utils/dash/dash.git/commit/?id=1d072e9c3292281a7eee54c41fec117ff22723e5 18 dash-0_5_12 = pkgs.dash.overrideAttrs (_old: rec { 19 version = "0.5.12"; 20 src = pkgs.fetchurl { 21 url = "http://gondor.apana.org.au/~herbert/dash/files/dash-${version}.tar.gz"; 22 hash = "sha256-akdKxG6LCzKRbExg32lMggWNMpfYs4W3RQgDDKSo8oo="; 23 }; 24 }); 25 26 htgen-fixed = stockholmPkgs.htgen.override { 27 pkgs = pkgs // { 28 dash = dash-0_5_12; 29 }; 30 }; 31 32 skip_track = pkgs.writers.writeBashBin "skip_track" '' 33 set -eu 34 35 # TODO come up with new rating, without moving files 36 # current_track=$(${pkgs.curl}/bin/curl -fSs http://localhost:8002/current | ${pkgs.jq}/bin/jq -r .filename) 37 # track_infos=$(${print_current}/bin/print_current) 38 # skip_count=$(${pkgs.attr}/bin/getfattr -n user.skip_count --only-values "$current_track" || echo 0) 39 # if [[ "$current_track" =~ .*/the_playlist/music/.* ]] && [ "$skip_count" -le 2 ]; then 40 # skip_count=$((skip_count+1)) 41 # ${pkgs.attr}/bin/setfattr -n user.skip_count -v "$skip_count" "$current_track" 42 # echo skipping: "$track_infos" skip_count: "$skip_count" 43 # else 44 # mkdir -p "$music_dir"/the_playlist/.graveyard/ 45 # mv "$current_track" "$music_dir"/the_playlist/.graveyard/ 46 # echo killing: "$track_infos" 47 # fi 48 ${pkgs.curl}/bin/curl -fSs -X POST http://localhost:8002/skip | 49 ${pkgs.jq}/bin/jq -r '.filename' 50 ''; 51 52 good_track = pkgs.writers.writeBashBin "good_track" '' 53 set -eu 54 55 current_track=$(${pkgs.curl}/bin/curl -fSs http://localhost:8002/current | ${pkgs.jq}/bin/jq -r .filename) 56 track_infos=$(${print_current}/bin/print_current) 57 # TODO come up with new rating, without moving files 58 # if [[ "$current_track" =~ .*/the_playlist/music/.* ]]; then 59 # ${pkgs.attr}/bin/setfattr -n user.skip_count -v 0 "$current_track" 60 # else 61 # mv "$current_track" "$music_dir"/the_playlist/music/ || : 62 # fi 63 echo good: "$track_infos" 64 ''; 65 66 print_current = pkgs.writers.writeDashBin "print_current" '' 67 file=$(${pkgs.curl}/bin/curl -fSs http://localhost:8002/current | 68 ${pkgs.jq}/bin/jq -r '.filename' | 69 ${pkgs.gnused}/bin/sed 's,^${music_dir},,' 70 ) 71 link=$(${pkgs.curl}/bin/curl http://localhost:8002/current | 72 ${pkgs.jq}/bin/jq -r '.filename' | 73 ${pkgs.gnused}/bin/sed 's@.*\(.\{11\}\)\.ogg@https://youtu.be/\1@' 74 ) 75 echo "$file": "$link" 76 ''; 77 78in 79{ 80 imports = [ 81 ./news.nix 82 ./weather.nix 83 ]; 84 85 users.users = { 86 "${name}" = rec { 87 inherit name; 88 createHome = true; 89 group = name; 90 description = "radio manager"; 91 home = "/home/${name}"; 92 useDefaultShell = true; 93 openssh.authorizedKeys.keys = [ 94 self.keys.ssh.barnacle.public 95 self.keys.ssh.yubi_pgp.public 96 self.keys.ssh.termux_massulus.public 97 self.keys.ssh.yubi1.public 98 self.keys.ssh.yubi2.public 99 self.keys.ssh.solo2.public 100 ]; 101 packages = [ 102 good_track 103 skip_track 104 print_current 105 ]; 106 }; 107 }; 108 109 users.groups = { 110 "radio" = { }; 111 }; 112 113 systemd.services.radio_watcher = { 114 wantedBy = [ "multi-user.target" ]; 115 after = [ "radio.service" ]; 116 serviceConfig = { 117 ExecStart = pkgs.writers.writeDash "radio_watcher" '' 118 set -efux 119 while :; do 120 ${pkgs.curl}/bin/curl -Ss http://localhost:8000/radio.ogg -o /dev/null 121 ${pkgs.systemd}/bin/systemctl restart radio 122 sleep 60 123 done 124 ''; 125 Restart = "on-failure"; 126 }; 127 }; 128 129 services.liquidsoap.streams.radio = ./radio.liq; 130 systemd.services.radio = { 131 environment = { 132 RADIO_PORT = "8002"; 133 HOOK_TRACK_CHANGE = pkgs.writers.writeDash "on_change" '' 134 set -xefu 135 LIMIT=100000 #how many tracks to keep in the history 136 HISTORY_FILE=/var/lib/radio/recent 137 138 listeners=$(${pkgs.curl}/bin/curl -fSs http://localhost:8000/status-json.xsl | 139 ${pkgs.jq}/bin/jq '[.icestats.source[].listeners] | add' || echo 0) 140 echo "$(${pkgs.coreutils}/bin/date -Is)" "$filename" | ${pkgs.coreutils}/bin/tee -a "$HISTORY_FILE" 141 echo "$(${pkgs.coreutils}/bin/tail -$LIMIT "$HISTORY_FILE")" > "$HISTORY_FILE" 142 ''; 143 MUSIC = "${music_dir}/the_playlist"; 144 ICECAST_HOST = "localhost"; 145 }; 146 path = [ 147 pkgs.bubblewrap 148 ]; 149 serviceConfig.User = lib.mkForce "radio"; 150 }; 151 152 nixpkgs.config.packageOverrides = opkgs: { 153 liquidsoap = opkgs.liquidsoap.override { 154 runtimePackages = with opkgs; [ 155 bubblewrap 156 curl 157 ffmpeg 158 ]; 159 }; 160 icecast = opkgs.icecast.overrideAttrs (old: rec { 161 version = "2.5-beta3"; 162 163 src = pkgs.fetchurl { 164 url = "http://downloads.xiph.org/releases/icecast/icecast-${version}.tar.gz"; 165 sha256 = "sha256-4FDokoA9zBDYj8RAO/kuTHaZ6jZYBLSJZiX/IYFaCW8="; 166 }; 167 168 NIX_CFLAGS_COMPILE = "-Wno-error=implicit-function-declaration"; 169 170 buildInputs = old.buildInputs ++ [ pkgs.pkg-config ]; 171 }); 172 }; 173 services.icecast = { 174 enable = true; 175 hostname = "radio.lassul.us"; 176 admin.password = "hackme"; 177 extraConf = '' 178 <authentication> 179 <source-password>hackme</source-password> 180 <admin-user>admin</admin-user> 181 <admin-password>hackme</admin-password> 182 </authentication> 183 <logging> 184 <accesslog>-</accesslog> 185 <errorlog>-</errorlog> 186 <loglevel>3</loglevel> 187 </logging> 188 <mount type="normal"> 189 <mount-name>/radio.badge</mount-name> 190 <queue-size>2048000</queue-size> 191 <burst-size>128000</burst-size> 192 </mount> 193 ''; 194 }; 195 196 networking.firewall.interfaces.retiolum.allowedTCPPorts = [ 197 8001 198 8002 199 ]; 200 201 krebs.htgen.radio = { 202 package = htgen-fixed; 203 port = 8001; 204 user = { 205 name = "radio"; 206 }; 207 scriptFile = pkgs.writers.writeDash "radio" '' 208 set -x 209 case "''${Method:-} ''${Request_URI:-}" in 210 "POST /skip") 211 printf 'HTTP/1.1 200 OK\r\n' 212 printf 'Connection: close\r\n' 213 printf '\r\n' 214 msg=$(${skip_track}/bin/skip_track) 215 echo "$msg" 216 exit 217 ;; 218 "POST /good") 219 printf 'HTTP/1.1 200 OK\r\n' 220 printf 'Connection: close\r\n' 221 printf '\r\n' 222 msg=$(${good_track}/bin/good_track) 223 echo "$msg" 224 exit 225 ;; 226 esac 227 ''; 228 }; 229 230 networking.firewall.allowedTCPPorts = [ 231 80 232 8000 233 ]; 234 services.nginx = { 235 enable = true; 236 virtualHosts."radio.r" = { 237 locations."/".extraConfig = '' 238 # https://github.com/aswild/icecast-notes#core-nginx-config 239 proxy_pass http://localhost:8000; 240 # Disable request size limit, very important for uploading large files 241 client_max_body_size 0; 242 243 # Enable support `Transfer-Encoding: chunked` 244 chunked_transfer_encoding on; 245 246 # Disable request and response buffering, minimize latency to/from Icecast 247 proxy_buffering off; 248 proxy_request_buffering off; 249 250 # Icecast needs HTTP/1.1, not 1.0 or 2 251 proxy_http_version 1.1; 252 253 # Forward all original request headers 254 proxy_pass_request_headers on; 255 256 # Set some standard reverse proxy headers. Icecast server currently ignores these, 257 # but may support them in a future version so that access logs are more useful. 258 proxy_set_header Host $host; 259 proxy_set_header X-Real-IP $remote_addr; 260 proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 261 proxy_set_header X-Forwarded-Proto $scheme; 262 263 # get source ip for weather reports 264 proxy_set_header user-agent "$http_user_agent; client-ip=$remote_addr"; 265 ''; 266 locations."= /recent".extraConfig = '' 267 default_type "text/plain"; 268 alias /var/lib/radio/recent; 269 ''; 270 locations."= /current".extraConfig = '' 271 proxy_pass http://localhost:8002; 272 ''; 273 locations."= /skip".extraConfig = '' 274 proxy_pass http://localhost:8001; 275 ''; 276 locations."= /good".extraConfig = '' 277 proxy_pass http://localhost:8001; 278 ''; 279 locations."= /radio.sh".alias = pkgs.writeScript "radio.sh" '' 280 #!/bin/sh 281 trap 'exit 0' EXIT 282 while sleep 1; do 283 mpv \ 284 --cache-secs=0 --demuxer-readahead-secs=0 --untimed --cache-pause=no \ 285 'http://radio.lassul.us/radio.ogg' 286 done 287 ''; 288 locations."= /controls".extraConfig = '' 289 default_type "text/html"; 290 alias ${./controls.html}; 291 ''; 292 extraConfig = '' 293 add_header 'Access-Control-Allow-Origin' '*'; 294 add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS'; 295 ''; 296 }; 297 }; 298 services.syncthing.settings.folders."/home/lass/tmp/the_playlist" = { 299 path = lib.mkForce "/var/music/the_playlist"; 300 devices = [ 301 "mors" 302 "radio" 303 ]; 304 }; 305 # lass and radio manage the playlist. The default ACL hands rw on new 306 # files and rwx on new directories to both (files are created without x, 307 # so the mask drops it); existing content keeps the ACLs it already has. 308 # No X: tmpfiles applies it to existing files with an r-- mask. 309 systemd.tmpfiles.settings."10-the-playlist" = { 310 "/var/music/the_playlist" = { 311 d = { }; 312 "a+".argument = "u:lass:rwx,u:radio:rwx"; 313 "A+".argument = "d:u:lass:rwx,d:u:radio:rwx"; 314 }; 315 # traverse down to the playlist 316 "/var/music"."a+".argument = "u:lass:x"; 317 "/var"."a+".argument = "u:lass:x"; 318 }; 319}