riffy-soundcloud 1.0.0
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.
- package/LICENSE +21 -0
- package/README.md +43 -0
- package/dist/plugin.js +129 -0
- package/index.d.ts +5 -0
- package/index.js +3 -0
- package/package.json +34 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 ramkrishna-js
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
# riffy-soundcloud
|
|
2
|
+
|
|
3
|
+
> [!IMPORTANT]
|
|
4
|
+
> This is an **unofficial** plugin and is not officially maintained or created by the [Riffy](https://riffy.js.org/) team.
|
|
5
|
+
|
|
6
|
+
A robust and easy-to-use plugin for [Riffy](https://github.com/riffy-team/riffy) that enables seamless SoundCloud track and playlist resolution using the V2 API. Perfect for Discord music bots looking to expand their audio sources beyond Spotify and YouTube.
|
|
7
|
+
|
|
8
|
+
## Installation
|
|
9
|
+
|
|
10
|
+
```bash
|
|
11
|
+
npm install riffy-soundcloud
|
|
12
|
+
```
|
|
13
|
+
|
|
14
|
+
## Usage
|
|
15
|
+
|
|
16
|
+
```javascript
|
|
17
|
+
const { Riffy } = require("riffy");
|
|
18
|
+
const { SoundCloud } = require("riffy-soundcloud");
|
|
19
|
+
|
|
20
|
+
const riffy = new Riffy(client, nodes, {
|
|
21
|
+
plugins: [
|
|
22
|
+
new SoundCloud({
|
|
23
|
+
clientId: "YOUR_SOUNDCLOUD_CLIENT_ID" // Required
|
|
24
|
+
})
|
|
25
|
+
]
|
|
26
|
+
});
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Features
|
|
30
|
+
|
|
31
|
+
- Resolves SoundCloud Tracks
|
|
32
|
+
- Resolves SoundCloud Playlists
|
|
33
|
+
- Supports `soundcloud.com` and `on.soundcloud.com` URLs
|
|
34
|
+
|
|
35
|
+
## Support
|
|
36
|
+
|
|
37
|
+
For support, you can:
|
|
38
|
+
- Create an [Issue](https://github.com/ramkrishna-js/riffy-soundcloud/issues)
|
|
39
|
+
- DM me on Discord: `ramkrishna0`
|
|
40
|
+
|
|
41
|
+
## License
|
|
42
|
+
|
|
43
|
+
This project is licensed under the [MIT License](LICENSE).
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
const { fetch } = require("undici");
|
|
2
|
+
const { Plugin, Track } = require("riffy");
|
|
3
|
+
|
|
4
|
+
const REGEX = /^https?:\/\/(?:www\.|m\.|on\.)?soundcloud\.com\/.+/;
|
|
5
|
+
|
|
6
|
+
class SoundCloud extends Plugin {
|
|
7
|
+
constructor(options) {
|
|
8
|
+
super();
|
|
9
|
+
this.baseURL = 'https://api-v2.soundcloud.com';
|
|
10
|
+
this.options = options;
|
|
11
|
+
|
|
12
|
+
if (!this.options?.clientId) {
|
|
13
|
+
throw new Error('SoundCloud Plugin: clientId is required.');
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async load(riffy) {
|
|
18
|
+
this.riffy = riffy;
|
|
19
|
+
this._resolve = riffy.resolve.bind(riffy);
|
|
20
|
+
riffy.resolve = this.resolve.bind(this);
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
check(query) {
|
|
24
|
+
return REGEX.test(query);
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
async resolve({ query, requester }) {
|
|
28
|
+
let trackLoaded = "",
|
|
29
|
+
playlistLoaded = "",
|
|
30
|
+
loadFailed = "";
|
|
31
|
+
|
|
32
|
+
const node = this.riffy.leastUsedNodes[0];
|
|
33
|
+
|
|
34
|
+
if (node.restVersion === "v4") {
|
|
35
|
+
trackLoaded = "track";
|
|
36
|
+
playlistLoaded = "playlist";
|
|
37
|
+
loadFailed = "error";
|
|
38
|
+
} else {
|
|
39
|
+
trackLoaded = "TRACK_LOADED";
|
|
40
|
+
playlistLoaded = "PLAYLIST_LOADED";
|
|
41
|
+
loadFailed = "LOAD_FAILED";
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
const finalQuery = query.query || query;
|
|
45
|
+
if (!this.check(finalQuery)) return this._resolve({ query, requester });
|
|
46
|
+
|
|
47
|
+
try {
|
|
48
|
+
const data = await this.fetchData(finalQuery);
|
|
49
|
+
if (!data) throw new Error("No data found");
|
|
50
|
+
|
|
51
|
+
if (data.kind === "track") {
|
|
52
|
+
const track = await this.buildUnresolved(data, requester);
|
|
53
|
+
return this.buildResponse(trackLoaded, [track], null, null);
|
|
54
|
+
} else if (data.kind === "playlist") {
|
|
55
|
+
// Filter out tracks that might not be playable or full objects if necessary
|
|
56
|
+
// But usually resolve returns enough info
|
|
57
|
+
const tracks = await Promise.all(data.tracks.map(async t => {
|
|
58
|
+
// Sometimes playlist tracks are incomplete?
|
|
59
|
+
if (!t.title) return null;
|
|
60
|
+
return await this.buildUnresolved(t, requester);
|
|
61
|
+
}));
|
|
62
|
+
|
|
63
|
+
const validTracks = tracks.filter(t => t !== null);
|
|
64
|
+
return this.buildResponse(playlistLoaded, validTracks, data.title, null);
|
|
65
|
+
} else {
|
|
66
|
+
return this.buildResponse(loadFailed, null, null, "Unsupported SoundCloud URL type");
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
} catch (e) {
|
|
70
|
+
return this.buildResponse(loadFailed, null, null, e.message || null);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
async fetchData(url) {
|
|
75
|
+
// Handle short links by following redirects if necessary, but API resolve usually handles them.
|
|
76
|
+
const res = await fetch(`${this.baseURL}/resolve?url=${encodeURIComponent(url)}&client_id=${this.options.clientId}`);
|
|
77
|
+
if (!res.ok) {
|
|
78
|
+
// Try to read body for error
|
|
79
|
+
throw new Error(`SoundCloud API Error: ${res.status} ${res.statusText}`);
|
|
80
|
+
}
|
|
81
|
+
return await res.json();
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
async buildUnresolved(track, requester) {
|
|
85
|
+
if (!track) throw new ReferenceError('The SoundCloud track object was not provided');
|
|
86
|
+
|
|
87
|
+
const node = this.riffy.leastUsedNodes[0];
|
|
88
|
+
|
|
89
|
+
const artwork = track.artwork_url ? track.artwork_url.replace('-large', '-t500x500') : null;
|
|
90
|
+
|
|
91
|
+
return new Track(
|
|
92
|
+
{
|
|
93
|
+
track: "",
|
|
94
|
+
info: {
|
|
95
|
+
identifier: String(track.id),
|
|
96
|
+
isSeekable: true,
|
|
97
|
+
author: track.user?.username || "Unknown",
|
|
98
|
+
length: track.duration,
|
|
99
|
+
isStream: false,
|
|
100
|
+
sourceName: "soundcloud",
|
|
101
|
+
title: track.title,
|
|
102
|
+
uri: track.permalink_url,
|
|
103
|
+
thumbnail: artwork,
|
|
104
|
+
position: 0,
|
|
105
|
+
},
|
|
106
|
+
},
|
|
107
|
+
requester,
|
|
108
|
+
node
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async buildResponse(loadType, tracks, name, error) {
|
|
113
|
+
return Object.assign(
|
|
114
|
+
{
|
|
115
|
+
loadType,
|
|
116
|
+
tracks,
|
|
117
|
+
playlistInfo: name ? {
|
|
118
|
+
name
|
|
119
|
+
} : null,
|
|
120
|
+
exception: error ? {
|
|
121
|
+
message: error,
|
|
122
|
+
severity: 'COMMON',
|
|
123
|
+
} : null
|
|
124
|
+
}
|
|
125
|
+
)
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
module.exports = { SoundCloud };
|
package/index.d.ts
ADDED
package/index.js
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "riffy-soundcloud",
|
|
3
|
+
"description": "A robust SoundCloud plugin for Riffy that enables seamless track and playlist resolution.",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"scripts": {
|
|
7
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
8
|
+
},
|
|
9
|
+
"dependencies": {
|
|
10
|
+
"riffy": "^1.0.3",
|
|
11
|
+
"undici": "^5.0.0"
|
|
12
|
+
},
|
|
13
|
+
"keywords": [
|
|
14
|
+
"riffy",
|
|
15
|
+
"soundcloud",
|
|
16
|
+
"music",
|
|
17
|
+
"bot",
|
|
18
|
+
"discord",
|
|
19
|
+
"plugin",
|
|
20
|
+
"music-bot",
|
|
21
|
+
"lavalink"
|
|
22
|
+
],
|
|
23
|
+
"author": "ramkrishna-js",
|
|
24
|
+
"license": "MIT",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "https://github.com/ramkrishna-js/riffy-soundcloud.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": {
|
|
30
|
+
"url": "https://github.com/ramkrishna-js/riffy-soundcloud/issues"
|
|
31
|
+
},
|
|
32
|
+
"homepage": "https://github.com/ramkrishna-js/riffy-soundcloud#readme"
|
|
33
|
+
}
|
|
34
|
+
|