diff options
author | Chocobozzz <me@florianbigard.com> | 2021-06-17 16:02:38 +0200 |
---|---|---|
committer | Chocobozzz <chocobozzz@cpy.re> | 2021-06-25 14:44:01 +0200 |
commit | 37a44fc915eef2140e22ceb96aba6b6eb2509007 (patch) | |
tree | dd4a370ecc96cf38c99b940261aadc27065da7ae /server/lib/activitypub | |
parent | 33eb19e5199cc9fa4d73c6675c97508e3e072ef9 (diff) | |
download | PeerTube-37a44fc915eef2140e22ceb96aba6b6eb2509007.tar.gz PeerTube-37a44fc915eef2140e22ceb96aba6b6eb2509007.tar.zst PeerTube-37a44fc915eef2140e22ceb96aba6b6eb2509007.zip |
Add ability to search playlists
Diffstat (limited to 'server/lib/activitypub')
-rw-r--r-- | server/lib/activitypub/actors/get.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/create-update.ts | 34 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/get.ts | 35 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/index.ts | 1 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/refresh.ts | 13 | ||||
-rw-r--r-- | server/lib/activitypub/playlists/shared/object-to-model-attributes.ts | 6 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-create.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/process/process-update.ts | 2 | ||||
-rw-r--r-- | server/lib/activitypub/videos/get.ts | 7 |
9 files changed, 76 insertions, 26 deletions
diff --git a/server/lib/activitypub/actors/get.ts b/server/lib/activitypub/actors/get.ts index d7cf2b678..8681ea02a 100644 --- a/server/lib/activitypub/actors/get.ts +++ b/server/lib/activitypub/actors/get.ts | |||
@@ -116,7 +116,7 @@ async function scheduleOutboxFetchIfNeeded (actor: MActor, created: boolean, ref | |||
116 | async function schedulePlaylistFetchIfNeeded (actor: MActorAccountId, created: boolean, accountPlaylistsUrl: string) { | 116 | async function schedulePlaylistFetchIfNeeded (actor: MActorAccountId, created: boolean, accountPlaylistsUrl: string) { |
117 | // We created a new account: fetch the playlists | 117 | // We created a new account: fetch the playlists |
118 | if (created === true && actor.Account && accountPlaylistsUrl) { | 118 | if (created === true && actor.Account && accountPlaylistsUrl) { |
119 | const payload = { uri: accountPlaylistsUrl, accountId: actor.Account.id, type: 'account-playlists' as 'account-playlists' } | 119 | const payload = { uri: accountPlaylistsUrl, type: 'account-playlists' as 'account-playlists' } |
120 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) | 120 | await JobQueue.Instance.createJobWithPromise({ type: 'activitypub-http-fetcher', payload }) |
121 | } | 121 | } |
122 | } | 122 | } |
diff --git a/server/lib/activitypub/playlists/create-update.ts b/server/lib/activitypub/playlists/create-update.ts index 37d748de4..ea3e61ac5 100644 --- a/server/lib/activitypub/playlists/create-update.ts +++ b/server/lib/activitypub/playlists/create-update.ts | |||
@@ -1,3 +1,5 @@ | |||
1 | import * as Bluebird from 'bluebird' | ||
2 | import { getAPId } from '@server/helpers/activitypub' | ||
1 | import { isArray } from '@server/helpers/custom-validators/misc' | 3 | import { isArray } from '@server/helpers/custom-validators/misc' |
2 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 4 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
3 | import { CRAWL_REQUEST_CONCURRENCY } from '@server/initializers/constants' | 5 | import { CRAWL_REQUEST_CONCURRENCY } from '@server/initializers/constants' |
@@ -6,7 +8,7 @@ import { updatePlaylistMiniatureFromUrl } from '@server/lib/thumbnail' | |||
6 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | 8 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' |
7 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' | 9 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' |
8 | import { FilteredModelAttributes } from '@server/types' | 10 | import { FilteredModelAttributes } from '@server/types' |
9 | import { MAccountDefault, MAccountId, MThumbnail, MVideoPlaylist, MVideoPlaylistFull } from '@server/types/models' | 11 | import { MThumbnail, MVideoPlaylist, MVideoPlaylistFull, MVideoPlaylistVideosLength } from '@server/types/models' |
10 | import { AttributesOnly } from '@shared/core-utils' | 12 | import { AttributesOnly } from '@shared/core-utils' |
11 | import { PlaylistObject } from '@shared/models' | 13 | import { PlaylistObject } from '@shared/models' |
12 | import { getOrCreateAPActor } from '../actors' | 14 | import { getOrCreateAPActor } from '../actors' |
@@ -19,11 +21,9 @@ import { | |||
19 | playlistObjectToDBAttributes | 21 | playlistObjectToDBAttributes |
20 | } from './shared' | 22 | } from './shared' |
21 | 23 | ||
22 | import Bluebird = require('bluebird') | ||
23 | |||
24 | const lTags = loggerTagsFactory('ap', 'video-playlist') | 24 | const lTags = loggerTagsFactory('ap', 'video-playlist') |
25 | 25 | ||
26 | async function createAccountPlaylists (playlistUrls: string[], account: MAccountDefault) { | 26 | async function createAccountPlaylists (playlistUrls: string[]) { |
27 | await Bluebird.map(playlistUrls, async playlistUrl => { | 27 | await Bluebird.map(playlistUrls, async playlistUrl => { |
28 | try { | 28 | try { |
29 | const exists = await VideoPlaylistModel.doesPlaylistExist(playlistUrl) | 29 | const exists = await VideoPlaylistModel.doesPlaylistExist(playlistUrl) |
@@ -35,19 +35,19 @@ async function createAccountPlaylists (playlistUrls: string[], account: MAccount | |||
35 | throw new Error(`Cannot refresh remote playlist ${playlistUrl}: invalid body.`) | 35 | throw new Error(`Cannot refresh remote playlist ${playlistUrl}: invalid body.`) |
36 | } | 36 | } |
37 | 37 | ||
38 | return createOrUpdateVideoPlaylist(playlistObject, account, playlistObject.to) | 38 | return createOrUpdateVideoPlaylist(playlistObject) |
39 | } catch (err) { | 39 | } catch (err) { |
40 | logger.warn('Cannot add playlist element %s.', playlistUrl, { err, ...lTags(playlistUrl) }) | 40 | logger.warn('Cannot add playlist element %s.', playlistUrl, { err, ...lTags(playlistUrl) }) |
41 | } | 41 | } |
42 | }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) | 42 | }, { concurrency: CRAWL_REQUEST_CONCURRENCY }) |
43 | } | 43 | } |
44 | 44 | ||
45 | async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) { | 45 | async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, to?: string[]) { |
46 | const playlistAttributes = playlistObjectToDBAttributes(playlistObject, byAccount, to) | 46 | const playlistAttributes = playlistObjectToDBAttributes(playlistObject, to || playlistObject.to) |
47 | 47 | ||
48 | await setVideoChannelIfNeeded(playlistObject, playlistAttributes) | 48 | await setVideoChannel(playlistObject, playlistAttributes) |
49 | 49 | ||
50 | const [ upsertPlaylist ] = await VideoPlaylistModel.upsert<MVideoPlaylist>(playlistAttributes, { returning: true }) | 50 | const [ upsertPlaylist ] = await VideoPlaylistModel.upsert<MVideoPlaylistVideosLength>(playlistAttributes, { returning: true }) |
51 | 51 | ||
52 | const playlistElementUrls = await fetchElementUrls(playlistObject) | 52 | const playlistElementUrls = await fetchElementUrls(playlistObject) |
53 | 53 | ||
@@ -56,7 +56,10 @@ async function createOrUpdateVideoPlaylist (playlistObject: PlaylistObject, byAc | |||
56 | 56 | ||
57 | await updatePlaylistThumbnail(playlistObject, playlist) | 57 | await updatePlaylistThumbnail(playlistObject, playlist) |
58 | 58 | ||
59 | return rebuildVideoPlaylistElements(playlistElementUrls, playlist) | 59 | const elementsLength = await rebuildVideoPlaylistElements(playlistElementUrls, playlist) |
60 | playlist.setVideosLength(elementsLength) | ||
61 | |||
62 | return playlist | ||
60 | } | 63 | } |
61 | 64 | ||
62 | // --------------------------------------------------------------------------- | 65 | // --------------------------------------------------------------------------- |
@@ -68,10 +71,12 @@ export { | |||
68 | 71 | ||
69 | // --------------------------------------------------------------------------- | 72 | // --------------------------------------------------------------------------- |
70 | 73 | ||
71 | async function setVideoChannelIfNeeded (playlistObject: PlaylistObject, playlistAttributes: AttributesOnly<VideoPlaylistModel>) { | 74 | async function setVideoChannel (playlistObject: PlaylistObject, playlistAttributes: AttributesOnly<VideoPlaylistModel>) { |
72 | if (!isArray(playlistObject.attributedTo) || playlistObject.attributedTo.length !== 1) return | 75 | if (!isArray(playlistObject.attributedTo) || playlistObject.attributedTo.length !== 1) { |
76 | throw new Error('Not attributed to for playlist object ' + getAPId(playlistObject)) | ||
77 | } | ||
73 | 78 | ||
74 | const actor = await getOrCreateAPActor(playlistObject.attributedTo[0]) | 79 | const actor = await getOrCreateAPActor(playlistObject.attributedTo[0], 'all') |
75 | 80 | ||
76 | if (!actor.VideoChannel) { | 81 | if (!actor.VideoChannel) { |
77 | logger.warn('Playlist "attributedTo" %s is not a video channel.', playlistObject.id, { playlistObject, ...lTags(playlistObject.id) }) | 82 | logger.warn('Playlist "attributedTo" %s is not a video channel.', playlistObject.id, { playlistObject, ...lTags(playlistObject.id) }) |
@@ -79,6 +84,7 @@ async function setVideoChannelIfNeeded (playlistObject: PlaylistObject, playlist | |||
79 | } | 84 | } |
80 | 85 | ||
81 | playlistAttributes.videoChannelId = actor.VideoChannel.id | 86 | playlistAttributes.videoChannelId = actor.VideoChannel.id |
87 | playlistAttributes.ownerAccountId = actor.VideoChannel.Account.id | ||
82 | } | 88 | } |
83 | 89 | ||
84 | async function fetchElementUrls (playlistObject: PlaylistObject) { | 90 | async function fetchElementUrls (playlistObject: PlaylistObject) { |
@@ -128,7 +134,7 @@ async function rebuildVideoPlaylistElements (elementUrls: string[], playlist: MV | |||
128 | 134 | ||
129 | logger.info('Rebuilt playlist %s with %s elements.', playlist.url, elementsToCreate.length, lTags(playlist.uuid, playlist.url)) | 135 | logger.info('Rebuilt playlist %s with %s elements.', playlist.url, elementsToCreate.length, lTags(playlist.uuid, playlist.url)) |
130 | 136 | ||
131 | return undefined | 137 | return elementsToCreate.length |
132 | } | 138 | } |
133 | 139 | ||
134 | async function buildElementsDBAttributes (elementUrls: string[], playlist: MVideoPlaylist) { | 140 | async function buildElementsDBAttributes (elementUrls: string[], playlist: MVideoPlaylist) { |
diff --git a/server/lib/activitypub/playlists/get.ts b/server/lib/activitypub/playlists/get.ts new file mode 100644 index 000000000..2c19c503a --- /dev/null +++ b/server/lib/activitypub/playlists/get.ts | |||
@@ -0,0 +1,35 @@ | |||
1 | import { getAPId } from '@server/helpers/activitypub' | ||
2 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | ||
3 | import { MVideoPlaylistFullSummary } from '@server/types/models' | ||
4 | import { APObject } from '@shared/models' | ||
5 | import { createOrUpdateVideoPlaylist } from './create-update' | ||
6 | import { scheduleRefreshIfNeeded } from './refresh' | ||
7 | import { fetchRemoteVideoPlaylist } from './shared' | ||
8 | |||
9 | async function getOrCreateAPVideoPlaylist (playlistObjectArg: APObject): Promise<MVideoPlaylistFullSummary> { | ||
10 | const playlistUrl = getAPId(playlistObjectArg) | ||
11 | |||
12 | const playlistFromDatabase = await VideoPlaylistModel.loadByUrlWithAccountAndChannelSummary(playlistUrl) | ||
13 | |||
14 | if (playlistFromDatabase) { | ||
15 | scheduleRefreshIfNeeded(playlistFromDatabase) | ||
16 | |||
17 | return playlistFromDatabase | ||
18 | } | ||
19 | |||
20 | const { playlistObject } = await fetchRemoteVideoPlaylist(playlistUrl) | ||
21 | if (!playlistObject) throw new Error('Cannot fetch remote playlist with url: ' + playlistUrl) | ||
22 | |||
23 | // playlistUrl is just an alias/rediraction, so process object id instead | ||
24 | if (playlistObject.id !== playlistUrl) return getOrCreateAPVideoPlaylist(playlistObject) | ||
25 | |||
26 | const playlistCreated = await createOrUpdateVideoPlaylist(playlistObject) | ||
27 | |||
28 | return playlistCreated | ||
29 | } | ||
30 | |||
31 | // --------------------------------------------------------------------------- | ||
32 | |||
33 | export { | ||
34 | getOrCreateAPVideoPlaylist | ||
35 | } | ||
diff --git a/server/lib/activitypub/playlists/index.ts b/server/lib/activitypub/playlists/index.ts index 2885830b4..e2470a674 100644 --- a/server/lib/activitypub/playlists/index.ts +++ b/server/lib/activitypub/playlists/index.ts | |||
@@ -1,2 +1,3 @@ | |||
1 | export * from './get' | ||
1 | export * from './create-update' | 2 | export * from './create-update' |
2 | export * from './refresh' | 3 | export * from './refresh' |
diff --git a/server/lib/activitypub/playlists/refresh.ts b/server/lib/activitypub/playlists/refresh.ts index 6f3a6be37..ef3cb3fe4 100644 --- a/server/lib/activitypub/playlists/refresh.ts +++ b/server/lib/activitypub/playlists/refresh.ts | |||
@@ -1,10 +1,17 @@ | |||
1 | import { logger, loggerTagsFactory } from '@server/helpers/logger' | 1 | import { logger, loggerTagsFactory } from '@server/helpers/logger' |
2 | import { PeerTubeRequestError } from '@server/helpers/requests' | 2 | import { PeerTubeRequestError } from '@server/helpers/requests' |
3 | import { MVideoPlaylistOwner } from '@server/types/models' | 3 | import { JobQueue } from '@server/lib/job-queue' |
4 | import { MVideoPlaylist, MVideoPlaylistOwner } from '@server/types/models' | ||
4 | import { HttpStatusCode } from '@shared/core-utils' | 5 | import { HttpStatusCode } from '@shared/core-utils' |
5 | import { createOrUpdateVideoPlaylist } from './create-update' | 6 | import { createOrUpdateVideoPlaylist } from './create-update' |
6 | import { fetchRemoteVideoPlaylist } from './shared' | 7 | import { fetchRemoteVideoPlaylist } from './shared' |
7 | 8 | ||
9 | function scheduleRefreshIfNeeded (playlist: MVideoPlaylist) { | ||
10 | if (!playlist.isOutdated()) return | ||
11 | |||
12 | JobQueue.Instance.createJob({ type: 'activitypub-refresher', payload: { type: 'video-playlist', url: playlist.url } }) | ||
13 | } | ||
14 | |||
8 | async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner): Promise<MVideoPlaylistOwner> { | 15 | async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner): Promise<MVideoPlaylistOwner> { |
9 | if (!videoPlaylist.isOutdated()) return videoPlaylist | 16 | if (!videoPlaylist.isOutdated()) return videoPlaylist |
10 | 17 | ||
@@ -22,8 +29,7 @@ async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner) | |||
22 | return videoPlaylist | 29 | return videoPlaylist |
23 | } | 30 | } |
24 | 31 | ||
25 | const byAccount = videoPlaylist.OwnerAccount | 32 | await createOrUpdateVideoPlaylist(playlistObject) |
26 | await createOrUpdateVideoPlaylist(playlistObject, byAccount, playlistObject.to) | ||
27 | 33 | ||
28 | return videoPlaylist | 34 | return videoPlaylist |
29 | } catch (err) { | 35 | } catch (err) { |
@@ -42,5 +48,6 @@ async function refreshVideoPlaylistIfNeeded (videoPlaylist: MVideoPlaylistOwner) | |||
42 | } | 48 | } |
43 | 49 | ||
44 | export { | 50 | export { |
51 | scheduleRefreshIfNeeded, | ||
45 | refreshVideoPlaylistIfNeeded | 52 | refreshVideoPlaylistIfNeeded |
46 | } | 53 | } |
diff --git a/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts b/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts index 6ec44485e..70fd335bc 100644 --- a/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts +++ b/server/lib/activitypub/playlists/shared/object-to-model-attributes.ts | |||
@@ -1,11 +1,11 @@ | |||
1 | import { ACTIVITY_PUB } from '@server/initializers/constants' | 1 | import { ACTIVITY_PUB } from '@server/initializers/constants' |
2 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' | 2 | import { VideoPlaylistModel } from '@server/models/video/video-playlist' |
3 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' | 3 | import { VideoPlaylistElementModel } from '@server/models/video/video-playlist-element' |
4 | import { MAccountId, MVideoId, MVideoPlaylistId } from '@server/types/models' | 4 | import { MVideoId, MVideoPlaylistId } from '@server/types/models' |
5 | import { AttributesOnly } from '@shared/core-utils' | 5 | import { AttributesOnly } from '@shared/core-utils' |
6 | import { PlaylistElementObject, PlaylistObject, VideoPlaylistPrivacy } from '@shared/models' | 6 | import { PlaylistElementObject, PlaylistObject, VideoPlaylistPrivacy } from '@shared/models' |
7 | 7 | ||
8 | function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount: MAccountId, to: string[]) { | 8 | function playlistObjectToDBAttributes (playlistObject: PlaylistObject, to: string[]) { |
9 | const privacy = to.includes(ACTIVITY_PUB.PUBLIC) | 9 | const privacy = to.includes(ACTIVITY_PUB.PUBLIC) |
10 | ? VideoPlaylistPrivacy.PUBLIC | 10 | ? VideoPlaylistPrivacy.PUBLIC |
11 | : VideoPlaylistPrivacy.UNLISTED | 11 | : VideoPlaylistPrivacy.UNLISTED |
@@ -16,7 +16,7 @@ function playlistObjectToDBAttributes (playlistObject: PlaylistObject, byAccount | |||
16 | privacy, | 16 | privacy, |
17 | url: playlistObject.id, | 17 | url: playlistObject.id, |
18 | uuid: playlistObject.uuid, | 18 | uuid: playlistObject.uuid, |
19 | ownerAccountId: byAccount.id, | 19 | ownerAccountId: null, |
20 | videoChannelId: null, | 20 | videoChannelId: null, |
21 | createdAt: new Date(playlistObject.published), | 21 | createdAt: new Date(playlistObject.published), |
22 | updatedAt: new Date(playlistObject.updated) | 22 | updatedAt: new Date(playlistObject.updated) |
diff --git a/server/lib/activitypub/process/process-create.ts b/server/lib/activitypub/process/process-create.ts index 6b7f5aae8..70e048d6e 100644 --- a/server/lib/activitypub/process/process-create.ts +++ b/server/lib/activitypub/process/process-create.ts | |||
@@ -128,5 +128,5 @@ async function processCreatePlaylist (activity: ActivityCreate, byActor: MActorS | |||
128 | 128 | ||
129 | if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url) | 129 | if (!byAccount) throw new Error('Cannot create video playlist with the non account actor ' + byActor.url) |
130 | 130 | ||
131 | await createOrUpdateVideoPlaylist(playlistObject, byAccount, activity.to) | 131 | await createOrUpdateVideoPlaylist(playlistObject, activity.to) |
132 | } | 132 | } |
diff --git a/server/lib/activitypub/process/process-update.ts b/server/lib/activitypub/process/process-update.ts index aa80d5d09..f40008a6b 100644 --- a/server/lib/activitypub/process/process-update.ts +++ b/server/lib/activitypub/process/process-update.ts | |||
@@ -111,5 +111,5 @@ async function processUpdatePlaylist (byActor: MActorSignature, activity: Activi | |||
111 | 111 | ||
112 | if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url) | 112 | if (!byAccount) throw new Error('Cannot update video playlist with the non account actor ' + byActor.url) |
113 | 113 | ||
114 | await createOrUpdateVideoPlaylist(playlistObject, byAccount, activity.to) | 114 | await createOrUpdateVideoPlaylist(playlistObject, activity.to) |
115 | } | 115 | } |
diff --git a/server/lib/activitypub/videos/get.ts b/server/lib/activitypub/videos/get.ts index 7bb14adc4..f3e2f0625 100644 --- a/server/lib/activitypub/videos/get.ts +++ b/server/lib/activitypub/videos/get.ts | |||
@@ -3,6 +3,7 @@ import { retryTransactionWrapper } from '@server/helpers/database-utils' | |||
3 | import { JobQueue } from '@server/lib/job-queue' | 3 | import { JobQueue } from '@server/lib/job-queue' |
4 | import { loadVideoByUrl, VideoLoadByUrlType } from '@server/lib/model-loaders' | 4 | import { loadVideoByUrl, VideoLoadByUrlType } from '@server/lib/model-loaders' |
5 | import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' | 5 | import { MVideoAccountLightBlacklistAllFiles, MVideoImmutable, MVideoThumbnail } from '@server/types/models' |
6 | import { APObject } from '@shared/models' | ||
6 | import { refreshVideoIfNeeded } from './refresh' | 7 | import { refreshVideoIfNeeded } from './refresh' |
7 | import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' | 8 | import { APVideoCreator, fetchRemoteVideo, SyncParam, syncVideoExternalAttributes } from './shared' |
8 | 9 | ||
@@ -13,21 +14,21 @@ type GetVideoResult <T> = Promise<{ | |||
13 | }> | 14 | }> |
14 | 15 | ||
15 | type GetVideoParamAll = { | 16 | type GetVideoParamAll = { |
16 | videoObject: { id: string } | string | 17 | videoObject: APObject |
17 | syncParam?: SyncParam | 18 | syncParam?: SyncParam |
18 | fetchType?: 'all' | 19 | fetchType?: 'all' |
19 | allowRefresh?: boolean | 20 | allowRefresh?: boolean |
20 | } | 21 | } |
21 | 22 | ||
22 | type GetVideoParamImmutable = { | 23 | type GetVideoParamImmutable = { |
23 | videoObject: { id: string } | string | 24 | videoObject: APObject |
24 | syncParam?: SyncParam | 25 | syncParam?: SyncParam |
25 | fetchType: 'only-immutable-attributes' | 26 | fetchType: 'only-immutable-attributes' |
26 | allowRefresh: false | 27 | allowRefresh: false |
27 | } | 28 | } |
28 | 29 | ||
29 | type GetVideoParamOther = { | 30 | type GetVideoParamOther = { |
30 | videoObject: { id: string } | string | 31 | videoObject: APObject |
31 | syncParam?: SyncParam | 32 | syncParam?: SyncParam |
32 | fetchType?: 'all' | 'only-video' | 33 | fetchType?: 'all' | 'only-video' |
33 | allowRefresh?: boolean | 34 | allowRefresh?: boolean |