videoQuota: body.videoQuota,
videoQuotaDaily: body.videoQuotaDaily,
adminFlags: body.adminFlags || UserAdminFlag.NONE
- })
+ }) as MUser
const { user, account } = await createUserAccountAndChannelAndPlaylist({ userToCreate: userToCreate })
import { UserVideoQuota } from '../../../../shared/models/users/user-video-quota.model'
import { updateAvatarValidator } from '../../../middlewares/validators/avatar'
import { updateActorAvatarFile } from '../../../lib/avatar'
-import { auditLoggerFactory, getAuditIdFromRes, UserAuditView } from '../../../helpers/audit-logger'
import { VideoImportModel } from '../../../models/video/video-import'
import { AccountModel } from '../../../models/account/account'
import { CONFIG } from '../../../initializers/config'
import { sequelizeTypescript } from '../../../initializers/database'
import { sendVerifyUserEmail } from '../../../lib/user'
-const auditLogger = auditLoggerFactory('users-me')
-
const reqAvatarFile = createReqFiles([ 'avatarfile' ], MIMETYPES.IMAGE.MIMETYPE_EXT, { avatarfile: CONFIG.STORAGE.TMP_DIR })
const meRouter = express.Router()
await user.destroy()
- auditLogger.delete(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})))
-
return res.sendStatus(204)
}
let sendVerificationEmail = false
const user = res.locals.oauth.token.user
- const oldUserAuditView = new UserAuditView(user.toFormattedJSON({}))
if (body.password !== undefined) user.password = body.password
if (body.nsfwPolicy !== undefined) user.nsfwPolicy = body.nsfwPolicy
await userAccount.save({ transaction: t })
await sendUpdateActor(userAccount, t)
-
- auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView)
})
if (sendVerificationEmail === true) {
async function updateMyAvatar (req: express.Request, res: express.Response) {
const avatarPhysicalFile = req.files[ 'avatarfile' ][ 0 ]
const user = res.locals.oauth.token.user
- const oldUserAuditView = new UserAuditView(user.toFormattedJSON({}))
const userAccount = await AccountModel.load(user.Account.id)
const avatar = await updateActorAvatarFile(avatarPhysicalFile, userAccount)
- auditLogger.update(getAuditIdFromRes(res), new UserAuditView(user.toFormattedJSON({})), oldUserAuditView)
-
return res.json({ avatar: avatar.toFormattedJSON() })
}
import { videoChannelsNameWithHostValidator, videosSortValidator } from '../../middlewares/validators'
import { sendUpdateActor } from '../../lib/activitypub/send'
import { VideoChannelCreate, VideoChannelUpdate } from '../../../shared'
-import { createVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
+import { createLocalVideoChannel, federateAllVideosOfChannel } from '../../lib/video-channel'
import { buildNSFWFilter, createReqFiles, isUserAbleToSearchRemoteURI } from '../../helpers/express-utils'
import { setAsyncActorKeys } from '../../lib/activitypub'
import { AccountModel } from '../../models/account/account'
const videoChannelCreated = await sequelizeTypescript.transaction(async t => {
const account = await AccountModel.load(res.locals.oauth.token.User.Account.id, t)
- return createVideoChannel(videoChannelInfo, account, t)
+ return createLocalVideoChannel(videoChannelInfo, account, t)
})
setAsyncActorKeys(videoChannelCreated.Actor)
import * as express from 'express'
import * as magnetUtil from 'magnet-uri'
-import 'multer'
import { auditLoggerFactory, getAuditIdFromRes, VideoImportAuditView } from '../../../helpers/audit-logger'
import { asyncMiddleware, asyncRetryTransactionMiddleware, authenticate, videoImportAddValidator } from '../../../middlewares'
import { MIMETYPES } from '../../../initializers/constants'
MChannelAccountDefault,
MThumbnail,
MUser,
+ MVideoAccountDefault,
MVideoTag,
MVideoThumbnailAccountDefault,
MVideoWithBlacklistLight
} from '@server/typings/models'
-import { MVideoImport, MVideoImportVideo } from '@server/typings/models/video/video-import'
+import { MVideoImport, MVideoImportFormattable } from '@server/typings/models/video/video-import'
const auditLogger = auditLoggerFactory('video-imports')
const videoImportsRouter = express.Router()
tags: string[],
videoImportAttributes: Partial<MVideoImport>,
user: MUser
-}): Bluebird<MVideoImportVideo> {
+}): Bluebird<MVideoImportFormattable> {
const { video, thumbnailModel, previewModel, videoChannel, tags, videoImportAttributes, user } = parameters
return sequelizeTypescript.transaction(async t => {
const sequelizeOptions = { transaction: t }
// Save video object in database
- const videoCreated = await video.save(sequelizeOptions) as (MVideoThumbnailAccountDefault & MVideoWithBlacklistLight & MVideoTag)
+ const videoCreated = await video.save(sequelizeOptions) as (MVideoAccountDefault & MVideoWithBlacklistLight & MVideoTag)
videoCreated.VideoChannel = videoChannel
if (thumbnailModel) await videoCreated.addAndSaveThumbnail(thumbnailModel, t)
const videoImport = await VideoImportModel.create(
Object.assign({ videoId: videoCreated.id }, videoImportAttributes),
sequelizeOptions
- ) as MVideoImportVideo
+ ) as MVideoImportFormattable
videoImport.Video = videoCreated
return videoImport
import { CONFIG } from '../initializers/config'
import * as srt2vtt from 'srt-to-vtt'
import { createReadStream, createWriteStream, move, remove } from 'fs-extra'
-import { MVideoCaption } from '@server/typings/models'
+import { MVideoCaptionFormattable } from '@server/typings/models'
-async function moveAndProcessCaptionFile (physicalFile: { filename: string, path: string }, videoCaption: MVideoCaption) {
+async function moveAndProcessCaptionFile (physicalFile: { filename: string, path: string }, videoCaption: MVideoCaptionFormattable) {
const videoCaptionsDir = CONFIG.STORAGE.CAPTIONS_DIR
const destination = join(videoCaptionsDir, videoCaption.getCaptionName())
} from '../../typings/models'
// Set account keys, this could be long so process after the account creation and do not block the client
-function setAsyncActorKeys (actor: MActor) {
+function setAsyncActorKeys <T extends MActor> (actor: T) {
return createPrivateAndPublicKeys()
.then(({ publicKey, privateKey }) => {
actor.publicKey = publicKey
sharedInboxUrl: WEBSERVER.URL + '/inbox',
followersUrl: url + '/followers',
followingUrl: url + '/following'
- })
+ }) as MActor
}
async function updateActorInstance (actorInstance: ActorModel, attributes: ActivityPubActor) {
import { ActivityPubActorType } from '../../shared/models/activitypub'
import { SERVER_ACTOR_NAME, WEBSERVER } from '../initializers/constants'
import { AccountModel } from '../models/account/account'
-import { UserModel } from '../models/account/user'
import { buildActorInstance, getAccountActivityPubUrl, setAsyncActorKeys } from './activitypub'
-import { createVideoChannel } from './video-channel'
+import { createLocalVideoChannel } from './video-channel'
import { ActorModel } from '../models/activitypub/actor'
import { UserNotificationSettingModel } from '../models/account/user-notification-setting'
import { UserNotificationSetting, UserNotificationSettingValue } from '../../shared/models/users'
import { Transaction } from 'sequelize/types'
import { Redis } from './redis'
import { Emailer } from './emailer'
-import { MAccountActor, MActor, MChannelActor } from '../typings/models'
-import { MUser, MUserId, MUserNotifSettingAccount } from '../typings/models/user'
+import { MAccountDefault, MActorDefault, MChannelActor } from '../typings/models'
+import { MUser, MUserDefault, MUserId } from '../typings/models/user'
type ChannelNames = { name: string, displayName: string }
async function createUserAccountAndChannelAndPlaylist (parameters: {
- userToCreate: UserModel,
+ userToCreate: MUser,
userDisplayName?: string,
channelNames?: ChannelNames,
validateUser?: boolean
-}): Promise<{ user: MUserNotifSettingAccount, account: MAccountActor, videoChannel: MChannelActor }> {
+}): Promise<{ user: MUserDefault, account: MAccountDefault, videoChannel: MChannelActor }> {
const { userToCreate, userDisplayName, channelNames, validateUser = true } = parameters
const { user, account, videoChannel } = await sequelizeTypescript.transaction(async t => {
validate: validateUser
}
- const userCreated: MUserNotifSettingAccount = await userToCreate.save(userOptions)
+ const userCreated: MUserDefault = await userToCreate.save(userOptions)
userCreated.NotificationSetting = await createDefaultUserNotificationSettings(userCreated, t)
const accountCreated = await createLocalAccountWithoutKeys({
userCreated.Account = accountCreated
const channelAttributes = await buildChannelAttributes(userCreated, channelNames)
- const videoChannel = await createVideoChannel(channelAttributes, accountCreated, t)
+ const videoChannel = await createLocalVideoChannel(channelAttributes, accountCreated, t)
const videoPlaylist = await createWatchLaterPlaylist(accountCreated, t)
const url = getAccountActivityPubUrl(name)
const actorInstance = buildActorInstance(type, url, name)
- const actorInstanceCreated: MActor = await actorInstance.save({ transaction: t })
+ const actorInstanceCreated: MActorDefault = await actorInstance.save({ transaction: t })
const accountInstance = new AccountModel({
name: displayName || name,
actorId: actorInstanceCreated.id
})
- const accountInstanceCreated: MAccountActor = await accountInstance.save({ transaction: t })
+ const accountInstanceCreated: MAccountDefault = await accountInstance.save({ transaction: t })
accountInstanceCreated.Actor = actorInstanceCreated
return accountInstanceCreated
import { VideoChannelModel } from '../models/video/video-channel'
import { buildActorInstance, federateVideoIfNeeded, getVideoChannelActivityPubUrl } from './activitypub'
import { VideoModel } from '../models/video/video'
-import { MAccountId, MChannelActor, MChannelId } from '../typings/models'
+import { MAccountId, MChannelDefault, MChannelId } from '../typings/models'
-type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelActor &
+type CustomVideoChannelModelAccount <T extends MAccountId> = MChannelDefault &
{ Account?: T }
-async function createVideoChannel <T extends MAccountId> (
+async function createLocalVideoChannel <T extends MAccountId> (
videoChannelInfo: VideoChannelCreate,
account: T,
t: Sequelize.Transaction
const videoChannel = new VideoChannelModel(videoChannelData)
const options = { transaction: t }
- const videoChannelCreated: CustomVideoChannelModelAccount<T> = await videoChannel.save(options) as MChannelActor
+ const videoChannelCreated: CustomVideoChannelModelAccount<T> = await videoChannel.save(options) as MChannelDefault
// Do not forget to add Account/Actor information to the created video channel
videoChannelCreated.Account = account
// ---------------------------------------------------------------------------
export {
- createVideoChannel,
+ createLocalVideoChannel,
federateAllVideosOfChannel
}
import { AccountBlock } from '../../../shared/models/blocklist'
import { Op } from 'sequelize'
import * as Bluebird from 'bluebird'
-import { MAccountBlocklist, MAccountBlocklistAccounts } from '@server/typings/models'
+import { MAccountBlocklist, MAccountBlocklistAccounts, MAccountBlocklistFormattable } from '@server/typings/models'
enum ScopeNames {
WITH_ACCOUNTS = 'WITH_ACCOUNTS'
})
}
- toFormattedJSON (): AccountBlock {
+ toFormattedJSON (this: MAccountBlocklistFormattable): AccountBlock {
return {
byAccount: this.ByAccount.toFormattedJSON(),
blockedAccount: this.BlockedAccount.toFormattedJSON(),
import { AccountVideoRate } from '../../../shared'
import { ScopeNames as VideoChannelScopeNames, SummaryOptions, VideoChannelModel } from '../video/video-channel'
import * as Bluebird from 'bluebird'
-import { MAccountVideoRate, MAccountVideoRateAccountUrl, MAccountVideoRateAccountVideo } from '@server/typings/models/video/video-rate'
+import {
+ MAccountVideoRate,
+ MAccountVideoRateAccountUrl,
+ MAccountVideoRateAccountVideo,
+ MAccountVideoRateFormattable
+} from '@server/typings/models/video/video-rate'
/*
Account rates per video.
})
}
- toFormattedJSON (): AccountVideoRate {
+ toFormattedJSON (this: MAccountVideoRateFormattable): AccountVideoRate {
return {
video: this.Video.toFormattedJSON(),
rating: this.type
import { AccountBlocklistModel } from './account-blocklist'
import { ServerBlocklistModel } from '../server/server-blocklist'
import { ActorFollowModel } from '../activitypub/actor-follow'
-import { MAccountActor, MAccountDefault } from '../../typings/models'
+import { MAccountActor, MAccountDefault, MAccountSummaryFormattable, MAccountFormattable } from '../../typings/models'
import * as Bluebird from 'bluebird'
export enum ScopeNames {
.findAll(query)
}
- toFormattedJSON (): Account {
+ toFormattedJSON (this: MAccountFormattable): Account {
const actor = this.Actor.toFormattedJSON()
const account = {
id: this.id,
return Object.assign(actor, account)
}
- toFormattedSummaryJSON (): AccountSummary {
- const actor = this.Actor.toFormattedJSON()
+ toFormattedSummaryJSON (this: MAccountSummaryFormattable): AccountSummary {
+ const actor = this.Actor.toFormattedSummaryJSON()
return {
id: this.id,
import { isUserNotificationSettingValid } from '../../helpers/custom-validators/user-notifications'
import { UserNotificationSetting, UserNotificationSettingValue } from '../../../shared/models/users/user-notification-setting.model'
import { clearCacheByUserId } from '../../lib/oauth-model'
+import { MNotificationSettingFormattable } from '@server/typings/models'
@Table({
tableName: 'userNotificationSetting',
return clearCacheByUserId(instance.userId)
}
- toFormattedJSON (): UserNotificationSetting {
+ toFormattedJSON (this: MNotificationSettingFormattable): UserNotificationSetting {
return {
newCommentOnMyVideo: this.newCommentOnMyVideo,
newVideoFromSubscription: this.newVideoFromSubscription,
import { isThemeNameValid } from '../../helpers/custom-validators/plugins'
import { getThemeOrDefault } from '../../lib/plugins/theme-utils'
import * as Bluebird from 'bluebird'
-import { MUserNotifSettingChannelDefault, MUserDefault, MUserId, MUserWithNotificationSetting } from '@server/typings/models'
+import {
+ MUserDefault,
+ MUserFormattable,
+ MUserId,
+ MUserNotifSettingChannelDefault,
+ MUserWithNotificationSetting
+} from '@server/typings/models'
enum ScopeNames {
WITH_VIDEO_CHANNEL = 'WITH_VIDEO_CHANNEL'
return comparePassword(password, this.password)
}
- toFormattedJSON (parameters: { withAdminFlags?: boolean } = {}): User {
+ toSummaryJSON
+
+ toFormattedJSON (this: MUserFormattable, parameters: { withAdminFlags?: boolean } = {}): User {
const videoQuotaUsed = this.get('videoQuotaUsed')
const videoQuotaUsedDaily = this.get('videoQuotaUsedDaily')
MActorFollowActorsDefault,
MActorFollowActorsDefaultSubscription,
MActorFollowFollowingHost,
+ MActorFollowFormattable,
MActorFollowSubscriptions
} from '@server/typings/models'
return ActorFollowModel.findAll(query)
}
- toFormattedJSON (): ActorFollow {
+ toFormattedJSON (this: MActorFollowFormattable): ActorFollow {
const follower = this.ActorFollower.toFormattedJSON()
const following = this.ActorFollowing.toFormattedJSON()
import { VideoChannelModel } from '../video/video-channel'
import { ActorFollowModel } from './actor-follow'
import { VideoModel } from '../video/video'
-import { MActor, MActorAccountChannelId, MActorFull } from '../../typings/models'
+import {
+ MActor,
+ MActorAccountChannelId,
+ MActorFormattable,
+ MActorFull, MActorHost,
+ MActorServer,
+ MActorSummaryFormattable,
+ MServerHost,
+ MActorRedundancyAllowed
+} from '../../typings/models'
import * as Bluebird from 'bluebird'
enum ScopeNames {
})
}
- toFormattedJSON () {
+ toFormattedSummaryJSON (this: MActorSummaryFormattable) {
let avatar: Avatar = null
if (this.Avatar) {
avatar = this.Avatar.toFormattedJSON()
}
return {
- id: this.id,
url: this.url,
name: this.preferredUsername,
host: this.getHost(),
+ avatar
+ }
+ }
+
+ toFormattedJSON (this: MActorFormattable) {
+ const base = this.toFormattedSummaryJSON()
+
+ return Object.assign(base, {
+ id: this.id,
hostRedundancyAllowed: this.getRedundancyAllowed(),
followingCount: this.followingCount,
followersCount: this.followersCount,
- avatar,
createdAt: this.createdAt,
updatedAt: this.updatedAt
- }
+ })
}
toActivityPubObject (name: string, type: 'Account' | 'Application' | 'VideoChannel') {
return this.serverId === null
}
- getWebfingerUrl () {
+ getWebfingerUrl (this: MActorServer) {
return 'acct:' + this.preferredUsername + '@' + this.getHost()
}
return this.Server ? `${this.preferredUsername}@${this.Server.host}` : this.preferredUsername
}
- getHost () {
+ getHost (this: MActorHost) {
return this.Server ? this.Server.host : WEBSERVER.HOST
}
- getRedundancyAllowed () {
+ getRedundancyAllowed (this: MActorRedundancyAllowed) {
return this.Server ? this.Server.redundancyAllowed : false
}
import { CONFIG } from '../../initializers/config'
import { throwIfNotValid } from '../utils'
import { isActivityPubUrlValid } from '../../helpers/custom-validators/activitypub/misc'
+import { MAvatarFormattable } from '@server/typings/models'
@Table({
tableName: 'avatar',
return AvatarModel.findOne(query)
}
- toFormattedJSON (): Avatar {
+ toFormattedJSON (this: MAvatarFormattable): Avatar {
return {
path: this.getStaticPath(),
createdAt: this.createdAt,
import { FindAndCountOptions, json } from 'sequelize'
import { RegisterServerSettingOptions } from '../../../shared/models/plugins/register-server-setting.model'
import * as Bluebird from 'bluebird'
-import { MPlugin } from '@server/typings/models'
+import { MPlugin, MPluginFormattable } from '@server/typings/models'
@DefaultScope(() => ({
attributes: {
return result
}
- toFormattedJSON (): PeerTubePlugin {
+ toFormattedJSON (this: MPluginFormattable): PeerTubePlugin {
return {
name: this.name,
type: this.type,
import { ServerBlock } from '../../../shared/models/blocklist'
import { getSort } from '../utils'
import * as Bluebird from 'bluebird'
-import { MServerBlocklist, MServerBlocklistAccountServer } from '@server/typings/models'
+import { MServerBlocklist, MServerBlocklistAccountServer, MServerBlocklistFormattable } from '@server/typings/models'
enum ScopeNames {
WITH_ACCOUNT = 'WITH_ACCOUNT',
})
}
- toFormattedJSON (): ServerBlock {
+ toFormattedJSON (this: MServerBlocklistFormattable): ServerBlock {
return {
byAccount: this.ByAccount.toFormattedJSON(),
blockedServer: this.BlockedServer.toFormattedJSON(),
import { throwIfNotValid } from '../utils'
import { ServerBlocklistModel } from './server-blocklist'
import * as Bluebird from 'bluebird'
-import { MServer } from '@server/typings/models/server'
+import { MServer, MServerFormattable } from '@server/typings/models/server'
@Table({
tableName: 'server',
return this.BlockedByAccounts && this.BlockedByAccounts.length !== 0
}
- toFormattedJSON () {
+ toFormattedJSON (this: MServerFormattable) {
return {
host: this.host
}
import { ScopeNames as VideoScopeNames, VideoModel } from './video'
import { VideoPrivacy } from '../../../shared/models/videos'
import { Op, Transaction } from 'sequelize'
+import { MScheduleVideoUpdateFormattable } from '@server/typings/models'
@Table({
tableName: 'scheduleVideoUpdate',
return ScheduleVideoUpdateModel.destroy(query)
}
- toFormattedJSON () {
+ toFormattedJSON (this: MScheduleVideoUpdateFormattable) {
return {
updateAt: this.updateAt,
privacy: this.privacy || undefined
import { VideoModel } from './video'
import { VideoAbuseState } from '../../../shared'
import { CONSTRAINTS_FIELDS, VIDEO_ABUSE_STATES } from '../../initializers/constants'
-import { MVideoAbuse, MVideoAbuseAccountVideo, MVideoAbuseVideo } from '../../typings/models'
+import { MVideoAbuse, MVideoAbuseFormattable, MVideoAbuseVideo } from '../../typings/models'
import * as Bluebird from 'bluebird'
@Table({
})
}
- toFormattedJSON (this: MVideoAbuseAccountVideo): VideoAbuse {
+ toFormattedJSON (this: MVideoAbuseFormattable): VideoAbuse {
return {
id: this.id,
reason: this.reason,
import { FindOptions } from 'sequelize'
import { ThumbnailModel } from './thumbnail'
import * as Bluebird from 'bluebird'
-import { MVideoBlacklist } from '@server/typings/models'
+import { MVideoBlacklist, MVideoBlacklistFormattable } from '@server/typings/models'
@Table({
tableName: 'videoBlacklist',
return VideoBlacklistModel.findOne(query)
}
- toFormattedJSON (): VideoBlacklist {
+ toFormattedJSON (this: MVideoBlacklistFormattable): VideoBlacklist {
return {
id: this.id,
createdAt: this.createdAt,
import { remove } from 'fs-extra'
import { CONFIG } from '../../initializers/config'
import * as Bluebird from 'bluebird'
-import { MVideoCaptionVideo } from '@server/typings/models'
+import { MVideoCaptionFormattable, MVideoCaptionVideo } from '@server/typings/models'
export enum ScopeNames {
WITH_VIDEO_UUID_AND_REMOTE = 'WITH_VIDEO_UUID_AND_REMOTE'
return this.Video.remote === false
}
- toFormattedJSON (): VideoCaption {
+ toFormattedJSON (this: MVideoCaptionFormattable): VideoCaption {
return {
language: {
id: this.language,
}
}
- getCaptionStaticPath () {
+ getCaptionStaticPath (this: MVideoCaptionFormattable) {
return join(LAZY_STATIC_PATHS.VIDEO_CAPTIONS, this.getCaptionName())
}
- getCaptionName () {
+ getCaptionName (this: MVideoCaptionFormattable) {
return `${this.Video.uuid}-${this.language}.vtt`
}
- removeCaptionFile () {
+ removeCaptionFile (this: MVideoCaptionFormattable) {
return remove(CONFIG.STORAGE.CAPTIONS_DIR + this.getCaptionName())
}
}
import { ScopeNames as VideoScopeNames, VideoModel } from './video'
import { VideoChangeOwnership, VideoChangeOwnershipStatus } from '../../../shared/models/videos'
import { getSort } from '../utils'
-import { MVideoChangeOwnershipFull } from '@server/typings/models/video/video-change-ownership'
+import { MVideoChangeOwnershipFormattable, MVideoChangeOwnershipFull } from '@server/typings/models/video/video-change-ownership'
import * as Bluebird from 'bluebird'
enum ScopeNames {
.findByPk(id)
}
- toFormattedJSON (): VideoChangeOwnership {
+ toFormattedJSON (this: MVideoChangeOwnershipFormattable): VideoChangeOwnership {
return {
id: this.id,
status: this.status,
import {
MChannelAccountDefault,
MChannelActor,
- MChannelActorAccountDefaultVideos
+ MChannelActorAccountDefaultVideos, MChannelSummaryFormattable, MChannelFormattable
} from '../../typings/models/video'
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
.findByPk(id, options)
}
- toFormattedJSON (): VideoChannel {
+ toFormattedSummaryJSON (this: MChannelSummaryFormattable): VideoChannelSummary {
+ const actor = this.Actor.toFormattedSummaryJSON()
+
+ return {
+ id: this.id,
+ name: actor.name,
+ displayName: this.getDisplayName(),
+ url: actor.url,
+ host: actor.host,
+ avatar: actor.avatar
+ }
+ }
+
+ toFormattedJSON (this: MChannelFormattable): VideoChannel {
const actor = this.Actor.toFormattedJSON()
const videoChannel = {
id: this.id,
return Object.assign(actor, videoChannel)
}
- toFormattedSummaryJSON (): VideoChannelSummary {
- const actor = this.Actor.toFormattedJSON()
-
- return {
- id: this.id,
- name: actor.name,
- displayName: this.getDisplayName(),
- url: actor.url,
- host: actor.host,
- avatar: actor.avatar
- }
- }
-
toActivityPubObject (): ActivityPubActor {
const obj = this.Actor.toActivityPubObject(this.name, 'VideoChannel')
import * as Bluebird from 'bluebird'
import {
MComment,
+ MCommentFormattable,
MCommentId,
MCommentOwner,
MCommentOwnerReplyVideoLight,
return uniq(result)
}
- toFormattedJSON () {
+ toFormattedJSON (this: MCommentFormattable) {
return {
id: this.id,
url: this.url,
} from '../../lib/activitypub'
import { isArray } from '../../helpers/custom-validators/misc'
import { VideoStreamingPlaylist } from '../../../shared/models/videos/video-streaming-playlist.model'
-import { MVideo, MVideoAP, MVideoDetails } from '../../typings/models'
+import { MVideo, MVideoAP, MVideoFormattable, MVideoFormattableDetails } from '../../typings/models'
import { MStreamingPlaylistRedundancies } from '../../typings/models/video/video-streaming-playlist'
import { MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file'
blacklistInfo?: boolean
}
}
-function videoModelToFormattedJSON (video: VideoModel, options?: VideoFormattingJSONOptions): Video {
+function videoModelToFormattedJSON (video: MVideoFormattable, options?: VideoFormattingJSONOptions): Video {
const userHistory = isArray(video.UserVideoHistories) ? video.UserVideoHistories[0] : undefined
const videoObject: Video = {
return videoObject
}
-function videoModelToFormattedDetailsJSON (video: MVideoDetails): VideoDetails {
+function videoModelToFormattedDetailsJSON (video: MVideoFormattableDetails): VideoDetails {
const formattedJson = video.toFormattedJSON({
additionalAttributes: {
scheduledUpdate: true,
import { isVideoMagnetUriValid } from '../../helpers/custom-validators/videos'
import { UserModel } from '../account/user'
import * as Bluebird from 'bluebird'
-import { MVideoImportDefault } from '@server/typings/models/video/video-import'
+import { MVideoImportDefault, MVideoImportFormattable } from '@server/typings/models/video/video-import'
@DefaultScope(() => ({
include: [
return this.targetUrl || this.magnetUri || this.torrentName
}
- toFormattedJSON (): VideoImport {
+ toFormattedJSON (this: MVideoImportFormattable): VideoImport {
const videoFormatOptions = {
completeDescription: true,
additionalAttributes: { state: true, waitTranscoding: true, scheduledUpdate: true }
import { PlaylistElementObject } from '../../../shared/models/activitypub/objects/playlist-element-object'
import * as validator from 'validator'
import { AggregateOptions, Op, ScopeOptions, Sequelize, Transaction } from 'sequelize'
-import { UserModel } from '../account/user'
import { VideoPlaylistElement, VideoPlaylistElementType } from '../../../shared/models/videos/playlist/video-playlist-element.model'
import { AccountModel } from '../account/account'
import { VideoPrivacy } from '../../../shared/models/videos'
import * as Bluebird from 'bluebird'
-import { MVideoPlaylistAP, MVideoPlaylistElement, MVideoPlaylistVideoThumbnail } from '@server/typings/models/video/video-playlist-element'
+import {
+ MVideoPlaylistElement,
+ MVideoPlaylistElementAP,
+ MVideoPlaylistElementFormattable,
+ MVideoPlaylistVideoThumbnail
+} from '@server/typings/models/video/video-playlist-element'
import { MUserAccountId } from '@server/typings/models'
@Table({
return VideoPlaylistElementModel.findByPk(playlistElementId)
}
- static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string): Bluebird<MVideoPlaylistAP> {
+ static loadByPlaylistAndVideoForAP (playlistId: number | string, videoId: number | string): Bluebird<MVideoPlaylistElementAP> {
const playlistWhere = validator.isUUID('' + playlistId) ? { uuid: playlistId } : { id: playlistId }
const videoWhere = validator.isUUID('' + videoId) ? { uuid: videoId } : { id: videoId }
return VideoPlaylistElementModel.increment({ position: by }, query)
}
- getType (displayNSFW?: boolean, accountId?: number) {
+ getType (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) {
const video = this.Video
if (!video) return VideoPlaylistElementType.DELETED
return VideoPlaylistElementType.REGULAR
}
- getVideoElement (displayNSFW?: boolean, accountId?: number) {
+ getVideoElement (this: MVideoPlaylistElementFormattable, displayNSFW?: boolean, accountId?: number) {
if (!this.Video) return null
if (this.getType(displayNSFW, accountId) !== VideoPlaylistElementType.REGULAR) return null
return this.Video.toFormattedJSON()
}
- toFormattedJSON (options: { displayNSFW?: boolean, accountId?: number } = {}): VideoPlaylistElement {
+ toFormattedJSON (
+ this: MVideoPlaylistElementFormattable,
+ options: { displayNSFW?: boolean, accountId?: number } = {}
+ ): VideoPlaylistElement {
return {
id: this.id,
position: this.position,
import * as Bluebird from 'bluebird'
import {
MVideoPlaylistAccountThumbnail,
+ MVideoPlaylistFormattable,
MVideoPlaylistFull,
MVideoPlaylistFullSummary,
MVideoPlaylistIdWithElements
return isOutdated(this, ACTIVITY_PUB.VIDEO_PLAYLIST_REFRESH_INTERVAL)
}
- toFormattedJSON (): VideoPlaylist {
+ toFormattedJSON (this: MVideoPlaylistFormattable): VideoPlaylist {
return {
id: this.id,
uuid: this.uuid,
MVideoFullLight,
MVideoIdThumbnail,
MVideoThumbnail,
- MVideoWithAllFiles,
- MVideoWithRights
+ MVideoWithAllFiles, MVideoWithFile,
+ MVideoWithRights,
+ MVideoFormattable
} from '../../typings/models'
import { MVideoFile, MVideoFileRedundanciesOpt } from '../../typings/models/video/video-file'
import { MThumbnail } from '../../typings/models/video/thumbnail'
this.VideoChannel.Account.isBlocked()
}
- getOriginalFile () {
+ getOriginalFile <T extends MVideoWithFile> (this: T) {
if (Array.isArray(this.VideoFiles) === false) return undefined
// The original file is the file that have the higher resolution
return maxBy(this.VideoFiles, file => file.resolution)
}
- getFile (resolution: number) {
+ getFile <T extends MVideoWithFile> (this: T, resolution: number) {
if (Array.isArray(this.VideoFiles) === false) return undefined
return this.VideoFiles.find(f => f.resolution === resolution)
return join(LAZY_STATIC_PATHS.PREVIEWS, preview.filename)
}
- toFormattedJSON (options?: VideoFormattingJSONOptions): Video {
+ toFormattedJSON <T extends MVideoFormattable> (this: T, options?: VideoFormattingJSONOptions): Video {
return videoModelToFormattedJSON(this, options)
}
import { AccountBlocklistModel } from '../../../models/account/account-blocklist'
import { PickWith } from '../../utils'
-import { MAccountDefault } from './account'
+import { MAccountDefault, MAccountFormattable } from './account'
type Use<K extends keyof AccountBlocklistModel, M> = PickWith<AccountBlocklistModel, K, M>
export type MAccountBlocklistAccounts = MAccountBlocklist &
Use<'ByAccount', MAccountDefault> &
Use<'BlockedAccount', MAccountDefault>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MAccountBlocklistFormattable = Pick<MAccountBlocklist, 'createdAt'> &
+ Use<'ByAccount', MAccountFormattable> &
+ Use<'BlockedAccount', MAccountFormattable>
MActorId,
MActorServer,
MActorSummary,
- MActorUrl
+ MActorSummaryFormattable,
+ MActorUrl,
+ MActorFormattable
} from './actor'
-import { PickWith } from '../../utils'
+import { FunctionProperties, PickWith } from '../../utils'
import { MAccountBlocklistId } from './account-blocklist'
import { MChannelDefault } from '@server/typings/models'
// For API
-export type MAccountSummary = Pick<MAccount, 'id' | 'name'> &
+export type MAccountSummary = FunctionProperties<MAccount> &
+ Pick<MAccount, 'id' | 'name'> &
Use<'Actor', MActorSummary>
export type MAccountSummaryBlocks = MAccountSummary &
export type MAccountAPI = MAccount &
Use<'Actor', MActorAPI>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MAccountSummaryFormattable = FunctionProperties<MAccount> &
+ Pick<MAccount, 'id' | 'name'> &
+ Use<'Actor', MActorSummaryFormattable>
+
+export type MAccountFormattable = FunctionProperties<MAccount> &
+ Pick<MAccount, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'userId'> &
+ Use<'Actor', MActorFormattable>
MActor,
MActorAccount,
MActorAccountChannel,
- MActorChannel,
MActorChannelAccountActor,
MActorDefault,
+ MActorFormattable,
MActorHost,
MActorUsername
} from './actor'
import { PickWith } from '../../utils'
import { ActorModel } from '@server/models/activitypub/actor'
+import { MChannelDefault } from '@server/typings/models'
type Use<K extends keyof ActorFollowModel, M> = PickWith<ActorFollowModel, K, M>
// For subscriptions
+type SubscriptionFollowing = MActorDefault &
+ PickWith<ActorModel, 'VideoChannel', MChannelDefault>
+
export type MActorFollowActorsDefaultSubscription = MActorFollow &
Use<'ActorFollower', MActorDefault> &
- Use<'ActorFollowing', MActorDefault & MActorChannel>
+ Use<'ActorFollowing', SubscriptionFollowing>
export type MActorFollowFollowingFullFollowerAccount = MActorFollow &
Use<'ActorFollower', MActorAccount> &
export type MActorFollowSubscriptions = MActorFollow &
Use<'ActorFollowing', MActorChannelAccountActor>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MActorFollowFormattable = Pick<MActorFollow, 'id' | 'score' | 'state' | 'createdAt' | 'updatedAt'> &
+ Use<'ActorFollower', MActorFormattable> &
+ Use<'ActorFollowing', MActorFormattable>
import { ActorModel } from '../../../models/activitypub/actor'
-import { PickWith } from '../../utils'
+import { FunctionProperties, PickWith } from '../../utils'
import { MAccount, MAccountDefault, MAccountId, MAccountIdActor } from './account'
-import { MServer, MServerHost, MServerHostBlocks } from '../server'
-import { MAvatar } from './avatar'
+import { MServer, MServerHost, MServerHostBlocks, MServerRedundancyAllowed } from '../server'
+import { MAvatar, MAvatarFormattable } from './avatar'
import { MChannel, MChannelAccountActor, MChannelAccountDefault, MChannelId, MChannelIdActor } from '../video'
type Use<K extends keyof ActorModel, M> = PickWith<ActorModel, K, M>
// Some association attributes
export type MActorHost = Use<'Server', MServerHost>
+export type MActorRedundancyAllowed = Use<'Server', MServerRedundancyAllowed>
export type MActorDefaultLight = MActorLight &
Use<'Server', MServerHost> &
// API
-export type MActorSummary = Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> &
+export type MActorSummary = FunctionProperties<MActor> &
+ Pick<MActor, 'id' | 'preferredUsername' | 'url' | 'serverId' | 'avatarId'> &
Use<'Server', MServerHost> &
Use<'Avatar', MAvatar>
export type MActorAPI = Omit<MActorDefault, 'publicKey' | 'privateKey' | 'inboxUrl' | 'outboxUrl' | 'sharedInboxUrl' |
'followersUrl' | 'followingUrl' | 'url' | 'createdAt' | 'updatedAt'>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MActorSummaryFormattable = FunctionProperties<MActor> &
+ Pick<MActor, 'url' | 'preferredUsername'> &
+ Use<'Server', MServerHost> &
+ Use<'Avatar', MAvatarFormattable>
+
+export type MActorFormattable = MActorSummaryFormattable &
+ Pick<MActor, 'id' | 'followingCount' | 'followersCount' | 'createdAt' | 'updatedAt'> &
+ Use<'Server', MServer>
import { AvatarModel } from '../../../models/avatar/avatar'
+import { FunctionProperties } from '@server/typings/utils'
export type MAvatar = AvatarModel
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MAvatarFormattable = FunctionProperties<MAvatar> &
+ Pick<MAvatar, 'filename' | 'createdAt' | 'updatedAt'>
import { PluginModel } from '@server/models/server/plugin'
export type MPlugin = PluginModel
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MPluginFormattable = Pick<MPlugin, 'name' | 'type' | 'version' | 'latestVersion' | 'enabled' | 'uninstalled'
+ | 'peertubeEngine' | 'description' | 'homepage' | 'settings' | 'createdAt' | 'updatedAt'>
import { ServerBlocklistModel } from '@server/models/server/server-blocklist'
import { PickWith } from '@server/typings/utils'
-import { MAccountDefault, MServer } from '@server/typings/models'
+import { MAccountDefault, MAccountFormattable, MServer, MServerFormattable } from '@server/typings/models'
type Use<K extends keyof ServerBlocklistModel, M> = PickWith<ServerBlocklistModel, K, M>
export type MServerBlocklistAccountServer = MServerBlocklist &
Use<'ByAccount', MAccountDefault> &
Use<'BlockedServer', MServer>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MServerBlocklistFormattable = Pick<MServerBlocklist, 'createdAt'> &
+ Use<'ByAccount', MAccountFormattable> &
+ Use<'BlockedServer', MServerFormattable>
import { ServerModel } from '../../../models/server/server'
-import { PickWith } from '../../utils'
+import { FunctionProperties, PickWith } from '../../utils'
import { MAccountBlocklistId } from '../account'
type Use<K extends keyof ServerModel, M> = PickWith<ServerModel, K, M>
// ############################################################################
export type MServerHost = Pick<MServer, 'host'>
+export type MServerRedundancyAllowed = Pick<MServer, 'redundancyAllowed'>
export type MServerHostBlocks = MServerHost &
Use<'BlockedByAccounts', MAccountBlocklistId[]>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MServerFormattable = FunctionProperties<MServer> &
+ Pick<MServer, 'host'>
import { UserNotificationSettingModel } from '@server/models/account/user-notification-setting'
export type MNotificationSetting = Omit<UserNotificationSettingModel, 'User'>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MNotificationSettingFormattable = MNotificationSetting
import { UserModel } from '../../../models/account/user'
-import { PickWith } from '../../utils'
-import { MAccount, MAccountDefault, MAccountDefaultChannelDefault, MAccountId, MAccountIdActorId, MAccountUrl } from '../account'
-import { MNotificationSetting } from './user-notification-setting'
+import { PickWith, PickWithOpt } from '../../utils'
+import {
+ MAccount,
+ MAccountDefault,
+ MAccountDefaultChannelDefault,
+ MAccountFormattable,
+ MAccountId,
+ MAccountIdActorId,
+ MAccountUrl
+} from '../account'
+import { MNotificationSetting, MNotificationSettingFormattable } from './user-notification-setting'
+import { AccountModel } from '@server/models/account/account'
+import { MChannelFormattable } from '@server/typings/models'
type Use<K extends keyof UserModel, M> = PickWith<UserModel, K, M>
// ############################################################################
+export type MUserQuotaUsed = MUser & { videoQuotaUsed?: number, videoQuotaUsedDaily?: number }
export type MUserId = Pick<UserModel, 'id'>
// ############################################################################
export type MUserDefault = MUser &
Use<'NotificationSetting', MNotificationSetting> &
Use<'Account', MAccountDefault>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MUserFormattable = MUserQuotaUsed &
+ Use<'Account', MAccountFormattable & PickWithOpt<AccountModel, 'VideoChannels', MChannelFormattable[]>> &
+ PickWithOpt<UserModel, 'NotificationSetting', MNotificationSettingFormattable>
import { ScheduleVideoUpdateModel } from '../../../models/video/schedule-video-update'
export type MScheduleVideoUpdate = Omit<ScheduleVideoUpdateModel, 'Video'>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MScheduleVideoUpdateFormattable = Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>
import { VideoAbuseModel } from '../../../models/video/video-abuse'
import { PickWith } from '../../utils'
import { MVideo } from './video'
-import { MAccountDefault } from '../account'
+import { MAccountDefault, MAccountFormattable } from '../account'
type Use<K extends keyof VideoAbuseModel, M> = PickWith<VideoAbuseModel, K, M>
Pick<VideoAbuseModel, 'toActivityPubObject'> &
Use<'Video', MVideo> &
Use<'Account', MAccountDefault>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoAbuseFormattable = MVideoAbuse &
+ Use<'Account', MAccountFormattable> &
+ Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'name'>>
import { VideoBlacklistModel } from '../../../models/video/video-blacklist'
import { PickWith } from '@server/typings/utils'
-import { MVideo } from '@server/typings/models'
+import { MVideo, MVideoFormattable } from '@server/typings/models'
type Use<K extends keyof VideoBlacklistModel, M> = PickWith<VideoBlacklistModel, K, M>
export type MVideoBlacklistVideo = MVideoBlacklist &
Use<'Video', MVideo>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoBlacklistFormattable = MVideoBlacklist &
+ Use<'Video', MVideoFormattable>
import { VideoCaptionModel } from '../../../models/video/video-caption'
-import { PickWith } from '@server/typings/utils'
-import { VideoModel } from '@server/models/video/video'
+import { FunctionProperties, PickWith } from '@server/typings/utils'
+import { MVideo, MVideoUUID } from '@server/typings/models'
type Use<K extends keyof VideoCaptionModel, M> = PickWith<VideoCaptionModel, K, M>
export type MVideoCaptionLanguage = Pick<MVideoCaption, 'language'>
export type MVideoCaptionVideo = MVideoCaption &
- Use<'Video', Pick<VideoModel, 'id' | 'remote' | 'uuid'>>
+ Use<'Video', Pick<MVideo, 'id' | 'remote' | 'uuid'>>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoCaptionFormattable = FunctionProperties<MVideoCaption> &
+ Pick<MVideoCaption, 'language'> &
+ Use<'Video', MVideoUUID>
import { VideoChangeOwnershipModel } from '@server/models/video/video-change-ownership'
import { PickWith } from '@server/typings/utils'
-import { MAccountDefault, MVideoWithFileThumbnail } from '@server/typings/models'
+import { MAccountDefault, MAccountFormattable, MVideo, MVideoWithFileThumbnail } from '@server/typings/models'
type Use<K extends keyof VideoChangeOwnershipModel, M> = PickWith<VideoChangeOwnershipModel, K, M>
Use<'Initiator', MAccountDefault> &
Use<'NextOwner', MAccountDefault> &
Use<'Video', MVideoWithFileThumbnail>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoChangeOwnershipFormattable = Pick<MVideoChangeOwnership, 'id' | 'status' | 'createdAt'> &
+ Use<'Initiator', MAccountFormattable> &
+ Use<'NextOwner', MAccountFormattable> &
+ Use<'Video', Pick<MVideo, 'id' | 'uuid' | 'url' | 'name'>>
-import { PickWith } from '../../utils'
+import { FunctionProperties, PickWith, PickWithOpt } from '../../utils'
import { VideoChannelModel } from '../../../models/video/video-channel'
import {
MAccountActor,
MAccountAPI,
MAccountDefault,
+ MAccountFormattable,
MAccountLight,
MAccountSummaryBlocks,
+ MAccountSummaryFormattable,
MAccountUserId,
MActor,
MActorAccountChannelId,
MActorAPI,
MActorDefault,
MActorDefaultLight,
+ MActorFormattable,
MActorLight,
- MActorSummary
+ MActorSummary,
+ MActorSummaryFormattable
} from '../account'
import { MVideo } from './video'
// For API
-export type MChannelSummary = Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> &
+export type MChannelSummary = FunctionProperties<MChannel> &
+ Pick<MChannel, 'id' | 'name' | 'description' | 'actorId'> &
Use<'Actor', MActorSummary>
export type MChannelSummaryAccount = MChannelSummary &
export type MChannelAPI = MChannel &
Use<'Actor', MActorAPI> &
Use<'Account', MAccountAPI>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MChannelSummaryFormattable = FunctionProperties<MChannel> &
+ Pick<MChannel, 'id' | 'name'> &
+ Use<'Actor', MActorSummaryFormattable>
+
+export type MChannelAccountSummaryFormattable = MChannelSummaryFormattable &
+ Use<'Account', MAccountSummaryFormattable>
+
+export type MChannelFormattable = FunctionProperties<MChannel> &
+ Pick<MChannel, 'id' | 'name' | 'description' | 'createdAt' | 'updatedAt' | 'support'> &
+ Use<'Actor', MActorFormattable> &
+ PickWithOpt<VideoChannelModel, 'Account', MAccountFormattable>
import { VideoCommentModel } from '../../../models/video/video-comment'
import { PickWith } from '../../utils'
-import { MAccountDefault } from '../account'
+import { MAccountDefault, MAccountFormattable } from '../account'
import { MVideoAccountLight, MVideoFeed, MVideoIdUrl } from './video'
type Use<K extends keyof VideoCommentModel, M> = PickWith<VideoCommentModel, K, M>
// ############################################################################
export type MComment = Omit<VideoCommentModel, 'OriginVideoComment' | 'InReplyToVideoComment' | 'Video' | 'Account'>
+export type MCommentTotalReplies = MComment & { totalReplies?: number }
export type MCommentId = Pick<MComment, 'id'>
// ############################################################################
// ############################################################################
export type MCommentAPI = MComment & { totalReplies: number }
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MCommentFormattable = MCommentTotalReplies &
+ Use<'Account', MAccountFormattable>
import { VideoImportModel } from '@server/models/video/video-import'
-import { PickWith } from '@server/typings/utils'
-import { MUser, MVideo, MVideoAccountLight, MVideoTag, MVideoThumbnail, MVideoWithFile } from '@server/typings/models'
+import { PickWith, PickWithOpt } from '@server/typings/utils'
+import { MUser, MVideo, MVideoAccountLight, MVideoFormattable, MVideoTag, MVideoThumbnail, MVideoWithFile } from '@server/typings/models'
type Use<K extends keyof VideoImportModel, M> = PickWith<VideoImportModel, K, M>
export type MVideoImportDefaultFiles = MVideoImport &
Use<'User', MUser> &
Use<'Video', VideoAssociation & MVideoWithFile>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoImportFormattable = MVideoImport &
+ PickWithOpt<VideoImportModel, 'Video', MVideoFormattable & MVideoTag>
import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element'
import { PickWith } from '@server/typings/utils'
-import { MVideoPlaylistPrivacy, MVideoThumbnail, MVideoUrl } from '@server/typings/models'
+import { MVideoFormattable, MVideoPlaylistPrivacy, MVideoThumbnail, MVideoUrl } from '@server/typings/models'
type Use<K extends keyof VideoPlaylistElementModel, M> = PickWith<VideoPlaylistElementModel, K, M>
// For API
-export type MVideoPlaylistAP = MVideoPlaylistElement &
+export type MVideoPlaylistElementAP = MVideoPlaylistElement &
Use<'Video', MVideoUrl> &
Use<'VideoPlaylist', MVideoPlaylistPrivacy>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoPlaylistElementFormattable = MVideoPlaylistElement &
+ Use<'Video', MVideoFormattable>
import { VideoPlaylistModel } from '../../../models/video/video-playlist'
import { PickWith } from '../../utils'
-import { MAccount, MAccountDefault, MAccountSummary } from '../account'
+import { MAccount, MAccountDefault, MAccountSummary, MAccountSummaryFormattable } from '../account'
import { MThumbnail } from './thumbnail'
-import { MChannelDefault, MChannelSummary } from './video-channels'
+import { MChannelDefault, MChannelSummary, MChannelSummaryFormattable } from './video-channels'
import { MVideoPlaylistElementLight } from '@server/typings/models/video/video-playlist-element'
type Use<K extends keyof VideoPlaylistModel, M> = PickWith<VideoPlaylistModel, K, M>
export type MVideoPlaylistId = Pick<MVideoPlaylist, 'id'>
export type MVideoPlaylistPrivacy = Pick<MVideoPlaylist, 'privacy'>
export type MVideoPlaylistUUID = Pick<MVideoPlaylist, 'uuid'>
-export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength: number }
+export type MVideoPlaylistVideosLength = MVideoPlaylist & { videosLength?: number }
// ############################################################################
Use<'Thumbnail', MThumbnail> &
Use<'OwnerAccount', MAccountSummary> &
Use<'VideoChannel', MChannelSummary>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoPlaylistFormattable = MVideoPlaylistVideosLength &
+ Use<'OwnerAccount', MAccountSummaryFormattable> &
+ Use<'VideoChannel', MChannelSummaryFormattable>
import { AccountVideoRateModel } from '@server/models/account/account-video-rate'
import { PickWith } from '@server/typings/utils'
-import { MAccountAudience, MAccountUrl, MVideo } from '..'
+import { MAccountAudience, MAccountUrl, MVideo, MVideoFormattable } from '..'
type Use<K extends keyof AccountVideoRateModel, M> = PickWith<AccountVideoRateModel, K, M>
export type MAccountVideoRateAccountVideo = MAccountVideoRate &
Use<'Account', MAccountAudience> &
Use<'Video', MVideo>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MAccountVideoRateFormattable = Pick<MAccountVideoRate, 'type'> &
+ Use<'Video', MVideoFormattable>
import { VideoModel } from '../../../models/video/video'
import { PickWith, PickWithOpt } from '../../utils'
-import { MChannelAccountDefault, MChannelAccountLight, MChannelActor, MChannelUserId } from './video-channels'
+import {
+ MChannelAccountDefault,
+ MChannelAccountLight,
+ MChannelAccountSummaryFormattable,
+ MChannelActor,
+ MChannelFormattable,
+ MChannelUserId
+} from './video-channels'
import { MTag } from './tag'
import { MVideoCaptionLanguage } from './video-caption'
import { MStreamingPlaylist, MStreamingPlaylistRedundancies } from './video-streaming-playlist'
import { MVideoFile, MVideoFileRedundanciesOpt } from './video-file'
import { MThumbnail } from './thumbnail'
-import { MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist'
+import { MVideoBlacklist, MVideoBlacklistLight, MVideoBlacklistUnfederated } from './video-blacklist'
import { MScheduleVideoUpdate } from './schedule-video-update'
import { MUserVideoHistoryTime } from '../user/user-video-history'
Use<'ScheduleVideoUpdate', MScheduleVideoUpdate> &
Use<'VideoBlacklist', MVideoBlacklistLight> &
Use<'Thumbnails', MThumbnail[]>
+
+// ############################################################################
+
+// Format for API or AP object
+
+export type MVideoFormattable = MVideo &
+ PickWithOpt<VideoModel, 'UserVideoHistories', MUserVideoHistoryTime[]> &
+ Use<'VideoChannel', MChannelAccountSummaryFormattable> &
+ PickWithOpt<VideoModel, 'ScheduleVideoUpdate', Pick<MScheduleVideoUpdate, 'updateAt' | 'privacy'>> &
+ PickWithOpt<VideoModel, 'VideoBlacklist', Pick<MVideoBlacklist, 'reason'>>
+
+export type MVideoFormattableDetails = MVideoFormattable &
+ Use<'VideoChannel', MChannelFormattable> &
+ Use<'Tags', MTag[]> &
+ Use<'VideoStreamingPlaylists', MStreamingPlaylistRedundancies[]> &
+ Use<'VideoFiles', MVideoFileRedundanciesOpt[]>
export type FunctionProperties<T> = Pick<T, FunctionPropertyNames<T>>
-export type ValueOf <T, KT extends keyof T> = T[KT]
-
export type PickWith<T, KT extends keyof T, V> = {
[P in KT]: T[P] extends V ? V : never
}