2018-03-02 04:48:12 +01:00
|
|
|
/*
|
|
|
|
This file is part of FreeTube.
|
|
|
|
|
|
|
|
FreeTube is free software: you can redistribute it and/or modify
|
|
|
|
it under the terms of the GNU General Public License as published by
|
|
|
|
the Free Software Foundation, either version 3 of the License, or
|
|
|
|
(at your option) any later version.
|
|
|
|
|
|
|
|
FreeTube is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
GNU General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
|
|
along with FreeTube. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Perform a search using the YouTube API. The search query is grabbed from the #search element.
|
|
|
|
*
|
|
|
|
* @param {string} nextPageToken - Optional: The page token to be inlcuded in the search.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function search(nextPageToken = '') {
|
|
|
|
const query = document.getElementById('search').value;
|
|
|
|
|
|
|
|
if (query === '') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (nextPageToken === '') {
|
|
|
|
clearMainContainer();
|
2018-03-10 22:03:32 +01:00
|
|
|
startLoadingAnimation();
|
2018-03-02 04:48:12 +01:00
|
|
|
} else {
|
|
|
|
console.log(nextPageToken);
|
|
|
|
showToast('Fetching results. Please wait...');
|
|
|
|
}
|
|
|
|
|
2018-03-10 22:03:32 +01:00
|
|
|
youtubeAPI('search', {
|
2018-03-02 04:48:12 +01:00
|
|
|
q: query,
|
2018-03-15 15:59:50 +01:00
|
|
|
part: 'id',
|
2018-03-02 04:48:12 +01:00
|
|
|
pageToken: nextPageToken,
|
|
|
|
maxResults: 25,
|
2018-04-09 03:04:41 +02:00
|
|
|
}, function(data) {
|
|
|
|
console.log(data);
|
|
|
|
|
|
|
|
let channels = data.items.filter((item) => {
|
|
|
|
if (item.id.kind === 'youtube#channel') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let playlists = data.items.filter((item) => {
|
|
|
|
if (item.id.kind === 'youtube#playlist') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let videos = data.items.filter((item) => {
|
|
|
|
if (item.id.kind === 'youtube#video') {
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log(channels);
|
|
|
|
console.log(typeof(channels));
|
|
|
|
console.log(playlists);
|
|
|
|
|
|
|
|
if(playlists.length > 0){
|
2018-06-02 00:17:33 +02:00
|
|
|
//displayPlaylists(playlists);
|
2018-04-09 03:04:41 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if(channels.length > 0){
|
|
|
|
displayChannels(channels);
|
|
|
|
}
|
|
|
|
|
|
|
|
let grabDuration = getDuration(videos);
|
2018-03-15 15:59:50 +01:00
|
|
|
|
|
|
|
grabDuration.then((videoList) => {
|
2018-04-09 03:04:41 +02:00
|
|
|
console.log(videoList);
|
2018-03-15 15:59:50 +01:00
|
|
|
videoList.items.forEach(displayVideo);
|
|
|
|
});
|
|
|
|
|
2018-03-02 04:48:12 +01:00
|
|
|
if (nextPageToken === '') {
|
2018-03-13 00:37:30 +01:00
|
|
|
createVideoListContainer('Search results:');
|
2018-03-10 22:03:32 +01:00
|
|
|
stopLoadingAnimation();
|
2018-03-02 04:48:12 +01:00
|
|
|
}
|
2018-03-12 02:30:43 +01:00
|
|
|
addNextPage(data.nextPageToken);
|
2018-03-10 22:03:32 +01:00
|
|
|
})
|
2018-03-02 04:48:12 +01:00
|
|
|
}
|
|
|
|
|
2018-03-15 15:59:50 +01:00
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Grab the duration of the videos
|
|
|
|
*
|
|
|
|
* @param {array} data - An array of videos to get the duration from
|
|
|
|
*
|
|
|
|
* @return {promise} - The list of videos with the duration included.
|
|
|
|
*/
|
|
|
|
function getDuration(data) {
|
2018-03-15 15:59:50 +01:00
|
|
|
return new Promise((resolve, reject) => {
|
|
|
|
let videoIdList = '';
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
for (let i = 0; i < data.length; i++) {
|
|
|
|
if (videoIdList === '') {
|
|
|
|
if (typeof(data[i]['id']) === 'string') {
|
2018-03-15 15:59:50 +01:00
|
|
|
videoIdList = data[i]['id'];
|
2018-04-09 03:04:41 +02:00
|
|
|
} else {
|
2018-03-15 15:59:50 +01:00
|
|
|
videoIdList = data[i]['id']['videoId'];
|
|
|
|
}
|
2018-04-09 03:04:41 +02:00
|
|
|
} else {
|
|
|
|
if (typeof(data[i]['id']) === 'string') {
|
2018-03-15 15:59:50 +01:00
|
|
|
videoIdList = videoIdList + ', ' + data[i]['id'];
|
2018-04-09 03:04:41 +02:00
|
|
|
} else {
|
2018-03-15 15:59:50 +01:00
|
|
|
videoIdList = videoIdList + ', ' + data[i]['id']['videoId'];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
youtubeAPI('videos', {
|
|
|
|
part: 'snippet, contentDetails',
|
|
|
|
id: videoIdList
|
|
|
|
}, (data) => {
|
|
|
|
resolve(data);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-02 04:48:12 +01:00
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Display a video on the page. Function is typically contained in a loop.
|
|
|
|
*
|
|
|
|
* @param {video} video - The video ID of the video to be displayed.
|
|
|
|
* @param {string} listType - Optional: Specifies the list type of the video
|
|
|
|
* Used for displaying the remove icon for history and saved videos.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-03-15 01:09:09 +01:00
|
|
|
function displayVideo(video, listType = '') {
|
2018-03-13 00:37:30 +01:00
|
|
|
const videoSnippet = video.snippet;
|
2018-03-15 15:59:50 +01:00
|
|
|
|
|
|
|
const videoDuration = parseVideoDuration(video.contentDetails.duration);
|
|
|
|
//const videoDuration = '00:00';
|
|
|
|
|
2018-03-11 19:15:54 +01:00
|
|
|
// Grab the published date for the video and convert to a user readable state.
|
2018-03-13 00:37:30 +01:00
|
|
|
const dateString = new Date(videoSnippet.publishedAt);
|
2018-03-11 19:15:54 +01:00
|
|
|
const publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
2018-03-15 15:59:50 +01:00
|
|
|
|
2018-03-11 19:15:54 +01:00
|
|
|
const searchMenu = $('#videoListContainer').html();
|
2018-03-15 01:09:09 +01:00
|
|
|
const videoId = video.id;
|
2018-03-11 19:15:54 +01:00
|
|
|
|
|
|
|
// Include a remove icon in the list if the application is displaying the history list or saved videos.
|
2018-03-15 01:09:09 +01:00
|
|
|
const deleteHtml = () => {
|
|
|
|
switch (listType) {
|
|
|
|
case 'saved':
|
2018-03-17 19:29:27 +01:00
|
|
|
return `<li onclick="removeSavedVideo('${videoId}'); showSavedVideos();">Remove Saved Video</li>`;
|
2018-03-15 01:09:09 +01:00
|
|
|
case 'history':
|
2018-03-17 19:29:27 +01:00
|
|
|
return `<li onclick="removeFromHistory('${videoId}'); showHistory();">Remove From History</li>`;
|
2018-03-15 01:09:09 +01:00
|
|
|
}
|
|
|
|
};
|
2018-03-11 19:15:54 +01:00
|
|
|
|
|
|
|
// Includes text if the video is live.
|
2018-04-09 03:04:41 +02:00
|
|
|
const liveText = (videoSnippet.liveBroadcastContent === 'live') ? 'LIVE NOW' : '';
|
2018-03-12 04:06:30 +01:00
|
|
|
const videoListTemplate = require('./templates/videoList.html');
|
2018-03-11 19:15:54 +01:00
|
|
|
|
|
|
|
mustache.parse(videoListTemplate);
|
|
|
|
const rendered = mustache.render(videoListTemplate, {
|
2018-03-13 00:37:30 +01:00
|
|
|
videoId: videoId,
|
2018-04-09 03:04:41 +02:00
|
|
|
videoThumbnail: videoSnippet.thumbnails.medium.url,
|
|
|
|
videoTitle: videoSnippet.title,
|
|
|
|
channelName: videoSnippet.channelTitle,
|
2018-03-13 00:37:30 +01:00
|
|
|
videoDescription: videoSnippet.description,
|
2018-04-09 03:04:41 +02:00
|
|
|
channelId: videoSnippet.channelId,
|
|
|
|
videoDuration: videoDuration,
|
2018-03-11 19:15:54 +01:00
|
|
|
publishedDate: publishedDate,
|
|
|
|
liveText: liveText,
|
|
|
|
deleteHtml: deleteHtml,
|
2018-03-02 04:48:12 +01:00
|
|
|
});
|
2018-03-15 01:09:09 +01:00
|
|
|
|
2018-03-11 19:15:54 +01:00
|
|
|
// Apply the render to the page
|
2018-03-15 01:09:09 +01:00
|
|
|
const nextButton = document.getElementById('getNextPage');
|
2018-03-11 19:15:54 +01:00
|
|
|
if (nextButton === null) {
|
|
|
|
$('#videoListContainer').append(rendered);
|
|
|
|
} else {
|
|
|
|
$(rendered).insertBefore('#getNextPage');
|
|
|
|
}
|
2018-03-02 04:48:12 +01:00
|
|
|
}
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
function displayChannels(channels) {
|
|
|
|
let channelIds;
|
|
|
|
|
|
|
|
channels.forEach((channel) => {
|
|
|
|
if (typeof(channelIds) === 'undefined') {
|
|
|
|
channelIds = channel.id.channelId;
|
|
|
|
} else {
|
|
|
|
channelIds = channelIds + ',' + channel.id.channelId;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log(channelIds);
|
|
|
|
|
|
|
|
youtubeAPI('channels', {
|
|
|
|
part: 'snippet,statistics',
|
|
|
|
id: channelIds,
|
|
|
|
}, function(data) {
|
|
|
|
console.log(data);
|
|
|
|
let items = data['items'].reverse();
|
|
|
|
const videoListTemplate = require('./templates/channelList.html');
|
|
|
|
|
|
|
|
console.log(items);
|
|
|
|
|
|
|
|
items.forEach((item) => {
|
|
|
|
mustache.parse(videoListTemplate);
|
|
|
|
let rendered = mustache.render(videoListTemplate, {
|
|
|
|
channelId: item.id,
|
|
|
|
channelThumbnail: item.snippet.thumbnails.medium.url,
|
|
|
|
channelName: item.snippet.title,
|
|
|
|
channelDescription: item.snippet.description,
|
|
|
|
subscriberCount: item.statistics.subscriberCount,
|
|
|
|
videoCount: item.statistics.videoCount,
|
|
|
|
});
|
|
|
|
|
|
|
|
$(rendered).insertBefore('#getNextPage');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
function displayPlaylists(playlists) {
|
|
|
|
let playlistIds;
|
|
|
|
|
|
|
|
playlists.forEach((playlist) => {
|
|
|
|
if (typeof(playlistIds) === 'undefined') {
|
|
|
|
playlistIds = playlist.id.playlistId;
|
|
|
|
} else {
|
|
|
|
playlistIds = playlistIds + ',' + playlist.id.playlistId;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
console.log(playlistIds);
|
|
|
|
|
|
|
|
youtubeAPI('playlists', {
|
|
|
|
part: 'snippet,contentDetails',
|
|
|
|
id: playlistIds,
|
|
|
|
}, function(data) {
|
|
|
|
console.log(data);
|
|
|
|
let items = data['items'].reverse();
|
|
|
|
const playlistListTemplate = require('./templates/playlistList.html');
|
|
|
|
|
|
|
|
console.log(items);
|
|
|
|
|
|
|
|
items.forEach((item) => {
|
|
|
|
let dateString = new Date(item.snippet.publishedAt);
|
|
|
|
let publishedDate = dateFormat(dateString, "mmm dS, yyyy");
|
|
|
|
|
|
|
|
mustache.parse(playlistListTemplate);
|
|
|
|
let rendered = mustache.render(playlistListTemplate, {
|
|
|
|
channelId: item.snippet.channelId,
|
|
|
|
channelName: item.snippet.channelTitle,
|
|
|
|
playlistThumbnail: item.snippet.thumbnails.medium.url,
|
|
|
|
playlistTitle: item.snippet.title,
|
|
|
|
playlistDescription: item.snippet.description,
|
|
|
|
videoCount: item.contentDetails.itemCount,
|
|
|
|
publishedDate: publishedDate,
|
|
|
|
});
|
|
|
|
|
|
|
|
$(rendered).insertBefore('#getNextPage');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-03-02 04:48:12 +01:00
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Changes the page token to the next page button during a video search.
|
|
|
|
*
|
|
|
|
* @param {string} nextPageToken - The page token to replace the button function.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function addNextPage(nextPageToken) {
|
|
|
|
let oldFetchButton = document.getElementById('getNextPage');
|
|
|
|
|
|
|
|
// Creates the element if it doesn't exist.
|
|
|
|
if (oldFetchButton === null) {
|
|
|
|
let fetchButton = document.createElement('div');
|
|
|
|
fetchButton.id = 'getNextPage';
|
|
|
|
fetchButton.innerHTML = '<i class="fas fa-search"></i> Fetch more results...';
|
|
|
|
|
|
|
|
$('#videoListContainer').append(fetchButton);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Update the on click method of the button.
|
|
|
|
$(document).off('click', '#getNextPage');
|
|
|
|
$(document).on('click', '#getNextPage', (event) => {
|
|
|
|
search(nextPageToken);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Grab the video recommendations for a video. This does not get recommendations based on what you watch,
|
|
|
|
* as that would defeat the main purpose of using FreeTube. At any time you can check the video on HookTube
|
|
|
|
* and compare the recommendations there. They should be nearly identical.
|
|
|
|
*
|
|
|
|
* @param {string} videoId - The video ID of the video to get recommendations from.
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function showVideoRecommendations(videoId) {
|
2018-03-10 22:03:32 +01:00
|
|
|
youtubeAPI('search', {
|
2018-03-15 15:59:50 +01:00
|
|
|
part: 'id',
|
2018-03-02 04:48:12 +01:00
|
|
|
type: 'video',
|
|
|
|
relatedToVideoId: videoId,
|
|
|
|
maxResults: 15,
|
2018-04-09 03:04:41 +02:00
|
|
|
}, function(data) {
|
2018-03-15 15:59:50 +01:00
|
|
|
let grabDuration = getDuration(data.items);
|
|
|
|
grabDuration.then((videoList) => {
|
|
|
|
videoList.items.forEach((video) => {
|
|
|
|
const snippet = video.snippet;
|
|
|
|
const videoDuration = parseVideoDuration(video.contentDetails.duration);
|
|
|
|
|
|
|
|
const recommTemplate = require('./templates/recommendations.html')
|
|
|
|
mustache.parse(recommTemplate);
|
|
|
|
const rendered = mustache.render(recommTemplate, {
|
|
|
|
videoId: video.id,
|
2018-04-09 03:04:41 +02:00
|
|
|
videoTitle: snippet.title,
|
|
|
|
channelName: snippet.channelTitle,
|
2018-03-15 15:59:50 +01:00
|
|
|
videoThumbnail: snippet.thumbnails.medium.url,
|
2018-04-09 03:04:41 +02:00
|
|
|
videoDuration: videoDuration,
|
2018-03-15 15:59:50 +01:00
|
|
|
publishedDate: dateFormat(snippet.publishedAt, "mmm dS, yyyy")
|
|
|
|
});
|
|
|
|
const recommendationHtml = $('#recommendations').html();
|
|
|
|
$('#recommendations').html(recommendationHtml + rendered);
|
2018-03-02 04:48:12 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Check if a link is a valid YouTube/HookTube link and play that video. Gets input
|
|
|
|
* from the #jumpToInput element.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-05-03 18:09:53 +02:00
|
|
|
function parseSearchText(url = '') {
|
|
|
|
let input;
|
|
|
|
|
|
|
|
if (url === ''){
|
|
|
|
input = document.getElementById('search').value;
|
|
|
|
}
|
|
|
|
else{
|
|
|
|
input = url;
|
|
|
|
}
|
2018-03-02 04:48:12 +01:00
|
|
|
|
|
|
|
if (input === '') {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// The regex to get the video id from a YouTube link. Thanks StackOverflow.
|
|
|
|
let rx = /^.*(?:(?:(you|hook)tu\.?be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
|
|
|
|
|
|
|
|
let match = input.match(rx);
|
|
|
|
|
|
|
|
console.log(match);
|
|
|
|
|
|
|
|
// Play video if a match is found.
|
|
|
|
try {
|
2018-05-03 18:09:53 +02:00
|
|
|
console.log('Match Found');
|
2018-03-02 04:48:12 +01:00
|
|
|
playVideo(match[2]);
|
|
|
|
} catch (err) {
|
2018-05-03 18:09:53 +02:00
|
|
|
console.log('Video not found');
|
|
|
|
search();
|
2018-03-02 04:48:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-03-15 15:59:50 +01:00
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Convert duration into a more readable format
|
|
|
|
*
|
|
|
|
* @param {string} durationString - The string containing the video duration. Formated as 'PT12H34M56S'
|
|
|
|
*
|
|
|
|
* @return {string} - The formated string. Ex: 12:34:56
|
|
|
|
*/
|
|
|
|
function parseVideoDuration(durationString) {
|
2018-03-15 15:59:50 +01:00
|
|
|
let match = durationString.match(/PT(\d+H)?(\d+M)?(\d+S)?/);
|
|
|
|
let duration = '';
|
|
|
|
|
|
|
|
match = match.slice(1).map(function(x) {
|
|
|
|
if (x != null) {
|
2018-04-09 03:04:41 +02:00
|
|
|
return x.replace(/\D/, '');
|
2018-03-15 15:59:50 +01:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
let hours = (parseInt(match[0]) || 0);
|
|
|
|
let minutes = (parseInt(match[1]) || 0);
|
|
|
|
let seconds = (parseInt(match[2]) || 0);
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
if (hours != 0) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = hours + ':';
|
2018-04-09 03:04:41 +02:00
|
|
|
} else {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = minutes + ':';
|
|
|
|
}
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
if (hours != 0 && minutes < 10) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + '0' + minutes + ':';
|
2018-04-09 03:04:41 +02:00
|
|
|
} else if (hours != 0 && minutes > 10) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + minutes + ':';
|
2018-04-09 03:04:41 +02:00
|
|
|
} else if (hours != 0 && minutes == 0) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + '00:';
|
|
|
|
}
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
if (seconds == 0) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + '00';
|
2018-04-09 03:04:41 +02:00
|
|
|
} else if (seconds < 10) {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + '0' + seconds;
|
2018-04-09 03:04:41 +02:00
|
|
|
} else {
|
2018-03-15 15:59:50 +01:00
|
|
|
duration = duration + seconds;
|
|
|
|
}
|
|
|
|
|
|
|
|
return duration;
|
|
|
|
}
|
|
|
|
|
2018-03-02 04:48:12 +01:00
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Grab the most popular videos over the last couple of days and display them.
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function showMostPopular() {
|
|
|
|
clearMainContainer();
|
2018-03-10 22:03:32 +01:00
|
|
|
startLoadingAnimation();
|
2018-03-02 04:48:12 +01:00
|
|
|
|
|
|
|
// Get the date of 2 days ago.
|
|
|
|
var d = new Date();
|
|
|
|
d.setDate(d.getDate() - 2);
|
|
|
|
|
|
|
|
// Grab all videos published 2 days ago and after and order them by view count.
|
|
|
|
// These are the videos that are considered as 'most popular' and is how similar
|
|
|
|
// Applications grab these. Videos in the 'Trending' tab on YouTube will be different.
|
|
|
|
// And there is no way to grab those videos.
|
2018-03-10 22:03:32 +01:00
|
|
|
youtubeAPI('search', {
|
2018-03-15 15:59:50 +01:00
|
|
|
part: 'id',
|
2018-03-02 04:48:12 +01:00
|
|
|
order: 'viewCount',
|
|
|
|
type: 'video',
|
|
|
|
publishedAfter: d.toISOString(),
|
|
|
|
maxResults: 50,
|
2018-04-09 03:04:41 +02:00
|
|
|
}, function(data) {
|
2018-03-02 04:48:12 +01:00
|
|
|
createVideoListContainer('Most Popular:');
|
2018-03-15 15:59:50 +01:00
|
|
|
console.log(data);
|
|
|
|
let grabDuration = getDuration(data.items);
|
|
|
|
|
|
|
|
grabDuration.then((videoList) => {
|
|
|
|
console.log(videoList);
|
|
|
|
videoList.items.forEach(displayVideo);
|
|
|
|
});
|
2018-03-10 22:03:32 +01:00
|
|
|
stopLoadingAnimation();
|
2018-03-02 04:48:12 +01:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Create a link of the video to HookTube or YouTube and copy it to the user's clipboard.
|
|
|
|
*
|
|
|
|
* @param {string} website - The website to watch the video on.
|
|
|
|
* @param {string} videoId - The video ID of the video to add to the URL
|
|
|
|
*
|
|
|
|
* @return {Void}
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function copyLink(website, videoId) {
|
|
|
|
// Create the URL and copy to the clipboard.
|
|
|
|
const url = 'https://' + website + '.com/watch?v=' + videoId;
|
|
|
|
clipboard.writeText(url);
|
|
|
|
showToast('URL has been copied to the clipboard');
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Get the YouTube embeded player of a video as well as channel information..
|
|
|
|
*
|
|
|
|
* @param {string} videoId - The video ID of the video to get.
|
|
|
|
*
|
|
|
|
* @return {promise} - The HTML of the embeded player
|
|
|
|
*/
|
2018-03-08 02:19:03 +01:00
|
|
|
function getChannelAndPlayer(videoId) {
|
2018-03-02 04:48:12 +01:00
|
|
|
console.log(videoId);
|
|
|
|
return new Promise((resolve, reject) => {
|
2018-03-10 22:03:32 +01:00
|
|
|
youtubeAPI('videos', {
|
|
|
|
part: 'snippet,player',
|
2018-03-02 04:48:12 +01:00
|
|
|
id: videoId,
|
2018-04-09 03:04:41 +02:00
|
|
|
}, function(data) {
|
2018-03-10 22:03:32 +01:00
|
|
|
let embedHtml = data.items[0].player.embedHtml;
|
2018-03-02 04:48:12 +01:00
|
|
|
embedHtml = embedHtml.replace('src="', 'src="https:');
|
|
|
|
embedHtml = embedHtml.replace('width="480px"', '');
|
|
|
|
embedHtml = embedHtml.replace('height="270px"', '');
|
|
|
|
embedHtml = embedHtml.replace(/\"/g, '"');
|
2018-03-10 22:03:32 +01:00
|
|
|
resolve([embedHtml, data.items[0].snippet.channelId]);
|
2018-03-02 04:48:12 +01:00
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2018-04-09 03:04:41 +02:00
|
|
|
* Check to see if the video URLs are valid. Change the video quality if one is not.
|
|
|
|
* The API will grab video URLs, but they will sometimes return a 404. This
|
|
|
|
* is why this check is needed. The video URL will typically be resolved over time.
|
|
|
|
*
|
|
|
|
* @param {string} video480p - The URL to the 480p video.
|
|
|
|
* @param {string} video720p - The URL to the 720p video.
|
|
|
|
*/
|
2018-03-02 04:48:12 +01:00
|
|
|
function checkVideoUrls(video480p, video720p) {
|
|
|
|
const currentQuality = $('#currentQuality').html();
|
|
|
|
let buttonEmbed = document.getElementById('qualityEmbed');
|
|
|
|
|
|
|
|
let valid480 = false;
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
if (typeof(video480p) !== 'undefined') {
|
2018-03-02 04:48:12 +01:00
|
|
|
let get480pUrl = fetch(video480p);
|
|
|
|
get480pUrl.then((status) => {
|
|
|
|
switch (status.status) {
|
|
|
|
case 404:
|
|
|
|
showToast('Found valid URL for 480p, but returned a 404. Video type might be available in the future.');
|
|
|
|
$(document).off('click', '#quality480p');
|
|
|
|
$(document).on('click', '#quality480p', (event) => {
|
|
|
|
changeQuality('');
|
|
|
|
});
|
|
|
|
buttonEmbed.click();
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
case 403:
|
|
|
|
showToast('This video is unavailable in your country.');
|
|
|
|
$(document).off('click', '#quality480p');
|
|
|
|
$(document).on('click', '#quality480p', (event) => {
|
|
|
|
changeQuality('');
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.log('480p is valid');
|
2018-04-09 03:04:41 +02:00
|
|
|
if (currentQuality === '720p' && typeof(video720p) === 'undefined') {
|
2018-03-02 04:48:12 +01:00
|
|
|
changeQuality(video480p);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2018-04-09 03:04:41 +02:00
|
|
|
if (typeof(video720p) !== 'undefined') {
|
2018-03-02 04:48:12 +01:00
|
|
|
let get720pUrl = fetch(video720p);
|
|
|
|
get720pUrl.then((status) => {
|
|
|
|
switch (status.status) {
|
|
|
|
case 404:
|
|
|
|
showToast('Found valid URL for 720p, but returned a 404. Video type might be available in the future.');
|
|
|
|
$(document).off('click', '#quality720p');
|
|
|
|
$(document).on('click', '#quality720p', (event) => {
|
|
|
|
changeQuality('');
|
|
|
|
});
|
2018-04-09 03:04:41 +02:00
|
|
|
if (typeof(valid480) !== 'undefined') {
|
2018-03-02 04:48:12 +01:00
|
|
|
changeQuality(video480p, '480p');
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
case 403:
|
|
|
|
showToast('This video is unavailable in your country.');
|
|
|
|
$(document).off('click', '#quality720p');
|
|
|
|
$(document).on('click', '#quality720p', (event) => {
|
|
|
|
changeQuality('');
|
|
|
|
});
|
|
|
|
return;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
console.log('720p is valid');
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|