85 lines
2.6 KiB
TypeScript
85 lines
2.6 KiB
TypeScript
'use strict'
|
|
|
|
import { youtube_v3 } from 'googleapis'
|
|
import { Context, Service, ServiceBroker, ServiceSchema } from 'moleculer'
|
|
import GoogleServices from '../mixins/google.mixin'
|
|
import { FeedResponse, FeedResult } from '../types/feed'
|
|
import { ApiMeta } from '../types/meta'
|
|
|
|
export default class YoutubeService extends Service {
|
|
private google = new GoogleServices().google
|
|
private channels: [channel: string, id: string][] = [
|
|
['Red Plateaus', 'UCsln1E-ttrNPsMivrnf9V7w'],
|
|
['Zoe Baker', 'UC3FD64RRsrCLpiZNkq7ZkSg'],
|
|
['Jonas Ceika,', 'UCSkzHxIcfoEr69MWBdo0ppg'],
|
|
['Radical Reviewer', 'UC_V9wKk1Dd2rpZ4fxj7pKXA'],
|
|
['donoteat01', 'UCFdazs-6CNzSVv1J0a-qy4A'],
|
|
['Contra', 'UCNvsIonJdJ5E4EXMa65VYpA'],
|
|
['Shaun', 'UCJ6o36XL0CpYb6U5dNBiXHQ'],
|
|
['hbomb', 'UClt01z1wHHT7c5lKcU8pxRQ'],
|
|
['Philo tube', 'UC2PA-AKmVpU6NKCGtZq_rKQ'],
|
|
['anark', 'UC1CjJYTUeor8EUFsbgwu5TQ']
|
|
]
|
|
|
|
// @ts-ignore
|
|
public constructor (public broker: ServiceBroker, schema: ServiceSchema<{}> = {}) {
|
|
super(broker)
|
|
|
|
this.parseServiceSchema(Service.mergeSchemas({
|
|
name: 'youtube',
|
|
actions: {
|
|
/**
|
|
* Get aggregate feed
|
|
*
|
|
*/
|
|
feed: {
|
|
cache: true,
|
|
rest: {
|
|
method: 'GET',
|
|
path: '/feed',
|
|
|
|
},
|
|
async handler (this: YoutubeService, ctx: Context<{}, ApiMeta>): Promise<FeedResponse> {
|
|
return this.GetAggregatedFeed()
|
|
}
|
|
}
|
|
}
|
|
}, schema))
|
|
}
|
|
|
|
public async GetAggregatedFeed (): Promise<FeedResponse> {
|
|
const onlyVideos = (item: youtube_v3.Schema$Activity) => item.snippet.type === 'upload'
|
|
|
|
return (await Promise.all(
|
|
this.channels.map(([channel, id]) => this.GetActivities(id))
|
|
))
|
|
.flatMap(response => response.data.items)
|
|
.filter(onlyVideos)
|
|
.map(item => this.PickActivityProperties(item))
|
|
}
|
|
|
|
private GetActivities (channelId: string) {
|
|
return this.google.youtube('v3').activities.list({
|
|
channelId,
|
|
part: ['snippet', 'contentDetails'],
|
|
maxResults: 1000
|
|
})
|
|
}
|
|
|
|
private PickBestThumbnail (thumbnails: youtube_v3.Schema$ThumbnailDetails) {
|
|
return String(Object.values(thumbnails).sort((a, b) => b.width - a.width)[0].url).split('/').pop()
|
|
/* https://i.ytimg.com/vi/${id}/${thumbnail} */
|
|
}
|
|
|
|
private PickActivityProperties (activity: youtube_v3.Schema$Activity): FeedResult {
|
|
return {
|
|
title: activity.snippet.title,
|
|
id: activity.contentDetails.upload.videoId,
|
|
description: activity.snippet.description?.substring(0, 127).split('\n')[0],
|
|
thumbnail: this.PickBestThumbnail(activity.snippet.thumbnails),
|
|
channel: activity.snippet.channelId,
|
|
date: new Date(activity.snippet.publishedAt).valueOf()
|
|
}
|
|
}
|
|
}
|