ニジカ投稿局 https://tv.nizika.tv
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

video-live-session.ts 4.6 KiB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216
  1. import { LiveVideoSession, type LiveVideoErrorType } from '@peertube/peertube-models'
  2. import { uuidToShort } from '@peertube/peertube-node-utils'
  3. import { AttributesOnly } from '@peertube/peertube-typescript-utils'
  4. import { MVideoLiveSession, MVideoLiveSessionReplay } from '@server/types/models/index.js'
  5. import { FindOptions } from 'sequelize'
  6. import {
  7. AllowNull,
  8. BeforeDestroy,
  9. BelongsTo,
  10. Column,
  11. CreatedAt,
  12. DataType,
  13. ForeignKey, Scopes,
  14. Table,
  15. UpdatedAt
  16. } from 'sequelize-typescript'
  17. import { VideoLiveReplaySettingModel } from './video-live-replay-setting.js'
  18. import { VideoModel } from './video.js'
  19. import { SequelizeModel } from '../shared/index.js'
  20. export enum ScopeNames {
  21. WITH_REPLAY = 'WITH_REPLAY'
  22. }
  23. @Scopes(() => ({
  24. [ScopeNames.WITH_REPLAY]: {
  25. include: [
  26. {
  27. model: VideoModel.unscoped(),
  28. as: 'ReplayVideo',
  29. required: false
  30. },
  31. {
  32. model: VideoLiveReplaySettingModel,
  33. required: false
  34. }
  35. ]
  36. }
  37. }))
  38. @Table({
  39. tableName: 'videoLiveSession',
  40. indexes: [
  41. {
  42. fields: [ 'replayVideoId' ],
  43. unique: true
  44. },
  45. {
  46. fields: [ 'liveVideoId' ]
  47. },
  48. {
  49. fields: [ 'replaySettingId' ],
  50. unique: true
  51. }
  52. ]
  53. })
  54. export class VideoLiveSessionModel extends SequelizeModel<VideoLiveSessionModel> {
  55. @CreatedAt
  56. createdAt: Date
  57. @UpdatedAt
  58. updatedAt: Date
  59. @AllowNull(false)
  60. @Column(DataType.DATE)
  61. startDate: Date
  62. @AllowNull(true)
  63. @Column(DataType.DATE)
  64. endDate: Date
  65. @AllowNull(true)
  66. @Column
  67. error: LiveVideoErrorType
  68. @AllowNull(false)
  69. @Column
  70. saveReplay: boolean
  71. @AllowNull(false)
  72. @Column
  73. endingProcessed: boolean
  74. @ForeignKey(() => VideoModel)
  75. @Column
  76. replayVideoId: number
  77. @BelongsTo(() => VideoModel, {
  78. foreignKey: {
  79. allowNull: true,
  80. name: 'replayVideoId'
  81. },
  82. as: 'ReplayVideo',
  83. onDelete: 'set null'
  84. })
  85. ReplayVideo: Awaited<VideoModel>
  86. @ForeignKey(() => VideoModel)
  87. @Column
  88. liveVideoId: number
  89. @BelongsTo(() => VideoModel, {
  90. foreignKey: {
  91. allowNull: true,
  92. name: 'liveVideoId'
  93. },
  94. as: 'LiveVideo',
  95. onDelete: 'set null'
  96. })
  97. LiveVideo: Awaited<VideoModel>
  98. @ForeignKey(() => VideoLiveReplaySettingModel)
  99. @Column
  100. replaySettingId: number
  101. @BelongsTo(() => VideoLiveReplaySettingModel, {
  102. foreignKey: {
  103. allowNull: true
  104. },
  105. onDelete: 'set null'
  106. })
  107. ReplaySetting: Awaited<VideoLiveReplaySettingModel>
  108. @BeforeDestroy
  109. static deleteReplaySetting (instance: VideoLiveSessionModel) {
  110. return VideoLiveReplaySettingModel.destroy({
  111. where: {
  112. id: instance.replaySettingId
  113. }
  114. })
  115. }
  116. static load (id: number): Promise<MVideoLiveSession> {
  117. return VideoLiveSessionModel.findOne({
  118. where: { id }
  119. })
  120. }
  121. static findSessionOfReplay (replayVideoId: number) {
  122. const query = {
  123. where: {
  124. replayVideoId
  125. }
  126. }
  127. return VideoLiveSessionModel.scope(ScopeNames.WITH_REPLAY).findOne(query)
  128. }
  129. static findCurrentSessionOf (videoUUID: string) {
  130. return VideoLiveSessionModel.findOne({
  131. where: {
  132. endDate: null
  133. },
  134. include: [
  135. {
  136. model: VideoModel.unscoped(),
  137. as: 'LiveVideo',
  138. required: true,
  139. where: {
  140. uuid: videoUUID
  141. }
  142. }
  143. ],
  144. order: [ [ 'startDate', 'DESC' ] ]
  145. })
  146. }
  147. static findLatestSessionOf (videoId: number) {
  148. return VideoLiveSessionModel.findOne({
  149. where: {
  150. liveVideoId: videoId
  151. },
  152. order: [ [ 'startDate', 'DESC' ] ]
  153. })
  154. }
  155. static listSessionsOfLiveForAPI (options: { videoId: number }) {
  156. const { videoId } = options
  157. const query: FindOptions<AttributesOnly<VideoLiveSessionModel>> = {
  158. where: {
  159. liveVideoId: videoId
  160. },
  161. order: [ [ 'startDate', 'ASC' ] ]
  162. }
  163. return VideoLiveSessionModel.scope(ScopeNames.WITH_REPLAY).findAll(query)
  164. }
  165. toFormattedJSON (this: MVideoLiveSessionReplay): LiveVideoSession {
  166. const replayVideo = this.ReplayVideo
  167. ? {
  168. id: this.ReplayVideo.id,
  169. uuid: this.ReplayVideo.uuid,
  170. shortUUID: uuidToShort(this.ReplayVideo.uuid)
  171. }
  172. : undefined
  173. const replaySettings = this.replaySettingId
  174. ? this.ReplaySetting.toFormattedJSON()
  175. : undefined
  176. return {
  177. id: this.id,
  178. startDate: this.startDate.toISOString(),
  179. endDate: this.endDate
  180. ? this.endDate.toISOString()
  181. : null,
  182. endingProcessed: this.endingProcessed,
  183. saveReplay: this.saveReplay,
  184. replaySettings,
  185. replayVideo,
  186. error: this.error
  187. }
  188. }
  189. }