Browse Source

feat: added job to get missing YouTube channels, and improved YouTube channel data

Kristian Vos 2 years ago
parent
commit
ba290c4fec

+ 1 - 0
backend/logic/actions/apis.js

@@ -768,6 +768,7 @@ export default {
 			page === "punishments" ||
 			page === "youtube" ||
 			page === "youtubeVideos" ||
+			page === "youtubeChannels" ||
 			page === "soundcloud" ||
 			page === "soundcloudTracks" ||
 			page === "import" ||

+ 2 - 1
backend/logic/db/schemas/youtubeChannel.js

@@ -1,8 +1,9 @@
 export default {
 	channelId: { type: String, required: true, index: true, unique: true },
 	title: { type: String, trim: true, required: true },
-	customUrl: { type: String, trim: true, required: true },
+	customUrl: { type: String, trim: true },
 	rawData: { type: Object },
 	createdAt: { type: Date, default: Date.now, required: true },
+	updatedAt: { type: Date, default: Date.now, required: true },
 	documentVersion: { type: Number, default: 1, required: true }
 };

+ 1 - 0
backend/logic/hooks/hasPermission.js

@@ -36,6 +36,7 @@ permissions.moderator = {
 	"admin.view.stations": true,
 	"admin.view.users": true,
 	"admin.view.youtubeVideos": true,
+	"admin.view.youtubeChannels": true,
 	"admin.view.soundcloudTracks": true,
 	"apis.searchDiscogs": true,
 	"news.create": true,

+ 110 - 0
backend/logic/youtube.js

@@ -117,6 +117,10 @@ class _YouTubeModule extends CoreClass {
 			modelName: "youtubeVideo"
 		});
 
+		this.youtubeChannelModel = this.YoutubeChannelModel = await DBModule.runJob("GET_MODEL", {
+			modelName: "youtubeChannel"
+		});
+
 		return new Promise(resolve => {
 			CacheModule.runJob("SUB", {
 				channel: "youtube.removeYoutubeApiRequest",
@@ -1497,6 +1501,85 @@ class _YouTubeModule extends CoreClass {
 		return { videos: newVideos };
 	}
 
+	/**
+	 * Get YouTube channels
+	 *
+	 * @param {object} payload - an object containing the payload
+	 * @param {string} payload.channelIds - an array of YouTube channel id's
+	 * @returns {Promise} - returns a promise (resolve, reject)
+	 */
+	async GET_CHANNELS_FROM_IDS(payload) {
+		const getChannels = async channelIds => {
+			const jobsToRun = [];
+
+			const chunkSize = 50;
+			while (channelIds.length > 0) {
+				const chunkedChannelIds = channelIds.splice(0, chunkSize);
+
+				const params = {
+					part: [
+						"brandingSettings",
+						"contentDetails",
+						"contentOwnerDetails",
+						"id",
+						"localizations",
+						"snippet",
+						"statistics",
+						"status",
+						"topicDetails"
+					].join(","),
+					id: chunkedChannelIds.join(",")
+				};
+
+				jobsToRun.push(YouTubeModule.runJob("API_GET_CHANNELS", { params }, this));
+			}
+
+			const jobResponses = await Promise.all(jobsToRun);
+
+			console.log(jobResponses);
+
+			return jobResponses
+				.map(jobResponse => jobResponse.response.data.items)
+				.flat()
+				.map(item => {
+					const youtubeChannel = {
+						channelId: item.id,
+						title: item.snippet.title,
+						customUrl: item.snippet.customUrl,
+						rawData: item
+					};
+
+					return youtubeChannel;
+				});
+		};
+
+		const { channelIds } = payload;
+		console.log(channelIds);
+
+		const existingChannels = (await YouTubeModule.youtubeChannelModel.find({ channelId: channelIds })).map(
+			channel => channel._doc
+		);
+		console.log(existingChannels);
+
+		const existingChannelIds = existingChannels.map(existingChannel => existingChannel.channelId);
+		const existingChannelObjectIds = existingChannels.map(existingChannel => existingChannel._id.toString());
+		console.log(existingChannelIds, existingChannelObjectIds);
+
+		if (channelIds.length === existingChannels.length) return { channels: existingChannels };
+
+		const missingChannelIds = channelIds.filter(channelId => existingChannelIds.indexOf(channelId) === -1);
+
+		console.log(missingChannelIds);
+
+		if (missingChannelIds.length === 0) return { videos: existingChannels };
+
+		const newChannels = await getChannels(missingChannelIds);
+
+		await YouTubeModule.youtubeChannelModel.insertMany(newChannels);
+
+		return { channels: existingChannels.concat(newChannels) };
+	}
+
 	/**
 	 * Remove YouTube videos
 	 *
@@ -1788,6 +1871,33 @@ class _YouTubeModule extends CoreClass {
 			v2
 		};
 	}
+
+	/**
+	 * Gets missing YouTube channels based on cached YouTube video's
+	 *
+	 * @returns {Promise} - returns a promise (resolve, reject)
+	 */
+	async GET_MISSING_CHANNELS() {
+		const currentChannelIds = await YouTubeModule.youtubeChannelModel.distinct("channelId");
+		const videoChannelIds = await YouTubeModule.youtubeVideoModel.distinct("rawData.snippet.channelId");
+
+		const missingChannelIds = videoChannelIds.filter(channelId => currentChannelIds.indexOf(channelId) === -1);
+
+		console.log(currentChannelIds);
+		console.log(videoChannelIds);
+		console.log(currentChannelIds.length, videoChannelIds.length);
+
+		const res = await YouTubeModule.runJob("GET_CHANNELS_FROM_IDS", { channelIds: missingChannelIds }, this);
+
+		const gotChannels = res.channels;
+
+		return {
+			current: currentChannelIds.length,
+			all: videoChannelIds.length,
+			missing: missingChannelIds.length,
+			got: gotChannels.length
+		};
+	}
 }
 
 export default new _YouTubeModule();

+ 7 - 1
frontend/src/pages/Admin/YouTube/Channels.vue

@@ -85,6 +85,12 @@ const columns = ref<TableColumn[]>([
 		minWidth: 215,
 		defaultWidth: 215
 	},
+	{
+		name: "title",
+		displayName: "Title",
+		properties: ["title"],
+		sortProperty: "title"
+	},
 	{
 		name: "custom_url",
 		displayName: "Custom URL",
@@ -330,7 +336,7 @@ const { openModal } = useModalsStore();
 			</template> -->
 			<template #column-channelId="slotProps">
 				<a
-					:href="`https://www.youtube.com/${slotProps.item.channelId}`"
+					:href="`https://www.youtube.com/channels/${slotProps.item.channelId}`"
 					target="_blank"
 				>
 					{{ slotProps.item.channelId }}