-
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update holodex for twitter broadcast
- Loading branch information
1 parent
180855a
commit 13f2c17
Showing
12 changed files
with
362 additions
and
111 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -53,3 +53,5 @@ holodex: | |
active: false | ||
space: | ||
active: false | ||
broadcast: | ||
active: false |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -8,4 +8,8 @@ export const holodexConfig = { | |
space: { | ||
active: false, | ||
}, | ||
|
||
broadcast: { | ||
active: false, | ||
}, | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,4 @@ | ||
export enum HolodexExternalStreamType { | ||
TWITTER_SPACE = 'twitter_space', | ||
TWITTER_BROADCAST = 'twitter_broadcast', | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { TwitterBroadcast } from '../../twitter/model/twitter-broadcast.entity' | ||
import { HolodexChannelAccount } from '../model/holodex-channel_account.entity' | ||
import { HolodexExternalStream } from '../model/holodex-external-stream.entity' | ||
|
||
export interface HolodexBroadcast extends TwitterBroadcast { | ||
holodexChannelAccount?: HolodexChannelAccount | ||
holodexExternalStream?: HolodexExternalStream | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
import { HolodexChannelAccount } from '../model/holodex-channel_account.entity' | ||
import { HolodexExternalStream } from '../model/holodex-external-stream.entity' | ||
|
||
export interface HolodexItem { | ||
holodexChannelAccount?: HolodexChannelAccount | ||
holodexExternalStream?: HolodexExternalStream | ||
} |
134 changes: 134 additions & 0 deletions
134
src/module/holodex/service/cron/base/holodex-base-cron.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
import Bottleneck from 'bottleneck' | ||
import { BaseCronService } from '../../../../../shared/service/base-cron.service' | ||
import { BaseExternalEntity } from '../../../../database/model/base-external.entity' | ||
import { DiscordService } from '../../../../discord/service/discord.service' | ||
import { HolodexExternalStreamType } from '../../../enum/holodex-external-stream-type.enum' | ||
import { HolodexItem } from '../../../interface/holodex.interface' | ||
import { HolodexApiService } from '../../api/holodex-api.service' | ||
import { HolodexExternalStreamService } from '../../data/holodex-external-stream.service' | ||
import { HolodexVideoService } from '../../data/holodex-video.service' | ||
|
||
export abstract class HolodexBaseCronService<T extends BaseExternalEntity> extends BaseCronService { | ||
protected readonly TITLE_MIN_LENGTH = 4 | ||
protected readonly TITLE_MAX_LENGTH = 120 | ||
|
||
protected extraDurationSec = 120 | ||
|
||
constructor( | ||
protected readonly holodexApiService: HolodexApiService, | ||
protected readonly holodexVideoService: HolodexVideoService, | ||
protected readonly holodexExternalStreamService: HolodexExternalStreamService, | ||
protected readonly discordService: DiscordService, | ||
) { | ||
super() | ||
} | ||
|
||
public abstract getType(): HolodexExternalStreamType | ||
|
||
public abstract getItems(): Promise<T[]> | ||
|
||
protected abstract getItemTitle(item: T): string | ||
|
||
protected abstract getItemUrl(item: T): string | ||
|
||
protected abstract getItemThumbnailUrl(item: T): string | ||
|
||
protected abstract getItemLiveTime(item: T): string | ||
|
||
protected abstract getItemDuration(item: T): number | ||
|
||
protected abstract getVideoCreatedAt(item: T): number | ||
|
||
protected async onTick() { | ||
try { | ||
const items = await this.getItems() | ||
if (!items?.length) { | ||
return | ||
} | ||
this.logger.debug('onTick', { count: items.length, ids: items.map((v) => v.id) }) | ||
const limiter = new Bottleneck({ maxConcurrent: 1 }) | ||
await Promise.allSettled(items.map((v) => limiter.schedule(() => this.notifyItem(v)))) | ||
} catch (error) { | ||
this.logger.error(`onTick: ${error.message}`) | ||
} | ||
} | ||
|
||
protected async notifyItem(item: T & HolodexItem) { | ||
try { | ||
const owner = await this.discordService.getOwner() | ||
const body = { | ||
id: item.holodexExternalStream?.id, | ||
channel_id: item.holodexChannelAccount.channelId, | ||
title: { | ||
name: this.getItemTitle(item), | ||
link: this.getItemUrl(item), | ||
thumbnail: this.getItemThumbnailUrl(item), | ||
placeholderType: 'external-stream', | ||
certainty: 'certain', | ||
credits: { | ||
bot: { | ||
link: 'https://discord.gg/A24AbzgvRJ', | ||
name: owner.username, | ||
user: owner.username, | ||
}, | ||
}, | ||
}, | ||
liveTime: this.getItemLiveTime(item), | ||
duration: this.getItemDuration(item), | ||
} | ||
|
||
debugger | ||
debugger | ||
debugger | ||
debugger | ||
debugger | ||
|
||
const { data } = await this.holodexApiService.postVideoPlaceholder(body) | ||
if (data.error) { | ||
const { placeholder } = data | ||
if (placeholder) { | ||
this.logger.error(`notifyItem#placeholder: ${data.error}`, { | ||
id: item.id, | ||
placeholder: { | ||
id: placeholder.id, | ||
link: placeholder.link, | ||
}, | ||
}) | ||
|
||
body.id = placeholder.id | ||
await this.holodexApiService.postVideoPlaceholder(body) | ||
await this.saveVideo(placeholder, item) | ||
return | ||
} | ||
|
||
this.logger.error(`notifyItem#response: ${data.error}`, { id: item.id }) | ||
return | ||
} | ||
|
||
if (!item.holodexExternalStream) { | ||
const limiter = new Bottleneck({ maxConcurrent: 1 }) | ||
await Promise.allSettled(data.map((v) => limiter.schedule(() => this.saveVideo(v, item)))) | ||
} | ||
} catch (error) { | ||
const msg = [error.message, error.response?.data] | ||
.filter((v) => v) | ||
.join('. ') | ||
this.logger.error(`notifyItem: ${msg}`, { id: item.id }) | ||
} | ||
} | ||
|
||
protected async saveVideo(data: any, item: T) { | ||
await this.holodexVideoService.save({ | ||
id: data.id, | ||
createdAt: this.getVideoCreatedAt(item), | ||
channelId: data.channel_id, | ||
type: data.type, | ||
}) | ||
await this.holodexExternalStreamService.add({ | ||
id: data.id, | ||
createdAt: this.getVideoCreatedAt(item), | ||
type: this.getType(), | ||
sourceId: item.id, | ||
}) | ||
} | ||
} |
78 changes: 78 additions & 0 deletions
78
src/module/holodex/service/cron/holodex-broadcast-cron.service.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,78 @@ | ||
/* eslint-disable class-methods-use-this */ | ||
|
||
import { Inject, Injectable, forwardRef } from '@nestjs/common' | ||
import { baseLogger } from '../../../../logger' | ||
import { DiscordService } from '../../../discord/service/discord.service' | ||
import { TwitterUtil } from '../../../twitter/util/twitter.util' | ||
import { HolodexExternalStreamType } from '../../enum/holodex-external-stream-type.enum' | ||
import { HolodexBroadcast } from '../../interface/holodex-broadcast.interface' | ||
import { HolodexApiService } from '../api/holodex-api.service' | ||
import { HolodexBroadcastService } from '../data/external/holodex-broadcast.service' | ||
import { HolodexExternalStreamService } from '../data/holodex-external-stream.service' | ||
import { HolodexVideoService } from '../data/holodex-video.service' | ||
import { HolodexBaseCronService } from './base/holodex-base-cron.service' | ||
|
||
@Injectable() | ||
export class HolodexBroadcastCronService extends HolodexBaseCronService<HolodexBroadcast> { | ||
protected readonly logger = baseLogger.child({ context: HolodexBroadcastCronService.name }) | ||
|
||
protected cronTime = '0 */1 * * * *' | ||
// protected cronRunOnInit = true | ||
|
||
constructor( | ||
@Inject(HolodexApiService) | ||
protected readonly holodexApiService: HolodexApiService, | ||
@Inject(HolodexVideoService) | ||
protected readonly holodexVideoService: HolodexVideoService, | ||
@Inject(HolodexExternalStreamService) | ||
protected readonly holodexExternalStreamService: HolodexExternalStreamService, | ||
@Inject(forwardRef(() => DiscordService)) | ||
protected readonly discordService: DiscordService, | ||
@Inject(HolodexBroadcastService) | ||
private readonly holodexBroadcastService: HolodexBroadcastService, | ||
) { | ||
super(holodexApiService, holodexVideoService, holodexExternalStreamService, discordService) | ||
} | ||
|
||
public getType(): HolodexExternalStreamType { | ||
throw HolodexExternalStreamType.TWITTER_BROADCAST | ||
} | ||
|
||
public async getItems(): Promise<HolodexBroadcast[]> { | ||
const items = await this.holodexBroadcastService.getManyLive() | ||
return items | ||
} | ||
|
||
protected getItemTitle(item: HolodexBroadcast): string { | ||
let title = item.title || `${item.user.username}'s Broadcast` | ||
if (title.length < this.TITLE_MIN_LENGTH) { | ||
title = `Broadcast: ${item.title}` | ||
} | ||
title = title.slice(0, this.TITLE_MAX_LENGTH) | ||
return title | ||
} | ||
|
||
protected getItemUrl(item: HolodexBroadcast): string { | ||
const url = TwitterUtil.getBroadcastUrl(item.id) | ||
return url | ||
} | ||
|
||
protected getItemThumbnailUrl(item: HolodexBroadcast): string { | ||
const url = item.imageUrl || item.user.profileImageUrl | ||
return url | ||
} | ||
|
||
protected getItemLiveTime(item: HolodexBroadcast): string { | ||
const time = new Date(item.startedAt).toISOString() | ||
return time | ||
} | ||
|
||
protected getItemDuration(item: HolodexBroadcast): number { | ||
const duration = Math.floor((Date.now() - item.startedAt) / 1000) + this.extraDurationSec | ||
return duration | ||
} | ||
|
||
protected getVideoCreatedAt(item: HolodexBroadcast): number { | ||
return item.startedAt | ||
} | ||
} |
Oops, something went wrong.