videoModelToFormattedDetailsJSON,
videoModelToFormattedJSON
} from './video-format-utils'
+import * as validator from 'validator'
+import { UserVideoHistoryModel } from '../account/user-video-history'
// FIXME: Define indexes here because there is an issue with TS and Sequelize.literal when called directly in the annotation
const indexes: Sequelize.DefineIndexesOptions[] = [
WITH_TAGS = 'WITH_TAGS',
WITH_FILES = 'WITH_FILES',
WITH_SCHEDULED_UPDATE = 'WITH_SCHEDULED_UPDATE',
- WITH_BLACKLISTED = 'WITH_BLACKLISTED'
+ WITH_BLACKLISTED = 'WITH_BLACKLISTED',
+ WITH_USER_HISTORY = 'WITH_USER_HISTORY'
}
type ForAPIOptions = {
include: [
{
model: () => VideoFileModel.unscoped(),
+ // FIXME: typings
+ [ 'separate' as any ]: true, // We may have multiple files, having multiple redundancies so let's separate this join
required: false,
include: [
{
+ attributes: [ 'fileUrl' ],
model: () => VideoRedundancyModel.unscoped(),
required: false
}
required: false
}
]
+ },
+ [ ScopeNames.WITH_USER_HISTORY ]: (userId: number) => {
+ return {
+ include: [
+ {
+ attributes: [ 'currentTime' ],
+ model: UserVideoHistoryModel.unscoped(),
+ required: false,
+ where: {
+ userId
+ }
+ }
+ ]
+ }
}
})
@Table({
@Column
commentsEnabled: boolean
+ @AllowNull(false)
+ @Column
+ downloadingEnabled: boolean
+
@AllowNull(false)
@Column
waitTranscoding: boolean
name: 'videoId',
allowNull: false
},
- onDelete: 'cascade',
- hooks: true
+ onDelete: 'cascade'
})
VideoViews: VideoViewModel[]
+ @HasMany(() => UserVideoHistoryModel, {
+ foreignKey: {
+ name: 'videoId',
+ allowNull: false
+ },
+ onDelete: 'cascade'
+ })
+ UserVideoHistories: UserVideoHistoryModel[]
+
@HasOne(() => ScheduleVideoUpdateModel, {
foreignKey: {
name: 'videoId',
accountId?: number,
videoChannelId?: number,
actorId?: number
- trendingDays?: number
+ trendingDays?: number,
+ userId?: number
}, countVideos = true) {
const query: IFindOptions<VideoModel> = {
offset: options.start,
accountId: options.accountId,
videoChannelId: options.videoChannelId,
includeLocalVideos: options.includeLocalVideos,
+ userId: options.userId,
trendingDays
}
tagsAllOf?: string[]
durationMin?: number // seconds
durationMax?: number // seconds
+ userId?: number
}) {
const whereAnd = []
licenceOneOf: options.licenceOneOf,
languageOneOf: options.languageOneOf,
tagsOneOf: options.tagsOneOf,
- tagsAllOf: options.tagsAllOf
+ tagsAllOf: options.tagsAllOf,
+ userId: options.userId
}
return VideoModel.getAvailableForApi(query, queryOptions)
}
- static load (id: number, t?: Sequelize.Transaction) {
- return VideoModel.findById(id, { transaction: t })
+ static load (id: number | string, t?: Sequelize.Transaction) {
+ const where = VideoModel.buildWhereIdOrUUID(id)
+ const options = {
+ where,
+ transaction: t
+ }
+
+ return VideoModel.findOne(options)
+ }
+
+ static loadOnlyId (id: number | string, t?: Sequelize.Transaction) {
+ const where = VideoModel.buildWhereIdOrUUID(id)
+
+ const options = {
+ attributes: [ 'id' ],
+ where,
+ transaction: t
+ }
+
+ return VideoModel.findOne(options)
}
static loadWithFile (id: number, t?: Sequelize.Transaction, logging?: boolean) {
.findById(id, { transaction: t, logging })
}
- static loadByUrlAndPopulateAccount (url: string, t?: Sequelize.Transaction) {
- const query: IFindOptions<VideoModel> = {
+ static loadByUUIDWithFile (uuid: string) {
+ const options = {
where: {
- url
+ uuid
}
}
- if (t !== undefined) query.transaction = t
-
- return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query)
+ return VideoModel
+ .scope([ ScopeNames.WITH_FILES ])
+ .findOne(options)
}
- static loadAndPopulateAccountAndServerAndTags (id: number) {
- const options = {
- order: [ [ 'Tags', 'name', 'ASC' ] ]
+ static loadByUrl (url: string, transaction?: Sequelize.Transaction) {
+ const query: IFindOptions<VideoModel> = {
+ where: {
+ url
+ },
+ transaction
}
- return VideoModel
- .scope([
- ScopeNames.WITH_TAGS,
- ScopeNames.WITH_BLACKLISTED,
- ScopeNames.WITH_FILES,
- ScopeNames.WITH_ACCOUNT_DETAILS,
- ScopeNames.WITH_SCHEDULED_UPDATE
- ])
- .findById(id, options)
+ return VideoModel.findOne(query)
}
- static loadByUUID (uuid: string) {
- const options = {
+ static loadByUrlAndPopulateAccount (url: string, transaction?: Sequelize.Transaction) {
+ const query: IFindOptions<VideoModel> = {
where: {
- uuid
- }
+ url
+ },
+ transaction
}
- return VideoModel
- .scope([ ScopeNames.WITH_FILES ])
- .findOne(options)
+ return VideoModel.scope([ ScopeNames.WITH_ACCOUNT_DETAILS, ScopeNames.WITH_FILES ]).findOne(query)
}
- static loadByUUIDAndPopulateAccountAndServerAndTags (uuid: string, t?: Sequelize.Transaction) {
+ static loadAndPopulateAccountAndServerAndTags (id: number | string, t?: Sequelize.Transaction, userId?: number) {
+ const where = VideoModel.buildWhereIdOrUUID(id)
+
const options = {
order: [ [ 'Tags', 'name', 'ASC' ] ],
- where: {
- uuid
- },
+ where,
transaction: t
}
+ const scopes = [
+ ScopeNames.WITH_TAGS,
+ ScopeNames.WITH_BLACKLISTED,
+ ScopeNames.WITH_FILES,
+ ScopeNames.WITH_ACCOUNT_DETAILS,
+ ScopeNames.WITH_SCHEDULED_UPDATE
+ ]
+
+ if (userId) {
+ scopes.push({ method: [ ScopeNames.WITH_USER_HISTORY, userId ] } as any) // FIXME: typings
+ }
+
return VideoModel
- .scope([
- ScopeNames.WITH_TAGS,
- ScopeNames.WITH_BLACKLISTED,
- ScopeNames.WITH_FILES,
- ScopeNames.WITH_ACCOUNT_DETAILS,
- ScopeNames.WITH_SCHEDULED_UPDATE
- ])
+ .scope(scopes)
.findOne(options)
}
return {}
}
- private static async getAvailableForApi (query: IFindOptions<VideoModel>, options: AvailableForListIDsOptions, countVideos = true) {
+ private static async getAvailableForApi (
+ query: IFindOptions<VideoModel>,
+ options: AvailableForListIDsOptions & { userId?: number},
+ countVideos = true
+ ) {
const idsScope = {
method: [
ScopeNames.AVAILABLE_FOR_LIST_IDS, options
if (ids.length === 0) return { data: [], total: count }
- const apiScope = {
- method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ]
+ // FIXME: typings
+ const apiScope: any[] = [
+ {
+ method: [ ScopeNames.FOR_API, { ids, withFiles: options.withFiles } as ForAPIOptions ]
+ }
+ ]
+
+ if (options.userId) {
+ apiScope.push({ method: [ ScopeNames.WITH_USER_HISTORY, options.userId ] })
}
const secondQuery = {
return VIDEO_STATES[ id ] || 'Unknown'
}
+ static buildWhereIdOrUUID (id: number | string) {
+ return validator.isInt('' + id) ? { id } : { uuid: id }
+ }
+
getOriginalFile () {
if (Array.isArray(this.VideoFiles) === false) return undefined
return getVideoFileResolution(originalFilePath)
}
- getDescriptionPath () {
+ getDescriptionAPIPath () {
return `/api/${API_VERSION}/videos/${this.uuid}/description`
}