Typescript continues

This commit is contained in:
Christer Warén 2023-06-07 06:41:58 +03:00
parent 25ac99379b
commit 16ef8e70e6
10 changed files with 129 additions and 142 deletions

View File

@ -1,34 +1,21 @@
import { Guild } from 'discord.js'; import { Guild } from 'discord.js';
import fs, { NoParamCallback } from 'fs'; import fs from 'fs';
import path from 'path'; import path from 'path';
import { state } from './Radio';
import { statistics } from './Statistics';
interface entry { export interface datastore {
guild: { guild: {
id: string, id: string,
name?: string name?: string
}, },
statistics: { statistics: statistics | {},
[key: string]: { state: state | {},
"time": number,
"used": number
}
} | {},
state: {
channels: {
"text": string,
"voice": string
},
date: string,
station: {
name: string,
owner: string
}
} | {},
updated?: string updated?: string
} }
export default class { export default class Datastore {
map: Map<string, any>; map: Map<string, datastore>;
constructor() { constructor() {
this.map = new Map(); this.map = new Map();
this.loadData(); this.loadData();
@ -66,7 +53,7 @@ export default class {
} }
createEntry(id: string){ createEntry(id: string){
let newData: entry = { let newData: datastore = {
guild: { guild: {
id: id, id: id,
}, },
@ -89,7 +76,7 @@ export default class {
return this.map.get(id); return this.map.get(id);
} }
updateEntry(guild: Guild | { id: string, name: string }, newData: entry) { updateEntry(guild: Guild | { id: string, name: string }, newData: datastore) {
newData.guild.name = guild.name; newData.guild.name = guild.name;
let date = new Date(); let date = new Date();
@ -100,32 +87,12 @@ export default class {
//this.showEntry(this.getEntry(guild.id)); //this.showEntry(this.getEntry(guild.id));
} }
showEntry(data : entry){ showEntry(data : datastore){
console.log(data); console.log(data);
} }
createTestFile () { saveEntry(file: string, data: datastore) {
let newData = { fs.writeFile(path.join(path.dirname(__dirname), '../../datastore') + "/" + file + ".json", JSON.stringify(data, null, 4), 'utf8', function(err: NodeJS.ErrnoException | null) {
"guild": {
"id": "test",
"name": "Test"
},
"statistics": {
"test": {
"time": 0,
"used": 0
}
},
"state": {
}
}
this.updateEntry(newData.guild, newData);
}
saveEntry(file: string, data: entry) {
fs.writeFile(path.join(path.dirname(__dirname), '../../datastore') + "/" + file + ".json", JSON.stringify(data, null, 4), 'utf8', function(err: any) {
if (err) { if (err) {
} }

View File

@ -1,27 +1,40 @@
import { Guild, GuildMember, TextBasedChannel, VoiceBasedChannel, VoiceChannel } from "discord.js"; import { Channel, Collection, GuildMember, OAuth2Guild, TextBasedChannel, VoiceBasedChannel, VoiceChannel } from "discord.js";
import { getVoiceConnection, joinVoiceChannel, VoiceConnection } from "@discordjs/voice"; import { getVoiceConnection, joinVoiceChannel, VoiceConnection } from "@discordjs/voice";
import RadioClient from "../../Client"; import RadioClient from "../../Client";
import { station } from "./Stations"; import { station } from "./Stations";
import { datastore } from "./Datastore";
export interface radio { export interface radio {
textChannel: TextBasedChannel | null, textChannel: Channel | TextBasedChannel | undefined | null,
voiceChannel: VoiceBasedChannel, voiceChannel: Channel | VoiceBasedChannel | undefined,
connection: VoiceConnection | null, connection: VoiceConnection | null,
message: null, message: null,
station: station, station: station,
datastore?: any, datastore?: datastore,
currentTime?: number, currentTime?: number,
startTime: number, startTime: number,
playTime?: number, playTime?: number,
} }
export interface state extends Object {
channels: {
"text": string,
"voice": string
},
date: string,
station: {
name: string,
owner: string
}
}
export default class Radio extends Map { export default class Radio extends Map {
constructor() { constructor() {
super(); super();
} }
save(client: RadioClient) { save(client: RadioClient): void {
let currentRadios = this.keys(); let currentRadios = this.keys();
let radio = currentRadios.next(); let radio = currentRadios.next();
@ -29,7 +42,7 @@ export default class Radio extends Map {
let currentRadio = this.get(radio.value); let currentRadio = this.get(radio.value);
if (currentRadio) { if (currentRadio) {
currentRadio.guild = client.datastore?.getEntry(radio.value).guild; currentRadio.guild = client.datastore?.getEntry(radio.value)?.guild;
client.statistics?.update(client, currentRadio.guild, currentRadio); client.statistics?.update(client, currentRadio.guild, currentRadio);
client.funcs.saveState(client, currentRadio.guild, currentRadio); client.funcs.saveState(client, currentRadio.guild, currentRadio);
@ -42,29 +55,32 @@ export default class Radio extends Map {
} }
} }
restore(client: RadioClient, guilds: any) { restore(client: RadioClient, guilds: Collection<string, OAuth2Guild>): void {
if(!client.stations) return; if(!client.stations) return;
guilds.forEach(async (guild: Guild) => { guilds.forEach(async (guild: OAuth2Guild) => {
let state = client.funcs.loadState(client, guild); let state = client.funcs.loadState(client, guild);
if(!state) return; if(!state) return;
if(!state.station || !state.channels.voice || !state.channels.text) return; if(!state.hasOwnProperty('station') || !state.hasOwnProperty('channels')) return;
let voiceChannel = client.channels.cache.get(state.channels.voice); let voiceChannel = client.channels.cache.get(state.channels.voice);
if(!voiceChannel || !(voiceChannel instanceof VoiceChannel)) return; if(!voiceChannel || !(voiceChannel instanceof VoiceChannel)) return;
if(voiceChannel.members.filter((member: GuildMember) => !member.user.bot).size === 0) return; if(voiceChannel.members.filter((member: GuildMember) => !member.user.bot).size === 0) return;
const sstation = client.stations?.search(state.station.name, "direct");
const sstation = await client.stations?.search(state.station.name, "direct");
let station = sstation; let station = sstation;
if(!station) return; if(!station) return;
const construct: any = { let date = new Date();
const construct: radio = {
textChannel: client.channels.cache.get(state.channels.text), textChannel: client.channels.cache.get(state.channels.text),
voiceChannel: client.channels.cache.get(state.channels.voice), voiceChannel: client.channels.cache.get(state.channels.voice),
connection: null, connection: null,
message: null, message: null,
station: station station: station,
startTime: date.getTime()
}; };
this.set(guild.id, construct); this.set(guild.id, construct);
@ -81,6 +97,7 @@ export default class Radio extends Map {
let date = new Date(); let date = new Date();
construct.startTime = date.getTime(); construct.startTime = date.getTime();
client.datastore?.checkEntry(guild.id); client.datastore?.checkEntry(guild.id);
//@ts-ignore
client.funcs.play(client, null, guild, station); client.funcs.play(client, null, guild, station);
} catch (error) { } catch (error) {
console.log(error); console.log(error);

View File

@ -1,62 +1,44 @@
const _importDynamic = new Function('modulePath', 'return import(modulePath)');
// @ts-ignore
const fetch = (...args: any) => _importDynamic('node-fetch').then(({default: fetch}) => fetch(...args));
import logger from "../funcs/logger"; import logger from "../funcs/logger";
export interface station { export interface station {
name: string, name: string,
owner: string, owner: string,
logo: string, logo: string,
stream: any stream: {
[key: string]: string
}
} }
export default class Stations extends Array { export default class Stations extends Array {
logger: any; counter: number;
constructor() { constructor() {
super(); super();
this.counter = 0;
} }
async fetch(options: any){ async fetch(options: { url: string, show?: boolean }){
try { try {
logger('Stations', 'Started fetching list - ' + options.url); logger('Stations', 'Started fetching list - ' + options.url);
let list = await fetch(options.url) let stations = await fetch(options.url)
.then(this.checkFetchStatus) .then(this.checkFetchStatus)
.then((response: { json: () => station; }) => response.json()); .then((response: { json: () => station[]; }) => response.json());
if(list){ if(!stations) return;
this.length = 0; for (const station of stations){
list.forEach((station: station) => { this.push(station.name);
try { if(options.show) logger('Stations', station.name);
this.push(station);
} catch (error) {
}
});
if(options.show){
list.forEach((station: { name: any; }) => {
logger('Stations', station.name);
});
} }
list.forEach(async (station: station) => { this.counter = 0;
try {
let stationTest = await fetch(station.stream[station.stream.default]);
if(stationTest.ok === true) return;
this.splice(this.indexOf(station),1);
} catch (error) {
this.splice(this.indexOf(station),1);
}
});
}
logger('Stations', 'Successfully fetched list'); logger('Stations', 'Successfully fetched list');
} catch (error) { } catch (error) {
logger('Stations', 'Fetching list failed'); logger('Stations', 'Fetching list failed');
console.error(error + "\n"); console.error(error + "\n");
if(this.length == 0) this.fetch(options); this.counter = this.counter + 1;
if(this.length == 0 && 5 < this.counter) this.fetch(options);
} }
} }
@ -126,21 +108,23 @@ export default class Stations extends Array {
} }
} }
} }
let highestProbabilityStation : any | { station: string, name: string, probability: number } | string | null = null; /*let highestProbabilityStation : { station: string, name: string, probability: number } | string | undefined;
for (let i = 0; i < foundStations.length; i++) { for (let i = 0; i < foundStations.length; i++) {
if ( if (
!highestProbabilityStation || !highestProbabilityStation ||
//@ts-ignore
highestProbabilityStation.probability < foundStations[i].probability highestProbabilityStation.probability < foundStations[i].probability
) )
highestProbabilityStation = foundStations[i]; highestProbabilityStation = foundStations[i];
if ( if (
highestProbabilityStation && highestProbabilityStation &&
//@ts-ignore
highestProbabilityStation.probability === foundStations[i].probability highestProbabilityStation.probability === foundStations[i].probability
) { ) {
highestProbabilityStation = foundStations[i].station; highestProbabilityStation = foundStations[i].station;
} }
} }
return highestProbabilityStation; return highestProbabilityStation;*/
} }
} }
}; };

View File

@ -2,8 +2,17 @@ import { Guild } from "discord.js";
import RadioClient from "../../Client"; import RadioClient from "../../Client";
import { radio } from "./Radio"; import { radio } from "./Radio";
export interface statistics {
[key: string]: statistic
}
interface statistic {
"time": number,
"used": number
}
export default class Statistics { export default class Statistics {
map: Map<any, any>; map: Map<string, statistics>;
constructor() { constructor() {
this.map = new Map(); this.map = new Map();
@ -16,19 +25,26 @@ export default class Statistics {
radio.datastore = client.datastore?.getEntry(guild.id); radio.datastore = client.datastore?.getEntry(guild.id);
//@ts-ignore
if(!radio.datastore.statistics[radio.station.name]){ if(!radio.datastore.statistics[radio.station.name]){
radio.datastore.statistics[radio.station.name] = {}; //@ts-ignore
radio.datastore.statistics[radio.station.name].time = 0; radio.datastore.statistics[radio.station.name] = {
radio.datastore.statistics[radio.station.name].used = 0; time: 0,
used: 0
};
//@ts-ignore
client.datastore?.updateEntry(guild, radio.datastore); client.datastore?.updateEntry(guild, radio.datastore);
} }
let date = new Date(); let date = new Date();
radio.currentTime = date.getTime(); radio.currentTime = date.getTime();
radio.playTime = radio.currentTime - radio.startTime; radio.playTime = radio.currentTime - radio.startTime;
//@ts-ignore
radio.datastore.statistics[radio.station.name].time = parseInt(radio.datastore.statistics[radio.station.name].time) + radio.playTime; radio.datastore.statistics[radio.station.name].time = parseInt(radio.datastore.statistics[radio.station.name].time) + radio.playTime;
//@ts-ignore
radio.datastore.statistics[radio.station.name].used = parseInt(radio.datastore.statistics[radio.station.name].used)+1; radio.datastore.statistics[radio.station.name].used = parseInt(radio.datastore.statistics[radio.station.name].used)+1;
//@ts-ignore
client.datastore?.updateEntry(guild, radio.datastore); client.datastore?.updateEntry(guild, radio.datastore);
this.calculateGlobal(client); this.calculateGlobal(client);
} }
@ -39,7 +55,7 @@ export default class Statistics {
let guilds = client.datastore.map.keys(); let guilds = client.datastore.map.keys();
let stations = client.stations; let stations = client.stations;
let statistics : any = {}; let statistics : statistics = {};
if(!client.stations) return; if(!client.stations) return;
@ -50,14 +66,18 @@ export default class Statistics {
if(calculation.value != 'global'){ if(calculation.value != 'global'){
if(stations){ if(stations){
for(const station of stations) { for(const station of stations) {
if(currentGuild.statistics[station.name] && currentGuild.statistics[station.name].time && parseInt(currentGuild.statistics[station.name].time) != 0 && currentGuild.statistics[station.name].used && parseInt(currentGuild.statistics[station.name].used) != 0){ //@ts-ignore
if(currentGuild.statistics[station.name] && currentGuild.statistics[station.name]?.time && parseInt(currentGuild.statistics[station.name].time) != 0 && currentGuild.statistics[station.name].used && parseInt(currentGuild.statistics[station.name].used) != 0){
if(!statistics[station.name]){ if(!statistics[station.name]){
statistics[station.name] = {}; statistics[station.name] = {
statistics[station.name].time = 0; time: 0,
statistics[station.name].used = 0; used: 0
};
} }
//@ts-ignore
statistics[station.name].time = parseInt(statistics[station.name].time)+parseInt(currentGuild.statistics[station.name].time); statistics[station.name].time = parseInt(statistics[station.name].time)+parseInt(currentGuild.statistics[station.name].time);
//@ts-ignore
statistics[station.name].used = parseInt(statistics[station.name].used)+parseInt(currentGuild.statistics[station.name].used); statistics[station.name].used = parseInt(statistics[station.name].used)+parseInt(currentGuild.statistics[station.name].used);
} }
} }
@ -66,11 +86,13 @@ export default class Statistics {
calculation = guilds.next(); calculation = guilds.next();
} }
let newData : any = {}; let newData = {
newData.guild = {}; guild: {
newData.guild.id = "global"; id: "global",
newData.guild.name = "global"; name: "global"
newData.statistics = statistics; },
statistics: statistics
};
client.datastore.updateEntry(newData.guild, newData); client.datastore.updateEntry(newData.guild, newData);
} }

View File

@ -4,7 +4,7 @@ import RadioClient from "../../Client";
import { station } from "./Stations"; import { station } from "./Stations";
export default class Streamer { export default class Streamer {
map: any; map: Map<string, any>;
mode: "auto" | "manual" = "manual"; mode: "auto" | "manual" = "manual";
constructor() { constructor() {
@ -37,12 +37,11 @@ export default class Streamer {
refresh(client: RadioClient){ refresh(client: RadioClient){
this.init(client); this.init(client);
let streamers = this.map.keys(); for (const streamer of this.map.keys()){
streamers.forEach((streamer: any) => {
if(client.stations?.findIndex((station: station) => station.name == streamer) == -1){ if(client.stations?.findIndex((station: station) => station.name == streamer) == -1){
this.stop(streamer); this.stop(streamer);
} }
}); }
} }
play(station: station) { play(station: station) {
@ -94,14 +93,14 @@ export default class Streamer {
return audioPlayer; return audioPlayer;
} }
stop(station: station){ stop(streamer: string){
let audioPlayer = this.map.get(station.name); let audioPlayer = this.map.get(streamer);
if(audioPlayer){ if(audioPlayer){
logger('Streamer', station.name + " / " + "Stop"); logger('Streamer', streamer + " / " + "Stop");
audioPlayer.removeAllListeners(); audioPlayer.removeAllListeners();
audioPlayer.stop(); audioPlayer.stop();
} }
this.map.delete(station.name); this.map.delete(streamer);
} }
listen(station: station) { listen(station: station) {
@ -113,7 +112,7 @@ export default class Streamer {
leave(client: RadioClient) { leave(client: RadioClient) {
if(!client.stations) return; if(!client.stations) return;
client.stations.forEach((station: station) => { client.stations.forEach((station: station) => {
this.stop(station); this.stop(station.name);
}); });
} }
}; };

View File

@ -1,10 +1,7 @@
import { ActionRowBuilder, AnyComponentBuilder, APIActionRowComponent, APISelectMenuOption, ButtonInteraction, ChatInputCommandInteraction, ColorResolvable, EmbedBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction } from "discord.js"; import { ActionRowBuilder, APISelectMenuOption, ButtonInteraction, ChatInputCommandInteraction, ColorResolvable, EmbedBuilder, StringSelectMenuBuilder, StringSelectMenuInteraction } from "discord.js";
import RadioClient from "../../Client"; import RadioClient from "../../Client";
import Streamer from "../classes/Streamer"; import Streamer from "../classes/Streamer";
import commands from "../commands"; import commands from "../commands";
const _importDynamic = new Function('modulePath', 'return import(modulePath)');
// @ts-ignore
const fetch = (...args) => _importDynamic('node-fetch').then(({default: fetch}) => fetch(...args));
export default { export default {
name: 'maintenance', name: 'maintenance',

View File

@ -1,10 +1,11 @@
import RadioClient from "../../Client"; import RadioClient from "../../Client";
import Datastore from "../classes/Datastore"; import Datastore, { datastore } from "../classes/Datastore";
import Radio from "../classes/Radio"; import Radio from "../classes/Radio";
import Stations from "../classes/Stations"; import Stations from "../classes/Stations";
import Streamer from "../classes/Streamer"; import Streamer from "../classes/Streamer";
import Statistics from "../classes/Statistics"; import Statistics from "../classes/Statistics";
import commands from "../commands"; import commands from "../commands";
import { OAuth2Guild } from "discord.js";
export default async function ready(client: RadioClient) { export default async function ready(client: RadioClient) {
client.funcs.logger("Bot", "Ready"); client.funcs.logger("Bot", "Ready");
@ -13,7 +14,7 @@ export default async function ready(client: RadioClient) {
client.funcs.logger('Datastore', 'Initialize'); client.funcs.logger('Datastore', 'Initialize');
client.datastore = new Datastore(); client.datastore = new Datastore();
client.datastore.map.forEach((datastore: { guild: { id: string; name: string; }; }) => { client.datastore.map.forEach((datastore: datastore) => {
client.funcs.logger('Datastore', datastore.guild.id + " / " + datastore.guild.name); client.funcs.logger('Datastore', datastore.guild.id + " / " + datastore.guild.name);
}); });
@ -45,7 +46,7 @@ export default async function ready(client: RadioClient) {
client.funcs.logger('Guilds', 'Started fetching list'); client.funcs.logger('Guilds', 'Started fetching list');
let guilds = await client.guilds.fetch(); let guilds = await client.guilds.fetch();
guilds.forEach((guild: { id: string; name: string; }) => { guilds.forEach((guild: OAuth2Guild) => {
client.funcs.logger('Guilds', guild.id + " / " + guild.name); client.funcs.logger('Guilds', guild.id + " / " + guild.name);
}); });

View File

@ -1,15 +1,12 @@
import { Guild } from "discord.js"; import { OAuth2Guild } from "discord.js";
import RadioClient from "../../Client"; import RadioClient from "../../Client";
export default function loadState(client: RadioClient, guild: Guild){ export default function loadState(client: RadioClient, guild: OAuth2Guild) {
if(!client.datastore) return; if(!client.datastore) return;
let data = client.datastore.getEntry(guild.id); let data = client.datastore.getEntry(guild.id);
if(!data) return; if(!data) return;
let state; let state = data.state;
state = data.state;
if(!state) return; if(!state) return;
data.state = {}; data.state = {};
client.datastore.updateEntry(guild, data); client.datastore.updateEntry(guild, data);
return state; return state;

View File

@ -1,8 +1,8 @@
import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, ColorResolvable, EmbedBuilder, Guild, StringSelectMenuInteraction } from "discord.js"; import { ActionRowBuilder, ButtonBuilder, ButtonStyle, ChatInputCommandInteraction, ColorResolvable, EmbedBuilder, Guild, OAuth2Guild, StringSelectMenuInteraction } from "discord.js";
import RadioClient from "../../Client"; import RadioClient from "../../Client";
import { station } from "../classes/Stations"; import { station } from "../classes/Stations";
export default async function play(client: RadioClient, interaction: ChatInputCommandInteraction | StringSelectMenuInteraction | null, guild: Guild | null, station: station) { export default async function play(client: RadioClient, interaction: ChatInputCommandInteraction | StringSelectMenuInteraction | null, guild: OAuth2Guild | Guild | null, station: station) {
if(!guild) return; if(!guild) return;
const radio = client.radio?.get(guild.id); const radio = client.radio?.get(guild.id);

View File

@ -9,15 +9,18 @@ export default function saveState(client: RadioClient, guild: Guild, radio: radi
let date = new Date(); let date = new Date();
let data = client.datastore.getEntry(guild.id); let data = client.datastore.getEntry(guild.id);
if(!data) return;
data.state = {}; data.state = {
data.state.channels = {}; channels: {
data.state.channels.text = radio.textChannel?.id; text: radio.textChannel?.id,
data.state.channels.voice = radio.voiceChannel.id; voice: radio.voiceChannel?.id
data.state.date = date.toISOString(); },
data.state.station = {}; date: date.toISOString(),
data.state.station.name = radio.station.name; station: {
data.state.station.owner = radio.station.owner; name: radio.station.name,
owner: radio.station.owner
}
};
client.datastore.updateEntry(guild, data); client.datastore.updateEntry(guild, data);
} }