j1-template 2024.3.19 → 2024.3.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (113) hide show
  1. checksums.yaml +4 -4
  2. data/_layouts/page.html +1 -0
  3. data/assets/data/amplitude_app.html +192 -163
  4. data/assets/data/swiper_app.2.html +757 -0
  5. data/assets/data/swiper_app.4.html +769 -0
  6. data/assets/data/swiper_app.html +171 -27
  7. data/assets/theme/j1/adapter/js/amplitude.js +1104 -216
  8. data/assets/theme/j1/adapter/js/swiper.js +63 -15
  9. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.css +111 -101
  10. data/assets/theme/j1/core/css/themes/bootstrap/bootstrap.min.css +1 -1
  11. data/assets/theme/j1/core/css/themes/unodark/bootstrap.css +111 -101
  12. data/assets/theme/j1/core/css/themes/unodark/bootstrap.min.css +1 -1
  13. data/assets/theme/j1/core/css/themes/unolight/bootstrap.css +111 -101
  14. data/assets/theme/j1/core/css/themes/unolight/bootstrap.min.css +1 -1
  15. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.css +177 -216
  16. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/amplitude.min.css +1 -1
  17. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.css +220 -339
  18. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/compact.min.css +1 -2
  19. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.css +324 -491
  20. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/large.min.css +1 -2
  21. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.css +70 -60
  22. data/assets/theme/j1/modules/amplitudejs/css/theme/uno/dark/player/mini.min.css +2 -1
  23. data/assets/theme/j1/modules/amplitudejs/js/tech/ytp.js +2074 -843
  24. data/assets/theme/j1/modules/amplitudejs/scss/theme/uno/dark/player/large.scss +439 -264
  25. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.css +16 -0
  26. data/assets/theme/j1/modules/swiperjs/css/modules/layoutBase.min.css +16 -0
  27. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.css +24 -24
  28. data/assets/theme/j1/modules/swiperjs/css/modules/layoutExpanding.min.css +1 -235
  29. data/assets/theme/j1/modules/swiperjs/css/modules/layoutNeighbor.min.css +2 -2
  30. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.css +16 -0
  31. data/assets/theme/j1/modules/swiperjs/css/modules/layoutParallax.min.css +16 -0
  32. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.css +6 -7
  33. data/assets/theme/j1/modules/swiperjs/css/modules/layoutStacked.min.css +1 -82
  34. data/assets/theme/j1/modules/swiperjs/css/modules/layoutThumbs.min.css +2 -29
  35. data/assets/theme/j1/modules/swiperjs/css/theme/uno.css +29 -12
  36. data/assets/theme/j1/modules/swiperjs/css/theme/uno.min.css +1 -1
  37. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.js +25 -0
  38. data/assets/theme/j1/modules/swiperjs/js/modules/layoutBase.min.js +25 -0
  39. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.js +1 -5
  40. data/assets/theme/j1/modules/swiperjs/js/modules/layoutExpanding.min.js +1 -5
  41. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.js +12 -14
  42. data/assets/theme/j1/modules/swiperjs/js/modules/layoutNeighbor.min.js +1 -17
  43. data/assets/theme/j1/modules/swiperjs/js/modules/layoutPanorama.js +0 -1
  44. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.js +25 -0
  45. data/assets/theme/j1/modules/swiperjs/js/modules/layoutParallax.min.js +25 -0
  46. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.0.js +114 -0
  47. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.1.js +93 -0
  48. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.js +42 -13
  49. data/assets/theme/j1/modules/swiperjs/js/modules/layoutStacked.min.js +17 -0
  50. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.js +76 -25
  51. data/assets/theme/j1/modules/swiperjs/js/modules/layoutThumbs.min.js +1 -17
  52. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.js +9152 -9131
  53. data/assets/theme/j1/modules/swiperjs/js/swiper-bundle.min.js +1 -1
  54. data/lib/j1/version.rb +1 -1
  55. data/lib/starter_web/README.md +5 -5
  56. data/lib/starter_web/_config.yml +1 -1
  57. data/lib/starter_web/_data/modules/amplitude_app.yml +206 -23
  58. data/lib/starter_web/_data/modules/amplitude_playlists.yml +1122 -19
  59. data/lib/starter_web/_data/modules/defaults/{amplitude_app.yml → amplitude.yml} +73 -26
  60. data/lib/starter_web/_data/modules/swiper_app.yml +356 -155
  61. data/lib/starter_web/_data/modules/swiper_playlists.yml +77 -1
  62. data/lib/starter_web/_data/resources.yml +6 -2
  63. data/lib/starter_web/_data/templates/feed.xml +1 -1
  64. data/lib/starter_web/_includes/attributes.asciidoc +5 -4
  65. data/lib/starter_web/_plugins/filter/filters.rb +1 -11
  66. data/lib/starter_web/_plugins/index/lunr.rb +1 -1
  67. data/lib/starter_web/assets/image/icon/bokeh/bokeh-32x32.ico +0 -0
  68. data/lib/starter_web/assets/image/icon/bokeh/bokeh.ico +0 -0
  69. data/lib/starter_web/assets/image/icon/bokeh/logo-160x160.png +0 -0
  70. data/lib/starter_web/assets/image/icon/hyvor-talk/hyvore-talk.ico +0 -0
  71. data/lib/starter_web/assets/image/icon/hyvor-talk/jpg/hyvor-logo.512x512.jpg +0 -0
  72. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.24x24.jpg +0 -0
  73. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.24x24.png +0 -0
  74. data/lib/starter_web/assets/image/icon/hyvor-talk/png/hyvor-logo.512x512.png +0 -0
  75. data/lib/starter_web/assets/image/icon/hyvor-talk/scalable/hyvor-logo.svg +81 -0
  76. data/lib/starter_web/assets/image/icon/jupyter/jupyter-32x32.ico +0 -0
  77. data/lib/starter_web/assets/image/icon/jupyter/jupyter.ico +0 -0
  78. data/lib/starter_web/assets/image/icon/jupyter/logo.png +0 -0
  79. data/lib/starter_web/assets/image/icon/mdi/mdi.svg +1 -0
  80. data/lib/starter_web/assets/image/icon/mdi/mdil.svg +1 -0
  81. data/lib/starter_web/assets/image/icon/scalable/facebook.svg +34 -0
  82. data/lib/starter_web/assets/image/icon/scalable/google.svg +35 -0
  83. data/lib/starter_web/assets/image/icon/scalable/ibm.svg +24 -0
  84. data/lib/starter_web/assets/image/icon/scalable/microsoft.svg +42 -0
  85. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-1.png +0 -0
  86. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-2.png +0 -0
  87. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-3.png +0 -0
  88. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-4.png +0 -0
  89. data/lib/starter_web/assets/image/module/swiper/avatar/avatar-5.png +0 -0
  90. data/lib/starter_web/assets/image/module/swiper/simple/test/image/diana_krall.jpg +0 -0
  91. data/lib/starter_web/index.html +3 -3
  92. data/lib/starter_web/package.json +1 -1
  93. data/lib/starter_web/pages/public/learn/where_to_go.adoc +1 -1
  94. data/lib/starter_web/pages/public/tools/previewer/preview_amplitudejs.adoc +69 -36
  95. data/lib/starter_web/pages/public/tools/tester/app_tester_amplitudejs_yt.adoc +65 -18
  96. data/lib/starter_web/pages/public/tools/tester/app_tester_swiper.adoc +87 -0
  97. data/lib/starter_web/pages/public/tools/tester/app_tester_swiperjs.adoc +121 -36
  98. data/lib/starter_web/pages/public/tour/_includes/attributes.asciidoc +3 -3
  99. data/lib/starter_web/pages/public/tour/{play_audio.adoc → audio_data.adoc} +51 -86
  100. data/lib/starter_web/pages/public/tour/{present_images.adoc → image_data.adoc} +4 -5
  101. data/lib/starter_web/pages/public/tour/{play_video.adoc → video_data.adoc} +18 -17
  102. metadata +52 -17
  103. data/assets/theme/j1/modules/swiperjs/js/highlightJS.js +0 -13376
  104. data/assets/theme/j1/modules/swiperjs/js/highlightJS.min.js +0 -1246
  105. data/assets/theme/j1/modules/swiperjs/js/modules/!readme +0 -3
  106. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/!info/!readme +0 -0
  107. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/!readme +0 -0
  108. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/1.jpg +0 -0
  109. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/2.jpg +0 -0
  110. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/3.jpg +0 -0
  111. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/4.jpg +0 -0
  112. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/5.jpg +0 -0
  113. /data/lib/starter_web/assets/image/module/swiper/extended/{poster → stacked}/image/6.jpg +0 -0
@@ -6,8 +6,8 @@ regenerate: true
6
6
 
7
7
  {% comment %}
8
8
  # -----------------------------------------------------------------------------
9
- # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.js
10
- # AmplitudeJS V5 Plugin|Tech for J1 Template
9
+ # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.31.js
10
+ # AmplitudeJS V5 Tech for J1 Template
11
11
  #
12
12
  # Product/Info:
13
13
  # https://jekyll.one
@@ -42,7 +42,7 @@ regenerate: true
42
42
 
43
43
  {% comment %} Set config data (settings only)
44
44
  -------------------------------------------------------------------------------- {% endcomment %}
45
- {% assign amplitude_defaults = modules.defaults.amplitude_app.defaults %}
45
+ {% assign amplitude_defaults = modules.defaults.amplitude.defaults %}
46
46
  {% assign amplitude_players = modules.amplitude_app.settings %}
47
47
  {% assign amplitude_playlists = modules.amplitude_playlists.settings %}
48
48
 
@@ -60,7 +60,7 @@ regenerate: true
60
60
 
61
61
  /*
62
62
  # -----------------------------------------------------------------------------
63
- # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.js
63
+ # ~/assets/theme/j1/modules/amplitudejs/js/plugins/tech/ytp.31.js
64
64
  # AmplitudeJS V5 Plugin|Tech for J1 Template
65
65
  #
66
66
  # Product/Info:
@@ -74,95 +74,397 @@ regenerate: true
74
74
  */
75
75
  "use strict";
76
76
 
77
- // date|time monitoring
78
- //------------------------------------------------------------------------------
79
- var startTime;
80
- var endTime;
81
- var startTimeModule;
82
- var endTimeModule;
83
- var timeSeconds;
84
-
85
- // YT API settings
86
- // -----------------------------------------------------------------------------
87
- var YT_PLAYER_STATE = {
88
- UNSTARTED: -1,
89
- ENDED: 0,
90
- PLAYING: 1,
91
- PAUSED: 2,
92
- BUFFERING: 3,
93
- CUED: 5
94
- };
95
-
96
- var firstScriptTag;
97
- var ytPlayer;
98
- var ytPlayerReady = false;
99
- var ytApiReady = false;
100
- var logger = log4javascript.getLogger('j1.adapter.amplitude.tech');
101
-
102
- // YT Player settings data (created dynamically)
103
- // -----------------------------------------------------------------------------
104
- // var ytPlayers = {};
105
- // var ytPlayersMap = new Map();
106
-
107
- // AmplitudeJS API settings
108
- // -----------------------------------------------------------------------------
109
-
110
- var dependency;
111
- var playerCounter = 0;
112
- var load_dependencies = {};
113
-
114
- // set default song index to FIRST item
115
- var songIndex = 0;
116
- var ytpSongIndex = 0;
117
-
118
- var ytpAutoPlay = false;
119
- var ytpLoop = true;
120
- var playLists = {};
121
- var playersUILoaded = { state: false };
122
- var apiInitialized = { state: false };
123
-
124
- var amplitudeDefaults = $.extend({}, {{amplitude_defaults | replace: 'nil', 'null' | replace: '=>', ':' }});
125
- var amplitudePlayers = $.extend({}, {{amplitude_players | replace: 'nil', 'null' | replace: '=>', ':' }});
126
- var amplitudePlaylists = $.extend({}, {{amplitude_playlists | replace: 'nil', 'null' | replace: '=>', ':' }});
127
- var amplitudeOptions = $.extend(true, {}, amplitudeDefaults, amplitudePlayers, amplitudePlaylists);
128
-
129
- var playerExistsInPage = false;
130
- var ytpContainer = null;
131
- var playerProperties = {};
132
- var playList;
133
- var playerProperties;
134
- var playerID;
135
- var playerType;
136
- var playListTitle;
137
- var playListName;
138
- var amplitudePlayerState;
139
- var ytPlayer;
140
- var ytpPlaybackRate
141
-
142
- var songs;
143
- var songMetaData;
144
- var songURL;
145
-
146
- var progress;
147
-
148
- // ---------------------------------------------------------------------------
149
- // Base YT functions and events
150
- // ---------------------------------------------------------------------------
151
-
152
- // Recursive function to MERGE objects
153
- var mergeObject = function() {
154
- mergeObject = Object.assign || function mergeObject(t) {
155
- for (var s, i=1, n=arguments.length; i<n; i++) {
156
- s = arguments[i];
157
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
158
- }
159
- return t;
160
- };
161
- return mergeObject.apply(this, arguments);
77
+ // date|time monitoring
78
+ //----------------------------------------------------------------------------
79
+ var startTime;
80
+ var endTime;
81
+ var startTimeModule;
82
+ var endTimeModule;
83
+ var timeSeconds;
84
+
85
+ // YT API settings
86
+ // ---------------------------------------------------------------------------
87
+ var YT_PLAYER_STATE = {
88
+ UNSTARTED: -1,
89
+ ENDED: 0,
90
+ PLAYING: 1,
91
+ PAUSED: 2,
92
+ BUFFERING: 3,
93
+ CUED: 5
94
+ };
95
+
96
+ var YT_PLAYER_STATE_NAMES = {
97
+ 0: "ended",
98
+ 1: "playing",
99
+ 2: "paused",
100
+ 3: "buffering",
101
+ 4: "not_used",
102
+ 5: "cued",
103
+ 6: "unstarted",
162
104
  };
163
105
 
106
+ // date|time monitoring
107
+ //----------------------------------------------------------------------------
108
+ var startTime;
109
+ var endTime;
110
+ var startTimeModule;
111
+ var endTimeModule;
112
+ var timeSeconds;
113
+
114
+ // AmplitudeJS API settings
115
+ // ---------------------------------------------------------------------------
116
+ var firstScriptTag;
117
+ var ytPlayer;
118
+ var ytPlayerReady = false;
119
+ var ytApiReady = false;
120
+ var logger = log4javascript.getLogger('j1.adapter.amplitude.tech');
121
+
122
+ var dependency;
123
+ var playerCounter = 0;
124
+ var load_dependencies = {};
125
+
126
+ // set default song index to FIRST track (video) in playlist
127
+ var songIndex = 0;
128
+ var ytpSongIndex = 0;
129
+
130
+ var ytpAutoPlay = false;
131
+ var ytpLoop = true;
132
+ var playLists = {};
133
+ var playersUILoaded = { state: false };
134
+ var apiInitialized = { state: false };
135
+
136
+ var amplitudeDefaults = $.extend({}, {{amplitude_defaults | replace: 'nil', 'null' | replace: '=>', ':' }});
137
+ var amplitudePlayers = $.extend({}, {{amplitude_players | replace: 'nil', 'null' | replace: '=>', ':' }});
138
+ var amplitudePlaylists = $.extend({}, {{amplitude_playlists | replace: 'nil', 'null' | replace: '=>', ':' }});
139
+ var amplitudeOptions = $.extend(true, {}, amplitudeDefaults, amplitudePlayers, amplitudePlaylists);
140
+
141
+ var playerExistsInPage = false;
142
+ var ytpContainer = null;
143
+ var ytpBufferQuote = 0;
144
+ var playerProperties = {};
145
+ var activeVideoElement = {};
146
+ var ytPlayerCurrentTime = 0;
147
+ var singleAudio = false;
148
+
149
+ var playerScrollerSongElementMin = {{amplitude_defaults.player.player_scroller_song_element_min}};
150
+ var playerScrollControl = {{amplitude_defaults.player.player_scroll_control}};
151
+ var playerAutoScrollSongElement = {{amplitude_defaults.player.player_auto_scroll_song_element}};
152
+ var playerFadeAudio = {{amplitude_defaults.player.player_fade_audio}};
153
+ var playerPlaybackRate = '{{amplitude_defaults.player.player_playback_rate}}';
154
+
155
+ var muteAfterVideoSwitchInterval = {{amplitude_defaults.player.mute_after_video_switch_interval}};
156
+ var checkActiveVideoInterval = {{amplitude_defaults.player.check_active_video_interval}};
157
+
158
+ var playList;
159
+ var playerProperties;
160
+ var playerID;
161
+ var playerType;
162
+ var playListTitle;
163
+ var playListName;
164
+ var amplitudePlayerState;
165
+
166
+ var ytPlayer;
167
+
168
+
169
+ var songs;
170
+ var songMetaData;
171
+ var songURL;
172
+
173
+ var progress;
174
+
175
+ // ---------------------------------------------------------------------------
176
+ // Base YT functions
177
+ // ===========================================================================
178
+
179
+ // ---------------------------------------------------------------------------
180
+ // mergeObject
181
+ // ---------------------------------------------------------------------------
182
+ // function mergeObject() {
183
+ // mergeObject = Object.assign || function mergeObject(t) {
184
+ // for (var s, i=1, n=arguments.length; i<n; i++) {
185
+ // s = arguments[i];
186
+ // for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
187
+ // }
188
+ // return t;
189
+ // };
190
+
191
+ // return mergeObject.apply(this, arguments);
192
+ // } // END mergeObject
193
+
194
+ // ---------------------------------------------------------------------------
195
+ // processOnVideoStart(trackID, player, startSec)
196
+ //
197
+ // ---------------------------------------------------------------------------
198
+ function processOnVideoStart(player, startSec) {
199
+ var currentVolume, playlist, playerID,
200
+ videoID, songIndex, trackID;
201
+
202
+ playlist = activeVideoElement.playlist;
203
+ playerID = playlist + '_large';
204
+ videoID = player.options.videoId;
205
+ songIndex = activeVideoElement.index;
206
+ trackID = songIndex + 1;
207
+
208
+ // seek video to START position
209
+ ytpSeekTo(player, startSec, true);
210
+
211
+ // fade-in audio (if enabled)
212
+ if (playerFadeAudio) {
213
+ currentVolume = player.getVolume();
214
+ logger.debug('\n' + `FADE-IN audio on StateChange at trackID|VideoID: ${trackID}|${videoID}`);
215
+ ytpFadeInAudio({
216
+ playerID: playerID,
217
+ targetVolume: currentVolume,
218
+ speed: 'default'
219
+ });
220
+ } // END if playerFadeAudio
221
+
222
+ } // END processOnVideoStart
223
+
224
+ // ---------------------------------------------------------------------------
225
+ // processOnVideoEnd(player)
226
+ //
227
+ // TODO:
228
+ // ---------------------------------------------------------------------------
229
+ function processOnVideoEnd(player) {
230
+ var currentVideoTime,
231
+ playlist, playerID, songIndex, songs,
232
+ trackID, activeVideoID, previousVideoID, isVideoChanged;
233
+
234
+ playlist = activeVideoElement.playlist;
235
+ playerID = playlist + '_large';
236
+ currentVideoTime = player.getCurrentTime();
237
+ previousVideoID = player.options.videoId;
238
+ activeVideoID = activeVideoElement.videoID;
239
+ songIndex = activeVideoElement.index;
240
+ trackID = songIndex + 1;
241
+ songs = activeVideoElement.songs;
242
+
243
+ // check if video is changed (to detect multiple videoIDs in playlist)
244
+ if (songIndex > 0) {
245
+ isVideoChanged = (previousVideoID !== activeVideoID) ? true : false;
246
+ } else {
247
+ isVideoChanged = true;
248
+ }
249
+
250
+ // fade-out audio (if enabled)
251
+ if (isVideoChanged && playerFadeAudio) {
252
+ logger.debug('\n' + `FADE-OUT audio on processOnVideoEnd at trackID|VideoID: ${trackID}|${activeVideoID}`);
253
+ ytpFadeOutAudio({
254
+ playerID: playerID,
255
+ speed: 'default'
256
+ });
257
+ } // END if playerFadeAudio
258
+
259
+ // if (!activeVideoElement.audio_single) {
260
+ if (isVideoChanged) {
261
+ // load next video
262
+ logger.debug('\n' + `LOAD next VIDEO on processOnVideoEnd at trackID|playlist: ${trackID}|${playlist}`);
263
+ loadNextVideo(playlist, songIndex);
264
+ } else {
265
+ // skip loading next video if a single video is used for playlist
266
+ logger.debug('\n' + `LOAD next TRACK in video on processOnVideoEnd at trackID|playlist: ${trackID}|${playlist}`);
267
+ }
268
+
269
+ } // END processOnVideoEnd
270
+
271
+ // ---------------------------------------------------------------------------
272
+ // doNothingOnStateChange(state)
273
+ //
274
+ // wrraper for states that are not processed
275
+ // ---------------------------------------------------------------------------
276
+ function doNothingOnStateChange(state) {
277
+ if (state > 0) {
278
+ logger.warn('\n' + `DO NOTHING on StateChange for state: ${YT_PLAYER_STATE_NAMES[state]}`);
279
+ } else {
280
+ logger.warn('\n' + `DO NOTHING on StateChange for state: ${YT_PLAYER_STATE_NAMES[6]}`);
281
+ }
282
+ } // END doNothingOnStateChange
283
+
284
+ // ---------------------------------------------------------------------------
285
+ // processOnStateChangePlaying()
286
+ //
287
+ // wrraper for processing on stae PLAYING
288
+ // ---------------------------------------------------------------------------
289
+ function processOnStateChangePlaying(event, playlist, songIndex) {
290
+ var activeSong, playlist, playerID, videoID,
291
+ ytPlayer, songs, songIndex,
292
+ currentPlayer, previousPlayer, trackID;
293
+
294
+ ytPlayer = event.target;
295
+
296
+ // update active song settings (manually)
297
+ checkActiveVideoElementYTP();
298
+
299
+ // get active song settings (manually)
300
+ activeSong = getActiveSong();
301
+
302
+ playlist = activeSong.playlist;
303
+ playerID = activeSong.playerID;
304
+ videoID = activeSong.videoID;
305
+ songs = activeSong.songs;
306
+ songIndex = activeSong.index;
307
+ currentPlayer = activeSong.player;
308
+ previousPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player
309
+
310
+ // save YT player GLOBAL data for later use (e.g. events)
311
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
312
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
313
+ j1.adapter.amplitude.data.ytpGlobals['videoID'] = videoID;
314
+
315
+ // save YT player data for later use (e.g. events)
316
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
317
+
318
+ // update time container for the ACTIVE video
319
+ // -----------------------------------------------------------------
320
+ setInterval(function() {
321
+ updateCurrentTimeContainerYTP(ytPlayer, playlist);
322
+ }, 500);
323
+
324
+ // update time progressbar for the ACTIVE video
325
+ // -----------------------------------------------------------------
326
+ setInterval(function() {
327
+ updateProgressBarsYTP();
328
+ }, 500);
329
+
330
+ trackID = songIndex + 1;
331
+ logger.debug('\n' + `PLAY video on StateChange at trackID|VideoID: ${trackID}|${videoID}`);
332
+
333
+ // check|process video for configured START position (if set)
334
+ // -------------------------------------------------------------------------
335
+ var songStartSec = activeSong.startSec;
336
+ if (songStartSec) {
337
+ var tsStartSec = seconds2timestamp(songStartSec);
338
+ var songCurrentTime = ytPlayer.getCurrentTime();
339
+
340
+ if (songCurrentTime < songStartSec) {
341
+ logger.debug('\n' + `START video on StateChange at trackID|timestamp: ${trackID}|${tsStartSec}`);
342
+ processOnVideoStart(ytPlayer, songStartSec);
343
+ }
344
+ } // END if songStartEnabled
345
+
346
+ // check|process video for configured END position (if set)
347
+ // -------------------------------------------------------------------------
348
+ var songEndSec = activeSong.endSec;
349
+ if (songEndSec) {
350
+ var tsEndSec = seconds2timestamp(songEndSec);
351
+
352
+ var checkOnVideoEnd = setInterval(function() {
353
+ var songCurrentTime = ytPlayer.getCurrentTime();
354
+
355
+ if (songCurrentTime >= songEndSec) {
356
+ logger.debug('\n' + `STOP video on StateChange at trackID|timestamp: ${trackID}|${tsEndSec}`);
357
+ processOnVideoEnd(ytPlayer);
358
+
359
+ clearInterval(checkOnVideoEnd);
360
+ } // END if currentVideoTime
361
+ }, 500); // END checkOnVideoEnd
362
+ } // END if songEndEnabled
363
+
364
+ // stop active AT players running in parallel
365
+ // -------------------------------------------------------------------------
366
+ var atpPlayerState = Amplitude.getPlayerState();
367
+ if (atpPlayerState === 'playing') {
368
+ Amplitude.stop();
369
+
370
+ // clear button MINI PlayerPlayPause (AT player)
371
+ var buttonPlayerPlayPauseMini = document.getElementsByClassName("mini-player-play-pause");
372
+ for (var i=0; i<buttonPlayerPlayPauseMini.length; i++) {
373
+ var htmlElement = buttonPlayerPlayPauseMini[i];
374
+
375
+ if (htmlElement.dataset.amplitudeSource === 'audio') {
376
+ htmlElement.classList.remove('amplitude-playing');
377
+ htmlElement.classList.add('amplitude-paused');
378
+ }
379
+
380
+ } // END for MINI buttonPlayerPlayPause
381
+
382
+ // clear button COMPACT PlayerPlayPause (AT player)
383
+ var buttonPlayerPlayPauseCompact = document.getElementsByClassName("compact-player-play-pause");
384
+ for (var i=0; i<buttonPlayerPlayPauseCompact.length; i++) {
385
+ var htmlElement = buttonPlayerPlayPauseCompact[i];
386
+
387
+ if (htmlElement.dataset.amplitudeSource === 'audio') {
388
+ htmlElement.classList.remove('amplitude-playing');
389
+ htmlElement.classList.add('amplitude-paused');
390
+ }
391
+
392
+ } // END for COMACT buttonPlayerPlayPause
393
+
394
+ // clear button LARGE PlayerPlayPause (AT player)
395
+ var buttonPlayerPlayPauseLarge = document.getElementsByClassName("large-player-play-pause");
396
+ for (var i=0; i<buttonPlayerPlayPauseLarge.length; i++) {
397
+ var htmlElement = buttonPlayerPlayPauseLarge[i];
398
+
399
+ if (htmlElement.dataset.amplitudeSource === 'audio') {
400
+ htmlElement.classList.remove('amplitude-playing');
401
+ htmlElement.classList.add('amplitude-paused');
402
+ }
403
+
404
+ } // END for LARGE buttonPlayerPlayPause
405
+
406
+ } // END if atpPlayerState 'playing'
407
+
408
+ // TODO: check if YT player stop is needed
409
+ // -------------------------------------------------------------------------
410
+ // stop active YT players running in parallel except the current
411
+ // if (previousPlayer.options.videoId !== videoID) {
412
+ // logger.debug('\n' + `STOP all video on StateChange running in parallel at trackID|playerID: ${trackID}|${playerID}`);
413
+ // var playerState = (previousPlayer.getPlayerState() > 0) ? previousPlayer.getPlayerState() : 6;
414
+ // var ytPlayerState = YT_PLAYER_STATE_NAMES[playerState];
415
+ //
416
+ // if (ytPlayerState === 'playing' || ytPlayerState === 'paused') {
417
+ // previousPlayer.stopVideo();
418
+ // }
419
+ // }
420
+ //
421
+ // stopAllActivePlayers(playerID);
422
+
423
+ } // END processOnStateChangePlaying
424
+
425
+
426
+ // ---------------------------------------------------------------------------
427
+ // processOnStateChangeEnded()
428
+ //
429
+ // ---------------------------------------------------------------------------
430
+ function processOnStateChangeEnded(event, playlist, songIndex) {
431
+ var videoID = event.target.options.videoId;
432
+ var trackID = songIndex + 1;
433
+
434
+ // save player current time data for later use
435
+ ytPlayerCurrentTime = ytPlayer.getCurrentTime();
436
+
437
+ logger.debug('\n' + `NEXT video on StateChange at trackID|VideoID: ${trackID}|${videoID}`);
438
+
439
+ // load NEXT song (video) in playlist
440
+ loadNextVideo(playlist, songIndex);
441
+
442
+ } // END processOnStateChangeEnded
443
+
444
+ // ---------------------------------------------------------------------------
445
+ // getSongIndex(songArray, videoID)
446
+ //
447
+ // TODO: Extend getSongIndex() for singleAudio
448
+ // ---------------------------------------------------------------------------
449
+ function getSongIndex(songArray, videoID) {
450
+ var index;
451
+
452
+ for (var i=0; i<songArray.length; i++) {
453
+ if (songArray[i].url.includes(videoID)) {
454
+ index = songArray[i].index;
455
+ break;
456
+ }
457
+ }
458
+
459
+ return index;
460
+ }
461
+
462
+ // ---------------------------------------------------------------------------
463
+ // addNestedProperty
464
+ //
164
465
  // Add property path dynamically to an existing object
165
466
  // Example: addNestedProperty(j1.adapter.amplitude.data, 'playlist.profile.name', 'Max Mustermann')
467
+ // ---------------------------------------------------------------------------
166
468
  function addNestedProperty(obj, path, value) {
167
469
  let current = obj;
168
470
  const properties = path.split('.');
@@ -179,6 +481,9 @@ var progress;
179
481
  });
180
482
  }
181
483
 
484
+ // ---------------------------------------------------------------------------
485
+ // setNestedProperty
486
+ // ---------------------------------------------------------------------------
182
487
  function setNestedProperty(obj, path, value) {
183
488
  const keys = path.split('.');
184
489
 
@@ -198,8 +503,12 @@ var progress;
198
503
  setNestedProperty(current, keys.slice(1).join('.'), value);
199
504
  }
200
505
 
506
+ // ---------------------------------------------------------------------------
507
+ // addNestedObject
508
+ //
201
509
  // Add (nested) object dynamically to an existing object
202
- // Example: createNestedObject(myObject, ['level1', 'arrayProperty', 0], 'element1');
510
+ // Example: createNestedObject(myObject, ['level1', 'arrayProperty', 0], 'element1');
511
+ // ---------------------------------------------------------------------------
203
512
  function addNestedObject(obj, path, value) {
204
513
  const lastKey = path[path.length - 1];
205
514
  let current = obj;
@@ -212,7 +521,157 @@ var progress;
212
521
  current[lastKey] = value;
213
522
  }
214
523
 
524
+ // ---------------------------------------------------------------------------
525
+ // timestamp2seconds
526
+ // ---------------------------------------------------------------------------
527
+ function timestamp2seconds(timestamp) {
528
+ // split timestamp
529
+ const parts = timestamp.split(':');
530
+
531
+ // check timestamp format
532
+ if (parts.length !== 3) {
533
+ // return "invalid timestamp";
534
+ return false;
535
+ }
536
+
537
+ // convert parts to integers
538
+ const hours = parseInt(parts[0], 10);
539
+ const minutes = parseInt(parts[1], 10);
540
+ const seconds = parseInt(parts[2], 10);
541
+
542
+ // check valid timestamp values
543
+ if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) ||
544
+ hours < 0 || hours > 23 ||
545
+ minutes < 0 || minutes > 59 ||
546
+ seconds < 0 || seconds > 59) {
547
+ return "invalid timestamp";
548
+ }
549
+
550
+ const totalSeconds = (hours * 3600) + (minutes * 60) + seconds;
551
+ return totalSeconds;
552
+ } // END timestamp2seconds
553
+
554
+ // ---------------------------------------------------------------------------
555
+ // seconds2timestamp
556
+ // ---------------------------------------------------------------------------
557
+ function seconds2timestamp(seconds) {
558
+ const hours = Math.floor(seconds / 3600);
559
+ const minutes = Math.floor((seconds % 3600) / 60);
560
+ const remainSeconds = seconds % 60;
561
+ const tsHours = hours.toString().padStart(2, '0');
562
+ const tsMinutes = minutes.toString().padStart(2, '0');
563
+ const tsSeconds = remainSeconds.toString().padStart(2, '0');
564
+
565
+ return `${tsHours}:${tsMinutes}:${tsSeconds}`;
566
+ } // END seconds2timestamp
567
+
568
+ // ---------------------------------------------------------------------------
569
+ // ytpFadeInAudio
570
+ // ---------------------------------------------------------------------------
571
+ function ytpFadeInAudio(params) {
572
+ const cycle = 1;
573
+ var settings, currentStep, steps, sliderID, volumeSlider;
574
+
575
+ // current fade-in settings using DEFAULTS (if available)
576
+ settings = {
577
+ playerID: params.playerID,
578
+ targetVolume: params.targetVolume = 50,
579
+ speed: params.speed = 'default'
580
+ };
581
+
582
+ // number of iteration steps to INCREASE the players volume on fade-in
583
+ // NOTE: number of steps controls how long and smooth the fade-in
584
+ // transition will be
585
+ const iterationSteps = {
586
+ 'default': 150,
587
+ 'slow': 250,
588
+ 'slower': 350,
589
+ 'slowest': 500
590
+ };
591
+
592
+ sliderID = 'volume_slider_' + settings.playerID;
593
+ volumeSlider = document.getElementById(sliderID);
594
+ steps = iterationSteps[settings.speed];
595
+ currentStep = 1;
596
+
597
+ if (volumeSlider === undefined || volumeSlider === null) {
598
+ logger.warn('\n' + 'no volume slider found at playerID: ' + settings.playerID);
599
+ return;
600
+ }
601
+
602
+ // (ytPlayer.isMuted()) && ytPlayer.unMute();
603
+
604
+ // skip fade-in when volume is already at target value
605
+ // if (ytPlayer.getVolume() >= targetVolume) {
606
+ // logger.warn('\n' + 'skipped fade-in for current video on volume: ', targetVolume);
607
+ // return;
608
+ // }
609
+
610
+ // Start the players volume muted
611
+ ytPlayer.setVolume(0);
612
+
613
+ const fadeInInterval = setInterval(() => {
614
+ const newVolume = settings.targetVolume * (currentStep / steps);
615
+
616
+ ytPlayer.setVolume(newVolume);
617
+ volumeSlider.value = newVolume;
618
+ currentStep++;
619
+
620
+ (currentStep > steps) && clearInterval(fadeInInterval);
621
+ }, cycle);
622
+
623
+ } // END ytpFadeInAudio
624
+
625
+ // ---------------------------------------------------------------------------
626
+ // ytpFadeOutAudio
627
+ // ---------------------------------------------------------------------------
628
+ function ytpFadeOutAudio(params) {
629
+ const cycle = 1;
630
+ var settings, currentStep, steps, newVolume, startVolume,
631
+ playerID, sliderID, volumeSlider;
632
+
633
+ // current fade-in settings using DEFAULTS (if available)
634
+ settings = {
635
+ playerID: params.playerID,
636
+ speed: params.speed = 'default'
637
+ };
638
+
639
+ // number of iteration steps to DECREASE the volume
640
+ const iterationSteps = {
641
+ 'default': 150,
642
+ 'slow': 250,
643
+ 'slower': 350,
644
+ 'slowest': 500
645
+ };
646
+
647
+ sliderID = 'volume_slider_' + settings.playerID;
648
+ volumeSlider = document.getElementById(sliderID);
649
+ startVolume = ytPlayer.getVolume();
650
+ steps = iterationSteps[settings.speed];
651
+ currentStep = 0;
652
+
653
+ if (volumeSlider === undefined || volumeSlider === null) {
654
+ logger.warn('\n' + 'no volume slider found at playerID: ' + settings.playerID);
655
+ return;
656
+ }
657
+
658
+ const fadeOutInterval = setInterval(() => {
659
+ newVolume = startVolume * (1 - currentStep / steps);
660
+
661
+ ytPlayer.setVolume(newVolume);
662
+ volumeSlider.value = newVolume;
663
+ currentStep++;
664
+
665
+ (currentStep > steps) && clearInterval(fadeOutInterval);
666
+ }, cycle);
667
+
668
+ } // END ytpFadeOutAudio
669
+
670
+ // ---------------------------------------------------------------------------
671
+ // initYtAPI
672
+ //
215
673
  // load YT Iframe player API
674
+ // ---------------------------------------------------------------------------
216
675
  function initYtAPI() {
217
676
  startTimeModule = Date.now();
218
677
 
@@ -227,10 +686,139 @@ var progress;
227
686
  firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
228
687
  }
229
688
 
230
- // setup YTPlayerUiEvents for AJS players
689
+ // ---------------------------------------------------------------------------
690
+ // loadNextVideo(list, index)
691
+ //
692
+ // load next video in playlist
693
+ // ---------------------------------------------------------------------------
694
+ function loadNextVideo(currentPlaylist, currentIndex) {
695
+ var activeSongSettings, trackID, songName, playlist, playerID, playerIFrame,
696
+ songs, songIndex, songMetaData, songURL, ytpVideoID;
697
+
698
+ // update active song settings (manually)
699
+ checkActiveVideoElementYTP();
700
+
701
+ // get active song settings (manually)
702
+ activeSongSettings = getActiveSong();
703
+
704
+ playlist = currentPlaylist;
705
+ playerID = playlist + '_large';
706
+ songs = activeSongSettings.songs;
707
+ ytPlayer = activeSongSettings.player;
708
+ songIndex = currentIndex;
709
+ trackID = songIndex + 1;
710
+
711
+ songIndex++;
712
+
713
+ ytpSongIndex = songIndex;
714
+
715
+
716
+ // play sonng (video) in playlist
717
+ if (songIndex <= songs.length - 1) {
718
+ songMetaData = songs[songIndex];
719
+ songURL = songMetaData.url;
720
+ ytVideoID = songURL.split('=')[1];
721
+
722
+ // save YT player data for later use (e.g. events)
723
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
724
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytVideoID;
725
+
726
+
727
+ logger.debug('\n' + `SWITCH video on loadNextVideo at trackID|VideoID: ${trackID}|${ytVideoID}`);
728
+ ytPlayer.loadVideoById(ytVideoID);
729
+
730
+ // delay after switch video
731
+ if (muteAfterVideoSwitchInterval) {
732
+ ytPlayer.mute();
733
+ setTimeout(() => {
734
+ ytPlayer.unMute();
735
+ }, muteAfterVideoSwitchInterval);
736
+ }
737
+
738
+ // update global song index
739
+ ytpSongIndex = songIndex;
740
+
741
+ // load the song cover image
742
+ loadCoverImage(songMetaData);
743
+
744
+ // update meta data
745
+ updatMetaContainers(songMetaData);
746
+
747
+ // set song (video) active at index in playlist
748
+ setSongActive(playlist, songIndex);
749
+
750
+ // reset progress bar settings
751
+ resetProgressBarYTP();
752
+
753
+ // scroll song active at index in player
754
+ if (playerAutoScrollSongElement) {
755
+ scrollToActiveElement(playlist);
756
+ }
757
+ } else {
758
+ // continue on FIRST track (video) in playlist
759
+ //
760
+ songIndex = 0;
761
+ var songMetaData = songs[songIndex];
762
+ var songURL = songMetaData.url;
763
+ var ytVideoID = songURL.split('=')[1];
764
+
765
+ // update global song index
766
+ ytpSongIndex = songIndex;
767
+
768
+ // load next video (paused)
769
+ // -----------------------------------------------------------------------
770
+
771
+ // save YT player data for later use (e.g. events)
772
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
773
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytpVideoID;
774
+
775
+ logger.debug('\n' + `SWITCH video on loadNextVideo at trackID|VideoID: ${trackID}|${ytVideoID}`);
776
+ ytPlayer.loadVideoById(ytVideoID);
777
+
778
+ // delay after switch video
779
+ if (muteAfterVideoSwitchInterval) {
780
+ ytPlayer.mute();
781
+ setTimeout(() => {
782
+ ytPlayer.unMute();
783
+ }, muteAfterVideoSwitchInterval);
784
+ }
785
+
786
+ // load the song cover image
787
+ loadCoverImage(songMetaData);
788
+
789
+ // update meta data
790
+ updatMetaContainers(songMetaData);
791
+
792
+ // set AJS play_pause button paused
793
+ var playPauseButtonClass = `large-player-play-pause-${playerID}`
794
+ setPlayPauseButtonPaused(playPauseButtonClass);
795
+
796
+ // set song (video) active at index in playlist
797
+ setSongActive(playlist, songIndex);
798
+
799
+ // reset progress bar settings
800
+ resetProgressBarYTP();
801
+
802
+ // scroll song active at index in player
803
+ if (playerAutoScrollSongElement) {
804
+ scrollToActiveElement(playlist);
805
+ }
806
+
807
+ // TODO: check if SHUFFLE is enabled on PLAYLIST (PLAYER ???)
808
+ // set FIRST song (video) paused
809
+ ytPlayer.pauseVideo();
810
+ }
811
+
812
+ } // END loadVideo
813
+
814
+ // ---------------------------------------------------------------------------
815
+ // initUiEventsForAJS
816
+ //
817
+ // setup YTPlayerUiEvents for AJS players
818
+ // ---------------------------------------------------------------------------
231
819
  function initUiEventsForAJS() {
232
820
 
233
- var dependencies_ytp_ready = setInterval (() => {
821
+ var dependencies_ytp_ready = setInterval (() => {
234
822
  var ytApiReady = (j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] !== undefined) ? j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] : false;
235
823
  var ytPlayerReady = (j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] !== undefined) ? j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] : false;
236
824
 
@@ -245,7 +833,7 @@ var progress;
245
833
  {% endif %}
246
834
 
247
835
  {% if player_source == 'video' %}
248
- var playerID = '{{player.id}}';
836
+ playerID = '{{player.id}}';
249
837
  mimikYTPlayerUiEventsForAJS(playerID);
250
838
  {% endif %}
251
839
 
@@ -256,22 +844,20 @@ var progress;
256
844
  } // END if ready
257
845
 
258
846
  }, 10); // END dependencies_ytp_ready
847
+
259
848
  } // END initUiEventsForAJS()
260
849
 
850
+ // ---------------------------------------------------------------------------
851
+ // onYouTubeIframeAPIReady
852
+ //
261
853
  // Create a player after Iframe player API is ready to use
262
854
  // ---------------------------------------------------------------------------
263
855
  function onYouTubeIframeAPIReady() {
264
- // var currentOptions;
265
- var playerSource;
266
-
267
- ytApiReady = true;
268
- // currentOptions = $.extend({}, {{amplitude_options | replace: 'nil', 'null' | replace: '=>', ':' }});
856
+ ytApiReady = true;
269
857
 
270
- {% for player in amplitude_options.players %}{% if player.enabled %}
858
+ {% for player in amplitude_options.players %}{% if player.enabled and player.source == 'video' %}
271
859
  {% capture xhr_container_id %}{{player.id}}_app{% endcapture %}
272
860
 
273
- playerSource = '{{player.source}}';
274
-
275
861
  {% if player.source == empty %}
276
862
  {% assign player_source = amplitude_defaults.player.source %}
277
863
  {% else %}
@@ -282,7 +868,7 @@ var progress;
282
868
  {% continue %}
283
869
  {% else %}
284
870
  // load players of type 'video' configured in current page
285
- //
871
+ // ---------------------------------------------------------------------
286
872
  playerExistsInPage = ($('#' + '{{xhr_container_id}}')[0] !== undefined) ? true : false;
287
873
  if (playerExistsInPage) {
288
874
  var playerSettings = $.extend({}, {{player | replace: 'nil', 'null' | replace: '=>', ':' }});
@@ -319,8 +905,8 @@ var progress;
319
905
  loop: ytpLoop
320
906
  },
321
907
  events: {
322
- 'onReady': {{player.id}}OnPlayerReady,
323
- 'onStateChange': {{player.id}}OnPlayerStateChange
908
+ 'onReady': {{player.id}}OnPlayerReady,
909
+ 'onStateChange': {{player.id}}OnPlayerStateChange
324
910
  }
325
911
  });
326
912
 
@@ -343,42 +929,78 @@ var progress;
343
929
  // store player properties for later use
344
930
  addNestedProperty(j1.adapter.amplitude.data.ytPlayers, '{{player.id}}', playerProperties);
345
931
 
346
- // save YT player data for later use (e.g. events)
347
- // j1.adapter.amplitude.data.ytpGlobals['ytVideoID'] = ytpVideoID;
348
- // j1.adapter.amplitude.data.ytpGlobals['ytPlayerDefaults'] = amplitudeDefaults.player;
349
- // j1.adapter.amplitude.data.ytpGlobals['ytPlayerSettings'] = playerSettings;
350
- j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] = ytApiReady;
932
+ // save YT player GLOBAL data for later use (e.g. events)
933
+ j1.adapter.amplitude.data.ytpGlobals['ytApiReady'] = ytApiReady;
351
934
 
352
-
353
935
  // reset current player
354
936
  playerExistsInPage = false;
355
937
 
356
938
  } // END if playerExistsInPage()
357
939
 
940
+ function checkPlayingStatus(player) {
941
+ if (player.getPlayerState() === YT_PLAYER_STATE.PLAYING) {
942
+ // code run after video is playing
943
+ // console.debug("checkPlayingStatus: AJS YouTube Player state: PLAYING");
944
+ // do nothing
945
+ return;
946
+ } else {
947
+ // re-check player state required
948
+ // console.debug("checkPlayingStatus: AJS YouTube Player state:", player.getPlayerState());
949
+ }
950
+ } // END checkPlayingStatus
951
+
358
952
  // run AJS YouTube Player initialization
359
953
  // ---------------------------------------------------------------------
360
954
  function {{player.id}}OnPlayerReady(event) {
361
- var hours, minutes, seconds;
362
- var ytPlayer = event.target;
363
- var ytPlayerReady = true;
955
+ var hours, minutes, seconds,
956
+ ytPlayer, ytPlayerReady, playerVolumePreset,
957
+ playListName, songsInPlaylist, titleListLargePlayer;
958
+
959
+ ytPlayer = event.target;
960
+ ytPlayerReady = true;
961
+ playerVolumePreset = parseInt({{player.volume_slider.preset_value}});
962
+
963
+ logger.debug('\n' + `FOUND video ready at ID: {{player.id}}`);
964
+
965
+ // set video playback quality to a minimum
966
+ ytPlayer.setPlaybackQuality('small');
967
+
968
+ // set configured player volume preset
969
+ ytPlayer.setVolume(playerVolumePreset);
970
+
971
+ // enable|disable scrolling on playlist
972
+ // -------------------------------------------------------------------
973
+ if (document.getElementById('large_player_right') !== null) {
974
+
975
+ // show|hide scrollbar in playlist
976
+ // -----------------------------------------------------------------
977
+ playListName = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerSettings.playlist.name;
978
+ songsInPlaylist = Amplitude.getSongsInPlaylist(playListName);
979
+ titleListLargePlayer = document.getElementById('large_player_title_list_' + playListName);
980
+
981
+ if (songsInPlaylist.length <= playerScrollerSongElementMin) {
982
+ if (titleListLargePlayer !== null) {
983
+ titleListLargePlayer.classList.add('hide-scrollbar');
984
+ }
985
+ }
986
+ }
364
987
 
365
988
  logger.info('\n' + 'AJS YouTube Player on ID {{player.id}}: ready');
366
989
 
367
- // save YT player data for later use (e.g. events)
990
+ // save YT player GLOBAL data for later use (e.g. events)
368
991
  j1.adapter.amplitude.data.ytpGlobals['ytPlayerReady'] = ytPlayerReady;
369
- j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerReady = ytPlayerReady;
370
992
 
371
- // setInterval(updateCurrentTimeContainerYTP, 1000);
372
- // setInterval(updateProgressBarsYTP, 1000)
993
+ // save YT player data for later use (e.g. events)
994
+ // j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerReady = ytPlayerReady;
373
995
 
374
996
  // get duration hours (if configured)
375
997
  if ({{player.display_hours}} ) {
376
- hours = ytpGetDurationHours (ytPlayer);
998
+ hours = ytpGetDurationHours(ytPlayer);
377
999
  }
378
1000
 
379
1001
  // get duration minutes|seconds
380
- minutes = ytpGetDurationMinutes (ytPlayer);
381
- seconds = ytpGetDurationSeconds (ytPlayer);
1002
+ minutes = ytpGetDurationMinutes(ytPlayer);
1003
+ seconds = ytpGetDurationSeconds(ytPlayer);
382
1004
 
383
1005
  // set duration time values for current video
384
1006
  // -------------------------------------------------------------------
@@ -409,210 +1031,243 @@ var progress;
409
1031
  logger.warn('\n' + 'Found NO players of type video (YTP) in page');
410
1032
  }
411
1033
 
1034
+ // update activeVideoElement data structure for the ACTIVE video
1035
+ // -------------------------------------------------------------------
1036
+ setInterval(function() {
1037
+ checkActiveVideoElementYTP();
1038
+ }, checkActiveVideoInterval);
1039
+ // END checkActiveVideoElementYTP
1040
+
412
1041
  logger.info('\n' + 'plugin|tech initializing time: ' + (endTimeModule-startTimeModule) + 'ms');
413
1042
 
414
1043
  } // END onPlayerReady()
415
1044
 
416
- // update YT player elements on state change (playing)
1045
+ // ---------------------------------------------------------------------
1046
+ // OnPlayerStateChange
1047
+ //
1048
+ // process all YT Player specific state changes
1049
+ // ---------------------------------------------------------------------
1050
+ // NOTE:
1051
+ // The YT API fires a lot of INTERMEDIATE states. MOST of them gets
1052
+ // ignored (do nothing). For state PLAYING, important initial values
1053
+ // are being set; e.g. start|stop positions for a video (when)
1054
+ // configured.
417
1055
  // ---------------------------------------------------------------------
418
1056
  function {{player.id}}OnPlayerStateChange(event) {
419
- var playlist = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.playerSettings.playlist.name;
420
- var playerID = playlist + '_large';
421
- var ytPlayer = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player;
422
- var songs = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.songs;
423
- // var activeIndex = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.activeIndex;
424
-
425
- // set active ytPlayer
426
- j1.adapter.amplitude.data.ytpGlobals['activePlayer'] = ytPlayer;
1057
+ var currentTime, playlist, ytPlayer, ytVideoID,
1058
+ songs, songIndex, trackID, playerID, songMetaData;
1059
+
1060
+ ytPlayer = event.target;
1061
+ ytVideoID = ytPlayer.options.videoId;
1062
+ playlist = '{{player.id}}'.replace('_large', '');
1063
+ playerID = '{{player.id}}';
1064
+ songs = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.songs;
1065
+ songIndex = ytpSongIndex; // getSongIndex(songs, ytVideoID);
1066
+ trackID = songIndex + 1;
1067
+ // songMetaData = songs[songIndex];
1068
+
1069
+ // save YT player GLOBAL data for later use (e.g. events)
1070
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
1071
+ j1.adapter.amplitude.data.ytpGlobals['activePlayer'] = ytPlayer;
1072
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
1073
+ j1.adapter.amplitude.data.ytpGlobals['activePlaylist'] = playlist;
427
1074
 
428
1075
  // save YT player data for later use (e.g. events)
429
- // j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player = ytPlayer;
1076
+ j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player = ytPlayer;
1077
+ j1.adapter.amplitude.data.ytPlayers.{{player.id}}.activeIndex = songIndex;
1078
+
1079
+ // reset time container|progressbar for the ACTIVE song (video)
1080
+ // -------------------------------------------------------------------
1081
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
1082
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
1083
+ resetProgressBarYTP();
1084
+
1085
+ // process all state changes fired by YT API
1086
+ // -------------------------------------------------------------------
1087
+ switch(event.data) {
1088
+ case YT_PLAYER_STATE.UNSTARTED:
1089
+ doNothingOnStateChange(YT_PLAYER_STATE.UNSTARTED);
1090
+ break;
1091
+ case YT_PLAYER_STATE.CUED:
1092
+ doNothingOnStateChange(YT_PLAYER_STATE.CUED);
1093
+ break;
1094
+ case YT_PLAYER_STATE.BUFFERING:
1095
+ doNothingOnStateChange(YT_PLAYER_STATE.BUFFERING);
1096
+ break;
1097
+ case YT_PLAYER_STATE.PAUSED:
1098
+ doNothingOnStateChange(YT_PLAYER_STATE.PAUSED);
1099
+ break;
1100
+ case YT_PLAYER_STATE.PLAYING:
1101
+ processOnStateChangePlaying(event, playlist, songIndex);
1102
+ break;
1103
+ case YT_PLAYER_STATE.ENDED:
1104
+ processOnStateChangeEnded(event, playlist, songIndex);
1105
+ break;
1106
+ default:
1107
+ logger.error('\n' + `UNKNOWN event on StateChange fired: ${event.data}`);
1108
+ } // END switch event.data
430
1109
 
431
- resetCurrentTimeContainerYTP();
432
- updateDurationTimeContainerYTP(ytPlayer);
1110
+ } // END {{player.id}}OnPlayerStateChange
433
1111
 
434
- // setInterval(updateCurrentTimeContainerYTP, 1000);
435
- // setInterval(updateProgressBarsYTP('{{player.id}}'), 1000)
1112
+ {% endif %}
1113
+ {% endif %}{% endfor %}
436
1114
 
437
- // Set the index of the active song (index starts by 0)
438
- // ytpSetActiveIndex({{player.id}}, activeIndex);
1115
+ } // END onYouTubeIframeAPIReady
439
1116
 
440
- if (event.data === YT_PLAYER_STATE.PLAYING || event.data === YT_PLAYER_STATE.BUFFERING) {
441
- setInterval(updateCurrentTimeContainerYTP, 1000);
442
- setInterval(updateProgressBarsYTP, 1000);
443
1117
 
444
- // j1.adapter.amplitude.data.ytpGlobals['activePlayer'] = ytPlayer;
445
- }
1118
+ // ---------------------------------------------------------------------------
1119
+ // main
1120
+ // ===========================================================================
446
1121
 
447
- // play next video
448
- if (event.data === YT_PLAYER_STATE.ENDED) {
1122
+ // ---------------------------------------------------------------------------
1123
+ // initYtAPI
1124
+ //
1125
+ // load|initialize YT Iframe player API
1126
+ // ---------------------------------------------------------------------------
1127
+ initYtAPI();
449
1128
 
450
- // var ytPlayer = j1.adapter.amplitude.data.ytpGlobals['ytPlayer'];
451
- // var ytPlayer = j1.adapter.amplitude.data.ytPlayers.{{player.id}}.player;
452
- // var songs = j1.adapter.amplitude.data.ytpGlobals['ytPlayerSongs'];
453
- // var songIndex = parseInt(j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex']) + 1;
1129
+ // ---------------------------------------------------------------------------
1130
+ // initUiEventsForAJS
1131
+ //
1132
+ // setup YTPlayerUiEvents for AJS players
1133
+ // ---------------------------------------------------------------------------
1134
+ initUiEventsForAJS();
454
1135
 
455
- var songIndex;
456
- songIndex = ytpSongIndex;
457
- songIndex++;
458
- ytpSongIndex = songIndex;
459
1136
 
460
- // var songIndex = j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex
461
- // songIndex++
1137
+ // ---------------------------------------------------------------------------
1138
+ // Base AJS Player functions
1139
+ // ===========================================================================
1140
+
1141
+ // ---------------------------------------------------------------------------
1142
+ // updatMetaContainers(metaData)
1143
+ //
1144
+ // update song name in meta-containers
1145
+ // ---------------------------------------------------------------------------
1146
+ function updatMetaContainers(metaData) {
1147
+ var playerID, playlist, songName, artistName, albumName,
1148
+ largePlayerSongAudioRating;
1149
+
1150
+ playlist = metaData.playlist;
1151
+ playerID = playlist + '_large';
1152
+
1153
+ var trackID = metaData.index + 1;
1154
+ logger.debug('\n' + `UPDATE metadata on updatMetaContainers for trackID|playlist at: ${trackID}|${playlist}`);
1155
+
1156
+ // update song name in meta-containers
1157
+ songName = document.getElementsByClassName("song-name");
1158
+ if (songName.length) {
1159
+ for (var i=0; i<songName.length; i++) {
1160
+ var currentPlaylist = songName[i].dataset.amplitudePlaylist;
1161
+ if (currentPlaylist === playlist) {
1162
+ songName[i].innerHTML = metaData.name;
1163
+ }
1164
+ }
1165
+ }
462
1166
 
463
- // update activeIndex
464
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1167
+ // update artist name in meta-containers
1168
+ artistName = document.getElementsByClassName("artist");
1169
+ if (artistName.length) {
1170
+ for (var i=0; i<artistName.length; i++) {
1171
+ var currentPlaylist = songName[i].dataset.amplitudePlaylist;
1172
+ if (currentPlaylist === playlist) {
1173
+ artistName[i].innerHTML = metaData.artist;
1174
+ }
1175
+ }
1176
+ }
465
1177
 
466
- if (songIndex < songs.length) {
467
- var songMetaData = songs[songIndex];
468
- var songURL = songMetaData.url;
469
- var ytpVideoID = songURL.split('=')[1];
1178
+ // update album name in meta-containers
1179
+ albumName = document.getElementsByClassName("album");
1180
+ if (albumName.length) {
1181
+ for (var i=0; i<albumName.length; i++) {
1182
+ var currentPlaylist = songName[i].dataset.amplitudePlaylist;
1183
+ if (currentPlaylist === playlist) {
1184
+ albumName[i].innerHTML = metaData.album;
1185
+ }
1186
+ }
1187
+ }
470
1188
 
471
- // continue on next video
472
- ytPlayer.loadVideoById(ytpVideoID);
1189
+ // update song rating in screen controls
1190
+ largePlayerSongAudioRating = document.getElementsByClassName("audio-rating-screen-controls");
1191
+ if (largePlayerSongAudioRating.length) {
1192
+ for (var i=0; i<largePlayerSongAudioRating.length; i++) {
1193
+ var currentPlaylist = largePlayerSongAudioRating[i].dataset.amplitudePlaylist;
1194
+ if (currentPlaylist === playlist) {
1195
+ if (metaData.rating) {
1196
+ var trackID = metaData.index + 1;
473
1197
 
474
- // reset|update time settings
475
- resetCurrentTimeContainerYTP();
476
- updateDurationTimeContainerYTP(ytPlayer);
1198
+ // save YT player data for later use (e.g. events)
1199
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = metaData.videoID;
477
1200
 
478
- // update global song index for next video
479
- ytpSongIndex = songIndex;
480
- // ytpSetActiveIndex({{player.id}}, songIndex);
1201
+ logger.debug('\n' + `UPDATE song rating on updatMetaContainers for trackID|playlist at: ${trackID}|${playlist} with a value of: ${metaData.rating}`);
1202
+ largePlayerSongAudioRating[i].innerHTML = '<img src="/assets/image/pattern/rating/scalable/' + metaData.rating + '-star.svg"' + 'alt="song rating">';
1203
+ } else {
1204
+ largePlayerSongAudioRating[i].innerHTML = '';
1205
+ }
1206
+ }
1207
+ }
1208
+ } // END if largePlayerSongAudioRating
481
1209
 
482
- // save YT player data for later use (e.g. events)
483
- // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
484
-
485
- // load cover image for next video
486
- var coverImage;
487
- var selector = ".cover-image-" + playlist;
488
- coverImage = document.querySelector(selector);
489
- coverImage.src = songMetaData.cover_art_url;
490
-
491
- // replace song name in meta-containers for next video
492
- var songName = document.getElementsByClassName("song-name");
493
- songName[0].innerHTML = songMetaData.name; // player-bottom
494
- songName[1].innerHTML = songMetaData.name; // playlist-screen-controls
495
-
496
- // replace song rating (playlist-screen|meta-container)
497
- var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
498
- if (largetPlayerSongAudioRating.length) {
499
- if (songMetaData.rating) {
500
- largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
501
- } else {
502
- largetPlayerSongAudioRating[0].innerHTML = '';
503
- }
504
- } // END if largetPlayerSongAudioRating
1210
+ } // END updatMetaContainers
505
1211
 
506
- // replace artist name in meta-containers for next video
507
- var artistName = document.getElementsByClassName("artist");
508
- artistName[0].innerHTML = songMetaData.artist;
509
-
510
- // replace album name in meta-containers for next video
511
- var albumName = document.getElementsByClassName("album");
512
- albumName[0].innerHTML = songMetaData.album;
513
-
514
- // set song active in playlist
515
- // setSongPlayed(songIndex);
516
- setSongPlayed(playerID, songIndex);
517
- } else {
518
- // select FIRST video
519
- songIndex = 0;
520
- var songMetaData = songs[songIndex];
521
- var songURL = songMetaData.url;
522
- var ytpVideoID = songURL.split('=')[1];
523
-
524
- // ytpSetActiveIndex({{player.id}}, songIndex);
525
-
526
- // continue (paused) on FIRST video
527
- ytPlayer.loadVideoById(ytpVideoID);
528
- // wait some time to make sure video is loaded|active
529
- setTimeout(() => {
530
- ytPlayer.pauseVideo();
531
- // reset|update time settings
532
- resetCurrentTimeContainerYTP();
533
- updateDurationTimeContainerYTP(ytPlayer);
534
-
535
- // update AJS play_pause button
536
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
537
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
538
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
539
- }, 300);
540
-
541
- // update global song index for first video
542
- ytpSongIndex = songIndex;
543
-
544
- // save YT player data for later use (e.g. events)
545
- // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
546
-
547
- // load cover image for first video
548
- var coverImage;
549
- var selector = ".cover-image-" + playlist;
550
- coverImage = document.querySelector(selector);
551
- coverImage.src = songMetaData.cover_art_url;
552
-
553
- // replace name in meta-containers for first video
554
- var songName = document.getElementsByClassName("song-name");
555
- songName[0].innerHTML = songMetaData.name; // player-bottom
556
- songName[1].innerHTML = songMetaData.name; // playlist-screen-controls
557
-
558
- // replace song rating (playlist-screen|meta-container)
559
- var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
560
- if (largetPlayerSongAudioRating.length) {
561
- if (songMetaData.rating) {
562
- largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
563
- } else {
564
- largetPlayerSongAudioRating[0].innerHTML = '';
565
- }
566
- } // END if largetPlayerSongAudioRating
567
-
568
- // replace artist name in meta-containers for next video
569
- var artistName = document.getElementsByClassName("artist");
570
- artistName.innerHTML = songMetaData.artist;
571
-
572
- // replace album name in meta-containers for next video
573
- var albumName = document.getElementsByClassName("album");
574
- albumName.innerHTML = songMetaData.album;
575
-
576
- // update AJS play_pause button
577
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
578
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
579
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
580
-
581
- // set song (video) active in playlist
582
- // setSongPlayed(songIndex);
583
- setSongPlayed(playerID, songIndex);
584
- }
585
- } // END if YT_PLAYER_STATE.ENDED
586
-
587
- } // END {{player.id}}OnPlayerStateChange
588
-
589
- {% endif %}
590
- {% endif %}{% endfor %}
591
-
592
- } // END onYouTubeIframeAPIReady ()
1212
+ // ---------------------------------------------------------------------------
1213
+ // loadCoverImage(metaData)
1214
+ //
1215
+ // load the configured cover image for a specic song (metaData)
1216
+ // ---------------------------------------------------------------------------
1217
+ function loadCoverImage(metaData) {
1218
+ var selector;
1219
+ var coverImage = {};
593
1220
 
1221
+ selector = ".cover-image-" + metaData.playlist;
1222
+ coverImage = document.querySelector(selector);
1223
+ coverImage.src = metaData.cover_art_url;
1224
+ } // END loadCoverImage
594
1225
 
595
1226
  // ---------------------------------------------------------------------------
596
- // main (plugin)
597
- // ---------------------------------------------------------------------------
598
- // load|initialize YT Iframe player API
1227
+ // stopAllActivePlayers(exceptPlayer)
599
1228
  //
600
- initYtAPI();
1229
+ // if multiple players used on a page, stop ALL active AT|YT players
1230
+ // running in parallel execpet the exceptPlayer
1231
+ // ---------------------------------------------------------------------------
1232
+ function stopAllActivePlayers(exceptPlayer) {
601
1233
 
602
- // setup YTPlayerUiEvents for AJS players
603
- //
604
- initUiEventsForAJS();
1234
+ // stop active AT players
1235
+ // -------------------------------------------------------------------------
1236
+ var atpPlayerState = Amplitude.getPlayerState();
1237
+ if (atpPlayerState === 'playing') {
1238
+ Amplitude.stop();
1239
+ } // END stop active AT players
605
1240
 
1241
+ // stop active YT players
1242
+ // -------------------------------------------------------------------------
1243
+ const ytPlayers = Object.keys(j1.adapter.amplitude.data.ytPlayers);
1244
+ for (let i=0; i<ytPlayers.length; i++) {
1245
+ const ytPlayerID = ytPlayers[i];
1246
+ const playerProperties = j1.adapter.amplitude.data.ytPlayers[ytPlayerID];
1247
+
1248
+ if (ytPlayerID !== exceptPlayer) {
1249
+ var player = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID]['player'];
1250
+ var playerState = (player.getPlayerState() > 0) ? player.getPlayerState() : 6;
1251
+ var ytPlayerState = YT_PLAYER_STATE_NAMES[playerState];
1252
+
1253
+ // if (ytPlayerState === 'playing' || ytPlayerState === 'paused' || ytPlayerState === 'buffering' || ytPlayerState === 'cued' || ytPlayerState === 'unstarted') {
1254
+ if (ytPlayerState === 'playing' || ytPlayerState === 'paused' || ytPlayerState === 'buffering' || ytPlayerState === 'cued' || ytPlayerState === 'unstarted') {
1255
+ logger.debug('\n' + `STOP player at stopAllActivePlayers for id: ${ytPlayerID}`);
1256
+ // player.mute();
1257
+ player.stopVideo();
1258
+ j1.adapter.amplitude.data.ytpGlobals.activeIndex = 0;
1259
+ }
1260
+ }
1261
+ } // END stop active YT players
1262
+
1263
+ } // END stopAllActivePlayers
606
1264
 
607
1265
  // ---------------------------------------------------------------------------
608
- // Base AJS Player functions
609
- // ---------------------------------------------------------------------------
610
-
611
- // ---------------------------------------------------------------------------
612
- // Returns the index of the current video (song) in the songs array
613
- // that is currently playing (starts by 0)
614
- // ---------------------------------------------------------------------------
1266
+ // getSongPlayed
615
1267
  //
1268
+ // Returns the index of the current video (song) in the songs array
1269
+ // that is currently playing (starts by 0)
1270
+ // ---------------------------------------------------------------------------
616
1271
  function getSongPlayed() {
617
1272
  var index = -1;
618
1273
  var songContainers = document.getElementsByClassName("amplitude-active-song-container");
@@ -630,79 +1285,41 @@ var progress;
630
1285
  } // END getSongPlayed
631
1286
 
632
1287
  // ---------------------------------------------------------------------------
633
- // Add class 'amplitude-active-song-container' to the element containing
634
- // visual information for the active song.
1288
+ // setSongActive(currentPlayList, currentIndex)
635
1289
  //
636
- // NOTE: We then don't care if shuffle is on or not.
1290
+ // set song (video) active at index in playlist
637
1291
  // ---------------------------------------------------------------------------
638
- //
639
- function setSongPlayed(playerID, index) {
640
- var direct;
1292
+ function setSongActive(currentPlayList, currentIndex) {
1293
+ var playlist, songContainers, songIndex;
641
1294
 
642
- // Specify if it was a (direct) click on the song container
643
- direct = true;
1295
+ songIndex = currentIndex;
644
1296
 
645
- // Get all song container elements
646
- var songContainers = document.getElementsByClassName("amplitude-song-container");
647
-
648
- // Clear all active song containrs
649
- for (var i = 0; i < songContainers.length; i++) {
1297
+ // clear ALL active song containers
1298
+ // -------------------------------------------------------------------------
1299
+ songContainers = document.getElementsByClassName("amplitude-song-container");
1300
+ for (var i=0; i<songContainers.length; i++) {
650
1301
  songContainers[i].classList.remove("amplitude-active-song-container");
651
1302
  }
652
1303
 
653
- // Find the active index and add the active song container to the element
654
- // that represents the song at the index.
655
- //
656
- if (Amplitude.getActivePlaylist() == "" || Amplitude.getActivePlaylist() == null) {
657
- var activeIndex = "";
658
-
659
- // If we click directly on the song element, we ignore
660
- // whether it's in shuffle or not.
661
- //
662
- if (direct) {
663
- // activeIndex = Amplitude.getActiveIndex();
664
- activeIndex = index;
665
- } else {
666
- if (Amplitude.getConfig().shuffle_on) {
667
- // activeIndex = Amplitude.getConfig().shuffle_list[Amplitude.getActiveIndex()];
668
- } else {
669
- // activeIndex = Amplitude.getActiveIndex();
670
- activeIndex = index;
671
- }
672
- }
673
-
674
- // activate playlist container
675
- if (document.querySelectorAll('.amplitude-song-container[data-amplitude-song-index="' + activeIndex + '"]')) {
676
- var _songContainers = document.querySelectorAll('.amplitude-song-container[data-amplitude-song-index="' + activeIndex + '"]');
677
- for (var _i = 0; _i < _songContainers.length; _i++) {
678
- if (_songContainers[_i].hasAttribute("data-amplitude-playlist")) {
679
- var _playerID = _songContainers[_i].getAttribute("data-amplitude-playlist") + '_large';
680
- if (_playerID === playerID) {
681
- _songContainers[_i].classList.add("amplitude-active-song-container");
682
- }
683
- }
684
- }
1304
+ // find current song container and activate the element
1305
+ // -------------------------------------------------------------------------
1306
+ songContainers = document.querySelectorAll('.amplitude-song-container[data-amplitude-song-index="' + songIndex + '"]');
1307
+ for (var i=0; i<songContainers.length; i++) {
1308
+ if (songContainers[i].hasAttribute("data-amplitude-playlist")) {
1309
+ playlist = songContainers[i].getAttribute("data-amplitude-playlist");
1310
+ if (playlist === currentPlayList) {
1311
+ songContainers[i].classList.add("amplitude-active-song-container");
685
1312
  }
686
- } else {
687
- // If we have an active playlist or the action took place directly on the
688
- // song element, we ignore the shuffle.
689
- //
690
- if (Amplitude.getActivePlaylist() != null && Amplitude.getActivePlaylist() != "" || direct) {
691
- var activePlaylistIndex = Amplitude.getActiveIndex();
692
- } else {
693
- var activePlaylistIndex = "";
1313
+ }
1314
+ }
694
1315
 
695
- if (Amplitude.getActivePlaylist().shuffle) {
696
- activePlaylistIndex = Amplitude.getActiveIndex();
697
- } else {
698
- activePlaylistIndex = Amplitude.getActiveIndex();
699
- }
700
- } // END if
701
- } // END if
702
1316
  } // END setSongPlayed
703
1317
 
1318
+ // ---------------------------------------------------------------------------
1319
+ // getProgressBarSelectedPositionPercentage
1320
+ //
704
1321
  // Returns the position as a percentage the user clicked in player progressbar
705
- // NOTE: The percentage is out of [0.00 .. 1.00]
1322
+ // NOTE: The percentage is out of [0.00 .. 1.00]
706
1323
  // ---------------------------------------------------------------------------
707
1324
  function getProgressBarSelectedPositionPercentage (event, progessBar) {
708
1325
  var offset = progessBar.getBoundingClientRect();
@@ -710,8 +1327,11 @@ var progress;
710
1327
  var percentage = (parseFloat(xpos) / parseFloat(progessBar.offsetWidth)).toFixed(2);
711
1328
 
712
1329
  return percentage;
713
- }
1330
+ } // END getProgressBarSelectedPositionPercentage
714
1331
 
1332
+ // ---------------------------------------------------------------------------
1333
+ // getTimeFromPercentage
1334
+ //
715
1335
  // Returns the time in seconds calculated from a percentage value
716
1336
  // NOTE: The percentage is out of [0.00 .. 1.00]
717
1337
  // ---------------------------------------------------------------------------
@@ -720,154 +1340,373 @@ var progress;
720
1340
  var time = parseFloat((videoDuration * percentage).toFixed(2));
721
1341
 
722
1342
  return time;
1343
+ } // END getTimeFromPercentage
1344
+
1345
+ // ---------------------------------------------------------------------------
1346
+ // checkActiveVideoElementYTP
1347
+ //
1348
+ //
1349
+ // ---------------------------------------------------------------------------
1350
+ function checkActiveVideoElementYTP() {
1351
+ var activeVideoElements = document.getElementsByClassName("amplitude-active-song-container");
1352
+ if (activeVideoElements.length) {
1353
+ var classArray = [].slice.call(activeVideoElements[0].classList, 0);
1354
+ var classString = classArray.toString();
1355
+
1356
+ // activeVideoElement.html = activeVideoElements[0];
1357
+ activeVideoElement.playlist = activeVideoElements[0].dataset.amplitudePlaylist;
1358
+ activeVideoElement.index = parseInt(activeVideoElements[0].dataset.amplitudeSongIndex);
1359
+ activeVideoElement.playerType = (classString.includes('large') ? 'large' : 'compact');
1360
+ activeVideoElement.playerID = activeVideoElement.playlist + '_' + activeVideoElement.playerType;
1361
+
1362
+ if (j1.adapter.amplitude.data.ytPlayers[activeVideoElement.playerID] !== undefined) {
1363
+ activeVideoElement.player = j1.adapter.amplitude.data.ytPlayers[activeVideoElement.playerID].player;
1364
+ activeVideoElement.songs = j1.adapter.amplitude.data.ytPlayers[activeVideoElement.playerID].songs;
1365
+
1366
+ var activeSong = activeVideoElement.songs[activeVideoElement.index];
1367
+
1368
+ activeVideoElement.album = activeSong.album;
1369
+ activeVideoElement.artist = activeSong.artist;
1370
+ activeVideoElement.audio_info = activeSong.audio_info;
1371
+ activeVideoElement.audio_single = activeSong.audio_single;
1372
+ activeVideoElement.currentTime = parseFloat(activeVideoElement.player.getCurrentTime());
1373
+ activeVideoElement.cover_art_url = activeSong.cover_art_url;
1374
+ activeVideoElement.duration = activeSong.duration;
1375
+ activeVideoElement.endSec = timestamp2seconds(activeSong.end);
1376
+ activeVideoElement.endTS = activeSong.end;
1377
+ activeVideoElement.name = activeSong.name;
1378
+ activeVideoElement.rating = activeSong.album;
1379
+ activeVideoElement.startSec = timestamp2seconds(activeSong.start);
1380
+ activeVideoElement.startTS = activeSong.start;
1381
+ activeVideoElement.url = activeSong.url;
1382
+
1383
+ var videoArray = activeSong.url.split('=');
1384
+
1385
+ activeVideoElement.videoID = videoArray[1];
1386
+
1387
+ }
1388
+ }
723
1389
  }
724
1390
 
1391
+ // ---------------------------------------------------------------------------
1392
+ // isObjectEmpty(obj)
1393
+ //
1394
+ // ---------------------------------------------------------------------------
1395
+ function isObjectEmpty(obj) {
1396
+ for (const prop in obj) {
1397
+ if (Object.hasOwn(obj, prop)) {
1398
+ return false;
1399
+ }
1400
+ }
1401
+
1402
+ return true;
1403
+ } // END isObjectEmpty
1404
+
1405
+ // ---------------------------------------------------------------------------
1406
+ // getActiveSong()
1407
+ //
1408
+ // Returns the time in seconds calculated from a percentage value
1409
+ // NOTE: The percentage is out of [0.00 .. 1.00]
1410
+ // ---------------------------------------------------------------------------
1411
+ function getActiveSong() {
1412
+
1413
+ if(!isObjectEmpty(activeVideoElement)) {
1414
+ return activeVideoElement;
1415
+ }
1416
+
1417
+ return false;
1418
+ } // END getActiveSong
1419
+
1420
+
1421
+ // ---------------------------------------------------------------------------
1422
+ // updateProgressBarsYTP
1423
+ //
725
1424
  // Update YTP specific progress data
726
1425
  // ---------------------------------------------------------------------------
727
1426
  function updateProgressBarsYTP() {
728
- var progress;
729
- var activePlayer = j1.adapter.amplitude.data.ytpGlobals['activePlayer'];
730
- var progressBars = document.getElementsByClassName("large-player-progress");
1427
+ var progress, progressBars, playlist, playerID,
1428
+ classArray, classString, activePlayer, activeClass;
731
1429
 
1430
+ progressBars = document.getElementsByClassName("large-player-progress");
732
1431
  for (var i=0; i<progressBars.length; i++) {
733
- if (activePlayer !== undefined) {
734
- // calc procent value (float, 2 decimals [0.00 .. 1.00])
735
- progress = parseFloat((activePlayer.getCurrentTime() / activePlayer.getDuration()).toFixed(2));
736
-
737
- // set current progess value if valid
738
- if (isFinite(progress)) {
739
- progressBars[i].value = progress;
1432
+ if (progressBars[i].dataset.amplitudeSource === 'audio') {
1433
+ // do nothing (managed by adapter)
1434
+ } else {
1435
+ playlist = progressBars[i].getAttribute("data-amplitude-playlist");
1436
+ playerID = playlist + '_large';
1437
+ classArray = [].slice.call(progressBars[i].classList, 0);
1438
+ classString = classArray.toString();
1439
+ activePlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1440
+ activeClass = 'large-player-progress-' + playlist;
1441
+
1442
+ if (activePlayer === undefined) {
1443
+ logger.error('\n' + 'YT player not defined');
1444
+ return;
1445
+ }
1446
+
1447
+ if (classString.includes(activeClass)) {
1448
+ // calc procent value (float, 2 decimals [0.00 .. 1.00])
1449
+ progress = parseFloat((activePlayer.getCurrentTime() / activePlayer.getDuration()).toFixed(2));
1450
+
1451
+ // set current progess value if valid
1452
+ if (isFinite(progress)) {
1453
+ progressBars[i].value = progress;
1454
+ }
740
1455
  }
741
1456
  }
742
1457
  } // END for
743
1458
 
744
- // calc procent value (float, 2 decimals [0.00 .. 1.00])
745
- // progress = parseFloat((ytPlayer.getCurrentTime() / ytPlayer.getDuration()).toFixed(2));
746
-
747
- // // jadams, 2024-12-07: added check on finite value
748
- // if (!isFinite(progress)) {
749
- // // TODO: check why progress value may NOT finite
750
- // progressBar.value = 0;
751
- // } else if (progress === 1) {
752
- // // reset progress value for next video
753
- // progressBar.value = 0;
754
- // } else {
755
- // // calculate current progress
756
- // progress = parseFloat((ytPlayer.getCurrentTime() / ytPlayer.getDuration()).toFixed(2));
757
- // progressBar.value = progress;
758
-
759
- // save YT player progress data for later use (e.g. events)
760
- // j1.adapter.amplitude.data.ytpGlobals['ytPlayerProgress'] = progress;
761
- //}
762
- }
1459
+ return;
1460
+ } // END updateProgressBarsYTP
763
1461
 
764
- // Update YTP specific duration time data
765
1462
  // ---------------------------------------------------------------------------
766
- function updateDurationTimeContainerYTP(player) {
1463
+ // updateDurationTimeContainerYTP(player, playlist)
1464
+ //
1465
+ // update time container values for current video
1466
+ // ---------------------------------------------------------------------------
1467
+ function updateDurationTimeContainerYTP(player, playlist) {
767
1468
  var hours, minutes, seconds;
768
1469
  var durationHours, durationMinutes, durationSeconds;
1470
+ var activeSongSettings, ytPlayer, activePlaylist;
769
1471
 
770
- // get current hours|minutes|seconds
771
- hours = ytpGetDurationHours(player);
772
- minutes = ytpGetDurationMinutes(player);
773
- seconds = ytpGetDurationSeconds(player);
1472
+ // update active song settings (manually)
1473
+ checkActiveVideoElementYTP();
1474
+
1475
+ // get active song settings (manually)
1476
+ activeSongSettings = getActiveSong();
1477
+ if (!activeSongSettings) {
1478
+ return false;
1479
+ }
1480
+
1481
+ ytPlayer = activeSongSettings.player;
1482
+ activePlaylist = activeSongSettings.playlist;
1483
+
1484
+ // if (activeSongSettings) {
1485
+ // ytPlayer = activeSongSettings.player;
1486
+ // activePlaylist = activeSongSettings.playlist;
1487
+ // } else {
1488
+ // ytPlayer = player;
1489
+ // activePlaylist = playlist;
1490
+ // }
774
1491
 
775
- // update time container values for current video
1492
+ // get current hours|minutes|seconds
776
1493
  // -------------------------------------------------------------------------
1494
+ hours = ytpGetDurationHours(ytPlayer);
1495
+ minutes = ytpGetDurationMinutes(ytPlayer);
1496
+ seconds = ytpGetDurationSeconds(ytPlayer);
777
1497
 
778
1498
  // update current duration|hours
1499
+ // -------------------------------------------------------------------------
779
1500
  durationHours = document.getElementsByClassName("amplitude-duration-hours");
780
1501
  if (durationHours.length && !isNaN(hours)) {
781
- durationHours[0].innerHTML = hours;
1502
+ for (var i=0; i<durationHours.length; i++) {
1503
+ var currentPlaylist = durationHours[i].dataset.amplitudePlaylist;
1504
+ if (currentPlaylist === activePlaylist) {
1505
+ durationHours[i].innerHTML = hours;
1506
+ }
1507
+ }
782
1508
  }
783
1509
 
784
1510
  // update current duration|minutes
1511
+ // -------------------------------------------------------------------------
785
1512
  durationMinutes = document.getElementsByClassName("amplitude-duration-minutes");
786
1513
  if (durationMinutes.length && !isNaN(minutes)) {
787
- durationMinutes[0].innerHTML = minutes;
1514
+ for (var i=0; i<durationMinutes.length; i++) {
1515
+ var currentPlaylist = durationMinutes[i].dataset.amplitudePlaylist;
1516
+ if (currentPlaylist === activePlaylist) {
1517
+ durationMinutes[i].innerHTML = minutes;
1518
+ }
1519
+ }
788
1520
  }
789
1521
 
790
1522
  // update duration|seconds
1523
+ // -------------------------------------------------------------------------
791
1524
  durationSeconds = document.getElementsByClassName("amplitude-duration-seconds");
792
1525
  if (durationSeconds.length && !isNaN(seconds)) {
793
- durationSeconds[0].innerHTML = seconds;
1526
+ for (var i=0; i<durationSeconds.length; i++) {
1527
+ var currentPlaylist = durationSeconds[i].dataset.amplitudePlaylist;
1528
+ if (currentPlaylist === activePlaylist) {
1529
+ durationSeconds[i].innerHTML = seconds;
1530
+ }
1531
+ }
794
1532
  }
795
- }
796
1533
 
797
- // Update YTP specific CURRENT time data
1534
+ return;
1535
+ } // END updateDurationTimeContainerYTP
1536
+
1537
+ // ---------------------------------------------------------------------------
1538
+ // updateCurrentTimeContainerYTP(player, metaData)
1539
+ //
1540
+ // update time container values for current video
798
1541
  // ---------------------------------------------------------------------------
799
- function updateCurrentTimeContainerYTP() {
1542
+ function updateCurrentTimeContainerYTP(player, playlist) {
800
1543
  var hours, minutes, seconds;
801
1544
  var currentHours, currentMinutes, currentSeconds;
802
1545
 
803
1546
  // get current hours|minutes|seconds
804
- hours = ytpGetCurrentHours(ytPlayer);
805
- minutes = ytpGetCurrentMinutes(ytPlayer);
806
- seconds = ytpGetCurrentSeconds(ytPlayer);
807
-
808
- // update time container values for current video
809
- // -------------------------------------------------------------------------
1547
+ hours = ytpGetCurrentHours(player);
1548
+ minutes = ytpGetCurrentMinutes(player);
1549
+ seconds = ytpGetCurrentSeconds(player);
810
1550
 
811
1551
  // update current duration|hours
1552
+ // -------------------------------------------------------------------------
812
1553
  if (hours !== '00') {
813
1554
  currentHours = document.getElementsByClassName("amplitude-current-hours");
814
- currentHours[0].innerHTML = hours;
1555
+ if (currentHours.length) {
1556
+ for (var i=0; i<currentHours.length; i++) {
1557
+ var currentPlaylist = currentHours[i].dataset.amplitudePlaylist;
1558
+ if (currentPlaylist === playlist) {
1559
+ currentHours[i].innerHTML = hours;
1560
+ }
1561
+ }
1562
+ }
815
1563
  }
816
1564
 
817
1565
  // update current duration|minutes
1566
+ // -------------------------------------------------------------------------
818
1567
  currentMinutes = document.getElementsByClassName("amplitude-current-minutes");
819
- currentMinutes[0].innerHTML = minutes;
820
-
1568
+ if (currentMinutes.length) {
1569
+ for (var i=0; i<currentMinutes.length; i++) {
1570
+ var currentPlaylist = currentMinutes[i].dataset.amplitudePlaylist;
1571
+ if (currentPlaylist === playlist) {
1572
+ currentMinutes[i].innerHTML = minutes;
1573
+ }
1574
+ }
1575
+ }
1576
+
821
1577
  // update duration|seconds
1578
+ // -------------------------------------------------------------------------
822
1579
  currentSeconds = document.getElementsByClassName("amplitude-current-seconds");
823
- currentSeconds[0].innerHTML = seconds;
824
- }
1580
+ if (currentSeconds.length) {
1581
+ for (var i=0; i<currentSeconds.length; i++) {
1582
+ var currentPlaylist = currentSeconds[i].dataset.amplitudePlaylist;
1583
+ if (currentPlaylist === playlist) {
1584
+ currentSeconds[i].innerHTML = seconds;
1585
+ }
1586
+ }
1587
+ }
1588
+
1589
+ return;
1590
+ } // END updateCurrentTimeContainerYTP
825
1591
 
826
- // Reset YTP specific progress data
827
1592
  // ---------------------------------------------------------------------------
828
- function resetProgressBarYTP(playerID) {
829
- if (playerID !== undefined) {
830
- var progressBar = j1.adapter.amplitude.data.ytPlayers[playerID].progressBar;
831
- progressBar.value = 0;
1593
+ // resetProgressBarYTP()
1594
+ //
1595
+ // Reset ALL progress bars
1596
+ // ---------------------------------------------------------------------------
1597
+ function resetProgressBarYTP() {
1598
+ var progressBars = document.getElementsByClassName("large-player-progress");
1599
+ for (var i=0; i<progressBars.length; i++) {
1600
+ progressBars[i].value = 0;
832
1601
  }
833
- }
1602
+ } // END resetProgressBarYTP
834
1603
 
835
- // Reset YTP specific CURRENT time data
836
1604
  // ---------------------------------------------------------------------------
837
- function resetCurrentTimeContainerYTP() {
1605
+ // resetCurrentTimeContainerYTP
1606
+ //
1607
+ // Reset YTP specific CURRENT time data
1608
+ // ---------------------------------------------------------------------------
1609
+ function resetCurrentTimeContainerYTP(player, playlist) {
838
1610
 
839
1611
  // reset duration|hours
840
1612
  var currentHours = document.getElementsByClassName("amplitude-current-hours");
841
1613
  if (currentHours.length) {
842
- currentHours[0].innerHTML = '00';
1614
+ for (var i=0; i<currentHours.length; i++) {
1615
+ var currentPlaylist = currentHours[i].dataset.amplitudePlaylist;
1616
+ if (currentPlaylist === playlist) {
1617
+ currentHours[i].innerHTML = '00';
1618
+ }
1619
+ }
843
1620
  }
844
1621
 
845
1622
  // reset duration|minutes
846
1623
  var currentMinutes = document.getElementsByClassName("amplitude-current-minutes");
847
- currentMinutes[0].innerHTML = '00';
1624
+ if (currentMinutes.length) {
1625
+ for (var i=0; i<currentHours.length; i++) {
1626
+ var currentPlaylist = currentMinutes[i].dataset.amplitudePlaylist;
1627
+ if (currentPlaylist === playlist) {
1628
+ currentMinutes[i].innerHTML = '00';
1629
+ }
1630
+ }
1631
+ }
848
1632
 
849
1633
  // reset duration|seconds
850
1634
  var currentSeconds = document.getElementsByClassName("amplitude-current-seconds");
851
- currentSeconds[0].innerHTML = '00';
852
- }
1635
+ if (currentSeconds.length) {
1636
+ for (var i=0; i<currentSeconds.length; i++) {
1637
+ var currentPlaylist = currentSeconds[i].dataset.amplitudePlaylist;
1638
+ if (currentPlaylist === playlist) {
1639
+ currentSeconds[i].innerHTML = '00';
1640
+ }
1641
+ }
1642
+ }
1643
+
1644
+ return;
1645
+ } // END resetCurrentTimeContainerYTP
853
1646
 
854
1647
 
855
1648
  // ---------------------------------------------------------------------------
856
1649
  // Mimik Base AJS API functions
1650
+ // ===========================================================================
1651
+
1652
+ // ---------------------------------------------------------------------------
1653
+ // ytpLoadVideById
1654
+ //
1655
+ // ???????
857
1656
  // ---------------------------------------------------------------------------
1657
+ function ytpLoadVideoById(player, id, bufferQuote) {
1658
+ const cycle = 250;
1659
+
1660
+ player.loadVideoById(id);
1661
+
1662
+ const videoLoaded = setInterval(() => {
1663
+ bufferQuote = ytpGetBuffered(player);
1664
+
1665
+ if (bufferQuote >= 3) {
1666
+ return true;
1667
+
1668
+ clearInterval(videoLoaded);
1669
+ } else {
1670
+ return false;
1671
+ }
1672
+ }, cycle);
858
1673
 
859
- // Seek (skip) video to time specified
1674
+ } // END ytpLoadVideoById
1675
+
1676
+ // ---------------------------------------------------------------------------
1677
+ // ytpSeekTo
1678
+ //
1679
+ // Seek (skip) video to specified time (position)
860
1680
  // ---------------------------------------------------------------------------
861
- function ytpSeekTo(player, time) {
862
- player.seekTo(time, true);
1681
+ function ytpSeekTo(player, time, seekAhead) {
1682
+ // const allowSeekAhead = true;
1683
+ // var buffered = ytpGetBuffered(player);
1684
+
1685
+ if (player.id !== undefined) {
1686
+ player.seekTo(time, seekAhead);
1687
+ // player.seekTo(time);
1688
+
1689
+ return true;
1690
+ } else {
1691
+ return false;
1692
+ }
1693
+
863
1694
  } // END ytpSeekTo
864
1695
 
865
- // Returns the buffered percentage of the playing video
1696
+
1697
+ // ---------------------------------------------------------------------------
1698
+ // ytpGetBuffered
1699
+ //
1700
+ // Returns the buffered percentage of the video currently playing
866
1701
  // ---------------------------------------------------------------------------
867
1702
  function ytpGetBuffered(player) {
868
- // to be defined
869
- }
870
1703
 
1704
+ return (player.getVideoLoadedFraction() * 100).toFixed(2);
1705
+ } // END ytpGetBuffered
1706
+
1707
+ // ---------------------------------------------------------------------------
1708
+ // ytpGetActiveIndex
1709
+ //
871
1710
  // Returns the active song index (in the songs array, starts by 0)
872
1711
  // ---------------------------------------------------------------------------
873
1712
  function ytpGetActiveIndex(playerID) {
@@ -880,6 +1719,10 @@ var progress;
880
1719
  return activeIndex;
881
1720
  } // END ytpGetActiveIndex
882
1721
 
1722
+
1723
+ // ---------------------------------------------------------------------------
1724
+ // ytpSetActiveIndex
1725
+ //
883
1726
  // Set the index of the active song (index starts by 0)
884
1727
  // ---------------------------------------------------------------------------
885
1728
  function ytpSetActiveIndex(playerID, idx) {
@@ -894,35 +1737,45 @@ var progress;
894
1737
  return success;
895
1738
  } // END ytpSetActiveIndex
896
1739
 
1740
+ // ---------------------------------------------------------------------------
1741
+ // ytpGetPlayedPercentage
1742
+ //
897
1743
  // Returns the percentage of the video played
898
1744
  // ---------------------------------------------------------------------------
899
1745
  function ytpGetPlayedPercentage(player) {
900
- // to be defined
901
- }
1746
+ // tbd
1747
+ } // END ytpGetPlayedPercentage
902
1748
 
1749
+ // ---------------------------------------------------------------------------
1750
+ // ytpGetAudio
1751
+ //
903
1752
  // Returns the actual video element
904
1753
  // ---------------------------------------------------------------------------
905
1754
  function ytpGetAudio(player) {
906
- // to be defined
907
- }
1755
+ // tbd
1756
+ } // END ytpGetAudio
908
1757
 
1758
+ // ---------------------------------------------------------------------------
1759
+ // ytpGetPlaybackSpeeds
1760
+ //
909
1761
  // Returns available playback speeds for the player
910
1762
  // ---------------------------------------------------------------------------
911
1763
  function ytpGetPlaybackSpeeds(player) {
912
- // to be defined
913
- }
1764
+ // tbd
1765
+ } // END ytpGetPlaybackSpeeds
914
1766
 
915
- // Returns the current playback speed for the player
916
1767
  // ---------------------------------------------------------------------------
917
- function ytpGetPlaybackSpeed(player) {
918
- }
919
-
1768
+ // ytpGetPlayerState
1769
+ //
920
1770
  // Returns the current state of the player
921
1771
  // ---------------------------------------------------------------------------
922
1772
  function ytpGetPlayerState(player) {
923
- // to be defined
924
- }
1773
+ // tbd
1774
+ } // END ytpGetPlayerState
925
1775
 
1776
+ // ---------------------------------------------------------------------------
1777
+ // ytpGetDuration
1778
+ //
926
1779
  // Returns the duration of the video
927
1780
  // ---------------------------------------------------------------------------
928
1781
  function ytpGetDuration(player) {
@@ -938,6 +1791,9 @@ var progress;
938
1791
  }
939
1792
  } // END ytpGetDuration
940
1793
 
1794
+ // ---------------------------------------------------------------------------
1795
+ // ytpGetCurrentTime
1796
+ //
941
1797
  // Returns the current time of the video played
942
1798
  // ---------------------------------------------------------------------------
943
1799
  function ytpGetCurrentTime(player) {
@@ -955,6 +1811,9 @@ var progress;
955
1811
  }
956
1812
  } // END ytpGetCurrentTime
957
1813
 
1814
+ // ---------------------------------------------------------------------------
1815
+ // ytpGetDurationHours
1816
+ //
958
1817
  // Returns the duration hours of the video
959
1818
  // ---------------------------------------------------------------------------
960
1819
  function ytpGetDurationHours(player) {
@@ -975,6 +1834,9 @@ var progress;
975
1834
  }
976
1835
  } // END ytpGetDurationHours
977
1836
 
1837
+ // ---------------------------------------------------------------------------
1838
+ // ytpGetDurationMinutes
1839
+ //
978
1840
  // Returns the duration minutes of the video
979
1841
  // ---------------------------------------------------------------------------
980
1842
  function ytpGetDurationMinutes(player) {
@@ -995,6 +1857,10 @@ var progress;
995
1857
  }
996
1858
  } // END ytpGetDurationMinutes
997
1859
 
1860
+
1861
+ // ---------------------------------------------------------------------------
1862
+ // ytpGetDurationSeconds
1863
+ //
998
1864
  // Returns the duration seconds of the video
999
1865
  // ---------------------------------------------------------------------------
1000
1866
  function ytpGetDurationSeconds(player) {
@@ -1015,6 +1881,9 @@ var progress;
1015
1881
  }
1016
1882
  } // END ytpGetDurationSeconds
1017
1883
 
1884
+ // ---------------------------------------------------------------------------
1885
+ // ytpGetCurrentHours
1886
+ //
1018
1887
  // Returns the current hours the user is into the video
1019
1888
  // ---------------------------------------------------------------------------
1020
1889
  function ytpGetCurrentHours(player) {
@@ -1035,6 +1904,9 @@ var progress;
1035
1904
  }
1036
1905
  } // END ytpGetCurrentHours
1037
1906
 
1907
+ // ---------------------------------------------------------------------------
1908
+ // ytpGetCurrentMinutes
1909
+ //
1038
1910
  // Returns the current minutes the user is into the video
1039
1911
  // ---------------------------------------------------------------------------
1040
1912
  function ytpGetCurrentMinutes (player) {
@@ -1055,6 +1927,9 @@ var progress;
1055
1927
  }
1056
1928
  } // END ytpGetCurrentMinutes
1057
1929
 
1930
+ // ---------------------------------------------------------------------------
1931
+ // ytpGetCurrentSeconds
1932
+ //
1058
1933
  // Returns the current seconds the user is into the video
1059
1934
  // ---------------------------------------------------------------------------
1060
1935
  function ytpGetCurrentSeconds(player) {
@@ -1076,10 +1951,81 @@ var progress;
1076
1951
  } // END ytpGetCurrentSeconds
1077
1952
 
1078
1953
  // ---------------------------------------------------------------------------
1079
- // mimikYTPlayerUiEventsForAJS()
1080
- // Mimik AJS button events for YT video
1954
+ // togglePlayPauseButton
1955
+ //
1956
+ // toggle button play|pause
1957
+ // ---------------------------------------------------------------------------
1958
+ function togglePlayPauseButton(elementClass) {
1959
+ var button, htmlElement;
1960
+
1961
+ button = document.getElementsByClassName(elementClass);
1962
+
1963
+ if (button.length) {
1964
+ htmlElement = button[0];
1965
+
1966
+ if (htmlElement.classList.contains('amplitude-paused')) {
1967
+ htmlElement.classList.remove('amplitude-paused');
1968
+ htmlElement.classList.add('amplitude-playing');
1969
+ } else {
1970
+ htmlElement.classList.remove('amplitude-playing');
1971
+ htmlElement.classList.add('amplitude-paused');
1972
+ }
1973
+ } else {
1974
+ return false;
1975
+ }
1976
+
1977
+ } // END togglePlayPauseButton
1978
+
1979
+ // ---------------------------------------------------------------------------
1980
+ // setPlayPauseButtonPaused
1981
+ // ---------------------------------------------------------------------------
1982
+ function setPlayPauseButtonPaused(element) {
1983
+ var button, htmlElement;
1984
+
1985
+ // button = document.getElementsByClassName(elementClass);
1986
+ // htmlElement = button[0];
1987
+
1988
+ element.classList.remove('amplitude-playing');
1989
+ element.classList.add('amplitude-paused');
1990
+
1991
+ } // END setPlayPauseButtonPaused
1992
+
1993
+ // ---------------------------------------------------------------------------
1994
+ // setPlayPauseButtonPlaying
1081
1995
  // ---------------------------------------------------------------------------
1996
+ function setPlayPauseButtonPlaying(elementClass) {
1997
+ var button, htmlElement;
1998
+
1999
+ button = document.getElementsByClassName(elementClass);
2000
+ htmlElement = button[0];
2001
+
2002
+ htmlElement.classList.remove('amplitude-paused');
2003
+ htmlElement.classList.add('amplitude-playing');
2004
+
2005
+ } // END setPlayPauseButtonPlaying
2006
+
2007
+ // ---------------------------------------------------------------------------
2008
+ // scrollToActiveElement(playlist)
2009
+ // ---------------------------------------------------------------------------
2010
+ function scrollToActiveElement(activePlaylist) {
2011
+ const scrollableList = document.getElementById('large_player_title_list_' + activePlaylist);
2012
+ const activeElement = scrollableList.querySelector('.amplitude-active-song-container');
2013
+ var activeElementOffsetTop = activeElement.offsetTop;
2014
+ var songIndex = parseInt(activeElement.getAttribute("data-amplitude-song-index"));
2015
+ var activeElementOffsetTop = songIndex * j1.adapter.amplitude.data.playerSongElementHeigth;
2016
+
2017
+ if (scrollableList && activeElement) {
2018
+ scrollableList.scrollTop = activeElementOffsetTop;
2019
+ }
2020
+ } // END scrollToActiveElement
2021
+
2022
+ // ---------------------------------------------------------------------------
2023
+ // mimikYTPlayerUiEventsForAJS
2024
+ //
2025
+ // Mimik AJS button events for YT video
2026
+ // ---------------------------------------------------------------------------
1082
2027
  function mimikYTPlayerUiEventsForAJS(ytPlayerID) {
2028
+
1083
2029
  if (j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID] !== undefined) {
1084
2030
  var playerDefaults = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerDefaults;
1085
2031
  var playerSettings = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings;
@@ -1087,59 +2033,207 @@ var progress;
1087
2033
 
1088
2034
  // -----------------------------------------------------------------------
1089
2035
  // Large AJS players
1090
- //
1091
- if (j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings.type === 'large') {
2036
+ // -----------------------------------------------------------------------
2037
+ if (j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings.type === 'large') {
2038
+ var playlist = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].playerSettings.playlist.name;
2039
+ var playerScrollList = document.getElementById('large_player_title_list_' + playlist);
2040
+
2041
+ if (playerScrollControl) {
2042
+ var listItemHeight = playerSongElementHeigth/2;
2043
+ var itemsPerBlock = 1;
2044
+ var isScrollingResetDelay = 150;
2045
+ var isScrolling = false;
2046
+
2047
+ playerScrollList.addEventListener('scroll', (event) => {
2048
+ // block multiple scroll events (while scrolling)
2049
+ if (isScrolling) {
2050
+ return;
2051
+ }
2052
+ isScrolling = true;
2053
+
2054
+ // calculate number of blocks already scrolled
2055
+ const scrolledBlocks = Math.round(list.scrollTop / (listItemHeight * itemsPerBlock));
2056
+
2057
+ // calculate top position based on number of blocks
2058
+ const targetScrollTop = scrolledBlocks * listItemHeight * itemsPerBlock;
2059
+
2060
+ // smooth scrolling
2061
+ list.scrollTo({
2062
+ top: targetScrollTop,
2063
+ behavior: 'smooth'
2064
+ });
2065
+
2066
+ // reset the scrolling flags
2067
+ setTimeout(() => {
2068
+ isScrolling = false;
2069
+ }, isScrollingResetDelay);
2070
+ });
2071
+ }
1092
2072
 
1093
2073
  // Overload AJS play_pause button for YT
1094
- //
2074
+ // TODO: Fix for multiple players in page
2075
+ // ---------------------------------------------------------------------
1095
2076
  var largePlayerPlayPauseButton = document.getElementsByClassName(playerButton);
1096
- for (var i=0; i<largePlayerPlayPauseButton.length; i++) {
2077
+ for (var i=0; i<largePlayerPlayPauseButton.length; i++) {
1097
2078
  var classArray = [].slice.call(largePlayerPlayPauseButton[i].classList, 0);
1098
2079
  var classString = classArray.toString();
1099
2080
 
1100
2081
  if (classString.includes(ytPlayerID)) {
1101
2082
  largePlayerPlayPauseButton[i].addEventListener('click', function(event) {
1102
- var playlist = this.getAttribute("data-amplitude-playlist");
1103
- var playerID = playlist + '_large';
1104
- var ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][playerID]['player'];
1105
- var songs = j1.adapter.amplitude['data']['ytPlayers'][playerID]['songs'];
1106
- var activeIndex = parseInt(j1.adapter.amplitude['data']['ytPlayers'][playerID]['activeIndex']);
1107
- var songMetaData = songs[songIndex];
1108
- var playPauseButton = `large-player-play-pause-${ytPlayerID}`;
1109
-
1110
- // toggle YT play|pause video
1111
- if (ytPlayer.getPlayerState() === YT_PLAYER_STATE.PLAYING || ytPlayer.getPlayerState() === YT_PLAYER_STATE.BUFFERING) {
1112
- ytPlayer.pauseVideo();
2083
+ var activeSongSettings, songs, songMetaData, ytPlayer,
2084
+ playlist, playerID, songIndex;
2085
+
2086
+ playlist = this.getAttribute("data-amplitude-playlist");
2087
+ playerID = playlist + '_large';
2088
+
2089
+ // update active song settings (manually)
2090
+ checkActiveVideoElementYTP();
2091
+
2092
+ // get active song settings (manually)
2093
+ activeSongSettings = getActiveSong();
2094
+
2095
+ // TODO: Extend getSongIndex() for singleAudio
2096
+ // var songIndex = (singleAudio) ? ytpSongIndex : getSongIndex(songs, ytVideoID);
2097
+ if (!activeSongSettings) {
2098
+ songIndex = 0;
2099
+ ytpSongIndex = 0;
1113
2100
  } else {
1114
- ytPlayer.playVideo();
2101
+
2102
+ // ytPlayerCurrentTime = activeSongSettings.currentTime;
2103
+
2104
+ if (activeSongSettings.playlist !== playlist) {
2105
+ songIndex = 0;
2106
+ ytpSongIndex = 0;
2107
+
2108
+ // reset previous player settings
2109
+ if (activeSongSettings.player !== undefined) {
2110
+ activeSongSettings.player.stopVideo();
2111
+ var playPauseButtonClass = `large-player-play-pause-${activeSongSettings.playerID}`;
2112
+ togglePlayPauseButton(playPauseButtonClass);
2113
+ }
2114
+ } else {
2115
+ songIndex = ytpSongIndex;
2116
+ }
1115
2117
  }
1116
2118
 
1117
- // toggle AJS PlayPauseButton
1118
- var largePlayerPlayPauseButton = document.getElementsByClassName(playPauseButton);
1119
- if (largePlayerPlayPauseButton[0].classList.contains('amplitude-paused')) {
1120
- largePlayerPlayPauseButton[0].classList.remove('amplitude-paused');
1121
- largePlayerPlayPauseButton[0].classList.add('amplitude-playing');
2119
+ // set song (video) active at index in playlist
2120
+ setSongActive(playlist, songIndex);
2121
+
2122
+ // reset progress bar settings
2123
+ resetProgressBarYTP();
2124
+
2125
+ // scroll song active at index in player
2126
+ if (playerAutoScrollSongElement) {
2127
+ scrollToActiveElement(playlist);
2128
+ }
2129
+
2130
+ // update activeAudio data (manually)
2131
+ checkActiveVideoElementYTP();
2132
+
2133
+ // get active song settings (manually)
2134
+ activeSongSettings = getActiveSong();
2135
+
2136
+ songs = activeSongSettings.songs;
2137
+ songMetaData = songs[songIndex];
2138
+ ytPlayer = activeSongSettings.player;
2139
+
2140
+ // update meta data
2141
+ updatMetaContainers(songMetaData);
2142
+
2143
+ // save player GLOBAL data for later use (e.g. events)
2144
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
2145
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
2146
+ j1.adapter.amplitude.data.ytpGlobals['activePlaylist'] = playlist;
2147
+
2148
+ // YT play|pause video
2149
+ // ---------------------------------------------------------------
2150
+ var playerState = ytPlayer.getPlayerState();
2151
+ if (playerState < 0) {
2152
+ var ytPlayerState = YT_PLAYER_STATE_NAMES[6];
1122
2153
  } else {
1123
- largePlayerPlayPauseButton[0].classList.remove('amplitude-playing');
1124
- largePlayerPlayPauseButton[0].classList.add('amplitude-paused');
2154
+ var ytPlayerState = YT_PLAYER_STATE_NAMES[playerState];
2155
+ }
2156
+
2157
+ // var playPauseButtonsMini = document.getElementsByClassName('mini-player-play-pause');
2158
+ // setPlayPauseButtonPaused(playPauseButtonsMini);
2159
+
2160
+ if (ytPlayerState === 'playing') {
2161
+ ytPlayer.pauseVideo();
2162
+
2163
+ ytPlayerCurrentTime = ytPlayer.getCurrentTime();
2164
+
2165
+ // var trackID = songIndex + 1;
2166
+ // logger.debug('\n' + `PAUSE video for PlayPauseButton on playlist|trackID: ${playlist}|${trackID} at: ${ytPlayerCurrentTime}`);
2167
+
2168
+ // var playPauseButtonsMini = document.getElementsByClassName('mini-player-play-pause');
2169
+ // setPlayPauseButtonPaused(playPauseButtonsMini);
2170
+
2171
+ // var playPauseButtonClassCompact = `compact-player-play-pause -${ytPlayerID}`;
2172
+ // togglePlayPauseButton(playPauseButtonClassCompact);
2173
+ // //
2174
+ // var playPauseButtonClassLarge = `large-player-play-pause-${ytPlayerID}`;
2175
+ // togglePlayPauseButton(playPauseButtonClassLarge);
2176
+
2177
+ // reset|update time settings
2178
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2179
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2180
+ }
2181
+
2182
+ if (ytPlayerState === 'paused') {
2183
+ ytPlayer.playVideo();
2184
+ ytpSeekTo(ytPlayer, ytPlayerCurrentTime, true);
2185
+
2186
+ var trackID = songIndex + 1;
2187
+ logger.debug('\n' + `PLAY video for PlayPauseButton on playlist|trackID: ${playlist}|${trackID} at: ${ytPlayerCurrentTime}`);
2188
+
2189
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2190
+ togglePlayPauseButton(playPauseButtonClass);
2191
+
2192
+ // reset|update time settings
2193
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2194
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
1125
2195
  }
1126
2196
 
1127
- // don't activate playlist item on FIRST || LAST song
1128
- // if (songIndex !== 0 && songIndex !== songs.length - 1) {
1129
- if (songIndex !== songs.length - 1) {
1130
- // set song active in playlist
1131
- //setSongPlayed(songIndex);
1132
- setSongPlayed(playerID, songIndex);
2197
+ if (ytPlayerState === 'cued') {
2198
+ ytPlayer.playVideo();
2199
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2200
+ togglePlayPauseButton(playPauseButtonClass);
2201
+
2202
+ // set song at songIndex active in playlist
2203
+ setSongActive(playlist, songIndex);
2204
+
2205
+ // scroll song active at index in player
2206
+ if (playerAutoScrollSongElement) {
2207
+ scrollToActiveElement(playlist);
2208
+ }
2209
+
2210
+ // reset|update time settings
2211
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2212
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2213
+ }
2214
+
2215
+ // TODO: unclear why state 'unstarted' is generated
2216
+ // on LAST item
2217
+ // workaround sofar
2218
+ if (ytPlayerState === 'unstarted') {
2219
+ ytPlayer.playVideo();
2220
+ // ytPlayer.mute();
2221
+
2222
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2223
+ togglePlayPauseButton(playPauseButtonClass);
2224
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2225
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
1133
2226
  }
1134
2227
 
1135
- // event.preventDefault();
1136
- event.stopImmediatePropagation(); // deactivate AJS events
2228
+ // deactivate AJS events (if any)
2229
+ event.stopImmediatePropagation();
1137
2230
  }); // END EventListener largePlayerPlayPauseButton 'click'
1138
- } // END if largePlayerPlayPauseButton
2231
+ }
1139
2232
  } // END for largePlayerPlayPauseButton
1140
2233
 
1141
2234
  // Overload AJS largePlayerSkipBackward button for YT
1142
- //
2235
+ // TODO: Fix for multiple players in page
2236
+ // ---------------------------------------------------------------------
1143
2237
  var largePlayerSkipForwardButtons = document.getElementsByClassName("large-player-skip-forward");
1144
2238
  for (var i=0; i<largePlayerSkipForwardButtons.length; i++) {
1145
2239
  var classArray = [].slice.call(largePlayerSkipForwardButtons[i].classList, 0);
@@ -1148,19 +2242,19 @@ var progress;
1148
2242
  // load player settings
1149
2243
  var playerForwardBackwardSkipSeconds = (playerSettings.forward_backward_skip_seconds === undefined) ? playerDefaults.forward_backward_skip_seconds : playerSettings.forward_backward_skip_seconds;
1150
2244
 
1151
- // if (largePlayerSkipForwardButtons[i].id === 'skip-forward_' + ytPlayerID) {
1152
- // if (classString.includes(ytPlayerID)) && largePlayerSkipForwardButtons[i].id === 'skip-forkward_' + ytPlayerID) {
1153
2245
  if (classString.includes(ytPlayerID)) {
1154
2246
  largePlayerSkipForwardButtons[i].addEventListener('click', function(event) {
1155
- var currentTime, playerState, skipOffset, ytPlayer;
2247
+ var currentVideoTime, playerState, skipOffset, ytPlayer;
1156
2248
 
1157
- skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1158
- ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
1159
- playerState = ytPlayer.getPlayerState();
1160
- currentTime = ytPlayer.getCurrentTime();
2249
+ skipOffset = parseInt(playerForwardBackwardSkipSeconds);
2250
+ ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
2251
+ playerState = ytPlayer.getPlayerState();
2252
+ currentVideoTime = ytPlayer.getCurrentTime();
1161
2253
 
1162
2254
  if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) {
1163
- ytPlayer.seekTo(currentTime + skipOffset, true);
2255
+ logger.debug('\n' + `SKIP forward on Button skipForward for ${skipOffset} seconds`);
2256
+ ytpSeekTo(ytPlayer, currentVideoTime + skipOffset, true);
2257
+
1164
2258
  }
1165
2259
 
1166
2260
  // deactivate AJS events (if any)
@@ -1170,7 +2264,8 @@ var progress;
1170
2264
  } // END for
1171
2265
 
1172
2266
  // Overload AJS largePlayerSkipBackward button for YT
1173
- //
2267
+ // TODO: Fix for multiple players in page
2268
+ // ---------------------------------------------------------------------
1174
2269
  var largePlayerSkipBackwardButtons = document.getElementsByClassName("large-player-skip-backward");
1175
2270
  for (var i=0; i<largePlayerSkipBackwardButtons.length; i++) {
1176
2271
  var classArray = [].slice.call(largePlayerSkipBackwardButtons[i].classList, 0);
@@ -1181,29 +2276,28 @@ var progress;
1181
2276
 
1182
2277
  if (classString.includes(ytPlayerID)) {
1183
2278
  largePlayerSkipBackwardButtons[i].addEventListener('click', function(event) {
1184
- var currentTime, playerState, skipOffset, ytPlayer;
2279
+ var currentVideoTime, playerState, skipOffset, ytPlayer;
1185
2280
 
1186
- skipOffset = parseFloat(playerForwardBackwardSkipSeconds);
1187
- ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
1188
- playerState = ytPlayer.getPlayerState();
1189
- currentTime = ytPlayer.getCurrentTime();
2281
+ skipOffset = parseInt(playerForwardBackwardSkipSeconds);
2282
+ ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][ytPlayerID].player;
2283
+ playerState = ytPlayer.getPlayerState();
2284
+ currentVideoTime = ytPlayer.getCurrentTime();
1190
2285
 
1191
2286
  if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) {
1192
- ytPlayer.seekTo(currentTime - skipOffset, true);
2287
+ logger.debug('\n' + `SKIP backward on Button skipBackward for ${skipOffset} seconds`);
2288
+ ytpSeekTo(ytPlayer, currentVideoTime - skipOffset, true);
1193
2289
  }
1194
2290
 
1195
2291
  // deactivate AJS events (if any)
1196
2292
  event.stopImmediatePropagation();
1197
2293
  }); // END Listener 'click'
1198
2294
  } // END if skip-backward button
1199
- } // END for
2295
+ } // END for
1200
2296
 
2297
+ // Overload AJS largePlayerNext button for YT
1201
2298
  // click on (player) next button
1202
2299
  // TODO: Fix for multiple players in page
1203
- // --------------------------------------------------------------------
1204
-
1205
- // Overload AJS largePlayerNext button for YT
1206
- //
2300
+ // ---------------------------------------------------------------------
1207
2301
  var largePlayerNextButton = document.getElementsByClassName("large-player-next");
1208
2302
  for (var i=0; i<largePlayerNextButton.length; i++) {
1209
2303
  var classArray = [].slice.call(largePlayerNextButton[i].classList, 0);
@@ -1211,426 +2305,563 @@ var progress;
1211
2305
 
1212
2306
  if (classString.includes(ytPlayerID)) {
1213
2307
  largePlayerNextButton[i].addEventListener('click', function(event) {
1214
- var ytpVideoID;
1215
- var playlist = this.getAttribute("data-amplitude-playlist");
1216
- var playerID = playlist + '_large';
1217
- // var songIndex = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex);
1218
- var songIndex = ytpSongIndex;
1219
- var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
1220
- var ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1221
-
1222
- // var songs = j1.adapter.amplitude['data']['ytPlayers'][playerID].songs
1223
- // var ytPlayer = j1.adapter.amplitude['data']['ytPlayers'][playerID].player;
1224
-
1225
- // if (songIndex < songs.length) {
1226
- if (songIndex < songs.length-1) {
1227
- // set song on next item
1228
- songIndex++;
1229
- ytpSongIndex = songIndex;
1230
-
1231
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2308
+ var playlist, playerID, songIndex, trackID,
2309
+ songs, songMetaData, songName, songURL,
2310
+ ytPlayer, ytpVideoID;
2311
+
2312
+ songIndex = ytpSongIndex;
2313
+ playlist = this.getAttribute("data-amplitude-playlist");
2314
+ playerID = playlist + '_large';
2315
+ songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2316
+ ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
2317
+
2318
+ if (ytPlayer === undefined) {
2319
+ logger.error('\n' + 'YT player not defined');
1232
2320
  }
1233
- // else {
1234
- // songIndex--;
1235
- // }
1236
2321
 
1237
- // collect (next) song data
1238
- // if (songIndex < songs.length) {
2322
+ // stop active AT|YT players except the current
2323
+ // stopAllActivePlayers(playerID);
2324
+
2325
+ // select video
1239
2326
  if (songIndex < songs.length-1) {
1240
- songMetaData = songs[songIndex];
1241
- songURL = songMetaData.url;
1242
- ytpVideoID = songURL.split('=')[1];
2327
+ // select NEXT video
2328
+ songIndex++;
2329
+ ytpSongIndex = songIndex;
1243
2330
  } else {
1244
- songIndex = 0;
1245
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1246
- songMetaData = songs[songIndex];
1247
- songURL = songMetaData.url;
1248
- ytpVideoID = songURL.split('=')[1];
2331
+ // select FIRST video
2332
+ songIndex = 0;
2333
+ ytpSongIndex = songIndex;
1249
2334
  }
1250
2335
 
1251
- // pause song (video) if FIRST item reached
1252
- // TODO: handle on player|shuffle different (do play)
1253
- if (songMetaData.index === 0) {
1254
-
1255
- // continue (paused) on FIRST video
1256
- if (ytPlayer !== undefined) {
1257
- ytPlayer.loadVideoById(ytpVideoID);
1258
-
1259
- // wait some time to make sure video is loaded|active
1260
- setTimeout(() => {
1261
- ytPlayer.pauseVideo();
1262
- // reset|update time settings
1263
- resetCurrentTimeContainerYTP();
1264
- updateDurationTimeContainerYTP(ytPlayer);
1265
- // resetProgressBarYTP(playerID);
1266
-
1267
- // update AJS play_pause button
1268
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1269
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1270
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
1271
- }, 300);
1272
- }
2336
+ // set song (video)^meta data
2337
+ songMetaData = songs[songIndex];
2338
+ songURL = songMetaData.url;
2339
+ ytpVideoID = songURL.split('=')[1];
2340
+
2341
+ // load next video
2342
+ // ---------------------------------------------------------------
2343
+
2344
+ // save YT player GLOBAL data for later use (e.g. events)
2345
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
2346
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
2347
+ j1.adapter.amplitude.data.ytpGlobals['activePlaylist'] = playlist;
2348
+
2349
+ // save YT player data for later use (e.g. events)
2350
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2351
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytpVideoID;
2352
+
2353
+ trackID = songIndex + 1;
2354
+ logger.debug('\n' + `SWITCH video for PlayerNextButton at trackID|VideoID: ${trackID}|${ytpVideoID}`);
2355
+ ytPlayer.loadVideoById(ytpVideoID);
2356
+
2357
+ // delay after switch video
2358
+ if (muteAfterVideoSwitchInterval) {
2359
+ ytPlayer.mute();
2360
+ setTimeout(() => {
2361
+ ytPlayer.unMute();
2362
+ }, muteAfterVideoSwitchInterval);
2363
+ }
2364
+
2365
+ if (songIndex === 0) {
2366
+
2367
+ // continue paused on FIRST video
2368
+ // TODO: handle on player|shuffle different (do play)
2369
+ ytPlayer.pauseVideo();
2370
+
2371
+ // reset|update time settings
2372
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2373
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2374
+ resetProgressBarYTP();
2375
+
2376
+ // set AJS play_pause button paused
2377
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2378
+ // setPlayPauseButtonPlaying(playPauseButtonClass);
2379
+ togglePlayPauseButton(playPauseButtonClass);
1273
2380
  } else {
1274
- // load NEXT video if available
1275
- if (ytPlayer !== undefined) {
1276
- ytPlayer.loadVideoById(ytpVideoID);
1277
-
1278
- // update AJS play_pause button (set playing)
1279
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1280
- largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1281
- largePlayerPlayPauseButton.classList.add('amplitude-playing');
1282
- } else {
1283
- // update AJS play_pause button (set paused)
1284
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1285
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1286
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
1287
- }
2381
+ // toggle AJS play_pause button
2382
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2383
+ togglePlayPauseButton(playPauseButtonClass);
1288
2384
  }
1289
2385
 
1290
2386
  // reset|update current time settings
1291
- resetCurrentTimeContainerYTP();
1292
- updateDurationTimeContainerYTP(ytPlayer);
1293
-
1294
- // load cover image for next video
1295
- var coverImage;
1296
- var selector = ".cover-image-" + playlist;
1297
- coverImage = document.querySelector(selector);
1298
- coverImage.src = songMetaData.cover_art_url;
1299
-
1300
- // replace new song name (meta-container)
1301
- var songName = document.getElementsByClassName("song-name");
1302
- songName[0].innerHTML = songMetaData.name; // player-bottom
1303
- songName[1].innerHTML = songMetaData.name; // playlist-screen
1304
-
1305
- // replace song rating (playlist-screen|meta-container)
1306
- var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1307
- if (largetPlayerSongAudioRating.length) {
1308
- if (songMetaData.rating) {
1309
- largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1310
- } else {
1311
- largetPlayerSongAudioRating[0].innerHTML = '';
1312
- }
1313
- } // END if largetPlayerSongAudioRating
1314
-
1315
- // replace artist name in meta-containers for next video
1316
- var artistName = document.getElementsByClassName("artist");
1317
- artistName[0].innerHTML = songMetaData.artist;
1318
-
1319
- // replace album name in meta-containers for next video
1320
- var albumName = document.getElementsByClassName("album");
1321
- albumName[0].innerHTML = songMetaData.album;
1322
-
1323
- // update AJS play_pause button
1324
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1325
- largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1326
- largePlayerPlayPauseButton.classList.add('amplitude-playing');
1327
-
1328
- // if (songIndex < songs.length) {
1329
- if (songIndex < songs.length-1) {
1330
- // set song active in playlist
1331
- // setSongPlayed(songIndex);
1332
- setSongPlayed(playerID, songIndex);
1333
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2387
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2388
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2389
+ resetProgressBarYTP();
2390
+
2391
+ // load the song cover image
2392
+ loadCoverImage(songMetaData);
2393
+
2394
+ // update meta data
2395
+ updatMetaContainers(songMetaData);
2396
+
2397
+ // set song at songIndex active in playlist
2398
+ setSongActive(playlist, songIndex);
2399
+
2400
+ // scroll song active at index in player
2401
+ if (playerAutoScrollSongElement) {
2402
+ scrollToActiveElement(playlist);
1334
2403
  }
1335
2404
 
1336
2405
  // deactivate AJS events (if any)
1337
2406
  event.stopImmediatePropagation();
1338
- }); // END EventListener 'click' next button
1339
- } // END if
2407
+
2408
+ }); // END EventListener 'click' next button
2409
+ } // END if
2410
+
1340
2411
  } // END for largePlayerNextButton
1341
2412
 
2413
+ // Overload AJS largePlayerPrevious button for YT
1342
2414
  // click on (player) previous button
1343
2415
  // TODO: Fix for multiple players in page
1344
2416
  // -----------------------------------------------------------------------
1345
-
1346
- // Overload AJS largePlayerPrevious button for YT
1347
- //
1348
2417
  var largePlayePreviousButton = document.getElementsByClassName("large-player-previous");
1349
2418
  for (var i=0; i<largePlayePreviousButton.length; i++) {
1350
- var classArray = [].slice.call(largePlayerNextButton[i].classList, 0);
2419
+ var classArray = [].slice.call(largePlayePreviousButton[i].classList, 0);
1351
2420
  var classString = classArray.toString();
1352
2421
 
1353
2422
  if (classString.includes(ytPlayerID)) {
1354
2423
  largePlayePreviousButton[i].addEventListener('click', function(event) {
1355
- var ytpVideoID;
1356
- var playlist = this.getAttribute("data-amplitude-playlist");
1357
- var playerID = playlist + '_large';
1358
- // var songIndex = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex);
1359
- var songIndex = ytpSongIndex;
1360
- var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
1361
- var ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
1362
-
1363
- if (songIndex < songs.length-1) {
1364
- // set song on previous item
1365
- songIndex--;
1366
- ytpSongIndex = songIndex;
1367
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2424
+ var playlist, playerID, songIndex, trackID,
2425
+ songs, songMetaData, songName, songURL,
2426
+ ytPlayer, ytpVideoID;
2427
+
2428
+ songIndex = ytpSongIndex;
2429
+ playlist = this.getAttribute("data-amplitude-playlist");
2430
+ playerID = playlist + '_large';
2431
+ songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2432
+ ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
2433
+
2434
+ if (ytPlayer === undefined) {
2435
+ logger.error('\n' + 'YT player not defined');
1368
2436
  }
1369
2437
 
1370
- // collect (next) song data
1371
- if (songIndex > 0 && songIndex < songs.length) {
1372
- songMetaData = songs[songIndex];
1373
- songIndex = songMetaData.index;
1374
- songURL = songMetaData.url;
1375
- ytpSongIndex = songMetaData.index;
1376
- ytpVideoID = songURL.split('=')[1];
2438
+ // stop active AT|YT players except the current
2439
+ // stopAllActivePlayers(playerID);
2440
+
2441
+ // select video
2442
+ if (songIndex > 0 && songIndex <= songs.length - 1) {
2443
+ // select NEXT video
2444
+ songIndex--;
2445
+ ytpSongIndex = songIndex;
1377
2446
  } else {
1378
- songIndex = 0;
1379
- ytpSongIndex = 0;
1380
- // j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
1381
- songMetaData = songs[songIndex];
1382
- songURL = songMetaData.url;
1383
- ytpSongIndex = songIndex;
1384
- ytpVideoID = songURL.split('=')[1];
2447
+ // select FIRST video
2448
+ songIndex = 0;
2449
+ ytpSongIndex = songIndex;
1385
2450
  }
1386
2451
 
2452
+ // set song (video)^meta data
2453
+ songMetaData = songs[songIndex];
2454
+ songURL = songMetaData.url;
2455
+ ytpVideoID = songURL.split('=')[1];
2456
+
2457
+ // save YT player GLOBAL data for later use (e.g. events)
2458
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
2459
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
2460
+ j1.adapter.amplitude.data.ytpGlobals['activePlaylist'] = playlist;
2461
+
2462
+ // load next video
2463
+ // -----------------------------------------------------------------
2464
+
1387
2465
  // save YT player data for later use (e.g. events)
1388
- // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
2466
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
2467
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2468
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytpVideoID;
1389
2469
 
1390
- // pause song (video) if FIRST item reached
1391
- // TODO: handle on player|shuffle different (do play)
1392
- if (songMetaData.index === 0) {
1393
- ytpSongIndex = 0;
2470
+ trackID = songIndex + 1;
2471
+ logger.debug('\n' + `SWITCH video for PlayePreviousButton at trackID|VideoID: ${trackID}|${ytpVideoID}`);
2472
+ ytPlayer.loadVideoById(ytpVideoID);
1394
2473
 
1395
- // continue (paused) on FIRST video
1396
- if (ytPlayer !== undefined) {
1397
- ytPlayer.loadVideoById(ytpVideoID);
2474
+ // delay after switch video
2475
+ if (muteAfterVideoSwitchInterval) {
2476
+ ytPlayer.mute();
2477
+ setTimeout(() => {
2478
+ ytPlayer.unMute();
2479
+ }, muteAfterVideoSwitchInterval);
2480
+ }
1398
2481
 
1399
- // wait some time to make sure video is loaded|active
1400
- setTimeout(() => {
1401
- ytPlayer.pauseVideo();
1402
- // reset|update time settings
1403
- resetCurrentTimeContainerYTP();
1404
- updateDurationTimeContainerYTP(ytPlayer);
1405
- resetProgressBarYTP(playerID);
1406
-
1407
- // update AJS play_pause button
1408
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1409
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1410
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
1411
- }, 300);
1412
- }
2482
+ if (songIndex === 0) {
2483
+
2484
+ // continue paused on FIRST video
2485
+ // TODO: handle on player|shuffle different (do play)
2486
+ ytPlayer.pauseVideo();
2487
+
2488
+ // reset|update time settings
2489
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2490
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2491
+ resetProgressBarYTP();
2492
+
2493
+ // set AJS play_pause button paused
2494
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2495
+ // setPlayPauseButtonPlaying(playPauseButtonClass);
2496
+ togglePlayPauseButton(playPauseButtonClass);
1413
2497
  } else {
1414
- // load NEXT video if available
1415
- if (ytPlayer !== undefined) {
1416
- ytPlayer.loadVideoById(ytpVideoID);
1417
-
1418
- // update AJS play_pause button (set playing)
1419
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1420
- largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1421
- largePlayerPlayPauseButton.classList.add('amplitude-playing');
1422
- } else {
1423
- // update AJS play_pause button (set paused)
1424
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1425
- largePlayerPlayPauseButton.classList.remove('amplitude-playing');
1426
- largePlayerPlayPauseButton.classList.add('amplitude-paused');
1427
- }
2498
+ // toggle AJS play_pause button
2499
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2500
+ togglePlayPauseButton(playPauseButtonClass);
1428
2501
  }
1429
2502
 
1430
2503
  // reset|update current time settings
1431
- resetCurrentTimeContainerYTP();
1432
- updateDurationTimeContainerYTP(ytPlayer);
1433
-
1434
- // replace new song name (meta-container)
1435
- var songName = document.getElementsByClassName("song-name");
1436
- songName[0].innerHTML = songMetaData.name; // player-bottom
1437
- songName[1].innerHTML = songMetaData.name; // playlist-screen
1438
-
1439
- // load cover image for next video
1440
- var coverImage;
1441
- var selector = ".cover-image-" + playlist;
1442
- coverImage = document.querySelector(selector);
1443
- coverImage.src = songMetaData.cover_art_url;
1444
-
1445
- // replace song rating (playlist-screen|meta-container)
1446
- var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1447
- if (largetPlayerSongAudioRating.length) {
1448
- if (songMetaData.rating) {
1449
- largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1450
- } else {
1451
- largetPlayerSongAudioRating[0].innerHTML = '';
1452
- }
1453
- } // END if largetPlayerSongAudioRating
2504
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2505
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2506
+ resetProgressBarYTP();
1454
2507
 
1455
- // replace artist name in meta-containers for next video
1456
- var artistName = document.getElementsByClassName("artist");
1457
- artistName[0].innerHTML = songMetaData.artist;
1458
-
1459
- // replace album name in meta-containers for next video
1460
- var albumName = document.getElementsByClassName("album");
1461
- albumName[0].innerHTML = songMetaData.album;
1462
-
1463
- // update AJS play_pause button
1464
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1465
- largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1466
- largePlayerPlayPauseButton.classList.add('amplitude-playing');
1467
-
1468
- // on LAST item, don't activate item in playlist
1469
- if (songIndex !== songs.length - 1) {
1470
- // set song active in playlist
1471
- // setSongPlayed(songIndex);
1472
- setSongPlayed(playerID, songIndex);
1473
- }
2508
+ // load the song cover image
2509
+ loadCoverImage(songMetaData);
2510
+
2511
+ // update meta data
2512
+ updatMetaContainers(songMetaData);
1474
2513
 
1475
- // set song active in playlist
1476
- // setSongPlayed(songIndex);
1477
- // setSongPlayed(playerID, songIndex);
2514
+ // set song at songIndex active in playlist
2515
+ setSongActive(playlist, songIndex);
2516
+
2517
+ // scroll song active at index in player
2518
+ if (playerAutoScrollSongElement) {
2519
+ scrollToActiveElement(playlist);
2520
+ }
1478
2521
 
1479
2522
  // deactivate AJS events (if any)
1480
- event.stopImmediatePropagation();
1481
- }); // END EventListener 'click' previous button
2523
+ event.stopImmediatePropagation();
2524
+
2525
+ }); // END EventListener 'click' next button
1482
2526
  } // END if
1483
- } // END for
1484
2527
 
1485
- // click on song container
1486
- // TODO: Fix for multiple players in page
1487
- // ---------------------------------------------------------------------
1488
- var largetPlayerSongContainer = document.getElementsByClassName("amplitude-song-container");
1489
- for (var i=0; i<largetPlayerSongContainer.length; i++) {
1490
- var classArray = [].slice.call(largetPlayerSongContainer[i].classList, 0);
1491
- var classString = classArray.toString();
1492
-
1493
- if (classString.includes(ytPlayerID)) {
1494
- largetPlayerSongContainer[i].addEventListener('click', function(event) {
1495
- var ytpVideoID;
1496
- var activeSongIndex;
1497
- var success;
2528
+ } // END for largePlayerNextButton
1498
2529
 
1499
- var playlist = this.getAttribute("data-amplitude-playlist");
1500
- var playerID = playlist + '_large';
1501
- // var ytpSongIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
1502
- var songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2530
+ // click on song container
2531
+ // TODO: Fix for multiple players in page
2532
+ // -------------------------------------------------------------------------
2533
+ var largePlayerSongContainer = document.getElementsByClassName("amplitude-song-container");
2534
+ for (var i=0; i<largePlayerSongContainer.length; i++) {
2535
+ var classArray = [].slice.call(largePlayerSongContainer[i].classList, 0);
2536
+ var classString = classArray.toString();
2537
+
2538
+ if (classString.includes(ytPlayerID)) {
2539
+ largePlayerSongContainer[i].addEventListener('click', function(event) {
2540
+ var activeSongSettings, playlist, playerID, playerState,
2541
+ songs, songIndex, songName, singleAudio, trackID,
2542
+ ytPlayer, ytpVideoID;
2543
+
2544
+ // set (current) playlist|song data
2545
+ playlist = this.getAttribute("data-amplitude-playlist");
2546
+ playerID = playlist + '_large';
2547
+ songIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
2548
+ trackID = songIndex + 1;
2549
+
2550
+ // update active song settings (manually)
2551
+ checkActiveVideoElementYTP();
2552
+
2553
+ // get active song settings (manually)
2554
+ activeSongSettings = getActiveSong();
2555
+
2556
+ if (activeSongSettings) {
2557
+ // ytpCurrentTime = activeSongSettings.currentTime;
2558
+ if (activeSongSettings.playlist !== playlist) {
2559
+ // set current player settings
2560
+ songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2561
+ ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
2562
+
2563
+ // reset previous player settings
2564
+ if (activeSongSettings.player !== undefined) {
2565
+ activeSongSettings.player.stopVideo();
2566
+ var playPauseButtonClass = `large-player-play-pause-${activeSongSettings.playerID}`;
2567
+ togglePlayPauseButton(playPauseButtonClass);
2568
+ }
2569
+ } else {
2570
+ // set current player settings
2571
+ songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2572
+ ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
2573
+ }
2574
+ } else {
2575
+ // set current player settings
2576
+ songs = j1.adapter.amplitude.data.ytPlayers[playerID].songs;
2577
+ ytPlayer = j1.adapter.amplitude.data.ytPlayers[playerID].player;
2578
+ }
1503
2579
 
1504
- // update global song index
1505
- ytpSongIndex = parseInt(this.getAttribute("data-amplitude-song-index"));
2580
+ // set (current) song meta data
2581
+ songMetaData = songs[songIndex];
2582
+ songURL = songMetaData.url;
2583
+ ytpVideoID = songURL.split('=')[1];
2584
+ playerState = ytPlayer.getPlayerState();
1506
2585
 
1507
- // get active song index if video (song) is playing
1508
- activeSongIndex = getSongPlayed();
2586
+ // TOGGLE state 'playing'|'paused' if video (audio) NOT changed
2587
+ var isItemChanged = (j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex !== songIndex) ? true : false;
2588
+ if (!isItemChanged && (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED)) {
1509
2589
 
1510
- // if (activeSongIndex >= 0) {
1511
- // success = ytpSetActiveIndex(playerID, activeSongIndex);
1512
- // } else {
1513
- // success = ytpSetActiveIndex(playerID, ytpSongIndex);
1514
- // }
2590
+ if (playerState === YT_PLAYER_STATE.PLAYING) {
2591
+ ytPlayer.pauseVideo();
2592
+ ytPlayerCurrentTime = ytPlayer.getCurrentTime();
1515
2593
 
1516
- // save YT player data for later use (e.g. events)
1517
- // j1.adapter.amplitude.data.ytpGlobals['ytPlayerSongs'] = songs;
1518
- // j1.adapter.amplitude.data.ytpGlobals['ytpSongIndex'] = ytpSongIndex;
2594
+ var trackID = songIndex + 1;
2595
+ logger.debug('\n' + `PAUSE video for PlayerSongContainer on playlist|trackID: ${playlist}|${trackID} at: ${ytPlayerCurrentTime}`);
1519
2596
 
1520
- var playerState = ytPlayer.getPlayerState();
1521
- if (playerState === YT_PLAYER_STATE.PLAYING && ytpSongIndex === activeSongIndex) {
1522
- // do NOT interupt current video (song) is playing
1523
- return;
1524
- } else {
1525
- // set (current) song data
1526
- songMetaData = songs[ytpSongIndex];
1527
- songIndex = songMetaData.index;
1528
- songURL = songMetaData.url;
1529
- ytpSongIndex = songIndex;
1530
- ytpVideoID = songURL.split('=')[1];
1531
- // load new video
1532
- ytPlayer.loadVideoById(ytpVideoID);
2597
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2598
+ togglePlayPauseButton(playPauseButtonClass);
2599
+
2600
+ // reset|update time settings
2601
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2602
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2603
+ return;
1533
2604
  }
1534
2605
 
1535
- // reset|update current time settings
1536
- resetCurrentTimeContainerYTP();
1537
- updateDurationTimeContainerYTP(ytPlayer);
1538
-
1539
- // load cover image for next video
1540
- var coverImage;
1541
- var selector = ".cover-image-" + playlist;
1542
- coverImage = document.querySelector(selector);
1543
- coverImage.src = songMetaData.cover_art_url;
1544
-
1545
- // replace new song name (meta-container)
1546
- var songName = document.getElementsByClassName("song-name");
1547
- songName[0].innerHTML = songMetaData.name; // player-bottom
1548
- songName[1].innerHTML = songMetaData.name; // playlist-screen
1549
-
1550
- // replace song info URL (playlist-screen|meta-container)
1551
- var largetPlayerSongInfoLink = document.getElementsByClassName("audio-info-link");
1552
- if (largetPlayerSongInfoLink.length) {
1553
- if (songMetaData.audio_info) {
1554
- largetPlayerSongInfoLink[0].href = songMetaData.audio_info;
1555
- } else {
1556
- largetPlayerSongInfoLink[0].href = songURL;
2606
+ if (playerState === YT_PLAYER_STATE.PAUSED) {
2607
+ ytPlayer.playVideo();
2608
+ ytpSeekTo(ytPlayer, ytPlayerCurrentTime, true);
2609
+
2610
+ var trackID = songIndex + 1;
2611
+ logger.debug('\n' + `PLAY video for PlayerSongContainer on playlist|trackID: ${playlist}|${trackID} at: ${ytPlayerCurrentTime}`);
2612
+
2613
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2614
+ togglePlayPauseButton(playPauseButtonClass);
2615
+
2616
+ // reset|update time settings
2617
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2618
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2619
+ return;
2620
+ }
2621
+
2622
+ } // END !changedAudio
2623
+
2624
+ // update global song index (start at 0)
2625
+ ytpSongIndex = songIndex;
2626
+
2627
+ // stop active AT|YT players
2628
+ // stopAllActivePlayers(playerID);
2629
+
2630
+ // save YT player GLOBAL data for later use (e.g. events)
2631
+ j1.adapter.amplitude.data.activePlayer = 'ytp';
2632
+ j1.adapter.amplitude.data.ytpGlobals['activeIndex'] = songIndex;
2633
+ j1.adapter.amplitude.data.ytpGlobals['activePlaylist'] = playlist;
2634
+
2635
+ // save YT player data for later use (e.g. events)
2636
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2637
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytpVideoID;
2638
+
2639
+ // reset|update current time settings
2640
+ resetCurrentTimeContainerYTP(ytPlayer, playlist);
2641
+ updateDurationTimeContainerYTP(ytPlayer, playlist);
2642
+ resetProgressBarYTP();
2643
+
2644
+ // load the song cover image
2645
+ loadCoverImage(songMetaData);
2646
+
2647
+ // update meta data
2648
+ updatMetaContainers(songMetaData);
2649
+
2650
+ // set AJS play_pause button playing
2651
+ var playPauseButtonClass = `large-player-play-pause-${ytPlayerID}`;
2652
+ setPlayPauseButtonPlaying(playPauseButtonClass)
2653
+
2654
+ // set song at songIndex active in playlist
2655
+ setSongActive(playlist, songIndex);
2656
+
2657
+ // scroll song active at index in player
2658
+ if (playerAutoScrollSongElement) {
2659
+ scrollToActiveElement(playlist);
2660
+ }
2661
+
2662
+ // save YT player data for later use (e.g. events)
2663
+ j1.adapter.amplitude.data.ytPlayers[playerID].activeIndex = songIndex;
2664
+ j1.adapter.amplitude.data.ytPlayers[playerID].videoID = ytpVideoID;
2665
+
2666
+ // load next video
2667
+ // -------------------------------------------------------------------
2668
+ trackID = songIndex + 1;
2669
+ logger.debug('\n' + `SWITCH video for PlayerSongContainer at trackID|VideoID: ${trackID}|${ytpVideoID}`);
2670
+ ytPlayer.loadVideoById(ytpVideoID);
2671
+
2672
+ // mute sound after next video load
2673
+ // -------------------------------------------------------------------
2674
+ if (muteAfterVideoSwitchInterval) {
2675
+ ytPlayer.mute();
2676
+ setTimeout(() => {
2677
+ ytPlayer.unMute();
2678
+ }, muteAfterVideoSwitchInterval);
2679
+ }
2680
+
2681
+ // deactivate AJS events (if any)
2682
+ event.stopImmediatePropagation();
2683
+ }); // END EventListener 'click' SongContainer
2684
+ } // END ifSWITCH video
2685
+ } // END for
2686
+
2687
+ // add listeners to all progress bars found
2688
+ // TODO: Fix for multiple players in page
2689
+ // -------------------------------------------------------------------------
2690
+ var progressBars = document.getElementsByClassName("large-player-progress");
2691
+ if (progressBars.length) {
2692
+ for (var i=0; i<progressBars.length; i++) {
2693
+ var classArray = [].slice.call(progressBars[i].classList, 0);
2694
+ var classString = classArray.toString();
2695
+ var progressId = progressBars[i].id;
2696
+ var playerID = progressId.split('large_player_progress_')[1];
2697
+ var progressClass = ('large-player-progress-' + playerID).replace('_large','');
2698
+
2699
+ if (progressBars[i].dataset.amplitudeSource === 'audio') {
2700
+ // do nothing (managed by adapter)
2701
+ } else {
2702
+ var progressBar = progressBars[i];
2703
+ if (classString.includes(progressClass)) {
2704
+ // save YT player data for later use (e.g. events)
2705
+ j1.adapter.amplitude.data.ytPlayers[playerID].progressBar = progressBar;
2706
+
2707
+ progressBars[i].addEventListener('click', function(event) {
2708
+ var activeSongSettings, playlist, ytPlayer,
2709
+ playerState, progressBar, percentage, time;
2710
+
2711
+ // update active song settings (manually)
2712
+ checkActiveVideoElementYTP();
2713
+
2714
+ // get active song settings (manually)
2715
+ activeSongSettings = getActiveSong();
2716
+
2717
+ if (!activeSongSettings) {
2718
+ // do nothing if current video (audio) item is NOT selected|active
2719
+ return;
1557
2720
  }
1558
- } // END if largetPlayerSongInfoLink
1559
2721
 
1560
- // replace song rating (playlist-screen|meta-container)
1561
- var largetPlayerSongAudioRating = document.getElementsByClassName("audio-rating");
1562
- if (largetPlayerSongAudioRating.length) {
1563
- if (songMetaData.rating) {
1564
- largetPlayerSongAudioRating[0].innerHTML = songMetaData.rating + ' <i class="mdib mdib-star md-gray-400 mdib-18px"></i>';
1565
- } else {
1566
- largetPlayerSongAudioRating[0].innerHTML = '';
2722
+ playlist = this.getAttribute("data-amplitude-playlist");
2723
+ if (activeSongSettings.playlist !== playlist) {
2724
+ // do nothing on PREVIOUS playlist (player)
2725
+ return;
1567
2726
  }
1568
- } // END if largetPlayerSongAudioRating
1569
2727
 
1570
- // update AJS play_pause button
1571
- var largePlayerPlayPauseButton = document.getElementById('large_player_play_pause');
1572
- largePlayerPlayPauseButton.classList.remove('amplitude-paused');
1573
- largePlayerPlayPauseButton.classList.add('amplitude-playing');
2728
+ ytPlayer = activeSongSettings.player;
2729
+ playerState = ytPlayer.getPlayerState();
1574
2730
 
1575
- // set song active in playlist
1576
- // if (event.currentTarget.className.includes(ytPlayerID)) {
1577
- // setSongPlayed(songIndex);
1578
- // }
2731
+ //if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.BUFFERING) {
2732
+ if (playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED || playerState === YT_PLAYER_STATE.BUFFERING) {
2733
+ progressBar = this;
2734
+ percentage = getProgressBarSelectedPositionPercentage(event, progressBar);
2735
+ time = getTimeFromPercentage(ytPlayer, percentage);
1579
2736
 
1580
- // set song active in playlist
1581
- setSongPlayed(ytPlayerID, songIndex);
2737
+ // seek video to current time
2738
+ // var buffered = ytpSeekTo(ytPlayer, time, true);
2739
+ ytpSeekTo(ytPlayer, time, true);
2740
+
2741
+ // set current progess value if valid
2742
+ if (isFinite(percentage)) {
2743
+ progressBar.value = percentage;
2744
+ }
2745
+ } // END if ytPlayer
1582
2746
 
1583
- // do NOT bubble up
1584
- event.stopPropagation();
2747
+ // deactivate AJS events (if any)
2748
+ event.stopImmediatePropagation();
2749
+ }); // END EventListener 'click'
2750
+ } // END if classString includes
2751
+ } // END if amplitudeSource
2752
+ } // END for progressBars
2753
+ } // END if progressBars
2754
+
2755
+ // add listeners to all volume sliders found
2756
+ // TODO: Fix for multiple players in page
2757
+ // -------------------------------------------------------------------------
2758
+ var volumeSliders = document.getElementsByClassName("amplitude-volume-slider");
2759
+ for (var i=0; i<volumeSliders.length; i++) {
2760
+ if (volumeSliders[i].dataset.amplitudeSource === 'audio') {
2761
+ // do nothing (managed by adapter)
2762
+ var bla = 1;
2763
+ } else {
2764
+ if (volumeSliders[i]) {
2765
+ // for (var i=0; i<volumeSliders.length; i++) {
2766
+ var volumeSlider = volumeSliders[i];
2767
+ var sliderID = volumeSliders[i].id;
2768
+ var playerID = sliderID.split('volume_slider_')[1];
1585
2769
 
1586
- // deactivate AJS events (if any)
1587
- event.stopImmediatePropagation();
1588
- }); // END EventListener 'click' SongContainer
1589
- } // END if
1590
- } // END for
2770
+ // save YT player data for later use (e.g. events)
2771
+ // j1.adapter.amplitude.data.ytPlayers[playerID].volumeSlider = volumeSlider;
1591
2772
 
1592
- // add listeners to all progress bars found
1593
- // TODO: Fix for multiple players in page
1594
- // ---------------------------------------------------------------------
1595
- var progressBars = document.getElementsByClassName("large-player-progress");
1596
- if (progressBars.length) {
1597
- for (var i=0; i<progressBars.length; i++) {
1598
- var progressBar = progressBars[i];
1599
- // var id = bar.id.split('large-player-progress_')[0];
1600
- // var progressId = progressBars[i].id.split('large-player-progress_')[0];
1601
- var progressId = progressBars[i].id;
1602
- var playerId = progressId.split('large_player_progress_')[1];
2773
+ volumeSliders[i].addEventListener('click', function(event) {
2774
+
2775
+ // update active song settings (manually)
2776
+ checkActiveVideoElementYTP();
2777
+
2778
+ // get active song settings (manually)
2779
+ var activeSongSettings = getActiveSong();
2780
+
2781
+ if (!activeSongSettings) {
2782
+ // do nothing if current video (audio) item is NOT selected|active
2783
+ return;
2784
+ }
2785
+
2786
+ var ytPlayer = activeSongSettings.player;
2787
+ var playerState = ytPlayer.getPlayerState();
2788
+
2789
+ if ((playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) && ytPlayer !== undefined) {
2790
+ var volumeSlider, volumeValue;
2791
+ var currenVolume = ytPlayer.getVolume();
2792
+
2793
+ volumeSlider = this;
2794
+ volumeValue = 50; // default
2795
+
2796
+ if (volumeSlider !== null) {
2797
+ volumeValue = parseInt(volumeSlider.value);
2798
+ }
2799
+
2800
+ ytPlayer.setVolume(volumeValue);
2801
+ } // END if ytPlayer
2802
+
2803
+ }); // END EventListener 'click'
2804
+ // } // END for
2805
+ } // END if volumeSliders
2806
+ } // END if volumeSliders
2807
+ } // END for volumeSliders
2808
+
2809
+ // add listeners to all mute buttons found
2810
+ // TODO: Fix for multiple buttons in page
2811
+ // -------------------------------------------------------------------------
2812
+ var volumeMutes = document.getElementsByClassName("amplitude-mute");
2813
+ for (var i=0; i<volumeMutes.length; i++) {
2814
+ if (volumeMutes[i].dataset.amplitudeSource === 'audio') {
2815
+ // do nothing (managed by adapter)
2816
+ var bla = 1;
2817
+ } else {
2818
+ if (volumeMutes[i]) {
2819
+ var volumMute = volumeMutes[i];
2820
+ var sliderID = volumeMutes[i].id;
2821
+ var playerID = sliderID.split('amplitude-mute_')[1];
1603
2822
 
1604
2823
  // save YT player data for later use (e.g. events)
1605
- // j1.adapter.amplitude.data.ytpGlobals['ytPlayerProgressBar'] = progressBars[i];
1606
- // j1.adapter.amplitude.data.ytPlayers[playerId].progressBar = progressId;
1607
- j1.adapter.amplitude.data.ytPlayers[playerId].progressBar = progressBar;
1608
-
1609
- progressBars[i].addEventListener('click', function(event) {
1610
- // if (ytPlayer.getPlayerState() === YT_PLAYER_STATE.PLAYING) {
1611
- if (ytPlayer !== undefined) {
1612
- var progressBar, percentage, time;
1613
- progressBar = this;
1614
- percentage = getProgressBarSelectedPositionPercentage(event, progressBar);
1615
- time = getTimeFromPercentage(ytPlayer, percentage);
1616
-
1617
- // seek video to current time
1618
- ytpSeekTo(ytPlayer, time);
1619
-
1620
- // set current progess value if valid
1621
- if (isFinite(percentage)) {
1622
- progressBar.value = percentage;
2824
+ // j1.adapter.amplitude.data.ytPlayers[playerID].volumMute = volumMute;
2825
+
2826
+ volumeMutes[i].addEventListener('click', function(event) {
2827
+
2828
+ // update active song settings (manually)
2829
+ checkActiveVideoElementYTP();
2830
+
2831
+ // get active song settings (manually)
2832
+ var activeSongSettings = getActiveSong();
2833
+
2834
+ if (!activeSongSettings) {
2835
+ // do nothing if current video (audio) item is NOT selected|active
2836
+ return;
2837
+ }
2838
+
2839
+ var ytPlayer = activeSongSettings.player;
2840
+ var playerState = ytPlayer.getPlayerState();
2841
+ var volumeSlider = j1.adapter.amplitude.data.ytPlayers[playerID].volumeSlider;
2842
+ var currenVolume = ytPlayer.getVolume();
2843
+ var playerVolumePreset = parseInt(j1.adapter.amplitude.data.ytPlayers[playerID].playerSettings.volume_slider.preset_value);
2844
+
2845
+ if ((playerState === YT_PLAYER_STATE.PLAYING || playerState === YT_PLAYER_STATE.PAUSED) && ytPlayer !== undefined) {
2846
+ if (currenVolume > 0) {
2847
+ volumeSlider.value = 0;
2848
+ ytPlayer.setVolume(0);
2849
+ } else {
2850
+ volumeSlider.value = playerVolumePreset;
2851
+ ytPlayer.setVolume(playerVolumePreset);
1623
2852
  }
1624
2853
  } // END if ytPlayer
1625
2854
 
1626
- // deactivate AJS events (if any)
1627
- event.stopImmediatePropagation();
1628
2855
  }); // END EventListener 'click'
1629
- } // END for
1630
- } // END if progressBars
1631
2856
 
1632
- } // END if playerType large'
1633
- }
2857
+ } // END if volumeMutes
2858
+ } // END if volumeSliders
2859
+ } // END for volumeSliders
2860
+
2861
+ } // END if playerSettings.type 'large'
2862
+
2863
+ }
2864
+
1634
2865
  } // END mimikYTPlayerUiEventsForAJS
1635
2866
 
1636
2867
  {%- endcapture -%}