unique: true
},
{
- fields: [ 'url'],
+ fields: [ 'url' ],
unique: true
}
]
}
@Scopes({
- [ScopeNames.FOR_API]: (options: ForAPIOptions) => {
+ [ ScopeNames.FOR_API ]: (options: ForAPIOptions) => {
const accountInclude = {
attributes: [ 'id', 'name' ],
model: AccountModel.unscoped(),
const query: IFindOptions<VideoModel> = {
where: {
id: {
- [Sequelize.Op.any]: options.ids
+ [ Sequelize.Op.any ]: options.ids
}
},
include: [ videoChannelInclude ]
return query
},
- [ScopeNames.AVAILABLE_FOR_LIST_IDS]: (options: AvailableForListIDsOptions) => {
+ [ ScopeNames.AVAILABLE_FOR_LIST_IDS ]: (options: AvailableForListIDsOptions) => {
const query: IFindOptions<VideoModel> = {
attributes: [ 'id' ],
where: {
id: {
- [Sequelize.Op.and]: [
+ [ Sequelize.Op.and ]: [
{
[ Sequelize.Op.notIn ]: Sequelize.literal(
'(SELECT "videoBlacklist"."videoId" FROM "videoBlacklist")'
}
]
},
- include: [ ]
+ include: []
}
if (options.filter || options.accountId || options.videoChannelId) {
// Force actorId to be a number to avoid SQL injections
const actorIdNumber = parseInt(options.actorId.toString(), 10)
- query.where['id'][Sequelize.Op.and].push({
+ query.where[ 'id' ][ Sequelize.Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal(
'(' +
- 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
- 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
- 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
- ' UNION ALL ' +
- 'SELECT "video"."id" AS "id" FROM "video" ' +
- 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
- 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
- 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
- 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
- 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
- localVideosReq +
+ 'SELECT "videoShare"."videoId" AS "id" FROM "videoShare" ' +
+ 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "videoShare"."actorId" ' +
+ 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
+ ' UNION ALL ' +
+ 'SELECT "video"."id" AS "id" FROM "video" ' +
+ 'INNER JOIN "videoChannel" ON "videoChannel"."id" = "video"."channelId" ' +
+ 'INNER JOIN "account" ON "account"."id" = "videoChannel"."accountId" ' +
+ 'INNER JOIN "actor" ON "account"."actorId" = "actor"."id" ' +
+ 'INNER JOIN "actorFollow" ON "actorFollow"."targetActorId" = "actor"."id" ' +
+ 'WHERE "actorFollow"."actorId" = ' + actorIdNumber +
+ localVideosReq +
')'
)
})
}
if (options.withFiles === true) {
- query.where['id'][Sequelize.Op.and].push({
+ query.where[ 'id' ][ Sequelize.Op.and ].push({
[ Sequelize.Op.in ]: Sequelize.literal(
'(SELECT "videoId" FROM "videoFile")'
)
}
if (options.tagsOneOf) {
- query.where['id'][Sequelize.Op.and].push({
- [Sequelize.Op.in]: Sequelize.literal(
+ query.where[ 'id' ][ Sequelize.Op.and ].push({
+ [ Sequelize.Op.in ]: Sequelize.literal(
'(' +
'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
}
if (options.tagsAllOf) {
- query.where['id'][Sequelize.Op.and].push({
- [Sequelize.Op.in]: Sequelize.literal(
+ query.where[ 'id' ][ Sequelize.Op.and ].push({
+ [ Sequelize.Op.in ]: Sequelize.literal(
'(' +
'SELECT "videoId" FROM "videoTag" ' +
'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
}
if (options.nsfw === true || options.nsfw === false) {
- query.where['nsfw'] = options.nsfw
+ query.where[ 'nsfw' ] = options.nsfw
}
if (options.categoryOneOf) {
- query.where['category'] = {
- [Sequelize.Op.or]: options.categoryOneOf
+ query.where[ 'category' ] = {
+ [ Sequelize.Op.or ]: options.categoryOneOf
}
}
if (options.licenceOneOf) {
- query.where['licence'] = {
- [Sequelize.Op.or]: options.licenceOneOf
+ query.where[ 'licence' ] = {
+ [ Sequelize.Op.or ]: options.licenceOneOf
}
}
if (options.languageOneOf) {
- query.where['language'] = {
- [Sequelize.Op.or]: options.languageOneOf
+ query.where[ 'language' ] = {
+ [ Sequelize.Op.or ]: options.languageOneOf
}
}
return query
},
- [ScopeNames.WITH_ACCOUNT_DETAILS]: {
+ [ ScopeNames.WITH_ACCOUNT_DETAILS ]: {
include: [
{
model: () => VideoChannelModel.unscoped(),
}
]
},
- [ScopeNames.WITH_TAGS]: {
+ [ ScopeNames.WITH_TAGS ]: {
include: [ () => TagModel ]
},
- [ScopeNames.WITH_BLACKLISTED]: {
+ [ ScopeNames.WITH_BLACKLISTED ]: {
include: [
{
attributes: [ 'id', 'reason' ],
}
]
},
- [ScopeNames.WITH_FILES]: {
+ [ ScopeNames.WITH_FILES ]: {
include: [
{
model: () => VideoFileModel.unscoped(),
}
]
},
- [ScopeNames.WITH_SCHEDULED_UPDATE]: {
+ [ ScopeNames.WITH_SCHEDULED_UPDATE ]: {
include: [
{
model: () => ScheduleVideoUpdateModel.unscoped(),
},
onDelete: 'cascade',
hooks: true,
- ['separate' as any]: true
+ [ 'separate' as any ]: true
})
VideoCaptions: VideoCaptionModel[]
// Do not wait video deletion because we could be in a transaction
Promise.all(tasks)
- .catch(err => {
- logger.error('Some errors when removing files of video %s in before destroy hook.', instance.uuid, { err })
- })
+ .catch(err => {
+ logger.error('Some errors when removing files of video %s in before destroy hook.', instance.uuid, { err })
+ })
return undefined
}
order: getVideoSort('createdAt', [ 'Tags', 'name', 'ASC' ]),
where: {
id: {
- [Sequelize.Op.in]: Sequelize.literal('(' + rawQuery + ')')
+ [ Sequelize.Op.in ]: Sequelize.literal('(' + rawQuery + ')')
},
- [Sequelize.Op.or]: [
+ [ Sequelize.Op.or ]: [
{ privacy: VideoPrivacy.PUBLIC },
{ privacy: VideoPrivacy.UNLISTED }
]
required: false,
// We only want videos shared by this actor
where: {
- [Sequelize.Op.and]: [
+ [ Sequelize.Op.and ]: [
{
id: {
- [Sequelize.Op.not]: null
+ [ Sequelize.Op.not ]: null
}
},
{
// totals: totalVideos + totalVideoShares
let totalVideos = 0
let totalVideoShares = 0
- if (totals[0]) totalVideos = parseInt(totals[0].total, 10)
- if (totals[1]) totalVideoShares = parseInt(totals[1].total, 10)
+ if (totals[ 0 ]) totalVideos = parseInt(totals[ 0 ].total, 10)
+ if (totals[ 1 ]) totalVideoShares = parseInt(totals[ 1 ].total, 10)
const total = totalVideos + totalVideoShares
return {
durationMin?: number // seconds
durationMax?: number // seconds
}) {
- const whereAnd = [ ]
+ const whereAnd = []
if (options.startDate || options.endDate) {
- const publishedAtRange = { }
+ const publishedAtRange = {}
- if (options.startDate) publishedAtRange[Sequelize.Op.gte] = options.startDate
- if (options.endDate) publishedAtRange[Sequelize.Op.lte] = options.endDate
+ if (options.startDate) publishedAtRange[ Sequelize.Op.gte ] = options.startDate
+ if (options.endDate) publishedAtRange[ Sequelize.Op.lte ] = options.endDate
whereAnd.push({ publishedAt: publishedAtRange })
}
if (options.durationMin || options.durationMax) {
- const durationRange = { }
+ const durationRange = {}
- if (options.durationMin) durationRange[Sequelize.Op.gte] = options.durationMin
- if (options.durationMax) durationRange[Sequelize.Op.lte] = options.durationMax
+ if (options.durationMin) durationRange[ Sequelize.Op.gte ] = options.durationMin
+ if (options.durationMax) durationRange[ Sequelize.Op.lte ] = options.durationMax
whereAnd.push({ duration: durationRange })
}
id: {
[ Sequelize.Op.in ]: Sequelize.literal(
'(' +
- 'SELECT "video"."id" FROM "video" ' +
- 'WHERE ' +
- 'lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' +
- 'lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' +
- 'UNION ALL ' +
- 'SELECT "video"."id" FROM "video" LEFT JOIN "videoTag" ON "videoTag"."videoId" = "video"."id" ' +
- 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
- 'WHERE "tag"."name" = ' + escapedSearch +
+ 'SELECT "video"."id" FROM "video" ' +
+ 'WHERE ' +
+ 'lower(immutable_unaccent("video"."name")) % lower(immutable_unaccent(' + escapedSearch + ')) OR ' +
+ 'lower(immutable_unaccent("video"."name")) LIKE lower(immutable_unaccent(' + escapedLikeSearch + '))' +
+ 'UNION ALL ' +
+ 'SELECT "video"."id" FROM "video" LEFT JOIN "videoTag" ON "videoTag"."videoId" = "video"."id" ' +
+ 'INNER JOIN "tag" ON "tag"."id" = "videoTag"."tagId" ' +
+ 'WHERE "tag"."name" = ' + escapedSearch +
')'
)
}
limit: count,
group: field,
having: Sequelize.where(Sequelize.fn('COUNT', Sequelize.col(field)), {
- [Sequelize.Op.gte]: threshold
+ [ Sequelize.Op.gte ]: threshold
}) as any, // FIXME: typings
where: {
- [field]: {
- [Sequelize.Op.not]: null
+ [ field ]: {
+ [ Sequelize.Op.not ]: null
},
privacy: VideoPrivacy.PUBLIC,
state: VideoState.PUBLISHED
}
return VideoModel.findAll(query)
- .then(rows => rows.map(r => r[field]))
+ .then(rows => rows.map(r => r[ field ]))
}
private static buildActorWhereWithFilter (filter?: VideoFilter) {
]
}
- const { count, rows: rowsId } = await VideoModel.scope(idsScope).findAndCountAll(query)
+ // Remove trending sort on count, because it uses a group by
+ const countOptions = Object.assign({}, options, { trendingDays: undefined })
+ const countQuery = Object.assign({}, query, { attributes: undefined, group: undefined })
+ const countScope = {
+ method: [
+ ScopeNames.AVAILABLE_FOR_LIST_IDS, countOptions
+ ]
+ }
+
+ const [ count, rowsId ] = await Promise.all([
+ VideoModel.scope(countScope).count(countQuery),
+ VideoModel.scope(idsScope).findAll(query)
+ ])
const ids = rowsId.map(r => r.id)
if (ids.length === 0) return { data: [], total: count }
}
private static getCategoryLabel (id: number) {
- return VIDEO_CATEGORIES[id] || 'Misc'
+ return VIDEO_CATEGORIES[ id ] || 'Misc'
}
private static getLicenceLabel (id: number) {
- return VIDEO_LICENCES[id] || 'Unknown'
+ return VIDEO_LICENCES[ id ] || 'Unknown'
}
private static getLanguageLabel (id: string) {
- return VIDEO_LANGUAGES[id] || 'Unknown'
+ return VIDEO_LANGUAGES[ id ] || 'Unknown'
}
private static getPrivacyLabel (id: number) {
- return VIDEO_PRIVACIES[id] || 'Unknown'
+ return VIDEO_PRIVACIES[ id ] || 'Unknown'
}
private static getStateLabel (id: number) {
- return VIDEO_STATES[id] || 'Unknown'
+ return VIDEO_STATES[ id ] || 'Unknown'
}
getOriginalFile () {
const { baseUrlHttp, baseUrlWs } = this.getBaseUrls()
return this.VideoFiles
- .map(videoFile => {
- let resolutionLabel = videoFile.resolution + 'p'
-
- return {
- resolution: {
- id: videoFile.resolution,
- label: resolutionLabel
- },
- magnetUri: this.generateMagnetUri(videoFile, baseUrlHttp, baseUrlWs),
- size: videoFile.size,
- fps: videoFile.fps,
- torrentUrl: this.getTorrentUrl(videoFile, baseUrlHttp),
- torrentDownloadUrl: this.getTorrentDownloadUrl(videoFile, baseUrlHttp),
- fileUrl: this.getVideoFileUrl(videoFile, baseUrlHttp),
- fileDownloadUrl: this.getVideoFileDownloadUrl(videoFile, baseUrlHttp)
- } as VideoFile
- })
- .sort((a, b) => {
- if (a.resolution.id < b.resolution.id) return 1
- if (a.resolution.id === b.resolution.id) return 0
- return -1
- })
+ .map(videoFile => {
+ let resolutionLabel = videoFile.resolution + 'p'
+
+ return {
+ resolution: {
+ id: videoFile.resolution,
+ label: resolutionLabel
+ },
+ magnetUri: this.generateMagnetUri(videoFile, baseUrlHttp, baseUrlWs),
+ size: videoFile.size,
+ fps: videoFile.fps,
+ torrentUrl: this.getTorrentUrl(videoFile, baseUrlHttp),
+ torrentDownloadUrl: this.getTorrentDownloadUrl(videoFile, baseUrlHttp),
+ fileUrl: this.getVideoFileUrl(videoFile, baseUrlHttp),
+ fileDownloadUrl: this.getVideoFileDownloadUrl(videoFile, baseUrlHttp)
+ } as VideoFile
+ })
+ .sort((a, b) => {
+ if (a.resolution.id < b.resolution.id) return 1
+ if (a.resolution.id === b.resolution.id) return 0
+ return -1
+ })
}
toActivityPubObject (): VideoTorrentObject {
for (const file of this.VideoFiles) {
url.push({
type: 'Link',
- mimeType: VIDEO_EXT_MIMETYPE[file.extname],
+ mimeType: VIDEO_EXT_MIMETYPE[ file.extname ],
href: this.getVideoFileUrl(file, baseUrlHttp),
height: file.resolution,
size: file.size,