mirror of
https://github.com/informaticker/discord-jellyfin-bot.git
synced 2024-11-23 10:11:56 +01:00
✨ Add update checker #13
This commit is contained in:
parent
cadb67e291
commit
73d36ae1f3
@ -31,6 +31,7 @@
|
||||
"@nestjs/core": "^9.0.0",
|
||||
"@nestjs/event-emitter": "^1.3.1",
|
||||
"@nestjs/platform-express": "^9.0.0",
|
||||
"@nestjs/schedule": "^2.1.0",
|
||||
"date-fns": "^2.29.3",
|
||||
"discord.js": "^14.7.1",
|
||||
"joi": "^17.7.0",
|
||||
@ -44,6 +45,7 @@
|
||||
"@nestjs/cli": "^9.0.0",
|
||||
"@nestjs/schematics": "^9.0.0",
|
||||
"@nestjs/testing": "^9.0.0",
|
||||
"@types/cron": "^2.0.0",
|
||||
"@types/express": "^4.17.13",
|
||||
"@types/jest": "28.1.8",
|
||||
"@types/node": "^16.0.0",
|
||||
|
@ -4,12 +4,14 @@ import * as Joi from 'joi';
|
||||
import { DiscordModule } from '@discord-nestjs/core';
|
||||
import { ConfigModule } from '@nestjs/config';
|
||||
import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { ScheduleModule } from '@nestjs/schedule';
|
||||
|
||||
import { DiscordConfigService } from './clients/discord/discord.config.service';
|
||||
import { DiscordClientModule } from './clients/discord/discord.module';
|
||||
import { JellyfinClientModule } from './clients/jellyfin/jellyfin.module';
|
||||
import { CommandModule } from './commands/command.module';
|
||||
import { PlaybackModule } from './playback/playback.module';
|
||||
import { UpdatesModule } from './updates/updates.module';
|
||||
|
||||
@Module({
|
||||
imports: [
|
||||
@ -19,8 +21,10 @@ import { PlaybackModule } from './playback/playback.module';
|
||||
JELLYFIN_SERVER_ADDRESS: Joi.string().required(),
|
||||
JELLYFIN_AUTHENTICATION_USERNAME: Joi.string().required(),
|
||||
JELLYFIN_AUTHENTICATION_PASSWORD: Joi.string().required(),
|
||||
UPDATER_DISABLE_NOTIFICATIONS: Joi.boolean(),
|
||||
}),
|
||||
}),
|
||||
ScheduleModule.forRoot(),
|
||||
DiscordModule.forRootAsync({
|
||||
useClass: DiscordConfigService,
|
||||
}),
|
||||
@ -30,6 +34,7 @@ import { PlaybackModule } from './playback/playback.module';
|
||||
DiscordClientModule,
|
||||
JellyfinClientModule,
|
||||
PlaybackModule,
|
||||
UpdatesModule,
|
||||
],
|
||||
controllers: [],
|
||||
providers: [],
|
||||
|
@ -20,7 +20,7 @@ export class JellyfinService {
|
||||
this.jellyfin = new Jellyfin({
|
||||
clientInfo: {
|
||||
name: Constants.Metadata.ApplicationName,
|
||||
version: Constants.Metadata.Version,
|
||||
version: Constants.Metadata.Version.All(),
|
||||
},
|
||||
deviceInfo: {
|
||||
id: 'jellyfin-discord-bot',
|
||||
|
@ -56,7 +56,7 @@ export class StatusCommand implements DiscordCommand {
|
||||
return embedBuilder.addFields([
|
||||
{
|
||||
name: 'Bot Version',
|
||||
value: Constants.Metadata.Version,
|
||||
value: Constants.Metadata.Version.All(),
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
|
6
src/models/github-release.ts
Normal file
6
src/models/github-release.ts
Normal file
@ -0,0 +1,6 @@
|
||||
export interface GithubRelease {
|
||||
html_url: string;
|
||||
tag_name: string;
|
||||
name: string;
|
||||
published_at: string;
|
||||
}
|
12
src/updates/updates.module.ts
Normal file
12
src/updates/updates.module.ts
Normal file
@ -0,0 +1,12 @@
|
||||
import { DiscordModule } from '@discord-nestjs/core';
|
||||
import { Module } from '@nestjs/common';
|
||||
import { DiscordClientModule } from '../clients/discord/discord.module';
|
||||
import { UpdatesService } from './updates.service';
|
||||
|
||||
@Module({
|
||||
imports: [DiscordModule.forFeature(), DiscordClientModule],
|
||||
providers: [UpdatesService],
|
||||
controllers: [],
|
||||
exports: [],
|
||||
})
|
||||
export class UpdatesModule {}
|
112
src/updates/updates.service.ts
Normal file
112
src/updates/updates.service.ts
Normal file
@ -0,0 +1,112 @@
|
||||
import { InjectDiscordClient } from '@discord-nestjs/core';
|
||||
import { ButtonBuilder } from '@discordjs/builders';
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
import { Cron } from '@nestjs/schedule';
|
||||
import axios from 'axios';
|
||||
import { formatRelative, parseISO } from 'date-fns';
|
||||
import { ActionRowBuilder, ButtonStyle, Client } from 'discord.js';
|
||||
import { DiscordMessageService } from '../clients/discord/discord.message.service';
|
||||
import { GithubRelease } from '../models/github-release';
|
||||
import { Constants } from '../utils/constants';
|
||||
|
||||
@Injectable()
|
||||
export class UpdatesService {
|
||||
private readonly logger = new Logger(UpdatesService.name);
|
||||
|
||||
constructor(
|
||||
@InjectDiscordClient() private readonly client: Client,
|
||||
private readonly discordMessageService: DiscordMessageService,
|
||||
) {}
|
||||
|
||||
@Cron('0 0 */1 * * *')
|
||||
async handleCron() {
|
||||
const isDisabled = process.env.UPDATER_DISABLE_NOTIFICATIONS;
|
||||
|
||||
if (isDisabled === 'true') {
|
||||
return;
|
||||
}
|
||||
|
||||
this.logger.debug('Checking for available updates...');
|
||||
|
||||
const latestGitHubRelease = await this.fetchLatestGithubRelease();
|
||||
const currentVersion = Constants.Metadata.Version.All();
|
||||
|
||||
if (latestGitHubRelease.tag_name <= currentVersion) {
|
||||
return;
|
||||
}
|
||||
|
||||
await this.contactOwnerAboutUpdate(currentVersion, latestGitHubRelease);
|
||||
}
|
||||
|
||||
private async contactOwnerAboutUpdate(
|
||||
currentVersion: string,
|
||||
latestVersion: GithubRelease,
|
||||
) {
|
||||
const guilds = this.client.guilds.cache;
|
||||
|
||||
const actionRow = new ActionRowBuilder<ButtonBuilder>().addComponents(
|
||||
new ButtonBuilder()
|
||||
.setLabel('See update')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(latestVersion.html_url),
|
||||
new ButtonBuilder()
|
||||
.setLabel('Report an issue')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(Constants.Links.ReportIssue),
|
||||
new ButtonBuilder()
|
||||
.setLabel('Turn this notification off')
|
||||
.setStyle(ButtonStyle.Link)
|
||||
.setURL(Constants.Links.Wiki.DisableNotifications),
|
||||
);
|
||||
|
||||
const isoDate = parseISO(latestVersion.published_at);
|
||||
const relativeReadable = formatRelative(isoDate, new Date());
|
||||
|
||||
guilds.forEach(async (guild, key) => {
|
||||
const owner = await guild.fetchOwner();
|
||||
|
||||
await owner.send({
|
||||
content: 'Update notification',
|
||||
embeds: [
|
||||
this.discordMessageService.buildMessage({
|
||||
title: 'Update is available',
|
||||
description: `Hello @${owner.user.tag},\nI'd like to inform you, that there is a new update available.\nTo ensure best security and being able to use the latest features, please update to the newest version.\n\n**${latestVersion.name}** (published ${relativeReadable})\n`,
|
||||
mixin(embedBuilder) {
|
||||
return embedBuilder.addFields([
|
||||
{
|
||||
name: 'Your version',
|
||||
value: currentVersion,
|
||||
inline: true,
|
||||
},
|
||||
{
|
||||
name: 'Newest version',
|
||||
value: latestVersion.tag_name,
|
||||
inline: true,
|
||||
},
|
||||
]);
|
||||
},
|
||||
}),
|
||||
],
|
||||
components: [actionRow],
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private async fetchLatestGithubRelease(): Promise<null | GithubRelease> {
|
||||
return axios({
|
||||
method: 'GET',
|
||||
url: Constants.Links.Api.GetLatestRelease,
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.status !== 200) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return response.data as GithubRelease;
|
||||
})
|
||||
.catch((err) => {
|
||||
this.logger.error('Error while checking for updates', err);
|
||||
return null;
|
||||
});
|
||||
}
|
||||
}
|
@ -1,6 +1,12 @@
|
||||
export const Constants = {
|
||||
Metadata: {
|
||||
Version: '0.0.1',
|
||||
Version: {
|
||||
Major: 0,
|
||||
Minor: 0,
|
||||
Patch: 1,
|
||||
All: () =>
|
||||
`${Constants.Metadata.Version.Major}.${Constants.Metadata.Version.Minor}.${Constants.Metadata.Version.Patch}`,
|
||||
},
|
||||
ApplicationName: 'Discord Jellyfin Music Bot',
|
||||
},
|
||||
Links: {
|
||||
@ -12,6 +18,16 @@ export const Constants = {
|
||||
new URL(
|
||||
`https://github.com/manuel-rw/jellyfin-discord-music-bot/issues/new?assignees=&labels=&template=bug_report.md&title=${title}`,
|
||||
),
|
||||
ReleasesPage:
|
||||
'https://github.com/manuel-rw/jellyfin-discord-music-bot/releases',
|
||||
Wiki: {
|
||||
DisableNotifications:
|
||||
'https://github.com/manuel-rw/jellyfin-discord-music-bot/wiki/%F0%9F%93%A2-Update-Notifications',
|
||||
},
|
||||
Api: {
|
||||
GetLatestRelease:
|
||||
'https://api.github.com/repos/manuel-rw/jellyfin-discord-music-bot/releases/latest',
|
||||
},
|
||||
},
|
||||
Design: {
|
||||
InvisibleSpace: '\u1CBC',
|
||||
|
49
yarn.lock
49
yarn.lock
@ -1155,6 +1155,20 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nestjs/schedule@npm:^2.1.0":
|
||||
version: 2.1.0
|
||||
resolution: "@nestjs/schedule@npm:2.1.0"
|
||||
dependencies:
|
||||
cron: 2.0.0
|
||||
uuid: 8.3.2
|
||||
peerDependencies:
|
||||
"@nestjs/common": ^7.0.0 || ^8.0.0 || ^9.0.0
|
||||
"@nestjs/core": ^7.0.0 || ^8.0.0 || ^9.0.0
|
||||
reflect-metadata: ^0.1.12
|
||||
checksum: 43423eb0491c692c08dcdb6d18d34ec758fe29cda52f4674a945e06933ec5b4e23229193c1b071971842b50db57024d6f1c55fe8f4c6392754b6a597b31eb423
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@nestjs/schematics@npm:^9.0.0":
|
||||
version: 9.0.3
|
||||
resolution: "@nestjs/schematics@npm:9.0.3"
|
||||
@ -1430,6 +1444,16 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/cron@npm:^2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "@types/cron@npm:2.0.0"
|
||||
dependencies:
|
||||
"@types/luxon": "*"
|
||||
"@types/node": "*"
|
||||
checksum: 392d2cfca51504140397533c30be8facd2196251074eb26ee09232a7e983144ff1d8364cd64922ed22d142686a4724934a70672fc8353b441fea729ac0ed0611
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/eslint-scope@npm:^3.7.3":
|
||||
version: 3.7.4
|
||||
resolution: "@types/eslint-scope@npm:3.7.4"
|
||||
@ -1538,6 +1562,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/luxon@npm:*":
|
||||
version: 3.1.0
|
||||
resolution: "@types/luxon@npm:3.1.0"
|
||||
checksum: 04768029342ad76fc2a9339436c143ea64797b35cf9b03ddded787c13eae30f0ca1246e51c2c5365ed912f98068e13a967a3931b137eb4585248a0ad7ec3fa86
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"@types/mime@npm:*":
|
||||
version: 3.0.1
|
||||
resolution: "@types/mime@npm:3.0.1"
|
||||
@ -2894,6 +2925,15 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cron@npm:2.0.0":
|
||||
version: 2.0.0
|
||||
resolution: "cron@npm:2.0.0"
|
||||
dependencies:
|
||||
luxon: ^1.23.x
|
||||
checksum: 179ec137ada4ceb44cafe51c55491e84954308d7012d2a44539f0dadbbb1ffbbe3072c2f7aaa88595d60bd56e0d536aae2e4aaa4430c869317d6c2abd966988b
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"cross-spawn@npm:^7.0.0, cross-spawn@npm:^7.0.2, cross-spawn@npm:^7.0.3":
|
||||
version: 7.0.3
|
||||
resolution: "cross-spawn@npm:7.0.3"
|
||||
@ -4452,8 +4492,10 @@ __metadata:
|
||||
"@nestjs/core": ^9.0.0
|
||||
"@nestjs/event-emitter": ^1.3.1
|
||||
"@nestjs/platform-express": ^9.0.0
|
||||
"@nestjs/schedule": ^2.1.0
|
||||
"@nestjs/schematics": ^9.0.0
|
||||
"@nestjs/testing": ^9.0.0
|
||||
"@types/cron": ^2.0.0
|
||||
"@types/express": ^4.17.13
|
||||
"@types/jest": 28.1.8
|
||||
"@types/node": ^16.0.0
|
||||
@ -5189,6 +5231,13 @@ __metadata:
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"luxon@npm:^1.23.x":
|
||||
version: 1.28.0
|
||||
resolution: "luxon@npm:1.28.0"
|
||||
checksum: 5250cb9f138b6048eeb0b3a9044a4ac994d0058f680c72a0da4b6aeaec8612460385639cba2b1052ef6d5564879e9ed144d686f26d9d97b38ab920d82e18281c
|
||||
languageName: node
|
||||
linkType: hard
|
||||
|
||||
"macos-release@npm:^2.5.0":
|
||||
version: 2.5.0
|
||||
resolution: "macos-release@npm:2.5.0"
|
||||
|
Loading…
Reference in New Issue
Block a user