Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added SearchCache #15

Merged
merged 2 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion example/package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
{
"name": "sunday.ts-example",
"module": "src/index.ts",
"type": "module",
"devDependencies": {
"@types/bun": "latest"
},
Expand Down
9 changes: 6 additions & 3 deletions example/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ let manager = new Manager({
manager.on("NodeConnect", (node) => {
console.log(`Node ${node.options.host} connected`);
});
manager.on("NodeRaw", async (node) => {
console.log(`sent raw data: ${JSON.stringify(node)}`);
});
// manager.on("NodeRaw", async (node) => {
// console.log(`sent raw data: ${JSON.stringify(node)}`);
// });
manager.on("PlayerCreate", (player) => {
console.log(`Player created in guild ${player.guild}`);
});
Expand Down Expand Up @@ -83,6 +83,9 @@ client.on("messageCreate", async (message) => {
return message.reply(`enqueuing ${res.tracks[0].title}. ${end}`);
}
});
manager.on("SearchCacheClear" , (key: string, values) => {
console.log(`Cache cleared for ${key} with values: ${values}`);
});
client.on("raw", (data) => manager.updateVoiceState(data));
client.on("ready" , () => {
manager.init(client.user?.id as string);
Expand Down
22 changes: 14 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"name": "sunday.ts",
"main": "dist/index.js",
"types": "dist/index.d.ts",
"version": "1.0.9-indev",
"version": "1.0.11-indev",
"description": "Sunday a lavalink wrapper",
"license": "MIT",
"author": "FAYStarNext",
Expand All @@ -18,7 +18,12 @@
"@types/bun": "latest",
"eslint": "9.x",
"globals": "^15.8.0",
"typescript-eslint": "^7.16.1"
"typescript-eslint": "^7.16.1",
"@babel/cli": "^7.24.8",
"@babel/core": "^7.24.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/preset-env": "^7.24.8",
"@babel/preset-typescript": "^7.24.7"
},
"publishConfig": {
"registry": "https://registry.npmjs.org/",
Expand All @@ -32,15 +37,16 @@
"typescript": "^5.5.3"
},
"dependencies": {
"@babel/cli": "^7.24.8",
"@babel/core": "^7.24.9",
"@babel/plugin-proposal-class-properties": "^7.18.6",
"@babel/preset-env": "^7.24.8",
"@babel/preset-typescript": "^7.24.7",
"@discordjs/collection": "^2.1.0",
"discord.js": "^14.15.3",
"node-fetch": "^3.3.2",
"tiny-typed-emitter": "^2.1.0",
"ws": "^8.18.0"
}
},
"keywords": [
"lavalink",
"discord",
"wrapper",
"api"
]
}
60 changes: 39 additions & 21 deletions src/structures/Manager.ts
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,14 @@ export class Manager extends TypedEmitter<ManagerEvents> {

if (this.options.nodes) this.options.nodes.forEach((nodeOptions) => { return new (Structure.get("Node"))(nodeOptions); });
setInterval(() => {
const searchCacheKeys = this.search_cache.keys();
const searchCacheValues = this.search_cache.values();
const firstKey = searchCacheKeys.next().value;
const firstValue = searchCacheValues.next().value;
if (firstKey && firstValue) {
const searchResultString = JSON.stringify(firstValue);
this.emit("SearchCacheClear", firstKey, searchResultString);
}
this.search_cache.clear();
}, this.options.cache?.time || 10000);
}
Expand Down Expand Up @@ -168,20 +176,15 @@ export class Manager extends TypedEmitter<ManagerEvents> {
* @param requester
* @returns The search result.
*/

public async search(options: SearchQuery): Promise<SearchResult> {
const node = this.useableNodes;
if (!node) throw new Error("No available nodes.");
const _query: SearchQuery = typeof options.query === "string" ? { query: options.query } : options.query;
const _source = Manager.DEFAULT_SOURCES[_query.source ?? this.options.defaultSearchPlatform] ?? _query.source;
let search = _query.query;

let code = this.CheckURL(options.query);
if (!/^https?:\/\//.test(search)) search = `${_source}:${search}`;
if (this.search_cache.get(String(search))) {
let data = await this.search_cache.get(String(search))
return data
};

if (this.search_cache.get(code)) return this.search_cache.get(code);
try {
const res = (await node.rest.get(`/v4/loadtracks?identifier=${encodeURIComponent(search)}`)) as LavalinkResponse;
if (!res) throw new Error("Query not found.");
Expand Down Expand Up @@ -237,23 +240,40 @@ export class Manager extends TypedEmitter<ManagerEvents> {
}
}
}

if (res.loadType === "search") await this.search_cache.set(String(search), result);

if (res.loadType === "search" || "track") this.search_cache.set(code, result);
return result;
} catch (err) {
throw new Error(err);
}
}

private ToOrginalURL(uri: string): string {
switch (uri.split(":")[0]) {
case "yt":
const videoCode = uri.match(/v=([^&]+)/)?.[1];
const playlistCode = uri.match(/list=([^&]+)/)?.[1];
if (playlistCode) {
return "https://www.youtube.com/playlist?list=" + playlistCode;
}
return "https://www.youtube.com/watch?v=" + (videoCode ?? "");
}
return uri;
}

private CheckURL(uri: string): string {
let data = this.regex_link(uri);
switch (data) {
case "yt":
return "yt:" + uri.replace("https://www.youtube.com/watch?v=", "");
const videoCode = uri.match(/v=([^&]+)/)?.[1];
const playlistCode = uri.match(/list=([^&]+)/)?.[1];
if (playlistCode) {
return "yt:playlist:" + playlistCode;
}
return "yt:" + (videoCode ?? "");
}
return uri;
}

private isLink(link: string) {
return /^(https?:\/\/)?(www\.)?([a-zA-Z0-9]+)\.([a-zA-Z0-9]+)\/.+$/.test(link);
}
Expand All @@ -262,26 +282,20 @@ export class Manager extends TypedEmitter<ManagerEvents> {
if (this.YOUTUBE_REGEX.test(link)) return "yt";
if (this.SOUNDCLOUD_REGEX.test(link)) return "sc";
if (this.SPOTIFY_REGEX.test(link)) return "sp";
if (this.BILIBILITV_REGEX.test(link)) return "bi:tv";
if (this.JOOX_REGEX.test(link)) return "jx";
if (this.isLink(link)) return "http";
return null;
}

/**
* Decodes the base64 encoded tracks and returns a TrackData array.
* @param tracks
*/
public decodeTracks(tracks: string[]): Promise<TrackData[]> {
return new Promise(async (resolve, reject) => {
return new Promise<TrackData[]>(async (resolve, reject) => {
const node = this.nodes.first();
if (!node) throw new Error("No available nodes.");

const res = (await node.rest.post("/v4/decodetracks", JSON.stringify(tracks)).catch((err) => reject(err))) as TrackData[];

if (!res) {
return reject(new Error("No data returned from query."));
}

if (!res) return reject(new Error("No data returned from query."));
return resolve(res);
});
}
Expand Down Expand Up @@ -444,6 +458,9 @@ export interface ManagerOptions {
}

export type SearchPlatform = "deezer" | "soundcloud" | "youtube music" | "youtube";
/* The above code is defining a TypeScript type that represents a union of
string literals. The type can only have one of the specified values:
"deezer", "soundcloud", "youtube music", or "youtube". */

export interface SearchQuery {
/** The source to search from. */
Expand Down Expand Up @@ -489,6 +506,7 @@ export interface PlaylistData {
}

export interface ManagerEvents {
SearchCacheClear: (key: string, values: SearchResult | unknown) => void;
NodeCreate: (node: Node) => void;
NodeDestroy: (node: Node) => void;
NodeConnect: (node: Node) => void;
Expand Down