mirror of
http://git.nowherejezfoltodf4jiyl6r56jnzintap5vyjlia7fkirfsnfizflqd.onion/nihilist/selfhosting-blogposts.git
synced 2025-05-16 12:16:59 +00:00
2987 lines
121 KiB
Markdown
2987 lines
121 KiB
Markdown
---
|
|
search:
|
|
exclude: true
|
|
---
|
|
# Lainon Radio Setup
|
|
|
|

|
|
|
|
In this tutorial we're going to setup a web radio for lainons on a debian server VM, figuring out how barrucadu installed [lainon.life](https://lainon.life) by looking at his github [repository](https://github.com/barrucadu/lainonlife).
|
|
|
|
## **Initial Setup**
|
|
|
|
First let's clone the repository into /srv
|
|
|
|
|
|
root@lain:/srv# apt update -y ; apt upgrade -y ; apt install git net-utils vim -y
|
|
|
|
#for arch users:
|
|
root@lain:/srv# pacman -Syyuu ; pacman -S git vim
|
|
|
|
root@lain:/srv# cd /srv
|
|
root@lain:/srv# git clone https://github.com/barrucadu/lainonlife
|
|
|
|
|
|
|
|
Once that's done we start to install the required dependencies:
|
|
|
|
|
|
root@lain:/srv# apt install curl mpd mpc alsa-utils nginx -y
|
|
|
|
#for arch users:
|
|
root@lain:/srv# pacman -S curl mpd mpc alsa-utils nginx -y
|
|
|
|
|
|
|
|
We're going to start with the nginx configuration:
|
|
|
|
|
|
root@lain:/srv# ls
|
|
lainonlife
|
|
root@lain:/srv# cd lainonlife/examples/
|
|
root@lain:/srv/lainonlife/examples# ls -l
|
|
total 12
|
|
-rw-r--r-- 1 root root 1944 Jul 11 22:11 icecast.xml
|
|
-rw-r--r-- 1 root root 1136 Jul 11 22:11 mpd-cyberia.conf
|
|
-rw-r--r-- 1 root root 1161 Jul 11 22:11 nginx.conf
|
|
|
|
|
|
root@lain:/srv/lainonlife/examples# cp nginx.conf /etc/nginx/sites-available/lainon.conf
|
|
root@lain:/srv/lainonlife/examples# cd /etc/nginx/sites-available/
|
|
root@lain:/etc/nginx/sites-available# rm default
|
|
root@lain:/etc/nginx/sites-available# rm ../sites-enabled/default
|
|
root@lain:/etc/nginx/sites-available# vim lain.conf
|
|
|
|
root@lain:/etc/nginx/sites-available# cat lain.conf
|
|
server {
|
|
listen 80 default_server;
|
|
listen [::]:80 default_server;
|
|
|
|
server_name lain.void.yt;
|
|
root /srv/http;
|
|
|
|
proxy_set_header Host $host;
|
|
proxy_set_header X-Real-IP $remote_addr;
|
|
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
proxy_set_header X-Forwarded-Proto $scheme;
|
|
proxy_set_header X-Forwarded-Host $host;
|
|
proxy_set_header X-Forwarded-Server $host;
|
|
proxy_set_header Accept-Encoding "";
|
|
|
|
# this is needed to let people ajax stuff from other sites.
|
|
add_header 'Access-Control-Allow-Origin' '*';
|
|
|
|
# this is very important! if you don't set it, nginx will buffer
|
|
# the proxied audio stream to disk and eat all your space!
|
|
proxy_max_temp_file_size 0;
|
|
|
|
location / {
|
|
try_files $uri $uri/ @script;
|
|
}
|
|
|
|
# icecast
|
|
location /radio/ {
|
|
proxy_pass http://localhost:8000/;
|
|
}
|
|
|
|
# grafana
|
|
#location /graphs/ {
|
|
# proxy_pass http://localhost:8001/;
|
|
#}
|
|
|
|
# backend
|
|
location @script {
|
|
proxy_pass http://localhost:8002;
|
|
}
|
|
}
|
|
|
|
root@lain:/etc/nginx/sites-available# ln -s /etc/nginx/sites-available/lain.conf /etc/nginx/sites-enabled/
|
|
root@lain:/etc/nginx/sites-available# nginx -t
|
|
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
|
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
|
|
|
|
|
|
|
So right here in the nginx config i changed the server_name to match the DNS i will give it, and i commented out the grafana block because i won't use it. Although we do need the @script backend and icecast. So now from here let's move on to [icecast](https://github.com/xiph/icecast-server), we're going to clone it in /srv too:
|
|
|
|
|
|
root@lain:/etc/nginx/sites-available# cd /srv
|
|
|
|
root@lain:/srv/icecast-server# apt install vorbis-tools libvorbis-dev libxml2 libxml2-dev libxslt1.1 libxslt1-dev curl pkg-config dh-autoreconf -y
|
|
|
|
root@lain:/srv/icecast-server# source ~/.bashrc
|
|
|
|
|
|
|
|
[ lain ] [ /dev/pts/1 ] [/srv]
|
|
→ git clone https://gitlab.xiph.org/xiph/icecast-server --recursive
|
|
Cloning into 'icecast-server'...
|
|
warning: redirecting to https://gitlab.xiph.org/xiph/icecast-server.git/
|
|
remote: Enumerating objects: 18225, done.
|
|
remote: Counting objects: 100% (1985/1985), done.
|
|
remote: Compressing objects: 100% (432/432), done.
|
|
remote: Total 18225 (delta 1571), reused 1949 (delta 1545), pack-reused 16240
|
|
Receiving objects: 100% (18225/18225), 6.78 MiB | 1.19 MiB/s, done.
|
|
Resolving deltas: 100% (14236/14236), done.
|
|
Submodule 'm4' (https://gitlab.xiph.org/xiph/icecast-m4.git) registered for path 'm4'
|
|
Submodule 'src/common' (https://gitlab.xiph.org/xiph/icecast-common.git) registered for path 'src/common'
|
|
Cloning into '/srv/icecast-server/m4'...
|
|
remote: Enumerating objects: 230, done.
|
|
remote: Counting objects: 100% (7/7), done.
|
|
remote: Compressing objects: 100% (5/5), done.
|
|
remote: Total 230 (delta 2), reused 7 (delta 2), pack-reused 223
|
|
Receiving objects: 100% (230/230), 50.94 KiB | 145.00 KiB/s, done.
|
|
Resolving deltas: 100% (131/131), done.
|
|
Cloning into '/srv/icecast-server/src/common'...
|
|
remote: Enumerating objects: 2613, done.
|
|
remote: Counting objects: 100% (72/72), done.
|
|
remote: Compressing objects: 100% (34/34), done.
|
|
remote: Total 2613 (delta 37), reused 72 (delta 37), pack-reused 2541
|
|
Receiving objects: 100% (2613/2613), 468.38 KiB | 587.00 KiB/s, done.
|
|
Resolving deltas: 100% (1828/1828), done.
|
|
Submodule path 'm4': checked out '2c950d5f44435b25fae36586f23ba98328adedfa'
|
|
Submodule path 'src/common': checked out '617d219021956706a6f664eba437f94bfdbde8b2'
|
|
|
|
root@lain:/srv# cd icecast-server/
|
|
|
|
root@lain:/srv/icecast-server# ./autogen.sh
|
|
|
|
root@lain:/srv/icecast-server# chmod +x configure
|
|
|
|
#for arch users:
|
|
root@lain:/srv/icecast-server# pacman -S libxslt
|
|
|
|
root@lain:/srv/icecast-server# ./configure
|
|
|
|
[...]
|
|
|
|
|
|
config.status: executing libtool commands
|
|
|
|
Icecast configuration
|
|
---------------------
|
|
Version : 2.4.99.2
|
|
cURL : no
|
|
TLS (openSSL) : no
|
|
|
|
Format/Codec support:
|
|
Ogg : yes
|
|
Theora : no
|
|
Speex : no
|
|
|
|
Features:
|
|
YP support : no
|
|
Client tests : no
|
|
|
|
Development logging: no
|
|
|
|
root@lain:/srv/icecast-server# make
|
|
root@lain:/srv/icecast-server# make install
|
|
|
|
|
|
|
|
Once it's done we should be able to get the **icecast** binary added to our PATH, and a sample config file in **/usr/local/etc/** :
|
|
|
|
|
|
root@lain:/srv/icecast-server# which icecast
|
|
/usr/local/bin/icecast
|
|
|
|
root@lain:/srv/icecast-server# ls /usr/local/etc
|
|
icecast.xml
|
|
|
|
|
|
|
|
Although barrucadu also left a sample config for us to use, so let's test it after we modify it to match our Icecast install's directory paths for **/var/log/icecast** , **/srv/IcecastServer/admin/** , and **/srv/icecast-server/web/** :
|
|
|
|
|
|
root@lain:/srv/icecast-server# mkdir /var/log/icecast
|
|
root@lain:/srv/icecast-server# ls -l /var/log/icecast /srv/icecast-server/admin/ /srv/icecast-server/web/
|
|
/srv/icecast-server/admin/:
|
|
total 88
|
|
-rw-r--r-- 1 root root 834 Jul 11 22:36 error-html.xsl
|
|
-rw-r--r-- 1 root root 650 Jul 11 22:36 error-plaintext.xsl
|
|
drwxr-xr-x 2 root root 4096 Jul 11 22:36 includes
|
|
-rw-r--r-- 1 root root 1735 Jul 11 22:36 listclients.xsl
|
|
-rw-r--r-- 1 root root 2431 Jul 11 22:36 listmounts.xsl
|
|
-rw-r--r-- 1 root root 16245 Jul 11 22:55 Makefile
|
|
-rw-r--r-- 1 root root 495 Jul 11 22:36 Makefile.am
|
|
-rw-r--r-- 1 root root 16338 Jul 11 22:48 Makefile.in
|
|
-rw-r--r-- 1 root root 2556 Jul 11 22:36 manageauth.xsl
|
|
-rw-r--r-- 1 root root 1686 Jul 11 22:36 moveclients.xsl
|
|
-rw-r--r-- 1 root root 714 Jul 11 22:36 response.xsl
|
|
-rw-r--r-- 1 root root 4541 Jul 11 22:36 stats.xsl
|
|
-rw-r--r-- 1 root root 1227 Jul 11 22:36 updatemetadata.xsl
|
|
-rw-r--r-- 1 root root 2322 Jul 11 22:36 vclt.xsl
|
|
-rw-r--r-- 1 root root 2981 Jul 11 22:36 xspf.xsl
|
|
|
|
/srv/icecast-server/web/:
|
|
total 108
|
|
drwxr-xr-x 4 root root 4096 Jul 11 22:36 assets
|
|
-rw-r--r-- 1 root root 1432 Jul 11 22:36 auth.xsl
|
|
-rw-r--r-- 1 root root 1406 Jul 11 22:36 favicon.ico
|
|
-rw-r--r-- 1 root root 9124 Jul 11 22:36 icecast.png
|
|
-rw-r--r-- 1 root root 2228 Jul 11 22:36 key.png
|
|
-rw-r--r-- 1 root root 16426 Jul 11 22:55 Makefile
|
|
-rw-r--r-- 1 root root 811 Jul 11 22:36 Makefile.am
|
|
-rw-r--r-- 1 root root 16525 Jul 11 22:48 Makefile.in
|
|
-rw-r--r-- 1 root root 1632 Jul 11 22:36 server_version.xsl
|
|
-rw-r--r-- 1 root root 2009 Jul 11 22:36 status-json.xsl
|
|
-rw-r--r-- 1 root root 5387 Jul 11 22:36 status.xsl
|
|
-rw-r--r-- 1 root root 3879 Jul 11 22:36 style.css
|
|
-rw-r--r-- 1 root root 2042 Jul 11 22:36 tunein.png
|
|
-rw-r--r-- 1 root root 9450 Jul 11 22:36 xml2json.xslt
|
|
|
|
/var/log/icecast:
|
|
total 0
|
|
|
|
root@lain:/srv/icecast-server# cd conf/
|
|
root@lain:/srv/icecast-server/conf# cp /srv/lainonlife/examples/icecast.xml .
|
|
|
|
root@lain:/srv/icecast-server/conf# vim icecast.xml
|
|
|
|
|
|
|
|
Here i basically changed the hostname, the admin password and the icecast directory paths we mentionned earlier:
|
|
|
|

|
|
|
|
Below those you can also see that we will need to setup the mpd mountpoints later on. We now change the ownership of /var/log/icecast to **nobody:nogroup**
|
|
|
|
|
|
root@lain:/srv/icecast-server/conf# ls -lash icecast.xml
|
|
4.0K -rw-r--r-- 1 root root 1.9K Jul 11 23:20 icecast.xml
|
|
|
|
root@lain:/srv/icecast-server/conf# mkdir /var/log/icecast/
|
|
root@lain:/srv/icecast-server/conf# chown -R nobody:nogroup /var/log/icecast/
|
|
root@lain:/srv/icecast-server/conf# ls -lash /var/log
|
|
total 760K
|
|
4.0K drwxr-xr-x 10 root root 4.0K Jul 11 23:04 .
|
|
4.0K drwxr-xr-x 12 root root 4.0K Jul 11 22:13 ..
|
|
28K -rw-r--r-- 1 root root 24K Jul 11 22:45 alternatives.log
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 11 23:22 apt
|
|
4.0K -rw-r----- 1 root adm 3.8K Jul 11 23:17 auth.log
|
|
0 -rw-rw---- 1 root utmp 0 Jul 11 21:41 btmp
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 11 21:52 cups
|
|
36K -rw-r----- 1 root adm 30K Jul 11 23:24 daemon.log
|
|
12K -rw-r----- 1 root adm 9.3K Jul 11 21:52 debug
|
|
408K -rw-r--r-- 1 root root 403K Jul 11 23:22 dpkg.log
|
|
8.0K -rw-r--r-- 1 root root 32K Jul 11 22:13 faillog
|
|
4.0K -rw-r--r-- 1 root root 2.1K Jul 11 22:13 fontconfig.log
|
|
4.0K drwxr-xr-x 3 root root 4.0K Jul 11 21:48 hp
|
|
4.0K drwxr-xr-x 2 nobody nogroup 4.0K Jul 11 23:04 icecast
|
|
4.0K drwxr-xr-x 3 root root 4.0K Jul 11 21:52 installer
|
|
60K -rw-r----- 1 root adm 60K Jul 11 21:59 kern.log
|
|
12K -rw-rw-r-- 1 root utmp 286K Jul 11 22:13 lastlog
|
|
52K -rw-r----- 1 root adm 51K Jul 11 21:59 messages
|
|
4.0K drwxr-xr-x 2 mpd audio 4.0K Jul 11 22:13 mpd
|
|
4.0K drwxr-xr-x 2 root adm 4.0K Jul 11 22:28 nginx
|
|
4.0K drwx------ 2 root root 4.0K Jul 11 21:52 private
|
|
92K -rw-r----- 1 root adm 90K Jul 11 23:24 syslog
|
|
4.0K -rw-rw-r-- 1 root utmp 3.0K Jul 11 21:59 wtmp
|
|
|
|
root@lain:/srv/icecast-server/conf# icecast -c /srv/icecast-server/conf/icecast.xml
|
|
[2021-07-11 23:24:33] WARN CONFIG/_parse_root Warning, <****location> not configured, using default value "Earth".
|
|
[2021-07-11 23:24:33] WARN CONFIG/_parse_root Warning, <****admin> contact not configured, using default value "icemaster@localhost". This breaks YP directory listings. YP directory support will be disabled.
|
|
Changed groupid to 65534.
|
|
Changed supplementary groups based on user: nobody.
|
|
Changed userid to 65534.
|
|
|
|
We can check that our icecast server is running on port 8000:
|
|
|
|

|
|
|
|
Now that's done, exit out of icecast with CTRL+C and let's configure mpd using barrucadu's sample config file:
|
|
|
|
|
|
root@lain:/srv/icecast-server/conf# cd ../..
|
|
root@lain:/srv# cd lainonlife/
|
|
root@lain:/srv/lainonlife# cd examples/
|
|
root@lain:/srv/lainonlife/examples# vim mpd-cyberia.conf
|
|
|
|
|
|
|
|

|
|
|
|
First we setup the root directory for our music files in **/srv/radio/music/cyberia/** and the **/srv/radio/data/cyberia/playlists** directory:
|
|
|
|
|
|
root@lain:/srv# mkdir -p /srv/radio/data/cyberia/playlists
|
|
root@lain:/srv# mkdir -p /srv/radio/music/cyberia/
|
|
root@lain:/srv/radio# tree .
|
|
.
|
|
├── data
|
|
│ └── cyberia
|
|
│ └── playlists
|
|
└── music
|
|
└── cyberia
|
|
|
|
root@lain:/srv# mkdir -p ~/.config/mpd/
|
|
|
|
root@lain:/srv# kill $(pidof mpd)
|
|
root@lain:/srv# cp /srv/lainonlife/examples/mpd-cyberia.conf ~/.config/mpd/mpd.conf
|
|
root@lain:/srv# mpd
|
|
|
|
|
|
|
|
Now basically we will put our music files into **/srv/radio/cyberia/** , and we can make playlists of it using **ncmpcpp** i will do it from my local machine since my debian VM is in the same local network as i am :
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/30 ] [~]
|
|
→ vim ~/.config/ncmpcpp/config
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/30 ] [~]
|
|
→ cat ~/.config/ncmpcpp/config
|
|
##
|
|
# Files
|
|
# mpd_music_dir = "~/Music"
|
|
lyrics_directory = ~/.ncmpcpp/lyrics
|
|
ncmpcpp_directory = ~/.ncmpcpp
|
|
|
|
# mpd_host = "localhost"
|
|
**mpd_host = "10.0.0.201"
|
|
mpd_port = "6601"**
|
|
|
|
|
|
mpd_connection_timeout = "5"
|
|
mpd_crossfade_time = "5"
|
|
|
|
# Playlist
|
|
playlist_disable_highlight_delay = "0"
|
|
playlist_display_mode = "columns"
|
|
playlist_show_remaining_time = "yes"
|
|
|
|
browser_display_mode = "columns"
|
|
autocenter_mode = "yes"
|
|
fancy_scrolling = "yes"
|
|
follow_now_playing_lyrics = "yes"
|
|
display_screens_numbers_on_start = "yes"
|
|
ignore_leading_the = "yes"
|
|
lyrics_database = "1"
|
|
song_columns_list_format = "(10)[blue]{l} (30)[green]{a} (30)[magenta]{b} (50)[yellow]{t}"
|
|
colors_enabled = "yes"
|
|
main_window_color = "white"
|
|
main_window_highlight_color = "blue"
|
|
header_window_color = "cyan"
|
|
volume_color = "red"
|
|
progressbar_color = "cyan"
|
|
statusbar_color = "white"
|
|
active_column_color = "cyan"
|
|
active_window_border = "blue"
|
|
|
|
alternative_header_first_line_format = "$0$aqqu$/a {$7%a - $9}{$5%t$9}|{$8%f$9} $0$atqq$/a$9"
|
|
alternative_header_second_line_format = "{{$6%b$9}{ [$6%y$9]}}|{%D}"
|
|
song_list_format = "{$3%n │ $9}{$7%a - $9}{$5%t$9}|{$8%f$9}$R{$6 │ %b$9}{$3 │ %l$9}"
|
|
user_interface = "alternative"
|
|
#user_interface = "classic"
|
|
default_place_to_search_in = "database"
|
|
|
|
|
|
# visualizer
|
|
#visualizer_fifo_path = "/tmp/mpd.fifo"
|
|
#visualizer_output_name = "my_fifo"
|
|
##visualizer_sync_interval = "12"
|
|
##visualizer_type = "wave" (spectrum/wave)
|
|
#visualizer_type = "spectrum" (spectrum/wave)
|
|
#visualizer_in_stereo = "yes"
|
|
#visualizer_look = "+|"
|
|
|
|
|
|
## Navigation ##
|
|
cyclic_scrolling = "yes"
|
|
header_text_scrolling = "yes"
|
|
jump_to_now_playing_song_at_start = "yes"
|
|
lines_scrolled = "2"
|
|
|
|
## Other ##
|
|
system_encoding = "utf-8"
|
|
regular_expressions = "extended"
|
|
|
|
|
|
|
|
## Selected tracks ##
|
|
selected_item_prefix = "* "
|
|
discard_colors_if_item_is_selected = "no"
|
|
|
|
## Seeking ##
|
|
incremental_seeking = "yes"
|
|
seek_time = "1"
|
|
|
|
## Visivility ##
|
|
header_visibility = "yes"
|
|
statusbar_visibility = "yes"
|
|
titles_visibility = "yes"
|
|
|
|
|
|
progressbar_look = "=>-"
|
|
#progressbar_boldness = "yes"
|
|
progressbar_elapsed_color = "white"
|
|
|
|
now_playing_prefix = "> "
|
|
song_status_format = " $2%a $4⟫$3⟫ $8%t $4⟫$3⟫ $5%b "
|
|
autocenter_mode = "yes"
|
|
centered_cursor = "yes"
|
|
|
|
# Misc
|
|
display_bitrate = "yes"
|
|
# enable_window_title = "no"
|
|
follow_now_playing_lyrics = "yes"
|
|
ignore_leading_the = "yes"
|
|
empty_tag_marker = ""
|
|
|
|
|
|
|
|
Now if we want to connec to the mpd server with ncmpcpp we need the mpd server to be bound to it's local ip address instead of it's localhost address, so let's change it and restart it:
|
|
|
|
|
|
root@lain:/srv/radio# vim ~/.config/mpd/mpd.conf
|
|
|
|
root@lain:/srv/radio# cat ~/.config/mpd/mpd.conf
|
|
music_directory "/srv/radio/music/cyberia"
|
|
playlist_directory "/srv/radio/data/cyberia/playlists"
|
|
db_file "/srv/radio/data/cyberia/db"
|
|
state_file "/srv/radio/data/cyberia/state"
|
|
sticker_file "/srv/radio/data/cyberia/sticker.sql"
|
|
log_file "/srv/radio/data/syslog"
|
|
#bind_to_address "127.0.0.1"
|
|
**bind_to_address "10.0.0.201"
|
|
port "6601"**
|
|
|
|
[...]
|
|
|
|
root@lain:/srv/radio# mpd
|
|
Jul 12 00:13 : hybrid_dsd: The Hybrid DSD decoder is disabled because it was not explicitly enabled
|
|
Jul 12 00:13 : exception: Input plugin 'tidal' is unavailable: No Tidal application token configured
|
|
Jul 12 00:13 : exception: Input plugin 'qobuz' is unavailable: No Qobuz app_id configured
|
|
|
|
root@lain:/srv/radio# pidof mpd
|
|
23898
|
|
|
|
|
|
|
|
You can ignore the the stderr from mpd, mpd is anyway launched as you can see from the pidof command. Now that's done we can connect to it with ncmpcpp:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/30 ] [~]
|
|
→ nmap -sCV -p 6601 10.0.0.201
|
|
Starting Nmap 7.91 ( https://nmap.org ) at 2021-07-12 00:19 CEST
|
|
Nmap scan report for 10.0.0.201
|
|
Host is up (0.0047s latency).
|
|
|
|
PORT STATE SERVICE VERSION
|
|
**6601/tcp open mpd Music Player Daemon 0.21.4**
|
|
|
|
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
|
|
Nmap done: 1 IP address (1 host up) scanned in 0.71 seconds
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/30 ] [~]
|
|
→ ncmpcpp -h 10.0.0.201 -p 6601
|
|
Reading configuration from /home/nothing/.config/ncmpcpp/config...
|
|
|
|
|
|
|
|

|
|
|
|
Now obviously there are no music files to play yet, so we need to add them to the server's **/srv/radio/music/cyberia/** directory:
|
|
|
|
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia# apt purge youtube-dl -y #youtube-dl is severly outdated on debian's repositories
|
|
root@lain:/srv/radio/music/cyberia# apt install python3-pip -y
|
|
root@lain:/srv/radio/music/cyberia# pip3 install youtube-dl
|
|
root@lain:/srv/radio/music/cyberia# bash
|
|
root@lain:/srv/radio/music/cyberia# youtube-dl --version
|
|
2021.06.06
|
|
|
|
root@lain:/srv/radio/music/cyberia# youtube-dl -x https://www.youtube.com/playlist?list=PLMR9WY6VV-0c0bv7MsYjudCxx0X1cXWBQ --audio-format mp3
|
|
[youtube:tab] PLMR9WY6VV-0c0bv7MsYjudCxx0X1cXWBQ: Downloading webpage
|
|
[download] Downloading playlist: Serial Experiments Lain OST
|
|
[youtube:tab] playlist Serial Experiments Lain OST: Downloading 14 videos
|
|
[download] Downloading video 1 of 14
|
|
[youtube] AsPLBQfZQ04: Downloading webpage
|
|
[download] Destination: Serial Experiment Lain - Infanity world-AsPLBQfZQ04.webm
|
|
[download] 5.3% of 4.98MiB at 54.61KiB/s ETA 01:28
|
|
|
|
|
|
EDIT 2023: now you need to use yt-dlp! https://github.com/yt-dlp/yt-dlp/wiki/Installation
|
|
|
|
sudo curl -L https://github.com/yt-dlp/yt-dlp/releases/latest/download/yt-dlp -o /usr/local/bin/yt-dlp
|
|
sudo chmod a+rx /usr/local/bin/yt-dlp # Make executable
|
|
yt-dlp -U
|
|
|
|
[...]
|
|
|
|
[download] Downloading video 14 of 14
|
|
[youtube] 5dbi4N6NGn4: Downloading webpage
|
|
[download] Destination: Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.webm
|
|
[download] 100% of 2.57MiB in 00:37
|
|
[ffmpeg] Destination: Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.mp3
|
|
Deleting original file Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.webm (pass -k to keep)
|
|
[download] Finished downloading playlist: Serial Experiments Lain OST
|
|
|
|
root@lain:/srv/radio/music/cyberia# ls -lash
|
|
total 62M
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 00:55 .
|
|
4.0K drwxr-xr-x 3 root root 4.0K Jul 12 00:04 ..
|
|
2.7M -rw-r--r-- 1 root root 2.7M Jun 9 2017 "Lain's Theme - Lain-o-cwuTmqz8c.mp3"
|
|
5.7M -rw-r--r-- 1 root root 5.7M Dec 15 2019 'Serial Experiment Lain - Antidepressant 044-KaOsmUDMdaE.mp3'
|
|
4.7M -rw-r--r-- 1 root root 4.7M Dec 24 2019 'Serial Experiment Lain - Cloudy with occasional rain-1TunrW7dRr0.mp3'
|
|
4.8M -rw-r--r-- 1 root root 4.8M Dec 9 2019 'Serial Experiment Lain - Duvet (cyberia remix)-juDqDMlTfUg.mp3'
|
|
1.5M -rw-r--r-- 1 root root 1.5M Mar 18 2015 'Serial Experiment Lain - Duvet (tv version)-EnEaNaqGMqU.mp3'
|
|
5.0M -rw-r--r-- 1 root root 5.0M Oct 15 2017 'Serial Experiment Lain - Infanity world-AsPLBQfZQ04.mp3'
|
|
4.6M -rw-r--r-- 1 root root 4.6M Jan 23 2020 'Serial Experiment Lain - Invisible file-32IlMQ8Bs6w.mp3'
|
|
4.7M -rw-r--r-- 1 root root 4.7M Dec 9 2019 'Serial Experiment Lain - Island in video cassette-CCdyzUPrLpM.mp3'
|
|
7.1M -rw-r--r-- 1 root root 7.1M Jul 9 2014 'Serial Experiment Lain - k.i.d.s-TvCJnW46ISo.mp3'
|
|
6.1M -rw-r--r-- 1 root root 6.1M Dec 16 2019 'Serial Experiment Lain - Prayer-yyPMWWjzMG8.mp3'
|
|
4.0M -rw-r--r-- 1 root root 4.0M Dec 25 2019 'Serial Experiment Lain - Professed intention and real-D4G97Xsc8PA.mp3'
|
|
3.8M -rw-r--r-- 1 root root 3.8M Jan 23 2020 'Serial Experiment Lain - Psychedelic farm-XEGz6CJnY04.mp3'
|
|
4.7M -rw-r--r-- 1 root root 4.7M Dec 17 2019 'Serial Experiment Lain - Speed-zFwQFdAsGGA.mp3'
|
|
2.7M -rw-r--r-- 1 root root 2.7M Nov 7 2018 'Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.mp3'
|
|
|
|
|
|
Now that's done, let's go back into ncmpcpp to make our playlist:
|
|
|
|
|
|
[ 10.10.14.8/23 ] [ /dev/pts/30 ] [~]
|
|
→ ncmpcpp -h 10.0.0.201 -p 6601
|
|
|
|
#once in ncmpcpp
|
|
#press 1 to get to the playlist tab
|
|
#press a to add
|
|
#if you can't connect to it, then use ncmpcpp on the remote host:
|
|
|
|
root@lain:~# mkdir ~/.config/ncmpcpp
|
|
root@lain:~# which ncmpcpp
|
|
/usr/bin/ncmpcpp
|
|
root@lain:~# vim ~/.config/ncmpcpp/config
|
|
|
|
#make sure that you have changed the 10.0.0.201 part to 127.0.0.1
|
|
#same goes for mpd:
|
|
#also make mpd use alsa for now:
|
|
|
|
root@lain:~# cat ~/.config/mpd/mpd.conf
|
|
music_directory "/srv/radio/music/cyberia"
|
|
playlist_directory "/srv/radio/data/cyberia/playlists"
|
|
db_file "/srv/radio/data/cyberia/db"
|
|
state_file "/srv/radio/data/cyberia/state"
|
|
sticker_file "/srv/radio/data/cyberia/sticker.sql"
|
|
log_file "/srv/radio/data/syslog"
|
|
bind_to_address "127.0.0.1"
|
|
#bind_to_address "10.0.0.201"
|
|
port "6601"
|
|
|
|
audio_output {
|
|
name "[mpd] cyberia (ogg)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "vorbis"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-cyberia.ogg"
|
|
user "source"
|
|
password "password for icecast"
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
|
|
audio_output {
|
|
name "[mpd] cyberia (mp3)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "lame"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-cyberia.mp3"
|
|
user "source"
|
|
password "password for icecast"
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
|
|
audio_output {
|
|
type "null"
|
|
name "null"
|
|
}
|
|
|
|
audio_output {
|
|
type "alsa"
|
|
name "alsa audio"
|
|
mixer_type "software"
|
|
}
|
|
|
|
audio_output {
|
|
type "fifo"
|
|
name "my_fifo"
|
|
path "/tmp/mpd.fifo"
|
|
format "44100:16:2"
|
|
}
|
|
|
|
|
|
root@lain:~# mpd
|
|
Jul 12 08:29 : hybrid_dsd: The Hybrid DSD decoder is disabled because it was not explicitly enabled
|
|
Jul 12 08:29 : exception: Input plugin 'tidal' is unavailable: No Tidal application token configured
|
|
Jul 12 08:29 : exception: Input plugin 'qobuz' is unavailable: No Qobuz app_id configured
|
|
root@lain:~# pidof mpd
|
|
29091
|
|
|
|
root@lain:~# netstat -alntup | grep 6601
|
|
tcp 0 0 127.0.0.1:6601 0.0.0.0:* LISTEN 29091/mpd
|
|
|
|
root@lain:~# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press 2 to go to the browsing tab and
|
|
#press u to update the mpd database
|
|
#select the songs you want to add to the playlist with INSERT
|
|
#then once you selected them press a to add to a playlist
|
|
#hit 'New playlist', choose the name you want for it:
|
|

|
|
|
|
#press 5 to go to the playlist editor tab to check the result:
|
|

|
|
#now here you see we have a small cyberia playlist.
|
|
#press 8 to go to the visualizer to verify that it's working properly:
|
|

|
|
#now press 7 to go to the Outputs tab to enable the ogg and mp3 outputs:
|
|

|
|
#We're going to need those for icecast. Now that's done we can exit out of ncmpcpp and mpd:
|
|
#mpd is going to run in the background, so we can always return to it with # ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press q to exit ncmpcpp
|
|
|
|
|
|
|
|
We can verify our cyberia ogg output exists on port 8000 by launching icecast and using it to verify it:
|
|
|
|
|
|
root@lain:~# icecast -c /srv/icecast-server/conf/icecast.xml
|
|
[2021-07-12 09:25:43] WARN CONFIG/_parse_root Warning, not configured, using default value "Earth".
|
|
[2021-07-12 09:25:43] WARN CONFIG/_parse_root Warning, contact not configured, using default value "icemaster@localhost". This breaks YP directory listings. YP directory support will be disabled.
|
|
Changed groupid to 65534.
|
|
Changed supplementary groups based on user: nobody.
|
|
Changed userid to 65534.
|
|
|
|
|
|
|
|
We can log into icecast using the **admin:P@SSW0RD_FOR_ADM1N** credentials we used earlier in the config:
|
|
|
|

|
|
|
|
Now we need to fix the fact that icecast doesn't detect our mountpoints:
|
|
|
|

|
|
|
|
First we fix the passwords in the mpd and icecast config files:
|
|
|
|
|
|
root@lain:~# vim ~/.config/mpd/mpd.conf
|
|
root@lain:~# cat ~/.config/mpd/mpd.conf
|
|
music_directory "/srv/radio/music/cyberia"
|
|
playlist_directory "/srv/radio/data/cyberia/playlists"
|
|
db_file "/srv/radio/data/cyberia/db"
|
|
state_file "/srv/radio/data/cyberia/state"
|
|
sticker_file "/srv/radio/data/cyberia/sticker.sql"
|
|
log_file "/srv/radio/data/syslog"
|
|
bind_to_address "127.0.0.1"
|
|
#bind_to_address "10.0.0.201"
|
|
port "6601"
|
|
|
|
audio_output {
|
|
name "[mpd] cyberia (ogg)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "vorbis"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-cyberia.ogg"
|
|
user "source"
|
|
**password "P@SSW0RD"**
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
|
|
audio_output {
|
|
name "[mpd] cyberia (mp3)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "lame"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-cyberia.mp3"
|
|
user "source"
|
|
**password "P@SSW0RD"**
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
[...]
|
|
|
|
root@lain:~# vim /srv/icecast-server/conf/icecast.xml
|
|

|
|
|
|
|
|
|
|
Next we restart mpd and icecast:
|
|
|
|
|
|
root@lain:~# systemctl restart mpd
|
|
root@lain:~# icecast -c /srv/icecast-server/conf/icecast.xml
|
|
|
|
|
|
|
|
Now icecast doesn't pick up our ogg stream, so let's try out the mp3 one:
|
|
|
|
|
|
root@lain:~# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|

|
|
|
|
|
|
|
|
And as you can see on icecast's admin page we see that the mp3 output does get picked up:
|
|
|
|

|
|
|
|
You can also see it appear on icecast's public **/status.xsl** page:
|
|
|
|

|
|
|
|
And we can play the direct **.m3u** link to our VLC player:
|
|
|
|

|
|
|
|
And it works! now let's make sure that mpd is running on loop while shuffling the songs, from ncmpcpp you can press **r** for repeat mode, and **z** for random mode. After that's working, we need to setup the website itself.
|
|
|
|
|
|
root@lain:/srv/lainonlife# mkdir /srv/http/
|
|
root@lain:/srv/lainonlife# cp config.json.example config.json
|
|
root@lain:/srv/lainonlife# vim config.json
|
|
root@lain:/srv/lainonlife# cat config.json
|
|
{ "channels":
|
|
{ "cyberia": { "mpd_host": "localhost", "mpd_port": 6601, "description": "classic lainchan radio: electronic, chiptune, weeb" }
|
|
}
|
|
|
|
, "template":
|
|
{ "default_channel": "cyberia"
|
|
, "icecast_status_url": "/radio/status-json.xsl"
|
|
, "icecast_stream_url_base": "https://lain.void.yt/"
|
|
, "server_cost": 10.00
|
|
, "currency_symbol": "€"
|
|
}
|
|
}
|
|
|
|
|
|
|
|
For now we only have one channel, but later on we can always add more. Now let's edit build.sh to use our new config json file:
|
|
|
|
|
|
root@lain:/srv/lainonlife#cd frontend
|
|
root@lain:/srv/lainonlife/frontend# vim build.sh
|
|
root@lain:/srv/lainonlife/frontend# cat build.sh
|
|
#!/usr/bin/env bash
|
|
|
|
if [ -z "$1" ]; then
|
|
#./build.py ../config.json.example
|
|
./build.py ../config.json.example
|
|
else
|
|
./build.py "$1"
|
|
fi
|
|
|
|
|
|
|
|
Now that's done we can build the frontend assets:
|
|
|
|
|
|
#debian users:
|
|
|
|
apt install python3-pip virtualenv -y
|
|
|
|
#arch users:
|
|
pacman -S python-pip python-virtualenv
|
|
pip3 install future ; pip install future
|
|
|
|
root@lain:/srv/lainonlife/frontend# pip install jinja2
|
|
root@lain:/srv/lainonlife/frontend# pip3 install jinja2
|
|
root@lain:/srv/lainonlife/frontend# which virtualenv
|
|
/usr/bin/virtualenv
|
|
|
|
root@lain:/srv/lainonlife/frontend# ./run.sh ../config.json
|
|
|
|
root@lain:/srv/lainonlife/frontend# ./run.sh ../config.json
|
|
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
|
|
Requirement already satisfied: jinja2 in ./__venv__/lib/python2.7/site-packages (from -r requirements.txt (line 1)) (2.11.3)
|
|
Requirement already satisfied: MarkupSafe>=0.23 in ./__venv__/lib/python2.7/site-packages (from jinja2->-r requirements.txt (line 1)) (1.1.1)
|
|
|
|
|
|
Now that's done, we can see our frontend assets in the **_site** directory:
|
|
|
|
|
|
root@lain:/srv/lainonlife/frontend# cd _site/
|
|
root@lain:/srv/lainonlife/frontend/_site# ls -lash
|
|
total 300K
|
|
4.0K drwxr-xr-x 9 root root 4.0K Jul 12 10:16 .
|
|
4.0K drwxr-xr-x 10 root root 4.0K Jul 12 10:16 ..
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 404
|
|
4.0K -rw-r--r-- 1 root root 1.2K Jul 12 10:16 404.html
|
|
52K -rw-r--r-- 1 root root 52K Jul 12 10:16 android-chrome-192x192.png
|
|
88K -rw-r--r-- 1 root root 88K Jul 12 10:16 android-chrome-256x256.png
|
|
44K -rw-r--r-- 1 root root 41K Jul 12 10:16 apple-touch-icon.png
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 backgrounds
|
|
4.0K -rw-r--r-- 1 root root 246 Jul 12 10:16 browserconfig.xml
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 bumps
|
|
4.0K drwxr-xr-x 3 root root 4.0K Jul 12 10:16 css
|
|
4.0K -rw-r--r-- 1 root root 1.2K Jul 12 10:16 https://blog.nowhere.moe/donate.html
|
|
4.0K -rw-r--r-- 1 root root 1.4K Jul 12 10:16 favicon-16x16.png
|
|
4.0K -rw-r--r-- 1 root root 2.9K Jul 12 10:16 favicon-32x32.png
|
|
16K -rw-r--r-- 1 root root 15K Jul 12 10:16 favicon.ico
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 file-list
|
|
8.0K -rw-r--r-- 1 root root 4.3K Jul 12 10:16 index.html
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 js
|
|
4.0K -rw-r--r-- 1 root root 414 Jul 12 10:16 manifest.json
|
|
28K -rw-r--r-- 1 root root 26K Jul 12 10:16 mstile-150x150.png
|
|
4.0K -rw-r--r-- 1 root root 1.8K Jul 12 10:16 safari-pinned-tab.svg
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:16 upload
|
|
|
|
|
|
|
|
And it's all here! so let's copy it to the root of our webserver at **/srv/http/**
|
|
|
|
|
|
root@lain:/srv/lainonlife/frontend/_site# cd ..
|
|
root@lain:/srv/lainonlife/frontend# cp -r _site/* /srv/http/
|
|
|
|
|
|
|
|
now that's done, we need to run the backend bashscript called **run.sh** and we need to pass it a few environment variables as we run it:
|
|
|
|
|
|
root@lain:/srv/lainonlife/frontend# cd ..
|
|
root@lain:/srv/lainonlife# cd backend/
|
|
root@lain:/srv/lainonlife/backend# ls -lash
|
|
total 36K
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 10:00 .
|
|
4.0K drwxr-xr-x 9 root root 4.0K Jul 12 10:05 ..
|
|
4.0K -rwxr-xr-x 1 root root 1.5K Jul 11 22:11 backend.py
|
|
4.0K -rw-r--r-- 1 root root 21 Jul 11 22:11 .gitignore
|
|
4.0K -rw-r--r-- 1 root root 58 Jul 11 22:11 requirements.txt
|
|
**4.0K -rwxr-xr-x 1 root root 205 Jul 11 22:11 run.sh**
|
|
8.0K -rw-r--r-- 1 root root 4.1K Jul 11 22:11 stream.py
|
|
4.0K -rw-r--r-- 1 root root 3.2K Jul 11 22:11 web.py
|
|
|
|
root@lain:/srv/lainonlife/backend# CONFIG=../config.json HTTP_DIR=/srv/http PORT=5000 ./run.sh
|
|
|
|
EDIT 2024:
|
|
|
|
DONT USE THE RUN.sh ANYMORE, USE BACKEND.PY DIRECTLY!
|
|
|
|
[ lain ] [ /dev/pts/3 ] [/srv/lainonlife/backend]
|
|
→ cat /etc/systemd/system/lainradio.service
|
|
[Unit]
|
|
Description=running the run.sh script with the correct arguements
|
|
After=network.target
|
|
After=systemd-user-sessions.service
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=/srv/lainonlife/backend/
|
|
Environment="CONFIG=../config.json"
|
|
Environment="HTTP_DIR=/srv/http"
|
|
Environment="PORT=8002"
|
|
#ExecStart=/srv/lainonlife/backend/run.sh ############################## DONT USE IT ANYMORE!
|
|
ExecStart=/srv/lainonlife/backend/backend.py ########################### USE IT DIRECTLY INSTEAD!
|
|
Restart=always
|
|
RestartSec=10
|
|
KillMode=process
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
|
|
|
|
|
|
Basically here it's going to (try to) install the required python dependencies, if it fails like for me you can install the missing dependencies:
|
|
|
|
|
|
|
|
[...]
|
|
|
|
Collecting MarkupSafe>=0.23
|
|
Using cached MarkupSafe-1.1.1-cp27-cp27mu-manylinux1_x86_64.whl (24 kB)
|
|
Installing collected packages: itsdangerous, click, MarkupSafe, Jinja2, Werkzeug, Flask, python-mpd2, pytz, tzlocal, futures, funcsigs, six, apscheduler, chardet, certifi, urllib3, idna, requests
|
|
Successfully installed Flask-1.1.4 Jinja2-2.11.3 MarkupSafe-1.1.1 Werkzeug-1.0.1 apscheduler-3.7.0 certifi-2021.5.30 chardet-4.0.0 click-7.1.2 funcsigs-1.0.2 futures-3.3.0 idna-2.10 itsdangerous-1.1.0 python-mpd2-1.1.0 pytz-2021.1 requests-2.25.1 six-1.16.0 tzlocal-2.1 urllib3-1.26.6
|
|
Traceback (most recent call last):
|
|
File "backend.py", line 7, in module>
|
|
import stream as stream
|
|
File "/srv/lainonlife/backend/stream.py", line 1, in module>
|
|
from apscheduler.schedulers.background import BackgroundScheduler
|
|
ModuleNotFoundError: No module named 'apscheduler'
|
|
|
|
root@lain:/srv/lainonlife/backend# pip3 install apscheduler ; pip install apscheduler
|
|
root@lain:/srv/lainonlife/backend# pip install --upgrade pip setuptools
|
|
root@lain:/srv/lainonlife/backend# pip3 install --upgrade pip setuptools
|
|
root@lain:/srv/lainonlife/backend# pip install --upgrade virtualenv
|
|
root@lain:/srv/lainonlife/backend# apt install python-mpd python3-mpd
|
|
root@lain:/srv/lainonlife/backend# pip install flask ; pip3 install flask
|
|
|
|
#2023 EDIT: on debian 12 it is like so:
|
|
|
|
root@lain:/srv/lainonlife/backend# apt install python3-{apscheduler,setuptools,pip,mpd,flask,docopt}
|
|
root@lain:/srv/lainonlife/backend#
|
|
|
|
|
|
|
|
root@lain:/srv/lainonlife/backend# CONFIG=../config.json HTTP_DIR=/srv/http PORT=5000 ./run.sh
|
|
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
|
|
Requirement already satisfied: Flask>=0.12.0 in ./__venv__/lib/python2.7/site-packages (from -r requirements.txt (line 1)) (1.1.4)
|
|
|
|
[...]
|
|
|
|
Requirement already satisfied: MarkupSafe>=0.23 in ./__venv__/lib/python2.7/site-packages (from Jinja2 3.0,>=2.10.1->Flask>=0.12.0->-r requirements.txt (line 1)) (1.1.1)
|
|
* Serving Flask app 'web' (lazy loading)
|
|
* Environment: production
|
|
WARNING: This is a development server. Do not use it in a production deployment.
|
|
Use a production WSGI server instead.
|
|
* Debug mode: off
|
|
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
|
error talking to prometheus: HTTPConnectionPool(host='localhost', port=9090): Max retries exceeded with url: /api/v1/query?query=sum%28listeners%29+by+%28channel%29 (Caused by NewConnectionError('<****urllib3.connection.HTTPConnection object at 0x7f82323eabe0>: Failed to establish a new connection: [Errno 111] Connection refused'))
|
|
|
|
Now it seems we forgot to install prometheus on port 9090. So let's install it following a tutorial i already made [here](../progra/index.md), obviously use an up to date release version of prometheus from their release pages [here](https://github.com/prometheus/prometheus/releases) to this date, the latest version is **2-28.1** :
|
|
|
|
|
|
root@lain:/tmp# mkdir /srv/prometheus
|
|
root@lain:/tmp# cd /srv/prometheus
|
|
root@lain:/srv/prometheus# apt update -y ; apt upgrade -y
|
|
root@lain:/srv/prometheus# wget https://github.com/prometheus/prometheus/releases/download/v2.28.1/prometheus-2.28.1.linux-amd64.tar.gz
|
|
|
|
root@lain:/srv/prometheus# tar -xvzf prometheus-2.28.1.linux-amd64.tar.gz
|
|
root@lain:/srv/prometheus# cd prometheus-2.28.1.linux-amd64
|
|
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# useradd -rs /bin/false prometheus
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# cp prometheus promtool /usr/local/bin/
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# chown prometheus:prometheus /usr/local/bin/prometheus
|
|
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# mkdir /etc/prometheus
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# cp -R consoles/ console_libraries/ prometheus.yml /etc/prometheus/
|
|
|
|
root@lain:/srv/prometheus/prometheus-2.28.1.linux-amd64# cd /lib/systemd/system
|
|
root@lain:/lib/systemd/system# wget https://blog.nowhere.moe/servers/progra/p.service -O /lib/systemd/system/prometheus.service
|
|
|
|
|
|
root@lain:/etc/prometheus# mkdir /data/prometheus -p
|
|
root@lain:/etc/prometheus# chown -R prometheus:prometheus /data/prometheus /etc/prometheus/*
|
|
|
|
root@lain:/lib/systemd/system# systemctl enable --now prometheus
|
|
root@lain:/lib/systemd/system# systemctl enable --now prometheus
|
|
|
|
root@lain:/etc/prometheus# systemctl status prometheus
|
|
● prometheus.service - Prometheus
|
|
Loaded: loaded (/lib/systemd/system/prometheus.service; enabled; vendor preset: enabled)
|
|
Active: active (running) since Mon 2021-07-12 11:01:40 CEST; 1min 9s ago
|
|
Main PID: 545 (prometheus)
|
|
Tasks: 9 (limit: 4700)
|
|
Memory: 29.8M
|
|
CGroup: /system.slice/prometheus.service
|
|
└─545 /usr/local/bin/prometheus --config.file=/etc/prometheus/prometheus.yml --storage.tsdb.path=/data/prometheus --web.console.templates=/etc/prometheus/consoles --web.console.libraries=/etc/prometheus/
|
|
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.623Z caller=head.go:780 component=tsdb msg="Replaying on-disk memory mappable chunks if any"
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.624Z caller=head.go:794 component=tsdb msg="On-disk memory mappable chunks replay completed" duration=26.9µs
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.624Z caller=head.go:800 component=tsdb msg="Replaying WAL, this may take a while"
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.627Z caller=head.go:854 component=tsdb msg="WAL segment loaded" segment=0 maxSegment=0
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.629Z caller=head.go:860 component=tsdb msg="WAL replay completed" checkpoint_replay_duration=143.441µs wal_replay_duration=3.876793ms total_re
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.632Z caller=main.go:851 fs_type=EXT4_SUPER_MAGIC
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.633Z caller=main.go:854 msg="TSDB started"
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.633Z caller=main.go:981 msg="Loading configuration file" filename=/etc/prometheus/prometheus.yml
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.636Z caller=main.go:1012 msg="Completed loading of configuration file" filename=/etc/prometheus/prometheus.yml totalDuration=2.953804ms remote
|
|
Jul 12 11:01:40 lain prometheus[545]: level=info ts=2021-07-12T09:01:40.636Z caller=main.go:796 msg="Server is ready to receive web requests."
|
|
|
|
|
|
And from here we can check if prometheus is running on the correct port:
|
|
|
|

|
|
|
|
Now that prometheus is running on port 9090 we can also setup grafana but we commented it out earlier. Let's run run.sh to see if it works this time:
|
|
|
|
|
|
root@lain:/etc/prometheus# cd /srv/lainonlife/backend/
|
|
|
|
root@lain:/srv/lainonlife/backend# CONFIG=../config.json HTTP_DIR=/srv/http PORT=5000 ./run.sh
|
|
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
|
|
Requirement already satisfied: Flask>=0.12.0 in ./__venv__/lib/python2.7/site-packages (from -r requirements.txt (line 1)) (1.1.4)
|
|
|
|
[...]
|
|
|
|
Requirement already satisfied: MarkupSafe>=0.23 in ./__venv__/lib/python2.7/site-packages (from Jinja2<3.0,>=2.10.1->Flask>=0.12.0->-r requirements.txt (line 1)) (1.1.1)
|
|
* Serving Flask app 'web' (lazy loading)
|
|
* Environment: production
|
|
WARNING: This is a development server. Do not use it in a production deployment.
|
|
Use a production WSGI server instead.
|
|
* Debug mode: off
|
|
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
|
|
|
|
|
|
|
|
This time around we don't have the missing prometheus errors, so let's check if the server is running properly, and let's restart it to run on port 8002 since we told nginx we would use it for the **@script** block:
|
|
|
|
|
|
root@lain:/srv/lainonlife/backend# CONFIG=../config.json HTTP_DIR=/srv/http PORT=8002 ./run.sh
|
|
DEPRECATION: Python 2.7 reached the end of its life on January 1st, 2020. Please upgrade your Python as Python 2.7 is no longer maintained. pip 21.0 will drop support for Python 2.7 in January 2021. More details about Python 2 support in pip can be found at https://pip.pypa.io/en/latest/development/release-process/#python-2-support pip 21.0 will remove support for this functionality.
|
|
|
|
Requirement already satisfied: MarkupSafe>=0.23 in ./__venv__/lib/python2.7/site-packages (from Jinja2<3.0,>=2.10.1->Flask>=0.12.0->-r requirements.txt (line 1)) (1.1.1)
|
|
* Serving Flask app 'web' (lazy loading)
|
|
* Environment: production
|
|
WARNING: This is a development server. Do not use it in a production deployment.
|
|
Use a production WSGI server instead.
|
|
* Debug mode: off
|
|
* Running on http://127.0.0.1:8002/ (Press CTRL+C to quit)
|
|
|
|
#on debian 12 going through the bashscript doesnt seem to work, we need to run it with the python script directly:
|
|
|
|
[ 10.0.0.201/16 ] [ lain ] [/srv/lainonlife/backend]
|
|
→ CONFIG=/srv/lainonlife/config.json HTTP_DIR=/srv/http PORT=8002 python3 backend.py
|
|
* Serving Flask app 'web'
|
|
* Debug mode: off
|
|
WARNING: This is a development server. Do not use it in a production deployment. Use a production WSGI server instead.
|
|
* Running on http://127.0.0.1:8002
|
|
Press CTRL+C to quit
|
|
127.0.0.1 - - [05/Jul/2023 19:34:12] "GET /assets/css/style.css HTTP/1.0" 200 -
|
|
127.0.0.1 - - [05/Jul/2023 19:34:13] "GET /assets/img/icecast.png HTTP/1.0" 200 -
|
|
127.0.0.1 - - [05/Jul/2023 19:34:16] "GET /assets/img/icecast.png HTTP/1.0" 200 -
|
|
127.0.0.1 - - [05/Jul/2023 19:34:19] "GET /background HTTP/1.0" 200 -
|
|
127.0.0.1 - - [05/Jul/2023 19:34:20] "GET /playlist/focus.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [05/Jul/2023 19:34:32] "GET /background HTTP/1.0" 200 -
|
|
|
|
|
|
|
|
Now let's check if it works properly in the browser on port 80:
|
|
|
|

|
|
|
|
We got some progress! However we need to correct a few things, first the background:
|
|
|
|
|
|
* Serving Flask app 'web' (lazy loading)
|
|
* Environment: production
|
|
WARNING: This is a development server. Do not use it in a production deployment.
|
|
Use a production WSGI server instead.
|
|
* Debug mode: off
|
|
* Running on http://127.0.0.1:8002/ (Press CTRL+C to quit)
|
|
127.0.0.1 - - [12/Jul/2021 11:12:55] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:13:10] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:13:25] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:13:40] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:13:55] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:09] "GET /css/font-awesome.min.css HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:09] "GET /background HTTP/1.0" 404 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:09] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:24] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:39] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:53] "GET /css/font-awesome.min.css HTTP/1.0" 304 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:53] "GET /background HTTP/1.0" 404 -
|
|
127.0.0.1 - - [12/Jul/2021 11:14:53] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 11:15:08] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
|
|
|
|
|
|
Let's upload a few backgrounds into **/srv/http/backgrounds/** :
|
|
|
|
|
|
root@lain:/srv/http# cd backgrounds/
|
|
root@lain:/srv/http/backgrounds# ls -l
|
|
total 4
|
|
-rw-r--r-- 1 root root 68 Jul 12 10:18 index.html
|
|
|
|
root@lain:/srv/http/backgrounds# wget https://wallpapercave.com/wp/wp6600388.jpg
|
|
|
|
root@lain:/srv/http/backgrounds# wget https://blog.nowhere.moe/wallpapers/joi1.png
|
|
|
|
root@lain:/srv/http/backgrounds# wget https://blog.nowhere.moe/wallpapers/wallpaper_blue_original.png
|
|
|
|
|
|
|
|

|
|
|
|
Now that we got some backgrounds we also need the missing **/css/font-awesome.min.css** in the root of the webdirectory:
|
|
|
|
|
|
root@lain:/srv/lainonlife/# cd /srv/http/css/
|
|
root@lain:/srv/http/css# wget https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css
|
|
|
|
|
|
|
|
Now we get some missing icons, however this is probably related to the fact that we're not accessing our lainradio server from the correct domain name **lain.void.yt** :
|
|
|
|

|
|
|
|
Now i intend to run this lain radio behind a reverse nginx proxy, so i'll set it up from main debian node:
|
|
|
|
|
|
root@home:~# curl ifconfig.me ; echo; ping lain.void.yt
|
|
86.243.158.34
|
|
PING void.yt (86.243.158.34) 56(84) bytes of data.
|
|
|
|
|
|
|
|
First we get the DNS to point to the right IP, i used a CNAME to point at my root domain's public IP, but you can also use an A record to specify which IP the subdomain / domain name should point to. Now on my main debian node i use acme.sh to get letsencrypt TLS 1.3 certificates, so let's get them after i make the reverse proxy nginx config:
|
|
|
|
|
|
root@home:/var/www/void.yt/config# cd /etc/nginx/sites-available/
|
|
root@home:/etc/nginx/sites-available# vim lain.void.yt.conf
|
|
|
|
root@home:/etc/nginx/sites-available# cat lain.void.yt.conf
|
|
upstream lainbackend {
|
|
server 10.0.0.201:80;
|
|
}
|
|
|
|
server {
|
|
listen 80;
|
|
listen [::]:80;
|
|
server_name lain.void.yt;
|
|
return 301 https://$server_name$request_uri;
|
|
}
|
|
|
|
server {
|
|
listen 443 ssl http2;
|
|
listen [::]:443 ssl http2;
|
|
server_name lain.void.yt;
|
|
|
|
ssl_certificate /root/.acme.sh/lain.void.yt/fullchain.cer;
|
|
ssl_trusted_certificate /root/.acme.sh/lain.void.yt/lain.void.yt.cer;
|
|
ssl_certificate_key /root/.acme.sh/lain.void.yt/lain.void.yt.key;
|
|
|
|
ssl_protocols TLSv1.3 TLSv1.2;
|
|
ssl_ciphers 'TLS13-CHACHA20-POLY1305-SHA256:TLS13-AES-256-GCM-SHA384:TLS13-AES-128-GCM-SHA256:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
|
|
ssl_prefer_server_ciphers on;
|
|
ssl_session_cache shared:SSL:10m;
|
|
ssl_session_timeout 10m;
|
|
ssl_session_tickets off;
|
|
ssl_ecdh_curve auto;
|
|
ssl_stapling on;
|
|
ssl_stapling_verify on;
|
|
resolver 80.67.188.188 80.67.169.40 valid=300s;
|
|
resolver_timeout 10s;
|
|
|
|
add_header X-XSS-Protection "1; mode=block"; #Cross-site scripting
|
|
add_header X-Frame-Options "SAMEORIGIN" always; #clickjacking
|
|
add_header X-Content-Type-Options nosniff; #MIME-type sniffing
|
|
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains; preload";
|
|
|
|
location / {
|
|
proxy_pass http://lainbackend;
|
|
proxy_http_version 1.1;
|
|
proxy_set_header Upgrade $http_upgrade;
|
|
proxy_set_header Connection "Upgrade";
|
|
}
|
|
}
|
|
|
|
|
|
|
|
You can tweak it however you like it, then we enable the site and get the letsencrypt certificates:
|
|
|
|
|
|
root@home:/etc/nginx/sites-available# ln -s /etc/nginx/sites-available/lain.void.yt.conf /etc/nginx/sites-enabled/
|
|
root@home:/etc/nginx/sites-available# nginx -t
|
|
nginx: [emerg] BIO_new_file("/root/.acme.sh/lain.void.yt/fullchain.cer") failed (SSL: error:02001002:system library:fopen:No such file or directory:fopen('/root/.acme.sh/lain.void.yt/fullchain.cer','r') error:2006D080:BIO routines:BIO_new_file:no such file)
|
|
nginx: configuration file /etc/nginx/nginx.conf test failed
|
|
root@home:/etc/nginx/sites-available# systemctl stop nginx
|
|
root@home:/etc/nginx/sites-available# acme.sh --issue --standalone -d lain.void.yt -k 4096
|
|
|
|
[...]
|
|
|
|
[Mon 12 Jul 2021 12:08:38 PM CEST] Your cert is in /root/.acme.sh/lain.void.yt/lain.void.yt.cer
|
|
[Mon 12 Jul 2021 12:08:38 PM CEST] Your cert key is in /root/.acme.sh/lain.void.yt/lain.void.yt.key
|
|
[Mon 12 Jul 2021 12:08:38 PM CEST] The intermediate CA cert is in /root/.acme.sh/lain.void.yt/ca.cer
|
|
[Mon 12 Jul 2021 12:08:38 PM CEST] And the full chain certs is there: /root/.acme.sh/lain.void.yt/fullchain.cer
|
|
|
|
|
|
|
|
Once that's done we can reactivate nginx and see the result:
|
|
|
|
|
|
root@home:/etc/nginx/sites-available# nginx -t
|
|
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
|
|
nginx: configuration file /etc/nginx/nginx.conf test is successful
|
|
|
|
root@home:/etc/nginx/sites-available# systemctl start nginx
|
|
|
|
|
|
|
|

|
|
|
|
Now we access our webservice and we see that the domain has been verified by letsencrypt, but we're still missing the song names: so let's take a look into the **/srv/lainonlife/scripts/** directory:
|
|
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# ls -lash
|
|
total 24K
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 12 12:23 .
|
|
4.0K drwxr-xr-x 9 root root 4.0K Jul 12 10:05 ..
|
|
4.0K -rwxr-xr-x 1 root root 2.3K Jul 11 22:11 album_times.py
|
|
4.0K -rwxr-xr-x 1 root root 943 Jul 11 22:11 file-list.sh
|
|
8.0K -rwxr-xr-x 1 root root 4.5K Jul 11 22:11 schedule.py
|
|
|
|
|
|
|
|
Here we have some scripts we should run. An easy one is **file-list.sh** :
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# ./file-list.sh
|
|
|
|
|
|
|
|
` 
|
|
|
|
That script is there so we can get a list of files to use:
|
|
|
|

|
|
|
|
Next we need to figure out **schedule.py** :
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# pip3 install docopt
|
|
root@lain:/srv/lainonlife/scripts# python3 schedule.py --host=127.0.0.1 6601
|
|
|
|
|
|
|
|
Now if this schedule.py script errors out, that's because it's looking for the **Lainchan Radio Transitions** album, so to make this script work, we need the aforementionned album containing some songs, so let's create it with tracks we put into **/srv/radio/music/cyberia/transitions/** :
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia# mkdir transitions
|
|
root@lain:/srv/radio/music/cyberia/transitions# apt install ffmpeg
|
|
|
|
root@lain:/srv/radio/music/cyberia/transitions# youtube-dl -x https://www.youtube.com/playlist?list=OLAK5uy_kBzNHyOb4LcpwQI-uca1LApynboNkEvAo --audio-format mp3
|
|
[youtube:tab] OLAK5uy_kBzNHyOb4LcpwQI-uca1LApynboNkEvAo: Downloading webpage
|
|
[download] Downloading playlist: Coloris
|
|
[youtube:tab] playlist Coloris: Downloading 15 videos
|
|
[download] Downloading video 1 of 15
|
|
[youtube] YTY7UV6GpkM: Downloading webpage
|
|
[download] Coloris-YTY7UV6GpkM.webm has already been downloaded
|
|
[download] 100% of 2.57MiB
|
|
[ffmpeg] Destination: Coloris-YTY7UV6GpkM.mp3
|
|
|
|
[...]
|
|
|
|
|
|
[youtube] 75yOApYoc6Y: Downloading webpage
|
|
[download] Destination: Traveling By Night-75yOApYoc6Y.webm
|
|
[download] 100% of 2.59MiB in 00:00
|
|
[ffmpeg] Destination: Traveling By Night-75yOApYoc6Y.mp3
|
|
Deleting original file Traveling By Night-75yOApYoc6Y.webm (pass -k to keep)
|
|
[download] Finished downloading playlist: Coloris
|
|
|
|
|
|
|
|
Now that we have our transition tracks let's add them to the correct album via ncmpcpp:
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia/transitions# cd ..
|
|
root@lain:/srv/radio/music/cyberia# tree .
|
|
.
|
|
├── Lain's Theme - Lain-o-cwuTmqz8c.mp3
|
|
├── Serial Experiment Lain - Antidepressant 044-KaOsmUDMdaE.mp3
|
|
├── Serial Experiment Lain - Cloudy with occasional rain-1TunrW7dRr0.mp3
|
|
├── Serial Experiment Lain - Duvet (cyberia remix)-juDqDMlTfUg.mp3
|
|
├── Serial Experiment Lain - Duvet (tv version)-EnEaNaqGMqU.mp3
|
|
├── Serial Experiment Lain - Infanity world-AsPLBQfZQ04.mp3
|
|
├── Serial Experiment Lain - Invisible file-32IlMQ8Bs6w.mp3
|
|
├── Serial Experiment Lain - Island in video cassette-CCdyzUPrLpM.mp3
|
|
├── Serial Experiment Lain - k.i.d.s-TvCJnW46ISo.mp3
|
|
├── Serial Experiment Lain - Prayer-yyPMWWjzMG8.mp3
|
|
├── Serial Experiment Lain - Professed intention and real-D4G97Xsc8PA.mp3
|
|
├── Serial Experiment Lain - Psychedelic farm-XEGz6CJnY04.mp3
|
|
├── Serial Experiment Lain - Speed-zFwQFdAsGGA.mp3
|
|
├── Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.mp3
|
|
└── transitions
|
|
├── Autumn In Space-nWqcLWxZOH0.mp3
|
|
├── Circuit Lover-zduKG8YUKxM.mp3
|
|
├── Coloris-YTY7UV6GpkM.mp3
|
|
├── Destination Luna4-VGaQwDylJPM.mp3
|
|
├── Distort Into Me-_zLINqJYH0U.mp3
|
|
├── Fuse-MhHshcp5tQs.mp3
|
|
├── Gum-tTGBo0Fmf4A.mp3
|
|
├── In Time-8PmEsQY5rq4.mp3
|
|
├── Monochrome-uFNppANT-Dk.mp3
|
|
├── Orbit-SHFmUt1Jit4.mp3
|
|
├── Reality-C0ybGDNZos8.mp3
|
|
├── Together-ohViqbZZnpE.mp3
|
|
├── Tokyo Nights-5fXc8aoF2eU.mp3
|
|
├── Touch and Go-gxfyax1IPdk.mp3
|
|
└── Traveling By Night-75yOApYoc6Y.mp3
|
|
|
|
root@lain:/srv/radio/music/cyberia# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press 2 and u to update the database, and you will see the transitions directory appear:
|
|

|
|
#and in it we have our transition audio tracks:
|
|

|
|
#so let's add them to the correct playlist album:
|
|
#select the tracks with INSERT
|
|
#then press a to add them to the **Lainchan Radio Transitions** playlist:
|
|

|
|
#press 5 to go to the playlists and you should see that result:
|
|

|
|
#now add a few more albums just like we did previously
|
|
#so that schedule.py has a few albums to cycle through and to put transitions in between:
|
|
|
|
root@lain:/srv/radio/music/cyberia# youtube-dl -x --audio-format mp3 https://www.youtube.com/playlist?list=PL9AnroPjNnk0ukW3RvRQlbxA6nsNjG_9k
|
|
root@lain:/srv/radio/music/cyberia# youtube-dl -x --audio-format mp3 https://www.youtube.com/playlist?list=PLEBA2CD188C3A8278
|
|
root@lain:/srv/radio/music/cyberia# youtube-dl -x --audio-format mp3 https://www.youtube.com/playlist?list=PL4D3810FF245A180B
|
|
|
|
#Each time make sure you add them to separate albums with ncmpcpp just like we previously did to keep things clean.
|
|

|
|
|
|
|
|
|
|
So right now i have 3 albums (playlists) and a transition playlist, now let's use schedule.py:
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# ls -l
|
|
total 16
|
|
-rwxr-xr-x 1 root root 2334 Jul 11 22:11 album_times.py
|
|
-rwxr-xr-x 1 root root 943 Jul 11 22:11 file-list.sh
|
|
-rwxr-xr-x 1 root root 4631 Jul 12 12:48 schedule.py
|
|
root@lain:/srv/lainonlife/scripts# python3 schedule.py --host=127.0.0.1 6601
|
|
Traceback (most recent call last):
|
|
File "schedule.py", line 168, in <****module>
|
|
schedule_radio(client)
|
|
File "schedule.py", line 114, in schedule_radio
|
|
album, album_dur = pick_album(client, target_dur)
|
|
File "schedule.py", line 68, in pick_album
|
|
album = all_albums[0]
|
|
IndexError: list index out of range
|
|
|
|
Apologies on my part, for MPD playlists are NOT albums, so we need to create albums for each artist:
|
|
|
|
To do that we can add id3 tags:
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# apt install libid3-tools -y
|
|
|
|
#for arch users:
|
|
pacman -S id3lib id3v2
|
|
|
|
root@lain:/srv/lainonlife/scripts# which id3tag
|
|
/usr/bin/id3tag
|
|
|
|
|
|
|
|
So with id3tag we're going to add the album tags to our mp3 files:
|
|
|
|
|
|
root@lain:/srv/radio/music# vim tagger.sh
|
|
|
|
|
|
|
|
Now before running it we're going to add a tag to one track and see if it works as intended:
|
|
|
|
|
|
cd cyberia/transitions/
|
|
root@lain:/srv/radio/music/cyberia/transitions# ls -lash Coloris-YTY7UV6GpkM.mp3
|
|
2.5M -rw-r--r-- 1 root root 2.5M Sep 15 2019 Coloris-YTY7UV6GpkM.mp3
|
|
|
|
|
|
|
|
Now since this is a Transition track let's add the **Lainchan Radio Transitions** album tag to it:
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia/transitions# id3tag --album "Lainchan Radio Transitions" Coloris-YTY7UV6GpkM.mp3
|
|
+++ Album = Lainchan Radio Transitions
|
|
Tagging Coloris-YTY7UV6GpkM.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
|
|
|
|
And when we check it inside of ncmpcpp we see the following after updating the database with **u** :
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia/transitions# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press u to update the database
|
|
#press 4 to goto the Media Library
|
|
|
|
|
|
|
|

|
|
|
|
So right here we have been able to create an album thanks to the **id3tag** tool, now if you're a masochist you can go ahead and do that manually for every song, if you're like me and want to make things simpler, we can use a script. i place it into **/srv/radio/music/** to tag the transition tracks:
|
|
|
|
|
|
root@lain:/srv/radio/music# vim tagger_transitions.sh
|
|
root@lain:/srv/radio/music# cat tagger_transitions.sh
|
|
#! /bin/bash
|
|
|
|
GREEN="\033[0;32m"
|
|
ORANGE="\033[0;33m"
|
|
RED="\033[0;31m"
|
|
NC="\033[0m"
|
|
|
|
echo -en "${GREEN}[+]${NC} Type the name of the channel directory (ex: cyberia): "
|
|
read channel
|
|
echo -en "${GREEN}[+]${NC} default album name: ${GREEN} Lainchan Radio Transitions"
|
|
album="Lainchan Radio Transitions"
|
|
|
|
|
|
#### First list the songs and ask if the user wants to add the album tag to them:
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel/transitions
|
|
SONGS=*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${ORANGE}[+] $SONG${NC}"
|
|
done
|
|
cd ../..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
|
|
|
|
echo -en "\n\n${GREEN}[+]${NC} add the ${RED}$album${NC} ${ORANGE}album${NC} tag to these songs ? (y/n)"
|
|
read choice
|
|
|
|
|
|
####### If user says 'y' then add the album tag to the selected songs:
|
|
|
|
if [ "$choice" == "y" ];
|
|
then
|
|
echo 'yes'
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel/transitions
|
|
SONGS=*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${GREEN}[+] $SONG${RED} ADDING TAG: ${ORANGE}$album${NC}"
|
|
id3tag --album="\"$album\"" $SONG
|
|
done
|
|
cd ../..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
else
|
|
echo 'cancelling...'
|
|
fi
|
|
|
|
echo
|
|
exit
|
|
|
|
|
|
So for me this script works, make sure you place it in **/srv/radio/music/** otherwise it will not work as intended.
|
|
|
|
|
|
root@lain:/srv/radio/music# ./tagger_transitions.sh
|
|
[+] Type the name of the channel directory (ex: cyberia): cyberia
|
|
[+] default album name: Lainchan Radio Transitions
|
|
[+] Autumn In Space-nWqcLWxZOH0.mp3
|
|
[+] Circuit Lover-zduKG8YUKxM.mp3
|
|
[+] Coloris-YTY7UV6GpkM.mp3
|
|
[+] Destination Luna4-VGaQwDylJPM.mp3
|
|
[+] Distort Into Me-_zLINqJYH0U.mp3
|
|
[+] Fuse-MhHshcp5tQs.mp3
|
|
[+] Gum-tTGBo0Fmf4A.mp3
|
|
[+] In Time-8PmEsQY5rq4.mp3
|
|
[+] Monochrome-uFNppANT-Dk.mp3
|
|
[+] Orbit-SHFmUt1Jit4.mp3
|
|
[+] Reality-C0ybGDNZos8.mp3
|
|
[+] Together-ohViqbZZnpE.mp3
|
|
[+] Tokyo Nights-5fXc8aoF2eU.mp3
|
|
[+] Touch and Go-gxfyax1IPdk.mp3
|
|
[+] Traveling By Night-75yOApYoc6Y.mp3
|
|
|
|
[+] add the Lainchan Radio Transitions album tag to these songs ? (y/n)y
|
|
yes
|
|
|
|
[+] Autumn In Space-nWqcLWxZOH0.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Autumn In Space-nWqcLWxZOH0.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Circuit Lover-zduKG8YUKxM.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Circuit Lover-zduKG8YUKxM.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Coloris-YTY7UV6GpkM.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Coloris-YTY7UV6GpkM.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Destination Luna4-VGaQwDylJPM.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Destination Luna4-VGaQwDylJPM.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Distort Into Me-_zLINqJYH0U.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Distort Into Me-_zLINqJYH0U.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Fuse-MhHshcp5tQs.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Fuse-MhHshcp5tQs.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Gum-tTGBo0Fmf4A.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Gum-tTGBo0Fmf4A.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] In Time-8PmEsQY5rq4.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging In Time-8PmEsQY5rq4.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Monochrome-uFNppANT-Dk.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Monochrome-uFNppANT-Dk.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Orbit-SHFmUt1Jit4.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Orbit-SHFmUt1Jit4.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Reality-C0ybGDNZos8.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Reality-C0ybGDNZos8.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Together-ohViqbZZnpE.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Together-ohViqbZZnpE.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Tokyo Nights-5fXc8aoF2eU.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Tokyo Nights-5fXc8aoF2eU.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Touch and Go-gxfyax1IPdk.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Touch and Go-gxfyax1IPdk.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Traveling By Night-75yOApYoc6Y.mp3 ADDING TAG: Lainchan Radio Transitions+++ Album = "Lainchan Radio Transitions"
|
|
Tagging Traveling By Night-75yOApYoc6Y.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
|
|
|
|
Now to tag the mp3 files in **/channel/songname.mp3** with their album names i made a different script in **/srv/radio/music/tagger.sh** , again make sure the location is correct otherwise it won't work either :
|
|
|
|
|
|
root@lain:/srv/radio/music# cat tagger.sh
|
|
#! /bin/bash
|
|
|
|
GREEN="\033[0;32m"
|
|
ORANGE="\033[0;33m"
|
|
RED="\033[0;31m"
|
|
NC="\033[0m"
|
|
|
|
echo -en "${GREEN}[+]${NC} Type the name of the channel directory (ex: cyberia): "
|
|
read channel
|
|
echo -en "${GREEN}[+]${NC} Type the name of the album: "
|
|
read album
|
|
echo -en "${GREEN}[+]${NC} Type the name of the regex to match the album: "
|
|
read regex
|
|
|
|
|
|
#### First list the songs and ask if the user wants to add the album tag to them:
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel
|
|
SONGS=*$regex*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${ORANGE}[+] $SONG${NC}"
|
|
done
|
|
cd ..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
|
|
|
|
echo -en "\n\n${GREEN}[+]${NC} add the ${RED}$album${NC} ${ORANGE}album${NC} tag to these songs ? (y/n)"
|
|
read choice
|
|
|
|
|
|
####### If user says 'y' then add the album tag to the selected songs:
|
|
|
|
if [ "$choice" == "y" ];
|
|
then
|
|
echo 'yes'
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel
|
|
SONGS=*$regex*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${GREEN}[+] $SONG${RED} ADDING TAG: ${ORANGE}$album${NC}"
|
|
id3tag --album="\"$album\"" $SONG
|
|
done
|
|
cd ..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
else
|
|
echo 'cancelling....'
|
|
fi
|
|
|
|
echo
|
|
exit
|
|
|
|
|
|
|
|
This time we specify the **channel** , the **album** , and the **regex** that we will use to match the files to add the tag to:
|
|
|
|
|
|
root@lain:/srv/radio/music# ./tagger.sh
|
|
[+] Type the name of the channel directory (ex: cyberia): cyberia
|
|
[+] Type the name of the album: Pendulum - Hold your Color^C
|
|
root@lain:/srv/radio/music# ./tagger.sh
|
|
[+] Type the name of the channel directory (ex: cyberia): cyberia
|
|
[+] Type the name of the album: Infected Mushroom - Army Of Mushrooms
|
|
[+] Type the name of the regex to match the album: Infected
|
|
|
|
[+] Infected Mushroom - (01) Nevermind [HQ] 2012-Fzj7BZeqVzk.mp3
|
|
[+] Infected Mushroom - (02) Nothing to Say [HQ] 2012-fQcB8yo46eI.mp3
|
|
[+] Infected Mushroom - (03) Send Me an Angel [HQ] 2012-W2Ks5AkCHow.mp3
|
|
[+] Infected Mushroom - (04) U R So Fucked [HQ] 2012-62gm17b2bMI.mp3
|
|
[+] Infected Mushroom - (05) The Rat [HQ] 2012-nHIWgbBDx0o.mp3
|
|
[+] Infected Mushroom - (06) Nation of Wusses [HQ] 2012-L25QxK0Csg0.mp3
|
|
[+] Infected Mushroom - (07) Wanted To [HQ] 2012-2PaSS6JFvXc.mp3
|
|
[+] Infected Mushroom - (08) Serve My Thirst [HQ] 2012-_J6feIrbcEo.mp3
|
|
[+] Infected Mushroom (09) - I Shine [HQ] 2012-OtbFUedy6Xs.mp3
|
|
[+] Infected Mushroom - (10) Drum n Baasa [HQ] 2012-4IhPuiuYx30.mp3
|
|
[+] Infected Mushroom - (11) The Pretender (Foo Fighters Cover) [HQ] 2012-boKAyiI-8WQ.mp3
|
|
[+] Infected Mushroom - (12) The Messenger 2012 [HQ] 2012-x0lRqrID3i4.mp3
|
|
[+] Infected Mushroom - (13) Swingish (Bonus Track) [HQ] 2012-7KwBE6XJbj4.mp3
|
|
|
|
[+] add the Infected Mushroom - Army Of Mushrooms album tag to these songs ? (y/n)y
|
|
yes
|
|
|
|
[+] Infected Mushroom - (01) Nevermind [HQ] 2012-Fzj7BZeqVzk.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (01) Nevermind [HQ] 2012-Fzj7BZeqVzk.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (02) Nothing to Say [HQ] 2012-fQcB8yo46eI.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (02) Nothing to Say [HQ] 2012-fQcB8yo46eI.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (03) Send Me an Angel [HQ] 2012-W2Ks5AkCHow.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (03) Send Me an Angel [HQ] 2012-W2Ks5AkCHow.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (04) U R So Fucked [HQ] 2012-62gm17b2bMI.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (04) U R So Fucked [HQ] 2012-62gm17b2bMI.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (05) The Rat [HQ] 2012-nHIWgbBDx0o.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (05) The Rat [HQ] 2012-nHIWgbBDx0o.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (06) Nation of Wusses [HQ] 2012-L25QxK0Csg0.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (06) Nation of Wusses [HQ] 2012-L25QxK0Csg0.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (07) Wanted To [HQ] 2012-2PaSS6JFvXc.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (07) Wanted To [HQ] 2012-2PaSS6JFvXc.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (08) Serve My Thirst [HQ] 2012-_J6feIrbcEo.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (08) Serve My Thirst [HQ] 2012-_J6feIrbcEo.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom (09) - I Shine [HQ] 2012-OtbFUedy6Xs.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom (09) - I Shine [HQ] 2012-OtbFUedy6Xs.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (10) Drum n Baasa [HQ] 2012-4IhPuiuYx30.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (10) Drum n Baasa [HQ] 2012-4IhPuiuYx30.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (11) The Pretender (Foo Fighters Cover) [HQ] 2012-boKAyiI-8WQ.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (11) The Pretender (Foo Fighters Cover) [HQ] 2012-boKAyiI-8WQ.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (12) The Messenger 2012 [HQ] 2012-x0lRqrID3i4.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (12) The Messenger 2012 [HQ] 2012-x0lRqrID3i4.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
[+] Infected Mushroom - (13) Swingish (Bonus Track) [HQ] 2012-7KwBE6XJbj4.mp3 ADDING TAG: Infected Mushroom - Army Of Mushrooms+++ Album = "Infected Mushroom - Army Of Mushrooms"
|
|
Tagging Infected Mushroom - (13) Swingish (Bonus Track) [HQ] 2012-7KwBE6XJbj4.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
|
|
|
|
After adding the other albums we can check the result in ncmpcpp:
|
|
|
|
|
|
root@lain:/srv/radio/music# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press 2 to get to the browsing tab
|
|
#press u to update the database
|
|
#see the album tags appear:
|
|

|
|
#press 4 to get to the media library:
|
|

|
|
|
|
|
|
|
|
We also fix the missing fonts in **/srv/http/fonts/**
|
|
|
|
|
|
|
|
127.0.0.1 - - [12/Jul/2021 14:55:14] "GET /fonts/fontawesome-webfont.woff2?v=4.7.0 HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 14:55:16] "GET /fonts/fontawesome-webfont.woff?v=4.7.0 HTTP/1.0" 200 -
|
|
127.0.0.1 - - [12/Jul/2021 14:55:17] "GET /fonts/fontawesome-webfont.ttf?v=4.7.0 HTTP/1.0" 304 -
|
|
|
|
root@lain:/srv/http# mkdir fonts
|
|
root@lain:/srv/http# cd fonts
|
|
root@lain:/srv/http/fonts# wget https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.woff2
|
|
root@lain:/srv/http/fonts# wget https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/fonts/fontawesome-webfont.ttf
|
|
|
|
|
|
|
|
Now the fonts are fixed once we check them in the browser:
|
|
|
|

|
|
|
|
first edit : index.html had broken links to the radio:
|
|
|
|
|
|
|
|
root@lain:/srv/http# cat index.html | grep void
|
|
lain.void.yt
|
|
const ICECAST_STREAM_URL_BASE = "https://lain.void.yt/radio/";
|
|
<****source src="https://lain.void.yt//cyberia.ogg" type="audio/ogg"/> <****source src="https://lain.void.yt//cyberia.mp3" type="audio/mpeg"/> <****a id="ogglink" href="https://lain.void.yt//cyberia.ogg.m3u">ogg <****/a> / <****a id="mp3link" href="https://lain.void.yt//cyberia.mp3.m3u">mp3 <****/a>
|
|
|
|
root@lain:/srv/http# vim index.html
|
|
root@lain:/srv/http# cat index.html | grep void lain.void.yt
|
|
const ICECAST_STREAM_URL_BASE = "https://lain.void.yt/radio/";
|
|
<****source src="https://lain.void.yt/radio/cyberia.ogg" type="audio/ogg"/> <****source src="https://lain.void.yt/radio/cyberia.mp3" type="audio/mpeg"/> <****a id="ogglink" href="https://lain.void.yt/radio/cyberia.ogg.m3u">ogg <****/a> / <****a id="mp3link" href="https://lain.void.yt/radio/cyberia.mp3.m3u">mp3 <****/a>
|
|
|
|
Now the radio actually plays from the browser :
|
|
|
|

|
|
|
|
However the title of each track are still missing.
|
|
|
|
EDIT 2: figured out how to go around the schedule.py errors
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# cat schedule.py
|
|
#!/usr/bin/env python3
|
|
|
|
"""Radio scheduling program.
|
|
|
|
Usage:
|
|
schedule.py [--host=HOST] PORT
|
|
|
|
Options:
|
|
--host=HOST Hostname of MPD [default: localhost]
|
|
-h --help Show this text
|
|
|
|
Takes a port number, and does the following:
|
|
|
|
1. Sets the play order to normal, looping.
|
|
2. Clears all music before the cursor position in the playlist.
|
|
3. Appends a roughly three-hour block of music to the end of the playlist in this format:
|
|
a. A transition track
|
|
b. A full album
|
|
c. Enough random tracks to make up the difference.
|
|
|
|
The new segment may be a little shorter if an exact fit is not possible, but in practice it will
|
|
be close.
|
|
|
|
Why do this? Listening to entire albums in order is nice, as tracks in an album often build off
|
|
each other. On the other hand, variety is also nice!
|
|
|
|
"""
|
|
|
|
from docopt import docopt
|
|
from mpd import MPDClient
|
|
from random import shuffle
|
|
|
|
|
|
def duration_of(filterty, filterval):
|
|
"""Get the combined duration of all tracks matching a filter."""
|
|
|
|
return int(client.count(filterty, filterval).get("playtime", "0"))
|
|
|
|
|
|
def pick_transition(client):
|
|
"""Picks a transition track."""
|
|
|
|
all_transitions = list(
|
|
filter(lambda t: "directory" not in t, client.listall("transitions"))
|
|
)
|
|
|
|
shuffle(all_transitions)
|
|
|
|
transition = all_transitions[0]["file"]
|
|
transition_dur = duration_of("file", transition)
|
|
|
|
return transition, transition_dur
|
|
|
|
|
|
def pick_album(client, dur):
|
|
"""Picks a random album which fits in the duration."""
|
|
|
|
# Get all albums
|
|
all_albums = [
|
|
a["album"]
|
|
for a in client.list("album")
|
|
if "album" in a and a["album"] not in ["", "Lainchan Radio Transitions"]
|
|
]
|
|
|
|
for a in client.list("album"):
|
|
print(a)
|
|
all_albums.append(a)
|
|
|
|
print(all_albums)
|
|
shuffle(all_albums)
|
|
|
|
album = all_albums[0]
|
|
album_dur = duration_of("album", album)
|
|
return album, album_dur
|
|
|
|
|
|
def pick_tracks(client, chosen_album, dur):
|
|
"""Attempts to pick a list of tracks to fill the given time.
|
|
|
|
Radio transitions and the chosen album are excluded from the list.
|
|
|
|
Because retrieving and operating over the list of all tracks is expensive, this does not try
|
|
more than once. It uses the simple greedy algorithm, and so may exceed the limit.
|
|
"""
|
|
|
|
all_tracks = []
|
|
for t in client.list("file"):
|
|
#print(t)
|
|
all_tracks.append(t)
|
|
#print(all_tracks)
|
|
#all_tracks = [
|
|
# t["file"]
|
|
# for t in client.list("file")
|
|
# if "file" in t
|
|
#]
|
|
|
|
shuffle(all_tracks)
|
|
|
|
chosen = []
|
|
remaining = dur
|
|
for t in all_tracks:
|
|
album = client.list("album", "file", t)[0]
|
|
duration = duration_of("file", t)
|
|
if album in [chosen_album, "Lainchan Radio Transitions"]:
|
|
continue
|
|
if duration > remaining:
|
|
continue
|
|
chosen.append(t)
|
|
remaining = remaining - duration
|
|
|
|
return chosen, dur - remaining
|
|
|
|
|
|
def schedule_radio(client, target_dur= 3 * 60 * 60):
|
|
"""Schedule music.
|
|
|
|
Keyword arguments:
|
|
target_dur -- the target duration to fill.
|
|
"""
|
|
|
|
# Pick a transition and two albums
|
|
transition, transition_dur = pick_transition(client)
|
|
album, album_dur = pick_album(client, target_dur)
|
|
|
|
# Determine how much time is remaining in the two-hour slot
|
|
time_remaining = target_dur - transition_dur - album_dur
|
|
|
|
# Pick a list of tracks to fill the gap
|
|
tracks, tracks_dur = pick_tracks(client, album, time_remaining)
|
|
|
|
# Some stats first
|
|
print("Transition: {} ({}s)".format(transition, transition_dur))
|
|
print("Album: {} ({}s)".format(album, album_dur))
|
|
print("Tracks: #{} ({}s)".format(len(tracks), tracks_dur))
|
|
print()
|
|
print("Target duration: {}s".format(target_dur))
|
|
print("Actual duration: {}s".format(transition_dur + album_dur + tracks_dur))
|
|
print("Difference: {}s".format(time_remaining - tracks_dur))
|
|
|
|
# Set playback to in-order repeat
|
|
client.random(0)
|
|
client.repeat(1)
|
|
|
|
# Make sure it's playing
|
|
client.play()
|
|
|
|
# Add tracks
|
|
client.add(transition)
|
|
client.findadd("album", album)
|
|
for t in tracks:
|
|
client.add(t)
|
|
|
|
# Delete up to the current track, minus 10 tracks (for the web
|
|
# playlist)
|
|
status = client.status()
|
|
if "song" in status:
|
|
client.delete((0, max(0, int(status["song"]) - 10)))
|
|
|
|
|
|
if __name__ == "__main__":
|
|
args = docopt(__doc__)
|
|
|
|
try:
|
|
args["PORT"] = int(args["PORT"])
|
|
except ValueError:
|
|
print("PORT must be an integer")
|
|
exit(1)
|
|
|
|
try:
|
|
client = MPDClient()
|
|
client.connect(args["--host"], args["PORT"])
|
|
except Exception as e:
|
|
print(f"could not connect to MPD: {e.args[0]}")
|
|
exit(2)
|
|
|
|
client.update()
|
|
schedule_radio(client)
|
|
|
|
|
|
|
|
Editing schedule.py to fix the python errors now it can be used:
|
|
|
|
|
|
root@lain:/srv/lainonlife/scripts# python3 schedule.py --host=127.0.0.1 6601
|
|
"Cyberia"
|
|
"Infected Mushroom - Army Of Mushrooms"
|
|
"Lainchan Radio Transitions"
|
|
"Pendulum"
|
|
['"Cyberia"', '"Infected Mushroom - Army Of Mushrooms"', '"Lainchan Radio Transitions"', '"Pendulum"']
|
|
Transition: transitions/Destination Luna4-VGaQwDylJPM.mp3 (142s)
|
|
Album: "Pendulum" (8631s)
|
|
Tracks: #0 (0s)
|
|
|
|
Target duration: 1800s
|
|
Actual duration: 8773s
|
|
Difference: -6973s
|
|
|
|
|
|
|
|
Now another guess for the 'undefined' song names problem, i assume that it's the missing tag titles, so let's see if that's the case:
|
|
|
|
|
|
root@lain:/srv/radio/music/cyberia# id3tag --song "Pendulum - The Tempest" The\ Tempest\ -\ Pendulum\ \[HQ\]-uy-3tWaKyg8.mp3
|
|
+++ Song = Pendulum - The Tempest
|
|
Tagging The Tempest - Pendulum [HQ]-uy-3tWaKyg8.mp3: attempting v1 and v2, tagged v1 and v2
|
|
|
|
root@lain:/srv/radio/music/cyberia# id3tag --song "Pendulum - The Other Side" Pendulum\ \- The\ Other\ Side\ -\ Pendulum\ \[HQ\]-z0hwFJ1rbbU.mp3
|
|
+++ Song = Pendulum - The Other Side
|
|
|
|
root@lain:/srv/radio/music/cyberia# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press u to update database
|
|
|
|
|
|
|
|

|
|
|
|
Looks like we were right! What we were missing here was the song/title tags for each mp3 file. so let's make a script to automatically add all of them:
|
|
|
|
|
|
root@lain:/srv/radio/music# vim tagger_titles.sh
|
|
root@lain:/srv/radio/music# cat tagger_titles.sh
|
|
#! /bin/bash
|
|
|
|
GREEN="\033[0;32m"
|
|
ORANGE="\033[0;33m"
|
|
RED="\033[0;31m"
|
|
NC="\033[0m"
|
|
|
|
echo -en "${GREEN}[+]${NC} Type the name of the channel directory (ex: cyberia): "
|
|
read channel
|
|
|
|
#### First list the songs and ask if the user wants to add the album tag to them:
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel
|
|
SONGS=*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${ORANGE}[+] $SONG${NC}"
|
|
done
|
|
cd ..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
|
|
|
|
echo -en "\n\n${GREEN}[+]${NC} add the filename as ${ORANGE}title${NC} tag to these songs ? (y/n)"
|
|
read choice
|
|
|
|
|
|
####### If user says 'y' then add the album tag to the selected songs:
|
|
|
|
if [ "$choice" == "y" ];
|
|
then
|
|
echo 'yes'
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
cd $channel
|
|
SONGS=*
|
|
|
|
for SONG in $SONGS ;
|
|
do
|
|
echo -en "\n ${GREEN}[+] $SONG${RED} ADDING TITLE TAG: ${ORANGE}$SONG${NC}"
|
|
id3tag --song="\"$SONG\"" $SONG
|
|
done
|
|
cd ..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
else
|
|
echo 'cancelling....'
|
|
fi
|
|
|
|
echo
|
|
exit
|
|

|
|
|
|
|
|
Now that's done we update the database with ncmpcpp as usual:
|
|
|
|
|
|
root@lain:/srv/radio/music# ncmpcpp -h 127.0.0.1 -p 6601 -c ~/.config/ncmpcpp/config
|
|
#press u to update the database
|
|
|
|
|
|
|
|

|
|
|
|
And there you go! We managed to make each file's name display.
|
|
|
|
## **Automation**
|
|
|
|
So now that we know our webserver is working as intended, let's write systemd services to handle automatically **mpd** , **icecast** and the **run.sh** bashscript:
|
|
|
|
|
|
|
|
root@lain:~# icecast -c /srv/icecast-server/conf/icecast.xml
|
|
root@lain:~# CONFIG=../config.json HTTP_DIR=/srv/http PORT=8002 ./run.sh
|
|
root@lain:~# mpd ~/.config/mpd.conf
|
|
|
|
|
|
|
|
In essence we need a systemd service to make the root user run these 3 commands so let's make them one by one. First the icecast systemd service:
|
|
|
|
|
|
root@lain:/srv/radio/music# cd /etc/systemd/system/
|
|
|
|
root@lain:/etc/systemd/system# vim icecast.service
|
|
|
|
root@lain:/etc/systemd/system# cat icecast.service**[Unit]
|
|
Description=Icecast systemd service with config in /srv/icecast-server/conf/icecast.xml
|
|
After=network.target
|
|
After=systemd-user-sessions.service
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=icecast -c /srv/icecast-server/conf/icecast.xml
|
|
Restart=always
|
|
RestartSec=10
|
|
KillMode=process
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
root@lain:/etc/systemd/system# systemctl daemon-reload**
|
|
root@lain:/etc/systemd/system# systemctl enable --now icecast
|
|
Created symlink /etc/systemd/system/multi-user.target.wants/icecast.service → /etc/systemd/system/icecast.service.
|
|
root@lain:/etc/systemd/system# systemctl status icecast
|
|
● icecast.service - Icecast systemd service with config in /srv/icecast-server/conf/icecast.xml
|
|
Loaded: loaded (/etc/systemd/system/icecast.service; enabled; vendor preset: enabled)
|
|
Active: active (running) since Mon 2021-07-12 22:52:27 CEST; 5s ago
|
|
Main PID: 10092 (icecast)
|
|
Tasks: 4 (limit: 4700)
|
|
Memory: 1.0M
|
|
CGroup: /system.slice/icecast.service
|
|
└─10092 /usr/local/bin/icecast -c /srv/icecast-server/conf/icecast.xml
|
|
|
|
Jul 12 22:52:27 lain systemd[1]: Started Icecast systemd service with config in /srv/icecast-server/conf/icecast.xml.
|
|
Jul 12 22:52:27 lain icecast[10092]: [2021-07-12 22:52:27] WARN CONFIG/_parse_root Warning, <****location> not configured, using default value "Earth".
|
|
Jul 12 22:52:27 lain icecast[10092]: [2021-07-12 22:52:27] WARN CONFIG/_parse_root Warning, <****admin> contact not configured, using default value "icemaster@localhost".
|
|
|
|
We do the same for the backend script run.sh used to run the radio itself:
|
|
|
|
|
|
|
|
root@lain:/etc/systemd/system# vim lainradio.service
|
|
root@lain:/etc/systemd/system# cat lainradio.service
|
|
**[Unit]
|
|
Description=running the run.sh script with the correct arguements
|
|
After=network.target
|
|
After=systemd-user-sessions.service
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
WorkingDirectory=/srv/lainonlife/backend/
|
|
Environment="CONFIG=../config.json"
|
|
Environment="HTTP_DIR=/srv/http"
|
|
Environment="PORT=8002"
|
|
ExecStart=/srv/lainonlife/backend/backend.py
|
|
Restart=always
|
|
RestartSec=10
|
|
KillMode=process
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target**
|
|
|
|
root@lain:/etc/systemd/system# systemctl daemon-reload
|
|
root@lain:/etc/systemd/system# systemctl enable --now lainradio
|
|
root@lain:/etc/systemd/system# systemctl status lainradio
|
|
● lainradio.service - running the run.sh script with the correct arguements
|
|
Loaded: loaded (/etc/systemd/system/lainradio.service; enabled; vendor preset: enabled)
|
|
Active: active (running) since Mon 2021-07-12 23:03:15 CEST; 2min 47s ago
|
|
Main PID: 10345 (bash)
|
|
Tasks: 13 (limit: 4700)
|
|
Memory: 30.8M
|
|
CGroup: /system.slice/lainradio.service
|
|
├─10345 bash /srv/lainonlife/backend/run.sh
|
|
└─10354 python3 backend.py
|
|
|
|
Jul 12 23:04:58 lain run.sh[10345]: 127.0.0.1 - - [12/Jul/2021 23:04:58] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
Jul 12 23:04:58 lain run.sh[10345]: 127.0.0.1 - - [12/Jul/2021 23:04:58] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
Jul 12 23:05:13 lain run.sh[10345]: 127.0.0.1 - - [12/Jul/2021 23:05:13] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
Jul 12 23:05:13 lain run.sh[10345]: 127.0.0.1 - - [12/Jul/2021 23:05:13] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
Jul 12 23:05:28 lain run.sh[10345]: 127.0.0.1 - - [12/Jul/2021 23:05:28] "GET /playlist/cyberia.json HTTP/1.0" 200 -
|
|
|
|
|
|
|
|
Now that's done we're going to setup the systemd service for mpd, now i intend to make a multiple-channel setup so i will make mpd use the config file:
|
|
|
|
|
|
root@lain:/etc/systemd/system# vim mpd-cyberia.service
|
|
root@lain:/etc/systemd/system# cat mpd-cyberia.service
|
|
**[Unit]
|
|
Description=mpd systemd service with config in /root/.config/mpd/cyberia.conf
|
|
After=network.target
|
|
After=systemd-user-sessions.service
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=mpd --no-daemon /root/.config/mpd/cyberia.conf
|
|
Restart=always
|
|
RestartSec=10
|
|
KillMode=process
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target**
|
|
root@lain:/etc/systemd/system# systemctl daemon-reload
|
|
root@lain:/etc/systemd/system#
|
|
|
|
root@lain:/etc/systemd/system# cd ~/.config/mpd/
|
|
root@lain:~/.config/mpd# ls -l
|
|
total 4
|
|
-rw-r--r-- 1 root root 1773 Jul 12 09:32 mpd.conf
|
|
|
|
root@lain:~/.config/mpd# cp mpd.conf cyberia.conf
|
|
|
|
root@lain:~/.config/mpd# cd -
|
|
/etc/systemd/system
|
|
|
|
root@lain:/etc/systemd/system# systemctl disable mpd
|
|
root@lain:/etc/systemd/system# kill $(pidof mpd)
|
|
root@lain:/etc/systemd/system# kill $(pidof mpd)
|
|
root@lain:/etc/systemd/system# kill $(pidof mpd)
|
|
root@lain:/etc/systemd/system# systemctl enable --now mpd-cyberia
|
|
|
|
root@lain:/etc/systemd/system# systemctl status mpd-cyberia.service
|
|
● mpd-cyberia.service - mpd systemd service with config in /root/.config/mpd/cyberia.conf
|
|
Loaded: loaded (/etc/systemd/system/mpd-cyberia.service; enabled; vendor preset: enabled)
|
|
Active: active (running) since Mon 2021-07-12 23:20:47 CEST; 3min 13s ago
|
|
Main PID: 10921 (mpd)
|
|
Tasks: 10 (limit: 4700)
|
|
Memory: 15.7M
|
|
CGroup: /system.slice/mpd-cyberia.service
|
|
└─10921 /usr/bin/mpd --no-daemon /root/.config/mpd/cyberia.conf
|
|
|
|
Jul 12 23:20:47 lain systemd[1]: Started mpd systemd service with config in /root/.config/mpd/cyberia.conf.
|
|
Jul 12 23:20:48 lain mpd[10921]: Jul 12 23:20 : hybrid_dsd: The Hybrid DSD decoder is disabled because it was not explicitly enabled
|
|
Jul 12 23:20:48 lain mpd[10921]: Jul 12 23:20 : exception: Input plugin 'tidal' is unavailable: No Tidal application token configured
|
|
Jul 12 23:20:48 lain mpd[10921]: Jul 12 23:20 : exception: Input plugin 'qobuz' is unavailable: No Qobuz app_id configured
|
|
|
|
|
|
|
|
And that's it! We managed to create 3 independent systemd services that will run everytime the host boots up, ensuring that the radio stays up and running from the start automatically. Now that should already be done but make sure that nginx and prometheus' systemd services are enabled too:
|
|
|
|
|
|
root@lain:/etc/systemd/system# systemctl enable --now nginx
|
|
root@lain:/etc/systemd/system# systemctl enable --now prometheus
|
|
|
|
|
|
|
|
## **Multi-Channel + Album Ordering Setup**
|
|
|
|
Before adding channels let's get a more organized music folder architecture:
|
|
|
|

|
|
|
|
Basically, for each channel, we're going to have a folder for each album, and inside of each album folder we're going to have our song files. And also let's not forget that we have our transition files in the **transitions** folder, we want to tag them correctly with **Lainchan Radio Transitions** special album name. So from here we proceed:
|
|
|
|

|
|
|
|
First i move all of my songs into folders:
|
|
|
|
|
|
mkdir "Serial Experiments Lain OST"
|
|
mkdir "Infected Mushroom - Army of Mushrooms"
|
|
mkdir "Pendulum - In Silico"
|
|
|
|
mv Infec* Infected\ Mushroom\ -\ Army\ of\ Mushrooms/
|
|
mv Serial* Serial\ Experiments\ Lain\ OST/
|
|
mv *Pendulum* Pendulum\ -\ In\ Silico/
|
|
mv *pendulum* Pendulum\ -\ In\ Silico/
|
|
mv Lain\'s\ Theme\ -\ Lain-o-cwuTmqz8c.mp3 Serial\ Experiments\ Lain\ OST/
|
|
|
|
root@lain:/srv/radio/music/cyberia# ls -lash
|
|
total 24K
|
|
4.0K drwxr-xr-x 6 root root 4.0K Jul 13 09:48 .
|
|
4.0K drwxr-xr-x 3 root root 4.0K Jul 13 09:44 ..
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 13 09:47 'Infected Mushroom - Army of Mushrooms'
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 13 09:48 'Pendulum - In Silico'
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 13 09:48 'Serial Experiments Lain OST'
|
|
4.0K drwxr-xr-x 2 root root 4.0K Jul 13 09:11 transitions
|
|
|
|
root@lain:/srv/radio/music/cyberia# tree .
|
|
.
|
|
├── Infected Mushroom - Army of Mushrooms
|
|
│ ├── Infected Mushroom - (01) Nevermind [HQ] 2012-Fzj7BZeqVzk.mp3
|
|
│ ├── Infected Mushroom - (02) Nothing to Say [HQ] 2012-fQcB8yo46eI.mp3
|
|
│ ├── Infected Mushroom - (03) Send Me an Angel [HQ] 2012-W2Ks5AkCHow.mp3
|
|
│ ├── Infected Mushroom - (04) U R So Fucked [HQ] 2012-62gm17b2bMI.mp3
|
|
│ ├── Infected Mushroom - (05) The Rat [HQ] 2012-nHIWgbBDx0o.mp3
|
|
│ ├── Infected Mushroom - (06) Nation of Wusses [HQ] 2012-L25QxK0Csg0.mp3
|
|
│ ├── Infected Mushroom - (07) Wanted To [HQ] 2012-2PaSS6JFvXc.mp3
|
|
│ ├── Infected Mushroom - (08) Serve My Thirst [HQ] 2012-_J6feIrbcEo.mp3
|
|
│ ├── Infected Mushroom (09) - I Shine [HQ] 2012-OtbFUedy6Xs.mp3
|
|
│ ├── Infected Mushroom - (10) Drum n Baasa [HQ] 2012-4IhPuiuYx30.mp3
|
|
│ ├── Infected Mushroom - (11) The Pretender (Foo Fighters Cover) [HQ] 2012-boKAyiI-8WQ.mp3
|
|
│ ├── Infected Mushroom - (12) The Messenger 2012 [HQ] 2012-x0lRqrID3i4.mp3
|
|
│ └── Infected Mushroom - (13) Swingish (Bonus Track) [HQ] 2012-7KwBE6XJbj4.mp3
|
|
├── Pendulum - In Silico
|
|
│ ├── 9,000 Miles - Pendulum [HQ]-9AudFoAMTik.mp3
|
|
│ ├── Different - Pendulum [HQ]-3JUwQglYFig.mp3
|
|
│ ├── Granite - Pendulum [HQ]-h17WaF6alVY.mp3
|
|
│ ├── Midnight Runner - Pendulum [HQ]-oSbop6jmBS4.mp3
|
|
│ ├── Mutiny - Pendulum [HQ]-ucchDCKCTTs.mp3
|
|
│ ├── pendulum axle grinder-UiGJbBlsrqE.mp3
|
|
│ ├── pendulum out here-SM3fWfBgyJk.mp3
|
|
│ ├── pendulum-prelude-PYUHFPqI3Rw.mp3
|
|
│ ├── Propane Nightmares - Pendulum [HQ]-SBohx23x0jw.mp3
|
|
│ ├── Showdown - Pendulum [HQ]-mszCJSB02_8.mp3
|
|
│ ├── The Other Side - Pendulum [HQ]-z0hwFJ1rbbU.mp3
|
|
│ ├── The Tempest - Pendulum [HQ]-uy-3tWaKyg8.mp3
|
|
│ └── Visions - Pendulum [HQ]-HXSfB-zQUAg.mp3
|
|
├── Serial Experiments Lain OST
|
|
│ ├── Lain's Theme - Lain-o-cwuTmqz8c.mp3
|
|
│ ├── Serial Experiment Lain - Antidepressant 044-KaOsmUDMdaE.mp3
|
|
│ ├── Serial Experiment Lain - Cloudy with occasional rain-1TunrW7dRr0.mp3
|
|
│ ├── Serial Experiment Lain - Duvet (cyberia remix)-juDqDMlTfUg.mp3
|
|
│ ├── Serial Experiment Lain - Duvet (tv version)-EnEaNaqGMqU.mp3
|
|
│ ├── Serial Experiment Lain - Infanity world-AsPLBQfZQ04.mp3
|
|
│ ├── Serial Experiment Lain - Invisible file-32IlMQ8Bs6w.mp3
|
|
│ ├── Serial Experiment Lain - Island in video cassette-CCdyzUPrLpM.mp3
|
|
│ ├── Serial Experiment Lain - k.i.d.s-TvCJnW46ISo.mp3
|
|
│ ├── Serial Experiment Lain - Prayer-yyPMWWjzMG8.mp3
|
|
│ ├── Serial Experiment Lain - Professed intention and real-D4G97Xsc8PA.mp3
|
|
│ ├── Serial Experiment Lain - Psychedelic farm-XEGz6CJnY04.mp3
|
|
│ ├── Serial Experiment Lain - Speed-zFwQFdAsGGA.mp3
|
|
│ └── Serial Experiments Lain - Cyberia Theme-5dbi4N6NGn4.mp3
|
|
└── transitions
|
|
├── Autumn
|
|
├── Autumn In Space-nWqcLWxZOH0.mp3
|
|
├── Circuit
|
|
├── Circuit Lover-zduKG8YUKxM.mp3
|
|
├── Coloris-YTY7UV6GpkM.mp3
|
|
├── Destination
|
|
├── Destination Luna4-VGaQwDylJPM.mp3
|
|
├── Distort
|
|
├── Distort Into Me-_zLINqJYH0U.mp3
|
|
├── Fuse-MhHshcp5tQs.mp3
|
|
├── Gum-tTGBo0Fmf4A.mp3
|
|
├── In
|
|
├── In Time-8PmEsQY5rq4.mp3
|
|
├── Monochrome-uFNppANT-Dk.mp3
|
|
├── Orbit-SHFmUt1Jit4.mp3
|
|
├── Reality-C0ybGDNZos8.mp3
|
|
├── Together-ohViqbZZnpE.mp3
|
|
├── Tokyo
|
|
├── Tokyo Nights-5fXc8aoF2eU.mp3
|
|
├── Touch
|
|
├── Touch and Go-gxfyax1IPdk.mp3
|
|
├── Traveling
|
|
└── Traveling By Night-75yOApYoc6Y.mp3
|
|
|
|
|
|
|
|
And now that's done we're going to change our tagger script as follows:
|
|
|
|
|
|
root@lain:/srv/radio/music# vim tagger.sh
|
|
root@lain:/srv/radio/music# cat tagger.sh
|
|
#! /bin/bash
|
|
|
|
GREEN="\033[0;32m"
|
|
ORANGE="\033[0;33m"
|
|
RED="\033[0;31m"
|
|
NC="\033[0m"
|
|
|
|
echo -en "${GREEN}[+]${NC} Type the name of the channel directory (ex: cyberia): "
|
|
read channel
|
|
|
|
|
|
#### First list the songs and ask if the user wants to add the album tag to them:
|
|
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
|
|
ALBUMS="*"
|
|
cd $channel
|
|
for ALBUM in $ALBUMS ;
|
|
do
|
|
echo -en "\n ${ORANGE}[+] $ALBUM${NC}"
|
|
cd $ALBUM
|
|
SONGS="*"
|
|
for SONG in $SONGS;
|
|
do
|
|
echo -en "\n ${GREEN} [+] $SONG${NC}"
|
|
done
|
|
cd ..
|
|
done
|
|
cd ..
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
|
|
echo -en "\n\n${GREEN}[+]${NC} add the ${RED}$album${NC} ${ORANGE}album${NC} tag to these ${GREEN}songs ${NC}? (y/n)"
|
|
read choice
|
|
|
|
|
|
|
|
|
|
|
|
|
|
####### If user says 'y' then add the album tag to the selected songs:
|
|
if [ "$choice" == "y" ];
|
|
then
|
|
echo 'yes'
|
|
#change IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
|
|
ALBUMS="*"
|
|
cd $channel
|
|
for ALBUM in $ALBUMS ;
|
|
do
|
|
echo -en "\n ${ORANGE}[+] $ALBUM${NC}"
|
|
cd $ALBUM
|
|
SONGS="*"
|
|
for SONG in $SONGS;
|
|
do
|
|
echo -en "\n ${GREEN} [+] $SONG${NC}"
|
|
if [ $ALBUM == "transitions" ];
|
|
then
|
|
id3tag --album="Lainchan Radio Transitions" $SONG
|
|
id3tag --song="\"$SONG\"" $SONG
|
|
else
|
|
id3tag --album="\"$ALBUM\"" $SONG
|
|
id3tag --song="\"$SONG\"" $SONG
|
|
|
|
fi
|
|
done
|
|
cd ..
|
|
done
|
|
cd ..
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
else
|
|
echo 'cancelling....'
|
|
fi
|
|
|
|
|
|
echo
|
|
exit
|
|
|
|
|
|
|
|

|
|
|
|
Basically, this script goes into the **channel/** directory, then goes into each **album/** directory, and then will add the tags as follows: the **filename.mp3** becomes the song's id3tag, and the song's **album/** directory becomes the song's album id3tag. Which fits how we want our service to function. Once that's done we simply run the **schedule.py** script to schedule our songs once again after updating the database:
|
|
|
|
|
|
root@lain:/srv/radio/music# ./tagger.sh
|
|
|
|
root@lain:/srv/radio/music# ncmpcpp -h 127.0.0.1 -p 6601
|
|
#press u to update database
|
|
#press q to quit
|
|
|
|
root@lain:/srv/radio/music# python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6601
|
|
"Infected Mushroom - Army of Mushrooms"
|
|
"Pendulum - In Silico"
|
|
"Serial Experiments Lain OST"
|
|
Lainchan Radio Transitions
|
|
['"Infected Mushroom - Army of Mushrooms"', '"Pendulum - In Silico"', '"Serial Experiments Lain OST"', 'Lainchan Radio Transitions']
|
|
Transition: transitions/In Time-8PmEsQY5rq4.mp3 (129s)
|
|
Album: "Serial Experiments Lain OST" (4057s)
|
|
Tracks: #18 (6581s)
|
|
|
|
Target duration: 10800s
|
|
Actual duration: 10767s
|
|
Difference: 33s
|
|
|
|
|
|
|
|
Now another thing we can do is run the schedule.py script automatically every 3 hours so that our songs are continuously being updated, we can do that with a cronjob:
|
|
|
|
|
|
root@lain:/srv/radio/music# crontab -e
|
|
no crontab for root - using an empty one
|
|
|
|
Select an editor. To change later, run 'select-editor'.
|
|
1. /bin/nano ---- easiest
|
|
2. /usr/bin/vim.basic
|
|
3. /usr/bin/vim.tiny
|
|
|
|
Choose 1-3 [1]: 2
|
|
|
|
|
|
# m h dom mon dow command
|
|
0 */3 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6601
|
|
|
|
:wq
|
|
|
|
|
|
|
|
Now in order to test our cronjob we can use cronitor:
|
|
|
|
|
|
|
|
|
|
[ lain ] [ /dev/pts/1 ] [~]
|
|
→ wget https://github.com/cronitorio/cronitor-cli/releases/download/28.8/linux_amd64.tar.gz
|
|
|
|
|
|
[ lain ] [ /dev/pts/1 ] [~]
|
|
→ sudo tar xvf linux_amd64.tar.gz -C /usr/bin/
|
|
cronitor
|
|
|
|
[ lain ] [ /dev/pts/1 ] [~]
|
|
→ sudo cronitor configure --api-key 1234567890
|
|
|
|
Configuration File:
|
|
/etc/cronitor/cronitor.json
|
|
|
|
Version:
|
|
28.8
|
|
|
|
API Key:
|
|
1234567890
|
|
|
|
Ping API Key:
|
|
Not Set
|
|
|
|
Environment:
|
|
Not Set
|
|
|
|
Hostname:
|
|
lain
|
|
|
|
Timezone Location:
|
|
{Europe/Paris}
|
|
|
|
Debug Log:
|
|
Off
|
|
|
|
root@lain:/srv/radio/music# cronitor list
|
|
|
|
----► Checking user "root" crontab
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
| SCHEDULE | COMMAND |
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
| 0 */3 * * * | python3 |
|
|
| | /srv/lainonlife/scripts/schedule.py |
|
|
| | --host=127.0.0.1 6601 |
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
|
|
----► Checking /etc/crontab
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
| SCHEDULE | COMMAND |
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
| 17 * * * * | cd / && run-parts --report |
|
|
| | /etc/cron.hourly |
|
|
| 25 6 * * * | test -x /usr/sbin/anacron || |
|
|
| | ( cd / && run-parts --report |
|
|
| | /etc/cron.daily ) |
|
|
| 47 6 * * 7 | test -x /usr/sbin/anacron || |
|
|
| | ( cd / && run-parts --report |
|
|
| | /etc/cron.weekly ) |
|
|
| 52 6 1 * * | test -x /usr/sbin/anacron || |
|
|
| | ( cd / && run-parts --report |
|
|
| | /etc/cron.monthly ) |
|
|
+-------------------+------------------------------------------------------------------------------------------------------+
|
|
|
|
|
|
|
|
|
|
Now to test the cronjob we run **cronitor select**
|
|
|
|
|
|
root@lain:/srv/radio/music# cronitor select
|
|
|
|
✔ python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6601
|
|
----► Running command: python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6601
|
|
|
|
"Infected Mushroom - Army of Mushrooms"
|
|
"Pendulum - In Silico"
|
|
"Serial Experiments Lain OST"
|
|
Lainchan Radio Transitions
|
|
['"Infected Mushroom - Army of Mushrooms"', '"Pendulum - In Silico"', '"Serial Experiments Lain OST"', 'Lainchan Radio Transitions']
|
|
Transition: transitions/Together-ohViqbZZnpE.mp3 (144s)
|
|
Album: "Serial Experiments Lain OST" (4057s)
|
|
Tracks: #19 (6506s)
|
|
|
|
Target duration: 10800s
|
|
Actual duration: 10707s
|
|
Difference: 93s
|
|
|
|
----► ✔ Command successful Elapsed time 0.223s
|
|
|
|
root@lain:/srv/radio/music#
|
|
|
|
|
|
|
|
And here we see that we have been able to successfully run the script through our cronjob, and the way we set it up makes it so schedule.py is being ran every 3 hours, that way it matches the 3 hours of audio it tries to queue. Now let's add another channel. To do that we need 3 things, a **channel** directory in **/srv/radio/music/** , another **mpd** service running on another port (i'll do ports 6601, 6602, 6603, 6604, etc) and to edit the website configuration **config.json** to let the clients choose which channel they want to listen to:
|
|
|
|
|
|
root@lain:/srv/radio/music# mkdir metal
|
|
root@lain:/srv/radio/music# cd metal
|
|
root@lain:/srv/radio/music/metal# mkdir "Rivers of Nihil - Where Owls Know My Name"
|
|
root@lain:/srv/radio/music/metal# mkdir "Behemoth - The Satanist"
|
|
root@lain:/srv/radio/music/metal# mkdir "Carnifex - Slow Death"
|
|
root@lain:/srv/radio/music/metal# mkdir "Rivers of Nihil - Monarchy"
|
|
root@lain:/srv/radio/music/metal# cd Rivers\ of\ Nihil\ -\ Where\ Owls\ Know\ My\ Name/
|
|
root@lain:/srv/radio/music/metal/Rivers of Nihil - Where Owls Know My Name#
|
|
root@lain:/srv/radio/music/metal/Rivers of Nihil - Where Owls Know My Name# youtube-dl https://www.youtube.com/playlist?list=PLEouLkiLHdSDIqsVoq7a9bJDifla6XNq9 -x --audio-format mp3
|
|
[youtube:tab] PLEouLkiLHdSDIqsVoq7a9bJDifla6XNq9: Downloading webpage
|
|
[download] Downloading playlist: Rivers Of Nihil - Where Owls Know My Name
|
|
[youtube:tab] playlist Rivers Of Nihil - Where Owls Know My Name: Downloading 10 videos
|
|
|
|
|
|
|
|
Now like this you can fill in each of your album folders just like we did for the cyberia channel, don't forget the transitions either:
|
|
|
|
|
|
root@lain:/srv/radio/music/metal# mkdir transitions
|
|
root@lain:/srv/radio/music/metal# youtube-dl LINK -x --audio-format mp3
|
|
|
|
|
|
|
|
once you filled up the channel directory with album directories, run the tagger:
|
|
|
|
|
|
root@lain:/srv/radio/music# ls -l metal/
|
|
total 40
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:34 'Behemoth - I Loved You At Your Darkest'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:11 'Behemoth - The Satanist'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:09 'Carnifex - Slow Death'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:22 'Meshuggah - Obzen'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:24 'Meshuggah - The Violent Sleep of Reason'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:07 'Rivers of Nihil - Monarchy'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:06 'Rivers of Nihil - Where Owls Know My Name'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:27 'The Black Dahlia Murder - Abysmal'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:26 'The Black Dahlia Murder - Deflorate'
|
|
drwxr-xr-x 2 root root 4096 Jul 13 11:20 transitions
|
|
root@lain:/srv/radio/music# ./tagger.sh
|
|
|
|
|
|
|
|
 
|
|
|
|
Once that's done we're going to make another mpd config for our second channel, my second channel's mpd config will be in **/root/.config/mpd/metal.conf** :
|
|
|
|
|
|
root@lain:~/.config/mpd# cat metal.conf
|
|
music_directory "/srv/radio/music/metal"
|
|
playlist_directory "/srv/radio/data/metal/playlists"
|
|
db_file "/srv/radio/data/metal/db"
|
|
state_file "/srv/radio/data/metal/state"
|
|
sticker_file "/srv/radio/data/metal/sticker.sql"
|
|
log_file "/srv/radio/data/syslog.metal"
|
|
bind_to_address "127.0.0.1"
|
|
#bind_to_address "10.0.0.201"
|
|
port "6602"
|
|
|
|
audio_output {
|
|
name "[mpd] metal (ogg)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "vorbis"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-metal.ogg"
|
|
user "source"
|
|
password "P@SSWORD"
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
|
|
audio_output {
|
|
name "[mpd] metal (mp3)"
|
|
description "classic lainchan radio: electronic, chiptune, weeb"
|
|
type "shout"
|
|
encoder "lame"
|
|
host "localhost"
|
|
port "8000"
|
|
mount "/mpd-metal.mp3"
|
|
user "source"
|
|
password "P@SSW0RD"
|
|
quality "3"
|
|
format "44100:16:2"
|
|
always_on "yes"
|
|
}
|
|
|
|
audio_output {
|
|
type "null"
|
|
name "null"
|
|
}
|
|
|
|
audio_output {
|
|
type "alsa"
|
|
name "alsa audio"
|
|
mixer_type "software"
|
|
}
|
|
|
|
audio_output {
|
|
type "fifo"
|
|
name "my_fifo2"
|
|
path "/tmp/mpd.fifo2"
|
|
format "44100:16:2"
|
|
}
|
|
|
|
|
|
I also create the directories it requires for the playlists and database:
|
|
|
|
|
|
root@lain:~/.config/mpd# mkdir -p /srv/radio/data/metal/playlists/
|
|
root@lain:~/.config/mpd# cd /srv/radio/data/
|
|
root@lain:/srv/radio/data# tree .
|
|
.
|
|
├── cyberia
|
|
│ ├── db
|
|
│ ├── playlists
|
|
│ │ ├── cyberia.m3u
|
|
│ │ ├── Infected Mushroom - Army of Mushrooms.m3u
|
|
│ │ ├── Lainchan Radio Transitions.m3u
|
|
│ │ └── pendulum.m3u
|
|
│ ├── state
|
|
│ └── sticker.sql
|
|
├── metal
|
|
│ └── playlists
|
|
└── syslog
|
|
|
|
4 directories, 8 files
|
|
|
|
|
|
|
|
Now since we already made a systemd service to run the cyberia mpd process, let's make another one for the second channel:
|
|
|
|
|
|
root@lain:/srv/radio/data# cd /etc/systemd/system/
|
|
root@lain:/etc/systemd/system# ls -l | grep mpd
|
|
-rw-r--r-- 1 root root 334 Jul 12 23:19 mpd-cyberia.service
|
|
root@lain:/etc/systemd/system# cp mpd-cyberia.service mpd-metal.service
|
|
|
|
root@lain:/etc/systemd/system# vim mpd-metal.service
|
|
root@lain:/etc/systemd/system# cat mpd-metal.service
|
|
[Unit]
|
|
Description=mpd systemd service with config in /root/.config/mpd/metal.conf
|
|
After=network.target
|
|
After=systemd-user-sessions.service
|
|
After=network-online.target
|
|
|
|
[Service]
|
|
Type=simple
|
|
ExecStart=mpd --no-daemon /root/.config/mpd/metal.conf
|
|
Restart=always
|
|
RestartSec=10
|
|
KillMode=process
|
|
|
|
[Install]
|
|
WantedBy=multi-user.target
|
|
root@lain:/etc/systemd/system# systemctl daemon-reload
|
|
root@lain:/etc/systemd/system# systemctl enable --now mpd-metal
|
|
Created symlink /etc/systemd/system/multi-user.target.wants/mpd-metal.service → /etc/systemd/system/mpd-metal.service.
|
|
|
|
|
|
|
|
Now once that's done we can connect to it on port 6602:
|
|
|
|
|
|
root@lain:/srv/radio/data# ncmpcpp -h 127.0.0.1 -p 6602
|
|
#press u to update database
|
|
#press 7 to go to the outputs
|
|
#press enter to activate the metal ogg and mp3 outputs
|
|
#press 4 to check the album tags
|
|

|
|
#press q to exit
|
|
|
|
root@lain:/srv/radio/data# python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6602
|
|
"Behemoth - I Loved You At Your Darkest"
|
|
"Behemoth - The Satanist"
|
|
"Carnifex - Slow Death"
|
|
"Meshuggah - Obzen"
|
|
"Meshuggah - The Violent Sleep of Reason"
|
|
"Rivers of Nihil - Monarchy"
|
|
"Rivers of Nihil - Where Owls Know My Name"
|
|
"The Black Dahlia Murder - Abysmal"
|
|
"The Black Dahlia Murder - Deflorate"
|
|
Lainchan Radio Transitions
|
|
['"Behemoth - I Loved You At Your Darkest"', '"Behemoth - The Satanist"', '"Carnifex - Slow Death"', '"Meshuggah - Obzen"', '"Meshuggah - The Violent Sleep of Reason"', '"Rivers of Nihil - Monarchy"', '"Rivers of Nihil - Where Owls Know My Name"', '"The Black Dahlia Murder - Abysmal"', '"The Black Dahlia Murder - Deflorate"', 'Lainchan Radio Transitions']
|
|
Transition: transitions/Buckethead - Asylum Of Glass (Song Only)-AgzzsbPj_1w.mp3 (278s)
|
|
Album: "Behemoth - The Satanist" (2671s)
|
|
Tracks: #29 (7762s)
|
|
|
|
Target duration: 10800s
|
|
Actual duration: 10711s
|
|
Difference: 89s
|
|
|
|
root@lain:/srv/radio/data# ncmpcpp -h 127.0.0.1 -p 6602
|
|
#press enter to start playing the tracks
|
|
#press q to exit
|
|
|
|
|
|
|
|
Now that's done let's add another cronjob to make sure the tracks are constantly added every 3 hours for our second channel:
|
|
|
|
|
|
root@lain:/srv/radio/data# crontab -e
|
|
|
|
# m h dom mon dow command
|
|
0 */3 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6601
|
|
0 */3 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6602
|
|
|
|
:wq
|
|
|
|
root@lain:/srv/radio/data# cronitor select
|
|
|
|
✔ python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6602
|
|
----► Running command: python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6602
|
|
|
|
"Behemoth - I Loved You At Your Darkest"
|
|
"Behemoth - The Satanist"
|
|
"Carnifex - Slow Death"
|
|
"Meshuggah - Obzen"
|
|
"Meshuggah - The Violent Sleep of Reason"
|
|
"Rivers of Nihil - Monarchy"
|
|
"Rivers of Nihil - Where Owls Know My Name"
|
|
"The Black Dahlia Murder - Abysmal"
|
|
"The Black Dahlia Murder - Deflorate"
|
|
Lainchan Radio Transitions
|
|
['"Behemoth - I Loved You At Your Darkest"', '"Behemoth - The Satanist"', '"Carnifex - Slow Death"', '"Meshuggah - Obzen"', '"Meshuggah - The Violent Sleep of Reason"', '"Rivers of Nihil - Monarchy"', '"Rivers of Nihil - Where Owls Know My Name"', '"The Black Dahlia Murder - Abysmal"', '"The Black Dahlia Murder - Deflorate"', 'Lainchan Radio Transitions']
|
|
Transition: transitions/Buckethead - I love my parents-BwXlzy9k7jI.mp3 (253s)
|
|
Album: "The Black Dahlia Murder - Deflorate" (2041s)
|
|
Tracks: #27 (8418s)
|
|
|
|
Target duration: 10800s
|
|
Actual duration: 10712s
|
|
Difference: 88s
|
|
|
|
----► ✔ Command successful Elapsed time 0.291s
|
|
|
|
|
|
|
|
Now that we finished our cronitor job for our second channel, we need to edit icecast.xml:
|
|
|
|
|
|
root@lain:/srv/radio/data# vim /srv/icecast-server/conf/icecast.xml
|
|

|
|
|
|
|
|
|
|
Once we add the following block we restart our icecast service:
|
|
|
|
|
|
root@lain:/srv/radio/data# systemctl restart icecast
|
|
root@lain:/srv/radio/data# systemctl status icecast
|
|
● icecast.service - Icecast systemd service with config in /srv/icecast-server/conf/icecast.xml
|
|
Loaded: loaded (/etc/systemd/system/icecast.service; enabled; vendor preset: enabled)
|
|
Active: active (running) since Tue 2021-07-13 12:06:07 CEST; 1s ago
|
|
Main PID: 5283 (icecast)
|
|
Tasks: 4 (limit: 4915)
|
|
Memory: 1.2M
|
|
CGroup: /system.slice/icecast.service
|
|
└─5283 /usr/local/bin/icecast -c /srv/icecast-server/conf/icecast.xml
|
|
|
|
Jul 13 12:06:07 lain systemd[1]: Started Icecast systemd service with config in /srv/icecast-server/conf/icecast.xml.
|
|
Jul 13 12:06:07 lain icecast[5283]: [2021-07-13 12:06:07] WARN CONFIG/_parse_root Warning, location> not configured, using default value "Earth".
|
|
Jul 13 12:06:07 lain icecast[5283]: [2021-07-13 12:06:07] WARN CONFIG/_parse_root Warning, admin> contact not configured, using default value "icemaster@localhost". This breaks YP
|
|
root@lain:/srv/radio/data#
|
|
|
|
|
|
|
|
Now if you do this you will probably see that icecast doesnt detect the mountpoints anymore, to fix that restart the mpd channels:
|
|
|
|
|
|
root@lain:/srv/radio/data# systemctl restart mpd-cyberia
|
|
root@lain:/srv/radio/data# systemctl restart mpd-metal
|
|
|
|
|
|
|
|
You can verify if it's working at **localip:8000/admin/listmounts.xsl**
|
|
|
|

|
|
|
|
Now we need to change config.json to include our second channel:
|
|
|
|
|
|
root@lain:/srv/lainonlife# ls -l
|
|
total 36
|
|
drwxr-xr-x 4 root root 4096 Jul 12 18:49 backend
|
|
drwxr-xr-x 2 root root 4096 Jul 12 16:34 concourse
|
|
-rw-r--r-- 1 root root 366 Jul 12 10:05 config.json
|
|
-rw-r--r-- 1 root root 695 Jul 11 22:11 config.json.example
|
|
drwxr-xr-x 2 root root 4096 Jul 11 23:32 examples
|
|
drwxr-xr-x 10 root root 4096 Jul 12 10:16 frontend
|
|
-rw-r--r-- 1 root root 1082 Jul 11 22:11 LICENSE
|
|
-rw-r--r-- 1 root root 2344 Jul 11 22:11 README.md
|
|
drwxr-xr-x 2 root root 4096 Jul 13 08:48 scripts
|
|
|
|
root@lain:/srv/lainonlife# vim config.json
|
|
root@lain:/srv/lainonlife# cat config.json
|
|
|
|
|
|
{ "channels":
|
|
{ "cyberia": { "mpd_host": "localhost", "mpd_port": 6601, "description": "classic lainchan radio: electronic, chiptune, weeb" }
|
|
, "metal": { "mpd_host": "localhost", "mpd_port": 6602, "description": "Death Metal, Deathcore, Black Metal" }}
|
|
|
|
, "template":
|
|
{ "default_channel": "cyberia"
|
|
, "icecast_status_url": "/radio/status-json.xsl"
|
|
, "icecast_stream_url_base": "https://lain.void.yt/radio/"
|
|
, "server_cost": 10.00
|
|
, "currency_symbol": "€"
|
|
}
|
|
}
|
|
|
|
|
|
Now since we modified the config file let's restart the lainradio service:
|
|
|
|
|
|
root@lain:/srv/lainonlife# systemctl restart lainradio.service
|
|
|
|
[ lain ] [ /dev/pts/0 ] [~]
|
|
→ vim /srv/lainonlife/scripts/restart-radio.sh
|
|
|
|
[ lain ] [ /dev/pts/0 ] [~]
|
|
→ cat /srv/lainonlife/scripts/restart-radio.sh
|
|
#!/bin/bash
|
|
|
|
GREEN="\033[0;32m"
|
|
ORANGE="\033[0;33m"
|
|
RED="\033[0;31m"
|
|
NC="\033[0m"
|
|
|
|
echo -en "${GREEN}[+]${NC} Stopping Lainradio and Icecast... \n"
|
|
systemctl stop lainradio
|
|
systemctl stop icecast
|
|
|
|
echo -en "${GREEN}[+]${NC} Shutting down Lainradio backend ... \n"
|
|
kill $(pidof python3 backend.py)
|
|
|
|
echo -en "${GREEN}[+]${NC} Restarting Lainradio and Icecast ... \n"
|
|
systemctl enable --now lainradio
|
|
systemctl enable --now icecast
|
|
|
|
echo -en "${GREEN}[+]${NC} Waiting 5 seconds for icecast... \n"
|
|
sleep 5
|
|
|
|
echo -en "${GREEN}[+]${NC} Restarting the existing MPD channels and nginx... \n"
|
|
systemctl restart nginx
|
|
|
|
|
|
|
|
#save IFS
|
|
SAVEIFS=$IFS
|
|
IFS=$(echo -en "\n\b")
|
|
|
|
|
|
CHANNELS="mpd*.service"
|
|
|
|
cd /etc/systemd/system/
|
|
for CHANNEL in $CHANNELS ;
|
|
do
|
|
echo -en "${ORANGE}[+]${NC} Restarting $CHANNEL ... \n"
|
|
systemctl restart $CHANNEL
|
|
done
|
|
cd -
|
|
|
|
#restore IFS
|
|
IFS=$SAVEIFS
|
|
|
|
|
|
[ lain ] [ /dev/pts/0 ] [~]
|
|
→ cronitor select
|
|
|
|
✔ /srv/lainonlife/scripts/restart-radio.sh
|
|
----► Running command: /srv/lainonlife/scripts/restart-radio.sh
|
|
|
|
[+] Stopping Lainradio and Icecast...
|
|
[+] Shutting down Lainradio backend ...
|
|
kill: usage: kill [-s sigspec | -n signum | -sigspec] pid | jobspec ... or kill -l [sigspec]
|
|
[+] Restarting Lainradio and Icecast ...
|
|
[+] Waiting 5 seconds for icecast...
|
|
[+] Restarting the existing MPD channels and nginx...
|
|
[+] Restarting mpd-focus.service ...
|
|
[+] Restarting mpd-nihilism.service ...
|
|
[+] Restarting mpd-temple.service ...
|
|
/root
|
|
|
|
----► ✔ Command successful Elapsed time 7.386s
|
|
|
|
|
|
|
|
Now by default the radio.js file looks for the channel names by their ogg extention, so i modified it to look for mp3 instead, and we finally get the channels to be displayed:
|
|
|
|
|
|
root@lain:/srv/http/js# cat radio.js | grep mp3
|
|
if(sname !== undefined && sname.startsWith("[mpd] ") && sname.endsWith(" (mp3)")) {
|
|
|
|
|
|
|
|
I changed it from ogg to mp3 because for some reason i can't get my .ogg output streams to work, but the mp3 ones work fine so we're using them instead:
|
|
|
|

|
|
|
|
And when we change channels we see that everything updates as intended:
|
|
|
|

|
|
|
|
So with the same process we can add other channels, each of them have a systemd **mpd-channel.service** file to launch a **mpd** process on a specific port (ex: **6603** with a mpd config at **/root/.config/mpd/channel.conf** , with a directory at **/srv/radio/music/channel/** of their own. Of course you need to edit **/srv/lainonlife/config.json** and **icecast.xml** with your changes everytime. and make sure that you have a cronjob running **python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6603** every 3 hours after you added the **transition** tracks just like for our previous 2 channels in order to keep the radios constantly updated with new albums / songs to play for the listeners.
|
|
|
|
here's the forked repository with all important files i edited [here](https://git.void.yt/nothing/lainonlife):
|
|
|
|
|
|
-icecast.service
|
|
-mpd-cyberia.service
|
|
-lainradio.service
|
|
|
|
-schedule.py
|
|
-tagger.sh
|
|
-index.html
|
|
|
|
-ncmpcpp.conf
|
|
-mpd-cyberia.conf
|
|
-js/player.js
|
|
|
|
|
|
Recap of crontab:
|
|
|
|
|
|
crontab -e
|
|
|
|
0 */12 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6603 # focus
|
|
0 */12 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6606 # nihilism
|
|
0 */12 * * * python3 /srv/lainonlife/scripts/schedule.py --host=127.0.0.1 6609 # temple
|
|
0 0 * * * /srv/lainonlife/scripts/restart-radio.sh
|
|
0 */24 * * * /srv/lainonlife/scripts/file-list.sh
|
|
0 */12 * * * echo '' | tee /srv/radio/data/syslog*
|
|
|
|
|
|
|