diff --git a/server/src/actions/set-title.js b/server/src/actions/set-title.js index 200d59ee..56323736 100644 --- a/server/src/actions/set-title.js +++ b/server/src/actions/set-title.js @@ -6,7 +6,6 @@ module.exports = { /*** * @param {ActionSuccessCallback} success * @param {ActionErrorCallback} error - * @param {PredictionAction} predictionAction * @param {number?} autoLockAfter * @param {ClientData} client * @param {CacheGetFunction} get @@ -15,8 +14,7 @@ module.exports = { * @returns {Promise} */ // eslint-disable-next-line no-empty-pattern - async handler(success, error, { predictionAction, autoLockAfter = 120 }, { client }, { get, auth }) { - + async handler(success, error, { }, { client }, { get, auth }) { const broadcast = await get(client?.broadcast?.[0]); if (!broadcast) return error("No broadcast associated"); if (!broadcast.channel) return error("No channel associated with broadcast"); diff --git a/server/src/actions/start-commercial.js b/server/src/actions/start-commercial.js new file mode 100644 index 00000000..7e7a9778 --- /dev/null +++ b/server/src/actions/start-commercial.js @@ -0,0 +1,44 @@ +const { ApiClient } = require("@twurple/api"); +const { StaticAuthProvider } = require("@twurple/auth"); +module.exports = { + key: "start-commercial", + auth: ["client"], + requiredParams: ["commercialDuration"], + /*** + * @param {ActionSuccessCallback} success + * @param {ActionErrorCallback} error + * @param {30 | 60 | 90 | 120 | 150 | 180} commercialDuration + * @param {ClientData} client + * @param {CacheGetFunction} get + * @param {CacheAuthFunctions} auth + * @param {SimpleUpdateRecord} updateRecord + * @returns {Promise} + */ + // eslint-disable-next-line no-empty-pattern + async handler(success, error, { commercialDuration }, { client, user }, { get, auth }) { + if (!user.airtable?.website_settings?.includes("Full broadcast permissions")) return error("You don't have permission to start a commercial", 403); + + const broadcast = await get(client?.broadcast?.[0]); + if (!broadcast) return error("No broadcast associated"); + if (!broadcast.channel) return error("No channel associated with broadcast"); + + const channel = await auth.getChannel(broadcast?.channel?.[0]); + if (!channel.twitch_refresh_token) return error("No twitch auth token associated with channel"); + if (!channel.channel_id || !channel.name || !channel.twitch_scopes) return error("Invalid channel data"); + let scopes = channel.twitch_scopes.split(" "); + if (!["channel:edit:commercial"].every(scope => scopes.includes(scope))) return error("Token doesn't have the required scopes"); + + const accessToken = await auth.getTwitchAccessToken(channel); + + const authProvider = new StaticAuthProvider(process.env.TWITCH_CLIENT_ID, accessToken); + const api = new ApiClient({authProvider}); + + try { + await api.channels.startChannelCommercial(channel.channel_id, commercialDuration); + } catch (e) { + console.log(e); + return error("Failed to start commercial"); + } + return success(); + } +}; diff --git a/website/src/components/website/dashboard/Commercials.vue b/website/src/components/website/dashboard/Commercials.vue new file mode 100644 index 00000000..3f09ac42 --- /dev/null +++ b/website/src/components/website/dashboard/Commercials.vue @@ -0,0 +1,36 @@ + + + + + diff --git a/website/src/utils/dashboard.js b/website/src/utils/dashboard.js index 39925e62..e2c849bd 100644 --- a/website/src/utils/dashboard.js +++ b/website/src/utils/dashboard.js @@ -45,6 +45,14 @@ export async function managePred(auth, client, predictionAction) { }); } +export async function startCommercial(auth, client, commercialDuration) { + if (!auth?.user) return { error: true, errorMessage: "Not authenticated" }; + return await authenticatedRequest(auth, "actions/start-commercial", { + client: client.id || client, + commercialDuration + }); +} + export async function updateAutomaticTitle(auth, client) { if (!auth?.user) return { error: true, errorMessage: "Not authenticated" }; return await authenticatedRequest(auth, "actions/set-title", { diff --git a/website/src/views/Dashboard.vue b/website/src/views/Dashboard.vue index bd5e170b..b3852531 100644 --- a/website/src/views/Dashboard.vue +++ b/website/src/views/Dashboard.vue @@ -13,6 +13,7 @@ + Update title @@ -30,10 +31,11 @@ import { BButton, BFormCheckbox } from "bootstrap-vue"; import { togglePlayerCams, updateAutomaticTitle } from "@/utils/dashboard"; import Predictions from "@/components/website/dashboard/Predictions"; import CommsControl from "@/components/website/dashboard/CommsControls"; +import Commercials from "@/components/website/dashboard/Commercials"; export default { name: "Dashboard", - components: { CommsControl, Predictions, MatchEditor, MatchThumbnail, BroadcastSwitcher, BFormCheckbox, BButton }, + components: { CommsControl, Commercials, Predictions, MatchEditor, MatchThumbnail, BroadcastSwitcher, BFormCheckbox, BButton }, computed: { user() { if (!this.$root.auth.user?.airtableID) return {}; @@ -76,9 +78,11 @@ export default { methods: { url, togglePlayerCams, - async updateTitle() { await updateAutomaticTitle(this.$root.auth, "self", "create"); + }, + hasPermission(permission) { + return (this.user.website_settings || []).includes(permission); } }, watch: {