Fetch video likes/dislikes too
This commit is contained in:
parent
d8553faa49
commit
16b9097594
|
@ -38,7 +38,7 @@ async function inboxController (req: express.Request, res: express.Response, nex
|
|||
if ([ 'Collection', 'CollectionPage' ].indexOf(rootActivity.type) !== -1) {
|
||||
activities = (rootActivity as ActivityPubCollection).items
|
||||
} else if ([ 'OrderedCollection', 'OrderedCollectionPage' ].indexOf(rootActivity.type) !== -1) {
|
||||
activities = (rootActivity as ActivityPubOrderedCollection).orderedItems
|
||||
activities = (rootActivity as ActivityPubOrderedCollection<Activity>).orderedItems
|
||||
} else {
|
||||
activities = [ rootActivity as Activity ]
|
||||
}
|
||||
|
|
|
@ -24,6 +24,14 @@ function activityPubContextify <T> (data: T) {
|
|||
})
|
||||
}
|
||||
|
||||
function activityPubCollection (results: any[]) {
|
||||
return {
|
||||
type: 'OrderedCollection',
|
||||
totalItems: results.length,
|
||||
orderedItems: results
|
||||
}
|
||||
}
|
||||
|
||||
function activityPubCollectionPagination (url: string, page: any, result: ResultList<any>) {
|
||||
let next: string
|
||||
let prev: string
|
||||
|
@ -74,5 +82,6 @@ function buildSignedActivity (byAccount: AccountInstance, data: Object) {
|
|||
export {
|
||||
activityPubContextify,
|
||||
activityPubCollectionPagination,
|
||||
activityPubCollection,
|
||||
buildSignedActivity
|
||||
}
|
||||
|
|
|
@ -1,11 +1,13 @@
|
|||
import * as Bluebird from 'bluebird'
|
||||
import { VideoTorrentObject } from '../../../../shared'
|
||||
import { ActivityAdd } from '../../../../shared/models/activitypub/activity'
|
||||
import { VideoRateType } from '../../../../shared/models/videos/video-rate.type'
|
||||
import { retryTransactionWrapper } from '../../../helpers/database-utils'
|
||||
import { logger } from '../../../helpers/logger'
|
||||
import { database as db } from '../../../initializers'
|
||||
import { AccountInstance } from '../../../models/account/account-interface'
|
||||
import { VideoChannelInstance } from '../../../models/video/video-channel-interface'
|
||||
import { VideoInstance } from '../../../models/video/video-interface'
|
||||
import { getOrCreateAccountAndServer } from '../account'
|
||||
import { getOrCreateVideoChannel } from '../video-channels'
|
||||
import { generateThumbnailFromUrl } from '../videos'
|
||||
|
@ -35,13 +37,29 @@ export {
|
|||
|
||||
// ---------------------------------------------------------------------------
|
||||
|
||||
function processAddVideo (account: AccountInstance, activity: ActivityAdd, videoChannel: VideoChannelInstance, video: VideoTorrentObject) {
|
||||
async function processAddVideo (
|
||||
account: AccountInstance,
|
||||
activity: ActivityAdd,
|
||||
videoChannel: VideoChannelInstance,
|
||||
videoToCreateData: VideoTorrentObject
|
||||
) {
|
||||
const options = {
|
||||
arguments: [ account, activity, videoChannel, video ],
|
||||
arguments: [ account, activity, videoChannel, videoToCreateData ],
|
||||
errorMessage: 'Cannot insert the remote video with many retries.'
|
||||
}
|
||||
|
||||
return retryTransactionWrapper(addRemoteVideo, options)
|
||||
const video = await retryTransactionWrapper(addRemoteVideo, options)
|
||||
|
||||
// Process outside the transaction because we could fetch remote data
|
||||
if (videoToCreateData.likes && Array.isArray(videoToCreateData.likes.orderedItems)) {
|
||||
await createRates(videoToCreateData.likes.orderedItems, video, 'like')
|
||||
}
|
||||
|
||||
if (videoToCreateData.dislikes && Array.isArray(videoToCreateData.dislikes.orderedItems)) {
|
||||
await createRates(videoToCreateData.dislikes.orderedItems, video, 'dislike')
|
||||
}
|
||||
|
||||
return video
|
||||
}
|
||||
|
||||
function addRemoteVideo (account: AccountInstance,
|
||||
|
@ -86,3 +104,30 @@ function addRemoteVideo (account: AccountInstance,
|
|||
return videoCreated
|
||||
})
|
||||
}
|
||||
|
||||
async function createRates (accountUrls: string[], video: VideoInstance, rate: VideoRateType) {
|
||||
let rateCounts = 0
|
||||
const tasks: Bluebird<any>[] = []
|
||||
|
||||
for (const accountUrl of accountUrls) {
|
||||
const account = await getOrCreateAccountAndServer(accountUrl)
|
||||
const p = db.AccountVideoRate
|
||||
.create({
|
||||
videoId: video.id,
|
||||
accountId: account.id,
|
||||
type: rate
|
||||
})
|
||||
.then(() => rateCounts += 1)
|
||||
|
||||
tasks.push(p)
|
||||
}
|
||||
|
||||
await Promise.all(tasks)
|
||||
|
||||
logger.info('Adding %d %s to video %s.', rateCounts, rate, video.uuid)
|
||||
|
||||
// This is "likes" and "dislikes"
|
||||
await video.increment(rate + 's', { by: rateCounts })
|
||||
|
||||
return
|
||||
}
|
||||
|
|
|
@ -31,7 +31,11 @@ async function processActivities (activities: Activity[], inboxAccount?: Account
|
|||
continue
|
||||
}
|
||||
|
||||
await activityProcessor(activity, inboxAccount)
|
||||
try {
|
||||
await activityProcessor(activity, inboxAccount)
|
||||
} catch (err) {
|
||||
logger.warn('Cannot process activity %s.', activity.type, err)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@ async function process (payload: ActivityPubHttpPayload, jobId: number) {
|
|||
}
|
||||
|
||||
function onError (err: Error, jobId: number) {
|
||||
logger.error('Error when broadcasting ActivityPub request in job %d.', jobId, err)
|
||||
logger.error('Error when fetcher ActivityPub request in job %d.', jobId, err)
|
||||
return Promise.resolve()
|
||||
}
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ import * as Sequelize from 'sequelize'
|
|||
import * as Promise from 'bluebird'
|
||||
|
||||
import { VideoRateType } from '../../../shared/models/videos/video-rate.type'
|
||||
import { AccountInstance } from './account-interface'
|
||||
|
||||
export namespace AccountVideoRateMethods {
|
||||
export type Load = (accountId: number, videoId: number, transaction: Sequelize.Transaction) => Promise<AccountVideoRateInstance>
|
||||
|
@ -15,6 +16,8 @@ export interface AccountVideoRateAttributes {
|
|||
type: VideoRateType
|
||||
accountId: number
|
||||
videoId: number
|
||||
|
||||
Account?: AccountInstance
|
||||
}
|
||||
|
||||
export interface AccountVideoRateInstance
|
||||
|
|
|
@ -8,6 +8,8 @@ import { TagAttributes, TagInstance } from './tag-interface'
|
|||
import { VideoChannelInstance } from './video-channel-interface'
|
||||
import { VideoFileAttributes, VideoFileInstance } from './video-file-interface'
|
||||
import { VideoShareInstance } from './video-share-interface'
|
||||
import { UserVideoRate } from '../../../shared/models/videos/user-video-rate.model'
|
||||
import { AccountVideoRateInstance } from '../account/account-video-rate-interface'
|
||||
|
||||
export namespace VideoMethods {
|
||||
export type GetThumbnailName = (this: VideoInstance) => string
|
||||
|
@ -123,6 +125,7 @@ export interface VideoAttributes {
|
|||
Tags?: TagInstance[]
|
||||
VideoFiles?: VideoFileInstance[]
|
||||
VideoShares?: VideoShareInstance[]
|
||||
AccountVideoRates?: AccountVideoRateInstance[]
|
||||
}
|
||||
|
||||
export interface VideoInstance extends VideoClass, VideoAttributes, Sequelize.Instance<VideoAttributes> {
|
||||
|
|
|
@ -47,6 +47,7 @@ import { VideoFileInstance, VideoFileModel } from './video-file-interface'
|
|||
import { VideoAttributes, VideoInstance, VideoMethods } from './video-interface'
|
||||
import { sendDeleteVideo } from '../../lib/index'
|
||||
import * as Bluebird from 'bluebird'
|
||||
import { activityPubCollection } from '../../helpers/activitypub'
|
||||
|
||||
const Buffer = safeBuffer.Buffer
|
||||
|
||||
|
@ -359,6 +360,14 @@ function associate (models) {
|
|||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
|
||||
Video.hasMany(models.AccountVideoRate, {
|
||||
foreignKey: {
|
||||
name: 'videoId',
|
||||
allowNull: false
|
||||
},
|
||||
onDelete: 'cascade'
|
||||
})
|
||||
}
|
||||
|
||||
function afterDestroy (video: VideoInstance) {
|
||||
|
@ -575,6 +584,25 @@ toActivityPubObject = function (this: VideoInstance) {
|
|||
}
|
||||
}
|
||||
|
||||
let likesObject
|
||||
let dislikesObject
|
||||
|
||||
if (Array.isArray(this.AccountVideoRates)) {
|
||||
const likes: string[] = []
|
||||
const dislikes: string[] = []
|
||||
|
||||
for (const rate of this.AccountVideoRates) {
|
||||
if (rate.type === 'like') {
|
||||
likes.push(rate.Account.url)
|
||||
} else if (rate.type === 'dislike') {
|
||||
dislikes.push(rate.Account.url)
|
||||
}
|
||||
}
|
||||
|
||||
likesObject = activityPubCollection(likes)
|
||||
dislikesObject = activityPubCollection(dislikes)
|
||||
}
|
||||
|
||||
const url = []
|
||||
for (const file of this.VideoFiles) {
|
||||
url.push({
|
||||
|
@ -630,7 +658,9 @@ toActivityPubObject = function (this: VideoInstance) {
|
|||
width: THUMBNAILS_SIZE.width,
|
||||
height: THUMBNAILS_SIZE.height
|
||||
},
|
||||
url // FIXME: needed?
|
||||
url,
|
||||
likes: likesObject,
|
||||
dislikes: dislikesObject
|
||||
}
|
||||
|
||||
return videoObject
|
||||
|
@ -845,8 +875,12 @@ listAllAndSharedByAccountForOutbox = function (accountId: number, start: number,
|
|||
}
|
||||
]
|
||||
},
|
||||
Video['sequelize'].models.Tag,
|
||||
Video['sequelize'].models.VideoFile
|
||||
{
|
||||
model: Video['sequelize'].models.AccountVideoRate,
|
||||
include: [ Video['sequelize'].models.Account ]
|
||||
},
|
||||
Video['sequelize'].models.VideoFile,
|
||||
Video['sequelize'].models.Tag
|
||||
]
|
||||
}
|
||||
|
||||
|
@ -1106,6 +1140,10 @@ loadAndPopulateAccountAndServerAndTags = function (id: number) {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
model: Video['sequelize'].models.AccountVideoRate,
|
||||
include: [ Video['sequelize'].models.Account ]
|
||||
},
|
||||
Video['sequelize'].models.Tag,
|
||||
Video['sequelize'].models.VideoFile
|
||||
]
|
||||
|
@ -1129,6 +1167,10 @@ loadByUUIDAndPopulateAccountAndServerAndTags = function (uuid: string) {
|
|||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
model: Video['sequelize'].models.AccountVideoRate,
|
||||
include: [ Video['sequelize'].models.Account ]
|
||||
},
|
||||
Video['sequelize'].models.Tag,
|
||||
Video['sequelize'].models.VideoFile
|
||||
]
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
import { Activity } from './activity'
|
||||
|
||||
export interface ActivityPubOrderedCollection {
|
||||
export interface ActivityPubOrderedCollection<T> {
|
||||
'@context': string[]
|
||||
type: 'OrderedCollection' | 'OrderedCollectionPage'
|
||||
totalItems: number
|
||||
partOf?: string
|
||||
orderedItems: Activity[]
|
||||
orderedItems: T[]
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@ import { Activity } from './activity'
|
|||
import { ActivityPubCollection } from './activitypub-collection'
|
||||
import { ActivityPubOrderedCollection } from './activitypub-ordered-collection'
|
||||
|
||||
export type RootActivity = Activity | ActivityPubCollection | ActivityPubOrderedCollection
|
||||
export type RootActivity = Activity | ActivityPubCollection | ActivityPubOrderedCollection<Activity>
|
||||
|
|
|
@ -4,6 +4,7 @@ import {
|
|||
ActivityTagObject,
|
||||
ActivityUrlObject
|
||||
} from './common-objects'
|
||||
import { ActivityPubOrderedCollection } from '../activitypub-ordered-collection'
|
||||
|
||||
export interface VideoTorrentObject {
|
||||
type: 'Video'
|
||||
|
@ -24,4 +25,6 @@ export interface VideoTorrentObject {
|
|||
icon: ActivityIconObject
|
||||
url: ActivityUrlObject[]
|
||||
actor?: string
|
||||
likes?: ActivityPubOrderedCollection<string>
|
||||
dislikes?: ActivityPubOrderedCollection<string>
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue