From 4ef50b0ad2ef03379ec0d4eccc8e318326725c7b Mon Sep 17 00:00:00 2001 From: gettinToasty Date: Fri, 3 Mar 2023 09:56:14 -0800 Subject: [PATCH] Display Page Events on Scheduler (#4489) * Display page events on schedule calendar * Remove game field from scheduler --- .../stream-scheduler/StreamScheduler.tsx | 2 +- .../stream-scheduler/useStreamScheduler.tsx | 4 +- .../platforms/FacebookEditStreamInfo.tsx | 2 +- app/i18n/en-US/facebook.json | 2 +- app/services/platforms/facebook.ts | 86 ++++++++----------- 5 files changed, 38 insertions(+), 58 deletions(-) diff --git a/app/components-react/pages/stream-scheduler/StreamScheduler.tsx b/app/components-react/pages/stream-scheduler/StreamScheduler.tsx index caed65e26333..4088988a9510 100644 --- a/app/components-react/pages/stream-scheduler/StreamScheduler.tsx +++ b/app/components-react/pages/stream-scheduler/StreamScheduler.tsx @@ -169,7 +169,7 @@ function EventSettingsModal() { description={ selectedPlatform === 'facebook' ? $t( - 'Please note that while you can schedule streams to Facebook, they will not appear on this calendar due to API limitations', + 'Please note that while you can schedule streams to Facebook, some will not appear on this calendar due to API limitations', ) : undefined } diff --git a/app/components-react/pages/stream-scheduler/useStreamScheduler.tsx b/app/components-react/pages/stream-scheduler/useStreamScheduler.tsx index d0b93c1333ac..838b799e5eb1 100644 --- a/app/components-react/pages/stream-scheduler/useStreamScheduler.tsx +++ b/app/components-react/pages/stream-scheduler/useStreamScheduler.tsx @@ -529,9 +529,7 @@ function convertFBLiveVideoToEvent(fbLiveVideo: IFacebookLiveVideoExtended): ISt return { platform: 'facebook', id: fbLiveVideo.id, - date: new Date( - fbLiveVideo.event_params?.start_time || fbLiveVideo.broadcast_start_time, - ).valueOf(), + date: new Date(fbLiveVideo.broadcast_start_time).valueOf(), title: fbLiveVideo.title, status: 'scheduled', facebook: { diff --git a/app/components-react/windows/go-live/platforms/FacebookEditStreamInfo.tsx b/app/components-react/windows/go-live/platforms/FacebookEditStreamInfo.tsx index 01a562890d23..5a7fdd1bec98 100644 --- a/app/components-react/windows/go-live/platforms/FacebookEditStreamInfo.tsx +++ b/app/components-react/windows/go-live/platforms/FacebookEditStreamInfo.tsx @@ -112,7 +112,7 @@ class FacebookEditStreamInfoModule { } get shouldShowGame() { - return !this.isUpdateMode; + return !this.isUpdateMode && !this.props.isScheduleMode; } get shouldShowPrivacy() { diff --git a/app/i18n/en-US/facebook.json b/app/i18n/en-US/facebook.json index 406c6751746a..b0a98e2c2b85 100644 --- a/app/i18n/en-US/facebook.json +++ b/app/i18n/en-US/facebook.json @@ -34,5 +34,5 @@ "Only Me": "Only Me", "Do not change privacy settings": "Do not change privacy settings", "Install %{overlayName}": "Install %{overlayName}", - "Please note that while you can schedule streams to Facebook, they will not appear on this calendar due to API limitations": "Please note that while you can schedule streams to Facebook, they will not appear on this calendar due to API limitations" + "Please note that while you can schedule streams to Facebook, some will not appear on this calendar due to API limitations": "Please note that while you can schedule streams to Facebook, some will not appear on this calendar due to API limitations" } diff --git a/app/services/platforms/facebook.ts b/app/services/platforms/facebook.ts index eb87c58312eb..3017be46b3a6 100644 --- a/app/services/platforms/facebook.ts +++ b/app/services/platforms/facebook.ts @@ -1,3 +1,6 @@ +import moment from 'moment'; +import flatten from 'lodash/flatten'; +import * as remote from '@electron/remote'; import { mutation, InheritMutations, ViewHandler } from '../core/stateful-service'; import { IPlatformService, IGame, TPlatformCapability, IPlatformRequest, IPlatformState } from '.'; import { HostsService } from 'services/hosts'; @@ -10,8 +13,6 @@ import { throwStreamError } from 'services/streaming/stream-error'; import { BasePlatformService } from './base-platform'; import { WindowsService } from '../windows'; import { assertIsDefined, getDefined } from '../../util/properties-type-guards'; -import flatten from 'lodash/flatten'; -import * as remote from '@electron/remote'; interface IFacebookPage { access_token: string; @@ -29,8 +30,17 @@ interface IFacebookGroup { administrator: boolean; } +interface IFacebookEvent { + description: string; + name: string; + start_time: string; + id: string; +} + +type TFacebookStatus = 'UNPUBLISHED' | 'SCHEDULED_UNPUBLISHED' | 'LIVE_STOPPED' | 'LIVE'; + export interface IFacebookLiveVideo { - status: 'UNPUBLISHED' | 'SCHEDULED_UNPUBLISHED' | 'LIVE_STOPPED' | 'LIVE'; + status: TFacebookStatus; id: string; stream_url: string; title: string; @@ -39,11 +49,7 @@ export interface IFacebookLiveVideo { permalink_url: string; video: { id: string }; broadcast_start_time: string; - event_params: { - start_time?: number; - cover?: string; - status?: 'UNPUBLISHED' | 'SCHEDULED_UNPUBLISHED' | 'LIVE_STOPPED' | 'LIVE'; - }; + event_params: { start_time?: number; cover?: string; status?: TFacebookStatus }; } /** @@ -82,11 +88,7 @@ export interface IFacebookStartStreamOptions { description?: string; liveVideoId?: string; privacy?: { value: TFacebookStreamPrivacy }; - event_params: { - start_time?: number; - cover?: string; - status?: 'UNPUBLISHED' | 'SCHEDULED_UNPUBLISHED' | 'LIVE_STOPPED' | 'LIVE'; - }; + event_params: { start_time?: number; cover?: string; status?: TFacebookStatus }; } export type TDestinationType = 'me' | 'page' | 'group' | ''; @@ -493,8 +495,6 @@ export class FacebookService const timeRange = 1000 * 60 * 60 * 24; const maxDate = Date.now() + timeRange; const minDate = Date.now() - timeRange; - const maxDateUnix = Math.floor(maxDate / 1000); - const minDateUnix = Math.floor(minDate / 1000); const token = this.views.getDestinationToken(destinationType, destinationId); let sourceParam = ''; if (destinationType === 'page' || destinationType === 'me') { @@ -504,8 +504,8 @@ export class FacebookService } let videos = ( - await this.requestFacebook<{ data: IFacebookLiveVideo[] }>( - `${this.apiBase}/${destinationId}/live_videos?status=["UNPUBLISHED","SCHEDULED_UNPUBLISHED"]&fields=title,description,status,event_params,permalink_url,from${sourceParam}&since=${minDateUnix}&until=${maxDateUnix}`, + await this.requestFacebook<{ data: IFacebookEvent[] }>( + `${this.apiBase}/${destinationId}/events`, token, ) ).data; @@ -513,13 +513,27 @@ export class FacebookService if (onlyUpcoming) { videos = videos.filter(v => { // some videos created in the new Live Producer don't have `planned_start_time` - if (!v.event_params?.start_time) return true; + if (!v.start_time) return true; - const videoDate = new Date(v.event_params.start_time).valueOf(); + const videoDate = new Date(v.start_time).valueOf(); return videoDate >= minDate && videoDate <= maxDate; }); } - return videos; + return videos.map(v => ({ + id: v.id, + title: v.name, + stream_url: '', + permalink_url: '', + event_params: { + start_time: moment(v.start_time).unix(), + status: 'SCHEDULED_UNPUBLISHED', + }, + description: v.description, + status: 'SCHEDULED_UNPUBLISHED', + game: '', + video: { id: v.id }, + broadcast_start_time: v.start_time, + })); } /** @@ -529,38 +543,6 @@ export class FacebookService // perform all requests simultaneously const requests: Promise[] = []; - // fetch videos from the timeline and groups - if (this.state.grantedPermissions.includes('publish_video')) { - const destinationType = 'me'; - const destinationId = 'me'; - requests.push( - this.fetchScheduledVideos(destinationType, destinationId, onlyUpcoming).then(videos => - videos.map(video => ({ - ...video, - destinationType, - destinationId, - })), - ), - ); - } - - // fetch videos from group - if (this.state.grantedPermissions.includes('publish_to_groups')) { - const destinationType = 'group'; - this.state.facebookGroups.forEach(group => { - const destinationId = group.id; - requests.push( - this.fetchScheduledVideos(destinationType, destinationId, onlyUpcoming).then(videos => - videos.map(video => ({ - ...video, - destinationType, - destinationId, - })), - ), - ); - }); - } - // fetch videos from pages this.state.facebookPages.forEach(page => { const destinationType = 'page';