From c18046406e972c3dcb7a9004930dca03a6a5f4b1 Mon Sep 17 00:00:00 2001 From: PrestonN Date: Fri, 28 Sep 2018 15:48:42 -0400 Subject: [PATCH] [Feature] Playlist Support mostly finished --- src/js/player.js | 138 +++++++++++++++++-------------- src/js/playlist.js | 86 ++++++++++++------- src/js/templates.js | 35 +++++++- src/js/videos.js | 4 +- src/style/darkTheme.css | 4 + src/style/lightTheme.css | 4 + src/style/main.css | 2 +- src/style/playlist.css | 75 +++++++++++++++++ src/templates/player.html | 19 ++++- src/templates/playlistView.html | 2 +- src/templates/videoTemplate.html | 2 +- 11 files changed, 272 insertions(+), 99 deletions(-) diff --git a/src/js/player.js b/src/js/player.js index 72bb4449a..7beb94770 100644 --- a/src/js/player.js +++ b/src/js/player.js @@ -28,7 +28,7 @@ * * @return {Void} */ -function playVideo(videoId) { +function playVideo(videoId, playlistId = '') { hideViews(); playerView.playerSeen = true; @@ -120,7 +120,7 @@ function playVideo(videoId) { if (typeof (playerView.video720p) === 'undefined' && typeof (playerView.video480p) === 'undefined') { //useEmbedPlayer = true; playerView.currentQuality = 'EMBED'; - //playerView.playerSeen = false; + playerView.playerSeen = false; //useEmbedPlayer = true; showToast('Unable to get video file. Reverting to embeded player.'); } @@ -196,6 +196,49 @@ function playVideo(videoId) { playerView.recommendedVideoList = playerView.recommendedVideoList.concat(data); }); + if (playlistId != '') { + playerView.playlistSeen = true; + playerView.playlistShowList = true; + playerView.playlistId = playlistId; + playerView.playlistVideoList = []; + + invidiousAPI('playlists', playlistId, {}, (data) => { + playerView.playlistTitle = data.title; + playerView.playlistChannelName = data.author; + playerView.playlistChannelId = data.authorId; + playerView.playlistTotal = data.videoCount; + + let amountOfPages = Math.ceil(data.videoCount / 100); + + console.log(amountOfPages); + + for (let i = 1; i <= amountOfPages; i++) { + invidiousAPI('playlists', playlistId, {page: i}, (data) => { + data.videos.forEach((video) => { + let data = {}; + + if (video.videoId == videoId){ + playerView.playlistIndex = video.index + 1; + } + + data.title = video.title; + data.videoId = video.videoId; + data.channelName = video.author; + data.index = video.index + 1; + data.thumbnail = video.videoThumbnails[4].url; + + playerView.playlistVideoList[video.index] = data; + }); + }); + } + }); + } + else{ + playerView.playlistSeen = false; + playerView.playlistShowList = false; + playerView.playlistId = ''; + } + loadingView.seen = false; if (subscriptionView.seen === false && aboutView.seen === false && headerView.seen === false && searchView.seen === false && settingsView.seen === false && popularView.seen === false && savedView.seen === false && historyView.seen === false && channelView.seen === false && channelVideosView.seen === false) { @@ -272,16 +315,22 @@ function checkVideoSettings() { switch (defaultQuality) { case '480': - playerView.videoUrl = playerView.video480p; - playerView.currentQuality = '480p'; + if (typeof(playerView.video480p) !== 'undefined') { + playerView.videoUrl = playerView.video480p; + playerView.currentQuality = '480p'; + } break; case '720': - playerView.videoUrl = playerView.video720p; - playerView.currentQuality = '720p'; + if (typeof(playerView.video720p) !== 'undefined') { + playerView.videoUrl = playerView.video720p; + playerView.currentQuality = '720p'; + } break; default: - playerView.videoUrl = playerView.video720p; - playerView.currentQuality = '720p'; + if (typeof(playerView.video720p) !== 'undefined') { + playerView.videoUrl = playerView.video720p; + playerView.currentQuality = '720p'; + } break; } @@ -292,63 +341,32 @@ function checkVideoSettings() { player.volume = currentVolume; } -/** - * Change the quality of the current video. - * - * @param {string} videoHtml - The HTML of the video player to be set. - * @param {string} qualityType - The Quality Type of the video. Ex: 720p, 480p - * @param {boolean} isEmbed - Optional: Value on if the videoHtml is the embeded player. - * - * @return {Void} - */ -function changeQuality(url, qualityText, isEmbed = false) { - if (videoHtml == '') { - showToast('Video quality type is not available. Unable to change quality.') - return; - } +function playNextVideo() { + let player = document.getElementById('videoPlayer'); - videoHtml = videoHtml.replace(/\"\;/g, '"'); + if (player.loop !== false || playerView.playlistSeen === false) { + return; + } - ft.log('HTML Video: ', videoHtml); - ft.log('(Is the video embeded?) isEmbed: ', isEmbed); + if (playerView.playlistShuffle === true) { + let randomVideo = Math.floor(Math.random() * playerView.playlistTotal); - // The YouTube API creates 2 more iFrames. This is why a boolean value is sent - // with the function. - const embedPlayer = document.getElementsByTagName('IFRAME')[0]; + loadingView.seen = true; + playVideo(playerView.playlistVideoList[randomVideo].videoId, playerView.playlistId); + return; + } - const html5Player = document.getElementsByClassName('videoPlayer'); + if (playerView.playlistLoop === true && playerView.playlistIndex == playerView.playlistTotal) { + loadingView.seen = true; + playVideo(playerView.playlistVideoList[0].videoId, playerView.playlistId); + return; + } - ft.log('Embeded Player Element: ', embedPlayer); - ft.log('HTML5 Player Element: ', html5Player); - - if (isEmbed && html5Player.length == 0) { - // The embeded player is already playing. Return. - showToast('You are already using the embeded player.') - return; - } else if (isEmbed) { - // Switch from HTML 5 player to embeded Player - html5Player[0].remove(); - const mainHtml = $('#main').html(); - $('#main').html(videoHtml + mainHtml); - $('#currentQuality').html(qualityType); - } else if (html5Player.length == 0) { - // Switch from embeded player to HTML 5 player - embedPlayer.remove(); - let videoPlayer = document.createElement('video'); - videoPlayer.className = 'videoPlayer'; - videoPlayer.src = videoHtml; - videoPlayer.controls = true; - videoPlayer.autoplay = true; - $('#main').prepend(videoPlayer); - $('#currentQuality').html(qualityType); - } else { - // Switch src on HTML 5 player - const currentPlayBackTime = $('.videoPlayer').get(0).currentTime; - html5Player[0].src = videoHtml; - html5Player[0].load(); - $('.videoPlayer').get(0).currentTime = currentPlayBackTime; - $('#currentQuality').html(qualityType); - } + if (playerView.playlistIndex != playerView.playlistTotal) { + loadingView.seen = true; + playVideo(playerView.playlistVideoList[playerView.playlistIndex].videoId, playerView.playlistId); + return; + } } /** diff --git a/src/js/playlist.js b/src/js/playlist.js index 611833880..72331e6e2 100644 --- a/src/js/playlist.js +++ b/src/js/playlist.js @@ -19,9 +19,12 @@ function showPlaylist(playlistId) { hideViews(); loadingView.seen = true; + playlistView.videoList = []; + invidiousAPI('playlists', playlistId, {}, (data) => { console.log(data); + playlistView.playlistId = playlistId; playlistView.channelName = data.author; playlistView.channelId = data.authorId; playlistView.channelThumbnail = data.authorThumbnails[3].url; @@ -34,43 +37,66 @@ function showPlaylist(playlistId) { dateString.setDate(dateString.getDate() + 1); playlistView.lastUpdated = dateFormat(dateString, "mmm dS, yyyy"); - data.videos.forEach((video) => { - let videoData = {}; + let amountOfPages = Math.ceil(data.videoCount / 100); - let time = video.lengthSeconds; - let hours = 0; + console.log(amountOfPages); - if (time >= 3600) { - hours = Math.floor(time / 3600); - time = time - hours * 3600; - } + for (let i = 1; i <= amountOfPages; i++) { + invidiousAPI('playlists', playlistId, {page: i}, (data) => { + console.log(data); + data.videos.forEach((video) => { + let videoData = {}; - let minutes = Math.floor(time / 60); - let seconds = time - minutes * 60; + let time = video.lengthSeconds; + let hours = 0; - if (seconds < 10) { - seconds = '0' + seconds; - } + if (time >= 3600) { + hours = Math.floor(time / 3600); + time = time - hours * 3600; + } - if (minutes < 10 && hours > 0) { - minutes = '0' + minutes; - } + let minutes = Math.floor(time / 60); + let seconds = time - minutes * 60; - if (hours > 0) { - videoData.duration = hours + ":" + minutes + ":" + seconds; - } else { - videoData.duration = minutes + ":" + seconds; - } + if (seconds < 10) { + seconds = '0' + seconds; + } - videoData.id = video.videoId; - videoData.title = video.title; - videoData.channelName = video.author; - videoData.channelId = video.authorId; - videoData.thumbnail = video.videoThumbnails[4].url; + if (minutes < 10 && hours > 0) { + minutes = '0' + minutes; + } - playlistView.videoList[video.index] = videoData; - }); - loadingView.seen = false; - playlistView.seen = true; + if (hours > 0) { + videoData.duration = hours + ":" + minutes + ":" + seconds; + } else { + videoData.duration = minutes + ":" + seconds; + } + + videoData.id = video.videoId; + videoData.title = video.title; + videoData.channelName = video.author; + videoData.channelId = video.authorId; + videoData.thumbnail = video.videoThumbnails[4].url; + + playlistView.videoList[video.index] = videoData; + }); + if (playlistView.seen !== false) { + playlistView.seen = false; + playlistView.seen = true; + } + }); + + loadingView.seen = false; + playlistView.seen = true; + } }); } + +function togglePlaylist() { + if (playerView.playlistShowList !== false) { + playerView.playlistShowList = false; + } + else{ + playerView.playlistShowList = true; + } +} diff --git a/src/js/templates.js b/src/js/templates.js index 463319883..420c88c5a 100644 --- a/src/js/templates.js +++ b/src/js/templates.js @@ -288,6 +288,7 @@ let playlistView = new Vue({ el: '#playlistView', data: { seen: false, + playlistId: '', channelName: '', channelId: '', thumbnail: '', @@ -301,7 +302,7 @@ let playlistView = new Vue({ methods: { play: (videoId) => { loadingView.seen = true; - playVideo(videoId); + playVideo(videoId, playlistView.playlistId); }, channel: (channelId) => { goToChannel(channelId); @@ -433,6 +434,7 @@ let playerView = new Vue({ el: '#playerView', data: { seen: false, + playlistSeen: false, firstLoad: true, publishedDate: '', videoUrl: '', @@ -461,6 +463,13 @@ let playerView = new Vue({ videoLikes: 0, videoDislikes: 0, playerSeen: true, + playlistTitle: '', + playlistChannelName: '', + playlistIndex: 1, + playlistTotal: 1, + playlistLoop: false, + playlistShuffle: false, + playlistShowList: true, recommendedVideoList: [], playlistVideoList: [], }, @@ -500,9 +509,9 @@ let playerView = new Vue({ save: (videoId) => { toggleSavedVideo(videoId); }, - play: (videoId) => { + play: (videoId, playlistId = '') => { loadingView.seen = true; - playVideo(videoId); + playVideo(videoId, playlistId); }, loop: () => { let player = document.getElementById('videoPlayer'); @@ -519,6 +528,26 @@ let playerView = new Vue({ playlist: (playlistId) => { showPlaylist(playlistId); }, + playlistLoopToggle: () => { + if (playerView.playlistLoop !== false) { + showToast('Playlist will no longer loop'); + playerView.playlistLoop = false; + } + else { + showToast('Playlist will now loop'); + playerView.playlistLoop = true; + } + }, + playlistShuffleToggle: () => { + if (playerView.playlistShuffle !== false) { + showToast('Playlist will no longer shuffle'); + playerView.playlistShuffle = false; + } + else{ + showToast('Playlist will now shuffle'); + playerView.playlistShuffle = true; + } + }, }, template: playerTemplate }); diff --git a/src/js/videos.js b/src/js/videos.js index 9d24b427b..8639705da 100644 --- a/src/js/videos.js +++ b/src/js/videos.js @@ -459,7 +459,7 @@ function checkVideoUrls(video480p, video720p, videoAudio) { default: ft.log('480p is valid'); if (currentQuality === '720p' && typeof (video720p) === 'undefined') { - changeQuality(video480p); + playerView.currentQuality = '480p'; } break; } @@ -477,7 +477,7 @@ function checkVideoUrls(video480p, video720p, videoAudio) { showToast('Found valid URL for 720p, but returned a 404. Video type might be available in the future.'); playerView.valid720p = false; if (typeof (valid480) !== 'undefined') { - changeQuality(video480p, '480p'); + playerView.currentQuality = '480p'; } break; case 403: diff --git a/src/style/darkTheme.css b/src/style/darkTheme.css index f874c1df4..299392e7d 100644 --- a/src/style/darkTheme.css +++ b/src/style/darkTheme.css @@ -267,3 +267,7 @@ input[type=text] { #comments { background-color: #424242; } + +#miniPL { + background-color: #424242; +} diff --git a/src/style/lightTheme.css b/src/style/lightTheme.css index 21b509064..287a6b4a9 100644 --- a/src/style/lightTheme.css +++ b/src/style/lightTheme.css @@ -211,3 +211,7 @@ body { #comments { background: #eee; } + +#miniPL { + background-color: white; +} diff --git a/src/style/main.css b/src/style/main.css index 235af43bb..25ec9bf9d 100644 --- a/src/style/main.css +++ b/src/style/main.css @@ -46,7 +46,7 @@ a { height: 3px; background-color: #f44336; display: block; - position: absolute; + position: fixed; bottom: 0; left: 0; z-index: 1; diff --git a/src/style/playlist.css b/src/style/playlist.css index a16b2e8b7..11845853a 100644 --- a/src/style/playlist.css +++ b/src/style/playlist.css @@ -71,3 +71,78 @@ font-size: 12px; cursor: pointer; } + +#miniPL { + width: 100%; +} + +.miniPLVideo { + width: 100%; + cursor: pointer; + height: 70px; +} + +.miniPLThumbnail { + width: 120px; + height: 80px; + margin-right: 5px; + float: left; +} + +.miniPLIndex { + float: left; + position: relative; + width: 15px; + top: 30px; + margin-right: 35px; +} + +.miniPLVideoTitle { + font-weight: bold; +} + +.miniPLVideoChannelName { + font-size: 12px; + position: relative; + bottom: 10px; +} + +#miniPLTitle { + font-weight: bold; + font-size: 20px; + margin-left: 20px; + padding-top: 25px; + cursor: pointer; +} + +#miniPLChannelName { + font-size: 15px; + font-weight: normal; +} + +#miniPLVideoList { + padding: 10px; + overflow: scroll; + height: 375px; +} + +#miniPLLoop { + margin-left: 20px; + font-size: 20px; + cursor: pointer; +} + +#miniPLShuffle { + margin-left: 20px; + font-size: 20px; + cursor: pointer; +} + +#miniPLDropdown { + float: right; + cursor: pointer; + font-size: 20px; + position: relative; + top: 20px; + right: 15px; +} diff --git a/src/templates/player.html b/src/templates/player.html index 93b08c7ed..6e0a7ceda 100644 --- a/src/templates/player.html +++ b/src/templates/player.html @@ -1,6 +1,6 @@
-
@@ -79,6 +79,23 @@
+
+ +

{{playlistTitle}}
{{playlistChannelName}} - {{playlistIndex}} / {{playlistTotal}}

+ + +

+
+
+
+ {{video.index}} + +

{{video.title}}

+

{{video.channelName}}

+
+
+
+
Show Comments (Max of 100)
diff --git a/src/templates/playlistView.html b/src/templates/playlistView.html index db64c716c..66a3a3a36 100644 --- a/src/templates/playlistView.html +++ b/src/templates/playlistView.html @@ -25,7 +25,7 @@

{{videoCount}} videos - {{viewCount}} views - Last updated on {{lastUpdated}}


-
+

{{channelName}}

diff --git a/src/templates/videoTemplate.html b/src/templates/videoTemplate.html index 45d28af35..cee2b2789 100644 --- a/src/templates/videoTemplate.html +++ b/src/templates/videoTemplate.html @@ -36,7 +36,7 @@
-
+
{{video.videoCount}}