.
diff --git a/packages/deezer/README.md b/packages/deezer/README.md
new file mode 100644
index 0000000..e9eb61a
--- /dev/null
+++ b/packages/deezer/README.md
@@ -0,0 +1,28 @@
+
+
+
+
+# @kirishima/deezer
+
+# Instalation
+```
+npm install @kirishima/deezer @kirishima/core
+```
+
+
+
+# Features
+- Written in TypeScript
+- Support ESM & CommonJS
+
+# Example
+```ts
+import { KirishimaDeezer } from "@kirishima/deezer";
+import { Kirishima } from "@kirishima/core";
+
+const kirishima = new Kirishima({
+ plugins: [
+ new KirishimaDeezer()
+ ]
+});
+```
\ No newline at end of file
diff --git a/packages/deezer/build.config.ts b/packages/deezer/build.config.ts
new file mode 100644
index 0000000..a8f1354
--- /dev/null
+++ b/packages/deezer/build.config.ts
@@ -0,0 +1,9 @@
+import { defineBuildConfig } from 'unbuild'
+
+export default defineBuildConfig({
+ entries: [
+ 'src/',
+ ],
+ clean: true,
+ declaration: true,
+})
\ No newline at end of file
diff --git a/packages/deezer/package.json b/packages/deezer/package.json
new file mode 100644
index 0000000..f89b0da
--- /dev/null
+++ b/packages/deezer/package.json
@@ -0,0 +1,45 @@
+{
+ "name": "@kirishima/deezer",
+ "description": "A simple wrapper for the Deezer API for @kirishima/core",
+ "author": {
+ "name": "KagChi"
+ },
+ "version": "0.1.0",
+ "license": "GPL-3.0",
+ "repository": {
+ "url": "https://github.com/kirishima-ship/sources"
+ },
+ "bugs": {
+ "url": "https://github.com/kirishima-ship/sources/issues"
+ },
+ "readme": "https://github.com/kirishima-ship/sources/blob/main/README.md",
+ "engines": {
+ "node": ">=14.0.0",
+ "npm": ">=7.0.0"
+ },
+ "scripts": {
+ "build": "rimraf dist && unbuild && tsc",
+ "lint": "eslint src",
+ "lint:fix": "eslint src --fix",
+ "format": "prettier --write {src,tests}/**/*.ts"
+ },
+ "devDependencies": {
+ "@babel/types": "7.17.0",
+ "@sapphire/eslint-config": "4.3.2",
+ "@sapphire/prettier-config": "1.4.1",
+ "@sapphire/ts-config": "3.3.3",
+ "@types/ws": "^8.5.3",
+ "eslint": "8.11.0",
+ "prettier": "2.6.0",
+ "rimraf": "3.0.2",
+ "typescript": "4.6.2",
+ "unbuild": "0.7.0"
+ },
+ "prettier": "@sapphire/prettier-config",
+ "dependencies": {
+ "@kirishima/core": "^0.6.2",
+ "@kirishima/fetch": "^0.2.1",
+ "lavalink-api-types": "^0.1.9",
+ "undici": "^4.16.0"
+ }
+}
diff --git a/packages/deezer/src/Structures/KirishimaPartialTrack.ts b/packages/deezer/src/Structures/KirishimaPartialTrack.ts
new file mode 100644
index 0000000..65746b0
--- /dev/null
+++ b/packages/deezer/src/Structures/KirishimaPartialTrack.ts
@@ -0,0 +1,28 @@
+import { PartialLavalinkTrack, Structure } from '@kirishima/core';
+
+export class KirishimaPartialTrack extends Structure.get('KirishimaPartialTrack') {
+ public isrc: string | null = null;
+ public artworkurl: string | null = null;
+
+ public constructor(raw: PartialLavalinkTrack) {
+ super(raw);
+ this.isrc = raw.isrc ?? null;
+ this.artworkurl = raw.artworkUrl ?? null;
+ }
+
+ public thumbnailURL() {
+ return this.artworkurl;
+ }
+}
+
+declare module '@kirishima/core' {
+ export interface PartialLavalinkTrack {
+ isrc?: string | null;
+ artworkUrl?: string | null;
+ }
+
+ export interface KirishimaPartialTrack {
+ isrc: string | null;
+ artworkurl: string | null;
+ }
+}
diff --git a/packages/deezer/src/Structures/KirisihimaPlayer.ts b/packages/deezer/src/Structures/KirisihimaPlayer.ts
new file mode 100644
index 0000000..f86e994
--- /dev/null
+++ b/packages/deezer/src/Structures/KirisihimaPlayer.ts
@@ -0,0 +1,12 @@
+import { Structure } from '@kirishima/core';
+import type { KirishimaPartialTrack } from './KirishimaPartialTrack';
+
+export class KirishimaPlayer extends Structure.get('KirishimaPlayer') {
+ public resolvePartialTrack(track: KirishimaPartialTrack) {
+ if (track.isrc) {
+ return this.kirishima.resolveTracks(track.isrc);
+ }
+
+ return this.kirishima.resolveTracks(`${track.info.title} - ${track.info.author ? track.info.author : ''}`);
+ }
+}
diff --git a/packages/deezer/src/index.ts b/packages/deezer/src/index.ts
new file mode 100644
index 0000000..cc1d5cc
--- /dev/null
+++ b/packages/deezer/src/index.ts
@@ -0,0 +1,203 @@
+import { Kirishima, KirishimaNode, KirishimaPlugin, LoadTrackResponse, KirishimaTrack } from '@kirishima/core';
+import { fetch, FetchResultTypes } from '@kirishima/fetch';
+import { LoadTypeEnum } from 'lavalink-api-types';
+import { KirishimaPartialTrack } from './Structures/KirishimaPartialTrack';
+import type { DeezerPlaylist, DeezerTrack } from './typings';
+
+export class KirishimaDeezer extends KirishimaPlugin {
+ private resolvers = {
+ track: this.loadTrack.bind(this),
+ album: this.loadAlbum.bind(this),
+ playlist: this.loadPlaylist.bind(this)
+ };
+
+ private baseURL = 'https://api.deezer.com/';
+ private regex = /^(?:https?:\/\/|)?(?:www\.)?deezer\.com\/(?:\w{2}\/)?(?track|album|playlist)\/(?\d+)/;
+ private _resolveTracks!: (
+ options: string | { source?: string | undefined; query: string },
+ node?: KirishimaNode
+ ) => Promise>;
+
+ public constructor() {
+ super({
+ name: 'deezer'
+ });
+ }
+
+ public load(kirishima: Kirishima) {
+ this._resolveTracks = kirishima.resolveTracks.bind(kirishima);
+ kirishima.resolveTracks = this.resolveTracks.bind(this);
+ }
+
+ public resolveTracks(
+ options: string | { source?: string | undefined; query: string },
+ node?: KirishimaNode
+ ): Promise> {
+ const query = typeof options === 'string' ? options : options.query;
+ const source = typeof options === 'string' ? undefined : options.source;
+ if (source === 'deezer') {
+ return this.searchTracks(query) as unknown as Promise>;
+ }
+
+ const [, type, id] = query.match(this.regex) ?? [];
+
+ if (type in this.resolvers) {
+ const resolver = this.resolvers[type as keyof typeof this.resolvers];
+ if (resolver) {
+ return resolver(id) as unknown as Promise>;
+ }
+ }
+
+ return this._resolveTracks(options, node);
+ }
+
+ public async loadPlaylist(identifier: string) {
+ try {
+ const deezer_playlist = await fetch(`${this.baseURL}/playlist/${identifier}`, undefined, FetchResultTypes.JSON);
+ if (deezer_playlist.tracks.data.length === 0) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+
+ return {
+ loadType: LoadTypeEnum.PLAYLIST_LOADED,
+ playlistInfo: {
+ name: deezer_playlist.title
+ },
+ tracks: deezer_playlist.tracks.data.map((track) => {
+ return new KirishimaPartialTrack({
+ artworkUrl: track.album.cover_small,
+ isrc: track.isrc ?? null,
+ info: {
+ title: track.title,
+ uri: track.link,
+ author: track.artist.name,
+ length: track.duration * 1000,
+ sourceName: 'deezer',
+ position: 0,
+ isSeekable: true,
+ isStream: false
+ }
+ });
+ })
+ };
+ } catch (e) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+ }
+
+ public async loadAlbum(identifier: string) {
+ try {
+ const deezer_playlist = await fetch(`${this.baseURL}/album/${identifier}`, undefined, FetchResultTypes.JSON);
+ if (deezer_playlist.tracks.data.length === 0) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+
+ return {
+ loadType: LoadTypeEnum.PLAYLIST_LOADED,
+ playlistInfo: {
+ name: deezer_playlist.title
+ },
+ tracks: deezer_playlist.tracks.data.map((track) => {
+ return new KirishimaPartialTrack({
+ artworkUrl: track.album.cover_small,
+ isrc: track.isrc ?? null,
+ info: {
+ title: track.title,
+ uri: track.link,
+ author: track.artist.name,
+ length: track.duration * 1000,
+ sourceName: 'deezer',
+ position: 0,
+ isSeekable: true,
+ isStream: false
+ }
+ });
+ })
+ };
+ } catch (e) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+ }
+
+ public async searchTracks(query: string) {
+ try {
+ const deezer_search = await fetch<{ data: DeezerTrack[] }>(
+ `${this.baseURL}search?q=${encodeURIComponent(query)}`,
+ undefined,
+ FetchResultTypes.JSON
+ );
+ if (deezer_search.data.length === 0) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+
+ return {
+ loadType: LoadTypeEnum.SEARCH_RESULT,
+ tracks: deezer_search.data.map((track) => {
+ return new KirishimaPartialTrack({
+ artworkUrl: track.album.cover_small,
+ isrc: track.isrc ?? null,
+ info: {
+ title: track.title,
+ uri: track.link,
+ author: track.artist.name,
+ length: track.duration * 1000,
+ sourceName: 'deezer',
+ position: 0,
+ isSeekable: true,
+ isStream: false
+ }
+ });
+ })
+ };
+ } catch (e) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+ }
+
+ public async loadTrack(identifier: string) {
+ try {
+ const deezer_track = await fetch(`${this.baseURL}/track/${identifier}`, undefined, FetchResultTypes.JSON);
+ const track = new KirishimaPartialTrack({
+ artworkUrl: deezer_track.album.cover_small,
+ isrc: deezer_track.isrc ?? null,
+ info: {
+ title: deezer_track.title,
+ uri: deezer_track.link,
+ author: deezer_track.artist.name,
+ length: deezer_track.duration * 1000,
+ sourceName: 'deezer',
+ position: 0,
+ isSeekable: true,
+ isStream: false
+ }
+ });
+ return {
+ loadType: LoadTypeEnum.TRACK_LOADED,
+ tracks: [track]
+ };
+ } catch (e) {
+ return {
+ loadType: LoadTypeEnum.NO_MATCHES,
+ tracks: []
+ };
+ }
+ }
+}
diff --git a/packages/deezer/src/typings/index.ts b/packages/deezer/src/typings/index.ts
new file mode 100644
index 0000000..ea57364
--- /dev/null
+++ b/packages/deezer/src/typings/index.ts
@@ -0,0 +1,27 @@
+export interface DeezerTrack {
+ id: number;
+ title: string;
+ isrc: string | null;
+ link: string;
+ duration: number;
+ artist: DeezerArtist;
+ album: DeezerAlbum;
+}
+
+export interface DeezerPlaylist {
+ tracks: {
+ data: DeezerTrack[];
+ };
+ title: string;
+}
+
+export interface DeezerAlbum {
+ id: number;
+ title: string;
+ cover_small: string;
+}
+
+export interface DeezerArtist {
+ id: number;
+ name: string;
+}
diff --git a/packages/deezer/tsconfig.eslint.json b/packages/deezer/tsconfig.eslint.json
new file mode 100644
index 0000000..c2f78f8
--- /dev/null
+++ b/packages/deezer/tsconfig.eslint.json
@@ -0,0 +1,4 @@
+{
+ "extends": "./tsconfig.json",
+ "include": ["src"]
+}
\ No newline at end of file
diff --git a/packages/deezer/tsconfig.json b/packages/deezer/tsconfig.json
new file mode 100644
index 0000000..f8d28c8
--- /dev/null
+++ b/packages/deezer/tsconfig.json
@@ -0,0 +1,10 @@
+{
+ "extends": "@sapphire/ts-config",
+ "compilerOptions": {
+ "rootDir": "./src",
+ "outDir": "./dist",
+ "composite": true,
+ "preserveConstEnums": true
+ },
+ "include": ["src/**/*.ts"]
+}
\ No newline at end of file
diff --git a/src/index.ts b/src/index.ts
deleted file mode 100644
index fa9f0ca..0000000
--- a/src/index.ts
+++ /dev/null
@@ -1,3 +0,0 @@
-export const main = () => 'Kirishima ship ready to serve !';
-
-export default main;
diff --git a/tsconfig.eslint.json b/tsconfig.eslint.json
index c2f78f8..5ddc52a 100644
--- a/tsconfig.eslint.json
+++ b/tsconfig.eslint.json
@@ -1,4 +1,4 @@
{
"extends": "./tsconfig.json",
- "include": ["src"]
+ "include": ["packages/**/*.ts"]
}
\ No newline at end of file
diff --git a/tsconfig.json b/tsconfig.json
index f8d28c8..f2279b7 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -6,5 +6,5 @@
"composite": true,
"preserveConstEnums": true
},
- "include": ["src/**/*.ts"]
+ "include": ["packages/**/*.ts"]
}
\ No newline at end of file
diff --git a/turbo.json b/turbo.json
new file mode 100644
index 0000000..5d6379c
--- /dev/null
+++ b/turbo.json
@@ -0,0 +1,17 @@
+{
+ "pipeline": {
+ "build": {
+ "dependsOn": ["^build"],
+ "outputs": ["dist/**"]
+ },
+ "lint": {
+ "outputs": []
+ },
+ "lint:fix": {
+ "outpus": []
+ },
+ "dev": {
+ "cache": false
+ }
+ }
+}