PageSourceSearch

https://www.thekickaround.com/wp-content/plugins/stream-player-pro/js/radio-player.js?ver=1780414532

js thekickaround.com collected 2026-10-07 00:36:11 UTC 69,590 bytes, 1,550 lines download raw bytes

1/* =============================== */
2/* === Radio Player Javascript === */
3/* --------- Version 1.0.5 ------- */
4/* =============================== */
5
6/* === Debounce Delay Callback === */
7var radio_player_debounce = (function () {
8	var player_debouncers = {};
9	return function (callback, ms, uniqueId) {
10		if (!uniqueId) {uniqueId = "nonuniqueid";}
11		if (player_debouncers[uniqueId]) {clearTimeout (player_debouncers[uniqueId]);}
12		player_debouncers[uniqueId] = setTimeout(callback, ms);
13	};
14})();
15
16/* === Cookie Value Function === */
17radio_player_cookie = {
18	set: function (name, value, days) {
19		if (days) {
20			var date = new Date();
21			date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
22			var expires = '; expires=' + date.toUTCString();
23		} else {var expires = '';}
24		document.cookie = 'radio_player_' + name + '=' + JSON.stringify(value) + expires + '; path=/';
25	},
26	get: function(name) {
27		var nameeq = 'radio_player_' + name + '=', ca = document.cookie.split(';');
28		for (var i = 0; i < ca.length; i++) {
29			var c = ca[i];
30			while (c.charAt(0) == ' ') {
31				c = c.substring(1, c.length);
32				if (c.indexOf(nameeq) == 0) {
33					/* 1.0.1: fix for possible empty value */
34					value = c.substring(nameeq.length, c.length).trim();
35					if (value == '') {return null;}
36					return JSON.parse(value);
37				}
38			}
39		}
40		return null;
41	},
42	delete: function(name) {
43		radio_player_cookie.set(name,'',-1);
44	}
45}
46
47/* === Load Audio Functions === */
48
49/* --- check data for format/script --- */
50function radio_player_check_format(data) {
51
52	if (radio_player.debug) {console.log(data);}
53	script = false; scripts = radio_player.scripts;
54	url = data.url; fallback = data.fallback; format = fformat = '';
55	if (typeof data.format != 'undefined') {format = data.format.toLowerCase();}
56	if (typeof data.fformat != 'undefined') {fformat = data.fformat.toLowerCase();}
57
58	/* attempt to get format from URL */
59	/* TODO: add more possible formats for detection ? */
60	formats = ['mp3','aac','m4a','mp4','ogg','oga','webm','rtmpa','wav','flac'];
61	if (format == '') {
62		if (radio_player.debug) {console.log('Detecting stream format from URL '+url);}
63		for (i = 0; i < formats.length; i++) {
64			length = formats[i].length;
65			if (url.substr(-length,length) == formats[i]) {format = formats[i];}
66		}
67		/* 2.5.18: added partial path match URL checking */
68		if (format == '') {
69			for (i = 0; i < formats.length; i++) {
70				checkurl = new URL(url); urlpath = checkurl.pathname + checkurl.search;
71				if (urlpath.indexOf(formats[i]) > -1) {format = formats[i];}
72			}
73		}
74	}
75	if (fformat == '') {
76		if (radio_player.debug) {console.log('Detecting fallback format from URL '+url);}
77		for (i = 0; i < formats.length; i++) {
78			length = formats[i].length;
79			if (fallback.substr(-length,length) == formats[i]) {fformat = formats[i];}
80		}
81		/* 2.5.18: added partial path match URL checking */
82		if (fformat = '') {
83			for (i = 0; i < formats.length; i++) {
84				checkurl = new URL(fallback); urlpath = checkurl.pathname + checkurl.search;
85				if (urlpath.indexOf(formats[i]) > -1) {fformat = formats[i];}
86			}
87		}
88	}
89
90	/* --- check against default script setting */
91	if (radio_player.settings.script) {
92		defaultscript = radio_player.settings.script;
93		if (defaultscript in scripts) {
94			if (format in radio_player.formats[defaultscript]) {script = defaultscript;}
95			else if (fformat in radio_player.formats[defaultscript]) {
96				/* switch to fallback format as recognized */
97				/* TODO: could test/improve this process ? */
98				script = defaultscript; a = url; b = format;
99				url = fallback; format = fformat; fallback = a; fformat = b;
100			}
101		}
102	}
103
104	/* check formats against available scripts */
105	if (!script) {
106		if (('amplitude' in scripts) && (format in radio_player.formats.amplitude)) {script = 'amplitude';}
107		else if (('jplayer' in scripts) && (format in radio_player.formats.jplayer)) {script = 'jplayer';}
108		/* else if (('audio5' in scripts) && (format in radio_player.formats.audio5)) {script = 'audio5';}
109		else if (('howler' in scripts) && (format in radio_player.formats.howler)) {script = 'howler';}
110		else if (('mediaelements' in scripts) && (format in radio_player.formats.mediaelements)) {script = 'mediaelements';} */
111		if (!script) {
112			if (('amplitude' in scripts) && (fformat in radio_player.formats.amplitude)) {script = 'amplitude';}
113			else if (('jplayer' in scripts) && (fformat in radio_player.formats.jplayer)) {script = 'jplayer';}
114			/* else if (('audio5' in scripts) && (fformat in radio_player.formats.audio5)) {script = 'audio5';}
115			else if (('howler' in scripts) && (fformat in radio_player.formats.howler)) {script = 'howler';}
116			else if (('mediaelements' in scripts) && (fformat in radio_player.formats.mediaelements)) {script = 'mediaelements';} */
117			if (script) {a = url; b = format; url = fallback; format = fformat; fallback = a; fformat = b;}
118		}
119		if (!script) {
120			if ('amplitude' in scripts) {script = 'amplitude';}
121			else if ('jplayer' in scripts) {script = 'jplayer';}
122			/* else if ('audio5' in scripts) {script = 'audio5';}
123			else if ('howler' in scripts) {script = 'howler';} */
124		}
125	}
126
127	data.script = script; data.url = url; data.format = format; data.fallback = fallback; data.fformat = fformat;
128	return data;
129}
130
131/* --- load default radio stream --- */
132function radio_player_load_radio(start) {
133	script = radio_player.settings.script; instance = radio_player_data.state.instance;
134	data = radio_player.stream_data; data.type = 'stream';
135	player = radio_player_load_stream(script, instance, data, start);
136}
137
138/* --- load HLS source --- */
139function radio_player_load_hls(script, instance, data, start) {
140	if (!instance) {instance = radio_player_default_instance();}
141	data.type = 'hls'; radio_player_data.data[instance] = data;
142	jQuery('#radio_player_'+instance).attr('data-channel', data.channel);
143	player = radio_player_load_audio(script, instance, data, false);
144	radio_player_hls_source(instance, data.url, start);
145}
146
147/* --- load a station --- */
148function radio_player_load_station(script, instance, data, start) {
149
150	if (!instance) {instance = radio_player_default_instance();}
151	data.type = 'station'; radio_player_data.data[instance] = data;
152	jQuery('#radio_player_'+instance).attr('data-station', data.station);
153
154	data = radio_player_check_format(data); script = data.script;
155	player = radio_player_load_audio(script, instance, data, start);
156	if (radio_player.debug) {console.log('Load Station '+station+' - Script: '+script+' - Instance: '+instance+' URL: '+data.url+' Format: '+data.format+' Start:'+start);}
157	if (player && start) {
158		setTimeout(function() {radio_player_play_on_load(player, script, instance);}, 50);
159	}
160}
161
162/* --- load a channel --- */
163function radio_player_load_channel(script, instance, data, start) {
164
165	if (!instance) {instance = radio_player_default_instance();}
166	data.type = 'channel'; radio_player_data.data[instance] = data;
167	jQuery('#radio_player_'+instance).attr('data-channel', data.channel);
168
169	data = radio_player_check_format(data); script = data.script;
170	player = radio_player_load_audio(script, instance, data, start);
171	if (radio_player.debug) {console.log('Load Channel '+channel+' - Script: '+script+' - Instance: '+instance+' URL: '+data.url+' Format: '+data.format+' Start:'+start);}
172	if (player && start) {
173		setTimeout(function() {radio_player_play_on_load(player, script, instance);}, 50);
174	}
175}
176
177/* --- load a stream --- */
178function radio_player_load_stream(script, instance, data, start) {
179
180	if (!instance) {instance = radio_player_default_instance();}
181	data.type = 'stream'; radio_player_data.data[instance] = data;
182
183	data = radio_player_check_format(data); script = data.script;
184	if (radio_player.debug) {console.log('Load Stream - Script: '+script+' - Instance: '+instance+' URL: '+data.url+' Format: '+data.format+' Start:'+start);}
185	player = radio_player_load_audio(script, instance, data, start);
186	if (player && start) {radio_player_play_on_load(player, script, instance);}
187}
188
189/* --- load a file --- */
190function radio_player_load_file(script, instance, data, start) {
191
192	if (!instance) {instance = radio_player_default_instance();}
193	data.type = 'file'; radio_player_data.data[instance] = data;
194
195	data = radio_player_check_format(data); script = data.script;
196	player = radio_player_load_audio(script, instance, data, start);
197	if (radio_player.debug) {console.log('Load File - Script: '+script+' - Instance: '+instance+' URL: '+data.url+' Format: '+data.format+' Start:'+start);}
198	if (player && start) {radio_player_play_on_load(player, script, instance);}
199}
200
201/* --- load audio in player --- */
202function radio_player_load_audio(script, instance, data, start) {
203	if (typeof radio_player_cancel_autoresume == 'function') {radio_player_cancel_autoresume({message:'Audio Loading'});} /* ??? */
204	url = data.url; format = data.format; fallback = data.fallback; fformat = data.fformat; type = data.type;
205	radio_player_set_data_state(script, instance, data, start);
206	loaded = radio_player_check_script(script);
207	if (loaded) {
208		if (radio_player.hasOwnProperty('delayed_player')) {clearInterval(radio_player.delayed_player);}
209		/* initialize the player if script is already loaded */
210		if (script == 'amplitude') {player =  radio_player_amplitude(instance, url, format, fallback, fformat);}
211		else if (script == 'jplayer') {player = radio_player_jplayer(instance, url, format, fallback, fformat);}
212		/* else if (script == 'audio5') {player = radio_player_audio5(instance, url, format, fallback, fformat);}
213		else if (script == 'howler') {player = radio_player_howler(instance, url, format, fallback, fformat);}
214		else if (script == 'mediaelements') {player = radio_player_mediaelements(instance, url, format, fallback, fformat);} */
215		if (player) {
216			detail = {script:script, instance:instance, url:url, format:format, fallback:fallback, fformat:fformat, type:type, start:start}
217			radio_player_event_handler('loading', detail);
218			/* note: radio_player_play_on_load called outside this function */
219		}
220		return player;
221	} else {
222		/* delay initialization until script is loaded */
223		if (radio_player.debug) {console.log('Script not ready, initializing Delayed Player');}
224		radio_player.delayed_data = {'time':0, 'start':start, 'script':script, 'instance':instance, 'url':url, 'format':format, 'fallback':fallback, 'fformat':fformat};
225		if (radio_player.hasOwnProperty('delayed_player')) {clearInterval(radio_player.delayed_player);}
226		radio_player.delayed_player = setInterval(function() {
227			radio_player.delayed_data.time++; data = radio_player.delayed_data; script = data.script; player = false;
228			if (data.time > 10) {console.log('Script load timed out. Please try again...'); clearInterval(radio_player.delayed_player);}
229			if ((script == 'amplitude') && (typeof window.Amplitude != 'undefined') && (typeof radio_player_amplitude != 'undefined')) {
230				clearInterval(radio_player.delayed_player);
231				player = radio_player_amplitude(data.instance, data.url, data.format, data.fallback, data.fformat);
232			} else if ((script == 'jplayer') && (typeof jQuery.jPlayer != 'undefined') && (typeof radio_player_jplayer != 'undefined')) {
233				clearInterval(radio_player.delayed_player);
234				player = radio_player_jplayer(data.instance, data.url, data.format, data.fallback, data.fformat);
235			} /* else if ((script == 'audio5') && (typeof window.audio5 != 'undefined') && (typeof radio_player_audio5 != 'undefined')) {
236				clearInterval(radio_player.delayed_player);
237				player = radio_player_audio5(data.instance, data.url, data.format, data.fallback, data.fformat);
238			} else if ((script == 'howler') && (typeof window.Howl != 'undefined') && (typeof radio_player_howler != 'undefined')) {
239				clearInterval(radio_player.delayed_player);
240				player = radio_player_howler(data.instance, data.url, data.format, data.fallback, data.fformat);
241			} else if ((script == 'mediaelement') && (typeof window.???? != 'undefined') && (typeof radio_player_mediaelement != 'undefined')) {
242				clearInterval(radio_player.delayed_player);
243				player = radio_player_mediaelements(instance, url, format, fallback, fformat);}
244			*/
245			if (player) {
246				radio_player_event_handler('loading', data);
247				radio_player_set_data_state(script, instance, data, data.start);
248				/* note: radio_player_play_on_load must be called inside delayed function */
249				if (data.start) {radio_player_play_on_load(player, data.script, data.instance);}
250			}
251		}, 1000);
252		return false;
253	}
254}
255
256/* --- auto start on player load ---*/
257function radio_player_play_on_load(player, script, instance) {
258	if (typeof player != 'undefined') {
259		if (radio_player.debug) {console.log('Loaded '+script+' script: '+(typeof player));}
260		detail = radio_player_data.data[instance]; detail.script = script, detail.instance = instance;
261		if ((script == 'amplitude') || (script == 'howler')) {
262			try {console.log(script+': Play'); player.play();
263				radio_player_custom_event('rp-play', detail);
264			} catch(e) {console.log(script+' error: could not play stream.'); console.log(e);}
265		} else if (script == 'jplayer') {
266			if (radio_player.jplayer_ready) {
267				try {console.log(script+': Play'); player.jPlayer('play');
268					radio_player_custom_event('rp-play', detail);
269				} catch(e) {console.log(script+' error: could not play stream.'); console.log(e);}
270			} else {
271				/* jPlayer not ready, wait until ready to play */
272				if (radio_player.debug) {console.log('jPlayer is not yet ready...');}
273				if (radio_player.hasOwnProperty('jplayer_load')) {clearInterval(radio_player.jplayer_load);}
274				radio_player.jplayer_load = setInterval(function() {
275					if (radio_player.jplayer_ready) {
276						clearInterval(radio_player.jplayer_load);
277						if (radio_player.debug) {console.log('Triggering jPlayer play.');}
278						try {player = radio_player_data.players[radio_player.jplayer_instance];
279							player.jPlayer('play'); radio_player_custom_event('rp-play', detail);
280						} catch(e) {console.log(script+' error: jPlayer could not play stream.'); console.log(e);}
281					}
282				}, 250);
283			}
284		} else if (script == 'audio5') {
285			try {console.log(script+': Play'); player.play();
286				radio_player_custom_event('rp-play', detail);
287			} catch(e) {console.log(script+' error: could not play stream.'); console.log(e);}
288		}
289	} else if (radio_player.debug) {
290		 console.log(script+' script not yet loaded...'); console.log(player);
291	}
292}
293
294// --- check/load a player script ---
295function radio_player_check_script(script) {
296	loading = false; head = document.getElementsByTagName('head')[0];
297	if (script == 'amplitude') {
298		if (typeof window.Amplitude == 'undefined') {
299			if (radio_player.debug) {console.log('Dynamically Loading Amplitude Player Script...');}
300			el = document.createElement('script'); el.src = radio_player.scripts.amplitude; head.appendChild(el); loading = true;
301		}
302	} else if (script == 'jplayer') {
303		if (typeof jQuery.jPlayer == 'undefined') {
304			if (radio_player.debug) {console.log('Dynamically Loading jPlayer Script...');}
305			el = document.createElement('script'); el.src = radio_player.scripts.jplayer; head.appendChild(el); loading = true;
306		}
307	} /* else if (script == 'audio5') {
308		if (typeof window.audio5 == 'undefined') {
309			if (radio_player.debug) {console.log('Dynamically Loading audio5 Player Script...');}
310			el = document.createElement('script'); el.src = radio_player.scripts.audio5; head.appendChild(el); loading = true;
311		}
312	} else if (script == 'howler') {
313		if (typeof window.Howl == 'undefined') {
314			if (radio_player.debug) {console.log('Dynamically Loading Howler Player Script...');}
315			el = document.createElement('script'); el.src = radio_player.scripts.howler; head.appendChild(el); loading = true;
316		}
317	} else if ( ( script == 'mediaelement') && (typeof mejs == 'undefined' ) ) {
318		el = document.createElement('script'); el.src = radio_player.scripts.media; head.appendChild(el);
319		el = document.createElement('script'); el.src = radio_player.scripts.elements; head.appendChild(el);
320		el = document.createElement('script'); el.src = funcs; head.appendChild(el);
321		loading = true;
322	} */
323	if (loading) {return false;}
324	return true;
325}
326
327/* --- player failed fallback to another script --- */
328function radio_player_player_fallback(instance, script) {
329	if (typeof radio_player.delayed_player != 'undefined') {clearInterval(radio_player.delayed_player);}
330	if (typeof radio_player_data.failed[instance] != 'undefined') {j = radio_player_data.failed[instance].length;}
331	else {radio_player_data.failed[instance] = []; j = 0;}
332
333	scripta = script+'-a'; scriptb = script+'-b';
334	if (!(scripta in radio_player_data.failed[instance])) {
335		radio_player_data.failed[instance][j] = scripta;
336	} else if (!(scriptb in radio_player_data.failed[instance])) {
337		radio_player_data.failed[instance][j] = scriptb;
338	}
339	jQuery('#radio_container_'+instance).removeClass('playing').removeClass('loaded');
340	data = radio_player_data.data[instance]; data.instance = instance;
341	radio_player_event_handler('failed', data);
342
343	/* retry different script with stored player instance data */
344	newscript = twoscript = false;
345	if (radio_player.scripts.length) {
346		for (k in radio_player.scripts) {
347			founda = foundb = false;
348			for (j = 0; j < radio_player_data.failed[instance].length; j++) {
349				if (radio_player_data.failed[instance][j] == k+'-a') {founda = true;}
350				if (radio_player_data.failed[instance][j] == k+'-b') {foundb = true;}
351			}
352			if (!founda || !foundb) {
353				if (!newscript) {newscript = k;} else {twoscript = k;}
354			}
355		}
356	}
357	
358	/* maybe swap to fallback stream data to retry */
359	if (newscript && !foundb) {
360		if (data.fallback != '') {
361			if (radio_player.debug) {console.log('Switching to Fallback Stream');}
362			tmpa = data.url; data.url = data.fallback; data.fallback = tmpa;
363			tmpb = data.format; data.fformat = data.format; data.fformat = tmpb;
364			data.switched = true; radio_player_data.data[instance] = data;
365			radio_player_load_audio(newscript,instance,data,data.start); return;
366		} else {
367			/* no fallback, set as failed and try next script */
368			j++; radio_player_data.failed[instance][j] = scriptb;
369			if (twoscript) {newscript = twoscript;} else {newscript = false;}
370		}
371	}
372
373	/* try new script */
374	if (newscript) {
375		if ((typeof data.switched != 'undefined') && data.switched) {
376			/* switch data back to original for new script retry */
377			tmpa = data.url; data.url = data.fallback; data.fallback = tmpa;
378			tmpb = data.format; data.fformat = data.format; data.fformat = tmpb;
379			data.switched = false; radio_player_data.data[instance] = data;
380		}
381		radio_player_data.data[instance].script = newscript;
382		if (radio_player.debug) {console.log('Trying New Player Script: '+newscript); console.log(data);}
383		radio_player_load_audio(newscript,instance,data,data.start);
384	} else {
385		if (radio_player.debug) {console.log('Exhausted All Player Script Type Attempts');}
386		radio_player_data.failed = []; /* reset */
387	}
388}
389
390/* --- show manual script switcher --- */
391function radio_player_show_switcher(instance) {
392	jQuery('#radio_container_'+instance+' .rp-show-switcher').hide();
393	jQuery('#radio_container_'+instance+' .rp-script-select').show();
394}
395
396/* --- switch player script --- */
397function radio_player_switch_script(instance, script) {
398	radio_player.loading = true;
399	data = radio_player_data.data[instance];
400	if ((typeof radio_player_data.players[instance] != 'undefined') && (typeof radio_player_data.scripts[instance] != script)) {radio_player_stop_instance(instance,true);}
401	player = radio_player_load_audio(script,instance,data,data.start);
402	if (player && data.start) {radio_player_play_on_load(player,script,instance);}
403}
404
405/* === Player Functions and Event Callbacks === */
406
407/* --- get player source --- */
408function radio_player_get_source(player, script) {
409	src = false;
410	if (script == 'amplitude') {src = player.getAudio().src;}
411	else if (script == 'jplayer') {src = player.data('jPlayer').status.src;}
412	/* else if (script == 'audio5') {src = player.???;} */
413	/* else if (script == 'howler') {src = player.???;} */
414	return src;
415}
416
417/* --- get instance audio element --- */
418function radio_player_audio_element(instance) {
419	if (typeof radio_player_data.players[instance] == 'undefined') {return false;}
420	player = radio_player_data.players[instance];
421	script = radio_player_data.scripts[instance];
422	if (script == 'amplitude') {audio = player.getAudio();}
423	else if (script == 'jplayer') {audio = player.data('jPlayer').htmlElement.audio;}
424	/* else if (script == 'howler') {audio = ???;} */
425	return audio;
426}
427
428/* --- get event source --- */
429function radio_player_event_source(e) {
430	src = false; instance = e.detail.instance;
431	if (e.detail.player != null) {
432		player = e.detail.player; script = e.detail.script;
433		src = radio_player_get_source(player,script);
434	} else if (typeof radio_player_data.players[instance] != 'undefined') {
435		player = radio_player_data.players[instance];
436		script = radio_player_data.scripts[instance];
437		src = radio_player_get_source(player,script);
438	} else if (typeof radio_player_data.data[instance] != 'undefined') {
439		src = radio_player_data.data[instance].url;
440	}
441	return src;
442}
443	
444/* --- get data for channel id --- */
445function radio_player_channel_data(channel) {
446	for (i in radio_player_data.channels) {
447		data = radio_player_data.channels[i];
448		if (parseInt(data.id) == parseInt(channel)) {return data;}
449	}
450	return false;
451}
452
453/* --- get data for station id --- */
454function radio_player_station_data(station) {
455	for (i in radio_player_data.stations) {
456		data = radio_player_data.stations[i];
457		if (parseInt(data.id) == parseInt(station)) {return data;}
458	}
459	return false;
460}
461
462/* --- play source --- */
463function radio_player_play_source(instance) {
464	container = jQuery('#radio_container_'+instance);
465	script = radio_player.settings.script;
466	if (typeof container.attr('data-script') != 'undefined') {script = container.attr('data-script');}
467	
468	data = radio_player_get_data(instance);
469	if (data.type == 'file') {
470		radio_player_load_file(script, instance, data, true);
471	} else if (data.type == 'channel') {
472		radio_player_load_channel(script, instance, data, true);
473	} else if (data.type == 'station') {
474		radio_player_load_station(script, instance, data, true);
475	} else if (data.type == 'stream') {
476		radio_player_load_stream(script, instance, data, true);
477	} else if (data.type == 'hls') {
478		radio_player_load_hls(script, instance, data, true);
479	}
480}
481
482/* --- get data to play --- */
483function radio_player_get_data(instance) {
484	container = jQuery('#radio_container_'+instance);
485	data = false; /* ensure reset */
486	if (typeof container.attr('data-href') != 'undefined') {
487		href = container.attr('data-href');
488		if (href.trim() != '') {
489			format = container.attr('data-format');
490			fallback = container.attr('data-fallback');
491			fformat = container.attr('data-fformat');
492			data = {url:href, format:format, fallback:fallback, fformat:fformat, type:'file'};
493			if (radio_player.debug) {console.log('File Source Data:');}
494		}
495	}
496	if (!data) {
497		/* get HLS data */
498		if ((typeof container.attr('data-hls') != 'undefined') && (container.attr('data-hls') != '')) {
499			url = container.attr('data-hls');
500			channel = parseInt(container.attr('data-channel'));
501			if (Number.isNaN(channel)) {channel = 0;}
502			data = {url:url, format:'hls', fallback:false, fformat:false, channel:channel, type:'hls'};
503			if (radio_player.debug) {console.log('HLS Source Data:');}
504		}
505	}
506	if (!data) {
507		/* get channel data */
508		channel = parseInt(container.attr('data-channel'));
509		if (!Number.isNaN(channel)) {
510			data = radio_player_channel_data(channel); data.type = 'channel'; data.channel = channel;
511			if (radio_player.debug) {console.log('Channel Source Data:');}
512		}
513	}
514	if (!data) {
515		/* get station data */
516		station = parseInt(container.attr('data-station'));
517		if (!Number.isNaN(station)) {
518			data = radio_player_station_data(station); data.type = 'station'; data.station = station;
519			if (radio_player.debug) {console.log('Station Source Data:');}
520		}		
521	}
522	/* get default stream data */
523	if (!data) {
524		data = radio_player.stream_data; data.type = 'stream';
525		if (radio_player.debug) {console.log('Stream Source Data:');}
526	}
527	if (radio_player.debug) {console.log(data);}
528	return data;
529}
530				
531/* --- play player instance --- */
532var radio_player_retry = {}
533function radio_player_play_instance(instance) {
534	if (typeof radio_player_autoresume == 'object') {radio_player_autoresume.cancelled = true;}
535	if (radio_player_is_playing(instance)) {return;}
536	radio_player.loading = true;
537	container = jQuery('#radio_container_'+instance);
538	if (container.hasClass('rewound') || container.hasClass('timeshift')) {
539		audio = radio_player_audio_element(instance);
540		hls.config.autoStartLoad = true; hls.startLoad();
541		hls.attachMedia(audio);
542		audio.play().catch( () => { radio_player_hls_source(instance,false,true); });
543	} /* else { */
544		player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
545		if (script == 'amplitude') {player.play();}
546		else if (script == 'jplayer') {player.jPlayer('play');}
547		else if ((script == 'audio5') || (script == 'howler')) {player.play();}
548		if (radio_player.debug) {console.log('Playing '+script+' Player Instance '+instance);}
549	/* } */
550	radio_player_custom_event('rp-play', {player:player, script:script, instance:instance});
551}
552
553/* --- pause player instance --- */
554function radio_player_pause_instance(instance) {
555	/* if (!radio_player_is_loading(instance) && !radio_player_is_playing(instance)) {return;} */
556	player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
557	detail = {player:player, script:script, instance:instance};
558	radio_player_custom_event('rp-before-pause', detail);
559	if (radio_player.debug) {console.log('Pausing '+script+' Player Instance '+instance);}
560	container = jQuery('#radio_container_'+instance);
561	audio = radio_player_audio_element(instance);
562	if (script == 'amplitude') {
563		if (container.hasClass('rewound') || container.hasClass('timeshift')) {audio.pause();}
564		else {src = player.getAudio().src;}
565	}
566	if ((script == 'amplitude') || (script == 'audio5') || (script == 'howler')) {player.pause();}
567	else if (script == 'jplayer') {player.jPlayer('pause');}
568	if (script == 'amplitude') {
569		/* amplitude empty src on pause error fix! */
570		if (container.hasClass('rewound') || container.hasClass('timeshift')) {
571			hls.config.autoStartLoad = false; hls.stopLoad();
572			/* hls.attachMedia(audio); */ audio.pause();
573		} else {player.getAudio().src = src;}
574	}
575	radio_player_custom_event('rp-pause', detail);
576}
577
578/* --- stop player instance --- */
579function radio_player_stop_instance(instance) {
580	player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
581	if (radio_player.debug) {console.log('Stopping '+script+' Player Instance '+instance);}
582	if (script == 'amplitude') {
583		/* ? amplitude bug: 'stop is not a function'! ? */
584		try {player.stop();} catch(e) {player.pause();}
585	} else if (script == 'jplayer') {player.jPlayer('stop');}
586	else if (script == 'audio5') {player.destroy();}
587	else if (script == 'howler') {player.unload();}
588	radio_player_custom_event('rp-stop', {player:player, script:script, instance:instance});
589}
590
591/* --- mute or unmute player --- */
592function radio_player_mute_instance(instance, player, script, mute) {
593	container = jQuery('#radio_container_'+instance);
594	if (script == 'amplitude') {
595		volume = player.getVolume();
596		if (mute) {
597			container.attr('data-volume',volume);
598			if (radio_player.debug) {console.log('Set Pre-muted Volume: '+volume);}
599			player.setVolume(0);
600		} else if (volume == 0) {
601			if (typeof container.attr('data-volume') != 'undefined') {
602				volume = container.attr('data-volume');
603				if (radio_player.debug) {console.log('Restore Pre-muted Volume: '+volume);}
604				try {player.setVolume(volume);} catch(e) {}
605			}
606		}
607	} else if (script == 'audio5') {
608		volume = player.volume();
609		if (mute) {
610			container.attr('data-volume',(volume * 100));
611			if (radio_player.debug) {console.log('Set Pre-muted Volume: '+volume);}
612			player.volume(0);
613		} else if (volume == 0) {
614			if (typeof container.attr('data-volume') != 'undefined') {
615				volume = parseInt(container.attr('data-volume')) / 100;
616				if (radio_player.debug) {console.log('Restore Pre-muted Volume: '+volume);}
617				try {player.volume(volume);} catch(e) {}
618			}
619		}
620	} else if (script == 'jplayer') {
621		if (mute) {player.jPlayer('mute');} else {player.jPlayer('unmute');}
622	} else if (script == 'howler') {
623		if (mute) {player.mute(true);} else {player.mute(false);}
624	}
625}
626
627/* --- check if player is playing */
628function radio_player_is_playing(instance) {
629	instances = Object.keys(radio_player_data.players);
630	if (!instances.includes(instance)) {return false;}
631	player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
632	if (script == 'amplitude') {
633		state = player.getPlayerState();
634		playing = (state == 'playing');
635	} else if (script == 'jplayer') {
636		/* ? possible bug: get status not working ? */
637		try {playing = !player.data('jPlayer').status.paused;}
638		catch(e) {playing = !player.data().jPlayer.status.paused;}
639	} else if (script == 'audio5') {
640		playing = player.playing;
641	} else if (script == 'howler') {
642		playing = player.playing();
643	}
644	if (radio_player.debug) {
645		if (playing) {console.log('Player Instance '+instance+' ('+script+') is playing.');}
646		else {console.log('Player Instance '+instance+' ('+script+') is not playing.');}
647	}
648	return playing;
649}
650
651/* --- check if player instance is loading --- */
652function radio_player_is_loading(instance) {
653	player = jQuery('#radio_player_'+instance);
654	if (player.hasClass('loading')) {return true;}
655	return false;	
656}
657	
658/* --- change player volume --- */
659function radio_player_change_volume(instance, volume) {
660	container = jQuery('#radio_container_'+instance);
661	container.attr('data-volume',volume);
662	if ((volume == 100) && !container.hasClass('maxed')) {container.addClass('maxed');}
663	else {container.removeClass('maxed');}
664	slider = jQuery('#radio_container_'+instance+' .rp-volume-slider');
665	if (!slider.hasClass('changed')) {slider.addClass('changed');}
666
667	if (typeof radio_player_data.players[instance] != 'undefined') {
668		player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
669		radio_player_set_volume(instance,volume);
670		detail = {player:player, script:script, instance:instance, volume:volume};
671		radio_player_custom_event('rp-volume', detail);
672	} else {
673		detail = {player:null, script: null, instance: instance, volume: volume};
674	}
675	radio_player_custom_event('rp-volume',detail);
676}
677
678/* --- set player volume --- */
679function radio_player_set_volume(instance, volume) {
680	player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
681	if (script == 'amplitude') {
682		player.setVolume(volume); newvolume = player.getVolume();
683		if (radio_player.debug) {console.log('Amplitude New Volume: '+volume+' - Now: '+newvolume);}
684	} else if (script == 'jplayer') {
685		volume = parseFloat(volume / 100);
686		/* note: this catches (browser?) error "cannot set to non-finite value" in jPlayer _html_setProperty */
687		try {player.jPlayer('volume', volume); newvolume = player.jPlayer('volume');} catch(e) {}
688		if (radio_player.debug) {console.log('jPlayer New Volume: '+volume+' - Now: '+newvolume);}
689	} else if (script == 'audio5') {
690		volume = parseFloat(volume / 100);
691		player.volume(volume); newvolume = player.volume();
692		if (radio_player.debug) {console.log('audio5 New Volume: '+volume+' - Now: '+newvolume);}
693	} else if (script == 'howler') {
694		volume = parseFloat(volume / 100);
695		player.volume(volume); newvolume = player.volume();
696		if (radio_player.debug) {console.log('Howler New Volume: '+volume+' - Now: '+newvolume);}
697	}
698}
699
700/* --- get player volume --- */
701function radio_player_get_volume(instance) {
702	player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
703	if (script == 'amplitude') {volume = player.getVolume();}
704	else if (script == 'jplayer') {volume = (player.jPlayer('volume') * 100);}
705	else if ((script == 'audio5') || (script == 'howler')) {volume = (player.volume() * 100);}
706	return volume;
707}
708
709/* --- set all volume sliders --- */
710function radio_player_volume_sliders(volume) {
711	jQuery('.radio-container').each(function() {
712		instance = jQuery(this).attr('data-instance');
713		radio_player_volume_slider(instance,volume);
714	});
715}
716
717/* --- set slider volume with background div width fix --- */
718function radio_player_volume_slider(instance, volume) {
719	jQuery('#radio_container_'+instance+', #rp_container_'+instance).each(function() {
720		slider = jQuery(this).find('.rp-volume-slider');
721		slider.addClass('changed');
722		sliderbg = jQuery(this).find('.rp-volume-slider-bg');
723		thumb = jQuery(this).find('.rp-volume-thumb');
724		if (slider.length) {
725			sliderbg.hide(); slider.val(volume); swidth = slider.width();
726			thumb.show(); twidth = thumb.width(); thumb.hide();
727			mwidth = parseInt(sliderbg.css('margin-left').replace('px',''));
728			bgwidth = parseInt((swidth - twidth) * (volume / 100)) - mwidth;
729			sliderbg.attr('style', 'width: '+bgwidth+'px !important;').show();
730			/* if (radio_player.debug) {
731				newwidth = parseInt(sliderbg.css('width')); console.log('Volume Slider BF: Slider '+swidth+' : Thumb '+twidth+' : Margin '+mwidth+' : BG '+bgwidth+' : Now '+newwidth);
732			} */
733			if (volume == 0) {jQuery(this).addClass('minned');} else {jQuery(this).removeClass('minned');}
734			if (volume == 100) {jQuery(this).addClass('maxed');} else {jQuery(this).removeClass('maxed');}	
735		}
736	});
737}
738
739/* --- mute or unmute a player -- */
740function radio_player_mute_unmute(instance, mute) {
741	jQuery('#radio_container_'+instance+', #rp_container_'+instance).each(function() {
742		if (mute) {jQuery(this).addClass('muted').removeClass('maxed');} else {jQuery(this).removeClass('muted');}
743	});
744	detail = {player:null, script:null, instance:instance, mute:mute};
745	if (typeof radio_player_data.players[instance] != 'undefined') {
746		player = radio_player_data.players[instance]; script = radio_player_data.scripts[instance];
747		radio_player_mute_instance(instance,player,script,mute);
748		detail = {player:player, script:script, instance:instance, mute:mute};
749	}
750	if (mute) {radio_player_custom_event('rp-muted', detail);}
751	else {radio_player_custom_event('rp-unmuted', detail);}
752}
753	
754/* --- get page default instance --- */
755function radio_player_default_instance() {
756	instance = false;
757	jQuery('.radio-player').each(function() {
758		if (!instance && jQuery(this).hasClass('default-player')) {
759			instance = parseInt(jQuery(this).attr('id').replace('radio_player_', ''));
760			return instance;
761		}
762	});
763	return instance;
764}
765
766/* --- pause all other instances */
767function radio_player_pause_others(instance) {
768	if (!radio_player.settings.singular) {return;}
769	if (typeof radio_player_toggle_current == 'function') {return;} /* skip for pro */
770	/* broadcast playing message to other windows */
771	radio_player_broadcast_playing(instance);
772}
773
774/* --- get instance from event target --- */
775function radio_player_event_instance(e, name, script) {
776	instance = false;
777	if (radio_player.debug) {
778		console.log(script+' Player Event: '+name);
779		if ((script == 'jplayer') && (typeof e.jPlayer.error != 'undefined')) {console.log(e.jPlayer.error);}
780		else if ((typeof e.target.error != 'undefined') && (e.target.error != null)) {console.log(e.target.error);}
781	}
782	if ((typeof e.target != 'undefined') && (e.target != null)) {
783		if (radio_player.debug) {console.log('Event Target'); console.log(e.target);}
784		if (e.target.hasAttribute('instance-id')) {
785			instance = e.target.getAttribute('instance-id');
786		} else if (jQuery(e.target)) {
787			instance = parseInt(jQuery(e.target).attr('id').replace('radio_player_',''));
788		}
789	}
790	/* if (instance && radio_player.debug) {console.log('Event Player Instance: '+instance);} */
791	return instance;
792}
793
794/* --- match instance from player object --- */
795function radio_player_match_instance(obj, e, script) {
796	instance = false;
797	for (i = 0; i < radio_player_data.players.length; i++) {
798		if (obj == radio_player_data.players[i]) {instance = i;}
799	}
800	return instance;
801}
802
803/* --- player event handler --- */
804function radio_player_event_handler(action, detail) {
805	if (typeof detail != 'object') {
806		if (radio_player.debug) {console.log('Event Handler Error for Action: '+action); console.log(detail);}
807		return;
808	}
809	instance = detail.instance; script = detail.script;
810	if (radio_player.debug) {console.log(script+' Player Instance '+instance+' : '+action);}
811	jQuery('#radio_container_'+instance+', #rp_container_'+instance).each(function() {
812		if (action == 'loading') {jQuery(this).removeClass('loaded playing stopped paused error');}
813		else if (action == 'loaded') {jQuery(this).removeClass('loading error');}
814		else if (action == 'playing') {jQuery(this).removeClass('paused stopped error');}
815		else if (action == 'paused') {jQuery(this).removeClass('playing stopped'); }
816		else if (action == 'stopped') {jQuery(this).removeClass('playing paused loaded loading'); radio_player_set_state('playing',false);}
817		else if (action == 'error') {jQuery(this).removeClass('playing paused loaded loading');}
818		if (!jQuery(this).hasClass(action)) {jQuery(this).addClass(action);}
819	});
820	if (action == 'playing') {radio_player_set_state('playing',true);}
821	if ((action == 'paused') || (action == 'stopped')) {radio_player_set_state('playing',false);}
822	radio_player_custom_event('rp-'+action, detail);
823}
824
825/* --- player volume changed --- */
826function radio_player_volume_changed(instance, script, volume) {
827	if (radio_player.debug) {console.log(script+' Player Instance '+instance+': Changed Volume to '+volume);}
828	slider = jQuery('#radio_container_'+instance+' .rp-volume-slider');
829	if (!slider.hasClass('changed')) {jQuery('#radio_container_'+instance+' .rp-volume-slider').addClass('changed');}
830
831	radio_player_custom_event('rp-volume-changed', {instance:instance, script:script, volume:volume});
832	radio_player_set_state('volume', volume);
833}
834
835/* --- sleep delay function (blocking!) --- */
836function radio_player_sleep_delay(sleep_ms) {
837	var radio_player_sleep_start = new Date().getTime();
838	while (sleep_ms > (new Date().getTime() - radio_player_sleep_start)) {}
839}
840
841/* === User Player State Functions === */
842
843/* --- load player state --- */
844function radio_player_load_state() {
845	if (typeof radio_player_data.state.checked == 'undefined') {
846		playing = radio_player_cookie.get('playing');
847		if (playing) {radio_player_data.state.playing = playing;}
848		channel = radio_player_cookie.get('channel');
849		if (channel != null) {radio_player_data.state.channel = channel;}
850		station = radio_player_cookie.get('station');
851		if (station != null) {radio_player_data.state.station = station;}
852		volume = radio_player_cookie.get('volume');
853		if (volume != null) {radio_player_data.state.volume = volume;}
854		mute = radio_player_cookie.get('mute');
855		if (mute != null) {radio_player_data.state.mute = mute;}
856		if (radio_player.debug) {
857			console.log('Loaded User Player State - Playing: '+playing+' - Station: '+station+' - Volume: '+volume+ ' - Muted: '+mute+' - Data: ');
858		}
859		data = radio_player_cookie.get('data');
860		if ((data != null) && (data.url != '')) {
861			radio_player_data.state.data = data;
862			if ((data.instance == false) || (data.instance == 'undefined')) {data.instance = 1;}
863			radio_player_data.data[data.instance] = data;
864			if (radio_player.debug) {console.log('Radio State Data:'); console.log(radio_player_data.data);}
865		}
866		if ((volume != null) && (data != null)) {radio_player_volume_sliders(volume);}
867		
868		/* set sync debug cookie switch */
869		if (typeof radio_player.sync_debug != 'undefined') {
870			if (radio_player.sync_debug == 'on') {
871				radio_player.sync_debug = true;
872				radio_player_cookie.set('sync_debug',1,7);
873			} else if (radio_player.sync_debug == 'off') {
874				radio_player.sync_debug = false;
875				radio_player_cookie.delete('sync_debug');
876			} else {
877				sync_debug = radio_player_cookie.get('sync_debug');
878				if (sync_debug != null) {radio_player.sync_debug = true;}
879				else {radio_player.sync_debug = false;}
880			}
881		} else {radio_player.sync_debug = false;}
882		radio_player_data.state.checked = true;
883	}
884}
885
886/* --- store user player state --- */
887function radio_player_set_state(key, value) {
888	changed = false;
889	if ((key == 'playing') && (value != radio_player_data.state.playing)) {
890		radio_player_cookie.set('playing', value, 7);
891		radio_player_data.state.playing = value; changed = true;
892	} else if ((key == 'channel') && value && (value > 0) && (value != radio_player_data.state.channel)) {
893		radio_player_cookie.set('channel', value, 30);
894		radio_player_data.state.channel = value; changed = true;
895	} else if ((key == 'station') && value && (value > 0) && (value != radio_player_data.state.station)) {
896		radio_player_cookie.set('station', value, 30);
897		radio_player_data.state.station = value; changed = true;
898	} else if ((key == 'volume') && (value != radio_player_data.state.volume)) {
899		radio_player_cookie.set('volume', value, 365);
900		radio_player_data.state.volume = value; changed = true;
901	} else if ((key == 'mute') && (value != radio_player_data.state.mute)) {
902		radio_player_cookie.set('mute', value, 1);
903		radio_player_data.state.mute = value; changed = true;
904	}
905	if (changed) {radio_player_data.state.changed = true;}
906	detail = {'state': radio_player_data.state}
907	radio_player_custom_event('rp-set-state', detail);
908}
909
910/* --- store player instance data */
911function radio_player_set_data_state(script, instance, data, start) {
912	url = data.url; format = data.format; fallback = data.fallback; fformat = data.fformat; type = data.type;
913	if (typeof radio_player_data.data[instance] != 'undefined') {
914		cdata = radio_player_data.data[instance];
915		if ( (cdata.script != script) || (cdata.url != url) || (cdata.format != format) || (cdata.fallback != fallback) || (cdata.fformat != fformat) || (cdata.start != start) ) {
916			radio_player_data.failed[instance] = new Array();
917		}
918		radio_player.previous_data = data;
919	}
920	data = {'script':script, 'instance':instance, 'url':url, 'format':format, 'fallback':fallback, 'fformat':fformat, 'type':type, 'start':start};
921	if (radio_player.debug) {console.log('Setting Data State:'); console.log(data);}
922	radio_player_data.data[instance] = data;
923	if (radio_player_data.state.data != data) {
924		radio_player_data.state.data = data;
925		radio_player_cookie.set('data', data, 7);
926		radio_player_data.state.changed = true;
927	}
928}
929
930/* --- save user meta values --- */
931function radio_player_save_user_state() {
932	if (radio_player_data.state.changed) {
933		state = radio_player_data.state;
934		if (state.loggedin && !state.saving) {
935			if (state.playing) {playing = '1';} else {playing = '0';}
936			if (state.station) {station = state.station;} else {station = '0';}
937			if (state.channel) {channel = state.channel;} else {channel = '0';}
938			if (state.volume) {volume = state.volume;} else {volume = '';}
939			if (state.mute) {mute = '1';} else {mute = '0';}
940			timestamp = Math.floor( (new Date()).getTime() / 1000 );
941			url = radio_player.settings.ajaxurl+'?action=radio_player_state';
942			/* ? TODO: instance ? */
943			url += '&playing='+playing+'&station='+station+'&channel='+channel+'&volume='+volume+'&mute='+mute+'&timestamp='+timestamp;
944			if (radio_player.debug) {url += '&player-debug=1';}
945			/* document.getElementById('radio-player-state-iframe').src = url; */
946			radio_player_data.state.saving = true;
947			jQuery.get(url, function(data) {
948				if (radio_player.debug) {console.log(data);}
949				radio_player_data.state.saving = false;
950			});
951		}
952	}
953	radio_player_data.state.changed = false;
954}
955
956/* --- volume change audio test --- */
957/* ref: https://stackoverflow.com/a/62094756/5240159 */
958/* 2.5.6: fix radio.debug to radio_player.debug */
959/* 2.5.13: append testaudio to document body for more robust test */
960function radio_player_volume_test() {
961	isIOS = ['iPad Simulator','iPhone Simulator','iPod Simulator','iPad','iPhone','iPod'].includes(navigator.platform);
962	if (radio_player.debug && isIOS) {console.log('iOS Mobile Device Detected. ');}
963    isAppleDevice = navigator.userAgent.includes('Macintosh');
964	if (radio_player.debug && isAppleDevice) {console.log('Apple Device Detected.');}
965    isTouchScreen = navigator.maxTouchPoints >= 1;
966	if (radio_player.debug && isTouchScreen) {console.log('Touch Screen Detected. ');}
967	iosAudioFailure = false; testaudio = new Audio(); document.body.appendChild(testaudio);
968	try {testaudio.volume = 0.5;} catch(e) {if (radio_player.debug) {console.log('Caught Volume Change Error.');} iosAudioFailure = true;}
969	if (testaudio.volume === 1) {if (radio_player.debug) {console.log('Volume could not be changed.');} iosAudioFailure = true;}
970    return isIOS || (isAppleDevice && (isTouchScreen || iosAudioFailure));
971}
972
973/* === Multi-Window/Tab Support === */
974
975/* --- set/get window tab unique ID --- */
976function radio_player_window_guid() {
977	if (!window.tabId) {
978		if (window.sessionStorage.tabId) {
979			window.tabId = window.sessionStorage.tabId;
980			window.sessionStorage.removeItem('tabId');
981		} else {
982			window.tabId = Math.floor(Math.random() * 10000000);
983		}
984	}
985	/* console.log('Window Guid:'+window.tabId); */
986	return window.tabId;
987}
988
989/* --- broadcast pause all message to other windows --- */
990function radio_player_broadcast_playing(instance) {
991	if ((instance === false) || (typeof sysend == 'undefined')) {return;}
992	if (!radio_player.settings.singular) {return;}
993
994	action = 'pauseothers';
995	player = radio_player_data.players[instance];
996	script = radio_player_data.scripts[instance]
997	url = radio_player_get_source(player,script);
998	windowid = radio_player_window_guid();
999	
1000	message = windowid+'::'+instance+'::'+action+'::'+url;
1001	if (radio_player.sync_debug) {console.log('Broadcast Message: '+message);}
1002	sysend.broadcast('radio-play', {message: message});
1003}
1004
1005/* --- check to pause player on receiving message --- */
1006function radio_player_check_to_pause(broadcast) {
1007	if (!radio_player.settings.singular) {return;}
1008	parts = broadcast.message.split('::');
1009	winid = parseInt(parts[0]); winstance = parseInt(parts[1]); action = parts[2]; url = parts[3];
1010	if (radio_player.sync_debug) {console.log('Received Message from Window ID '+winid+' Instance '+winstance+' Type '+action+' URL '+url);}
1011	windowid = radio_player_window_guid();
1012	if (!radio_player_data.players.length) {return;}
1013	for (instance in radio_player_data.players) {
1014		if ( (winid != windowid) || ((winid == windowid) && (winstance != instance)) ) {
1015			if (radio_player_is_playing(instance)) {
1016				if (radio_player.sync_debug) {console.log('Pausing Window '+windowid+' Instance '+instance);}
1017				radio_player_pause_instance(instance);
1018			}
1019		}
1020	}
1021}
1022
1023
1024/* === Audio Player Scripts === */
1025
1026/* Amplitude Player Script */
1027var radio_player_amp_doc_listeners = false;
1028function radio_player_amplitude(instance, url, format, fallback, fformat) {
1029
1030	container = jQuery('#radio_container_'+instance);
1031	if (url == '') {url = radio_player.settings.url;}
1032	if (url == '') {return;}
1033	if (!format || (format == '')) {format = 'aac';}
1034	/* if (fallback == '') {fallback = radio_player.settings.fallback;} */
1035	if (!fallback || !fformat || (fformat == '')) {fallback = ''; fformat = '';}
1036
1037	/* set song streams */
1038	songs = new Array();
1039	songs[0] = {'name': '',	'artist': '', 'album': '', 'url': url, 'cover_art_url': '',	'live': true};
1040	/* if ('' != fallback) {songs[1] = {'name': '', 'artist': '', 'album': '', 'url': fallback, 'cover_art_url': '', 'live': true};} */
1041
1042	/* set volume */
1043	if (container.find('.rp-volume-slider').length && container.find('.rp-volume-slider').hasClass('changed')) {
1044		volume = container.find('.rp-volume-slider').val();
1045	} else if (typeof container.attr('data-volume') != 'undefined') {
1046		volume = container.attr('data-volume');
1047	} else if (typeof radio_player_data.state.volume != 'undefined') {
1048		volume = radio_player_data.state.volume;
1049	} else {volume = radio_player.settings.volume;}
1050	radio_player_volume_slider(instance, volume);
1051
1052	/* initialize player */
1053	if (radio_player.debug) {console.log('Init Amplitude: '+instance+' : '+url+' : '+format+' : '+fallback+' : '+fformat+' : '+volume);}
1054	radio_player_instance = Amplitude;
1055	radio_player_instance.init({
1056		'debug': radio_player.debug,
1057		'songs': songs,
1058		'volume': volume,
1059		'volume_increment': 5,
1060		'volume_decrement': 5,
1061		'continue_next': false,
1062		'preload': 'none',
1063	});
1064	radio_player_data.players[instance] = radio_player_instance;
1065	radio_player_data.scripts[instance] = 'amplitude';
1066
1067	/* set instance on audio source */
1068	audio = radio_player_instance.getAudio();
1069	if (radio_player.debug) {console.log('Amplitude Audio Element:'); console.log(audio);}
1070	audio.setAttribute('instance-id', instance);
1071
1072	/* amp 5.0.3 bind loaded to canplay event (as initialized callback not firing!) */
1073	/* amp 5.3.2 initialized callback is now firing */
1074	audio.addEventListener('canplay', function(e) {
1075		radio_player.loading = false;
1076		instance = radio_player_event_instance(e, 'Loaded', 'amplitude');
1077		radio_player_event_handler('loaded', {instance:instance, script:'amplitude'});
1078	}, false);
1079
1080	/* amp 5.0.3: bind play(ing) event (as play callback not firing!) */
1081	/* amp 5.3.2: play callback is now firing */
1082	audio.addEventListener('playing', function(e) {
1083		radio_player.loading = false;
1084		instance = radio_player_event_instance(e, 'Playing', 'amplitude');
1085		radio_player_event_handler('playing', {instance:instance, script:'amplitude'});
1086		radio_player_pause_others(instance);
1087	}, false);
1088
1089	/* bind volume change event */
1090	audio.addEventListener('volumechange', function(e) {
1091		instance = radio_player_event_instance(e, 'Volume', 'amplitude');
1092		if (instance && (radio_player_data.scripts[instance] == 'amplitude')) {
1093			volume = radio_player_data.players[instance].getConfig().volume;
1094			radio_player_volume_changed(instance, 'amplitude', volume);
1095		}
1096	}, false);
1097	
1098	/* bind error event (as event not being passed in callback) */
1099	/* warning: triggered if audio src is not reset after pause! */
1100	audio.addEventListener('error', function(e) {
1101		if ((typeof e.target.error.code != 'undefined') && e.target.error.code == 4) {
1102			if (radio_player.debug) {console.log('Skipping Amplitude Empty Audio Source Bug');}
1103			return;
1104		}
1105		instance = radio_player_event_instance(e, 'Error', 'amplitude');
1106		if (radio_player.debug) {console.log('Amplitude Error Event'); console.log(e);}
1107		radio_player_event_handler('error', {instance:instance, script:'amplitude'});
1108		radio_player_player_fallback(instance, 'amplitude', 'Amplitude Error');
1109	}, false);
1110
1111	/* add document listeners only once */
1112	if (!radio_player_amp_doc_listeners) {
1113		radio_player_amp_doc_listeners = true;
1114
1115		/* listen for pause event */
1116		document.addEventListener('rp-pause', function(e) {
1117			instance = e.detail.instance;
1118			if (radio_player_data.scripts[instance] == 'amplitude') {
1119				radio_player_event_handler('paused', {instance:instance, script:'amplitude'});
1120			}
1121		}, false);
1122		
1123		/* listen for stop event */
1124		document.addEventListener('rp-stop', function(e) {
1125			instance = e.detail.instance;
1126			if (radio_player_data.scripts[instance] == 'amplitude') {
1127				radio_player_event_handler('stopped', {instance:instance, script:'amplitude'});
1128			}
1129		}, false);
1130	}
1131
1132	/* match script select dropdown value */
1133	if (container.find(' .rp-script-select').length) {container.find('.rp-script-select').val('amplitude');}
1134
1135	return radio_player_instance;
1136}
1137
1138
1139/* jPlayer Player Script */
1140function radio_player_jplayer(instance, url, format, fallback, fformat) {
1141
1142	player_id = 'radio_player_'+instance;
1143	container_id = 'radio_container_'+instance;
1144	container = jQuery('#'+container_id);
1145	if (url == '') {url = radio_player.settings.url;}
1146	if (url == '') {return;}
1147	if (!format || (format == '') || (format == 'aac')) {format = 'm4a';}
1148	/* if (fallback == '') {fallback = radio_player.settings.fallback;} */
1149	if (!fallback || !fformat || (fformat == '')) {fallback = ''; fformat = '';}
1150	if (fformat == 'aac') {fformat = 'm4a';}
1151
1152	/* set volume */
1153	if (container.find('.rp-volume-slider').length && container.find('.rp-volume-slider').hasClass('changed')) {
1154		volume = container.find('.rp-volume-slider').val();
1155	} else if (typeof container.attr('data-volume') != 'undefined') {
1156		volume = container.attr('data-volume');
1157	} else if (typeof radio_player_data.state.volume != 'undefined') {
1158		volume = radio_player_data.state.volume;
1159	} else {volume = radio_player.settings.volume;}
1160	radio_player_volume_slider(instance,volume);
1161	volume = parseFloat(volume / 100);
1162	if (radio_player.debug) {console.log('jPlayer init Volume: '+volume);}
1163
1164	media = {}; /* media.title = ''; */ media[format] = url; supplied = format;
1165	/* if (fallback && fformat) {media[fformat] = fallback; supplied += ', '+fformat;} */
1166	radio_player.jplayer_media = media;
1167	radio_player.jplayer_ready = false;
1168	radio_player.jplayer_instance = instance;
1169
1170	/* load jplayer */
1171	if (radio_player.debug) {console.log('Init jPlayer: '+instance+' : '+url+' : '+format+' : '+fallback+' : '+fformat+' : '+volume);}
1172	radio_player_instance = jQuery('#'+player_id).jPlayer({
1173		ready: function () {
1174			console.log(radio_player.jplayer_media);
1175			jQuery(this).jPlayer('setMedia', radio_player.jplayer_media);
1176			radio_player.jplayer_ready = true;
1177		},
1178		supplied: supplied,
1179		cssSelectorAncestor: '#'+container_id,
1180		swfPath: '', /* radio_player.settings.swf_path, */
1181		idPrefix: 'rp',
1182		preload: 'none',
1183		volume: volume,
1184		globalVolume: true,
1185		useStateClassSkin: true,
1186		autoBlur: false,
1187		smoothPlayBar: true,
1188		keyEnabled: true,
1189		remainingDuration: false,
1190		toggleDuration: false,
1191		backgroundColor: 'transparent',
1192	});
1193	radio_player_data.players[instance] = radio_player_instance;
1194	radio_player_data.scripts[instance] = 'jplayer';
1195
1196	audio = radio_player_instance.data('jPlayer').htmlElement.audio;
1197	if (radio_player.debug) {console.log('jPlayer Audio Element:'); console.log(audio);}
1198	audio.setAttribute('instance-id', instance);
1199
1200	/* bind load event */
1201	jQuery('#'+player_id).bind(jQuery.jPlayer.event.load, function(e) {
1202		radio_player.loading = false;
1203		instance = radio_player_event_instance(e, 'Loaded', 'jplayer');
1204		radio_player_event_handler('loaded', {instance:instance, script:'jplayer'});
1205	});
1206
1207	/* bind play event */
1208	jQuery('#'+player_id).bind(jQuery.jPlayer.event.play, function(e) {
1209		radio_player.loading = false;
1210		instance = radio_player_event_instance(e, 'Playing', 'jplayer');
1211		radio_player_event_handler('playing', {instance:instance, script:'jplayer'});
1212		radio_player_pause_others(instance);
1213	});
1214
1215	/* bind pause and stop events */
1216	jQuery('#'+player_id).bind(jQuery.jPlayer.event.pause, function(e) {
1217		instance = radio_player_event_instance(e, 'Paused', 'jplayer');
1218		radio_player_event_handler('paused', {instance:instance, script:'jplayer'});
1219	});
1220	jQuery('#'+player_id).bind(jQuery.jPlayer.event.stop, function(e) {
1221		instance = radio_player_event_instance(e, 'Stopped', 'jplayer');
1222		radio_player_event_handler('stopped', {instance:instance, script:'jplayer'});
1223	});
1224
1225	/* bind volume change event */
1226	jQuery('#'+player_id).bind(jQuery.jPlayer.event.volumechange, function(e) {
1227		instance = radio_player_event_instance(e, 'Volume', 'jplayer');
1228		if (instance && (radio_player_data.scripts[instance] == 'jplayer')) {
1229			radio_player_volume_changed(instance, 'jplayer', volume);
1230		}
1231	});
1232
1233	/* bind can play debug message */
1234	jQuery('#'+player_id).bind(jQuery.jPlayer.event.canplay, function(e) {
1235		instance = radio_player_event_instance(e, 'CanPlay', 'jplayer');
1236		console.log('jPlayer Instance '+instance+' Can Play');
1237	});
1238
1239	/* bind player error event to fallback scripts */
1240	jQuery('#'+player_id).bind(jQuery.jPlayer.event.error, function(e) {
1241		radio_player.jplayer_ready = false;
1242		instance = radio_player_event_instance(e, 'Error', 'jplayer');
1243		radio_player_event_handler('error', {instance:instance, script:'jplayer'});
1244		radio_player_player_fallback(instance, 'jplayer', 'jPlayer Error');
1245	});
1246
1247	/* match script select dropdown value */
1248	if (container.find('.rp-script-select').length) {container.find('.rp-script-select').val('jplayer');}
1249
1250	return radio_player_instance;
1251}
1252
1253/* Howler Player Script */
1254function radio_player_howler(instance, url, format, fallback, fformat) {
1255
1256	container = jQuery('#radio_container_'+instance);
1257	if (url == '') {url = radio_player.settings.url;}
1258	if (url == '') {return;}
1259	if (!format || (format == '')) {format = 'aac';}
1260	/* if (fallback == '') {fallback = radio_player.settings.fallback;} */
1261	if (!fallback || !fformat || (fformat == '')) {fallback = ''; fformat = '';}
1262
1263	/* set sources */
1264	sources = new Array(); formats = new Array();
1265	sources[0] = url; /* if (fallback != '') {sources[1] = fallback;} */
1266	formats[0] = format; /* if ((fallback != '') && (fformat != '')) {formats[1] = fformat;} */
1267
1268	/* set volume */
1269	if (container.find('.rp-volume-slider').length && container.find('.rp-volume-slider').hasClass('changed')) {
1270		volume = container.find('.rp-volume-slider').val();
1271	} else if (typeof container.attr('data-volume') != 'undefined') {
1272		volume = container.attr('data-volume');
1273	} else if (typeof radio_player_data.state.volume != 'undefined') {
1274		volume = radio_player_data.state.volume;
1275	} else {volume = radio_player.settings.volume;}
1276	radio_player_volume_slider(instance,volume);
1277	volume = parseFloat(volume / 100);
1278
1279	/* intialize player */
1280	if (radio_player.debug) {console.log('Init Howler: '+instance+' : '+url+' : '+format+' : '+fallback+' : '+fformat+' : '+volume);}
1281	radio_player_instance = new Howl({
1282		src: sources,
1283		format: formats,
1284		html5: false,
1285		autoplay: false,
1286		preload: false,
1287		volume: volume,
1288		onload: function(e) {
1289			/* possible bug: maybe not always being triggered ? */
1290			radio_player.loading = false;
1291			instance = radio_player_match_instance(this, e, 'howler');
1292			radio_player_event_handler('loaded', {instance:instance, script:'howler'});
1293		},
1294		onplay: function(e) {
1295			radio_player.loading = false;
1296			instance = radio_player_match_instance(this, e, 'howler');
1297			radio_player_event_handler('playing', {instance:instance, script:'howler'});
1298			radio_player_pause_others(instance);
1299		},
1300		onpause: function(e) {
1301			instance = radio_player_match_instance(this, e, 'howler');
1302			radio_player_event_handler('paused', {instance:instance, script:'howler'});
1303		},
1304		onstop: function(e) {
1305			instance = radio_player_match_instance(this, e, 'howler');
1306			radio_player_event_handler('stopped', {instance:instance, script:'howler'});
1307		},
1308		onvolume: function(e) {
1309			instance = radio_player_match_instance(this, e, 'howler');
1310			if (instance && (radio_player_data.scripts[instance] == 'howler')) {
1311				volume = this.volume() * 100;
1312				if (volume > 100) {volume = 100;}
1313				radio_player_volume_changed(instance, 'howler', volume);
1314			}
1315		},
1316		onloaderror: function(id,e) {
1317			instance = radio_player_match_instance(this, e, 'howler');
1318			radio_player_event_handler('error', {instance:instance, script:'howler'});
1319			if (radio_player.debug) {console.log('Load Error, Howler Instance: '+instance+', Sound ID: '+id);}
1320			radio_player_player_fallback(instance, 'howler', 'Howler Load Error');
1321		},
1322		onplayerror: function(id,e) {
1323			instance = radio_player_match_instance(this, e, 'howler');
1324			radio_player_event_handler('error', {instance:instance, script:'howler'});
1325			if (radio_player.debug) {console.log('Play Error, Howler Instance: '+instance+', Sound ID: '+id);}
1326			radio_player_player_fallback(instance, 'howler', 'Howler Play Error');
1327		},
1328	});
1329	radio_player_data.players[instance] = radio_player_instance;
1330	radio_player_data.scripts[instance] = 'howler';
1331
1332	/* match script select dropdown value */
1333	if (container.find('.rp-script-select').length) {container.find('.rp-script-select').val('howler');}
1334
1335	return radio_player_instance;
1336}
1337
1338
1339/* === Document Ready Functions === */
1340
1341/* --- add player event listeners --- */
1342var radio_player_initializing;
1343jQuery(document).ready(function() {
1344
1345	/* --- set window unique ID --- */
1346	radio_player_window_guid();
1347
1348	/* --- preserve window tab ID on tab reload --- */
1349	window.addEventListener('beforeunload', function (e) {
1350	    window.sessionStorage.tabId = window.tabId; return null;
1351	});
1352
1353	/* --- prevent conflict on duplicate script load --- */
1354	if (radio_player_initializing) {return;}
1355	radio_player_initializ
1355ing = true;
1356
1357	/* --- preload pause image --- */
1358	/* src = jQuery('.rp-pause-image-preload').attr('src');	image = new Image(); image.src = src; */
1359
1360	/* listen for window broadcast messages */
1361	if (typeof sysend != 'undefined') {
1362		sysend.on('radio-play', function(message) {radio_player_check_to_pause(message);} );
1363		/* sysend.on('radio-request', function(message) {radio_player_broadcast_action(message);} ); */
1364		radio_player_custom_event('rp-sysend', false);
1365	}
1366
1367	/* --- hide all volume controls if no support (iOS) --- */
1368	novolumesupport = radio_player_volume_test();
1369	if (novolumesupport) {
1370		jQuery('.rp-volume-controls').each(function() {
1371			jQuery(this).hide();
1372			jQuery('.rp-volume-button').hide();
1373			container = jQuery(this).closest('.radio-container');
1374			if (container.length) {container.addClass('no-volume-controls');}
1375			container = jQuery(this).closest('.rp-container');
1376			if (container.length) {container.addClass('no-volume-controls');}
1377		});
1378		jQuery('.rp-volume-button').hide();
1379	}
1380
1381	/* --- bind pause/play button clicks --- */
1382	jQuery('.rp-play-pause-button').on('click', function(e) {
1383		e.stopImmediatePropagation(); e.preventDefault();
1384		container = jQuery(this).closest('.radio-container');
1385		if (!container.length) {container = jQuery(this).closest('.rp-container');}
1386		instance = container.attr('data-instance');
1387		if (radio_player.debug) {console.log('Play/Pause Button Click on Instance '+instance);}
1388
1389		/* maybe toggle currently playing radio */
1390		inst = instance;
1391		if (typeof radio_player_toggle_current == 'function') {
1392			if (radio_player.debug) {console.log('Trigger Toggle of Player. New Instance '+instance);}
1393			done = radio_player_toggle_current(instance);
1394			if (done) {return;}
1395		}
1396		instance = inst; /* <- this is a fix */
1397		
1398		/* check to pause or play */
1399		if (radio_player_is_loading(instance) || radio_player_is_playing(instance)) {
1400			if (radio_player.debug) {console.log('Trigger Pause of Player Instance '+instance);}
1401			radio_player_pause_instance(instance);
1402		} else {
1403			if (radio_player.debug) {console.log('Trigger Play of Player Instance '+instance);}
1404			instances = Object.keys(radio_player_data.players);
1405			jQuery('#radio_player_'+instance).addClass('loading');
1406			if (instances.includes(instance)) {
1407				radio_player_play_instance(instance);
1408			} else {
1409				radio_player_play_source(instance);
1410			}
1411		}
1412	});
1413
1414	/* --- bind volume slider background changes --- */
1415	jQuery('.rp-volume-slider').on('mousemove', function() {
1416		container = jQuery(this).closest('.radio-container, .rp-container');
1417		instance = container.attr('data-instance');
1418		volume = parseInt(jQuery(this).val());
1419		radio_player_volume_slider(instance,volume);
1420	});
1421
1422	/* --- bind volume slider changes --- */
1423	jQuery('.rp-volume-slider').on('change', function() {
1424		container = jQuery(this).closest('.radio-container, .rp-container');
1425		instance = container.attr('data-instance');
1426		if (radio_player.debug) {console.log('Volume Click Instance '+instance+': '+volume);}
1427		volume = parseInt(jQuery(this).val());
1428		if (volume == 0) {mute = true;} else {mute = false;}
1429		radio_player_volume_slider(instance,volume);
1430		radio_player_change_volume(instance,volume);
1431		radio_player_set_state('volume',volume);
1432	});
1433
1434	/* ---- bind mute clicks --- */
1435	jQuery('.rp-mute').on('click', function() {
1436		container = jQuery(this).closest('.radio-container, .rp-container');
1437		instance = container.attr('data-instance');
1438		if (radio_player.debug) {console.log('Mute Click Instance '+instance);}
1439		if (typeof radio_player_toggle_mute == 'function') {
1440			done = radio_player_toggle_mute(instance); if (done) {return;}
1441		}
1442		mute = (!container.hasClass('muted'));
1443		radio_player_mute_unmute(instance,mute);
1444		radio_player_set_state('mute',mute);
1445	});
1446
1447	/* --- bind max volume clicks --- */
1448	jQuery('.rp-volume-max').on('click', function() {
1449		container = jQuery(this).closest('.radio-container, .rp-container');
1450		instance = container.attr('data-instance');
1451		if (!container.hasClass('maxed')) {container.addClass('maxed');}
1452		container.find('.rp-volume-slider').val(100);
1453		radio_player_volume_slider(instance,100);
1454		radio_player_change_volume(instance,100);
1455		radio_player_mute_unmute(instance,false);
1456		radio_player_set_state('mute',false);
1457	});
1458
1459	/* --- bind volume decrease/increase clicks --- */
1460	jQuery('.rp-volume-down, .rp-volume-up').on('click', function() {
1461		container = jQuery(this).closest('.radio-container, .rp-container');
1462		instance = container.attr('data-instance');
1463		slider = container.find('.rp-volume-slider');
1464		oldvolume = parseInt(slider.val());
1465		if (jQuery(this).hasClass('rp-volume-down')) {
1466			volume = oldvolume - 5; if (volume < 0) {volume = 0;} slider.val(volume);
1467			if (radio_player.debug) {console.log('Volume Down Instance '+instance+': '+oldvolume
1467+' to '+volume);}
1468		} else if (jQuery(this).hasClass('rp-volume-up')) {
1469			volume = oldvolume + 5; if (volume > 100) {volume = 100;} slider.val(volume);
1470			if (radio_player.debug) {console.log('Volume Up Instance '+instance+': '+oldvolume+' to '+volume);}
1471		}
1472		radio_player_volume_slider(instance,volume);
1473		radio_player_change_volume(instance,volume);
1474		radio_player_set_state('volume',volume);
1475		/* if (volume > 0) {mute = false;} else {mute = true;}
1476		radio_player_mute_unmute(instance,mute);
1477		radio_player_set_state('mute',mute); */
1478	});
1479
1480	/* --- detect script selection switcher change --- */
1481	jQuery('.rp-script-select').change(function() {
1482		container = jQuery(this).closest('.radio-container, .rp-container');
1483		instance = container.attr('data-instance');
1484		script = jQuery(this).val(); radio_player_switch_script(instance,script);
1485	});
1486
1487	/* --- add player listener to cancel loading flag --- */
1488	document.addEventListener('rp-play', function(e) {
1489		instance = e.detail.instance;
1490		jQuery('#radio_player_'+instance).addClass('loading');
1491	}, false);
1492	document.addEventListener('rp-playing', function(e) {
1493		instance = e.detail.instance;
1494		jQuery('#radio_player_'+instance).removeClass('loading');
1495	}, false);
1496	document.addEventListener('rp-pause', function(e) {
1497		instance = e.detail.instance;
1498		jQuery('#radio_player_'+instance).removeClass('loading');
1499	}, false);
1500	document.addEventListener('rp-stop', function(e) {
1501		instance = e.detail.instance;
1502		jQuery('#radio_player_'+instance).removeClass('loading');
1503	}, false);
1504
1505	/* --- pause on media elements player play --- */
1506	jQuery('audio.mejs__player').on('play', function(e) {
1507		if (!radio_player.settings.singular) {return;}
1508		jQuery('.radio-container').each(function() {
1509			instance = jQuery(this).attr('data-instance');
1510			radio_player_pause_instance(instance);
1511			radio_player_broadcast_playing(instance);
1512		});
1513	});
1514	
1515	/* --- pause media elements on player play --- */
1516	document.addEventListener('rp-play', function(e) {
1517		if (!radio_player.settings.singular) {return;}
1518		jQuery('audio.mejs__player').each(function() {
1519			el = jQuery(this)[0];
1520			if (!el.paused) {
1521				el.pause();
1522				if (radio_player.debug) {console.log( 'Paused MediaElement Audio: '+el.src);}
1523			}
1524		});
1525	}, false);
1526	
1527});
1528
1529
1530/* === Custom Events === */
1531
1532/* --- Trigger Custom Event --- */
1533function radio_player_custom_event(name, detail) {
1534	params = {bubbles: false, cancelable: false, detail: detail}
1535	var event = new CustomEvent(name, params); document.dispatchEvent(event);
1536    if (radio_player.debug) {console.log('Radio Player Custom Event: '+name);}
1537}
1538
1539/* --- CustomEvent support polyfill --- */
1540(function () {
1541	if (typeof window.CustomEvent === 'function') {return false;}
1542	function CustomEvent(event, params) {
1543		params = params || {bubbles: false, cancelable: false, detail: undefined};
1544		var evt = document.createEvent('CustomEvent');
1545		evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
1546		return evt;
1547	}
1548	CustomEvent.prototype = window.Event.prototype;
1549	window.CustomEvent = CustomEvent;
1550})();

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.