PageSourceSearch

https://ninbot.com/nb-player.js

js ninbot.com collected 2026-10-04 01:36:43 UTC 35,195 bytes, 1,228 lines download raw bytes

1//
2//  nb-player.js
3//
4//  Audio Player Controller
5//
6//
7//
8"use strict"
9
10var app = angular.module('nb-player', ['nb-mtrack'])
11
12.directive('player', function() {
13    return {
14    	controller: "nb-player",
15    	templateUrl: "template-player.html"
16    };
17})
18.factory('nbplayer', function($http ) {
19    var nbplayer = {};
20    return(nbplayer);
21})
22
23.controller('nb-player', function( $scope, $http, $sce, $window, nbserverlist, nbplayer, nbmain, nbuser, nbplaylist, $location) {
24    nbplayer.scope = $scope;
25    $scope.dl_menu = {};
26    $scope.dl_menu.open = 0;
27    $scope.dl_menu.list = [
28	{  desc: "One" },
29	{  desc: "two" },
30	{  desc: "three" },
31	{  desc: "forur" },
32    ];
33    $scope.audio = document.getElementById("audio");
34//    console.log("nb-player start " + $scope.player.num);
35    if (!$scope.player) {
36        $scope.player = {};
37    }
38   
39    $scope.player_playlist_control  = function(enable) {
40	$scope.player_playlist_control = enable ;
41    }
42/* moved to nb-playlsit
43    $scope.plist_add_setin = function() {	
44console.log("SetIn");
45	$scope.edit_in = $scope.audio.currentTime;
46    }
47    $scope.plist_add_setout = function() {
48console.log("SetOut");
49	$scope.edit_out = $scope.audio.currentTime;
50    }
51    
52*/
53    $scope.player_playlist_edit_song  = function(eobj) {
54	$scope.player_focus("edit_playlist");
55    }
56    $scope.player_playlist_add_song  = function(s) {
57	//s = $scope.player.song;
58	let dur = $scope.player.duration;
59console.log("Add SOng");
60	$scope.player_focus("add_playlist");
61
62	$scope.player_playlist_edit_song = s;
63	nbplaylist.add_new_track($scope.player.song, $scope.player.duration);
64
65	//$scope.player_playlist_edit_song_dur = dur;
66
67
68
69    	setTimeout($scope.mp3_element_update, 30);
70    }
71
72    // 
73    // Play Radio Stream
74    //
75    $scope.radio_play  = function(idx) {
76        var audio = document.getElementById('audio');
77        var source = document.getElementById('audioSource');
78        var s = $scope.list.servers[idx].stream;
79	if (!s) return;
80        if (document.location.protocol == "https:") {
81             s = $scope.list.servers[idx].ssl_stream;
82	     if (!s) return;
83//             s = "https:" + $scope.list.servers[idx].stream.substr(5, 999);
84        }
85
86        var n = $scope.list.servers[idx].name;
87	if ($scope.player.song == n) {
88	    if ($scope.audio.paused) {
89		$scope.map_radio($scope.list.servers[idx].name);
90                $scope.audio.play();
91	    } else  {
92                $scope.audio.pause();
93		$scope.map_radio("");
94	    }
95	    return;
96	}
97        if (s) {
98            source.src = s;
99            audio.load(); //call this to just preload the audio without playing
100            audio.play();
101            $scope.player.song = n;
102            $scope.player.url = s;
103            $scope.player.isradio = 1;
104	    $scope.map_radio(n);
105  	    $scope.player.radio_user_update();
106	   // console.log("Radio called here " + n);
107        }
108	$scope.player.users = [];
109	$location.search("track", n);
110	//$scope.location_set_path("/radio/" + n);
111        setTimeout($scope.mp3_element_update, 5);
112    }
113    //
114    //  Play or Pause
115    //
116    //
117    $scope.play_pause = function(){
118        if ($scope.audio.paused) {
119                var audio = document.getElementById('audio');
120		$location.search("track", $scope.player.song);
121                audio.play();
122        }
123        else {
124	    //$location.search("track", null);
125	    $location.search("time", $scope.audio.currentTime );
126            $scope.audio.pause();
127	    //$scope.location_set_path("");
128        }
129    };
130    var can = document.getElementById("audio_seek");
131
132    //
133    //   mounse down in seek canvas
134    //
135    can.onmousedown = function(e) {
136        var rect = can.getBoundingClientRect();
137   	//var wid= can.width;
138   	var wid= can.offsetWidth;
139
140        var p = (e.x - rect.left) / wid;
141	//console.log("wid is + " + can.width + " wid = " + wid + "  got e.x  = " + e.x + " rect.left is " +rect.left + " = " +  (e.x - rect.left) + "  Pp = " + p);
142//can.width;
143//200;
144        var ct = $scope.player.duration * p;
145        $scope.audio.currentTime = ct;
146	$location.search("time", $scope.audio.currentTime );
147
148
149    };
150    $scope.player_focus = function(val, which) {
151	console.log("Player focus " + val + " called");
152	if ( $scope.player.focus == val && val  == "user") {
153	     if ($scope.player.user_focus == which ){
154	    	$scope.player.focus = null;
155	     }
156	     return;
157	}
158
159	if ( $scope.player.focus == val && val != "user") {
160	    $scope.player.focus = null;
161	} else {
162	    $scope.player.focus = val;
163	}
164    }
165
166    //
167    //  Handle audio ending and queue next song
168    //
169    //
170    //
171    $scope.player.next_track = function()  {
172        for(var nn =0; nn < $scope.mp3list.length;nn++) {
173            if ($scope.mp3list[nn].s == $scope.player.song) {
174		var nnn = ((nn - 1) + $scope.mp3list.length) % $scope.mp3list.length;
175                $scope.mp3_play(nnn);
176             }
177        }
178    }
179    $scope.player.seek_to = function(where)  {
180	$scope.audio.currentTime = where;
181	$location.search("time", $scope.audio.currentTime );
182    }
183    $scope.player.prev_track = function()  {
184        for(var nn =0; nn < $scope.mp3list.length;nn++) {
185            if ($scope.mp3list[nn].s == $scope.player.song) {
186		var nnn = ((nn + 1) + $scope.mp3list.length) % $scope.mp3list.length;
187                $scope.mp3_play(nnn);
188		break;
189             }
190        }
191    }
192    $scope.audio.onended = function()  {
193        if ($scope.audio.currentTime < ($scope.player.duration - 5)) return;
194	if ($scope.mp3_onend_cb) {
195	    $scope.mp3_onend_cb();
196	    $scope.mp3_onend_cb = null;
197	    return;
198	} 
199        for(var nn =0; nn < $scope.mp3list.length;nn++) {
200            if ($scope.mp3list[nn].s == $scope.player.song) {
201                if (nn > 0) {
202                    var nnn = nn-1;
203                    $scope.mp3_play(nnn);
204                }
205             }
206        }
207    }
208
209    $scope.last_url_tcode_time = 0;
210    $scope.player.mediasession = function(song)  {
211//, artist, album, icon) {
212	var ss = song.lastIndexOf("mp3") ;
213	if (ss != -1) {
214	    song = song.substr(0, song.length -4);
215	}
216	let userstr = "";
217	var signs = song.split("-");
218	for(var ii = 1; ii < signs.length; ii ++) {
219	     userstr += signs[ii] + " ";
220	}
221	var tstamp = signs[0];
222	// return;
223	if ('mediaSession' in navigator) {
224
225  	    navigator.mediaSession.metadata = new MediaMetadata({
226    	 	title: tstamp,
227    		artist: userstr, 
228    		album: "ninbot.com",
229    		artwork: [
230      		    { src: "/ninbot_head.png",   sizes: '96x96',   type: 'image/png' },
231    		]
232  	});
233	$scope.player.track_mediasession_icons(song);
234
235  	//navigator.mediaSession.setActionHandler('seekbackward', function() {});
236  	//navigator.mediaSession.setActionHandler('seekforward', function() {});
237  	
238  	navigator.mediaSession.setActionHandler('play', function() { $scope.play_pause()});
239  	navigator.mediaSession.setActionHandler('pause', function() { $scope.play_pause()});
240  	navigator.mediaSession.setActionHandler('previoustrack', function() {
241    		$scope.player.prev_track();
242	});
243  	navigator.mediaSession.setActionHandler('nexttrack', function() {
244    		$scope.player.next_track();
245	});
246  	navigator.mediaSession.setActionHandler('seekto', function(details) { $scope.player.seek_to(details.seekTime); });
247
248
249       }
250    }
251    $scope.player.track_mediasession_icons = function(song ) {
252	let users = []
253	//var song =$scope.player.song;
254	if (!$scope.player.users) return;
255	for (var ii = 0; ii < $scope.player.users.length;ii++) {
256	    if ($scope.player.users[ii].picture) {
257		users.push($scope.player.users[ii]);
258	    }
259	}
260	var ss = song.lastIndexOf("mp3") ;
261	if (ss != -1) {
262	    song = song.substr(0, song.length -4);
263	}
264	var ss = song.lastIndexOf("mp3") ;
265	if (ss != -1) {
266	    song = song.substr(0, song.length -4);
267	}
268	let userstr = "";
269	var signs = song.split("-");
270	for(var ii = 1; ii < signs.length; ii ++) {
271	     userstr += signs[ii] + " ";
272	}
273	var tstamp = signs[0];
274
275        let r = Math.floor(Math.random() * users.length);
276	let sstr = $scope.player.song + " " ;
277	
278        if ('mediaSession' in navigator) {
279            let art = { src: "/ninbot_head.png",   sizes: '96x96',   type: 'image/png' };
280	    if (users.length) {
281                 art.src = users[r].picture;
282	     }
283            navigator.mediaSession.metadata = new MediaMetadata({
284                title:  tstamp,
285                artist: userstr,
286                album: "ninbot.com",
287                artwork: [
288                    art
289                ]
290            });
291	//console.log("sending", art);
292        }
293	
294	
295    }
296
297
298/*
299      		    { src: 'https://dummyimage.com/128x128', sizes: '128x128', type: 'image/png' },
300      		    { src: 'https://dummyimage.com/192x192', sizes: '192x192', type: 'image/png' },
301       		    { src: 'https://dummyimage.com/256x256', sizes: '256x256', type: 'image/png' },
302      	 	    { src: 'https://dummyimage.com/384x384', sizes: '384x384', type: 'image/png' },
303      		    { src: 'https://dummyimage.com/512x512', sizes: '512x512', type: 'image/png' },
304*/
305    //
306    //   Draw the canvas using the current player time
307    //
308    let last_mediasession_update = 0;
309    let last_radio_user_update =0;
310    nbserverlist.on("change", function(list) {
311	if ($scope.player.isradio)  {
312	    $scope.player.radio_user_update();
313	    $scope.$apply();
314	}
315    })
316    $scope.audio.ontimeupdate = function()
317    {
318        $scope.player.currentTime =  $scope.audio.currentTime;
319/*
320	if ($scope.player.isradio)  {
321	    let tm = new Date().getTime();
322	    if (tm - last_radio_user_update > 15000) {
323		$scope.player.radio_user_update();
324		last_radio_user_update = tm;
325	    }
326        }
327*/
328
329	let song = $scope.player.song;
330	var ss = song.lastIndexOf("mp3") ;
331	if (ss != -1) {
332	    song = song.substr(0, song.length -4);
333	}
334	let nnow = new Date().getTime();
335	let sec = 15;
336	if (nnow - last_mediasession_update >= (sec * 1000)) {
337	    //console.log("Mediasession update");
338	    last_mediasession_update = nnow;
339    	    $scope.player.track_mediasession_icons($scope.player.song);
340	}
341/*
342	let userstr = "";
343	let sec = 5;
344	let nnow = new Date().getTime();
345	if (nnow - last_mediasession_update >= (sec * 1000)) {
346	var signs = song.split("-");
347	for(var ii = 1; ii < signs.length; ii ++) {
348	     userstr += signs[ii] + " ";
349	}
350	let remain = $scope.player.duration - $scope.player.currentTime;
351        let rmin = Math.floor(remain / 60);
352	let rsec = Math.floor( remain - (rmin * 60));
353	let rcode = rmin + ":";
354	if (rsec < 10) rcode +="0";
355	rcode += rsec;
356
357	signs.push("(" + rcode + ")");
358	signs.push("ninbot.com");
359	signs.push("CC 2.5");
360	let num = $scope.player.currentTime / sec;
361	num = Math.floor(num);
362	num = num % signs.length;
363	$scope.player.currentTitle = signs[num];
364	     //console.log("Updaed mediasession");
365    	     //$scope.player.mediasession (signs[num],signs[num], "ninbot.com", "/ninbot_head.png");
366	    last_mediasession_update = nnow;
367	}
368*/
369	
370	
371/*
372	let tscreen = 
373	var now = new Date().getTime();
374	if ( now - $scope.last_url_tcode_time > 60000) {
375	    $scope.last_url_tcode_time = now;
376	    $location.search("time", $scope.audio.currentTime);
377	}
378*/
379
380        $scope.player.duration =  $scope.audio.duration;
381	
382        $scope.$apply();
383        var c = document.getElementById("audio_seek");
384        var ctx = c.getContext("2d");
385   	var wid= c.width;
386        ctx.fillStyle = "#333";
387        ctx.fillRect(0, 0, wid, 150);
388        ctx.fillStyle = "#36b";
389        ctx.fillRect(0, 0,  wid * ($scope.player.currentTime / $scope.player.duration), 150);
390    }
391
392
393    //
394    //  Handle window resize
395    //
396    window.onresize = function() {
397        $scope.mp3_element_update();
398    }
399    //
400    //  Move Player on Scrooll
401    //
402    document.body.onscroll = function() {
403        $scope.mp3_element_update();
404    }
405
406    $scope.player_share = function() {
407	$scope.sharemenu_init();
408	$scope.dl_menu.open = 1 - $scope.dl_menu.open;
409	$scope.player.share = (!$scope.player.share);
410	setTimeout( $scope.mp3_element_update, 30);
411    }
412
413    //
414    //  Move the floating player div
415    //
416    $scope.mp3_element_update = function()
417    {
418        var ap = document.getElementById("audio_panel");
419	
420        var tp = document.scrollingElement.scrollTop;
421	var hei = window.innerHeight
422        //ap.style.top = (tp-50 + hei - 100)+ "px";
423        var whei =  ap.offsetHeight;
424        //var whei =  ap.height;
425        var off = -10;
426        if (nbmain.scope.mobile) {
427	   off += 50;
428	}
429//not        ap.style.top = (tp-50 + hei - whei - off)+ "px";
430       
431
432
433 //ap.style.top = -80 +"px";
434        //ap.style.top = (otp - hei + 100)+ "px";
435        return;
436    }
437
438    //
439    //   Check if mp3 is on archive.org;
440    //   Return 0 or 1
441    //
442    var is_archive = function(s) {
443	//console.log("Is Archive called");
444	var age = $scope.ninjam_age(s);
445	var hrs = age  / 60 / 60;
446	if (hrs > (24 * 14)) {
447	    return(1);
448  	} 
449	return(0);
450    }
451    $scope.ninjam_age = function(time) {
452                var yy = time.substr(0,4);
453                var mm = time.substr(4,2);
454                var dd = time.substr(6,2);
455                var h = time.substr(9,2);
456                var m = time.substr(11,2);
457                var d = new Date(yy, mm -1, dd , h, m);
458                var offset = new Date().getTimezoneOffset();
459                offset = offset - (5 * 60);
460                var ms = d.getTime();
461                ms -= (offset * 60 * 1000) ;
462                time = ms;
463
464            	var local = Date.now();
465            	if (angular.isDate(time)) {
466                    time = time.getTime();
467            	} else if (typeof time === "string") {
468                   time = new Date(time).getTime();
469                }
470                //local = local.getTime();
471
472                offset = Math.abs((local - time) / 1000)
473
474	return(offset);
475    }
476
477    //
478    //  Download current song zipfile track
479    //
480    //
481    $scope.player_download_tracks = function()
482    {
483        var url ="/tracks/" + $scope.player.song.substr(0, $scope.player.song.length -4) + ".ZIP";
484        var s =  $scope.player.song;
485        if (is_archive(s)) {
486            var dstr = s.substr(0,8);
487            var z = s.substr(0, s.length -4) + ".ZIP";
488            //url = "https://ia803201.us.archive.org/19/items/ninbot_tracks_" + dstr + "/" + z
489            url = "https://archive.org/download/ninbot_tracks_" + dstr + "/" + z;
490        }
491        let a = document.createElement('a')
492        a.href = url;
493        a.download = url.split('/').pop()
494        document.body.appendChild(a)
495        a.click()
496        document.body.removeChild(a)
497    }
498    $scope.player_play_video = function(s)
499    {
500	console.log("player play video " + s.name);
501    }
502
503    //
504    //  Download current song mp3
505    //
506    //
507    $scope.player_download_mp3 = function()
508    {
509        let a = document.createElement('a');
510        a.href = $scope.player.url
511        a.download = $scope.player.url.split('/').pop()
512        document.body.appendChild(a)
513        a.click()
514        document.body.removeChild(a)
515
516return;
517/*
518        let a = document.createElement('a')
519        a.href = $scope.player.url
520        a.download = $scope.player.url.split('/').pop()
521        document.body.appendChild(a)
522        a.click()
523        document.body.removeChild(a)
524*/
525    }
526    $scope.player_radio_tracks = function()
527    {
528	var s = $scope.player.song;
529	$scope.player_stop();
530	//$scope.mtrack_radio(s);
531	//$scope.mtrack_edit_song(s);
532	$scope.mtrack_edit_radio(s);
533
534    }
535    $scope.player_playlist_add = function() {
536	var s = $scope.player.song;
537	$scope.playlist_add_song(s);
538    }
539    $scope.player_edit_tracks = function()
540    {
541	var s = $scope.player.song;
542	$scope.player_stop();
543	$scope.mtrack_edit_song(s);
544    }
545    $scope.radio_play_byname = function(s) {
546console.log("Radio Play By Name " +1);
547	if ($scope.player.song == s) return;
548console.log("Radio Play By Name " +2);
549        var audio = document.getElementById('audio');
550        var source = document.getElementById('audioSource');
551	if (!$scope.list) {
552	    setTimeout(function() {
553			$scope.radio_play_byname(s);
554	 	}, 5000);
555	    return;
556	}
557console.log("List is ", $scope.list);
558
559        for(var ii = 0; ii <  $scope.list.servers.length;ii++) {
560	     if ($scope.list.servers[ii].name == s) {
561        	$scope.player.song = $scope.list.servers[ii].name;
562        	$scope.player.url = $scope.list.servers[ii].stream;
563		$scope.player.radio_users = $scope.list.servers[ii].users;
564console.log("GOt Radio users", $scope.player.radio_users);
565		source.src = $scope.list.servers[ii].stream;     
566		audio.load(); //call this to just preload the audio without playing
567        	audio.play();
568        	$scope.player.isradio = 1;
569        	setTimeout( $scope.mp3_element_update, 30);
570
571	     }
572	}
573    }
574    $scope.radio_player_focus = function(type, val) {
575	console.log("Focus Radio " + val);
576	nbuser.lookup(val.name, function(data) {
577		console.log("LOokup " + val.name, data);
578	 	if ( $scope.player.user_focus != data) {
579	             $scope.player.user_focus = data;
580	    	     $scope.player.focus = "user";
581		} else {
582	    	    $scope.player_focus();
583	    	    $scope.player.user_focus = null;
584		}
585		//$scope.$apply();
586
587	});
588/*	
589	if ( $scope.player.focus == val && val  == "user") {
590	     if ($scope.player.user_focus == which ){
591	    	$scope.player.focus = null;
592	     }
593	     return;
594	}
595
596	if ( $scope.player.focus == val && val != "user") {
597	    $scope.player.focus = null;
598	} else {
599	    $scope.player.focus = val;
600	}
601*/
602    }
603    $scope.player.radio_user_update = function() {
604	console.log("Radio Update");
605        for(var ii = 0; ii <  $scope.list.servers.length;ii++) {
606       	     if ($scope.player.song ==  $scope.list.servers[ii].name) {
607		$scope.player.radio_users = $scope.list.servers[ii].users;
608	     }
609	}
610	let sstr = $scope.player.song + " " ;
611	let tstr = "";
612	let pics = [];
613	for (var ii = 0; ii < $scope.player.radio_users.length; ii++) {	
614	    if ($scope.player.radio_users[ii].avatar) {
615	 	pics.push($scope.player.radio_users[ii].avatar);
616	    }
617	    tstr += " " + $scope.player.radio_users[ii].name;
618	}
619	let r = Math.floor(Math.random() * pics.length);	
620	let pic = null;
621	if (pics.length) 
622	   pic = pics[r];
623	
624	//$scope.player.currentTitle = tstr;
625	if ('mediaSession' in navigator) {
626	    let art = { src: "/ninbot_head.png",   sizes: '96x96',   type: 'image/png' };
627	    if (pic) art.src = pic;
628
629
630  	    navigator.mediaSession.metadata = new MediaMetadata({
631    	 	title: sstr,
632    		artist: tstr, 
633    		album: "ninbot.com",
634    		artwork: [
635      		    art
636    		]
637  	});
638	}
639//    res.status(404).send("Not Found");
640    }
641    $scope.mp3_play_url = function(s)
642    {
643
644    }
645    $scope.mp3_play_playlist_obj = function(obj, playlist, onend)
646    {
647console.log("PLAY BY OBJ ", playlist);
648	$scope.player.playlist = playlist;
649	$scope.player.playlist_obj = obj;
650	$scope.mp3_onend_cb = onend;
651	var s = obj.s;
652
653        var url = "/mp3/" + s;
654        if (is_archive(s)) {
655            var dstr = s.substr(0,8);
656            //url = "https://ia803201.us.archive.org/19/items/ninbot_" + dstr + "/" + s;
657            url = "https://archive.org/download/ninbot_" + dstr + "/" + s;
658	}
659        var audio = document.getElementById('audio');
660        var source = document.getElementById('audioSource');
661        $scope.player.song = s;
662	$location.search("track", s);
663        //$scope.player.songid = ind;
664        $scope.player.url = url;
665    	$scope.player.mediasession ($scope.player.song);
666
667        source.src = url;
668        audio.load(); //call this to just preload the audio without playing
669
670 	var nofade = 1;
671	var dur = 70;
672	var fdur = 1;
673    // Set the point in playback that fadeout begins. This is for a 2 second fade out.
674	var tin = obj.ein;
675	var tout =  obj.eout;
676        var fadein = tin + fdur;
677        var fadeout = tout - fdur;
678
679	$location.search("time", tin);
680	$location.search("out", tout);
681        audio.addEventListener('loadedmetadata', function _mrlisten()  {
682	        if (tin) {
683		    audio.currentTime = tin;
684		}
685         	audio.removeEventListener('loadedmetadata', _mrlisten,true);
686        	audio.play();
687	//	playButton.removeClass('loading');
688	}, true);
689
690
691	if (!nofade) {
692
693
694        var fadeAudio = setInterval(function () {
695	     var tm = audio.currentTime;
696	     var vol = 1.0;
697	     if (tm < fadein) {
698		vol = 1 - ((fadein - tm) / fdur);
699	     } 
700	     if (tm > fadeout) {
701		vol = 1 - ((tm - fadeout) / fdur);
702	     }
703	     if (vol < 0) vol = 0;
704	     if (vol > 1) vol = 1;
705	     audio.volume = vol;
706//console.log(tm + " " + tout);
707	     if (tm >= tout) {
708//console.log("Tm is at the end");
709                 clearInterval(fadeAudio);
710		 audio.pause();
711		 $scope.mp3_onend_cb();
712	     }
713
714	}, 200);
715	}
716
717        $scope.player.isradio = 0;
718	setTimeout( $scope.mp3_element_update, 30);
719
720
721
722    }
723    $scope.player_permission = function( song ) {
724	$scope.player_permission_song = song;
725    }
726    $scope.playlist_click = function() {
727	console.log("Playlist Click");
728    }
729
730    $scope.$watch("player.song", function(nval, oval) {
731	if (!nval) return;
732	$scope.player.focus = null;  // Close any user focus
733	
734	let s = nval;
735	let ss = nval.lastIndexOf(".");
736	if (ss != -1) {
737	   s= s.substr(0, ss);
738	}
739	let narray = s.split("-");
740
741
742  	$scope.player.users = []
743  	let uarray = [];
744	for(let ii = 1; ii < narray.length; ii++) {
745	    let uname = narray[ii];
746	    uarray.push({ name: uname });
747	}
748  	$scope.player.users = uarray;
749	for(let ii = 0; ii < $scope.player.users.length; ii++) {
750	    nbuser.lookup($scope.player.users[ii].name, function(data) {
751		if (data) {
752		     for(let jj = 0; jj < $scope.player.users.length; jj++) {
753			if (data.name.toLowerCase() == $scope.player.users[jj].name.toLowerCase()) {
754			     let name = $scope.player.users[jj].name;
755			     $scope.player.users[jj] = data;
756			     $scope.player.users[jj].name = name;
757			}
758		     }
759	 	}
760	    });
761	}
762
763    });
764
765	
766    $scope.mp3_play_byname = function(s, onend, tm)
767    {
768	if ($scope.player.song == s) return;
769	$scope.mp3_onend_cb = onend;
770        var url = "/mp3/" + s;
771	if ($scope.playlist && $scope.playlist.archive) { 
772//console.log("Have Playlist");
773            var dstr = s.substr(0,8);
774            url = "https://archive.org/download/" + $scope.playlist.archive + "_"  + dstr + "/" + s;
775		//console.log(url);
776	} else {
777        if (is_archive(s)) {
778            var dstr = s.substr(0,8);
779            //url = "https://ia803201.us.archive.org/19/items/ninbot_" + dstr + "/" + s;
780            url = "https://archive.org/download/ninbot_" + dstr + "/" + s;
781	}
782
783	}
784        var audio = document.getElementById('audio');
785	audio.onerror = function(err) {
786	     console.log("Error 001 Playing audio " + url, err);
787	}
788        var source = document.getElementById('audioSource');
789        $scope.player.song = s;
790        //$scope.player.songid = ind;
791        $scope.player.url = url;
792
793        if (tm) {	
794	    url += "#t=" + tm;
795	}
796        source.src = url;
797        audio.load(); //call this to just preload the audio without playing
798        var promise = audio.play();
799
800	if (promise !== undefined) {
801    	    promise.then(_ => {
802        // Autoplay started!
803    	   }).catch(error => {
804
805	    $scope.player_permission($scope.player.song);
806        // Autoplay was prevented.
807        // Show a "Play" button so that user can start playback.
808	  	console.log("Unable to play withoug interaction", error);
809		$scope.player.giant_play_button = 1;
810    	   });
811        }
812/*
813	try {
814        audio.play();
815	} catch(err) {
816	  console.log("an error occurred");
817	}
818*/
819        $scope.player.isradio = 0;
820	setTimeout( $scope.mp3_element_update, 30);
821
822    }
823
824    var user_cache = {};
825        $scope.mp3_info = function(mp3, cb) {
826	   $http( {method:"GET",
827              url:"/mp3info?mp3=" + mp3
828                }).then(function(res) {
829                    cb(res.data);
830
831                }, function(err) {
832                    cb(null);
833                });
834
835
836
837	}
838
839    $scope.mp3_play_userupdate = function()
840    {
841	var arr = $scope.player.song.split("-");
842	if (arr.length < 1) return;
843	var sarr = arr.splice(1, arr.length);
844	sarr[sarr.length -1] = sarr[sarr.length -1].substr(0, sarr[sarr.length -1].length -4);
845	$scope.player.users = sarr;
846/*	
847        $scope.mp3_info ($scope.player.song, function(info) {
848		$scope.player.mp3info = info;
849		console.log("mp3info");
850		console.log(info);
851	});
852
853*/
854
855	$scope.map_track( $scope.player.song, sarr);
856    }
857    //
858    //  Play index from mp3list
859    //
860    //
861/*
862    setInterval(function() {
863        $scope.mp3_seturl_time();
864    }, 5000);
865    $scope.mp3_seturl_time = function()
866    {
867        var audio = document.getElementById('audio');
868	var pos = audio.currentTime;
869	$scope.location_set_path("/tracks/" + s + "?t=" + pos);
870    }
871*/
872
873    $scope.mp3_play = function(ind)
874    {
875// Check if playlist ugh
876        var obj = $scope.mp3list[ind];
877        var s = obj.s;
878	//console.log("mp3 play " +s);
879        var audio = document.getElementById('audio');
880        var source = document.getElementById('audioSource');
881        var url = "/mp3/" + s;
882        var alturl = "/mp3/" + s;
883        var old_song = $scope.player.song;
884        $scope.player.song = s;
885	$scope.player.playlist_obj = null;
886
887	
888	
889	//$scope.location_set_path("/tracks/" + s);
890//	var scr = document.body.scrollTop;
891	//var scr = window.scrollY;
892	$location.search("track", s);
893if (0) {
894	var scr = document.documentElement.scrollTop;
895//.body.scrollTop;
896	$location.search("track", s);
897	document.documentElement.scrollTop = scr;
898	setTimeout(function() {
899	document.documentElement.scrollTop = scr;
900	}, 1);
901}
902	//window.scrollY = scr;
903	//document.body.scrollTop = scr;
904	
905         var dstr = s.substr(0,8);
906
907//console.log("MP3 PLAY", $scope.playlist);
908	if ($scope.playlist && $scope.playlist.archive) { 
909            url = "https://archive.org/download/" + $scope.playlist.archive + "_"  + dstr + "/" + s;
910//		console.log(url);
911	} else {
912        if (is_archive(s)) {
913            //url = "https://ia803201.us.archive.org/19/items/ninbot_" + dstr + "/" + s
914            url = "https://archive.org/download/ninbot_" + dstr + "/" + s;
915        }
916 	if (s.indexOf("-") > 14 || s.indexOf("-") == -1) {
917            url = "https://archive.org/download/ninjam_autosongs_" + dstr + "/" 
917+ s;
918        }
919	}
920
921        for(var nn =0; nn < $scope.mp3list.length;nn++) {
922             if ($scope.mp3list[nn].s == old_song) {
923                $scope.player.songid = nn;
924             }
925        }
926
927        if ($scope.player.songid || $scope.player.songid ==0) {
928            var el = document.getElementById("MP3-" + $scope.player.songid);
929	    if (el != null) {
930               el.classList.remove("current_song");
931	    }
932        }
933        $scope.player.songid = ind;
934        $scope.player.url = url;
935        var el = document.getElementById("MP3-" + ind);
936        el.classList.add("current_song");
937console.log("Calling Media session " + s + " " + $scope.player.song);
938    	$scope.player.mediasession ($scope.player.song);
939//, userstr, "ninbot.com", "/ninbot_head.png");
940//, "ninbot.com", "ninbot.com", "/ninbot_head.png");
941
942        source.src = url;
943	//console.log("Play 002 " + url);
944	source.onerror = function(err) {
945	     console.log("Error Playing MP3 " + url, err);
946	     if (url != alturl) {
947		url = alturl;
948         	source.src = url;
949        	audio.load();
950        	audio.play();
951	      	console.log("Atttempting restart " + url);
952	     }
953	}
954        audio.load(); //call this to just preload the audio without playing
955        audio.play();
956        $scope.player.isradio = 0;
957	setTimeout( $scope.mp3_element_update, 30);
958        $scope.mp3_play_userupdate();
959
960    } 
961    $scope.nb_player_skip = function(dir) {
962        var audio = document.getElementById('audio');
963	var pos = audio.currentTime;
964	pos += (dir * 30);
965	if (pos < 0) pos = 0;
966	audio.currentTime = pos;
967    }
968
969    $scope.$on('$locationChangeSuccess', function(event) {
970        $scope.nb_player_location_sync();
971/*
972	console.log("location change for player");
973        var query = $location.search();
974
975        var path = $location.path();
976
977
978        if (query.track) {
979	    console.log("found query .track");
980   	   var s = query.track;
981	   if (s.indexOf(":") != -1) {
982	       $scope.radio_play_byname(s);
983	   } else {
984	       $scope.mp3_play_byname(s);
985	    }
986            //$scope.user_menu_select_bytag(query.page);
987        }
988*/
989    });
990    $scope.nj_local_time = function(time) {
991        //let tm = $scope.ninjam_age(s);
992        if (!time) return(new Date());
993        var yy = time.substr(0,4);
994        var mm = time.substr(4,2);
995        var dd = time.substr(6,2);
996        var h = time.substr(9,2);
997        var m = time.substr(11,2);
998        var d = new Date(yy, mm -1, dd , h, m);
999
1000        var offset = new Date().getTimezoneOffset();
1001        offset = offset - (5 * 60);
1002        var ms = d.getTime();
1003        ms -= (offset * 60 * 1000) ;
1004        time = ms;
1005        let dt = new Date(time);
1006	return(dt);
1007/*
1008	let yr = s.substr(0,4);
1009	let mo = s.substr(4,2);
1010	let day = s.substr(6,2);
1011	let hr = s.substr(9,2);
1012	let min = s.substr(11,2);
1013*/
1014	
1015
1016    }
1017
1018    $scope.nb_player_location_sync = function() {
1019        var query = $location.search();
1020
1021        var path = $location.path();
1022	if (path) {
1023	    var sp = path.split("/");
1024	    if (sp.length > 2) {
1025	       if (sp[1] == "tracks") {
1026		   query.track = sp[2];
1027         	   $location.path(null);
1028	       }
1029	
1030	    }
1031	}
1032
1033
1034        if (query.track) {
1035   	   var s = query.track;
1036	   if (s.indexOf(":") != -1) {
1037
1038	       $scope.radio_play_byname(s);
1039	   } else {
1040		if (query.time) {
1041		    var tm = query.time;
1042	            $scope.mp3_play_byname(s, null, tm);
1043		} else {
1044	           $scope.mp3_play_byname(s);
1045		}
1046	        if (query.tm) {
1047	           delete $location.search().tm;
1048		}
1049	    }
1050/*
1051            if (query.time) {
1052		console.log("Setting current time " + query.time);
1053		$scope.audio.bind('canplay', function() {
1054  		    $scope.audio.currentTime = query.time;
1055		});
1056	    }
1057*/
1058            //$scope.user_menu_select_bytag(query.page);
1059        }
1060    }
1061
1062    $scope.nb_player_location = function(s) {
1063	if ($scope.player.song == s) return;
1064	if (s.indexOf(":") != -1) {
1065	   $scope.radio_play_byname(s);
1066	} else {
1067	   $scope.mp3_play_byname(s);
1068	}
1069    }
1070
1071    $scope.player_stop = function() {
1072        var audio = document.getElementById('audio');
1073	audio.pause();
1074/*
1075	if ($scope.player.song) {
1076            var el = document.getElementById("MP3-" + $scope.player.songid);
1077            el.classList.remove("current_song");
1078	}
1079
1080        var el = document.getElementById("MP3-" + $scope.player.songid);
1081        el.classList.remove("current_song");
1082	delete $scope.player.song;
1083*/
1084	
1085    }
1086
1087    //
1088    //  Change Style of Current Track
1089    // 
1090    //
1091    $scope.update_song_select = function() {
1092        var s = $scope.player.song;
1093	if (s == null) return;
1094        for(var nn =0; nn < $scope.mp3list.length;nn++) {
1095             if ($scope.mp3list[nn].s == s) {
1096                $scope.player.songid = nn;
1097                var el = document.getElementById("MP3-" + nn);
1098                el.classList.add("current_song");
1099
1100            }
1101        }
1102    }
1103/*
1104    setInterval(function() {
1105        var audio = document.getElementById('audio');
1106	var sec = audio.currentTime;
1107	var active = video_is_active();
1108	if (active) {
1109	}
1110	console.log("Play active " + active);
1111	console.log("Play Monitor " + sec);
1112	//console.log("Play Monitor " + sec);
1113	//$scope.location_set_path_no_history("/tracks/" + $scope.player.song + "&s=" + sec);
1114    }, 5000);
1115*/
1116    var video_is_active = function () {
1117        var audio = document.getElementById('audio');
1118        return !!(audio.currentTime > 0 && !audio.paused && !audio.ended && audio.readyState > 2);
1119    }
1120
1121
1122    $scope.mp3_element_update();
1123
1124    if (navigator.share) {
1125	$scope.sharing_enabled = true;
1126    }
1127    $scope.sharing_enabled = true;
1128
1129function copyToClipboard(text) {
1130    if (window.clipboardData && window.clipboardData.setData) {
1131        // Internet Explorer-specific code path to prevent textarea being shown while dialog is visible.
1132        return window.clipboardData.setData("Text", text);
1133
1134    }
1135    else if (document.queryCommandSupported && document.queryCommandSupported("copy")) {
1136        var textarea = document.createElement("textarea");
1137        textarea.textContent = text;
1138        textarea.style.position = "fixed";  // Prevent scrolling to bottom of page in Microsoft Edge.
1139        document.body.appendChild(textarea);
1140        textarea.select();
1141        try {
1142            return document.execCommand("copy");  // Security exception may be thrown by some browsers.
1143        }
1144        catch (ex) {
1145            console.warn("Copy to clipboard failed.", ex);
1146            return prompt("Copy to clipboard: Ctrl+C, Enter", text);
1147        }
1148        finally {
1149            document.body.removeChild(textarea);
1150        }
1151    }
1152}
1153    
1154    $scope.copy_url = function() {
1155        if (!$scope.player.isradio) {
1156	    $location.search("time", $scope.audio.currentTime );
1157	    setTimeout(function() {
1158	 	var urlstr = window.location.href;
1159 	 	copyToClipboard(urlstr);
1160	    }, 500);
1161	    return;
1162	}
1163
1164	var urlstr = window.location.href;
1165 	copyToClipboard(urlstr);
1166	return;
1167    }
1168    $scope.share_url = function() {
1169	var url = window.location.href;
1170        //$scope.audio.currentTime = ct;
1171        //$scope.audio.currentTime = ct;
1172	//$scope.player.songid
1173
1174  	if (navigator.share) {
1175    	    navigator.share({
1176		title: $scope.player.song,
1177      		url: url
1178    	}).then(() => {
1179      	     //console.log('Thanks for sharing!');
1180        })
1181        .catch(console.error);
1182        } else {
1183        }
1184
1185    }
1186
1187    $scope.sharemenu_init = function() {
1188    	 $scope.sharemenu_radio = [];
1189    	 $scope.sharemenu_mp3 = [];
1190	     $scope.sharemenu_mp3.push( { desc: "Download Mp3", cb: $scope.player_download_mp3 });
1191	     $scope.sharemenu_mp3.push( { desc: "Download tracks", cb: $scope.player_download_tracks });
1192	
1193	
1194	 if ($scope.mtrack_mixer && $scope.user && $scope.mtrack_group()) { 
1195	     $scope.sharemenu_radio.push( { desc: "Multitrack", cb: $scope.player_radio_tracks });
1196	     $scope.sharemenu_mp3.push( { desc: "Multitrack", cb: $scope.player_edit_tracks });
1197	 }
1198	 if ($scope.user && $scope.user.groups.includes("playlist")) { 
1199	     if (0 && $scope.player.playlist_obj) {
1200	         $scope.sharemenu_mp3.push( { desc: "Edit Playlist Track", cb: function(){ $scope.player_playlist_edit_song($scope.player.playlist_obj); } });
1201	     } else {
1202	         $scope.sharemenu_mp3.push( { desc: "Add Playlist", cb: function(){ $scope.player_playlist_add_song($scope.player.song); } });
1203	     }
1204	 }
1205	     $scope.sharemenu_radio.push( { desc: "Copy Url", cb: $scope.copy_url } );
1206	     $scope.sharemenu_mp3.push( { desc: "Copy Url", cb: $scope.copy_url } );
1207	     if (location.protocol == 'https:') {
1208	         $scope.sharemenu_mp3.push( { desc: "Share Url", cb: $scope.share_url });
1209	         $scope.sharemenu_radio.push( { desc: "Share Url", cb: $scope.share_url });
1210	     }
1211	     //$scope.sharemenu_mp3.push( { desc: "Share Url", cb: $scope.share_url } );
1212/*
1213	     $scope.sharemenu_mp3.push( { desc: "Share Link", function() {
1214		     $scope.player_share_mode = "share";
1215		}});
1216	    $scope.sharemenu_mp3.push( { desc: "Share", cb: share_url });
1217*/
1218    }
1219    $scope.sharemenu_init();
1220
1221    //console.log("nb-player end " + $scope.player.num);
1222    setTimeout( $scope.nb_player_location_sync, 1500);
1223
1224
1225});
1226
1227
1228

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.