forked from Tilka/selfnet-iptv
-
Notifications
You must be signed in to change notification settings - Fork 0
/
radio.html
184 lines (167 loc) · 5.69 KB
/
radio.html
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
<!doctype html>
<meta charset=utf-8>
<title>SelfStreaming: Radio</title>
<link rel=stylesheet href=css/bootstrap.min.css>
<link rel=icon href=favicon.ico>
<script src=js/jquery-2.1.1.min.js></script>
<script src=js/fixencoding.js></script>
<style>
#channel-list td:nth-child(-n+2) {
cursor: pointer;
}
.player {
position: fixed; top: 0; left: 0;
padding: 10px;
background-color: black;
border: solid #f1943d;
border-width: 0 3px 3px 0;
border-bottom-right-radius: 20px;
}
</style>
<div class="container">
<div class="page-header text-center">
<a href=/><img src=img/selfstreaming.png alt=SelfStreaming height=58 width=382></a>
<p class=lead>SelfStreaming also has some radio channels
</div>
<h2>Radio Channels (Beta)</h2>
<p>These channels are currently <strong>not</strong> announced via SAP. In most modern browsers, you should be able to play them directly, otherwise you need to open the links in your media player. Buffering can take a couple of seconds.
<table id=channel-list class="table table-hover table-condensed">
<thead><tr><th>Channel<th>Current Title<th>Website<th>Stream Link
<tbody>
</table>
<noscript>This website requires JavaScript.</noscript>
<hr>
<p>If you have any questions or suggestions, <a href=mailto:[email protected]>send us an email</a>.
</div>
<div class=player>
<audio id=player style=display:none controls></audio>
<br>
<span id=metadata-name></span>
<br>
<span id=metadata-title></span>
</div>
<script>
var Selfnet = {};
Selfnet.Timer = function(callback, delay) {
var timerID, lastExecution = new Date(), me = this;
function execute() {
timerID = null;
lastExecution = new Date();
callback(me);
}
function reschedule() {
var remaining = me.delay - (new Date() - lastExecution);
timerID = setTimeout(execute, remaining);
}
me.start = function() {
if (!timerID) {
execute();
}
return me;
};
me.reschedule = function() {
if (!timerID) {
reschedule();
}
return me;
};
me.pause = function() {
if (timerID) {
clearTimeout(timerID);
timerID = null;
}
return me;
};
me.delay = delay;
};
$(function() {
var player = $('#player').show().on('error', function(e) {
console.error(e);
if (player.attr('src').match(/ogg$/)) {
console.info('If you are using Chrome/Chromium, you may be hitting http://crbug.com/175281. For Firefox, make sure to use version 20 or newer.');
}
});
var currentlyPlaying;
function updateCurrentChannel(tr, name, title) {
currentlyPlaying = tr.attr('id');
tr.addClass('active');
$('#metadata-name').text(name);
$('#metadata-title').text(title);
}
function channelID(mount) {
return 'channel-' + mount.replace(/[!,.\/]/g, '');
}
function updateChannel(source, doc) {
function evalXPath(node, expr) {
return doc.evaluate(expr, source, null, XPathResult.STRING_TYPE, null).stringValue;
}
var mount = evalXPath(source, '@mount');
var id = channelID(mount);
// only the dead can know peace from this encoding chaos
var name = fixEncoding(evalXPath(source, 'server_name/text()'));
var title = fixEncoding(evalXPath(source, 'title/text()'));
var url = evalXPath(source, 'server_url/text()');
// don't display links with no dots or links set by software defaults
url = url.match(/^([^.]*|http:\/\/(www.shoutcast.com|savonet.sf.net))$/) ? '' : (url.match(/^http:\/\//) ? url : ('http://' + url));
var short_url = url.substr(7);
short_url = short_url.replace(/^www\./, '').replace(/\/$/, '');
short_url = short_url.length > 21 ? (short_url.substr(0, 21-3) + '...') : short_url;
// some stations add boilerplate copyright notices or links at the end, remove these
name = name.replace(/( - |, )?(©|\(c\)).*$/, '').replace(/( -)? (OGG|MP3)$/, '').replace(/ - www\..+$/, '');
// others display the mount point or default names, use the local mount point instead
name = name.match(/^(|\/.*|Unspecified name|Unnamed Server)$/) ? mount.substr(1).replace(/\.(ogg|mp3)$/, '').split('_').join(' ') : name;
var short_title = title.length > 80 ? (title.substr(0, 80-3) + '...') : title;
var stream = 'radio' + mount;
// === create table row ===
var td1 = $('<td>').text(name);
var td2 = $('<td>').text(short_title);
if (short_title != title) {
td2.attr('title', title);
}
var td3 = $('<td>').append($('<a>').attr('href', url).text(short_url));
var td4 = $('<td>').append($('<a>').attr('href', stream).text('Link'));
var tr = $('<tr>').attr('id', id).append(td1, td2, td3, td4);
function clickHandler() {
player.attr('src', stream).trigger('play');
$('#channel-list tr').removeClass('active');
updateCurrentChannel(tr, name, title);
}
td1.click(clickHandler);
td2.click(clickHandler);
// === add to table ===
var oldElement = $('#' + id);
if (oldElement.length) {
oldElement.replaceWith(tr);
} else {
$('#channel-list tbody').append(tr);
}
if (id == currentlyPlaying) {
updateCurrentChannel(tr, name, title);
}
}
function updateChannelList(timer) {
$.get('radio/status.xml', function(data) {
var doc = data.documentElement.ownerDocument;
var sources = doc.evaluate('/icestats/source', data, null, XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
var source, i = 0;
while (source = sources.iterateNext()) {
++i;
updateChannel(source, doc);
}
console.log('got', i, 'channels');
}, 'xml').fail(function(e) {
console.error(e);
}).complete(function() {
timer.reschedule();
});
}
var updateTimer = new Selfnet.Timer(updateChannelList, 60*1000).start();
$(document).on('visibilitychange webkitvisibilitychange', function(e) {
if (document.hidden || document.webkitHidden) {
updateTimer.pause();
} else {
updateTimer.reschedule();
}
});
});
</script>