Skip to content

Commit

Permalink
[Youtube] Added channel view count and subscriber count badges (#6333)
Browse files Browse the repository at this point in the history
Co-authored-by: Pierre-Yves B <PyvesDev@gmail.com>
  • Loading branch information
tarun7singh and PyvesB committed Apr 5, 2021
1 parent a67ea4b commit f037952
Show file tree
Hide file tree
Showing 11 changed files with 175 additions and 50 deletions.
57 changes: 38 additions & 19 deletions services/youtube/youtube-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,26 @@ const documentation = `
<code>https://www.youtube.com/t/terms</code></p>`

const schema = Joi.object({
items: Joi.array()
.items(
Joi.object({
statistics: Joi.object({
pageInfo: Joi.object({
totalResults: nonNegativeInteger,
resultsPerPage: nonNegativeInteger,
}).required(),
items: Joi.array().items(
Joi.object({
statistics: Joi.alternatives(
Joi.object({
viewCount: nonNegativeInteger,
likeCount: nonNegativeInteger,
dislikeCount: nonNegativeInteger,
commentCount: nonNegativeInteger,
}).required(),
})
)
.required(),
}),
Joi.object({
viewCount: nonNegativeInteger,
subscriberCount: nonNegativeInteger,
})
),
})
),
}).required()

class YouTubeBase extends BaseJsonService {
Expand All @@ -39,38 +47,49 @@ class YouTubeBase extends BaseJsonService {
namedLogo: 'youtube',
}

static renderSingleStat({ statistics, statisticName, videoId }) {
static renderSingleStat({ statistics, statisticName, id }) {
return {
label: `${statisticName}s`,
message: metric(statistics[`${statisticName}Count`]),
style: 'social',
link: `https://www.youtube.com/watch?v=${encodeURIComponent(videoId)}`,
link: `https://www.youtube.com/${this.type}/${encodeURIComponent(id)}`,
}
}

async fetch({ videoId }) {
async fetch({ id }) {
return this._requestJson(
this.authHelper.withQueryStringAuth(
{ passKey: 'key' },
{
schema,
url: 'https://www.googleapis.com/youtube/v3/videos',
url: `https://www.googleapis.com/youtube/v3/${this.constructor.type}s`,
options: {
qs: { id: videoId, part: 'statistics' },
qs: { id, part: 'statistics' },
},
}
)
)
}

async handle({ videoId }, queryParams) {
const json = await this.fetch({ videoId })
if (json.items.length === 0) {
throw new NotFound({ prettyMessage: 'video not found' })
async handle({ channelId, videoId }, queryParams) {
const id = channelId || videoId
const json = await this.fetch({ id })
if (json.pageInfo.totalResults === 0) {
throw new NotFound({
prettyMessage: `${this.constructor.type} not found`,
})
}
const statistics = json.items[0].statistics
return this.constructor.render({ statistics, videoId }, queryParams)
return this.constructor.render({ statistics, id }, queryParams)
}
}

module.exports = { documentation, YouTubeBase }
class YouTubeVideoBase extends YouTubeBase {
static type = 'video'
}

class YouTubeChannelBase extends YouTubeBase {
static type = 'channel'
}

module.exports = { documentation, YouTubeVideoBase, YouTubeChannelBase }
31 changes: 31 additions & 0 deletions services/youtube/youtube-channel-views.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
'use strict'

const { documentation, YouTubeChannelBase } = require('./youtube-base')

module.exports = class YouTubeChannelViews extends YouTubeChannelBase {
static route = {
base: 'youtube/channel/views',
pattern: ':channelId',
}

static get examples() {
const preview = this.render({
statistics: { viewCount: 30543 },
id: 'UC8butISFwT-Wl7EV0hUK0BQ',
})
// link[] is not allowed in examples
delete preview.link
return [
{
title: 'YouTube Channel Views',
namedParams: { channelId: 'UC8butISFwT-Wl7EV0hUK0BQ' },
staticPreview: preview,
documentation,
},
]
}

static render({ statistics, id }) {
return super.renderSingleStat({ statistics, statisticName: 'view', id })
}
}
25 changes: 25 additions & 0 deletions services/youtube/youtube-channel-views.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

const t = (module.exports = require('../tester').createServiceTester())
const { noToken } = require('../test-helpers')
const { isMetric } = require('../test-validators')
const noYouTubeToken = noToken(require('./youtube-channel-views.service'))

t.create('channel view count')
.skipWhen(noYouTubeToken)
.get('/UC8butISFwT-Wl7EV0hUK0BQ.json')
.expectBadge({
label: 'views',
message: isMetric,
color: 'red',
link: ['https://www.youtube.com/channel/UC8butISFwT-Wl7EV0hUK0BQ'],
})

t.create('channel not found')
.skipWhen(noYouTubeToken)
.get('/doesnotexist.json')
.expectBadge({
label: 'youtube',
message: 'channel not found',
color: 'red',
})
14 changes: 5 additions & 9 deletions services/youtube/youtube-comments.service.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'

const { documentation, YouTubeBase } = require('./youtube-base')
const { documentation, YouTubeVideoBase } = require('./youtube-base')

module.exports = class YouTubeComments extends YouTubeBase {
module.exports = class YouTubeComments extends YouTubeVideoBase {
static route = {
base: 'youtube/comments',
pattern: ':videoId',
Expand All @@ -11,7 +11,7 @@ module.exports = class YouTubeComments extends YouTubeBase {
static get examples() {
const preview = this.render({
statistics: { commentCount: 209 },
videoId: 'wGJHwc5ksMA',
id: 'wGJHwc5ksMA',
})
// link[] is not allowed in examples
delete preview.link
Expand All @@ -25,11 +25,7 @@ module.exports = class YouTubeComments extends YouTubeBase {
]
}

static render({ statistics, videoId }) {
return super.renderSingleStat({
statistics,
statisticName: 'comment',
videoId,
})
static render({ statistics, id }) {
return super.renderSingleStat({ statistics, statisticName: 'comment', id })
}
}
2 changes: 1 addition & 1 deletion services/youtube/youtube-comments.tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ t.create('video comment count')
label: 'comments',
message: isMetric,
color: 'red',
link: ['https://www.youtube.com/watch?v=wGJHwc5ksMA'],
link: ['https://www.youtube.com/video/wGJHwc5ksMA'],
})

t.create('video not found')
Expand Down
16 changes: 7 additions & 9 deletions services/youtube/youtube-likes.service.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

const Joi = require('joi')
const { metric } = require('../text-formatters')
const { documentation, YouTubeBase } = require('./youtube-base')
const { documentation, YouTubeVideoBase } = require('./youtube-base')

const documentationWithDislikes = `
${documentation}
Expand All @@ -16,7 +16,7 @@ const queryParamSchema = Joi.object({
withDislikes: Joi.equal(''),
}).required()

module.exports = class YouTubeLikes extends YouTubeBase {
module.exports = class YouTubeLikes extends YouTubeVideoBase {
static route = {
base: 'youtube/likes',
pattern: ':videoId',
Expand All @@ -26,16 +26,14 @@ module.exports = class YouTubeLikes extends YouTubeBase {
static get examples() {
const previewLikes = this.render({
statistics: { likeCount: 7 },
videoId: 'abBdk8bSPKU',
id: 'abBdk8bSPKU',
})
const previewVotes = this.render(
{
statistics: { likeCount: 10236, dislikeCount: 396 },
videoId: 'pU9Q6oiQNd0',
id: 'pU9Q6oiQNd0',
},
{
withDislikes: '',
}
{ withDislikes: '' }
)
// link[] is not allowed in examples
delete previewLikes.link
Expand All @@ -59,11 +57,11 @@ module.exports = class YouTubeLikes extends YouTubeBase {
]
}

static render({ statistics, videoId }, queryParams) {
static render({ statistics, id }, queryParams) {
let renderedBadge = super.renderSingleStat({
statistics,
statisticName: 'like',
videoId,
id,
})
if (queryParams && typeof queryParams.withDislikes !== 'undefined') {
renderedBadge = {
Expand Down
4 changes: 2 additions & 2 deletions services/youtube/youtube-likes.tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ t.create('video like count')
label: 'likes',
message: isMetric,
color: 'red',
link: ['https://www.youtube.com/watch?v=pU9Q6oiQNd0'],
link: ['https://www.youtube.com/video/pU9Q6oiQNd0'],
})

t.create('video vote count')
Expand All @@ -25,7 +25,7 @@ t.create('video vote count')
/^([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY]) 👍 ([1-9][0-9]*[kMGTPEZY]?|[1-9]\.[1-9][kMGTPEZY]) 👎$/
),
color: 'red',
link: ['https://www.youtube.com/watch?v=pU9Q6oiQNd0'],
link: ['https://www.youtube.com/video/pU9Q6oiQNd0'],
})

t.create('video not found')
Expand Down
35 changes: 35 additions & 0 deletions services/youtube/youtube-subscribers.service.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
'use strict'

const { documentation, YouTubeChannelBase } = require('./youtube-base')

module.exports = class YouTubeSubscribes extends YouTubeChannelBase {
static route = {
base: 'youtube/channel/subscribers',
pattern: ':channelId',
}

static get examples() {
const preview = this.render({
statistics: { subscriberCount: 14577 },
id: 'UC8butISFwT-Wl7EV0hUK0BQ',
})
// link[] is not allowed in examples
delete preview.link
return [
{
title: 'YouTube Channel Subscribers',
namedParams: { channelId: 'UC8butISFwT-Wl7EV0hUK0BQ' },
staticPreview: preview,
documentation,
},
]
}

static render({ statistics, id }) {
return super.renderSingleStat({
statistics,
statisticName: 'subscriber',
id,
})
}
}
25 changes: 25 additions & 0 deletions services/youtube/youtube-subscribers.tester.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
'use strict'

const t = (module.exports = require('../tester').createServiceTester())
const { noToken } = require('../test-helpers')
const { isMetric } = require('../test-validators')
const noYouTubeToken = noToken(require('./youtube-subscribers.service'))

t.create('subscriber count')
.skipWhen(noYouTubeToken)
.get('/UC8butISFwT-Wl7EV0hUK0BQ.json')
.expectBadge({
label: 'subscribers',
message: isMetric,
color: 'red',
link: ['https://www.youtube.com/channel/UC8butISFwT-Wl7EV0hUK0BQ'],
})

t.create('channel not found')
.skipWhen(noYouTubeToken)
.get('/doesnotexist.json')
.expectBadge({
label: 'youtube',
message: 'channel not found',
color: 'red',
})
14 changes: 5 additions & 9 deletions services/youtube/youtube-views.service.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
'use strict'

const { documentation, YouTubeBase } = require('./youtube-base')
const { documentation, YouTubeVideoBase } = require('./youtube-base')

module.exports = class YouTubeViews extends YouTubeBase {
module.exports = class YouTubeViews extends YouTubeVideoBase {
static route = {
base: 'youtube/views',
pattern: ':videoId',
Expand All @@ -11,7 +11,7 @@ module.exports = class YouTubeViews extends YouTubeBase {
static get examples() {
const preview = this.render({
statistics: { viewCount: 14577 },
videoId: 'abBdk8bSPKU',
id: 'abBdk8bSPKU',
})
// link[] is not allowed in examples
delete preview.link
Expand All @@ -25,11 +25,7 @@ module.exports = class YouTubeViews extends YouTubeBase {
]
}

static render({ statistics, videoId }) {
return super.renderSingleStat({
statistics,
statisticName: 'view',
videoId,
})
static render({ statistics, id }) {
return super.renderSingleStat({ statistics, statisticName: 'view', id })
}
}
2 changes: 1 addition & 1 deletion services/youtube/youtube-views.tester.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ t.create('video view count')
label: 'views',
message: isMetric,
color: 'red',
link: ['https://www.youtube.com/watch?v=abBdk8bSPKU'],
link: ['https://www.youtube.com/video/abBdk8bSPKU'],
})

t.create('video not found')
Expand Down

0 comments on commit f037952

Please sign in to comment.