Custom channel emoticons WIP (#130) + Fix cleanup on channel deletion.
This commit is contained in:
parent
92e9d6d1af
commit
893708d93a
@ -11,6 +11,10 @@ TODO: handle custom emojis url for remote video.
|
|||||||
* #377: new setting to listen C2S connection on non-localhost interfaces.
|
* #377: new setting to listen C2S connection on non-localhost interfaces.
|
||||||
* #130: custom channel emoticons.
|
* #130: custom channel emoticons.
|
||||||
|
|
||||||
|
### Minor changes and fixes
|
||||||
|
|
||||||
|
* Fix cleanup on channel deletion.
|
||||||
|
|
||||||
## 10.0.2
|
## 10.0.2
|
||||||
|
|
||||||
### Minor changes and fixes
|
### Minor changes and fixes
|
||||||
|
@ -8,6 +8,7 @@ import { fillVideoCustomFields } from '../../custom-fields'
|
|||||||
import { videoHasWebchat } from '../../../../shared/lib/video'
|
import { videoHasWebchat } from '../../../../shared/lib/video'
|
||||||
import { updateProsodyRoom } from '../../prosody/api/manage-rooms'
|
import { updateProsodyRoom } from '../../prosody/api/manage-rooms'
|
||||||
import { getChannelInfosById } from '../../database/channel'
|
import { getChannelInfosById } from '../../database/channel'
|
||||||
|
import { Emojis } from '../../emojis'
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register stuffs related to channel configuration
|
* Register stuffs related to channel configuration
|
||||||
@ -40,11 +41,12 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
|||||||
|
|
||||||
registerHook({
|
registerHook({
|
||||||
target: 'action:api.video-channel.deleted',
|
target: 'action:api.video-channel.deleted',
|
||||||
handler: async (params: { channel: VideoChannel }) => {
|
handler: async (params: { videoChannel: VideoChannel }) => {
|
||||||
// When a video is deleted, we can delete the channel2room and room2channel files.
|
// When a video is deleted, we can delete the channel2room and room2channel files.
|
||||||
// Note: don't need to check if there is a chat for this video, just deleting existing files...
|
// Note: don't need to check if there is a chat for this video, just deleting existing files...
|
||||||
if (!params.channel.isLocal) { return }
|
|
||||||
const channelId = params.channel.id
|
// Note: this hook is only called for local channels.
|
||||||
|
const channelId = params.videoChannel.id
|
||||||
logger.info(`Channel ${channelId} deleted, removing 'channel configuration' related stuff.`)
|
logger.info(`Channel ${channelId} deleted, removing 'channel configuration' related stuff.`)
|
||||||
// Here the associated channel can be either channel.X@mucdomain or video_uuid@mucdomain.
|
// Here the associated channel can be either channel.X@mucdomain or video_uuid@mucdomain.
|
||||||
// In first case, nothing to do... in the second, we must delete.
|
// In first case, nothing to do... in the second, we must delete.
|
||||||
@ -55,6 +57,13 @@ async function initChannelConfiguration (options: RegisterServerOptions): Promis
|
|||||||
logger.error(err)
|
logger.error(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
logger.info(`Channel ${channelId} deleted, removing 'custom emojis' related stuff.`)
|
||||||
|
try {
|
||||||
|
Emojis.singletonSafe()?.deleteChannelDefinition(channelId)
|
||||||
|
} catch (err) {
|
||||||
|
logger.error(err)
|
||||||
|
}
|
||||||
|
|
||||||
// Note: we don't delete the room. So that admins can check logs afterward, if any doubts.
|
// Note: we don't delete the room. So that admins can check logs afterward, if any doubts.
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
@ -32,7 +32,7 @@ export class Emojis {
|
|||||||
constructor (options: RegisterServerOptions) {
|
constructor (options: RegisterServerOptions) {
|
||||||
const logger = options.peertubeHelpers.logger
|
const logger = options.peertubeHelpers.logger
|
||||||
this.options = options
|
this.options = options
|
||||||
this.channelBasePath = path.resolve(
|
this.channelBasePath = path.join(
|
||||||
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
options.peertubeHelpers.plugin.getDataDirectoryPath(),
|
||||||
'emojis',
|
'emojis',
|
||||||
'channel'
|
'channel'
|
||||||
@ -69,7 +69,7 @@ export class Emojis {
|
|||||||
*/
|
*/
|
||||||
public channelCustomEmojisDefinitionPath (channelId: number): string {
|
public channelCustomEmojisDefinitionPath (channelId: number): string {
|
||||||
if (typeof channelId !== 'number') { throw new Error('Invalid channelId') }
|
if (typeof channelId !== 'number') { throw new Error('Invalid channelId') }
|
||||||
return path.resolve(this.channelBasePath, channelId.toString(), 'definition.json')
|
return path.join(this.channelBasePath, channelId.toString(), 'definition.json')
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -199,13 +199,24 @@ export class Emojis {
|
|||||||
* @returns the file path
|
* @returns the file path
|
||||||
*/
|
*/
|
||||||
public channelCustomEmojisFilePath (channelId: number, fileName: string): string {
|
public channelCustomEmojisFilePath (channelId: number, fileName: string): string {
|
||||||
if (typeof channelId !== 'number') { throw new Error('Invalid channelId') }
|
|
||||||
if (!this.validImageFileName(fileName)) { throw new Error('Invalid filename') }
|
if (!this.validImageFileName(fileName)) { throw new Error('Invalid filename') }
|
||||||
return path.resolve(
|
return path.join(
|
||||||
|
this.channelCustomEmojisDirPath(channelId),
|
||||||
|
fileName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the dir path where to store emojis files relative to a channel.
|
||||||
|
* @param channelId channel Id
|
||||||
|
* @returns the dir path
|
||||||
|
*/
|
||||||
|
public channelCustomEmojisDirPath (channelId: number): string {
|
||||||
|
if (typeof channelId !== 'number') { throw new Error('Invalid channelId') }
|
||||||
|
return path.join(
|
||||||
this.channelBasePath,
|
this.channelBasePath,
|
||||||
channelId.toString(),
|
channelId.toString(),
|
||||||
'files',
|
'files'
|
||||||
fileName
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -293,27 +304,62 @@ export class Emojis {
|
|||||||
bufferInfos: BufferInfos[]
|
bufferInfos: BufferInfos[]
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const filepath = this.channelCustomEmojisDefinitionPath(channelId)
|
const filepath = this.channelCustomEmojisDefinitionPath(channelId)
|
||||||
await fs.promises.mkdir(
|
await fs.promises.mkdir(path.dirname(filepath), {
|
||||||
path.resolve(
|
|
||||||
path.dirname(filepath),
|
|
||||||
'files'
|
|
||||||
),
|
|
||||||
{
|
|
||||||
recursive: true
|
recursive: true
|
||||||
}
|
})
|
||||||
)
|
|
||||||
await fs.promises.writeFile(filepath, JSON.stringify(def))
|
await fs.promises.writeFile(filepath, JSON.stringify(def))
|
||||||
|
|
||||||
|
const fileDirPath = this.channelCustomEmojisDirPath(channelId)
|
||||||
|
await fs.promises.mkdir(fileDirPath, {
|
||||||
|
recursive: true
|
||||||
|
})
|
||||||
for (const b of bufferInfos) {
|
for (const b of bufferInfos) {
|
||||||
const fp = path.resolve(
|
const fp = path.join(
|
||||||
path.dirname(filepath),
|
fileDirPath,
|
||||||
'files',
|
|
||||||
b.filename
|
b.filename
|
||||||
)
|
)
|
||||||
await fs.promises.writeFile(fp, b.buf)
|
await fs.promises.writeFile(fp, b.buf)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: remove deprecated files.
|
// Finally, remove deprecated files
|
||||||
|
const presentFiles = new Map<string, true>()
|
||||||
|
for (const e of def.customEmojis) {
|
||||||
|
const fn = e.url.split('/').pop()
|
||||||
|
if (fn === undefined) { continue }
|
||||||
|
presentFiles.set(fn, true)
|
||||||
|
}
|
||||||
|
const dirents = await fs.promises.readdir(fileDirPath, { withFileTypes: true })
|
||||||
|
for (const dirent of dirents) {
|
||||||
|
if (!dirent.isFile()) { continue }
|
||||||
|
if (presentFiles.has(dirent.name)) { continue }
|
||||||
|
const fp = path.join(fileDirPath, dirent.name)
|
||||||
|
this.logger.debug('Deleting obsolete emojis file: ' + fp)
|
||||||
|
await fs.promises.unlink(fp)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes channel custom emojis definitions and files.
|
||||||
|
* @param channelId channel id
|
||||||
|
*/
|
||||||
|
public async deleteChannelDefinition (channelId: number): Promise<void> {
|
||||||
|
const filepath = this.channelCustomEmojisDefinitionPath(channelId)
|
||||||
|
const fileDirPath = this.channelCustomEmojisDirPath(channelId)
|
||||||
|
this.logger.info('Deleting all channel ' + channelId.toString() + ' emojis...')
|
||||||
|
try {
|
||||||
|
await fs.promises.rm(fileDirPath, {
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
})
|
||||||
|
await fs.promises.rm(path.dirname(filepath), {
|
||||||
|
force: true,
|
||||||
|
recursive: true
|
||||||
|
})
|
||||||
|
} catch (err: any) {
|
||||||
|
if (!(('code' in err) && err.code === 'ENOENT')) {
|
||||||
|
this.logger.error(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
x
Reference in New Issue
Block a user