Skip to content
Open
Show file tree
Hide file tree
Changes from 2 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
2 changes: 1 addition & 1 deletion websites/B/BBC/metadata.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"www.bbc.com"
],
"regExp": "^https?[:][/][/](www[.])?bbc[.](com|co[.]uk)[/]",
"version": "2.3.0",
"version": "2.3.2",

Check failure

Code scanning / PMD

Makes sure the version is bumped Error

Expected version of activity BBC to be bumped to one of the following: 2.3.1, 2.4.0, 3.0.0
Comment thread
github-advanced-security[bot] marked this conversation as resolved.
Fixed
"logo": "https://cdn.rcd.gg/PreMiD/websites/B/BBC/assets/logo.png",
"thumbnail": "https://cdn.rcd.gg/PreMiD/websites/B/BBC/assets/thumbnail.png",
"color": "#000000",
Expand Down
97 changes: 83 additions & 14 deletions websites/B/BBC/presence.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ function getStrings() {
{
play: 'general.playing',
pause: 'general.paused',
Live: 'general.Live',
Live: 'general.live',
browse: 'general.browsing',
searchSomething: 'general.searchSomething',
viewTeam: 'twitch.viewTeam',
Expand Down Expand Up @@ -57,6 +57,17 @@ function formatChannelName(channelId?: string): string {
return channelMap[channelId.toLowerCase()] || channelId.toUpperCase()
}

const LIVE_DURATION_THRESHOLD = 86400 * 30 // nothing on iPlayer is 30 days long
function isEpochAnchored(value: number): boolean {
return Number.isFinite(value) && value > LIVE_DURATION_THRESHOLD
}
function isLiveTimeline(media: { duration: number, currentTime: number }): boolean {
// `duration` alone is ambiguous: MSE streams (live or VOD) can report
// Infinity while the seekable range is still unresolved. `currentTime`
// anchored to wall-clock epoch seconds is the reliable live signature.
return isEpochAnchored(media.currentTime) || isEpochAnchored(media.duration)
}

const serviceName = (() => {
switch (location.pathname.split('/')[1]) {
case 'iplayer':
Expand Down Expand Up @@ -90,6 +101,7 @@ let SoundMedia: MediaData = {
}
let iPlayer: IPlayerData
let soundData: SoundData
let lastPath: string | undefined

presence.on('iFrameData', (data: IFrameData) => {
if (data.audio)
Expand Down Expand Up @@ -126,7 +138,16 @@ presence.on('UpdateData', async () => {
}
}
const handleVideo = () => {
presenceData.type = ActivityType.Watching;
presenceData.type = ActivityType.Watching

if (isLiveTimeline(VideoMedia)) {
presenceData.smallImageKey = Assets.Live
presenceData.smallImageText = strings.Live
delete presenceData.startTimestamp
delete presenceData.endTimestamp
return
}

[presenceData.startTimestamp, presenceData.endTimestamp] = getTimestamps(VideoMedia.currentTime, VideoMedia.duration)

presenceData.smallImageKey = VideoMedia.paused
Expand All @@ -144,9 +165,23 @@ presence.on('UpdateData', async () => {

if (path.includes('/iplayer')) {
presenceData.type = ActivityType.Watching
iPlayer ??= await presence
.getPageVariable('__IPLAYER_REDUX_STATE__')
.then(data => data.__IPLAYER_REDUX_STATE__) as IPlayerData
if (lastPath !== path) {
lastPath = path
const data = await presence.getPageVariable<Record<string, any>>(
'__IPLAYER_REDUX_STATE__.episode',
'__IPLAYER_REDUX_STATE__.versions',
'__IPLAYER_REDUX_STATE__.channel',
'__IPLAYER_REDUX_STATE__.header',
'__IPLAYER_REDUX_STATE__.relatedEpisodes',
)
iPlayer = {
episode: data['__IPLAYER_REDUX_STATE__.episode'],
versions: data['__IPLAYER_REDUX_STATE__.versions'],
channel: data['__IPLAYER_REDUX_STATE__.channel'],
header: data['__IPLAYER_REDUX_STATE__.header'],
relatedEpisodes: data['__IPLAYER_REDUX_STATE__.relatedEpisodes'],
} as IPlayerData
}

let iPlayerVideo: HTMLVideoElement | MediaData | undefined = document
.querySelector('smp-toucan-player')
Expand All @@ -159,14 +194,38 @@ presence.on('UpdateData', async () => {
iPlayerVideo = VideoMedia
// OD Programming:
if (iPlayerVideo && path.includes('/iplayer/episode')) {
if (!iPlayerVideo.duration || iPlayer.episode?.Live) {
if (iPlayer.channel?.onAir || iPlayer.episode?.Live) {
presenceData.details = (iPlayer.channel ?? iPlayer.episode)?.title
presenceData.state = strings.Live
const simulcast = iPlayer.versions?.find(version => version.kind === 'simulcast')
const isSimulcast = Boolean(simulcast) || iPlayer.episode?.live
if (!iPlayerVideo.duration || isSimulcast || isLiveTimeline(iPlayerVideo)) {
if (iPlayer.channel?.onAir || isSimulcast || isLiveTimeline(iPlayerVideo)) {
if (usePresenceName) {
presenceData.name = iPlayer.episode?.title ?? presenceData.name
presenceData.details = iPlayer.episode?.subtitle?.match(/: (.*)/)?.[1]
?? iPlayer.episode?.subtitle
?? strings.Live
presenceData.state = iPlayer.episode?.subtitle ?? strings.Live
}
else {
presenceData.details = (iPlayer.channel ?? iPlayer.episode)?.title
presenceData.state = iPlayer.episode?.subtitle || strings.Live
}

setCover(iPlayer.episode?.images?.standard)

presenceData.smallImageKey = Assets.Live
presenceData.smallImageText = strings.Live

if (simulcast?.startTime) {
presenceData.startTimestamp = simulcast.startTime
if (simulcast.endTime && simulcast.endTime > Math.floor(Date.now() / 1000))
presenceData.endTimestamp = simulcast.endTime
else
delete presenceData.endTimestamp
}
else {
delete presenceData.startTimestamp
delete presenceData.endTimestamp
}
}
else if (!iPlayer.channel) {
setCover(
Expand Down Expand Up @@ -270,7 +329,6 @@ presence.on('UpdateData', async () => {
presenceData.smallImageText = strings.Live

delete presenceData.startTimestamp
presenceData.startTimestamp = Date.now() // milliseconds
delete presenceData.endTimestamp
}
else {
Expand All @@ -282,9 +340,15 @@ presence.on('UpdateData', async () => {
}
else if (path.includes('/sounds')) {
presenceData.type = ActivityType.Listening
soundData ??= await presence
.getPageVariable('__PRELOADED_STATE__')
.then(data => data.__PRELOADED_STATE__) as SoundData
if (lastPath !== path) {
lastPath = path
const data = await presence.getPageVariable<Record<string, any>>(
'__PRELOADED_STATE__.programmes',
)
soundData = {
programmes: data['__PRELOADED_STATE__.programmes'],
} as SoundData
}

if (path.includes('/play/')) {
const isLive = path.includes('Live:')
Expand Down Expand Up @@ -815,7 +879,7 @@ interface IPlayerData {
episode?: {
title: string
subtitle: string
Live: boolean
live: boolean
images: {
portrait?: string
standard: string
Expand All @@ -826,6 +890,11 @@ interface IPlayerData {
category: string
}
}
versions?: {
kind: string
startTime: number
endTime: number
}[]
relatedEpisodes?: {
count: number
episodes: {
Expand Down
Loading