More robust channel sync
This commit is contained in:
parent
22ab711501
commit
48f1d4b186
|
@ -61,7 +61,7 @@ export class VideoImportService {
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.authHttp
|
return this.authHttp
|
||||||
.get<ResultList<VideoImport>>(UserService.BASE_USERS_URL + '/me/videos/imports', { params })
|
.get<ResultList<VideoImport>>(UserService.BASE_USERS_URL + 'me/videos/imports', { params })
|
||||||
.pipe(
|
.pipe(
|
||||||
switchMap(res => this.extractVideoImports(res)),
|
switchMap(res => this.extractVideoImports(res)),
|
||||||
catchError(err => this.restExtractor.handleError(err))
|
catchError(err => this.restExtractor.handleError(err))
|
||||||
|
|
|
@ -232,12 +232,23 @@ describe('Test video imports', function () {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should search in my imports', async function () {
|
it('Should search in my imports', async function () {
|
||||||
const { total, data: videoImports } = await servers[0].imports.getMyVideoImports({ search: 'peertube2' })
|
{
|
||||||
expect(total).to.equal(1)
|
const { total, data } = await servers[0].imports.getMyVideoImports({ search: 'peertube2' })
|
||||||
expect(videoImports).to.have.lengthOf(1)
|
expect(total).to.equal(1)
|
||||||
|
expect(data).to.have.lengthOf(1)
|
||||||
|
|
||||||
expect(videoImports[0].magnetUri).to.equal(FIXTURE_URLS.magnet)
|
expect(data[0].magnetUri).to.equal(FIXTURE_URLS.magnet)
|
||||||
expect(videoImports[0].video.name).to.equal('super peertube2 video')
|
expect(data[0].video.name).to.equal('super peertube2 video')
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const { total, data } = await servers[0].imports.getMyVideoImports({ search: FIXTURE_URLS.magnet })
|
||||||
|
expect(total).to.equal(1)
|
||||||
|
expect(data).to.have.lengthOf(1)
|
||||||
|
|
||||||
|
expect(data[0].magnetUri).to.equal(FIXTURE_URLS.magnet)
|
||||||
|
expect(data[0].video.name).to.equal('super peertube2 video')
|
||||||
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Should have the video listed on the two instances', async function () {
|
it('Should have the video listed on the two instances', async function () {
|
||||||
|
|
|
@ -26,7 +26,7 @@ export async function processVideoChannelImport (job: Job) {
|
||||||
channelSync = await VideoChannelSyncModel.loadWithChannel(payload.partOfChannelSyncId)
|
channelSync = await VideoChannelSyncModel.loadWithChannel(payload.partOfChannelSyncId)
|
||||||
|
|
||||||
if (!channelSync) {
|
if (!channelSync) {
|
||||||
throw new Error('Unlnown channel sync specified in videos channel import')
|
throw new Error('Unknown channel sync specified in videos channel import')
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
import { logger } from '@server/helpers/logger.js'
|
import { logger, loggerTagsFactory } from '@server/helpers/logger.js'
|
||||||
import { YoutubeDLWrapper } from '@server/helpers/youtube-dl/index.js'
|
import { YoutubeDLWrapper } from '@server/helpers/youtube-dl/index.js'
|
||||||
import { CONFIG } from '@server/initializers/config.js'
|
import { CONFIG } from '@server/initializers/config.js'
|
||||||
import { buildYoutubeDLImport } from '@server/lib/video-pre-import.js'
|
import { buildYoutubeDLImport } from '@server/lib/video-pre-import.js'
|
||||||
|
@ -9,6 +9,8 @@ import { VideoChannelSyncState, VideoPrivacy } from '@peertube/peertube-models'
|
||||||
import { CreateJobArgument, JobQueue } from './job-queue/index.js'
|
import { CreateJobArgument, JobQueue } from './job-queue/index.js'
|
||||||
import { ServerConfigManager } from './server-config-manager.js'
|
import { ServerConfigManager } from './server-config-manager.js'
|
||||||
|
|
||||||
|
const lTags = loggerTagsFactory('channel-synchronization')
|
||||||
|
|
||||||
export async function synchronizeChannel (options: {
|
export async function synchronizeChannel (options: {
|
||||||
channel: MChannelAccountDefault
|
channel: MChannelAccountDefault
|
||||||
externalChannelUrl: string
|
externalChannelUrl: string
|
||||||
|
@ -36,7 +38,7 @@ export async function synchronizeChannel (options: {
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
'Fetched %d candidate URLs for sync channel %s.',
|
'Fetched %d candidate URLs for sync channel %s.',
|
||||||
targetUrls.length, channel.Actor.preferredUsername, { targetUrls }
|
targetUrls.length, channel.Actor.preferredUsername, { targetUrls, ...lTags() }
|
||||||
)
|
)
|
||||||
|
|
||||||
if (targetUrls.length === 0) {
|
if (targetUrls.length === 0) {
|
||||||
|
@ -51,19 +53,25 @@ export async function synchronizeChannel (options: {
|
||||||
const children: CreateJobArgument[] = []
|
const children: CreateJobArgument[] = []
|
||||||
|
|
||||||
for (const targetUrl of targetUrls) {
|
for (const targetUrl of targetUrls) {
|
||||||
if (await skipImport(channel, targetUrl, onlyAfter)) continue
|
logger.debug(`Import candidate: ${targetUrl}`, lTags())
|
||||||
|
|
||||||
const { job } = await buildYoutubeDLImport({
|
try {
|
||||||
user,
|
if (await skipImport(channel, targetUrl, onlyAfter)) continue
|
||||||
channel,
|
|
||||||
targetUrl,
|
|
||||||
channelSync,
|
|
||||||
importDataOverride: {
|
|
||||||
privacy: VideoPrivacy.PUBLIC
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
children.push(job)
|
const { job } = await buildYoutubeDLImport({
|
||||||
|
user,
|
||||||
|
channel,
|
||||||
|
targetUrl,
|
||||||
|
channelSync,
|
||||||
|
importDataOverride: {
|
||||||
|
privacy: VideoPrivacy.PUBLIC
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
children.push(job)
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(`Cannot build import for ${targetUrl} in channel ${channel.name}`, { err, ...lTags() })
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Will update the channel sync status
|
// Will update the channel sync status
|
||||||
|
@ -76,7 +84,7 @@ export async function synchronizeChannel (options: {
|
||||||
|
|
||||||
await JobQueue.Instance.createJobWithChildren(parent, children)
|
await JobQueue.Instance.createJobWithChildren(parent, children)
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
logger.error(`Failed to import ${externalChannelUrl} in channel ${channel.name}`, { err })
|
logger.error(`Failed to import ${externalChannelUrl} in channel ${channel.name}`, { err, ...lTags() })
|
||||||
channelSync.state = VideoChannelSyncState.FAILED
|
channelSync.state = VideoChannelSyncState.FAILED
|
||||||
await channelSync.save()
|
await channelSync.save()
|
||||||
}
|
}
|
||||||
|
@ -86,7 +94,7 @@ export async function synchronizeChannel (options: {
|
||||||
|
|
||||||
async function skipImport (channel: MChannel, targetUrl: string, onlyAfter?: Date) {
|
async function skipImport (channel: MChannel, targetUrl: string, onlyAfter?: Date) {
|
||||||
if (await VideoImportModel.urlAlreadyImported(channel.id, targetUrl)) {
|
if (await VideoImportModel.urlAlreadyImported(channel.id, targetUrl)) {
|
||||||
logger.debug('%s is already imported for channel %s, skipping video channel synchronization.', targetUrl, channel.name)
|
logger.debug('%s is already imported for channel %s, skipping video channel synchronization.', targetUrl, channel.name, lTags())
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -159,7 +159,7 @@ export class VideoImportModel extends Model<Partial<AttributesOnly<VideoImportMo
|
||||||
}) {
|
}) {
|
||||||
const { userId, start, count, sort, targetUrl, videoChannelSyncId, search } = options
|
const { userId, start, count, sort, targetUrl, videoChannelSyncId, search } = options
|
||||||
|
|
||||||
const where: WhereOptions = { userId }
|
const where: WhereOptions = [ { userId } ]
|
||||||
const include: IncludeOptions[] = [
|
const include: IncludeOptions[] = [
|
||||||
{
|
{
|
||||||
attributes: [ 'id' ],
|
attributes: [ 'id' ],
|
||||||
|
@ -172,14 +172,22 @@ export class VideoImportModel extends Model<Partial<AttributesOnly<VideoImportMo
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|
||||||
if (targetUrl) where['targetUrl'] = targetUrl
|
if (targetUrl) where.push({ targetUrl })
|
||||||
if (videoChannelSyncId) where['videoChannelSyncId'] = videoChannelSyncId
|
if (videoChannelSyncId) where.push({ videoChannelSyncId })
|
||||||
|
|
||||||
if (search) {
|
if (search) {
|
||||||
include.push({
|
include.push({
|
||||||
model: defaultVideoScope(),
|
model: defaultVideoScope(),
|
||||||
required: true,
|
required: false
|
||||||
where: searchAttribute(search, 'name')
|
})
|
||||||
|
|
||||||
|
where.push({
|
||||||
|
[Op.or]: [
|
||||||
|
searchAttribute(search, '$Video.name$'),
|
||||||
|
searchAttribute(search, 'targetUrl'),
|
||||||
|
searchAttribute(search, 'torrentName'),
|
||||||
|
searchAttribute(search, 'magnetUri')
|
||||||
|
]
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
include.push({
|
include.push({
|
||||||
|
|
Loading…
Reference in New Issue