@nekosuneprojects/nekosunevrtools 1.1.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/.github/workflows/ci.yml +33 -0
- package/.github/workflows/npm-publish-github-packages.yml +35 -0
- package/.github/workflows/npm-publish.yml +34 -0
- package/README.md +201 -0
- package/bin/nekosunevrtools.js +13 -0
- package/package.json +31 -0
- package/src/cli.js +550 -0
- package/src/earnings.js +128 -0
- package/src/index.d.ts +174 -0
- package/src/index.js +25 -0
- package/src/shorturl/provider/adlinkfly-compatible.js +73 -0
- package/src/shorturl/provider/presets.js +37 -0
- package/src/shorturl/providers.js +11 -0
- package/src/upload/client.js +57 -0
- package/src/upload/provider/catbox.js +68 -0
- package/src/upload/provider/fileio.js +64 -0
- package/src/upload/provider/transfersh.js +58 -0
- package/src/upload/provider/upfiles.js +67 -0
- package/src/upload/providers.js +11 -0
- package/src/upload-client.js +1 -0
- package/src/utils/file.js +66 -0
- package/src/video/provider/doodstream.js +228 -0
- package/src/video/providers.js +5 -0
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { PassThrough } = require("stream");
|
|
4
|
+
|
|
5
|
+
function ensureReadableFile(filePath) {
|
|
6
|
+
if (!fs.existsSync(filePath)) {
|
|
7
|
+
throw new Error(`File does not exist: ${filePath}`);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
const stat = fs.statSync(filePath);
|
|
11
|
+
if (!stat.isFile()) {
|
|
12
|
+
throw new Error(`Path is not a file: ${filePath}`);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
return stat;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
function createProgressFilePart(filePath, onProgress) {
|
|
19
|
+
const stat = ensureReadableFile(filePath);
|
|
20
|
+
const totalBytes = stat.size;
|
|
21
|
+
const filename = path.basename(filePath);
|
|
22
|
+
const source = fs.createReadStream(filePath);
|
|
23
|
+
const tracked = new PassThrough();
|
|
24
|
+
let transferred = 0;
|
|
25
|
+
|
|
26
|
+
if (typeof onProgress === "function") {
|
|
27
|
+
onProgress({
|
|
28
|
+
phase: "start",
|
|
29
|
+
filename,
|
|
30
|
+
totalBytes,
|
|
31
|
+
bytesTransferred: 0,
|
|
32
|
+
percent: totalBytes === 0 ? 100 : 0
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
source.on("data", (chunk) => {
|
|
37
|
+
transferred += chunk.length;
|
|
38
|
+
if (typeof onProgress === "function") {
|
|
39
|
+
const percent = totalBytes === 0 ? 100 : Math.min(100, Math.round((transferred / totalBytes) * 100));
|
|
40
|
+
onProgress({
|
|
41
|
+
phase: "uploading",
|
|
42
|
+
filename,
|
|
43
|
+
totalBytes,
|
|
44
|
+
bytesTransferred: transferred,
|
|
45
|
+
percent
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
source.on("error", (error) => {
|
|
51
|
+
tracked.destroy(error);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
source.pipe(tracked);
|
|
55
|
+
|
|
56
|
+
return {
|
|
57
|
+
stream: tracked,
|
|
58
|
+
filename,
|
|
59
|
+
totalBytes
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
module.exports = {
|
|
64
|
+
ensureReadableFile,
|
|
65
|
+
createProgressFilePart
|
|
66
|
+
};
|
|
@@ -0,0 +1,228 @@
|
|
|
1
|
+
const FormData = require("form-data");
|
|
2
|
+
const { createProgressFilePart } = require("../../utils/file");
|
|
3
|
+
|
|
4
|
+
const DOOD_API_BASE = "https://doodapi.co";
|
|
5
|
+
|
|
6
|
+
async function upload(context) {
|
|
7
|
+
const { filePath, apiKey, http, onProgress } = context;
|
|
8
|
+
assertApiKey(apiKey);
|
|
9
|
+
|
|
10
|
+
const serverResponse = await http.get(`${DOOD_API_BASE}/api/upload/server`, {
|
|
11
|
+
params: { key: apiKey }
|
|
12
|
+
});
|
|
13
|
+
const serverData = serverResponse.data || {};
|
|
14
|
+
if (serverData.status !== 200 || !serverData.result) {
|
|
15
|
+
throw new Error(serverData.msg || "Failed to get DoodStream upload server.");
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
const filePart = createProgressFilePart(filePath, onProgress);
|
|
19
|
+
const form = new FormData();
|
|
20
|
+
form.append("api_key", apiKey);
|
|
21
|
+
form.append("file", filePart.stream, filePart.filename);
|
|
22
|
+
|
|
23
|
+
const uploadTarget = buildUploadTarget(serverData.result, apiKey);
|
|
24
|
+
const uploadResponse = await http.post(uploadTarget, form, {
|
|
25
|
+
headers: {
|
|
26
|
+
...form.getHeaders()
|
|
27
|
+
},
|
|
28
|
+
maxBodyLength: Infinity
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
const uploadData = uploadResponse.data || {};
|
|
32
|
+
if (uploadData.status !== 200 || !uploadData.result || !uploadData.result.length) {
|
|
33
|
+
throw new Error(uploadData.msg || "DoodStream upload failed.");
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const uploaded = uploadData.result[0];
|
|
37
|
+
const watchUrl = uploaded.protected_embed || uploaded.download_url || uploaded.url;
|
|
38
|
+
if (!watchUrl) {
|
|
39
|
+
throw new Error("DoodStream did not return a watch/download URL.");
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (typeof onProgress === "function") {
|
|
43
|
+
onProgress({
|
|
44
|
+
phase: "complete",
|
|
45
|
+
filename: filePart.filename,
|
|
46
|
+
totalBytes: filePart.totalBytes,
|
|
47
|
+
bytesTransferred: filePart.totalBytes,
|
|
48
|
+
percent: 100
|
|
49
|
+
});
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
provider: "doodstream",
|
|
54
|
+
success: true,
|
|
55
|
+
videoId: uploaded.filecode || null,
|
|
56
|
+
filecode: uploaded.filecode || null,
|
|
57
|
+
watchUrl,
|
|
58
|
+
raw: uploadData
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async function cloneFile(context) {
|
|
63
|
+
const { apiKey, fileCode, folderId, http } = context;
|
|
64
|
+
assertApiKey(apiKey);
|
|
65
|
+
if (!fileCode) {
|
|
66
|
+
throw new Error('Missing "fileCode" for doodstream clone.');
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const response = await http.get(`${DOOD_API_BASE}/api/file/clone`, {
|
|
70
|
+
params: {
|
|
71
|
+
key: apiKey,
|
|
72
|
+
file_code: fileCode,
|
|
73
|
+
fld_id: folderId || undefined
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
const body = response.data || {};
|
|
77
|
+
if (body.status !== 200) {
|
|
78
|
+
throw new Error(body.msg || "DoodStream clone failed.");
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
return {
|
|
82
|
+
provider: "doodstream",
|
|
83
|
+
success: true,
|
|
84
|
+
result: body.result || null,
|
|
85
|
+
raw: body
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
async function remoteUploadAdd(context) {
|
|
90
|
+
const { apiKey, uploadUrl, folderId, newTitle, http } = context;
|
|
91
|
+
assertApiKey(apiKey);
|
|
92
|
+
if (!uploadUrl) {
|
|
93
|
+
throw new Error('Missing "uploadUrl" for doodstream remote upload.');
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
const response = await http.get(`${DOOD_API_BASE}/api/upload/url`, {
|
|
97
|
+
params: {
|
|
98
|
+
key: apiKey,
|
|
99
|
+
url: uploadUrl,
|
|
100
|
+
fld_id: folderId || undefined,
|
|
101
|
+
new_title: newTitle || undefined
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
const body = response.data || {};
|
|
105
|
+
if (body.status !== 200) {
|
|
106
|
+
throw new Error(body.msg || "DoodStream remote upload add failed.");
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return {
|
|
110
|
+
provider: "doodstream",
|
|
111
|
+
success: true,
|
|
112
|
+
filecode: body.result && body.result.filecode ? body.result.filecode : null,
|
|
113
|
+
raw: body
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
async function remoteUploadList(context) {
|
|
118
|
+
const { apiKey, http } = context;
|
|
119
|
+
assertApiKey(apiKey);
|
|
120
|
+
|
|
121
|
+
const response = await http.get(`${DOOD_API_BASE}/api/urlupload/list`, {
|
|
122
|
+
params: { key: apiKey }
|
|
123
|
+
});
|
|
124
|
+
const body = response.data || {};
|
|
125
|
+
if (body.status !== 200) {
|
|
126
|
+
throw new Error(body.msg || "DoodStream remote upload list failed.");
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
return {
|
|
130
|
+
provider: "doodstream",
|
|
131
|
+
success: true,
|
|
132
|
+
items: Array.isArray(body.result) ? body.result : [],
|
|
133
|
+
raw: body
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
async function remoteUploadStatus(context) {
|
|
138
|
+
const { apiKey, fileCode, http } = context;
|
|
139
|
+
assertApiKey(apiKey);
|
|
140
|
+
if (!fileCode) {
|
|
141
|
+
throw new Error('Missing "fileCode" for doodstream remote upload status.');
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
const response = await http.get(`${DOOD_API_BASE}/api/urlupload/status`, {
|
|
145
|
+
params: {
|
|
146
|
+
key: apiKey,
|
|
147
|
+
file_code: fileCode
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
const body = response.data || {};
|
|
151
|
+
if (body.status !== 200) {
|
|
152
|
+
throw new Error(body.msg || "DoodStream remote upload status failed.");
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
return {
|
|
156
|
+
provider: "doodstream",
|
|
157
|
+
success: true,
|
|
158
|
+
items: Array.isArray(body.result) ? body.result : [],
|
|
159
|
+
raw: body
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
async function remoteUploadSlots(context) {
|
|
164
|
+
const { apiKey, http } = context;
|
|
165
|
+
assertApiKey(apiKey);
|
|
166
|
+
|
|
167
|
+
const response = await http.get(`${DOOD_API_BASE}/api/urlupload/slots`, {
|
|
168
|
+
params: { key: apiKey }
|
|
169
|
+
});
|
|
170
|
+
const body = response.data || {};
|
|
171
|
+
if (body.status !== 200) {
|
|
172
|
+
throw new Error(body.msg || "DoodStream remote upload slots failed.");
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
provider: "doodstream",
|
|
177
|
+
success: true,
|
|
178
|
+
totalSlots: body.total_slots || null,
|
|
179
|
+
usedSlots: body.used_slots || null,
|
|
180
|
+
raw: body
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
async function remoteUploadActions(context) {
|
|
185
|
+
const { apiKey, restartErrors, clearErrors, clearAll, deleteCode, http } = context;
|
|
186
|
+
assertApiKey(apiKey);
|
|
187
|
+
|
|
188
|
+
const response = await http.get(`${DOOD_API_BASE}/api/urlupload/actions`, {
|
|
189
|
+
params: {
|
|
190
|
+
key: apiKey,
|
|
191
|
+
restart_errors: restartErrors ? 1 : undefined,
|
|
192
|
+
clear_errors: clearErrors ? 1 : undefined,
|
|
193
|
+
clear_all: clearAll ? 1 : undefined,
|
|
194
|
+
delete_code: deleteCode || undefined
|
|
195
|
+
}
|
|
196
|
+
});
|
|
197
|
+
const body = response.data || {};
|
|
198
|
+
if (body.status !== 200) {
|
|
199
|
+
throw new Error(body.msg || "DoodStream remote upload action failed.");
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
return {
|
|
203
|
+
provider: "doodstream",
|
|
204
|
+
success: true,
|
|
205
|
+
raw: body
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function assertApiKey(apiKey) {
|
|
210
|
+
if (!apiKey) {
|
|
211
|
+
throw new Error('Missing apiKey for "doodstream".');
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
function buildUploadTarget(serverUrl, apiKey) {
|
|
216
|
+
const separator = serverUrl.includes("?") ? "&" : "?";
|
|
217
|
+
return `${serverUrl}${separator}${encodeURIComponent(apiKey)}`;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
module.exports = {
|
|
221
|
+
upload,
|
|
222
|
+
cloneFile,
|
|
223
|
+
remoteUploadAdd,
|
|
224
|
+
remoteUploadList,
|
|
225
|
+
remoteUploadStatus,
|
|
226
|
+
remoteUploadSlots,
|
|
227
|
+
remoteUploadActions
|
|
228
|
+
};
|