aboutsummaryrefslogtreecommitdiffhomepage
path: root/shared
diff options
context:
space:
mode:
authorChocobozzz <me@florianbigard.com>2019-02-26 10:55:40 +0100
committerChocobozzz <chocobozzz@cpy.re>2019-03-18 11:17:59 +0100
commit418d092afa81e2c8fe8ac6838fc4b5eb0af6a782 (patch)
tree5e9bc5604fd5d66a006cfebb7acdbdd5486e5d1e /shared
parentb427febb4d5cebf03b815bca2c59af6e82491569 (diff)
downloadPeerTube-418d092afa81e2c8fe8ac6838fc4b5eb0af6a782.tar.gz
PeerTube-418d092afa81e2c8fe8ac6838fc4b5eb0af6a782.tar.zst
PeerTube-418d092afa81e2c8fe8ac6838fc4b5eb0af6a782.zip
Playlist server API
Diffstat (limited to 'shared')
-rw-r--r--shared/models/activitypub/activity.ts5
-rw-r--r--shared/models/activitypub/activitypub-actor.ts1
-rw-r--r--shared/models/activitypub/objects/playlist-element-object.ts10
-rw-r--r--shared/models/activitypub/objects/playlist-object.ts23
-rw-r--r--shared/models/actors/account.model.ts11
-rw-r--r--shared/models/overviews/videos-overview.ts4
-rw-r--r--shared/models/users/user-right.enum.ts4
-rw-r--r--shared/models/users/user-role.ts1
-rw-r--r--shared/models/videos/channel/video-channel.model.ts12
-rw-r--r--shared/models/videos/playlist/video-playlist-create.model.ts11
-rw-r--r--shared/models/videos/playlist/video-playlist-element-create.model.ts4
-rw-r--r--shared/models/videos/playlist/video-playlist-element-update.model.ts4
-rw-r--r--shared/models/videos/playlist/video-playlist-privacy.model.ts5
-rw-r--r--shared/models/videos/playlist/video-playlist-update.model.ts10
-rw-r--r--shared/models/videos/playlist/video-playlist.model.ts23
-rw-r--r--shared/models/videos/video.model.ts32
-rw-r--r--shared/utils/videos/video-playlists.ts198
-rw-r--r--shared/utils/videos/video-streaming-playlists.ts51
-rw-r--r--shared/utils/videos/videos.ts25
19 files changed, 373 insertions, 61 deletions
diff --git a/shared/models/activitypub/activity.ts b/shared/models/activitypub/activity.ts
index 89994f665..95801190d 100644
--- a/shared/models/activitypub/activity.ts
+++ b/shared/models/activitypub/activity.ts
@@ -6,6 +6,7 @@ import { VideoAbuseObject } from './objects/video-abuse-object'
6import { VideoCommentObject } from './objects/video-comment-object' 6import { VideoCommentObject } from './objects/video-comment-object'
7import { ViewObject } from './objects/view-object' 7import { ViewObject } from './objects/view-object'
8import { APObject } from './objects/object.model' 8import { APObject } from './objects/object.model'
9import { PlaylistObject } from './objects/playlist-object'
9 10
10export type Activity = ActivityCreate | ActivityUpdate | 11export type Activity = ActivityCreate | ActivityUpdate |
11 ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce | 12 ActivityDelete | ActivityFollow | ActivityAccept | ActivityAnnounce |
@@ -31,12 +32,12 @@ export interface BaseActivity {
31 32
32export interface ActivityCreate extends BaseActivity { 33export interface ActivityCreate extends BaseActivity {
33 type: 'Create' 34 type: 'Create'
34 object: VideoTorrentObject | VideoAbuseObject | ViewObject | DislikeObject | VideoCommentObject | CacheFileObject 35 object: VideoTorrentObject | VideoAbuseObject | ViewObject | DislikeObject | VideoCommentObject | CacheFileObject | PlaylistObject
35} 36}
36 37
37export interface ActivityUpdate extends BaseActivity { 38export interface ActivityUpdate extends BaseActivity {
38 type: 'Update' 39 type: 'Update'
39 object: VideoTorrentObject | ActivityPubActor | CacheFileObject 40 object: VideoTorrentObject | ActivityPubActor | CacheFileObject | PlaylistObject
40} 41}
41 42
42export interface ActivityDelete extends BaseActivity { 43export interface ActivityDelete extends BaseActivity {
diff --git a/shared/models/activitypub/activitypub-actor.ts b/shared/models/activitypub/activitypub-actor.ts
index 119bc22d4..5e30bf783 100644
--- a/shared/models/activitypub/activitypub-actor.ts
+++ b/shared/models/activitypub/activitypub-actor.ts
@@ -8,6 +8,7 @@ export interface ActivityPubActor {
8 id: string 8 id: string
9 following: string 9 following: string
10 followers: string 10 followers: string
11 playlists?: string
11 inbox: string 12 inbox: string
12 outbox: string 13 outbox: string
13 preferredUsername: string 14 preferredUsername: string
diff --git a/shared/models/activitypub/objects/playlist-element-object.ts b/shared/models/activitypub/objects/playlist-element-object.ts
new file mode 100644
index 000000000..b85e4fe19
--- /dev/null
+++ b/shared/models/activitypub/objects/playlist-element-object.ts
@@ -0,0 +1,10 @@
1export interface PlaylistElementObject {
2 id: string
3 type: 'PlaylistElement'
4
5 url: string
6 position: number
7
8 startTimestamp?: number
9 stopTimestamp?: number
10}
diff --git a/shared/models/activitypub/objects/playlist-object.ts b/shared/models/activitypub/objects/playlist-object.ts
new file mode 100644
index 000000000..5f6733f92
--- /dev/null
+++ b/shared/models/activitypub/objects/playlist-object.ts
@@ -0,0 +1,23 @@
1import { ActivityIconObject } from './common-objects'
2
3export interface PlaylistObject {
4 id: string
5 type: 'Playlist'
6
7 name: string
8 content: string
9 uuid: string
10
11 totalItems: number
12 attributedTo: string[]
13
14 icon: ActivityIconObject
15
16 orderedItems?: string[]
17
18 partOf?: string
19 next?: string
20 first?: string
21
22 to?: string[]
23}
diff --git a/shared/models/actors/account.model.ts b/shared/models/actors/account.model.ts
index 7f1dbbc37..043a2507e 100644
--- a/shared/models/actors/account.model.ts
+++ b/shared/models/actors/account.model.ts
@@ -1,4 +1,5 @@
1import { Actor } from './actor.model' 1import { Actor } from './actor.model'
2import { Avatar } from '../avatars'
2 3
3export interface Account extends Actor { 4export interface Account extends Actor {
4 displayName: string 5 displayName: string
@@ -6,3 +7,13 @@ export interface Account extends Actor {
6 7
7 userId?: number 8 userId?: number
8} 9}
10
11export interface AccountSummary {
12 id: number
13 uuid: string
14 name: string
15 displayName: string
16 url: string
17 host: string
18 avatar?: Avatar
19}
diff --git a/shared/models/overviews/videos-overview.ts b/shared/models/overviews/videos-overview.ts
index ee009d94c..e725f166b 100644
--- a/shared/models/overviews/videos-overview.ts
+++ b/shared/models/overviews/videos-overview.ts
@@ -1,8 +1,8 @@
1import { Video, VideoChannelAttribute, VideoConstant } from '../videos' 1import { Video, VideoChannelSummary, VideoConstant } from '../videos'
2 2
3export interface VideosOverview { 3export interface VideosOverview {
4 channels: { 4 channels: {
5 channel: VideoChannelAttribute 5 channel: VideoChannelSummary
6 videos: Video[] 6 videos: Video[]
7 }[] 7 }[]
8 8
diff --git a/shared/models/users/user-right.enum.ts b/shared/models/users/user-right.enum.ts
index 090256bca..eaa064bd9 100644
--- a/shared/models/users/user-right.enum.ts
+++ b/shared/models/users/user-right.enum.ts
@@ -20,8 +20,12 @@ export enum UserRight {
20 20
21 REMOVE_ANY_VIDEO, 21 REMOVE_ANY_VIDEO,
22 REMOVE_ANY_VIDEO_CHANNEL, 22 REMOVE_ANY_VIDEO_CHANNEL,
23 REMOVE_ANY_VIDEO_PLAYLIST,
23 REMOVE_ANY_VIDEO_COMMENT, 24 REMOVE_ANY_VIDEO_COMMENT,
25
24 UPDATE_ANY_VIDEO, 26 UPDATE_ANY_VIDEO,
27 UPDATE_ANY_VIDEO_PLAYLIST,
28
25 SEE_ALL_VIDEOS, 29 SEE_ALL_VIDEOS,
26 CHANGE_VIDEO_OWNERSHIP 30 CHANGE_VIDEO_OWNERSHIP
27} 31}
diff --git a/shared/models/users/user-role.ts b/shared/models/users/user-role.ts
index 59c2ba106..0b6554e51 100644
--- a/shared/models/users/user-role.ts
+++ b/shared/models/users/user-role.ts
@@ -25,6 +25,7 @@ const userRoleRights: { [ id: number ]: UserRight[] } = {
25 UserRight.MANAGE_VIDEO_ABUSES, 25 UserRight.MANAGE_VIDEO_ABUSES,
26 UserRight.REMOVE_ANY_VIDEO, 26 UserRight.REMOVE_ANY_VIDEO,
27 UserRight.REMOVE_ANY_VIDEO_CHANNEL, 27 UserRight.REMOVE_ANY_VIDEO_CHANNEL,
28 UserRight.REMOVE_ANY_VIDEO_PLAYLIST,
28 UserRight.REMOVE_ANY_VIDEO_COMMENT, 29 UserRight.REMOVE_ANY_VIDEO_COMMENT,
29 UserRight.UPDATE_ANY_VIDEO, 30 UserRight.UPDATE_ANY_VIDEO,
30 UserRight.SEE_ALL_VIDEOS, 31 UserRight.SEE_ALL_VIDEOS,
diff --git a/shared/models/videos/channel/video-channel.model.ts b/shared/models/videos/channel/video-channel.model.ts
index 92918f66c..14a813f8f 100644
--- a/shared/models/videos/channel/video-channel.model.ts
+++ b/shared/models/videos/channel/video-channel.model.ts
@@ -1,6 +1,6 @@
1import { Actor } from '../../actors/actor.model' 1import { Actor } from '../../actors/actor.model'
2import { Video } from '../video.model'
3import { Account } from '../../actors/index' 2import { Account } from '../../actors/index'
3import { Avatar } from '../../avatars'
4 4
5export interface VideoChannel extends Actor { 5export interface VideoChannel extends Actor {
6 displayName: string 6 displayName: string
@@ -9,3 +9,13 @@ export interface VideoChannel extends Actor {
9 isLocal: boolean 9 isLocal: boolean
10 ownerAccount?: Account 10 ownerAccount?: Account
11} 11}
12
13export interface VideoChannelSummary {
14 id: number
15 uuid: string
16 name: string
17 displayName: string
18 url: string
19 host: string
20 avatar?: Avatar
21}
diff --git a/shared/models/videos/playlist/video-playlist-create.model.ts b/shared/models/videos/playlist/video-playlist-create.model.ts
new file mode 100644
index 000000000..386acbb96
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist-create.model.ts
@@ -0,0 +1,11 @@
1import { VideoPlaylistPrivacy } from './video-playlist-privacy.model'
2
3export interface VideoPlaylistCreate {
4 displayName: string
5 description: string
6 privacy: VideoPlaylistPrivacy
7
8 videoChannelId?: number
9
10 thumbnailfile?: Blob
11}
diff --git a/shared/models/videos/playlist/video-playlist-element-create.model.ts b/shared/models/videos/playlist/video-playlist-element-create.model.ts
new file mode 100644
index 000000000..9bd56a8ca
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist-element-create.model.ts
@@ -0,0 +1,4 @@
1export interface VideoPlaylistElementCreate {
2 startTimestamp?: number
3 stopTimestamp?: number
4}
diff --git a/shared/models/videos/playlist/video-playlist-element-update.model.ts b/shared/models/videos/playlist/video-playlist-element-update.model.ts
new file mode 100644
index 000000000..15a30fbdc
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist-element-update.model.ts
@@ -0,0 +1,4 @@
1export interface VideoPlaylistElementUpdate {
2 startTimestamp?: number
3 stopTimestamp?: number
4}
diff --git a/shared/models/videos/playlist/video-playlist-privacy.model.ts b/shared/models/videos/playlist/video-playlist-privacy.model.ts
new file mode 100644
index 000000000..96e5e2211
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist-privacy.model.ts
@@ -0,0 +1,5 @@
1export enum VideoPlaylistPrivacy {
2 PUBLIC = 1,
3 UNLISTED = 2,
4 PRIVATE = 3
5}
diff --git a/shared/models/videos/playlist/video-playlist-update.model.ts b/shared/models/videos/playlist/video-playlist-update.model.ts
new file mode 100644
index 000000000..c7a15c550
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist-update.model.ts
@@ -0,0 +1,10 @@
1import { VideoPlaylistPrivacy } from './video-playlist-privacy.model'
2
3export interface VideoPlaylistUpdate {
4 displayName: string
5 description: string
6 privacy: VideoPlaylistPrivacy
7
8 videoChannelId?: number
9 thumbnailfile?: Blob
10}
diff --git a/shared/models/videos/playlist/video-playlist.model.ts b/shared/models/videos/playlist/video-playlist.model.ts
new file mode 100644
index 000000000..6aa04048c
--- /dev/null
+++ b/shared/models/videos/playlist/video-playlist.model.ts
@@ -0,0 +1,23 @@
1import { AccountSummary } from '../../actors/index'
2import { VideoChannelSummary, VideoConstant } from '..'
3import { VideoPlaylistPrivacy } from './video-playlist-privacy.model'
4
5export interface VideoPlaylist {
6 id: number
7 uuid: string
8 isLocal: boolean
9
10 displayName: string
11 description: string
12 privacy: VideoConstant<VideoPlaylistPrivacy>
13
14 thumbnailPath: string
15
16 videosLength: number
17
18 createdAt: Date | string
19 updatedAt: Date | string
20
21 ownerAccount?: AccountSummary
22 videoChannel?: VideoChannelSummary
23}
diff --git a/shared/models/videos/video.model.ts b/shared/models/videos/video.model.ts
index df800461c..6e7a6831e 100644
--- a/shared/models/videos/video.model.ts
+++ b/shared/models/videos/video.model.ts
@@ -1,4 +1,4 @@
1import { VideoResolution, VideoState } from '../../index' 1import { AccountSummary, VideoChannelSummary, VideoResolution, VideoState } from '../../index'
2import { Account } from '../actors' 2import { Account } from '../actors'
3import { Avatar } from '../avatars/avatar.model' 3import { Avatar } from '../avatars/avatar.model'
4import { VideoChannel } from './channel/video-channel.model' 4import { VideoChannel } from './channel/video-channel.model'
@@ -18,26 +18,6 @@ export interface VideoFile {
18 fps: number 18 fps: number
19} 19}
20 20
21export interface VideoChannelAttribute {
22 id: number
23 uuid: string
24 name: string
25 displayName: string
26 url: string
27 host: string
28 avatar?: Avatar
29}
30
31export interface AccountAttribute {
32 id: number
33 uuid: string
34 name: string
35 displayName: string
36 url: string
37 host: string
38 avatar?: Avatar
39}
40
41export interface Video { 21export interface Video {
42 id: number 22 id: number
43 uuid: string 23 uuid: string
@@ -68,12 +48,18 @@ export interface Video {
68 blacklisted?: boolean 48 blacklisted?: boolean
69 blacklistedReason?: string 49 blacklistedReason?: string
70 50
71 account: AccountAttribute 51 account: AccountSummary
72 channel: VideoChannelAttribute 52 channel: VideoChannelSummary
73 53
74 userHistory?: { 54 userHistory?: {
75 currentTime: number 55 currentTime: number
76 } 56 }
57
58 playlistElement?: {
59 position: number
60 startTimestamp: number
61 stopTimestamp: number
62 }
77} 63}
78 64
79export interface VideoDetails extends Video { 65export interface VideoDetails extends Video {
diff --git a/shared/utils/videos/video-playlists.ts b/shared/utils/videos/video-playlists.ts
index eb25011cb..5186d9c4f 100644
--- a/shared/utils/videos/video-playlists.ts
+++ b/shared/utils/videos/video-playlists.ts
@@ -1,51 +1,185 @@
1import { makeRawRequest } from '../requests/requests' 1import { makeDeleteRequest, makeGetRequest, makePostBodyRequest, makePutBodyRequest, makeUploadRequest } from '../requests/requests'
2import { sha256 } from '../../../server/helpers/core-utils' 2import { VideoPlaylistCreate } from '../../models/videos/playlist/video-playlist-create.model'
3import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model' 3import { omit } from 'lodash'
4import { expect } from 'chai' 4import { VideoPlaylistUpdate } from '../../models/videos/playlist/video-playlist-update.model'
5import { VideoPlaylistElementCreate } from '../../models/videos/playlist/video-playlist-element-create.model'
6import { VideoPlaylistElementUpdate } from '../../models/videos/playlist/video-playlist-element-update.model'
5 7
6function getPlaylist (url: string, statusCodeExpected = 200) { 8function getVideoPlaylistsList (url: string, start: number, count: number, sort?: string) {
7 return makeRawRequest(url, statusCodeExpected) 9 const path = '/api/v1/video-playlists'
10
11 const query = {
12 start,
13 count,
14 sort
15 }
16
17 return makeGetRequest({
18 url,
19 path,
20 query
21 })
8} 22}
9 23
10function getSegment (url: string, statusCodeExpected = 200, range?: string) { 24function getVideoPlaylist (url: string, playlistId: number | string, statusCodeExpected = 200) {
11 return makeRawRequest(url, statusCodeExpected, range) 25 const path = '/api/v1/video-playlists/' + playlistId
26
27 return makeGetRequest({
28 url,
29 path,
30 statusCodeExpected
31 })
12} 32}
13 33
14function getSegmentSha256 (url: string, statusCodeExpected = 200) { 34function deleteVideoPlaylist (url: string, token: string, playlistId: number | string, statusCodeExpected = 200) {
15 return makeRawRequest(url, statusCodeExpected) 35 const path = '/api/v1/video-playlists/' + playlistId
36
37 return makeDeleteRequest({
38 url,
39 path,
40 token,
41 statusCodeExpected
42 })
16} 43}
17 44
18async function checkSegmentHash ( 45function createVideoPlaylist (options: {
19 baseUrlPlaylist: string, 46 url: string,
20 baseUrlSegment: string, 47 token: string,
21 videoUUID: string, 48 playlistAttrs: VideoPlaylistCreate,
22 resolution: number, 49 expectedStatus: number
23 hlsPlaylist: VideoStreamingPlaylist 50}) {
24) { 51 const path = '/api/v1/video-playlists/'
25 const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`) 52
26 const playlist = res.text 53 const fields = omit(options.playlistAttrs, 'thumbnailfile')
27 54
28 const videoName = `${videoUUID}-${resolution}-fragmented.mp4` 55 const attaches = options.playlistAttrs.thumbnailfile
56 ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
57 : {}
29 58
30 const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist) 59 return makeUploadRequest({
60 method: 'POST',
61 url: options.url,
62 path,
63 token: options.token,
64 fields,
65 attaches,
66 statusCodeExpected: options.expectedStatus
67 })
68}
31 69
32 const length = parseInt(matches[1], 10) 70function updateVideoPlaylist (options: {
33 const offset = parseInt(matches[2], 10) 71 url: string,
34 const range = `${offset}-${offset + length - 1}` 72 token: string,
73 playlistAttrs: VideoPlaylistUpdate,
74 expectedStatus: number
75}) {
76 const path = '/api/v1/video-playlists/'
35 77
36 const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, 206, `bytes=${range}`) 78 const fields = omit(options.playlistAttrs, 'thumbnailfile')
37 79
38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url) 80 const attaches = options.playlistAttrs.thumbnailfile
81 ? { thumbnailfile: options.playlistAttrs.thumbnailfile }
82 : {}
39 83
40 const sha256Server = resSha.body[ videoName ][range] 84 return makeUploadRequest({
41 expect(sha256(res2.body)).to.equal(sha256Server) 85 method: 'PUT',
86 url: options.url,
87 path,
88 token: options.token,
89 fields,
90 attaches,
91 statusCodeExpected: options.expectedStatus
92 })
93}
94
95function addVideoInPlaylist (options: {
96 url: string,
97 token: string,
98 playlistId: number | string,
99 elementAttrs: VideoPlaylistElementCreate
100 expectedStatus: number
101}) {
102 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos'
103
104 return makePostBodyRequest({
105 url: options.url,
106 path,
107 token: options.token,
108 fields: options.elementAttrs,
109 statusCodeExpected: options.expectedStatus
110 })
111}
112
113function updateVideoPlaylistElement (options: {
114 url: string,
115 token: string,
116 playlistId: number | string,
117 videoId: number | string,
118 elementAttrs: VideoPlaylistElementUpdate,
119 expectedStatus: number
120}) {
121 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
122
123 return makePutBodyRequest({
124 url: options.url,
125 path,
126 token: options.token,
127 fields: options.elementAttrs,
128 statusCodeExpected: options.expectedStatus
129 })
130}
131
132function removeVideoFromPlaylist (options: {
133 url: string,
134 token: string,
135 playlistId: number | string,
136 videoId: number | string,
137 expectedStatus: number
138}) {
139 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos/' + options.videoId
140
141 return makeDeleteRequest({
142 url: options.url,
143 path,
144 token: options.token,
145 statusCodeExpected: options.expectedStatus
146 })
147}
148
149function reorderVideosPlaylist (options: {
150 url: string,
151 token: string,
152 playlistId: number | string,
153 elementAttrs: {
154 startPosition: number,
155 insertAfter: number,
156 reorderLength?: number
157 },
158 expectedStatus: number
159}) {
160 const path = '/api/v1/video-playlists/' + options.playlistId + '/videos'
161
162 return makePutBodyRequest({
163 url: options.url,
164 path,
165 token: options.token,
166 fields: options.elementAttrs,
167 statusCodeExpected: options.expectedStatus
168 })
42} 169}
43 170
44// --------------------------------------------------------------------------- 171// ---------------------------------------------------------------------------
45 172
46export { 173export {
47 getPlaylist, 174 getVideoPlaylistsList,
48 getSegment, 175 getVideoPlaylist,
49 getSegmentSha256, 176
50 checkSegmentHash 177 createVideoPlaylist,
178 updateVideoPlaylist,
179 deleteVideoPlaylist,
180
181 addVideoInPlaylist,
182 removeVideoFromPlaylist,
183
184 reorderVideosPlaylist
51} 185}
diff --git a/shared/utils/videos/video-streaming-playlists.ts b/shared/utils/videos/video-streaming-playlists.ts
new file mode 100644
index 000000000..eb25011cb
--- /dev/null
+++ b/shared/utils/videos/video-streaming-playlists.ts
@@ -0,0 +1,51 @@
1import { makeRawRequest } from '../requests/requests'
2import { sha256 } from '../../../server/helpers/core-utils'
3import { VideoStreamingPlaylist } from '../../models/videos/video-streaming-playlist.model'
4import { expect } from 'chai'
5
6function getPlaylist (url: string, statusCodeExpected = 200) {
7 return makeRawRequest(url, statusCodeExpected)
8}
9
10function getSegment (url: string, statusCodeExpected = 200, range?: string) {
11 return makeRawRequest(url, statusCodeExpected, range)
12}
13
14function getSegmentSha256 (url: string, statusCodeExpected = 200) {
15 return makeRawRequest(url, statusCodeExpected)
16}
17
18async function checkSegmentHash (
19 baseUrlPlaylist: string,
20 baseUrlSegment: string,
21 videoUUID: string,
22 resolution: number,
23 hlsPlaylist: VideoStreamingPlaylist
24) {
25 const res = await getPlaylist(`${baseUrlPlaylist}/${videoUUID}/${resolution}.m3u8`)
26 const playlist = res.text
27
28 const videoName = `${videoUUID}-${resolution}-fragmented.mp4`
29
30 const matches = /#EXT-X-BYTERANGE:(\d+)@(\d+)/.exec(playlist)
31
32 const length = parseInt(matches[1], 10)
33 const offset = parseInt(matches[2], 10)
34 const range = `${offset}-${offset + length - 1}`
35
36 const res2 = await getSegment(`${baseUrlSegment}/${videoUUID}/${videoName}`, 206, `bytes=${range}`)
37
38 const resSha = await getSegmentSha256(hlsPlaylist.segmentsSha256Url)
39
40 const sha256Server = resSha.body[ videoName ][range]
41 expect(sha256(res2.body)).to.equal(sha256Server)
42}
43
44// ---------------------------------------------------------------------------
45
46export {
47 getPlaylist,
48 getSegment,
49 getSegmentSha256,
50 checkSegmentHash
51}
diff --git a/shared/utils/videos/videos.ts b/shared/utils/videos/videos.ts
index b3d24bc53..2c09f0086 100644
--- a/shared/utils/videos/videos.ts
+++ b/shared/utils/videos/videos.ts
@@ -223,6 +223,28 @@ function getVideoChannelVideos (
223 }) 223 })
224} 224}
225 225
226function getPlaylistVideos (
227 url: string,
228 accessToken: string,
229 playlistId: number | string,
230 start: number,
231 count: number,
232 query: { nsfw?: boolean } = {}
233) {
234 const path = '/api/v1/video-playlists/' + playlistId + '/videos'
235
236 return makeGetRequest({
237 url,
238 path,
239 query: immutableAssign(query, {
240 start,
241 count
242 }),
243 token: accessToken,
244 statusCodeExpected: 200
245 })
246}
247
226function getVideosListPagination (url: string, start: number, count: number, sort?: string) { 248function getVideosListPagination (url: string, start: number, count: number, sort?: string) {
227 const path = '/api/v1/videos' 249 const path = '/api/v1/videos'
228 250
@@ -601,5 +623,6 @@ export {
601 parseTorrentVideo, 623 parseTorrentVideo,
602 getLocalVideos, 624 getLocalVideos,
603 completeVideoCheck, 625 completeVideoCheck,
604 checkVideoFilesWereRemoved 626 checkVideoFilesWereRemoved,
627 getPlaylistVideos
605} 628}