@zibot/scdl 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/README.md +118 -0
  2. package/index.d.ts +78 -0
  3. package/index.js +124 -0
  4. package/package.json +34 -0
package/README.md ADDED
@@ -0,0 +1,118 @@
1
+ # @zibot/scdl
2
+
3
+ @zibot/scdl là một module JavaScript hỗ trợ tải, tìm kiếm, và quản lý dữ liệu từ SoundCloud thông qua API. Module này cung cấp các
4
+ phương thức tiện lợi để xử lý track, playlist, và tải nội dung.
5
+
6
+ ## Cài đặt
7
+
8
+ Bạn có thể cài đặt module này bằng npm hoặc yarn:
9
+
10
+ ```bash
11
+ npm install @zibot/scdl
12
+ ```
13
+
14
+ hoặc
15
+
16
+ ```bash
17
+ yarn add @zibot/scdl
18
+ ```
19
+
20
+ ## Sử dụng
21
+
22
+ ### Khởi tạo
23
+
24
+ Đầu tiên, bạn cần khởi tạo lớp `SoundCloud` để sử dụng các chức năng của module:
25
+
26
+ ```javascript
27
+ const { SoundCloud } = require("@zibot/scdl");
28
+
29
+ (async () => {
30
+ const scdl = new SoundCloud({ init: true }); // Tự động lấy client ID
31
+ await scdl.init(); // Đảm bảo client ID được khởi tạo
32
+ })();
33
+ ```
34
+
35
+ ---
36
+
37
+ ### Các phương thức
38
+
39
+ #### **`searchTracks(options)`**
40
+
41
+ Tìm kiếm các track trên SoundCloud.
42
+
43
+ ```javascript
44
+ const tracks = await scdl.searchTracks({ query: "chill", limit: 5 });
45
+ console.log(tracks);
46
+ ```
47
+
48
+ **Tham số:**
49
+
50
+ - `query` (bắt buộc): Từ khóa để tìm kiếm.
51
+ - `limit` (mặc định: `20`): Số lượng track tối đa.
52
+ - `offset` (mặc định: `0`): Vị trí bắt đầu.
53
+
54
+ ---
55
+
56
+ #### **`getTrack(url)`**
57
+
58
+ Lấy thông tin chi tiết về một track.
59
+
60
+ ```javascript
61
+ const track = await scdl.getTrack("https://soundcloud.com/user/song");
62
+ console.log(track);
63
+ ```
64
+
65
+ **Tham số:**
66
+
67
+ - `url` (bắt buộc): URL của track.
68
+
69
+ ---
70
+
71
+ #### **`getPlaylist(url)`**
72
+
73
+ Lấy thông tin chi tiết về một playlist.
74
+
75
+ ```javascript
76
+ const playlist = await scdl.getPlaylist("https://soundcloud.com/user/playlist");
77
+ console.log(playlist);
78
+ ```
79
+
80
+ **Tham số:**
81
+
82
+ - `url` (bắt buộc): URL của playlist.
83
+
84
+ ---
85
+
86
+ #### **`downloadTrack(url, options)`**
87
+
88
+ Tải một track từ SoundCloud.
89
+
90
+ ```javascript
91
+ const stream = await scdl.downloadTrack("https://soundcloud.com/user/song");
92
+ stream.pipe(fs.createWriteStream("track.mp3"));
93
+ ```
94
+
95
+ **Tham số:**
96
+
97
+ - `url` (bắt buộc): URL của track.
98
+ - `options` (tùy chọn): Cấu hình tải xuống.
99
+
100
+ ---
101
+
102
+ ### Lưu ý
103
+
104
+ - Trước khi sử dụng các phương thức như `searchTracks`, `getTrack`, hoặc `downloadTrack`, cần đảm bảo rằng phương thức `init()` đã
105
+ hoàn thành để lấy `clientId`.
106
+ - Nếu `clientId` không được khởi tạo, các phương thức này sẽ ném lỗi.
107
+
108
+ ---
109
+
110
+ ## Đóng góp
111
+
112
+ Nếu bạn muốn đóng góp cho dự án này, vui lòng tạo một pull request hoặc mở một issue trên GitHub.
113
+
114
+ ---
115
+
116
+ ## Giấy phép
117
+
118
+ Dự án này được cấp phép theo giấy phép MIT. Xem file [LICENSE](LICENSE) để biết thêm chi tiết.
package/index.d.ts ADDED
@@ -0,0 +1,78 @@
1
+ declare module "@zibot/scdl" {
2
+ import { Readable } from "stream";
3
+
4
+ // Types
5
+ export interface SearchOptions {
6
+ query: string;
7
+ limit?: number;
8
+ offset?: number;
9
+ type?: "all" | "tracks" | "playlists" | "users";
10
+ }
11
+
12
+ export interface DownloadOptions {
13
+ quality?: "high" | "low";
14
+ }
15
+
16
+ export interface Track {
17
+ id: number;
18
+ title: string;
19
+ url: string;
20
+ user: { id: number; username: string };
21
+ media: {
22
+ transcodings: {
23
+ url: string;
24
+ format: { protocol: string; mime_type: string };
25
+ }[];
26
+ };
27
+ }
28
+
29
+ export interface Playlist {
30
+ id: number;
31
+ title: string;
32
+ tracks: Track[];
33
+ }
34
+
35
+ export interface User {
36
+ id: number;
37
+ username: string;
38
+ followers_count: number;
39
+ track_count: number;
40
+ }
41
+
42
+ export interface SearchResponse {
43
+ collection: (Track | Playlist | User)[];
44
+ next_href?: string;
45
+ }
46
+
47
+ export class SoundCloud {
48
+ clientId: string | null;
49
+ apiBaseUrl: string;
50
+
51
+ constructor(options?: { init?: boolean });
52
+
53
+ /**
54
+ * Initialize the SoundCloud client to retrieve clientId.
55
+ */
56
+ init(): Promise<void>;
57
+
58
+ /**
59
+ * Search for tracks, playlists, or users on SoundCloud.
60
+ */
61
+ searchTracks(options: SearchOptions): Promise<SearchResponse>;
62
+
63
+ /**
64
+ * Retrieve detailed information about a single track.
65
+ */
66
+ getTrack(url: string): Promise<Track>;
67
+
68
+ /**
69
+ * Retrieve detailed information about a playlist.
70
+ */
71
+ getPlaylist(url: string): Promise<Playlist>;
72
+
73
+ /**
74
+ * Download a track as a stream.
75
+ */
76
+ downloadTrack(url: string, options?: DownloadOptions): Promise<Readable>;
77
+ }
78
+ }
package/index.js ADDED
@@ -0,0 +1,124 @@
1
+ const axios = require("axios");
2
+ const m3u8stream = require("m3u8stream");
3
+
4
+ class SoundCloud {
5
+ constructor(options = {}) {
6
+ const defaultOptions = { init: true, apiBaseUrl: "https://api-v2.soundcloud.com" };
7
+ options = { ...defaultOptions, ...options };
8
+ this.clientId = null;
9
+ this.apiBaseUrl = options.apiBaseUrl;
10
+ if (options.init) this.init();
11
+ }
12
+
13
+ // Auto-fetch Client ID
14
+ async init() {
15
+ const clientIdRegex = /client_id=(:?[\w\d]{32})/;
16
+ const soundCloudDom = (await axios.get("https://soundcloud.com")).data;
17
+ const scriptUrls = (soundCloudDom.match(/<script crossorigin src="(.*?)"><\/script>/g) || [])
18
+ .map((tag) => tag.match(/src="(.*?)"/)?.[1])
19
+ .filter(Boolean);
20
+
21
+ for (const url of scriptUrls) {
22
+ const response = await axios.get(url);
23
+ const match = response.data.match(clientIdRegex);
24
+ if (match) {
25
+ this.clientId = match[1];
26
+ return;
27
+ }
28
+ }
29
+
30
+ throw new Error("Failed to fetch client ID");
31
+ }
32
+
33
+ // Search SoundCloud
34
+ async searchTracks({ query, limit = 20, offset = 0, type = "all" }) {
35
+ const path = type === "all" ? "" : `/${type}`;
36
+ const url = `${this.apiBaseUrl}/search${path}?q=${encodeURIComponent(
37
+ query,
38
+ )}&limit=${limit}&offset=${offset}&access=playable&client_id=${this.clientId}`;
39
+ console.log(url);
40
+ try {
41
+ const { data } = await axios.get(url);
42
+ return data;
43
+ } catch (error) {
44
+ console.error("Search error:", error.message || error);
45
+ throw new Error("Search failed");
46
+ }
47
+ }
48
+
49
+ // Get track details
50
+ async getTrackDetails(trackUrl) {
51
+ try {
52
+ return await this.fetchItem(trackUrl);
53
+ } catch (error) {
54
+ throw new Error("Invalid track URL");
55
+ }
56
+ }
57
+
58
+ // Get playlist details
59
+ async getPlaylistDetails(playlistUrl) {
60
+ try {
61
+ const playlist = await this.fetchItem(playlistUrl);
62
+ const { tracks } = playlist;
63
+
64
+ const loadedTracks = tracks.filter((track) => track.title);
65
+ const unloadedTrackIds = tracks.filter((track) => !track.title).map((track) => track.id);
66
+
67
+ if (unloadedTrackIds.length > 0) {
68
+ const moreTracks = await this.fetchTracksByIds(unloadedTrackIds);
69
+ playlist.tracks = loadedTracks.concat(moreTracks);
70
+ }
71
+
72
+ return playlist;
73
+ } catch (error) {
74
+ throw new Error("Invalid playlist URL");
75
+ }
76
+ }
77
+
78
+ // Download track stream
79
+ async downloadTrack(trackUrl, options = {}) {
80
+ const track = await this.getTrackDetails(trackUrl);
81
+ const transcoding = track.media.transcodings.find((t) => t.format.protocol === "hls");
82
+
83
+ if (!transcoding) throw new Error("No valid HLS stream found");
84
+
85
+ const m3u8Url = await this.getStreamUrl(transcoding.url);
86
+ return m3u8stream(m3u8Url, options);
87
+ }
88
+
89
+ // Fetch single item (track/playlist/user)
90
+ async fetchItem(itemUrl) {
91
+ const url = `${this.apiBaseUrl}/resolve?url=${itemUrl}&client_id=${this.clientId}`;
92
+ try {
93
+ const { data } = await axios.get(url);
94
+ return data;
95
+ } catch (error) {
96
+ throw new Error("Failed to fetch item details");
97
+ }
98
+ }
99
+
100
+ // Fetch multiple tracks by their IDs
101
+ async fetchTracksByIds(trackIds) {
102
+ const ids = trackIds.join(",");
103
+ const url = `${this.apiBaseUrl}/tracks?ids=${ids}&client_id=${this.clientId}`;
104
+ try {
105
+ const { data } = await axios.get(url);
106
+ return data;
107
+ } catch (error) {
108
+ throw new Error("Failed to fetch tracks by IDs");
109
+ }
110
+ }
111
+
112
+ // Get HLS stream URL
113
+ async getStreamUrl(transcodingUrl) {
114
+ const url = `${transcodingUrl}?client_id=${this.clientId}`;
115
+ try {
116
+ const { data } = await axios.get(url);
117
+ return data.url;
118
+ } catch (error) {
119
+ throw new Error("Failed to fetch stream URL");
120
+ }
121
+ }
122
+ }
123
+
124
+ module.exports = SoundCloud;
package/package.json ADDED
@@ -0,0 +1,34 @@
1
+ {
2
+ "name": "@zibot/scdl",
3
+ "version": "0.0.1",
4
+ "description": "Soucloud download",
5
+ "main": "index.js",
6
+ "scripts": {
7
+ "test": "echo \"Error: no test specified\" && exit 1"
8
+ },
9
+ "repository": {
10
+ "type": "git",
11
+ "url": "git+https://github.com/zijipia/Zibot_Package.git"
12
+ },
13
+ "keywords": [
14
+ "@zibot/scdl",
15
+ "scdl"
16
+ ],
17
+ "author": "Ziji",
18
+ "license": "ISC",
19
+ "bugs": {
20
+ "url": "https://github.com/zijipia/Zibot_Package/issues"
21
+ },
22
+ "publishConfig": {
23
+ "access": "public"
24
+ },
25
+ "homepage": "https://github.com/zijipia/Zibot_Package#readme",
26
+ "devDependencies": {
27
+ "discord.js": "^14.16.3"
28
+ },
29
+ "dependencies": {
30
+ "axios": "^1.7.7",
31
+ "events": "^3.3.0",
32
+ "m3u8stream": "^0.8.6"
33
+ }
34
+ }