Liquidsoap Radio System
| ########################################################################################### | |
| # Liquidsoap Radio System - built by GeekBrony, based from Liquidsoap. # | |
| ########################################################################################### | |
| # Primary Features: | |
| # - AutoDJ that crossfades between songs and has a 1/10 chance of landing on a Station ID/Jingle/Ad. | |
| # - AutoDJ also selects tracks from "High Priority", "Low Priority" and "New Songs" playlists randomly. | |
| # - Live Shows (that automatically dump to a directory) | |
| # - Mic to speak over the stream. | |
| # - Requests via Telnet/Web Interface, which have a 80-90% chance of queuing up when a song ends. | |
| # - Outputs in 96kbps, 128kbps, and 320kbps MP3 with ID3v2 tags. | |
| # | |
| # Planned Changes: | |
| # - Fix Live Show Dumping creating a file upon start, which is unnecessary. | |
| # - Queuing Playlists | |
| # - Add alternate streams with only the playlist running, for people who just want music. | |
| # | |
| ################################# | |
| # <BEGIN CONFIGURATION SECTION> # | |
| ################################# | |
| # Please edit to your needs, or else you will get errors upon startup # | |
| # Music | |
| # 'musicdir' and 'jingledir' can be a local directory/playlist OR a playlist (pls/m3u) file on the internet. | |
| musicdir = "/store/music/" | |
| jingledir = "/store/ident/" | |
| # Music Selection Mode | |
| # random : Every playlist reload, shuffle. | |
| # randomize : Every song, shuffle. | |
| # normal : Sequential order. | |
| pls_mode = "random" | |
| # The variable 'securityuri' has to be a local file otherwise you will get an error saying 'That source is fallible!' | |
| securityuri = "/var/www/bdn/httpdocs/maintenance/elevator.mp3" | |
| # Playlists | |
| # Hits | |
| #hits_list = "/srv/pls/current_hits.m3u" | |
| # Music Selection Mode | |
| # random : Every playlist reload, shuffle. | |
| # randomize : Every song, shuffle. | |
| # normal : Sequential order. | |
| #hits_mode = "random" | |
| # New Songs | |
| new_song_list = "/store/new_music/" | |
| # Music Selection Mode | |
| # random : Every playlist reload, shuffle. | |
| # randomize : Every song, shuffle. | |
| # normal : Sequential order. | |
| new_mode = "random" | |
| # Mellow Mondays | |
| mellow_list = "/srv/pls/mellow_mondays.m3u" | |
| # Music Selection Mode | |
| # random : Every playlist reload, shuffle. | |
| # randomize : Every song, shuffle. | |
| # normal : Sequential order. | |
| mellow_mode = "random" | |
| # High Priority Songs | |
| hp_list = "/var/www/bdn/httpdocs/api/voting/high_priority.pls" | |
| hp_mode = "randomize" | |
| # Low Priority Songs | |
| lp_list = "/store/low_priority/" | |
| lp_mode = "randomize" | |
| # Live Stream | |
| # Live Mount URL | |
| livem = "http://localhost:8000/stream-live" | |
| # Buffer | |
| live_buffer = 5. | |
| live_buffer_max = 15. | |
| # Microphone (Speak over music) | |
| # Microphone Mount URL | |
| micm = "http://localhost:8000/stream-mic" | |
| # Buffer | |
| mic_buffer = 2. | |
| mic_buffer_max = 10. | |
| # Volume | |
| background_volume = 0.15 | |
| # Logging | |
| log_to_stdout = true | |
| log_to_file = true | |
| logpath = "/home/server/liquidsoapconfig/log.log" | |
| loglevel = 3 | |
| # Telnet | |
| enable_telnet = true | |
| telnetbindaddr = "127.0.0.1" | |
| telnetport = 2345 | |
| # Live Dumping | |
| # To disable live dumping, comment out lines 335-340 with '#' | |
| # Make sure the directory exists and/or has permission to make one. | |
| # %Y = year, %m = month, %d = day, %H = hour, %M = minute, %S = seconds | |
| #dump_mp3_file = "/var/www/brony.co/htdocs/rdmp/LIVE_%Y-%m-%d_%H-%M-%S.mp3" | |
| # Liquidsoap will add this string after request metadata | |
| # Example: "Artist - Title (Remix) [RQ]" | |
| # request_m = "[RQ]" | |
| # NOT IN USE | |
| # Last.fm Scrobbling | |
| lfm_enable = true | |
| lfmuser = "" | |
| lfmpass = "" | |
| # Icecast Information: | |
| hostname = "127.0.0.1" | |
| iceport = 8000 | |
| passw = "[REDACTED]" | |
| # Stream Name | |
| icename = "Radio" | |
| # Stream Genre | |
| icegenre = "Pony" | |
| # Description | |
| icedesc = "Best Variety Pony Hits + Live Shows" | |
| # Website URL | |
| iceurl = "localhost" | |
| ############################### | |
| # <END CONFIGURATION SECTION> # | |
| ############################### | |
| #- DO NOT EDIT AFTER THIS LINE UNLESS YOU KNOW WHAT YOU ARE DOING -# | |
| # For requests, add variable 'request_m' after the metadata | |
| def append_title_request(m) = | |
| # Grab the current title | |
| title = m["title"] | |
| # Return a new title metadata, which is disabled (for now). | |
| [("title","#{title}")] | |
| end | |
| def crossfade(s) | |
| #duration is automatically overwritten by metadata fields passed in | |
| #with audio | |
| s = fade.in(type="sin", duration=4., s) | |
| s = fade.out(type="sin", duration=5., s) | |
| fader = fun (a,b) -> add(normalize=false,[b,a]) | |
| cross(fader,s) | |
| end | |
| def smooth_add(~delay=0.5,~p=0.2,~normal,~special) | |
| d = delay | |
| fade.final = fade.final(duration=d*2.) | |
| fade.initial = fade.initial(duration=d*2.) | |
| q = 1. - p | |
| c = amplify | |
| fallback(track_sensitive=false, | |
| [special,normal], | |
| transitions=[ | |
| fun(normal,special)-> | |
| add(normalize=false, | |
| [c(p,normal), | |
| c(q,fade.final(type="sin",normal)), | |
| sequence([blank(duration=d),c(q,special)])]), | |
| fun(special,normal)-> | |
| add(normalize=false, | |
| [c(p,normal), | |
| c(q,fade.initial(type="sin",normal))]) | |
| ]) | |
| end | |
| # Add a skip function to a source | |
| # when it does not have one | |
| # by default | |
| def add_skip_command(~command,s) | |
| # Register the command: | |
| server.register( | |
| usage="skip", | |
| description="Skip the current song in source.", | |
| command, | |
| fun(_) -> begin source.skip(s) "Done!" end | |
| ) | |
| end | |
| # Enable logging on Standard Output and set logging level. | |
| set("log.stdout",log_to_stdout) | |
| set("log.level",loglevel) | |
| # Enable logging to file. See variable: logpath | |
| set("log.file",log_to_file) | |
| set("log.file.path",logpath) | |
| # Allow requests from Telnet (Liquidsoap Requester) | |
| set("server.telnet",enable_telnet) | |
| set("server.telnet.bind_addr",telnetbindaddr) | |
| set("server.telnet.port",telnetport) | |
| set("harbor.bind_addr","0.0.0.0") | |
| def lastfm.scrobble(~user,~password,m) = | |
| if lfm_enable then | |
| audioscrobbler.submit(user=user,password=password,m) | |
| audioscrobbler.nowplaying(user=user,password=password,m) | |
| end | |
| # Only enable this if you really understand what everything does in these three PHP files | |
| # Which at the moment, only GeekBrony knows what it does. | |
| meta_database = true | |
| if meta_database then | |
| str = base64.encode(json_of(compact=true, m)) | |
| system("php /var/www/bdn/httpdocs/api/countPlayed.php \"#{str}\"") | |
| system("php /var/www/bdn/httpdocs/api/extra_info.php \"#{str}\"") | |
| system("php /var/www/bdn/httpdocs/api/album_art.php \"#{str}\"") | |
| end | |
| end | |
| myplaylist = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| mode=pls_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",musicdir) | |
| #hits = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| # mode=hits_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",hits_list) | |
| new = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| mode=new_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",new_song_list) | |
| mellow = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| mode=mellow_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",mellow_list) | |
| hp = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| mode=hp_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",hp_list) | |
| lp = playlist(id="playlist",length=3600.0,default_duration=1800.0,timeout=10.0, | |
| mode=lp_mode,reload=480,reload_mode="seconds",mime_type="audio/x-mpegurl",lp_list) | |
| # myplaylist = smart_crossfade(myplaylist) | |
| # Request Queue from Telnet (Liquidsoap Requester) | |
| requests = audio_to_stereo(request.queue(id="requests")) | |
| requests = map_metadata(append_title_request, requests) | |
| jingles = nrj(playlist(jingledir)) | |
| liveshow = nrj(audio_to_stereo(input.http(buffer=live_buffer,max=live_buffer_max,livem))) | |
| microphone = nrj(audio_to_stereo(input.http(buffer=mic_buffer,max=mic_buffer_max,micm))) | |
| # Start building the feed with music | |
| # Randomize the source choices | |
| radio = random(id="randomizer", weights=[7000, 2399, 400, 1, 200], [requests, myplaylist, hp, lp, new]) | |
| radio=fallback(track_sensitive=true,[switch([ | |
| #Monday = 1w# | |
| ({ (1w) and 8h-12h }, mellow), | |
| #({ (5w) and 14h-18h }, ), | |
| ]), radio]) | |
| # Add fallbacks and jingles | |
| security = nrj(single(securityuri)) | |
| radio = rotate(weights = [5, 1],[radio, jingles]) | |
| radio = fallback(id="switcher",track_sensitive = false, [liveshow, radio, security]) #myplaylist | |
| #radio = fallback(track_sensitive = false,[liveshow, radio]) | |
| # Add a skip command for use via telnet | |
| add_skip_command(command="skip", radio) | |
| # Add an announcement queue. | |
| announce = audio_to_stereo(request.queue(id="announce")) | |
| # Talk over stream using microphone mount. | |
| radio = smooth_add(delay=0.8, p=background_volume, normal=radio, special=microphone) | |
| # Make quick announcements on the fly with this. | |
| radio = smooth_add(delay=0.8, p=background_volume, normal=radio, special=announce) | |
| radio = on_metadata(lastfm.scrobble(user=lfmuser,password=lfmpass), radio) | |
| radio = mksafe(radio) | |
| # Setup the output streams, and autodump to a webserver: | |
| output.icecast(%mp3(samplerate=44100,stereo=true,id3v2=true,bitrate=128),id="ToVorbis",name=icename, | |
| host=hostname,port=iceport,password=passw,mount="stream-128.mp3",genre=icegenre,icy_metadata="true", | |
| description="#{icedesc} (Normal)",url=iceurl,public=true,radio) | |
| output.icecast(%mp3(samplerate=48000,stereo=true,id3v2=true,bitrate=320),id="ToVorbis",name=icename, | |
| host=hostname,port=iceport,password=passw,mount="stream-320.mp3",genre=icegenre,icy_metadata="true", | |
| description="#{icedesc} (Ultra Quality)",url=iceurl,public=true,radio) | |
| output.icecast(%mp3(samplerate=32000,stereo=false,id3v2=true,bitrate=96),id="ToVorbis",name=icename, | |
| host=hostname,port=iceport,password=passw,mount="stream-96.mp3",genre=icegenre,icy_metadata="true", | |
| description="#{icedesc} (Mobile)",url=iceurl,public=true,mean(radio)) | |
| # radio = on_shutdown(fun(_) -> fade.final(type="sin", duration=3., radio)) | |
| # Fail attempt at fading out on shutdown, will try to fix later. | |
| #output.file( | |
| # %mp3(bitrate=192),fallible=true, | |
| # on_start={log("Starting live dump.")}, | |
| # reopen_on_metadata=false,"#{dump_mp3_file}", | |
| # on_close=fun(_) -> (log("Stopped live dump.")), | |
| #liveshow) | |
| # END OF SCRIPT # |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment