Init commit

This commit is contained in:
ShreejitPanchal
2026-05-19 19:56:02 +08:00
commit 6601501eff
4047 changed files with 2185372 additions and 0 deletions

View File

@@ -0,0 +1,61 @@
import { logger } from '@server/helpers/logger.js'
import { t } from '@server/helpers/i18n.js'
import { WEBSERVER } from '@server/initializers/constants.js'
import { UserModel } from '@server/models/user/user.js'
import { UserNotificationModel } from '@server/models/user/user-notification.js'
import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotificationModelForApi } from '@server/types/models/index.js'
import { UserNotificationType } from '@peertube/peertube-models'
import { AbstractNotification } from '../common/abstract-notification.js'
export abstract class AbstractOwnedVideoPublication extends AbstractNotification<MVideoFullLight> {
protected user: MUserDefault
async prepare () {
this.user = await UserModel.loadByVideoId(this.payload.id)
}
log () {
logger.info('Notifying user %s of the publication of its video %s.', this.user.username, this.payload.url)
}
getSetting (user: MUserWithNotificationSetting) {
return user.NotificationSetting.myVideoPublished
}
getTargetUsers () {
if (!this.user) return []
return [ this.user ]
}
createNotification (user: MUserWithNotificationSetting) {
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
type: UserNotificationType.MY_VIDEO_PUBLISHED,
userId: user.id,
videoId: this.payload.id
})
notification.Video = this.payload
return notification
}
createEmail (user: MUserWithNotificationSetting) {
const to = { email: user.email, language: user.getLanguage() }
const language = user.getLanguage()
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
return {
to,
subject: t('Your video has been published', language),
text: t('Your video {videoName} has been published.', language, { videoName: this.payload.name }),
locals: {
title: t('Your video is live', language),
action: {
text: t('View video', language),
url: videoUrl
}
}
}
}
}

View File

@@ -0,0 +1,100 @@
import { To, UserNotificationType } from '@peertube/peertube-models'
import { t } from '@server/helpers/i18n.js'
import { logger } from '@server/helpers/logger.js'
import { WEBSERVER } from '@server/initializers/constants.js'
import { myVideoImportsUrl } from '@server/lib/client-urls.js'
import { UserNotificationModel } from '@server/models/user/user-notification.js'
import { UserModel } from '@server/models/user/user.js'
import { MUserDefault, MUserWithNotificationSetting, MVideoImportVideo, UserNotificationModelForApi } from '@server/types/models/index.js'
import { AbstractNotification } from '../common/abstract-notification.js'
export type ImportFinishedForOwnerPayload = {
videoImport: MVideoImportVideo
success: boolean
}
export class ImportFinishedForOwner extends AbstractNotification<ImportFinishedForOwnerPayload> {
private user: MUserDefault
async prepare () {
this.user = await UserModel.loadByVideoImportId(this.videoImport.id)
}
log () {
logger.info('Notifying user %s its video import %s is finished.', this.user.username, this.videoImport.getTargetIdentifier())
}
getSetting (user: MUserWithNotificationSetting) {
return user.NotificationSetting.myVideoImportFinished
}
getTargetUsers () {
if (!this.user) return []
return [ this.user ]
}
createNotification (user: MUserWithNotificationSetting) {
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
type: this.payload.success
? UserNotificationType.MY_VIDEO_IMPORT_SUCCESS
: UserNotificationType.MY_VIDEO_IMPORT_ERROR,
userId: user.id,
videoImportId: this.videoImport.id
})
notification.VideoImport = this.videoImport
return notification
}
createEmail (user: MUserWithNotificationSetting) {
const to = { email: user.email, language: user.getLanguage() }
if (this.payload.success) return this.createSuccessEmail(to)
return this.createFailEmail(to)
}
private createSuccessEmail (to: To) {
const videoUrl = WEBSERVER.URL + this.videoImport.Video.getWatchStaticPath()
const language = to.language
const targetId = this.videoImport.getTargetIdentifier()
return {
to,
subject: t('Your video import is complete', language),
text: t('Your video {targetId} has just finished importing.', language, { targetId }),
locals: {
action: {
text: t('View video', language),
url: videoUrl
}
}
}
}
private createFailEmail (to: To) {
const language = to.language
const targetId = this.videoImport.getTargetIdentifier()
const text = t('Your video import {targetId} encountered an error.', language, { targetId })
return {
to,
subject: t('Your video import encountered an error', language),
text,
locals: {
title: t('Import failed', language),
action: {
text: t('Review imports', language),
url: myVideoImportsUrl
}
}
}
}
private get videoImport () {
return this.payload.videoImport
}
}

View File

@@ -0,0 +1,6 @@
export * from './new-video-or-live-for-subscribers.js'
export * from './import-finished-for-owner.js'
export * from './owned-publication-after-auto-unblacklist.js'
export * from './owned-publication-after-schedule-update.js'
export * from './owned-publication-after-transcoding.js'
export * from './studio-edition-finished-for-owner.js'

View File

@@ -0,0 +1,84 @@
import { UserNotificationType, VideoPrivacy, VideoState } from '@peertube/peertube-models'
import { logger } from '@server/helpers/logger.js'
import { WEBSERVER } from '@server/initializers/constants.js'
import { UserNotificationModel } from '@server/models/user/user-notification.js'
import { UserModel } from '@server/models/user/user.js'
import { MUserWithNotificationSetting, MVideoAccountLight, UserNotificationModelForApi } from '@server/types/models/index.js'
import { AbstractNotification } from '../common/abstract-notification.js'
import { t } from '@server/helpers/i18n.js'
export class NewVideoOrLiveForSubscribers extends AbstractNotification<MVideoAccountLight> {
private users: MUserWithNotificationSetting[]
async prepare () {
// List all followers that are users
this.users = await UserModel.listUserSubscribersOf(this.payload.VideoChannel.Actor.id)
}
log () {
logger.info('Notifying %d users of new video %s.', this.users.length, this.payload.url)
}
isDisabled () {
if (this.payload.privacy !== VideoPrivacy.PUBLIC && this.payload.privacy !== VideoPrivacy.INTERNAL) return true
if (this.payload.state !== VideoState.PUBLISHED) return true
if (this.payload.isBlacklisted()) return true
return false
}
getSetting (user: MUserWithNotificationSetting) {
return user.NotificationSetting.newVideoFromSubscription
}
getTargetUsers () {
return this.users
}
createNotification (user: MUserWithNotificationSetting) {
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
type: this.payload.isLive
? UserNotificationType.NEW_LIVE_FROM_SUBSCRIPTION
: UserNotificationType.NEW_VIDEO_FROM_SUBSCRIPTION,
userId: user.id,
videoId: this.payload.id
})
notification.Video = this.payload
return notification
}
// ---------------------------------------------------------------------------
createEmail (user: MUserWithNotificationSetting) {
const to = { email: user.email, language: user.getLanguage() }
const channelName = this.payload.VideoChannel.getDisplayName()
const channelUrl = WEBSERVER.URL + this.payload.VideoChannel.getClientUrl()
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
const videoName = this.payload.name
const isLive = this.payload.isLive
const subject = isLive
? t('{channelName} is live streaming', to.language, { channelName })
: t('{channelName} just published a new video: { videoName }', to.language, { channelName, videoName })
return {
template: 'video-published-for-subscribers',
to,
subject,
locals: {
channelName,
channelUrl,
videoName,
videoUrl,
isLive,
action: {
text: t('View video', to.language),
url: videoUrl
}
}
}
}
}

View File

@@ -0,0 +1,10 @@
import { VideoState } from '@peertube/peertube-models'
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
export class OwnedPublicationAfterAutoUnblacklist extends AbstractOwnedVideoPublication {
isDisabled () {
// Don't notify if video is still waiting for transcoding or scheduled update
return !!this.payload.ScheduleVideoUpdate || (this.payload.waitTranscoding && this.payload.state !== VideoState.PUBLISHED)
}
}

View File

@@ -0,0 +1,10 @@
import { VideoState } from '@peertube/peertube-models'
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
export class OwnedPublicationAfterScheduleUpdate extends AbstractOwnedVideoPublication {
isDisabled () {
// Don't notify if video is still blacklisted or waiting for transcoding
return !!this.payload.VideoBlacklist || (this.payload.waitTranscoding && this.payload.state !== VideoState.PUBLISHED)
}
}

View File

@@ -0,0 +1,9 @@
import { AbstractOwnedVideoPublication } from './abstract-owned-video-publication.js'
export class OwnedPublicationAfterTranscoding extends AbstractOwnedVideoPublication {
isDisabled () {
// Don't notify if didn't wait for transcoding or video is still blacklisted/waiting for scheduled update
return !this.payload.waitTranscoding || !!this.payload.VideoBlacklist || !!this.payload.ScheduleVideoUpdate
}
}

View File

@@ -0,0 +1,59 @@
import { UserNotificationType } from '@peertube/peertube-models'
import { t } from '@server/helpers/i18n.js'
import { logger } from '@server/helpers/logger.js'
import { WEBSERVER } from '@server/initializers/constants.js'
import { UserNotificationModel } from '@server/models/user/user-notification.js'
import { UserModel } from '@server/models/user/user.js'
import { MUserDefault, MUserWithNotificationSetting, MVideoFullLight, UserNotificationModelForApi } from '@server/types/models/index.js'
import { AbstractNotification } from '../common/abstract-notification.js'
export class StudioEditionFinishedForOwner extends AbstractNotification<MVideoFullLight> {
private user: MUserDefault
async prepare () {
this.user = await UserModel.loadByVideoId(this.payload.id)
}
log () {
logger.info('Notifying user %s its video studio edition %s is finished.', this.user.username, this.payload.url)
}
getSetting (user: MUserWithNotificationSetting) {
return user.NotificationSetting.myVideoStudioEditionFinished
}
getTargetUsers () {
if (!this.user) return []
return [ this.user ]
}
createNotification (user: MUserWithNotificationSetting) {
const notification = UserNotificationModel.build<UserNotificationModelForApi>({
type: UserNotificationType.MY_VIDEO_STUDIO_EDITION_FINISHED,
userId: user.id,
videoId: this.payload.id
})
notification.Video = this.payload
return notification
}
createEmail (user: MUserWithNotificationSetting) {
const to = { email: user.email, language: user.getLanguage() }
const videoUrl = WEBSERVER.URL + this.payload.getWatchStaticPath()
return {
to,
subject: t('Edition of your video has finished', to.language),
text: t('Edition of your video {videoName} has finished.', to.language, { videoName: this.payload.name }),
locals: {
title: t('Video edition has finished', to.language),
action: {
text: t('View video', to.language),
url: videoUrl
}
}
}
}
}