mirror of https://github.com/Chocobozzz/PeerTube
Fix video upload and videos list
parent
8e13fa7d09
commit
8e10cf1a5a
|
@ -108,7 +108,11 @@ async function follow (req: express.Request, res: express.Response, next: expres
|
|||
tasks.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
// Don't make the client wait the tasks
|
||||
Promise.all(tasks)
|
||||
.catch(err => {
|
||||
logger.error('Error in follow.', err)
|
||||
})
|
||||
|
||||
return res.status(204).end()
|
||||
}
|
||||
|
|
|
@ -1,20 +1,17 @@
|
|||
import * as validator from 'validator'
|
||||
|
||||
import { ACTIVITY_PUB } from '../../../initializers'
|
||||
import { exists, isDateValid, isUUIDValid } from '../misc'
|
||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
||||
import {
|
||||
ACTIVITY_PUB
|
||||
} from '../../../initializers'
|
||||
import { isDateValid, isUUIDValid } from '../misc'
|
||||
import {
|
||||
isVideoViewsValid,
|
||||
isVideoNSFWValid,
|
||||
isVideoTruncatedDescriptionValid,
|
||||
isVideoDurationValid,
|
||||
isVideoNameValid,
|
||||
isVideoNSFWValid,
|
||||
isVideoTagValid,
|
||||
isVideoUrlValid
|
||||
isVideoTruncatedDescriptionValid,
|
||||
isVideoUrlValid,
|
||||
isVideoViewsValid
|
||||
} from '../videos'
|
||||
import { isVideoChannelDescriptionValid, isVideoChannelNameValid } from '../video-channels'
|
||||
import { isActivityPubUrlValid, isBaseActivityValid } from './misc'
|
||||
import { isBaseActivityValid } from './misc'
|
||||
|
||||
function isVideoTorrentAddActivityValid (activity: any) {
|
||||
return isBaseActivityValid(activity, 'Add') &&
|
||||
|
@ -30,10 +27,19 @@ function isVideoTorrentDeleteActivityValid (activity: any) {
|
|||
return isBaseActivityValid(activity, 'Delete')
|
||||
}
|
||||
|
||||
function isActivityPubVideoDurationValid (value: string) {
|
||||
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
|
||||
return exists(value) &&
|
||||
typeof value === 'string' &&
|
||||
value.startsWith('PT') &&
|
||||
value.endsWith('S') &&
|
||||
isVideoDurationValid(value.replace(/[^0-9]+/, ''))
|
||||
}
|
||||
|
||||
function isVideoTorrentObjectValid (video: any) {
|
||||
return video.type === 'Video' &&
|
||||
isVideoNameValid(video.name) &&
|
||||
isVideoDurationValid(video.duration) &&
|
||||
isActivityPubVideoDurationValid(video.duration) &&
|
||||
isUUIDValid(video.uuid) &&
|
||||
setValidRemoteTags(video) &&
|
||||
isRemoteIdentifierValid(video.category) &&
|
||||
|
|
|
@ -69,6 +69,10 @@ function isVideoNSFWValid (value: any) {
|
|||
return typeof value === 'boolean' || (typeof value === 'string' && validator.isBoolean(value))
|
||||
}
|
||||
|
||||
function isVideoDurationValid (value: string) {
|
||||
return exists(value) && validator.isInt(value + '', VIDEOS_CONSTRAINTS_FIELDS.DURATION)
|
||||
}
|
||||
|
||||
function isVideoTruncatedDescriptionValid (value: string) {
|
||||
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.TRUNCATED_DESCRIPTION)
|
||||
}
|
||||
|
@ -77,15 +81,6 @@ function isVideoDescriptionValid (value: string) {
|
|||
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.DESCRIPTION)
|
||||
}
|
||||
|
||||
function isVideoDurationValid (value: string) {
|
||||
// https://www.w3.org/TR/activitystreams-vocabulary/#dfn-duration
|
||||
return exists(value) &&
|
||||
typeof value === 'string' &&
|
||||
value.startsWith('PT') &&
|
||||
value.endsWith('S') &&
|
||||
validator.isInt(value.replace(/[^0-9]+/, ''), VIDEOS_CONSTRAINTS_FIELDS.DURATION)
|
||||
}
|
||||
|
||||
function isVideoNameValid (value: string) {
|
||||
return exists(value) && validator.isLength(value, VIDEOS_CONSTRAINTS_FIELDS.NAME)
|
||||
}
|
||||
|
@ -197,7 +192,6 @@ export {
|
|||
isVideoNSFWValid,
|
||||
isVideoTruncatedDescriptionValid,
|
||||
isVideoDescriptionValid,
|
||||
isVideoDurationValid,
|
||||
isVideoFileInfoHashValid,
|
||||
isVideoNameValid,
|
||||
isVideoTagsValid,
|
||||
|
@ -214,6 +208,7 @@ export {
|
|||
isVideoFileSizeValid,
|
||||
isVideoPrivacyValid,
|
||||
isRemoteVideoPrivacyValid,
|
||||
isVideoDurationValid,
|
||||
isVideoFileResolutionValid,
|
||||
checkVideoExists,
|
||||
isVideoTagValid,
|
||||
|
|
|
@ -11,6 +11,7 @@ import { signObject, activityPubContextify } from '../../helpers'
|
|||
import { Activity } from '../../../shared'
|
||||
import { VideoAbuseInstance } from '../../models/video/video-abuse-interface'
|
||||
import { getActivityPubUrl } from '../../helpers/activitypub'
|
||||
import { logger } from '../../helpers/logger'
|
||||
|
||||
async function sendCreateVideoChannel (videoChannel: VideoChannelInstance, t: Sequelize.Transaction) {
|
||||
const videoChannelObject = videoChannel.toActivityPubObject()
|
||||
|
@ -100,7 +101,11 @@ export {
|
|||
// ---------------------------------------------------------------------------
|
||||
|
||||
async function broadcastToFollowers (data: any, fromAccount: AccountInstance, t: Sequelize.Transaction) {
|
||||
const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id, 0)
|
||||
const result = await db.AccountFollow.listAcceptedFollowerUrlsForApi(fromAccount.id)
|
||||
if (result.data.length === 0) {
|
||||
logger.info('Not broadcast because of 0 followers.')
|
||||
return
|
||||
}
|
||||
|
||||
const jobPayload = {
|
||||
uris: result.data,
|
||||
|
|
|
@ -22,8 +22,9 @@ function onError (err: Error, jobId: number) {
|
|||
return Promise.resolve()
|
||||
}
|
||||
|
||||
async function onSuccess (jobId: number) {
|
||||
function onSuccess (jobId: number) {
|
||||
logger.info('Job %d is a success.', jobId)
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -20,8 +20,9 @@ function onError (err: Error, jobId: number) {
|
|||
return Promise.resolve()
|
||||
}
|
||||
|
||||
async function onSuccess (jobId: number) {
|
||||
function onSuccess (jobId: number) {
|
||||
logger.info('Job %d is a success.', jobId)
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
|
|
@ -9,7 +9,7 @@ import { error } from 'util'
|
|||
export interface JobHandler<P, T> {
|
||||
process (data: object, jobId: number): Promise<T>
|
||||
onError (err: Error, jobId: number)
|
||||
onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>)
|
||||
onSuccess (jobId: number, jobResult: T, jobScheduler: JobScheduler<P, T>): Promise<any>
|
||||
}
|
||||
type JobQueueCallback = (err: Error) => void
|
||||
|
||||
|
@ -127,7 +127,7 @@ class JobScheduler<P, T> {
|
|||
|
||||
try {
|
||||
await job.save()
|
||||
jobHandler.onSuccess(job.id, jobResult, this)
|
||||
await jobHandler.onSuccess(job.id, jobResult, this)
|
||||
} catch (err) {
|
||||
this.cannotSaveJobError(err)
|
||||
}
|
||||
|
|
|
@ -39,8 +39,8 @@ async function onSuccess (jobId: number, video: VideoInstance, jobScheduler: Job
|
|||
await sendAddVideo(video, undefined)
|
||||
|
||||
const originalFileHeight = await videoDatabase.getOriginalFileHeight()
|
||||
// Create transcoding jobs if there are enabled resolutions
|
||||
|
||||
// Create transcoding jobs if there are enabled resolutions
|
||||
const resolutionsEnabled = computeResolutionsToTranscode(originalFileHeight)
|
||||
logger.info(
|
||||
'Resolutions computed for video %s and origin file height of %d.', videoDatabase.uuid, originalFileHeight,
|
||||
|
|
|
@ -10,8 +10,8 @@ export namespace AccountFollowMethods {
|
|||
export type ListFollowingForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
|
||||
export type ListFollowersForApi = (id: number, start: number, count: number, sort: string) => Bluebird< ResultList<AccountInstance> >
|
||||
|
||||
export type ListAcceptedFollowerUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
|
||||
export type ListAcceptedFollowingUrlsForApi = (id: number, start: number, count?: number) => Promise< ResultList<string> >
|
||||
export type ListAcceptedFollowerUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
|
||||
export type ListAcceptedFollowingUrlsForApi = (id: number, start?: number, count?: number) => Promise< ResultList<string> >
|
||||
}
|
||||
|
||||
export interface AccountFollowClass {
|
||||
|
|
|
@ -146,17 +146,17 @@ listFollowersForApi = function (id: number, start: number, count: number, sort:
|
|||
})
|
||||
}
|
||||
|
||||
listAcceptedFollowerUrlsForApi = function (id: number, start: number, count?: number) {
|
||||
return createListAcceptedFollowForApiQuery('followers', id, start, count)
|
||||
listAcceptedFollowerUrlsForApi = function (accountId: number, start?: number, count?: number) {
|
||||
return createListAcceptedFollowForApiQuery('followers', accountId, start, count)
|
||||
}
|
||||
|
||||
listAcceptedFollowingUrlsForApi = function (id: number, start: number, count?: number) {
|
||||
return createListAcceptedFollowForApiQuery('following', id, start, count)
|
||||
listAcceptedFollowingUrlsForApi = function (accountId: number, start?: number, count?: number) {
|
||||
return createListAcceptedFollowForApiQuery('following', accountId, start, count)
|
||||
}
|
||||
|
||||
// ------------------------------ UTILS ------------------------------
|
||||
|
||||
async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', id: number, start: number, count?: number) {
|
||||
async function createListAcceptedFollowForApiQuery (type: 'followers' | 'following', accountId: number, start?: number, count?: number) {
|
||||
let firstJoin: string
|
||||
let secondJoin: string
|
||||
|
||||
|
@ -168,20 +168,20 @@ async function createListAcceptedFollowForApiQuery (type: 'followers' | 'followi
|
|||
secondJoin = 'targetAccountId'
|
||||
}
|
||||
|
||||
const selections = [ '"Followers"."url" AS "url"', 'COUNT(*) AS "total"' ]
|
||||
const selections = [ '"Follows"."url" AS "url"', 'COUNT(*) AS "total"' ]
|
||||
const tasks: Promise<any>[] = []
|
||||
|
||||
for (const selection of selections) {
|
||||
let query = 'SELECT ' + selection + ' FROM "Account" ' +
|
||||
'INNER JOIN "AccountFollow" ON "AccountFollow"."' + firstJoin + '" = "Account"."id" ' +
|
||||
'INNER JOIN "Account" AS "Follows" ON "Followers"."id" = "Follows"."' + secondJoin + '" ' +
|
||||
'WHERE "Account"."id" = $id AND "AccountFollow"."state" = \'accepted\' ' +
|
||||
'LIMIT ' + start
|
||||
let query = 'SELECT ' + selection + ' FROM "Accounts" ' +
|
||||
'INNER JOIN "AccountFollows" ON "AccountFollows"."' + firstJoin + '" = "Accounts"."id" ' +
|
||||
'INNER JOIN "Accounts" AS "Follows" ON "AccountFollows"."' + secondJoin + '" = "Follows"."id" ' +
|
||||
'WHERE "Accounts"."id" = $accountId AND "AccountFollows"."state" = \'accepted\' '
|
||||
|
||||
if (start !== undefined) query += 'LIMIT ' + start
|
||||
if (count !== undefined) query += ', ' + count
|
||||
|
||||
const options = {
|
||||
bind: { id },
|
||||
bind: { accountId },
|
||||
type: Sequelize.QueryTypes.SELECT
|
||||
}
|
||||
tasks.push(AccountFollow['sequelize'].query(query, options))
|
||||
|
|
|
@ -263,6 +263,7 @@ function associate (models) {
|
|||
name: 'targetAccountId',
|
||||
allowNull: false
|
||||
},
|
||||
as: 'followers',
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
}
|
||||
|
|
|
@ -329,7 +329,7 @@ function associate (models) {
|
|||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
Video.belongsTo(models.VideoChannel, {
|
||||
Video.belongsTo(models.Video, {
|
||||
foreignKey: {
|
||||
name: 'parentId',
|
||||
allowNull: true
|
||||
|
@ -825,9 +825,11 @@ listForApi = function (start: number, count: number, sort: string) {
|
|||
include: [
|
||||
{
|
||||
model: Video['sequelize'].models.VideoChannel,
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
model: Video['sequelize'].models.Account,
|
||||
required: true,
|
||||
include: [
|
||||
{
|
||||
model: Video['sequelize'].models.Server,
|
||||
|
|
Loading…
Reference in New Issue