diff options
-rw-r--r-- | server/controllers/api/videos/import.ts | 3 | ||||
-rw-r--r-- | server/helpers/youtube-dl.ts | 19 | ||||
-rw-r--r-- | server/lib/activitypub/actor.ts | 2 | ||||
-rw-r--r-- | server/models/video/video-import.ts | 1 | ||||
-rw-r--r-- | server/tests/api/videos/video-imports.ts | 58 |
5 files changed, 47 insertions, 36 deletions
diff --git a/server/controllers/api/videos/import.ts b/server/controllers/api/videos/import.ts index e9b9d68d7..fb9d73140 100644 --- a/server/controllers/api/videos/import.ts +++ b/server/controllers/api/videos/import.ts | |||
@@ -172,11 +172,12 @@ async function addYoutubeDLImport (req: express.Request, res: express.Response) | |||
172 | user | 172 | user |
173 | }) | 173 | }) |
174 | 174 | ||
175 | |||
176 | // Get video subtitles | 175 | // Get video subtitles |
177 | try { | 176 | try { |
178 | const subtitles = await getYoutubeDLSubs(targetUrl) | 177 | const subtitles = await getYoutubeDLSubs(targetUrl) |
179 | 178 | ||
179 | logger.info('Will create %s subtitles from youtube import %s.', subtitles.length, targetUrl) | ||
180 | |||
180 | for (const subtitle of subtitles) { | 181 | for (const subtitle of subtitles) { |
181 | const videoCaption = new VideoCaptionModel({ | 182 | const videoCaption = new VideoCaptionModel({ |
182 | videoId: video.id, | 183 | videoId: video.id, |
diff --git a/server/helpers/youtube-dl.ts b/server/helpers/youtube-dl.ts index 277422645..6d2e6f6d1 100644 --- a/server/helpers/youtube-dl.ts +++ b/server/helpers/youtube-dl.ts | |||
@@ -21,8 +21,8 @@ export type YoutubeDLInfo = { | |||
21 | } | 21 | } |
22 | 22 | ||
23 | export type YoutubeDLSubs = { | 23 | export type YoutubeDLSubs = { |
24 | language: string, | 24 | language: string |
25 | filename: string, | 25 | filename: string |
26 | path: string | 26 | path: string |
27 | }[] | 27 | }[] |
28 | 28 | ||
@@ -61,15 +61,20 @@ function getYoutubeDLSubs (url: string, opts?: object): Promise<YoutubeDLSubs> { | |||
61 | youtubeDL.getSubs(url, options, (err, files) => { | 61 | youtubeDL.getSubs(url, options, (err, files) => { |
62 | if (err) return rej(err) | 62 | if (err) return rej(err) |
63 | 63 | ||
64 | logger.debug('Get subtitles from youtube dl.', { url, files }) | ||
65 | |||
64 | const subtitles = files.reduce((acc, filename) => { | 66 | const subtitles = files.reduce((acc, filename) => { |
65 | const matched = filename.match(/\.([a-z]{2})\.(vtt|ttml)/i) | 67 | const matched = filename.match(/\.([a-z]{2})\.(vtt|ttml)/i) |
66 | 68 | ||
67 | if (matched[1]) { | 69 | if (matched[1]) { |
68 | return [...acc, { | 70 | return [ |
69 | language: matched[1], | 71 | ...acc, |
70 | path: join(cwd, filename), | 72 | { |
71 | filename | 73 | language: matched[1], |
72 | }] | 74 | path: join(cwd, filename), |
75 | filename | ||
76 | } | ||
77 | ] | ||
73 | } | 78 | } |
74 | }, []) | 79 | }, []) |
75 | 80 | ||
diff --git a/server/lib/activitypub/actor.ts b/server/lib/activitypub/actor.ts index c3598b75b..8132ac135 100644 --- a/server/lib/activitypub/actor.ts +++ b/server/lib/activitypub/actor.ts | |||
@@ -117,7 +117,7 @@ async function getOrCreateActorAndServerAndModel ( | |||
117 | if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor | 117 | if (actor.VideoChannel) (actor as MActorAccountChannelIdActor).VideoChannel.Actor = actor |
118 | 118 | ||
119 | const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) | 119 | const { actor: actorRefreshed, refreshed } = await retryTransactionWrapper(refreshActorIfNeeded, actor, fetchType) |
120 | if (!actorRefreshed) throw new Error('Actor ' + actorRefreshed.url + ' does not exist anymore.') | 120 | if (!actorRefreshed) throw new Error('Actor ' + actor.url + ' does not exist anymore.') |
121 | 121 | ||
122 | if ((created === true || refreshed === true) && updateCollections === true) { | 122 | if ((created === true || refreshed === true) && updateCollections === true) { |
123 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } | 123 | const payload = { uri: actor.outboxUrl, type: 'activity' as 'activity' } |
diff --git a/server/models/video/video-import.ts b/server/models/video/video-import.ts index af5314ce9..fbe0ee0a7 100644 --- a/server/models/video/video-import.ts +++ b/server/models/video/video-import.ts | |||
@@ -129,6 +129,7 @@ export class VideoImportModel extends Model<VideoImportModel> { | |||
129 | distinct: true, | 129 | distinct: true, |
130 | include: [ | 130 | include: [ |
131 | { | 131 | { |
132 | attributes: [ 'id' ], | ||
132 | model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query | 133 | model: UserModel.unscoped(), // FIXME: Without this, sequelize try to COUNT(DISTINCT(*)) which is an invalid SQL query |
133 | required: true | 134 | required: true |
134 | } | 135 | } |
diff --git a/server/tests/api/videos/video-imports.ts b/server/tests/api/videos/video-imports.ts index 1e97cc6ca..8e179b825 100644 --- a/server/tests/api/videos/video-imports.ts +++ b/server/tests/api/videos/video-imports.ts | |||
@@ -62,11 +62,14 @@ describe('Test video imports', function () { | |||
62 | 62 | ||
63 | expect(videoTorrent.name).to.contain('你好 世界 720p.mp4') | 63 | expect(videoTorrent.name).to.contain('你好 世界 720p.mp4') |
64 | expect(videoMagnet.name).to.contain('super peertube2 video') | 64 | expect(videoMagnet.name).to.contain('super peertube2 video') |
65 | |||
66 | const resCaptions = await listVideoCaptions(url, idHttp) | ||
67 | expect(resCaptions.body.total).to.equal(2) | ||
65 | } | 68 | } |
66 | 69 | ||
67 | async function checkVideoServer2 (url: string, id: number | string) { | 70 | async function checkVideoServer2 (url: string, id: number | string) { |
68 | const res = await getVideo(url, id) | 71 | const res = await getVideo(url, id) |
69 | const video = res.body | 72 | const video: VideoDetails = res.body |
70 | 73 | ||
71 | expect(video.name).to.equal('my super name') | 74 | expect(video.name).to.equal('my super name') |
72 | expect(video.category.label).to.equal('Entertainment') | 75 | expect(video.category.label).to.equal('Entertainment') |
@@ -77,6 +80,9 @@ describe('Test video imports', function () { | |||
77 | expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ]) | 80 | expect(video.tags).to.deep.equal([ 'supertag1', 'supertag2' ]) |
78 | 81 | ||
79 | expect(video.files).to.have.lengthOf(1) | 82 | expect(video.files).to.have.lengthOf(1) |
83 | |||
84 | const resCaptions = await listVideoCaptions(url, id) | ||
85 | expect(resCaptions.body.total).to.equal(2) | ||
80 | } | 86 | } |
81 | 87 | ||
82 | before(async function () { | 88 | before(async function () { |
@@ -114,44 +120,42 @@ describe('Test video imports', function () { | |||
114 | expect(res.body.video.name).to.equal('small video - youtube') | 120 | expect(res.body.video.name).to.equal('small video - youtube') |
115 | 121 | ||
116 | const resCaptions = await listVideoCaptions(servers[0].url, res.body.video.id) | 122 | const resCaptions = await listVideoCaptions(servers[0].url, res.body.video.id) |
117 | const videoCaptions: VideoCaption[] = resCaptions.body | 123 | const videoCaptions: VideoCaption[] = resCaptions.body.data |
118 | expect(videoCaptions).to.have.lengthOf(2) | 124 | expect(videoCaptions).to.have.lengthOf(2) |
119 | 125 | ||
120 | const enCaption = videoCaptions.filter(caption => caption.language.label === 'en')[0] | 126 | const enCaption = videoCaptions.find(caption => caption.language.id === 'en') |
121 | expect(enCaption).to.not(undefined) | 127 | expect(enCaption).to.exist |
122 | expect(enCaption.language.label).to.equal('en') | 128 | expect(enCaption.language.label).to.equal('English') |
123 | expect(enCaption.captionPath).to.equal(`/static/video-captions/${res.body.video.uuid}-en.vtt`) | 129 | expect(enCaption.captionPath).to.equal(`/static/video-captions/${res.body.video.uuid}-en.vtt`) |
124 | await testCaptionFile(servers[0].url, enCaption.captionPath, `WEBVTT | 130 | await testCaptionFile(servers[0].url, enCaption.captionPath, `WEBVTT |
131 | Kind: captions | ||
132 | Language: en | ||
125 | 133 | ||
126 | 1 | 134 | 00:00:01.600 --> 00:00:04.200 |
127 | 00:00:01.600 --> 00:00:04.200 | 135 | English (US) |
128 | English (US) | ||
129 | 136 | ||
130 | 2 | 137 | 00:00:05.900 --> 00:00:07.999 |
131 | 00:00:05.900 --> 00:00:07.999 | 138 | This is a subtitle in American English |
132 | This is a subtitle in American English | ||
133 | 139 | ||
134 | 3 | 140 | 00:00:10.000 --> 00:00:14.000 |
135 | 00:00:10.000 --> 00:00:14.000 | 141 | Adding subtitles is very easy to do`) |
136 | Adding subtitles is very easy to do`) | ||
137 | 142 | ||
138 | const frCaption = videoCaptions.filter(caption => caption.language.label === 'fr')[0] | 143 | const frCaption = videoCaptions.find(caption => caption.language.id === 'fr') |
139 | expect(frCaption).to.not(undefined) | 144 | expect(frCaption).to.exist |
140 | expect(frCaption.language.label).to.equal('fr') | 145 | expect(frCaption.language.label).to.equal('French') |
141 | expect(frCaption.captionPath).to.equal(`/static/video-captions/${res.body.video.uuid}-en.vtt`) | 146 | expect(frCaption.captionPath).to.equal(`/static/video-captions/${res.body.video.uuid}-fr.vtt`) |
142 | await testCaptionFile(servers[0].url, frCaption.captionPath, `WEBVTT | 147 | await testCaptionFile(servers[0].url, frCaption.captionPath, `WEBVTT |
148 | Kind: captions | ||
149 | Language: fr | ||
143 | 150 | ||
144 | 1 | 151 | 00:00:01.600 --> 00:00:04.200 |
145 | 00:00:01,600 --> 00:00:04.200 | 152 | Français (FR) |
146 | Français (FR) | ||
147 | 153 | ||
148 | 2 | 154 | 00:00:05.900 --> 00:00:07.999 |
149 | 00:00:05,900 --> 00:00:07.999 | 155 | C'est un sous-titre français |
150 | C'est un sous-titre français | ||
151 | 156 | ||
152 | 3 | 157 | 00:00:10.000 --> 00:00:14.000 |
153 | 00:00:10,000 --> 00:00:14.000 | 158 | Ajouter un sous-titre est vraiment facile`) |
154 | Ajouter un sous-titre est vraiment facile`) | ||
155 | } | 159 | } |
156 | 160 | ||
157 | { | 161 | { |