Skip to content

Commit

Permalink
refactor, new methods
Browse files Browse the repository at this point in the history
  • Loading branch information
s1adem4n committed Nov 6, 2023
1 parent 165cbcf commit 0771493
Show file tree
Hide file tree
Showing 16 changed files with 468 additions and 65 deletions.
9 changes: 7 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,14 @@ npm i @slademan/soundcloud
```

```ts
import { greet } from "soundcloud";
import Soundcloud from "@slademan/soundcloud";

greet("Hello, world!");
const sc = new Soundcloud(ClientID, OauthTokem);

const me = await sc.me.get();
if (me.success && me.data) {
console.log(me.data);
}
```

## Development
Expand Down
8 changes: 4 additions & 4 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

52 changes: 42 additions & 10 deletions src/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
/* eslint-disable eslint-comments/disable-enable-pair */
/* eslint-disable @typescript-eslint/no-explicit-any */

interface RequestOpts {
params?: Record<string, any>;
body?: Record<string, any>;
}

type HttpVerb = "GET" | "POST" | "PUT" | "PATCH" | "DELETE";

export class API {
public static headers: Record<string, any> = {
Origin: "https://soundcloud.com",
Expand All @@ -16,30 +23,55 @@ export class API {
API.headers.Authorization = `OAuth ${oauthToken}`;
}

public async get(
private async makeRequest(
endpoint: string,
params?: Record<string, any> | undefined,
): Promise<Response> {
method: HttpVerb,
opts: RequestOpts = {},
) {
const url = new URL(`${this.apiURL}${endpoint}`);
if (params) {
url.search = `${new URLSearchParams(params).toString()}&client_id=${
if (opts.params) {
url.search = `${new URLSearchParams(opts.params).toString()}&client_id=${
this.clientID
}`;
} else {
url.search = `?client_id=${this.clientID}`;
}

const response = await fetch(url.toString(), {
method,
headers: API.headers,
body: JSON.stringify(opts.body),
});

return response;
}

public async fetch<T>(
endpoint: string,
method: HttpVerb,
opts?: RequestOpts,
) {
const res = await this.makeRequest(endpoint, method, opts);
return {
success: res.ok,
data: res.ok ? ((await res.json()) as T) : null,
};
}

public async getURL(url: string) {
const urlObj = new URL(url);
if (!urlObj.searchParams.has("client_id")) {
urlObj.searchParams.append("client_id", this.clientID);
}
const response = await fetch(urlObj.toString(), {
method: "GET",
headers: API.headers,
});
if (!response.ok) {
throw new Error(
`Failed to fetch ${url.toString()}: "${
response.statusText
}" with status code ${response.status}`,
`Failed to fetch ${urlObj.toString()}: ${response.status}`,
);
}

return response;
}

Expand Down
28 changes: 28 additions & 0 deletions src/entities/Discover.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import type {
SoundcloudFilter,
SoundcloudSelectionSearch,
SoundcloudTrackSearch,
} from "../types";
import { Base } from "./Base";

export class Discover extends Base {
public recentTracks = async (genre: string, params?: SoundcloudFilter) => {
return this.api.fetch<SoundcloudTrackSearch>(
`/recent_tracks/${genre}`,
"GET",
{
params,
},
);
};

public mixedCollections = async (params?: SoundcloudFilter) => {
return this.api.fetch<SoundcloudSelectionSearch>(
`/mixed_collections`,
"GET",
{
params,
},
);
};
}
66 changes: 64 additions & 2 deletions src/entities/Me.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,72 @@
import type {
SoundcloudFilter,
SoundcloudPlaylist,
SoundcloudTrack,
} from "../types";
import {
type SoundcloudLikesIDsSearch,
type SoundcloudWhoToFollowFilter,
type SoundcloudWhoToFollowSearch,
} from "../types/MeTypes";
import type { SoundcloudUser } from "../types/UserTypes";

import { Base } from "./Base.js";

export class Me extends Base {
public get = async () => {
const response = await this.sc.api.get("/me");
return (await response.json()) as SoundcloudUser;
return this.api.fetch<SoundcloudUser>("/me", "GET");
};

trackReposts = {
put: async (id: number) => {
return this.sc.api.fetch<null>(`/me/track_reposts/${id}`, "PUT");
},
delete: async (id: number) => {
return this.sc.api.fetch<null>(`/me/track_reposts/${id}`, "DELETE");
},
caption: async (id: number, caption: string) => {
return await this.sc.api.fetch<null>(
`/me/track_reposts/${id}/caption`,
"PUT",
{
body: { payload: { caption }, type: "raw" },
},
);
},
};
trackLikes = {
get: async (params?: SoundcloudFilter) => {
return this.sc.api.fetch<SoundcloudLikesIDsSearch>(
"/me/track_likes/ids",
"GET",
{
params,
},
);
},
put: async (id: number) => {
return this.sc.api.fetch<null>(`/me/track_likes/${id}`, "PUT");
},
delete: async (id: number) => {
return this.sc.api.fetch<null>(`/me/track_likes/${id}`, "DELETE");
},
};
library = {
all: async (params?: SoundcloudFilter) => {
return this.api.fetch<SoundcloudPlaylist>("/me/library", "GET", {
params,
});
},
};
suggested = {
who_to_follow: async (params?: SoundcloudWhoToFollowFilter) => {
return this.api.fetch<SoundcloudWhoToFollowSearch>(
"/me/suggested/who_to_follow",
"GET",
{
params,
},
);
},
};
}
64 changes: 64 additions & 0 deletions src/entities/Search.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
import type {
SoundcloudAlbumFilter,
SoundcloudAlbumSearch,
SoundcloudAllSearch,
SoundcloudPlaylistFilter,
SoundcloudPlaylistSearch,
SoundcloudQuerySearch,
SoundcloudSearchFilter,
SoundcloudTrackFilter,
SoundcloudTrackSearch,
SoundcloudUserFilter,
SoundcloudUserSearch,
} from "../types";
import { Base } from "./Base";

export class Search extends Base {
public tracks = async (params?: SoundcloudTrackFilter) => {
return await this.api.fetch<SoundcloudTrackSearch>(
"/search/tracks",
"GET",
{ params },
);
};

public users = async (params?: SoundcloudUserFilter) => {
return await this.api.fetch<SoundcloudUserSearch>("/search/users", "GET", {
params,
});
};

public queries = async (params?: SoundcloudSearchFilter) => {
return await this.api.fetch<SoundcloudQuerySearch>(
"/search/queries",
"GET",
{ params },
);
};

public playlists = async (params?: SoundcloudPlaylistFilter) => {
return await this.api.fetch<SoundcloudPlaylistSearch>(
"/search/playlists",
"GET",
{ params },
);
};

public albums = async (params?: SoundcloudAlbumFilter) => {
return await this.api.fetch<SoundcloudAlbumSearch>(
"/search/albums",
"GET",
{ params },
);
};

public all = async (params?: SoundcloudSearchFilter) => {
return await this.api.fetch<SoundcloudAllSearch>("/search", "GET", {
params,
});
};

public async searchNext<T>(next_href: string) {
return await this.api.getURL(next_href);
}
}
32 changes: 23 additions & 9 deletions src/entities/Tracks.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,38 @@
import type {
SoundcloudCommentSearch,
SoundcloudTrack,
SoundcloudTrackFilter,
SoundcloudTrackSearch,
SoundcloudCommentFilter,
SoundcloudFilter,
} from "../types";

import { Base } from "./Base.js";

export class Tracks extends Base {
public get = async (id: number) => {
const response = await this.api.get(`/tracks/${id}`);
return (await response.json()) as SoundcloudTrack;
return await this.api.fetch<SoundcloudTrack>(`/tracks/${id}`, "GET");
};

public related = async (id: number, limit?: number) => {
const response = await this.api.get(`/tracks/${id}/related`, { limit });
return (await response.json()) as SoundcloudTrack[];
public related = async (id: number, params?: SoundcloudFilter) => {
return await this.api.fetch<SoundcloudTrackSearch>(
`/tracks/${id}/related`,
"GET",
{ params },
);
};

public search = async (params?: SoundcloudTrackFilter) => {
const response = await this.api.get("/search/tracks", params);
return (await response.json()) as SoundcloudTrackSearch;
public getMultiple = async (ids: number[]) => {
const params = { ids: ids.join(",") };
return await this.api.fetch<SoundcloudTrack[]>(`/tracks`, "GET", {
params,
});
};

public comments = async (id: number, params?: SoundcloudCommentFilter) => {
return await this.api.fetch<SoundcloudCommentSearch>(
`/tracks/${id}/comments`,
"GET",
{ params },
);
};
}
17 changes: 13 additions & 4 deletions src/entities/Util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,14 @@ export class Util extends Base {
? `&client_id=${client_id}`
: `?client_id=${client_id}`;
try {
return await fetch(url + connect, { headers })
.then((r) => r.json())
// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
.then((r) => r.url as string);
const res = await fetch(url + connect, {
method: "GET",
headers: headers,
});

return (await res.json()) as {
url: string;
} | null;
} catch {
return null;
}
Expand Down Expand Up @@ -51,4 +55,9 @@ export class Util extends Base {

return await this.getStreamLink(transcodings[0]);
};

public hqArtwork = (track: SoundcloudTrack) => {
const hqArtwork = track.artwork_url.replace("large", "t500x500");
return hqArtwork;
};
}
17 changes: 15 additions & 2 deletions src/types/APITypes.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,24 @@
export interface SoundcloudFilter {
limit?: number;
offset?: number;
}

export interface SoundcloudSearchFilter extends SoundcloudFilter {
q: string;
}

export interface SoundcloudSearch {
next_href: string;
next_href: string | null;
query_urn: string;
total_results: number;
total_results?: number;
}

export type SoundcloudLicense =
| "all-rights-reserved"
| "cc-by"
| "cc-by-nc"
| "cc-by-nc-nd"
| "cc-by-nc-sa"
| "cc-by-nd"
| "cc-by-sa"
| "no-rights-reserved";
Loading

0 comments on commit 0771493

Please sign in to comment.