Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: auto schedule youtube stream #851

Closed
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 121 additions & 0 deletions .github/workflows/create-event-helpers/youtube/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
const path = require('path');
const {google} = require('googleapis');
const fetch = require('node-fetch');
const OAuth2 = google.auth.OAuth2;
const youtube = google.youtube('v3');

const CREDENTIALS = JSON.parse(process.env.GOOGLE_OAUTH_TOKEN); // token.json file contents
const CLIENT_SECRET = JSON.parse(process.env.GOOGLE_OAUTH_CLIENT_SECRET); // client_secret.json file contents

const OAUTH_CLIENT = new OAuth2(
CLIENT_SECRET.web.client_id,
CLIENT_SECRET.web.client_secret,
CLIENT_SECRET.web.redirect_uris[0]
);
OAUTH_CLIENT.credentials = CREDENTIALS;

module.exports = { scheduleLivestream };

/**
* Schedules a live stream with the parameters provided.
*
* @param {String} title Title
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

update jsdoc please

* @param {String} description Description
* @param {String} scheduledStartTime RFC3339 scheduled starting time
* @param {String} thumbnail Thumbnail URL (only supports PNG and JPG formats)
* @param {String} playlistId Playlist ID to add the stream to
*/
async function scheduleLivestream(scheduledStartTime, playlistId) {
try {
const title = process.env.MEETING_NAME;
const suffix = process.env.MEETING_NAME_SUFFIX;
const description = process.env.MEETING_DESC;
const banner = process.env.MEETING_BANNER;
const summary = suffix ? `${title} ${suffix}` : title;

const id = await _createNewBroadcast(summary, description, scheduledStartTime);
await Promise.all([
_addThumbnailToVideo(id, banner),
_addVideoToPlaylist(id, playlistId)
]);

} catch ( e ) {
console.log(e);
}
}

function _createNewBroadcast(title, description, startTime) {
return new Promise((resolve, reject) => {
youtube.liveBroadcasts.insert({
auth: OAUTH_CLIENT,
part: 'id,snippet,contentDetails,status',
requestBody: {
snippet: {
title,
description,
scheduledStartTime: startTime
},
status: {
privacyStatus: 'public',
selfDeclaredMadeForKids: false
}
}
}, (err, res) => {
if ( err ) {
reject(err);
} else {
resolve(res.data.id);
}
})
});
}

function _addThumbnailToVideo(videoId, thumbnailUri) {
return new Promise((resolve, reject) => {
const ext = path.extname(thumbnailUri);
const mimeType = (ext == 'png' ? 'image/png' : 'image/jpeg');

fetch(thumbnailUri).then(res => {
const thumbnailStream = res.body;

youtube.thumbnails.set({
auth: OAUTH_CLIENT,
videoId,
media: {
mimeType,
body: thumbnailStream
}
}, (err, res) => {
if ( err ) {
reject(err);
} else {
resolve();
}
});
});
});
}

function _addVideoToPlaylist(videoId, playlistId) {
return new Promise((resolve, reject) => {
youtube.playlistItems.insert({
auth: OAUTH_CLIENT,
part: 'contentDetails,id,snippet,status',
requestBody: {
snippet: {
playlistId,
resourceId: {
kind: 'youtube#video',
videoId
}
}
}
}, (err, res) => {
if ( err ) {
reject(err);
} else {
resolve();
}
})
});
}
16 changes: 16 additions & 0 deletions .github/workflows/create-event-workflow-reusable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,10 @@ on:
required: true
TWITTER_ACCESS_TOKEN_SECRET:
required: true
GOOGLE_OAUTH_TOKEN:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you will need to update all the workflows that start with create-event, like https://github.com/asyncapi/community/blob/master/.github/workflows/create-event-lets-talk-about.yml

you need to pass these 2 additional google secrets

required: true
GOOGLE_OAUTH_CLIENT_SECRET:
required: true

jobs:
setup-meeting:
Expand Down Expand Up @@ -155,3 +159,15 @@ jobs:
twitter_consumer_secret: ${{ secrets.TWITTER_CONSUMER_SECRET }}
twitter_access_token_key: ${{ secrets.TWITTER_ACCESS_TOKEN_KEY }}
twitter_access_token_secret: ${{ secrets.TWITTER_ACCESS_TOKEN_SECRET }}
- name: Schedule YouTube Livestream
uses: actions/github-script@v4
env:
MEETING_NAME: ${{ inputs.meeting_name }}
MEETING_NAME_SUFFIX: ${{ inputs.meeting_name_suffix }}
MEETING_DESC: ${{ inputs.meeting_desc }}
MEETING_BANNER: ${{ inputs.meeting_banner }}
GUEST: ${{ inputs.guest }}
with:
script: |
const { scheduleLivestream } = require('./.github/workflows/create-event-helpers/youtube/index.js');
scheduleLivestream('${{ inputs.date }}T${{ inputs.time }}:00Z', 'PLbi1gRlP7pijUwZJErzyYf_Rc-PWu4lXS');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

playlist id cannot be hardcoded here as there are different playlists per meeting

we need to be able to use it this way that for example in https://github.com/asyncapi/community/blob/master/.github/workflows/create-event-lets-talk-about.yml

I can do:

with:
    yt_playlist: PLbi1gRlP7pigPBrBMaNQhUeniR1pdDMiY

so here you need

Suggested change
scheduleLivestream('${{ inputs.date }}T${{ inputs.time }}:00Z', 'PLbi1gRlP7pijUwZJErzyYf_Rc-PWu4lXS');
scheduleLivestream('${{ inputs.date }}T${{ inputs.time }}:00Z', '${{ inputs.yt_playlist }}');