1
0
Fork 0
mirror of https://github.com/Chocobozzz/PeerTube.git synced 2025-10-05 19:42:24 +02:00

Add channel collaborators feature

This commit is contained in:
Chocobozzz 2025-09-16 14:36:37 +02:00
parent 94e55dfc6c
commit b30ded66f6
No known key found for this signature in database
GPG key ID: 583A612D890159BE
192 changed files with 5534 additions and 2642 deletions

View file

@ -12,13 +12,13 @@ type ImageModel = {
filename: string
onDisk: boolean
isOwned (): boolean
getPath (): string
isLocal(): boolean
getPath(): string
save (): Promise<Model>
save(): Promise<Model>
}
export abstract class AbstractPermanentFileCache <M extends ImageModel> {
export abstract class AbstractPermanentFileCache<M extends ImageModel> {
// Unsafe because it can return paths that do not exist anymore
private readonly filenameToPathUnsafeCache = new LRUCache<string, string>({
max: LRU_CACHE.FILENAME_TO_PATH_PERMANENT_FILE_CACHE.MAX_SIZE
@ -28,7 +28,6 @@ export abstract class AbstractPermanentFileCache <M extends ImageModel> {
protected abstract loadModel (filename: string): Promise<M>
constructor (private readonly directory: string) {
}
async lazyServe (options: {
@ -102,7 +101,7 @@ export abstract class AbstractPermanentFileCache <M extends ImageModel> {
const { err, image, filename, next } = options
// It seems this actor image is not on the disk anymore
if (err.status === HttpStatusCode.NOT_FOUND_404 && !image.isOwned()) {
if (err.status === HttpStatusCode.NOT_FOUND_404 && !image.isLocal()) {
logger.error('Cannot lazy serve image %s.', filename, { err })
this.filenameToPathUnsafeCache.delete(filename)

View file

@ -2,10 +2,9 @@ import { remove } from 'fs-extra/esm'
import { logger } from '../../../helpers/logger.js'
import memoizee from 'memoizee'
type GetFilePathResult = { isOwned: boolean, path: string, downloadName?: string } | undefined
export abstract class AbstractSimpleFileCache <T> {
type GetFilePathResult = { isLocal: boolean, path: string, downloadName?: string } | undefined
export abstract class AbstractSimpleFileCache<T> {
getFilePath: (params: T) => Promise<GetFilePathResult>
abstract getFilePathImpl (params: T): Promise<GetFilePathResult>
@ -19,7 +18,7 @@ export abstract class AbstractSimpleFileCache <T> {
max,
promise: true,
dispose: (result?: GetFilePathResult) => {
if (result && result.isOwned !== true) {
if (result && result.isLocal !== true) {
remove(result.path)
.then(() => logger.debug('%s removed from %s', result.path, this.constructor.name))
.catch(err => logger.error('Cannot remove %s from cache %s.', result.path, this.constructor.name, { err }))

View file

@ -21,8 +21,8 @@ class VideoCaptionsSimpleFileCache extends AbstractSimpleFileCache<string> {
const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(filename)
if (!videoCaption) return undefined
if (videoCaption.isOwned()) {
return { isOwned: true, path: videoCaption.getFSFilePath() }
if (videoCaption.isLocal()) {
return { isLocal: true, path: videoCaption.getFSFilePath() }
}
return this.loadRemoteFile(filename)
@ -33,7 +33,7 @@ class VideoCaptionsSimpleFileCache extends AbstractSimpleFileCache<string> {
const videoCaption = await VideoCaptionModel.loadWithVideoByFilename(key)
if (!videoCaption) return undefined
if (videoCaption.isOwned()) throw new Error('Cannot load remote caption of owned video.')
if (videoCaption.isLocal()) throw new Error('Cannot load remote caption of owned video.')
// Used to fetch the path
const video = await VideoModel.loadFull(videoCaption.videoId)
@ -45,7 +45,7 @@ class VideoCaptionsSimpleFileCache extends AbstractSimpleFileCache<string> {
try {
await doRequestAndSaveToFile(remoteUrl, destPath)
return { isOwned: false, path: destPath }
return { isLocal: false, path: destPath }
} catch (err) {
logger.info('Cannot fetch remote caption file %s.', remoteUrl, { err })

View file

@ -1,14 +1,13 @@
import { ThumbnailType } from '@peertube/peertube-models'
import { logger } from '@server/helpers/logger.js'
import { doRequestAndSaveToFile } from '@server/helpers/requests.js'
import { ThumbnailModel } from '@server/models/video/thumbnail.js'
import { join } from 'path'
import { FILES_CACHE } from '../../initializers/constants.js'
import { VideoModel } from '../../models/video/video.js'
import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache.js'
import { doRequestAndSaveToFile } from '@server/helpers/requests.js'
import { ThumbnailModel } from '@server/models/video/thumbnail.js'
import { ThumbnailType } from '@peertube/peertube-models'
import { logger } from '@server/helpers/logger.js'
class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache <string> {
class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache<string> {
private static instance: VideoPreviewsSimpleFileCache
private constructor () {
@ -23,7 +22,7 @@ class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache <string> {
const thumbnail = await ThumbnailModel.loadWithVideoByFilename(filename, ThumbnailType.PREVIEW)
if (!thumbnail) return undefined
if (thumbnail.Video.isOwned()) return { isOwned: true, path: thumbnail.getPath() }
if (thumbnail.Video.isLocal()) return { isLocal: true, path: thumbnail.getPath() }
return this.loadRemoteFile(thumbnail.Video.uuid)
}
@ -33,7 +32,7 @@ class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache <string> {
const video = await VideoModel.loadFull(key)
if (!video) return undefined
if (video.isOwned()) throw new Error('Cannot load remote preview of owned video.')
if (video.isLocal()) throw new Error('Cannot load remote preview of owned video.')
const preview = video.getPreview()
const destPath = join(FILES_CACHE.PREVIEWS.DIRECTORY, preview.filename)
@ -44,7 +43,7 @@ class VideoPreviewsSimpleFileCache extends AbstractSimpleFileCache <string> {
logger.debug('Fetched remote preview %s to %s.', remoteUrl, destPath)
return { isOwned: false, path: destPath }
return { isLocal: false, path: destPath }
} catch (err) {
logger.info('Cannot fetch remote preview file %s.', remoteUrl, { err })

View file

@ -1,12 +1,11 @@
import { join } from 'path'
import { logger } from '@server/helpers/logger.js'
import { doRequestAndSaveToFile } from '@server/helpers/requests.js'
import { StoryboardModel } from '@server/models/video/storyboard.js'
import { join } from 'path'
import { FILES_CACHE } from '../../initializers/constants.js'
import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache.js'
class VideoStoryboardsSimpleFileCache extends AbstractSimpleFileCache <string> {
class VideoStoryboardsSimpleFileCache extends AbstractSimpleFileCache<string> {
private static instance: VideoStoryboardsSimpleFileCache
private constructor () {
@ -21,7 +20,7 @@ class VideoStoryboardsSimpleFileCache extends AbstractSimpleFileCache <string> {
const storyboard = await StoryboardModel.loadWithVideoByFilename(filename)
if (!storyboard) return undefined
if (storyboard.Video.isOwned()) return { isOwned: true, path: storyboard.getPath() }
if (storyboard.Video.isLocal()) return { isLocal: true, path: storyboard.getPath() }
return this.loadRemoteFile(storyboard.filename)
}
@ -39,7 +38,7 @@ class VideoStoryboardsSimpleFileCache extends AbstractSimpleFileCache <string> {
logger.debug('Fetched remote storyboard %s to %s.', remoteUrl, destPath)
return { isOwned: false, path: destPath }
return { isLocal: false, path: destPath }
} catch (err) {
logger.info('Cannot fetch remote storyboard file %s.', remoteUrl, { err })

View file

@ -8,8 +8,7 @@ import { FILES_CACHE } from '../../initializers/constants.js'
import { VideoModel } from '../../models/video/video.js'
import { AbstractSimpleFileCache } from './shared/abstract-simple-file-cache.js'
class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache <string> {
class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache<string> {
private static instance: VideoTorrentsSimpleFileCache
private constructor () {
@ -24,10 +23,10 @@ class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache <string> {
const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(filename)
if (!file) return undefined
if (file.getVideo().isOwned()) {
if (file.getVideo().isLocal()) {
const downloadName = this.buildDownloadName(file.getVideo(), file)
return { isOwned: true, path: join(CONFIG.STORAGE.TORRENTS_DIR, file.torrentFilename), downloadName }
return { isLocal: true, path: join(CONFIG.STORAGE.TORRENTS_DIR, file.torrentFilename), downloadName }
}
return this.loadRemoteFile(filename)
@ -38,7 +37,7 @@ class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache <string> {
const file = await VideoFileModel.loadWithVideoOrPlaylistByTorrentFilename(key)
if (!file) return undefined
if (file.getVideo().isOwned()) throw new Error('Cannot load remote file of owned video.')
if (file.getVideo().isLocal()) throw new Error('Cannot load remote file of owned video.')
// Used to fetch the path
const video = await VideoModel.loadFull(file.getVideo().id)
@ -52,7 +51,7 @@ class VideoTorrentsSimpleFileCache extends AbstractSimpleFileCache <string> {
const downloadName = this.buildDownloadName(video, file)
return { isOwned: false, path: destPath, downloadName }
return { isLocal: false, path: destPath, downloadName }
} catch (err) {
logger.info('Cannot fetch remote torrent file %s.', remoteUrl, { err })