forked from farpenoodle/FB2KNowPlayingOverlay
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathnowplaying.html
More file actions
342 lines (298 loc) · 11.2 KB
/
Copy pathnowplaying.html
File metadata and controls
342 lines (298 loc) · 11.2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
<html>
<head>
<link rel="stylesheet" href="css/stylesheet.css" type="text/css" charset="utf-8">
<script src="js/jquery-2.1.0.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/TweenMax.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/CSSPlugin.min.js" type="text/javascript" charset="utf-8"></script>
<script src="js/ScrollToPlugin.min.js" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript">
// =======================================
// Collect flags from URL
params = new URLSearchParams(document.location.search);
// Flags default to false, and become true if you pass them in the URL with any value.
// Example: nowplaying.html?noart=yep&fade=sure
// The above will enable art and fadeout, but would do the same thing even if you put "nope" in the value.
var artFlag = params.get("noart") != null ? false : true;
var fadeFlag = params.get("fade") != null ? true : false;
var fadeTimeout = params.get("fadetime") != null ?
parseInt(params.get("fadetime")) != NaN ? parseInt(params.get("fadetime")) : 10
: 10;
var maxWidth = params.get("width") != null ?
parseInt(params.get("width")) != NaN ? parseInt(params.get("width")) : 500
: 500;
var useFolderName = params.get("foldername") != null ? true : false;
var useFileName = params.get("filename") != null ? true : false;
var lastPlayed = params.get("lastplayed") != null ?
parseInt(params.get("lastplayed")) != NaN ? parseInt(params.get("lastplayed")) : 350
: 0;
// ======================================
var npObj; // Stores the data retrieved from the server
var xhr = new XMLHttpRequest();
var playState = 0; // Tracks play/pause state
var fadeStatus = 0; // Timer for fadeout
var progressLength; // Calculated width of progress bar
var lastTracks = []; // Log of recently played tracks
// Get everything going
function init() {
xhr.overrideMimeType('application/json');
// Set initial progress bar width
progressLength = $("#progresswrapper").width();
// Retrieve updated metadata every second
this.window.setInterval(function() {
// Get the data, sending the current date to defeat server side caching
xhr.open('GET', "nowplaying.json?test="+Date.now(),true);
xhr.send();
xhr.onreadystatechange = function(){
if (xhr.readyState === 4) {
try {
npObj = JSON.parse(xhr.responseText);
updateBoard();
} catch (error) {
if(error.name == "SyntaxError") {
// This usually happens if the JSON file was in the middle of being
// rewritten, so it's gonna happen from time to time.
console.log("JSON wasn't valid.");
} else {
throw error;
}
}
}
}
}, 1000);
// Set board width
$("#board").css("width", maxWidth);
// Show/hide the album art field.
if (artFlag == true) {
$("#meta-art").removeClass("hidden");
}
// Show the board if fade is disabled
if (fadeFlag != true) {
$("#board").css("opacity", 1);
}
// Show the recently-played list if enabled
if (lastPlayed > 0) {
$("#history").removeClass("hidden");
}
}
// Data from last update
var lastPlaying = 0;
var lastPaused = 0;
var lastFile = "None";
var lastState = "None";
var lastTrack;
// Main logic
function updateBoard() {
var np = npObj.nowplaying;
var state = "";
// Identify our current state or transition
if (np.playing == 1 && (np.paused == 1 && lastPaused == 0)) {
state = "playing->paused";
} else if (np.playing == 1 && (np.paused == 0 && lastPaused == 1)) {
state = "paused->playing";
} else if (np.playing == 1 && (np.paused == 1 && lastPaused == 1)) {
state = "paused";
} else if (np.playing == 1 && lastPlaying == 0) {
state = "stopped->playing";
} else if (np.playing == 0 && lastPlaying == 1) {
state = "playing->stopped";
} else if (np.playing == 0 && lastPlaying == 0) {
state = "stopped";
} else if (np.playing == 1 && lastPlaying == 1) {
state = "playing";
}
if (state != lastState) {
console.log(lastState, state);
lastState = state;
}
// Handle different states
if (np.path != lastFile) {
// Changing tracks
console.log("Changing tracks");
// Add last track to recently-played list.
if (lastTrack && lastTrack.playing == 1) {
var track = { ...lastTrack }; // Clone the last track data
if (track.artist != "?" || track.albumartist != "?")
{
if (track.artist != track.albumartist) {
track.artist += "(" + track.albumartist + ")";
}
} else {
track.artist = "Unknown Artist";
}
lastTracks.push([track.title, track.artist].join(" - "));
// Show the recently-played list if enabled
if (lastPlayed > 0) {
$("#log").text(lastTracks.slice(0 - lastPlayed).toReversed().join("\n"));
}
}
// Clone the track info for next loop
lastTrack = { ...np };
UpdateAndShowBoard(np);
}
if (state == "playing") {
// Calculate the current playback position
var elMins = Math.floor(npObj.nowplaying.elapsed / 60);
var elSecs = npObj.nowplaying.elapsed - elMins * 60;
if (elSecs < 10) {
elSecs = "0" + elSecs;
}
var leMins = Math.floor(npObj.nowplaying.length / 60);
var leSecs = npObj.nowplaying.length - leMins * 60;
if (leSecs < 10) {
leSecs = "0" + leSecs;
}
// Put the elapsed time on the board
$('#elapsed').html("<span class=\"elapsedtime\">"+ elMins + ":" + elSecs + "</span>/" + leMins + ":" + leSecs);
// Update the width of the progress bar.
var progressWidth = Math.ceil(progressLength * (npObj.nowplaying.elapsed / npObj.nowplaying.length));
$('#progress').css("width",progressWidth);
} else {
switch(state) {
case "playing->paused":
case "stopped->paused":
// Fade the icon out, change it, and fade it back in
TweenMax.to($('#playpaused'), 0.5, {opacity: 0,onComplete: function(){
$('#playpaused').html("⏸"); // Pause emoji
}});
TweenMax.to($('#playpaused'), 0.5, {opacity: 1, delay:0.5});
UpdateAndShowBoard(np); // Make the board fade in
break;
case "playing->stopped":
case "paused->stopped":
// Fade the icon out, change it, and fade it back in
TweenMax.to($('#playpaused'), 0.5, {opacity: 0,onComplete: function(){
$('#playpaused').html("⏹"); // Stop emoji
}});
TweenMax.to($('#playpaused'), 0.5, {opacity: 1, delay:0.5});
UpdateAndShowBoard(np); // Make the board fade in
break;
case "paused->playing":
case "stopped->playing":
// Fade the icon out, change it, and fade it back in
TweenMax.to($('#playpaused'), 0.5, {opacity: 0,onComplete: function(){
$('#playpaused').html("▶"); // Play emoji
}});
TweenMax.to($('#playpaused'), 0.5, {opacity: 1, delay:0.5});
UpdateAndShowBoard(np); // Make the board fade in
break;
}
}
// Check if board needs to fade out
if (fadeStatus > 0 && fadeFlag) {
fadeStatus--;
} else if (fadeStatus == 0 && fadeFlag) {
TweenMax.killTweensOf($('#board'));
TweenMax.to($('#board'), 1, {opacity: 0});
fadeStatus = -1;
}
// Update progressbar width in case it's changed due to album art loading weirdness or something.
progressLength = $("#progresswrapper").width();
// Store values for reference next loop
lastPlaying = np.playing;
lastPaused = np.paused;
lastFile = np.path;
}
// Update metadata fields on screen
function UpdateFields(ptrack) {
var track = { ...ptrack }; // Clone the passed data
// If album artist and artist fields aren't the same, then
// display the album artist in parentheses after the artist.
// Also, if the artist is blank, we'll put in nothing instead of a ?.
if (track.artist != "?" || track.albumartist != "?")
{
if (track.artist != track.albumartist) {
track.artist += "(" + track.albumartist + ")";
}
} else {
// If the user has requested we use the folder or file name when the artist isn't
// available, then do so, otherwise blank the field
if (useFolderName == true) {
track.artist = track.path.split("\\").slice(-2)[0];
} else if (useFileName == true) {
track.artist = track.path.split("\\").slice(-1)[0];
} else {
track.artist = " ";
}
}
// If album name is ?, make it empty.
if (track.album == "?") track.album = " ";
// Of course, if we aren't playing, then just blank everything
if (track.playing == 0) {
track.title = "Nothing playing",
track.artist = " ",
track.album = " "
}
fields = {
"title" : track.title,
"artist" : track.artist,
"album" : track.album
}
// Update fields in board with track info
for (const [field, value] of Object.entries(fields)) {
// If the string is different than the existing one, update it.
if ($('#' + field).html() != value) {
// Fade out the field name
TweenMax.to($('#' + field), 0.5, {opacity: 0,onComplete: function(){
// Replace its contents with the new data
$('#' + field).html(value);
// Scroll the field all the way to the left
TweenMax.to($('#' + field), 0, {scrollTo:{x:0}});
// Tell it to continuously scroll back and forth if it doesn't fit on the screen
TweenMax.to($('#' + field), 4, {scrollTo:{x:"max"},ease:Linear.easeNone,repeat: -1, repeatDelay:1,yoyo:true});
}});
// Fade the field back in.
TweenMax.to($('#' + field), 0.5, {opacity: 1, delay:0.5});
}
};
// If nothing is playing, sub in the no-art image.
if (track.playing == 0) {
$('#artimg').attr("src", "noart.jpg");
$('#artfield').css("background-image", 'url("/noart.jpg")');
} else {
// Otherwise, force a reload of the album art.
// The .5-second delay accounts for delays updating the file on the server side.
// Appending the date is necessary so the browser knows it's a new file.
$('#artimg').attr("src", "albumart.jpg?" + Date.now());
$('#artfield').css("background-image", 'url("/albumart.jpg?' + Date.now() + '")');
}
}
// If the board needs to be shown, do so, then update the fields once it appears
// Otherwise, update them immediately.
function UpdateAndShowBoard(np) {
if (fadeFlag == true) {
TweenMax.killTweensOf($('#board'));
TweenMax.to($('#board'), 1, {opacity: 1, onComplete: function(){
// Update track display
UpdateFields(np);
}});
fadeStatus = fadeTimeout;
} else {
UpdateFields(np);
}
}
</script>
</head>
<body onLoad="init()">
<div id="board">
<div id="metadata">
<div id="meta-text">
<div id="title">Nothing playing</div>
<div id="artist"> </div>
<div id="album"> </div>
</div>
<div id="meta-art" class="hidden">
<img id="artimg" src="noart.jpg">
</div>
</div>
<div id="progressbar">
<div id="elapsed"><span style="opacity:0.6;">0:00</span>/0:00</div>
<div id="playpaused">⏹</div>
<div id="progresswrapper"><div id="progress"></div></div>
</div>
<div id="history" class="hidden">
<div class="header">Recently played:</div>
<div id="log"></div>
</div>
</div>
</body>
</html>