Old 21st February 2015, 11:20   #1
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
DL's Streaming Toolbox

audio/video streaming, music management, automation, podcast generation, encoding, recording, transcoding, stats generation, etc, etc.

http://www.dlnetworks.net/tools

the quick list

scserv dnas v1/2
liquid soap
ffmpeg
streamtranscoder
eyed3
perl/curl/php/python/html/javascript/shell scripting
htaccess/mod rewrite
api usage (youtube/soundcloud)
crontab
dopelabs is offline   Reply With Quote
Old 21st February 2015, 11:24   #2
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
DL’s Streaming Toolbox: How to Liquidsoap

http://www.dlnetworks.net/tools/stre...ox-liquidsoap/

install liquidsoap

the following commands were tested on a fresh/default install of ubuntu server 14.04 lts, and is expected you already have an ice/shoutcast server running, and know your way around the linux command line.

you can find a list of the available liquidsoap packages for install by searching the apt list:

code:
$ sudo apt-cache search liquidsoap


i take the easy route and just go ahead and also install all the supported streaming plugins as well.

code:
$ sudo apt-get install liquidsoap liquidsoap-plugin-all


once installed you are ready to write a script.

this example will have the following functions/capabilities:

the script runs in the background (deamon mode)
plays local mp3’s listed in a playlist file (txt)
immediately switch to live dj (and back) on connect/disconnect
play a local backup file of any of the above fails for any reason
manually set title via url GET request (http://127.0.0.1:8080/setmeta?title=SongTitleGoesHere)
output the stream to multiple instances of shoutcast at different bit rates and formats (transcoding)

to execute simply
code:
$ ./whateveryouwant.liq


create a file containing the following and name it whateveryouwant.liq and edit values as needed
code:
#!/usr/bin/liquidsoap

# run this script in the background
set("init.daemon",true)

# do not create a pid file
set("init.daemon.pidfile",false)

# set the path and permissions for the logfile
set("log.file.path","/home/user/log/liquidsoap.log")
set("log.file.perms",755)
set("log.unix_timestamps",true)

# local ip address to bind and listen for input (dj or metadata)
set("harbor.bind_addr","127.0.0.1")

# port and pass for live djs to connect to (shoutcast protocol)
live = input.harbor(icy=true,"/",port=8888,password="PASS")

# path to playlist file which contains a list of local mp3's (/home/user/mp3/song.mp3)
playlist = playlist("/home/user/mp3/playlist.txt")

# path to failover song if all above fails
emergency = single("/home/user/mp3/backup.mp3")

# do not monitor for silence and specify the fallback/priority order
radio = fallback(track_sensitive=false,[live,playlist,emergency])

# function to manually change song title
title = insert_metadata(radio)
insert = fst(title)
radio = snd(title)

def set_meta(~protocol,~data,~headers,uri) =
title = url.split(uri)
meta = metadata.export(snd(title))
ret = if meta != [] then insert(meta) "OK!" else "No metadata to add!" end
http_response(protocol=protocol,code=200,headers=[("Content-Type","text/html")],data="#{ret}") end

# port to register metadata updates via http
harbor.http.register(port=8080,method="GET","/setmeta",set_meta)

# shoutcast servers to broadcast to
output.shoutcast(%mp3(bitrate=256,samplerate=44100,stereo=true),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 8000,password = "PASS",radio)
output.shoutcast(%mp3(bitrate=128,samplerate=44100,stereo=true),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 8002,password = "PASS",radio)
output.shoutcast(%mp3(bitrate=64,samplerate=44100,stereo=true),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 8004,password = "PASS",radio)
output.shoutcast(%mp3(bitrate=24,samplerate=22050,stereo=true),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 8006,password = "PASS",radio)
output.shoutcast(%aac(bitrate=256),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 9000,password = "PASS",radio)
output.shoutcast(%aac(bitrate=128),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 9002,password = "PASS",radio)
output.shoutcast(%aac(bitrate=64),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 9004,password = "PASS",radio)
output.shoutcast(%aac(bitrate=24),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 9006,password = "PASS",radio)



another example, relay a shoutcast stream

relay.liq
code:
#!/usr/bin/liquidsoap

# set the path and permissions for the logfile
set("log.file.path","/home/user/log/liquidsoap.log")
set("log.file.perms",755)
set("log.unix_timestamps",true)

# stream url to relay (source)
url = "http://127.0.0.1:9000"
relay = mksafe(input.http(url))
radio = fallback(track_sensitive=false,[relay])

# shoutcast server to broadcast to
output.shoutcast(%mp3(bitrate=256,samplerate=44100,stereo=true),name="RADIO NAME",genre="GENRE",host="127.0.0.1",port = 8000,password = "PASS",radio)



other samples can be found on the liquidsoap website http://liquidsoap.fm/doc-svn/scripts
dopelabs is offline   Reply With Quote
Old 7th March 2015, 13:08   #3
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
jquery shoutcast status

https://github.com/Wavestreaming/jqu...iki/Easy-Setup

this will display shoutcast dnas v2 status/info, auto updating every 5 seconds without page reload.

Prerequisites

Your DNAS version must have JSON support, if it does not then you will not be able to use this plugin.

Setup

Download the plugin and store jquery.shoutcast.easy.min.js somewhere on your server.

https://github.com/Wavestreaming/jquery-shoutcast.git

Configuration

In the second script tag you need to edit example.com to be your host and also edit the port if necessary, this is the minimum configration that is required by the plugin, there are more options which can be found here

Usage

Once you have configured the plugin you will need to add various elements to your page.

Showing Stats

To show any statistics from your stream you simply need to add an element with adata-shoutcast-value=”” attribute, for example, if I wanted to show the currently playing song this is what you would have:

code:
<p data-shoutcast-value="songtitle"></p>


Or current listeners:

code:
<span data-shoutcast-value="currentlisteners"></span>


All of the available values can be found here

Showing played tracks

To show played tracks you need to an an ul element with an id of played to your page:

code:
<ul id="played"></ul>


With the above element on the page the names of the recently played tracks will be displayed in order.

Example HTML
code:

<body>
<h1 data-shoutcast-value="servertitle"></h1>

<p>Now Playing: <span data-shoutcast-value="songtitle"></span></p>
<p>Listeners: <span data-shoutcast-value="currentlisteners"></span>/<span data-shoutcast-value="maxlisteners"></span></p>

<h2>You just missed</h2>
<ul id="played"></ul>

<script src="//ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script src="jquery.shoutcast.easy.min.js?host=example.com&port=8000&interval=5000"></script>
</body>


The above HTML will display the server title, the current song, the current listeners, the maximum listeners and a list of all of the recently played tracks.
dopelabs is offline   Reply With Quote
Old 22nd April 2015, 04:36   #4
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
DL’s streaming toolbox: ffmpeg to shoutcast with remote sources

http://www.dlnetworks.net/tools/dls-...emote-sources/

use ffmpeg to encode/re-encode any local or remote media to mp3 and stream to shoutcast.

prerequisites:

ffmpeg with libmp3lame and openssl enabled
http://ffmpeg.org
youtube-dl
http://yt-dl.org
shout-perl
http://downloads.us.xiph.org/release...out-2.1.tar.gz
libshout3
http://packages.ubuntu.com/search?keywords=libshout3
libmp3lame
http://packages.ubuntu.com/search?keywords=libmp3lame

usage:

code:
$ ffmpeg -d -re -i "/path/to/local/media.wav" -vn -c:a mp3 -b:a 256k -f mp3 - | ./stream_stdin.pl


streaming to shoutcast is handled by piping audio data to a perl script (shout-perl)

here is the perl script that reads audio data from pipe or STDIN

shout_stdin.pl
code:
#!/usr/bin/perl -w

use strict;
use Shout;
use bytes;


###############################################################################
### C O N F I G U R A T I O N
###############################################################################


# shoutcast DNAS version 1 or 2
my $version = 1;

# shoutcast v2 stream id
my $sid = 1;

# hostname or ip address without http://
my $host = '123.123.123.123';

# port
my $port = 8000;

# password
my $password = 'password';

# stream name
my $name = 'ffmpeg';

# stream url
my $url = 'http://www.radioname.com';

# stream genre
my $genre = 'genre';

# 1 for public, 0 for private
my $public = 0;

# bitrate
my $bitrate = 256;

# samplerate
my $samplerate = 44100;

###############################################################################
### M A I N P R O G R A M
###############################################################################

my $streamer = new Shout
host => $host,
port => $port,
password => $password,
name => $name,
url => $url,
bitrate => $bitrate,
genre => $genre,
format => SHOUT_FORMAT_MP3,
protocol => SHOUT_PROTOCOL_ICY,
public => $public;

$streamer->set_audio_info(SHOUT_AI_BITRATE => $bitrate, SHOUT_AI_SAMPLERATE => $samplerate);

if ($streamer->open) {
print "connected\n";
print "host: $host\n";
print "port: $port\n";
print "password: $password\n";
print "name: $name\n";
print "url: $url\n";
print "bitrate: $bitrate\n";
print "genre: $genre\n";
print "format: SHOUT_FORMAT_MP3\n";
print "public: $public\n";
print "Streaming from STDIN...\n";

$streamer->set_metadata("song" => "Streaming from STDIN");

my ($buff, $len);
while (($len = sysread(STDIN, $buff, 4096)) > 0) {
unless ($streamer->send($buff)) {
print "Error while sending: " . $streamer->get_error . "\n";
last;
}
$streamer->sync;
}
$streamer->close;
} else {
print "failed... " . $streamer->get_error . "\n";
}



remote sources are handled using youtube-dl by using backticks in the ffmpeg command. this will enable you to stream any media resource thats supported by youtube-dl and ffmpeg, such as soundcloud, mixcloud, youtube, vimeo, twitch.tv, etc.

usage:

code:
$ ffmpeg -d -re -i "`youtube-dl -f bestaudio -g https://soundcloud.com/dubstepfm/dubstep-fm-archive-2014-11-09-all-widdler-vol-7-mixed-by-dopelabs`" -vn -c:a mp3 -b:a 256k -f mp3 - | ./shout_perl.pl


shout_perl.pl expects raw mp3 audio data via pip or STDIN. this means you can simply:

code:
$ cat song.mp3 | ./shout_perl.pl


and it will stream a single mp3. a little bit of crafty scripting and you can easily create your own auto dj.
dopelabs is offline   Reply With Quote
Old 26th April 2015, 05:54   #5
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
multi server shoutcast listener stats tcl for eggdrop irc bot

https://github.com/dlnetworks/multi-...cl-for-eggdrop

tcl script for eggdrop irc bots with multi server totals, bandwidth totals, and record/peak tracking.

triggers: .stat .record

output: bitrate - current/max/bandwidth

Radio Name Stats: (24 Kbps - 0/100/0.00 Mbps) (64 Kbps - 2/100/0.12 Mbps) (128 Kbps - 8/200/1.00 Mbps) (256 Kbps - 52/400/13.00 Mbps) (Total - 62/800/14.12 Mbps)


code:

## original script by Niels Roosen (niels at okkernoot dot net)
## modified for dnas v2 and other fixes by dlnetworks.net

## Set some configuration options

## Shoutcast configuration
## Stream servers, format: { host_or_ip port stream_id }
set shoutcast_relays {

{ 127.0.0.1 80 1 }
{ host.domain.com 8000 1 }
{ 127.0.0.1 8030 1 }
{ 127.0.0.1 8050 1 }
{ host.domain.com 80 2 }
{ 127.0.0.1 8000 2 }
{ host.domain.com 8030 2 }
{ 127.0.0.1 8050 2 }
}

## Channel to show shoutcast stats on
set shoutcast_channels { "#channel" }

## Interval for showing stats
set shoutcast_show_interval 60

## Name of the radio station
set shoutcast_station_name "Radio Station"

## End of shoutcast configuration

package require http
package require tdom

bind pub - ".record" show_listener_record
bind msg - ".stat" msg_show_stats
bind pub - ".stat" pub_show_stats
bind msg - ".stats" msg_show_stats
bind pub - ".stats" pub_show_stats
bind time - "?? * * * *" timer_show_stats

### CODE STARTS HERE ###

# Set show_stats semaphore
set sem_show_shoutstats 0

# Set show_stats counter
set counter_show_shoutstats $shoutcast_show_interval

proc test_stats {n m h c a} {
after 0 [timer_show_stats 0 0 0 0 0]
}

proc pub_show_stats {nick mask hand channel args} {
after 0 [show_shoutstats $channel "requested"]
}

proc msg_show_stats {nick mask hand channel args} {
after 0 [show_shoutstats $nick "requested"]
}

proc timer_show_stats {mi ho da mo ye} {
after 0 [show_shoutstats "#" "timer"]
}

proc show_listener_record {nick hand channel args} {
after 0 [show_shoutstats $channel "record"]
}

set shoutcast_station_name2 "$shoutcast_station_name"


proc show_shoutstats {channel mode} {
global shoutcast_relays sem_show_shoutstats shoutcast_show_interval \
shoutcast_station_name2 shoutcast_station_name counter_show_shoutstats shoutcast_channels \
homedir
set run_allowed 0

## First wait for any other show functions to complete w/ some test-and-set instruction
while { $run_allowed == 0 } {
if { ( $sem_show_shoutstats == 0 ) && ( [set sem_show_shoutstats 1] ) && ( [set run_allowed 1] ) } {
## Continue the function
} else {
vwait $sem_show_shoutstats
putserv "PRIVMSG $channel: I was delayed for execution"
}
}

# Initialize the total stats
# Per relay: { quality { current max bandwidth }}
set total_stats {}

# Totals current max bandwidth
set t_unique 0
set t_maxlst 0
set t_bw 0.0

# Extract data per relay
foreach relay $shoutcast_relays {

# Get attributes
set server [lindex $relay 0]
set port [lindex $relay 1]
set sid [lindex $relay 2]
set mark [lindex $relay 3]

# Get the actual data
if { [catch {::http::geturl "http://$server:$port/7.html?sid=$sid" \
-timeout 5000 -headers "User-Agent: Mozilla (The King Kong of Lawn Care)"} stats_token] } {
continue
} else {
# DO NOTHING
set status [::http::status $stats_token]
if { $status != "ok" } {
continue
}
}
set stats_data [::http::data $stats_token]

# Get the stats from the html body
set begin [expr [string first "<body>" $stats_data] + 6]
set end [expr [string first "</body>" $stats_data] - 1]
set relay_rawstats [string range $stats_data $begin $end]

# Now extract the max-allowed and unique listener stats from the string
set relay_liststats [split $relay_rawstats ","]

set relay_unique [lindex $relay_liststats 1]
set relay_maxlst [lindex $relay_liststats 3]
set quality [lindex $relay_liststats 5]
set relay_bw [expr ($quality * $relay_unique) / 1024.0 ]

# Accumulate this to the totals
# First check if this quality already appears in the totals list
# And eventually search for the index where it should be inserted then
set length [llength $total_stats]
if { $length == 0 } {
# The list is yet empty
set q_totals[list $quality[list $relay_unique $relay_maxlst $relay_bw]]
set total_stats [concat $total_stats $q_totals]
} else {
# Search for the right quality in the index
# First try to find it in the list
for { set q_index 0 } { $q_index <= $length } { set q_index [expr $q_index + 2] } {
if { [lindex $total_stats $q_index] == $quality } {
break
}
}

if { $q_index > $length } {
# It doesnt exist yet
# Now we have to insert it in the list
for { set q_index 0 } { ($quality > [lindex $total_stats $q_index]) \
&& ($q_index < $length) } { set q_index [expr $q_index + 2] } {
}
if { $q_index > $length } {
# We have to append it to the list
set q_totals[list $quality[list $relay_unique $relay_maxlst $relay_bw]]
set total_stats [concat $total_stats $q_totals]
} else {
# We have to insert it in the list
set q_totals[list $quality[list $relay_unique $relay_maxlst $relay_bw]]
# First put it behind the first part of the list
set total_stats_first [lrange $total_stats 0 [expr $q_index - 1]]
set total_stats_last [lrange $total_stats $q_index end]
set total_stats [concat $total_stats_first $q_totals]
set total_stats [concat $total_stats $total_stats_last]
}
} else {
# The stats for this quality already exist, add it to them
# First get the current stats
set cq_totals [lindex $total_stats [expr $q_index + 1]]

# Add them together
set q_unique [expr $relay_unique + [lindex $cq_totals 0]]
set q_maxlst [expr $relay_maxlst + [lindex $cq_totals 1]]
set q_bw [expr $relay_bw + [lindex $cq_totals 2]]

# Replace the qurrent values in the totals
set q_totals[list $q_unique $q_maxlst $q_bw]
set total_stats [lreplace $total_stats [expr $q_index + 1] [expr $q_index + 1] $q_totals]
}
}

# And accumulate this to the absolute totals
set t_unique [expr $t_unique + $relay_unique]
set t_maxlst [expr $t_maxlst + $relay_maxlst]
set t_bw [expr $t_bw + $relay_bw]

::http::cleanup $stats_token
}

# Reset the show_stats_now var
set show_stats_now 0

# Truncate the bandwidth
set t_bw [format "%.2f" $t_bw]

# Now, before we display anything, check if the record is broken
# If so, we dont display the stats but display a new record notice instead
# Format of the file:
#
# Date\tListeners\tBw

# First try to open the file
if { [file exists "./$shoutcast_station_name.record"] == 1 } {
set statfile [open "./$shoutcast_station_name.record" r]
set record [read $statfile]
close $statfile

set frecord [split $record "\t"]

# Now check if there was already something in the file
if { [llength $frecord] != 4 } {
set record_broken 1
} elseif { [lindex $frecord 2] < $t_unique } {
set record_broken 1
} else {
set record_broken 0
}
} else {
# The file didnt exist
set record_broken 1
}

# Now, check if we are gonna show the stats or the new record
if { $record_broken == 1 } {
# Re-open the statfile
set statfile [open "./$shoutcast_station_name.record" w]

# Insert the new data in the file
set current_time [clock seconds]
set ctime [clock format $current_time -format "%A %m-%d-%Y %H:%M"]

set current_song [lindex $shoutcast_now_playing 0]
puts -nonewline $statfile "$ctime\t$t_unique\t$t_bw"

## Be sure to close the file
close $statfile

set outputs "$shoutcast_station_name2 new record - Listener record broken on $ctime with $t_unique listeners."
# Now print the record to the chat
if { $mode == "timer" } {
# For each shoutcast channel
foreach chan $shoutcast_channels {
putquick "PRIVMSG $chan :$outputs"
}
} else {
# For the specified channel
putquick "PRIVMSG $channel :$outputs"
}
} else {
# Perform the command requested (timer, requested or record)
if { $mode == "record" } {
set rsong [lindex $frecord 0]
set rtime [lindex $frecord 1]
set rlst [lindex $frecord 2]
set rbw [lindex $frecord 3]
set outputs "$shoutcast_station_name2 record - Current record was set on $rtime with $rlst listeners."
putquick "PRIVMSG $channel :$outputs"
} else {
# Format all stats in one line
set outputs "$shoutcast_station_name2 Stats:"

foreach {q s} $total_stats {
set current [lindex $s 0]
set max [lindex $s 1]
set bw [format "%.2f" [lindex $s 2]]
set outputs "$outputs ($q Kbps - $current/$max/$bw Mbps)"
}
set outputs "$outputs (Total - $t_unique/$t_maxlst/$t_bw Mbps)"

if { $mode == "requested" } {
# It seems we have a normal channel
putquick "PRIVMSG $channel :$outputs"
} else {
# Just assume this is a timer thing
set counter_show_shoutstats [expr $counter_show_shoutstats - 1]
# putserv "PRIVMSG $channel ecreasing counter to $counter_show_shoutstats"
if { $counter_show_shoutstats <= 0 } {
set counter_show_shoutstats $shoutcast_show_interval

# Now display those stats
foreach chan $shoutcast_channels {
putquick "PRIVMSG $chan :$outputs"
}
}
}
}
}

## Free the semaphore
set sem_show_shoutstats 0
}

###############################
# Execute the show_stats
show_shoutstats "#" "timer"

putlog "multi server shoutcast listener stats tcl for eggdrop loaded..."

dopelabs is offline   Reply With Quote
Old 15th June 2016, 11:43   #6
Yusadolat
Junior Member
 
Join Date: Dec 2015
Posts: 15
Sorry Please If i may ask, How can i run this on a remote server ? . If this is not possible then how can i run it on MacBook Pro ?
Yusadolat is offline   Reply With Quote
Old 15th October 2016, 16:54   #7
dopelabs
Major Dude
 
dopelabs's Avatar
 
Join Date: Oct 2006
Location: Silicon Valley
Posts: 534
Send a message via AIM to dopelabs
Quote:
Originally Posted by Yusadolat View Post
Sorry Please If i may ask, How can i run this on a remote server ?
the same way you run it on any server.

Quote:
Originally Posted by Yusadolat View Post
If this is not possible then how can i run it on MacBook Pro ?
it is possible... even on the mac =] most or all of the tools are compatible with any modern *nix flavor
dopelabs is offline   Reply With Quote
Reply
Go Back   Winamp & Shoutcast Forums > Shoutcast > Shoutcast Discussions

Thread Tools Search this Thread
Search this Thread:

Advanced Search
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off

Forum Jump