@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.
@@ -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
+ };
@@ -0,0 +1,5 @@
1
+ const doodstream = require("./provider/doodstream");
2
+
3
+ module.exports = {
4
+ doodstream
5
+ };