distube-invidious 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 +157 -0
- package/dist/index.d.ts +52 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +248 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +72 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/url-utils.d.ts +27 -0
- package/dist/url-utils.d.ts.map +1 -0
- package/dist/url-utils.js +143 -0
- package/dist/url-utils.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 techtimefor
|
|
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,157 @@
|
|
|
1
|
+
# DisTube Invidious Plugin
|
|
2
|
+
|
|
3
|
+
A [DisTube](https://github.com/skick1234/DisTube) extractor plugin that routes all YouTube URLs through an [Invidious](https://invidious.io/) instance for privacy-friendly music playback.
|
|
4
|
+
|
|
5
|
+
This is an ExtractorPlugin, find out more about it [here](https://github.com/skick1234/DisTube/wiki/Projects-Hub#extractorplugin).
|
|
6
|
+
|
|
7
|
+
## Features
|
|
8
|
+
|
|
9
|
+
- 🎵 Play YouTube videos through any Invidious instance
|
|
10
|
+
- 🔒 Privacy-friendly - no direct YouTube API calls
|
|
11
|
+
- 📝 Playlist support
|
|
12
|
+
- 🔍 Search functionality
|
|
13
|
+
- 🎼 Related songs recommendations
|
|
14
|
+
- ⚙️ Configurable timeout
|
|
15
|
+
- 🌐 Supports all YouTube URL formats (watch, shorts, live, embed, youtu.be, playlists)
|
|
16
|
+
|
|
17
|
+
## Installation
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
npm install distube-invidious
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
## Usage
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import { DisTube } from "distube";
|
|
27
|
+
import { InvidiousPlugin } from "distube-invidious";
|
|
28
|
+
|
|
29
|
+
const distube = new DisTube({
|
|
30
|
+
plugins: [
|
|
31
|
+
new InvidiousPlugin({
|
|
32
|
+
instance: "yewtu.be", // or any other Invidious instance
|
|
33
|
+
}),
|
|
34
|
+
],
|
|
35
|
+
});
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
### Basic Example
|
|
39
|
+
|
|
40
|
+
```typescript
|
|
41
|
+
import { DisTube } from "distube";
|
|
42
|
+
import { InvidiousPlugin } from "distube-invidious";
|
|
43
|
+
|
|
44
|
+
// Initialize DisTube with Invidious plugin
|
|
45
|
+
const distube = new DisTube({
|
|
46
|
+
plugins: [
|
|
47
|
+
new InvidiousPlugin({
|
|
48
|
+
instance: "yewtu.be",
|
|
49
|
+
timeout: 10000, // Optional: request timeout in milliseconds (default: 10000)
|
|
50
|
+
}),
|
|
51
|
+
],
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
// Play a YouTube video
|
|
55
|
+
distube.play(voiceChannel, "https://youtube.com/watch?v=dQw4w9WgXcQ");
|
|
56
|
+
|
|
57
|
+
// Play a playlist
|
|
58
|
+
distube.play(voiceChannel, "https://youtube.com/playlist?list=PLxyz123");
|
|
59
|
+
|
|
60
|
+
// Search for a song
|
|
61
|
+
distube.play(voiceChannel, "never gonna give you up");
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## Configuration Options
|
|
65
|
+
|
|
66
|
+
### `InvidiousPluginOptions`
|
|
67
|
+
|
|
68
|
+
| Option | Type | Required | Default | Description |
|
|
69
|
+
|--------|------|----------|---------|-------------|
|
|
70
|
+
| `instance` | `string` | Yes | - | Invidious instance URL (e.g., "yewtu.be", "https://yewtu.be", "http://localhost:8095") |
|
|
71
|
+
| `timeout` | `number` | No | `10000` | Request timeout in milliseconds |
|
|
72
|
+
|
|
73
|
+
### Public Invidious Instances
|
|
74
|
+
|
|
75
|
+
You can find a list of public Invidious instances at:
|
|
76
|
+
- https://docs.invidious.io/instances/
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
## Supported YouTube URLs
|
|
80
|
+
|
|
81
|
+
The plugin supports all YouTube URL formats:
|
|
82
|
+
|
|
83
|
+
- **Videos**: `youtube.com/watch?v=ID`
|
|
84
|
+
- **Short URLs**: `youtu.be/ID`
|
|
85
|
+
- **Shorts**: `youtube.com/shorts/ID`
|
|
86
|
+
- **Live**: `youtube.com/live/ID`
|
|
87
|
+
- **Embed**: `youtube.com/embed/ID`
|
|
88
|
+
- **Playlists**: `youtube.com/playlist?list=ID`
|
|
89
|
+
- **Channels**: `youtube.com/channel/UCxxxx`, `youtube.com/@handle`, `youtube.com/c/CustomName`, `youtube.com/user/username`
|
|
90
|
+
|
|
91
|
+
It also handles shared YouTube links with tracking parameters:
|
|
92
|
+
- `https://youtu.be/ID?si=xxx` ✅
|
|
93
|
+
|
|
94
|
+
## Advanced Usage
|
|
95
|
+
|
|
96
|
+
### Direct Playlist Resolution
|
|
97
|
+
|
|
98
|
+
```typescript
|
|
99
|
+
import { InvidiousPlugin } from "distube-invidious";
|
|
100
|
+
|
|
101
|
+
const plugin = new InvidiousPlugin({ instance: "yewtu.be" });
|
|
102
|
+
|
|
103
|
+
// Resolve a playlist directly
|
|
104
|
+
const playlist = await plugin.playlist(
|
|
105
|
+
"https://youtube.com/playlist?list=PLxyz123",
|
|
106
|
+
{}
|
|
107
|
+
);
|
|
108
|
+
|
|
109
|
+
console.log(`Playlist: ${playlist.name}`);
|
|
110
|
+
console.log(`Songs: ${playlist.songs.length}`);
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
### Stream URL Extraction
|
|
114
|
+
|
|
115
|
+
```typescript
|
|
116
|
+
// Get the audio stream URL for a song
|
|
117
|
+
const streamUrl = await plugin.getStreamURL(song);
|
|
118
|
+
console.log(`Stream URL: ${streamUrl}`);
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
### Related Songs
|
|
122
|
+
|
|
123
|
+
```typescript
|
|
124
|
+
// Get related songs for a video
|
|
125
|
+
const relatedSongs = await plugin.getRelatedSongs(song);
|
|
126
|
+
console.log(`Found ${relatedSongs.length} related songs`);
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
## API
|
|
130
|
+
|
|
131
|
+
### `InvidiousPlugin`
|
|
132
|
+
|
|
133
|
+
#### Methods
|
|
134
|
+
|
|
135
|
+
- **`validate(url: string): boolean`** - Checks if a URL is a valid YouTube URL
|
|
136
|
+
- **`resolve(url, options): Promise<Song \| Playlist>`** - Resolves a URL to a Song or Playlist
|
|
137
|
+
- **`searchSong(query, options): Promise<Song \| null>`** - Searches for a song
|
|
138
|
+
- **`getStreamURL(song): Promise<string>`** - Gets the audio stream URL
|
|
139
|
+
- **`getRelatedSongs(song): Promise<Song[]>`** - Gets related songs
|
|
140
|
+
- **`playlist(url, options): Promise<Playlist>`** - Resolves a playlist directly
|
|
141
|
+
|
|
142
|
+
## Requirements
|
|
143
|
+
|
|
144
|
+
- Node.js 16+
|
|
145
|
+
- DisTube 4.0.0 or 5.0.0+
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
MIT
|
|
150
|
+
|
|
151
|
+
## Contributing
|
|
152
|
+
|
|
153
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
|
154
|
+
|
|
155
|
+
## Disclaimer
|
|
156
|
+
|
|
157
|
+
This plugin is not affiliated with, endorsed by, or connected to YouTube, DisTube or Invidious. Also this plugin is an unofficial plugin to help enhance your DisTube experience!
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { ExtractorPlugin, Playlist, ResolveOptions, Song } from "distube";
|
|
2
|
+
import type { InvidiousPluginOptions } from "./types.js";
|
|
3
|
+
export declare class InvidiousPlugin extends ExtractorPlugin {
|
|
4
|
+
readonly instance: string;
|
|
5
|
+
private readonly timeout;
|
|
6
|
+
constructor(options: InvidiousPluginOptions);
|
|
7
|
+
/**
|
|
8
|
+
* Validates if URL is a YouTube URL.
|
|
9
|
+
* Calls stripQuery() first to remove tracking parameters.
|
|
10
|
+
*/
|
|
11
|
+
validate(url: string): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Resolves a URL to a Song or Playlist.
|
|
14
|
+
* Calls stripQuery() first to remove tracking parameters.
|
|
15
|
+
*/
|
|
16
|
+
resolve<T>(url: string, options: ResolveOptions<T>): Promise<Song<T> | Playlist<T>>;
|
|
17
|
+
/**
|
|
18
|
+
* Searches for a song and returns the first result.
|
|
19
|
+
*/
|
|
20
|
+
searchSong<T>(query: string, options: ResolveOptions<T>): Promise<Song<T> | null>;
|
|
21
|
+
/**
|
|
22
|
+
* Gets the stream URL for a song.
|
|
23
|
+
* Fetches fresh video data and extracts highest-quality audio stream.
|
|
24
|
+
*/
|
|
25
|
+
getStreamURL(song: Song): Promise<string>;
|
|
26
|
+
/**
|
|
27
|
+
* Gets related songs for a given song.
|
|
28
|
+
*/
|
|
29
|
+
getRelatedSongs(song: Song): Promise<Song[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Public method for direct playlist resolution.
|
|
32
|
+
*/
|
|
33
|
+
playlist<T>(url: string, options: ResolveOptions<T>): Promise<Playlist<T>>;
|
|
34
|
+
/**
|
|
35
|
+
* Wraps fetch with AbortController for timeout handling.
|
|
36
|
+
*/
|
|
37
|
+
private fetchWithTimeout;
|
|
38
|
+
/**
|
|
39
|
+
* Returns highest-resolution thumbnail URL.
|
|
40
|
+
*/
|
|
41
|
+
private getBestThumbnail;
|
|
42
|
+
/**
|
|
43
|
+
* Creates a Song object from Invidious video data.
|
|
44
|
+
*/
|
|
45
|
+
private createSong;
|
|
46
|
+
/**
|
|
47
|
+
* Creates a Song object from video data (for related videos).
|
|
48
|
+
*/
|
|
49
|
+
private createSongFromData;
|
|
50
|
+
}
|
|
51
|
+
export default InvidiousPlugin;
|
|
52
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EACf,QAAQ,EACR,cAAc,EACd,IAAI,EAEL,MAAM,SAAS,CAAC;AAEjB,OAAO,KAAK,EACV,sBAAsB,EAIvB,MAAM,YAAY,CAAC;AAWpB,qBAAa,eAAgB,SAAQ,eAAe;IAClD,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,sBAAsB;IAe3C;;;OAGG;IAEH,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IAI9B;;;OAGG;IAEG,OAAO,CAAC,CAAC,EACb,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,QAAQ,CAAC,CAAC,CAAC,CAAC;IAsBjC;;OAEG;IAEG,UAAU,CAAC,CAAC,EAChB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC;IAsB1B;;;OAGG;IAEG,YAAY,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC;IA2C/C;;OAEG;IAEG,eAAe,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,EAAE,CAAC;IAgBlD;;OAEG;IAEG,QAAQ,CAAC,CAAC,EACd,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GACzB,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC;IAsDvB;;OAEG;YAEW,gBAAgB;IA2B9B;;OAEG;IAEH,OAAO,CAAC,gBAAgB;IAcxB;;OAEG;IAEH,OAAO,CAAC,UAAU;IA4BlB;;OAEG;IAEH,OAAO,CAAC,kBAAkB;CAqB3B;AAED,eAAe,eAAe,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,248 @@
|
|
|
1
|
+
import { ExtractorPlugin, Playlist, Song, DisTubeError, } from "distube";
|
|
2
|
+
import fetch from "node-fetch";
|
|
3
|
+
import { stripQuery, isYouTubeUrl, extractVideoId, extractPlaylistId, } from "./url-utils.js";
|
|
4
|
+
// InvidiousPlugin Class
|
|
5
|
+
export class InvidiousPlugin extends ExtractorPlugin {
|
|
6
|
+
instance;
|
|
7
|
+
timeout;
|
|
8
|
+
constructor(options) {
|
|
9
|
+
super();
|
|
10
|
+
// Normalize instance:
|
|
11
|
+
// 1. Remove trailing slash
|
|
12
|
+
// 2. Prepend "https://" if missing
|
|
13
|
+
let normalized = options.instance.replace(/\/+$/, "");
|
|
14
|
+
if (!normalized.startsWith("http://") && !normalized.startsWith("https://")) {
|
|
15
|
+
normalized = "https://" + normalized;
|
|
16
|
+
}
|
|
17
|
+
this.instance = normalized;
|
|
18
|
+
this.timeout = options.timeout ?? 10000;
|
|
19
|
+
}
|
|
20
|
+
// Required ExtractorPlugin Methods
|
|
21
|
+
/**
|
|
22
|
+
* Validates if URL is a YouTube URL.
|
|
23
|
+
* Calls stripQuery() first to remove tracking parameters.
|
|
24
|
+
*/
|
|
25
|
+
validate(url) {
|
|
26
|
+
return isYouTubeUrl(url);
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Resolves a URL to a Song or Playlist.
|
|
30
|
+
* Calls stripQuery() first to remove tracking parameters.
|
|
31
|
+
*/
|
|
32
|
+
async resolve(url, options) {
|
|
33
|
+
const cleanUrl = stripQuery(url);
|
|
34
|
+
// Check if it's a playlist URL
|
|
35
|
+
if (cleanUrl.includes("list=") && !cleanUrl.includes("v=")) {
|
|
36
|
+
return this.playlist(url, options);
|
|
37
|
+
}
|
|
38
|
+
// Extract video ID
|
|
39
|
+
const videoId = extractVideoId(cleanUrl);
|
|
40
|
+
if (!videoId) {
|
|
41
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", "Invalid YouTube URL");
|
|
42
|
+
}
|
|
43
|
+
// Fetch video data from Invidious API
|
|
44
|
+
const apiUrl = `${this.instance}/api/v1/videos/${videoId}`;
|
|
45
|
+
const data = (await this.fetchWithTimeout(apiUrl));
|
|
46
|
+
// Convert to Song
|
|
47
|
+
return this.createSong(data, options);
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Searches for a song and returns the first result.
|
|
51
|
+
*/
|
|
52
|
+
async searchSong(query, options) {
|
|
53
|
+
const apiUrl = `${this.instance}/api/v1/search?q=${encodeURIComponent(query)}&type=video`;
|
|
54
|
+
const data = (await this.fetchWithTimeout(apiUrl));
|
|
55
|
+
if (!data || data.length === 0) {
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
const firstResult = data[0];
|
|
59
|
+
if (!firstResult.videoId) {
|
|
60
|
+
return null;
|
|
61
|
+
}
|
|
62
|
+
// Fetch full video data
|
|
63
|
+
const videoUrl = `${this.instance}/api/v1/videos/${firstResult.videoId}`;
|
|
64
|
+
const videoData = (await this.fetchWithTimeout(videoUrl));
|
|
65
|
+
return this.createSong(videoData, options);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Gets the stream URL for a song.
|
|
69
|
+
* Fetches fresh video data and extracts highest-quality audio stream.
|
|
70
|
+
*/
|
|
71
|
+
async getStreamURL(song) {
|
|
72
|
+
const apiUrl = `${this.instance}/api/v1/videos/${song.id}`;
|
|
73
|
+
const data = (await this.fetchWithTimeout(apiUrl));
|
|
74
|
+
// Priority 1: Audio-only from adaptiveFormats
|
|
75
|
+
// Check both 'type' and 'mimeType' fields as different instances may use either
|
|
76
|
+
if (data.adaptiveFormats && data.adaptiveFormats.length > 0) {
|
|
77
|
+
// First try to find opus audio
|
|
78
|
+
let bestAudio = data.adaptiveFormats.find((format) => {
|
|
79
|
+
const mimeType = format.mimeType || format.type || "";
|
|
80
|
+
return mimeType.includes("audio") && mimeType.includes("opus");
|
|
81
|
+
});
|
|
82
|
+
// If no opus, try AAC
|
|
83
|
+
if (!bestAudio) {
|
|
84
|
+
bestAudio = data.adaptiveFormats.find((format) => {
|
|
85
|
+
const mimeType = format.mimeType || format.type || "";
|
|
86
|
+
return mimeType.includes("audio") && mimeType.includes("mp4");
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
// If still no audio, find any audio format
|
|
90
|
+
if (!bestAudio) {
|
|
91
|
+
bestAudio = data.adaptiveFormats.find((format) => {
|
|
92
|
+
const mimeType = format.mimeType || format.type || "";
|
|
93
|
+
return mimeType.includes("audio");
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
if (bestAudio && bestAudio.url) {
|
|
97
|
+
return bestAudio.url;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
// Priority 2: Fallback to first entry in formatStreams
|
|
101
|
+
if (data.formatStreams && data.formatStreams.length > 0) {
|
|
102
|
+
return data.formatStreams[0].url;
|
|
103
|
+
}
|
|
104
|
+
// Priority 3: Throw error if no valid stream found
|
|
105
|
+
throw new DisTubeError("CANNOT_GET_STREAM_URL", "No playable stream found");
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Gets related songs for a given song.
|
|
109
|
+
*/
|
|
110
|
+
async getRelatedSongs(song) {
|
|
111
|
+
const apiUrl = `${this.instance}/api/v1/videos/${song.id}`;
|
|
112
|
+
const data = (await this.fetchWithTimeout(apiUrl));
|
|
113
|
+
if (!data.recommendedVideos || data.recommendedVideos.length === 0) {
|
|
114
|
+
return [];
|
|
115
|
+
}
|
|
116
|
+
// Return up to 10 related songs
|
|
117
|
+
return data.recommendedVideos.slice(0, 10).map((video) => this.createSongFromData(video));
|
|
118
|
+
}
|
|
119
|
+
// Playlist Resolution
|
|
120
|
+
/**
|
|
121
|
+
* Public method for direct playlist resolution.
|
|
122
|
+
*/
|
|
123
|
+
async playlist(url, options) {
|
|
124
|
+
const cleanUrl = stripQuery(url);
|
|
125
|
+
const playlistId = extractPlaylistId(cleanUrl);
|
|
126
|
+
if (!playlistId) {
|
|
127
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", "Invalid playlist URL");
|
|
128
|
+
}
|
|
129
|
+
const apiUrl = `${this.instance}/api/v1/playlists/${playlistId}`;
|
|
130
|
+
const data = (await this.fetchWithTimeout(apiUrl));
|
|
131
|
+
// Create Song objects from playlist videos
|
|
132
|
+
const songs = data.videos.map((video) => this.createSongFromData({
|
|
133
|
+
videoId: video.videoId,
|
|
134
|
+
title: video.title,
|
|
135
|
+
author: video.author,
|
|
136
|
+
authorId: data.authorId,
|
|
137
|
+
authorUrl: `/channel/${data.authorId}`,
|
|
138
|
+
lengthSeconds: video.lengthSeconds,
|
|
139
|
+
videoThumbnails: video.videoThumbnails.map((t) => ({
|
|
140
|
+
quality: "",
|
|
141
|
+
url: t.url,
|
|
142
|
+
width: t.width,
|
|
143
|
+
height: t.height,
|
|
144
|
+
})),
|
|
145
|
+
viewCount: 0,
|
|
146
|
+
likeCount: 0,
|
|
147
|
+
liveNow: false,
|
|
148
|
+
recommendedVideos: [],
|
|
149
|
+
formatStreams: [],
|
|
150
|
+
adaptiveFormats: [],
|
|
151
|
+
}));
|
|
152
|
+
// Create Playlist object
|
|
153
|
+
const playlist = new Playlist({
|
|
154
|
+
source: "youtube",
|
|
155
|
+
name: data.title,
|
|
156
|
+
id: data.playlistId,
|
|
157
|
+
url: `${this.instance}/playlist?list=${data.playlistId}`,
|
|
158
|
+
thumbnail: this.getBestThumbnail(data.videos[0]?.videoThumbnails || []),
|
|
159
|
+
songs,
|
|
160
|
+
}, options);
|
|
161
|
+
return playlist;
|
|
162
|
+
}
|
|
163
|
+
// Private Helper Methods
|
|
164
|
+
/**
|
|
165
|
+
* Wraps fetch with AbortController for timeout handling.
|
|
166
|
+
*/
|
|
167
|
+
async fetchWithTimeout(url) {
|
|
168
|
+
const controller = new AbortController();
|
|
169
|
+
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
|
|
170
|
+
try {
|
|
171
|
+
const response = await fetch(url, {
|
|
172
|
+
signal: controller.signal,
|
|
173
|
+
});
|
|
174
|
+
if (!response.ok) {
|
|
175
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", `HTTP ${response.status}: ${response.statusText}`);
|
|
176
|
+
}
|
|
177
|
+
return await response.json();
|
|
178
|
+
}
|
|
179
|
+
catch (error) {
|
|
180
|
+
if (error.name === "AbortError") {
|
|
181
|
+
throw new DisTubeError("CANNOT_RESOLVE_SONG", "Request timeout");
|
|
182
|
+
}
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
finally {
|
|
186
|
+
clearTimeout(timeoutId);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
/**
|
|
190
|
+
* Returns highest-resolution thumbnail URL.
|
|
191
|
+
*/
|
|
192
|
+
getBestThumbnail(thumbnails) {
|
|
193
|
+
if (!thumbnails || thumbnails.length === 0) {
|
|
194
|
+
return "";
|
|
195
|
+
}
|
|
196
|
+
// Sort by resolution (width * height) and return the highest
|
|
197
|
+
const sorted = [...thumbnails].sort((a, b) => b.width * b.height - a.width * a.height);
|
|
198
|
+
return sorted[0].url;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Creates a Song object from Invidious video data.
|
|
202
|
+
*/
|
|
203
|
+
createSong(data, options) {
|
|
204
|
+
const song = new Song({
|
|
205
|
+
plugin: this,
|
|
206
|
+
source: "youtube",
|
|
207
|
+
playFromSource: true,
|
|
208
|
+
id: data.videoId,
|
|
209
|
+
name: data.title,
|
|
210
|
+
url: `${this.instance}/watch?v=${data.videoId}`,
|
|
211
|
+
thumbnail: this.getBestThumbnail(data.videoThumbnails),
|
|
212
|
+
duration: data.lengthSeconds,
|
|
213
|
+
isLive: data.liveNow,
|
|
214
|
+
views: data.viewCount,
|
|
215
|
+
likes: data.likeCount,
|
|
216
|
+
uploader: {
|
|
217
|
+
name: data.author,
|
|
218
|
+
url: `${this.instance}${data.authorUrl}`,
|
|
219
|
+
},
|
|
220
|
+
}, options);
|
|
221
|
+
return song;
|
|
222
|
+
}
|
|
223
|
+
/**
|
|
224
|
+
* Creates a Song object from video data (for related videos).
|
|
225
|
+
*/
|
|
226
|
+
createSongFromData(data) {
|
|
227
|
+
const song = new Song({
|
|
228
|
+
plugin: this,
|
|
229
|
+
source: "youtube",
|
|
230
|
+
playFromSource: true,
|
|
231
|
+
id: data.videoId,
|
|
232
|
+
name: data.title,
|
|
233
|
+
url: `${this.instance}/watch?v=${data.videoId}`,
|
|
234
|
+
thumbnail: this.getBestThumbnail(data.videoThumbnails),
|
|
235
|
+
duration: data.lengthSeconds,
|
|
236
|
+
isLive: data.liveNow,
|
|
237
|
+
views: data.viewCount,
|
|
238
|
+
likes: data.likeCount,
|
|
239
|
+
uploader: {
|
|
240
|
+
name: data.author,
|
|
241
|
+
url: `${this.instance}/channel/${data.authorId}`,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
return song;
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
export default InvidiousPlugin;
|
|
248
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
export interface InvidiousPluginOptions {
|
|
2
|
+
instance: string;
|
|
3
|
+
timeout?: number;
|
|
4
|
+
}
|
|
5
|
+
export interface InvidiousVideoResponse {
|
|
6
|
+
videoId: string;
|
|
7
|
+
title: string;
|
|
8
|
+
videoThumbnails: Array<{
|
|
9
|
+
quality: string;
|
|
10
|
+
url: string;
|
|
11
|
+
width: number;
|
|
12
|
+
height: number;
|
|
13
|
+
}>;
|
|
14
|
+
lengthSeconds: number;
|
|
15
|
+
author: string;
|
|
16
|
+
authorId: string;
|
|
17
|
+
authorUrl: string;
|
|
18
|
+
viewCount: number;
|
|
19
|
+
likeCount: number;
|
|
20
|
+
liveNow: boolean;
|
|
21
|
+
recommendedVideos: InvidiousVideoResponse[];
|
|
22
|
+
formatStreams: Array<{
|
|
23
|
+
url: string;
|
|
24
|
+
type: string;
|
|
25
|
+
mimeType?: string;
|
|
26
|
+
quality: string;
|
|
27
|
+
}>;
|
|
28
|
+
adaptiveFormats: Array<{
|
|
29
|
+
url: string;
|
|
30
|
+
type: string;
|
|
31
|
+
mimeType?: string;
|
|
32
|
+
encoding?: string;
|
|
33
|
+
}>;
|
|
34
|
+
hlsUrl?: string;
|
|
35
|
+
dashUrl?: string;
|
|
36
|
+
}
|
|
37
|
+
export interface InvidiousPlaylistResponse {
|
|
38
|
+
title: string;
|
|
39
|
+
playlistId: string;
|
|
40
|
+
author: string;
|
|
41
|
+
authorId: string;
|
|
42
|
+
videoCount: number;
|
|
43
|
+
videos: Array<{
|
|
44
|
+
title: string;
|
|
45
|
+
videoId: string;
|
|
46
|
+
author: string;
|
|
47
|
+
lengthSeconds: number;
|
|
48
|
+
videoThumbnails: Array<{
|
|
49
|
+
url: string;
|
|
50
|
+
width: number;
|
|
51
|
+
height: number;
|
|
52
|
+
}>;
|
|
53
|
+
}>;
|
|
54
|
+
}
|
|
55
|
+
export interface InvidiousSearchResponse {
|
|
56
|
+
type: string;
|
|
57
|
+
title: string;
|
|
58
|
+
videoId?: string;
|
|
59
|
+
author: string;
|
|
60
|
+
videoThumbnails: Array<{
|
|
61
|
+
url: string;
|
|
62
|
+
width: number;
|
|
63
|
+
height: number;
|
|
64
|
+
}>;
|
|
65
|
+
lengthSeconds?: number;
|
|
66
|
+
}
|
|
67
|
+
export interface InvidiousChannelResponse {
|
|
68
|
+
author: string;
|
|
69
|
+
authorId: string;
|
|
70
|
+
latestVideos: InvidiousVideoResponse[];
|
|
71
|
+
}
|
|
72
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,MAAM,CAAC;IAChB,KAAK,EAAE,MAAM,CAAC;IACd,eAAe,EAAE,KAAK,CAAC;QACrB,OAAO,EAAE,MAAM,CAAC;QAChB,GAAG,EAAE,MAAM,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,MAAM,EAAE,MAAM,CAAC;KAChB,CAAC,CAAC;IACH,aAAa,EAAE,MAAM,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,CAAC;IACjB,iBAAiB,EAAE,sBAAsB,EAAE,CAAC;IAC5C,aAAa,EAAE,KAAK,CAAC;QACnB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;IACH,eAAe,EAAE,KAAK,CAAC;QACrB,GAAG,EAAE,MAAM,CAAC;QACZ,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;KACnB,CAAC,CAAC;IACH,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,yBAAyB;IACxC,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,KAAK,CAAC;QACZ,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;QAChB,MAAM,EAAE,MAAM,CAAC;QACf,aAAa,EAAE,MAAM,CAAC;QACtB,eAAe,EAAE,KAAK,CAAC;YAAE,GAAG,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAC;YAAC,MAAM,EAAE,MAAM,CAAA;SAAE,CAAC,CAAC;KACxE,CAAC,CAAC;CACJ;AAED,MAAM,WAAW,uBAAuB;IACtC,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,KAAK,CAAC;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAC;IACvE,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED,MAAM,WAAW,wBAAwB;IACvC,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,sBAAsB,EAAE,CAAC;CACxC"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,oDAAoD"}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Strips query parameters from URL (everything from "?" onward).
|
|
3
|
+
* Must be called FIRST in all URL parsing functions to handle shared
|
|
4
|
+
* YouTube links with tracking parameters (e.g., https://youtu.be/ID?si=xxx).
|
|
5
|
+
*/
|
|
6
|
+
export declare function stripQuery(url: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Tests if URL matches any YouTube URL pattern.
|
|
9
|
+
*/
|
|
10
|
+
export declare function isYouTubeUrl(url: string): boolean;
|
|
11
|
+
/**
|
|
12
|
+
* Extracts video ID from URL patterns.
|
|
13
|
+
*/
|
|
14
|
+
export declare function extractVideoId(url: string): string | null;
|
|
15
|
+
/**
|
|
16
|
+
* Extracts playlist ID using pattern: [?&]list=
|
|
17
|
+
*/
|
|
18
|
+
export declare function extractPlaylistId(url: string): string | null;
|
|
19
|
+
/**
|
|
20
|
+
* Extracts channel identifier from patterns.
|
|
21
|
+
*/
|
|
22
|
+
export declare function extractChannel(url: string): string | null;
|
|
23
|
+
/**
|
|
24
|
+
* Converts any YouTube URL to Invidious equivalent using normalized instance URL.
|
|
25
|
+
*/
|
|
26
|
+
export declare function toInvidious(url: string, instance: string): string;
|
|
27
|
+
//# sourceMappingURL=url-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-utils.d.ts","sourceRoot":"","sources":["../src/url-utils.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,UAAU,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAG9C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAejD;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAwBzD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAI5D;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAoBzD;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAqDjE"}
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
// URL Parser Helper Functions for YouTube/Invidious URLs
|
|
2
|
+
/**
|
|
3
|
+
* Strips query parameters from URL (everything from "?" onward).
|
|
4
|
+
* Must be called FIRST in all URL parsing functions to handle shared
|
|
5
|
+
* YouTube links with tracking parameters (e.g., https://youtu.be/ID?si=xxx).
|
|
6
|
+
*/
|
|
7
|
+
export function stripQuery(url) {
|
|
8
|
+
const q = url.indexOf("?");
|
|
9
|
+
return q === -1 ? url : url.substring(0, q);
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Tests if URL matches any YouTube URL pattern.
|
|
13
|
+
*/
|
|
14
|
+
export function isYouTubeUrl(url) {
|
|
15
|
+
const cleanUrl = stripQuery(url);
|
|
16
|
+
const patterns = [
|
|
17
|
+
/^https?:\/\/(www\.)?youtube\.com\/watch\?v=/,
|
|
18
|
+
/^https?:\/\/youtu\.be\//,
|
|
19
|
+
/^https?:\/\/(www\.)?youtube\.com\/shorts\//,
|
|
20
|
+
/^https?:\/\/(www\.)?youtube\.com\/live\//,
|
|
21
|
+
/^https?:\/\/(www\.)?youtube\.com\/embed\//,
|
|
22
|
+
/^https?:\/\/(www\.)?youtube\.com\/playlist/,
|
|
23
|
+
/^https?:\/\/(www\.)?youtube\.com\/channel\//,
|
|
24
|
+
/^https?:\/\/(www\.)?youtube\.com\/c\//,
|
|
25
|
+
/^https?:\/\/(www\.)?youtube\.com\/user\//,
|
|
26
|
+
/^https?:\/\/(www\.)?youtube\.com\/@/,
|
|
27
|
+
];
|
|
28
|
+
return patterns.some((pattern) => pattern.test(cleanUrl));
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Extracts video ID from URL patterns.
|
|
32
|
+
*/
|
|
33
|
+
export function extractVideoId(url) {
|
|
34
|
+
const cleanUrl = stripQuery(url);
|
|
35
|
+
// Standard watch URL: ?v=ID
|
|
36
|
+
const watchMatch = cleanUrl.match(/[?&]v=([^&]+)/);
|
|
37
|
+
if (watchMatch)
|
|
38
|
+
return watchMatch[1];
|
|
39
|
+
// Short URL: youtu.be/ID
|
|
40
|
+
const shortMatch = cleanUrl.match(/youtu\.be\/([^/?]+)/);
|
|
41
|
+
if (shortMatch)
|
|
42
|
+
return shortMatch[1];
|
|
43
|
+
// Shorts: /shorts/ID
|
|
44
|
+
const shortsMatch = cleanUrl.match(/youtube\.com\/shorts\/([^/?]+)/);
|
|
45
|
+
if (shortsMatch)
|
|
46
|
+
return shortsMatch[1];
|
|
47
|
+
// Live: /live/ID
|
|
48
|
+
const liveMatch = cleanUrl.match(/youtube\.com\/live\/([^/?]+)/);
|
|
49
|
+
if (liveMatch)
|
|
50
|
+
return liveMatch[1];
|
|
51
|
+
// Embed: /embed/ID
|
|
52
|
+
const embedMatch = cleanUrl.match(/youtube\.com\/embed\/([^/?]+)/);
|
|
53
|
+
if (embedMatch)
|
|
54
|
+
return embedMatch[1];
|
|
55
|
+
return null;
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Extracts playlist ID using pattern: [?&]list=
|
|
59
|
+
*/
|
|
60
|
+
export function extractPlaylistId(url) {
|
|
61
|
+
const cleanUrl = stripQuery(url);
|
|
62
|
+
const match = cleanUrl.match(/[?&]list=([^&]+)/);
|
|
63
|
+
return match ? match[1] : null;
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Extracts channel identifier from patterns.
|
|
67
|
+
*/
|
|
68
|
+
export function extractChannel(url) {
|
|
69
|
+
const cleanUrl = stripQuery(url);
|
|
70
|
+
// /channel/UCxxxx
|
|
71
|
+
const channelMatch = cleanUrl.match(/\/channel\/([^/?]+)/);
|
|
72
|
+
if (channelMatch)
|
|
73
|
+
return channelMatch[1];
|
|
74
|
+
// /c/CustomName
|
|
75
|
+
const customMatch = cleanUrl.match(/\/c\/([^/?]+)/);
|
|
76
|
+
if (customMatch)
|
|
77
|
+
return customMatch[1];
|
|
78
|
+
// /user/username
|
|
79
|
+
const userMatch = cleanUrl.match(/\/user\/([^/?]+)/);
|
|
80
|
+
if (userMatch)
|
|
81
|
+
return userMatch[1];
|
|
82
|
+
// /@handle
|
|
83
|
+
const handleMatch = cleanUrl.match(/\/@([^/?]+)/);
|
|
84
|
+
if (handleMatch)
|
|
85
|
+
return handleMatch[1];
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Converts any YouTube URL to Invidious equivalent using normalized instance URL.
|
|
90
|
+
*/
|
|
91
|
+
export function toInvidious(url, instance) {
|
|
92
|
+
const cleanUrl = stripQuery(url);
|
|
93
|
+
const patterns = [
|
|
94
|
+
{
|
|
95
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/watch\?v=([^&]+)/,
|
|
96
|
+
replace: `${instance}/watch?v=$2`,
|
|
97
|
+
},
|
|
98
|
+
{
|
|
99
|
+
regex: /^https?:\/\/youtu\.be\/([^/?]+)/,
|
|
100
|
+
replace: `${instance}/watch?v=$1`,
|
|
101
|
+
},
|
|
102
|
+
{
|
|
103
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/shorts\/([^/?]+)/,
|
|
104
|
+
replace: `${instance}/watch?v=$2`,
|
|
105
|
+
},
|
|
106
|
+
{
|
|
107
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/live\/([^/?]+)/,
|
|
108
|
+
replace: `${instance}/watch?v=$2`,
|
|
109
|
+
},
|
|
110
|
+
{
|
|
111
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/embed\/([^/?]+)/,
|
|
112
|
+
replace: `${instance}/watch?v=$2`,
|
|
113
|
+
},
|
|
114
|
+
{
|
|
115
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/playlist\?list=([^&]+)/,
|
|
116
|
+
replace: `${instance}/playlist?list=$2`,
|
|
117
|
+
},
|
|
118
|
+
{
|
|
119
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/channel\/([^/?]+)/,
|
|
120
|
+
replace: `${instance}/channel/$2`,
|
|
121
|
+
},
|
|
122
|
+
{
|
|
123
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/c\/([^/?]+)/,
|
|
124
|
+
replace: `${instance}/channel/$2`,
|
|
125
|
+
},
|
|
126
|
+
{
|
|
127
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/user\/([^/?]+)/,
|
|
128
|
+
replace: `${instance}/user/$2`,
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
regex: /^https?:\/\/(www\.)?youtube\.com\/@([^/?]+)/,
|
|
132
|
+
replace: `${instance}/@$2`,
|
|
133
|
+
},
|
|
134
|
+
];
|
|
135
|
+
for (const pattern of patterns) {
|
|
136
|
+
const match = cleanUrl.match(pattern.regex);
|
|
137
|
+
if (match) {
|
|
138
|
+
return pattern.replace;
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return url;
|
|
142
|
+
}
|
|
143
|
+
//# sourceMappingURL=url-utils.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"url-utils.js","sourceRoot":"","sources":["../src/url-utils.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "distube-invidious",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"author": "techtimefor",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "git+https://github.com/techtimefor/distube-invidious.git"
|
|
8
|
+
},
|
|
9
|
+
"description": "An unofficial Invidious extractor plugin for DisTube",
|
|
10
|
+
"type": "module",
|
|
11
|
+
"main": "./dist/index.js",
|
|
12
|
+
"types": "./dist/index.d.ts",
|
|
13
|
+
"exports": "./dist/index.js",
|
|
14
|
+
"files": [
|
|
15
|
+
"dist"
|
|
16
|
+
],
|
|
17
|
+
"directories": {
|
|
18
|
+
"lib": "src"
|
|
19
|
+
},
|
|
20
|
+
"scripts": {
|
|
21
|
+
"build": "tsc",
|
|
22
|
+
"typecheck": "tsc --noEmit",
|
|
23
|
+
"test": "npm run typecheck",
|
|
24
|
+
"prepack": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"distube",
|
|
28
|
+
"invidious",
|
|
29
|
+
"youtube",
|
|
30
|
+
"music",
|
|
31
|
+
"bot",
|
|
32
|
+
"plugin",
|
|
33
|
+
"discord",
|
|
34
|
+
"distube-invidious",
|
|
35
|
+
"distube-invidious-plugin",
|
|
36
|
+
"invidious-plugin"
|
|
37
|
+
],
|
|
38
|
+
"license": "MIT",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"distube": "^4.0.0 || ^5.0.0"
|
|
44
|
+
},
|
|
45
|
+
"dependencies": {
|
|
46
|
+
"node-fetch": "^3.3.2"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.0.0",
|
|
50
|
+
"typescript": "^5.0.0"
|
|
51
|
+
}
|
|
52
|
+
}
|