@fett/synology-api 0.0.1-beta.3 → 0.0.1-beta.6
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/README.md +7 -3
- package/bin/syno +6 -0
- package/lib/cjs/index.js +732 -0
- package/package.json +21 -10
- package/dist/cjs/index.js +0 -341
- package/dist/esm/constants.js +0 -4
- package/dist/esm/core.js +0 -102
- package/dist/esm/helpers.js +0 -80
- package/dist/esm/index.js +0 -3
- package/dist/esm/modules/Api/Auth.js +0 -43
- package/dist/esm/modules/Api/Info.js +0 -26
- package/dist/esm/modules/Api/index.js +0 -2
- package/dist/esm/modules/AudioStation/Song/index.js +0 -25
- package/dist/esm/modules/AudioStation/Song/types.js +0 -1
- package/dist/esm/modules/AudioStation/index.js +0 -5
- package/dist/esm/modules/index.js +0 -20
- package/dist/esm/types/API.js +0 -2
- package/dist/esm/types/index.js +0 -1
- package/dist/esm/utils.js +0 -14
- package/dist/types/constants.d.ts +0 -4
- package/dist/types/core.d.ts +0 -38
- package/dist/types/helpers.d.ts +0 -2
- package/dist/types/index.d.ts +0 -3
- package/dist/types/modules/Api/Auth.d.ts +0 -3
- package/dist/types/modules/Api/Info.d.ts +0 -2
- package/dist/types/modules/Api/index.d.ts +0 -2
- package/dist/types/modules/AudioStation/Song/index.d.ts +0 -5
- package/dist/types/modules/AudioStation/Song/types.d.ts +0 -18
- package/dist/types/modules/AudioStation/index.d.ts +0 -5
- package/dist/types/modules/index.d.ts +0 -5
- package/dist/types/types/API.d.ts +0 -9
- package/dist/types/types/index.d.ts +0 -1
- package/dist/types/utils.d.ts +0 -3
package/lib/cjs/index.js
ADDED
|
@@ -0,0 +1,732 @@
|
|
|
1
|
+
var __create = Object.create;
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __defProps = Object.defineProperties;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
|
|
6
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
7
|
+
var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
8
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
9
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
10
|
+
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
11
|
+
var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
|
|
12
|
+
var __spreadValues = (a, b) => {
|
|
13
|
+
for (var prop in b || (b = {}))
|
|
14
|
+
if (__hasOwnProp.call(b, prop))
|
|
15
|
+
__defNormalProp(a, prop, b[prop]);
|
|
16
|
+
if (__getOwnPropSymbols)
|
|
17
|
+
for (var prop of __getOwnPropSymbols(b)) {
|
|
18
|
+
if (__propIsEnum.call(b, prop))
|
|
19
|
+
__defNormalProp(a, prop, b[prop]);
|
|
20
|
+
}
|
|
21
|
+
return a;
|
|
22
|
+
};
|
|
23
|
+
var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
|
|
24
|
+
var __export = (target, all) => {
|
|
25
|
+
for (var name in all)
|
|
26
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
27
|
+
};
|
|
28
|
+
var __copyProps = (to, from, except, desc) => {
|
|
29
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
30
|
+
for (let key of __getOwnPropNames(from))
|
|
31
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
32
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
33
|
+
}
|
|
34
|
+
return to;
|
|
35
|
+
};
|
|
36
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
37
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
38
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
39
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
40
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
41
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
42
|
+
mod
|
|
43
|
+
));
|
|
44
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
45
|
+
var __async = (__this, __arguments, generator) => {
|
|
46
|
+
return new Promise((resolve, reject) => {
|
|
47
|
+
var fulfilled = (value) => {
|
|
48
|
+
try {
|
|
49
|
+
step(generator.next(value));
|
|
50
|
+
} catch (e) {
|
|
51
|
+
reject(e);
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
var rejected = (value) => {
|
|
55
|
+
try {
|
|
56
|
+
step(generator.throw(value));
|
|
57
|
+
} catch (e) {
|
|
58
|
+
reject(e);
|
|
59
|
+
}
|
|
60
|
+
};
|
|
61
|
+
var step = (x) => x.done ? resolve(x.value) : Promise.resolve(x.value).then(fulfilled, rejected);
|
|
62
|
+
step((generator = generator.apply(__this, __arguments)).next());
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/index.ts
|
|
67
|
+
var index_exports = {};
|
|
68
|
+
__export(index_exports, {
|
|
69
|
+
AudioStationApi: () => AudioStationApi,
|
|
70
|
+
FileStationApi: () => FileStationApi,
|
|
71
|
+
SynologyApi: () => SynologyApi,
|
|
72
|
+
SynologyApiInfo: () => SynologyApiInfo,
|
|
73
|
+
default: () => index_default,
|
|
74
|
+
loadCli: () => loadCli
|
|
75
|
+
});
|
|
76
|
+
module.exports = __toCommonJS(index_exports);
|
|
77
|
+
|
|
78
|
+
// src/core.ts
|
|
79
|
+
var import_axios4 = __toESM(require("axios"));
|
|
80
|
+
|
|
81
|
+
// src/types/apiInfo.ts
|
|
82
|
+
var SynologyApiInfo = /* @__PURE__ */ ((SynologyApiInfo2) => {
|
|
83
|
+
SynologyApiInfo2["Auth"] = "SYNO.API.Auth";
|
|
84
|
+
SynologyApiInfo2["Info"] = "SYNO.API.Info";
|
|
85
|
+
SynologyApiInfo2["OTP"] = "SYNO.API.OTP";
|
|
86
|
+
return SynologyApiInfo2;
|
|
87
|
+
})(SynologyApiInfo || {});
|
|
88
|
+
var AudioStationApi = /* @__PURE__ */ ((AudioStationApi2) => {
|
|
89
|
+
AudioStationApi2["Song"] = "SYNO.AudioStation.Song";
|
|
90
|
+
AudioStationApi2["Album"] = "SYNO.AudioStation.Album";
|
|
91
|
+
AudioStationApi2["Artist"] = "SYNO.AudioStation.Artist";
|
|
92
|
+
AudioStationApi2["Genre"] = "SYNO.AudioStation.Genre";
|
|
93
|
+
AudioStationApi2["Playlist"] = "SYNO.AudioStation.Playlist";
|
|
94
|
+
AudioStationApi2["Folder"] = "SYNO.AudioStation.Folder";
|
|
95
|
+
AudioStationApi2["Cover"] = "SYNO.AudioStation.Cover";
|
|
96
|
+
AudioStationApi2["Download"] = "SYNO.AudioStation.Download";
|
|
97
|
+
AudioStationApi2["Info"] = "SYNO.AudioStation.Info";
|
|
98
|
+
AudioStationApi2["Lyrics"] = "SYNO.AudioStation.Lyrics";
|
|
99
|
+
AudioStationApi2["LyricsSearch"] = "SYNO.AudioStation.LyricsSearch";
|
|
100
|
+
AudioStationApi2["Radio"] = "SYNO.AudioStation.Radio";
|
|
101
|
+
AudioStationApi2["Stream"] = "SYNO.AudioStation.Stream";
|
|
102
|
+
AudioStationApi2["Tag"] = "SYNO.AudioStation.Tag";
|
|
103
|
+
return AudioStationApi2;
|
|
104
|
+
})(AudioStationApi || {});
|
|
105
|
+
var FileStationApi = /* @__PURE__ */ ((FileStationApi2) => {
|
|
106
|
+
FileStationApi2["File"] = "SYNO.FileStation.File";
|
|
107
|
+
FileStationApi2["Info"] = "SYNO.FileStation.Info";
|
|
108
|
+
FileStationApi2["List"] = "SYNO.FileStation.List";
|
|
109
|
+
FileStationApi2["Quota"] = "SYNO.FileStation.Quota";
|
|
110
|
+
FileStationApi2["Share"] = "SYNO.FileStation.Share";
|
|
111
|
+
FileStationApi2["Thumb"] = "SYNO.FileStation.Thumb";
|
|
112
|
+
FileStationApi2["Upload"] = "SYNO.FileStation.Upload";
|
|
113
|
+
return FileStationApi2;
|
|
114
|
+
})(FileStationApi || {});
|
|
115
|
+
|
|
116
|
+
// src/modules/AudioStation/Song.ts
|
|
117
|
+
function getSongList(params) {
|
|
118
|
+
return __async(this, null, function* () {
|
|
119
|
+
const res = yield this.run("SYNO.AudioStation.Song" /* Song */, {
|
|
120
|
+
params: __spreadValues({
|
|
121
|
+
method: "list",
|
|
122
|
+
library: "all"
|
|
123
|
+
}, params)
|
|
124
|
+
});
|
|
125
|
+
return res.data;
|
|
126
|
+
});
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
// src/modules/AudioStation/index.ts
|
|
130
|
+
var METHODS = {
|
|
131
|
+
getSongList
|
|
132
|
+
};
|
|
133
|
+
var SPELLING_KEY = "AudioStation";
|
|
134
|
+
var SIMPLIFY_KEY = "as";
|
|
135
|
+
|
|
136
|
+
// src/modules/FileStation/Info.ts
|
|
137
|
+
function getInfo() {
|
|
138
|
+
return __async(this, null, function* () {
|
|
139
|
+
const res = yield this.run("SYNO.FileStation.Info" /* Info */, {
|
|
140
|
+
params: {
|
|
141
|
+
method: "get"
|
|
142
|
+
}
|
|
143
|
+
});
|
|
144
|
+
return res.data;
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
// src/utils.ts
|
|
149
|
+
function isHttpUrl(url) {
|
|
150
|
+
return /^https?:\/\//.test(url);
|
|
151
|
+
}
|
|
152
|
+
function isUndfined(value) {
|
|
153
|
+
return value === void 0;
|
|
154
|
+
}
|
|
155
|
+
function getApiKey(apiName) {
|
|
156
|
+
return apiName.split(".")[1];
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// src/modules/FileStation/List.ts
|
|
160
|
+
function getFileList() {
|
|
161
|
+
return __async(this, arguments, function* (params = {}) {
|
|
162
|
+
const { additional = ["real_path", "size", "owner", "time"], filetype = "all" } = params;
|
|
163
|
+
if (isUndfined(params.folder_path)) {
|
|
164
|
+
throw new Error("folder_path is required");
|
|
165
|
+
}
|
|
166
|
+
const res = yield this.run("SYNO.FileStation.List" /* List */, {
|
|
167
|
+
params: __spreadValues({
|
|
168
|
+
method: "list",
|
|
169
|
+
additional: JSON.stringify(additional),
|
|
170
|
+
filetype,
|
|
171
|
+
folder_path: params.folder_path
|
|
172
|
+
}, params)
|
|
173
|
+
});
|
|
174
|
+
return res.data;
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
function getFileListShare() {
|
|
178
|
+
return __async(this, arguments, function* (params = {}) {
|
|
179
|
+
const { additional = ["real_path", "size", "owner", "time"], onlywritable = false } = params;
|
|
180
|
+
const res = yield this.run("SYNO.FileStation.List" /* List */, {
|
|
181
|
+
params: __spreadValues({
|
|
182
|
+
method: "list_share",
|
|
183
|
+
additional: JSON.stringify(additional),
|
|
184
|
+
onlywritable
|
|
185
|
+
}, params)
|
|
186
|
+
});
|
|
187
|
+
return res.data;
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// src/modules/FileStation/index.ts
|
|
192
|
+
var METHODS2 = {
|
|
193
|
+
getInfo,
|
|
194
|
+
getFileList,
|
|
195
|
+
getFileListShare
|
|
196
|
+
};
|
|
197
|
+
var SPELLING_KEY2 = "FileStation";
|
|
198
|
+
var SIMPLIFY_KEY2 = "fs";
|
|
199
|
+
|
|
200
|
+
// src/modules/index.ts
|
|
201
|
+
var SynologyApiKeys = {
|
|
202
|
+
FileStation: SPELLING_KEY2,
|
|
203
|
+
fs: SIMPLIFY_KEY2,
|
|
204
|
+
AudioStation: SPELLING_KEY,
|
|
205
|
+
as: SIMPLIFY_KEY
|
|
206
|
+
};
|
|
207
|
+
SPELLING_KEY, SIMPLIFY_KEY, SPELLING_KEY2, SIMPLIFY_KEY2;
|
|
208
|
+
var BaseSynologyApi = class {
|
|
209
|
+
constructor() {
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
function methodsBundler(instance, methods) {
|
|
213
|
+
const output = {};
|
|
214
|
+
for (const key in methods) {
|
|
215
|
+
output[key] = methods[key].bind(instance);
|
|
216
|
+
}
|
|
217
|
+
return output;
|
|
218
|
+
}
|
|
219
|
+
Object.defineProperties(BaseSynologyApi.prototype, {
|
|
220
|
+
// FileStation
|
|
221
|
+
[SynologyApiKeys.FileStation]: {
|
|
222
|
+
get() {
|
|
223
|
+
return methodsBundler(this, METHODS2);
|
|
224
|
+
}
|
|
225
|
+
},
|
|
226
|
+
[SynologyApiKeys.fs]: {
|
|
227
|
+
get() {
|
|
228
|
+
return methodsBundler(this, METHODS2);
|
|
229
|
+
}
|
|
230
|
+
},
|
|
231
|
+
// AudioStation
|
|
232
|
+
[SynologyApiKeys.AudioStation]: {
|
|
233
|
+
get() {
|
|
234
|
+
return methodsBundler(this, METHODS);
|
|
235
|
+
}
|
|
236
|
+
},
|
|
237
|
+
[SynologyApiKeys.as]: {
|
|
238
|
+
get() {
|
|
239
|
+
return methodsBundler(this, METHODS);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
// src/helpers.ts
|
|
245
|
+
var import_axios = __toESM(require("axios"));
|
|
246
|
+
|
|
247
|
+
// src/constants.ts
|
|
248
|
+
var GLOBAL_QUICK_CONNECT_URL = "https://global.quickconnect.cn/Serv.php";
|
|
249
|
+
var QUICK_CONNECT_PINGPANG_API = "/webman/pingpong.cgi?action=cors&quickconnect=true";
|
|
250
|
+
|
|
251
|
+
// src/helpers.ts
|
|
252
|
+
var getServersFromServerInfo = (serverInfo) => __async(null, null, function* () {
|
|
253
|
+
var _a, _b, _c, _d, _e, _f;
|
|
254
|
+
if ((_a = serverInfo == null ? void 0 : serverInfo.service) == null ? void 0 : _a.relay_ip) {
|
|
255
|
+
const server = `http://${serverInfo.service.relay_ip}:${serverInfo.service.relay_port}`;
|
|
256
|
+
const res = yield pingpang(server);
|
|
257
|
+
if (res) {
|
|
258
|
+
return server;
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
if ((_c = (_b = serverInfo == null ? void 0 : serverInfo.server) == null ? void 0 : _b.external) == null ? void 0 : _c.ip) {
|
|
262
|
+
const server = `http://${serverInfo.server.external.ip}:${serverInfo.service.port}`;
|
|
263
|
+
if (yield pingpang(server)) {
|
|
264
|
+
return server;
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
if ((_e = (_d = serverInfo == null ? void 0 : serverInfo.server) == null ? void 0 : _d.interface) == null ? void 0 : _e[0]) {
|
|
268
|
+
const server = `http://${(_f = serverInfo.server.interface) == null ? void 0 : _f[0].ip}:${serverInfo.service.port}`;
|
|
269
|
+
if (yield pingpang(server)) {
|
|
270
|
+
return server;
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
});
|
|
274
|
+
var getServerInfo = (quickConnectId) => __async(null, null, function* () {
|
|
275
|
+
var _a, _b, _c, _d;
|
|
276
|
+
const params = {
|
|
277
|
+
version: 1,
|
|
278
|
+
id: "dsm",
|
|
279
|
+
serverID: quickConnectId,
|
|
280
|
+
get_ca_fingerprints: true,
|
|
281
|
+
command: "get_server_info"
|
|
282
|
+
};
|
|
283
|
+
const serverInfo = yield import_axios.default.post(GLOBAL_QUICK_CONNECT_URL, params);
|
|
284
|
+
if (!((_b = (_a = serverInfo.data) == null ? void 0 : _a.service) == null ? void 0 : _b.relay_ip) && !((_d = (_c = serverInfo.data) == null ? void 0 : _c.service) == null ? void 0 : _d.relay_port)) {
|
|
285
|
+
const relayRequestParams = {
|
|
286
|
+
version: 1,
|
|
287
|
+
id: "dsm",
|
|
288
|
+
serverID: quickConnectId,
|
|
289
|
+
platform: "web",
|
|
290
|
+
command: "request_tunnel"
|
|
291
|
+
};
|
|
292
|
+
const result = yield import_axios.default.post(
|
|
293
|
+
`https://${serverInfo.data.env.control_host}/Serv.php`,
|
|
294
|
+
relayRequestParams
|
|
295
|
+
);
|
|
296
|
+
return getServersFromServerInfo(result.data);
|
|
297
|
+
} else {
|
|
298
|
+
return getServersFromServerInfo(serverInfo.data);
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
var pingpang = (server) => __async(null, null, function* () {
|
|
302
|
+
try {
|
|
303
|
+
const result = yield import_axios.default.get(`${server}/${QUICK_CONNECT_PINGPANG_API}`, {
|
|
304
|
+
timeout: 3e3
|
|
305
|
+
});
|
|
306
|
+
if (result.data.success) {
|
|
307
|
+
return true;
|
|
308
|
+
} else {
|
|
309
|
+
return false;
|
|
310
|
+
}
|
|
311
|
+
} catch (_err) {
|
|
312
|
+
return false;
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
// src/modules/Api/Auth.ts
|
|
317
|
+
var import_axios2 = __toESM(require("axios"));
|
|
318
|
+
function login(core) {
|
|
319
|
+
return __async(this, null, function* () {
|
|
320
|
+
const params = {
|
|
321
|
+
api: "SYNO.API.Auth" /* Auth */,
|
|
322
|
+
version: 6,
|
|
323
|
+
method: "login",
|
|
324
|
+
account: core.username,
|
|
325
|
+
passwd: core.password,
|
|
326
|
+
format: "sid"
|
|
327
|
+
};
|
|
328
|
+
const url = `${core.baseUrl}entry.cgi`;
|
|
329
|
+
const result = yield import_axios2.default.get(url, { params });
|
|
330
|
+
if (!result.data.success) {
|
|
331
|
+
throw new Error(result.data.error.message);
|
|
332
|
+
}
|
|
333
|
+
return result.data;
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
function logout(core) {
|
|
337
|
+
return __async(this, null, function* () {
|
|
338
|
+
const params = {
|
|
339
|
+
api: "SYNO.API.Auth" /* Auth */,
|
|
340
|
+
version: 6,
|
|
341
|
+
method: "logout"
|
|
342
|
+
};
|
|
343
|
+
const url = `${core.baseUrl}entry.cgi`;
|
|
344
|
+
const result = yield import_axios2.default.get(url, { params });
|
|
345
|
+
if (!result.data.success) {
|
|
346
|
+
throw new Error(result.data.error.message);
|
|
347
|
+
}
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// src/modules/Api/Info.ts
|
|
352
|
+
var import_axios3 = __toESM(require("axios"));
|
|
353
|
+
function getApiInfo(core) {
|
|
354
|
+
return __async(this, null, function* () {
|
|
355
|
+
const params = {
|
|
356
|
+
api: "SYNO.API.Info" /* Info */,
|
|
357
|
+
version: 1,
|
|
358
|
+
method: "query"
|
|
359
|
+
};
|
|
360
|
+
const url = `${core.baseUrl}entry.cgi`;
|
|
361
|
+
const result = yield import_axios3.default.get(url, { params });
|
|
362
|
+
if (!result.data.success) {
|
|
363
|
+
throw new Error(result.data.error.message);
|
|
364
|
+
}
|
|
365
|
+
return result.data;
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/errorcodes.ts
|
|
370
|
+
var CODE_SUCCESS = 0;
|
|
371
|
+
var CODE_UNKNOWN = 9999;
|
|
372
|
+
var SYNOLOGY_ERROR_CODES = {
|
|
373
|
+
[SynologyApiKeys.FileStation]: {
|
|
374
|
+
400: "Invalid parameter of file operation",
|
|
375
|
+
401: "Unknown error of file operation",
|
|
376
|
+
402: "System is too busy",
|
|
377
|
+
403: "Invalid user does this file operation",
|
|
378
|
+
404: "Invalid group does this file operation",
|
|
379
|
+
405: "Invalid user and group does this file operation",
|
|
380
|
+
406: "Can't get user/group information from the account server",
|
|
381
|
+
407: "Operation not permitted",
|
|
382
|
+
408: "No such file or directory",
|
|
383
|
+
409: "Non-supported file system",
|
|
384
|
+
410: "Failed to connect internet-based file system (e.g., CIFS)",
|
|
385
|
+
411: "Read-only file system",
|
|
386
|
+
412: "Filename too long in the non-encrypted file system",
|
|
387
|
+
413: "Filename too long in the encrypted file system",
|
|
388
|
+
414: "File already exists",
|
|
389
|
+
415: "Disk quota exceeded",
|
|
390
|
+
416: "No space left on device",
|
|
391
|
+
417: "Input/output error",
|
|
392
|
+
418: "Illegal name or path",
|
|
393
|
+
419: "Illegal file name",
|
|
394
|
+
420: "Illegal file name on FAT file system",
|
|
395
|
+
421: "Device or resource busy",
|
|
396
|
+
599: "No such task of the file operation"
|
|
397
|
+
},
|
|
398
|
+
[SynologyApiKeys.AudioStation]: {},
|
|
399
|
+
COMMON_CODES: {
|
|
400
|
+
[CODE_SUCCESS]: "Success",
|
|
401
|
+
100: "Unknown error",
|
|
402
|
+
101: "No parameter of API, method or version",
|
|
403
|
+
102: "The requested API does not exist",
|
|
404
|
+
103: "The requested method does not exist",
|
|
405
|
+
104: "The requested version does not support the functionality",
|
|
406
|
+
105: "The logged in session does not have permission",
|
|
407
|
+
106: "Session timeout",
|
|
408
|
+
107: "Session interrupted by duplicated login",
|
|
409
|
+
108: "Failed to upload the file",
|
|
410
|
+
109: "The network connection is unstable or the system is busy",
|
|
411
|
+
110: "The network connection is unstable or the system is busy",
|
|
412
|
+
111: "The network connection is unstable or the system is busy",
|
|
413
|
+
112: "Preserve for other purpose",
|
|
414
|
+
113: "Preserve for other purpose",
|
|
415
|
+
114: "Lost parameters for this API",
|
|
416
|
+
115: "Not allowed to upload a file",
|
|
417
|
+
116: "Not allowed to perform for a demo site",
|
|
418
|
+
117: "The network connection is unstable or the system is busy",
|
|
419
|
+
118: "The network connection is unstable or the system is busy",
|
|
420
|
+
119: "Invalid session / SID not found.",
|
|
421
|
+
// # 120-149 Preserve for other purpose
|
|
422
|
+
120: "Preserve for other purpose",
|
|
423
|
+
121: "Preserve for other purpose",
|
|
424
|
+
122: "Preserve for other purpose",
|
|
425
|
+
123: "Preserve for other purpose",
|
|
426
|
+
124: "Preserve for other purpose",
|
|
427
|
+
125: "Preserve for other purpose",
|
|
428
|
+
126: "Preserve for other purpose",
|
|
429
|
+
127: "Preserve for other purpose",
|
|
430
|
+
128: "Preserve for other purpose",
|
|
431
|
+
129: "Preserve for other purpose",
|
|
432
|
+
130: "Preserve for other purpose",
|
|
433
|
+
131: "Preserve for other purpose",
|
|
434
|
+
132: "Preserve for other purpose",
|
|
435
|
+
133: "Preserve for other purpose",
|
|
436
|
+
134: "Preserve for other purpose",
|
|
437
|
+
135: "Preserve for other purpose",
|
|
438
|
+
136: "Preserve for other purpose",
|
|
439
|
+
137: "Preserve for other purpose",
|
|
440
|
+
138: "Preserve for other purpose",
|
|
441
|
+
139: "Preserve for other purpose",
|
|
442
|
+
140: "Preserve for other purpose",
|
|
443
|
+
141: "Preserve for other purpose",
|
|
444
|
+
142: "Preserve for other purpose",
|
|
445
|
+
143: "Preserve for other purpose",
|
|
446
|
+
144: "Preserve for other purpose",
|
|
447
|
+
145: "Preserve for other purpose",
|
|
448
|
+
146: "Preserve for other purpose",
|
|
449
|
+
147: "Preserve for other purpose",
|
|
450
|
+
148: "Preserve for other purpose",
|
|
451
|
+
149: "Preserve for other purpose",
|
|
452
|
+
150: "Request source IP does not match the login IP",
|
|
453
|
+
160: "Insufficient application privilege",
|
|
454
|
+
[CODE_UNKNOWN]: "Unknown error"
|
|
455
|
+
}
|
|
456
|
+
};
|
|
457
|
+
var resWithErrorCode = (apiKey, res) => {
|
|
458
|
+
var _a, _b;
|
|
459
|
+
const errorCodes = SYNOLOGY_ERROR_CODES[apiKey];
|
|
460
|
+
const code = (_a = res == null ? void 0 : res.error) == null ? void 0 : _a.code;
|
|
461
|
+
if (isUndfined(code)) return res;
|
|
462
|
+
return __spreadProps(__spreadValues({}, res), {
|
|
463
|
+
error: __spreadProps(__spreadValues({}, res.error), {
|
|
464
|
+
message: ((_b = res == null ? void 0 : res.error) == null ? void 0 : _b.message) || (errorCodes == null ? void 0 : errorCodes[code]) || "Unknown error"
|
|
465
|
+
})
|
|
466
|
+
});
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// src/core.ts
|
|
470
|
+
var SynologyApi = class extends BaseSynologyApi {
|
|
471
|
+
constructor(options) {
|
|
472
|
+
super();
|
|
473
|
+
this.isConnecting = false;
|
|
474
|
+
this.authInfo = null;
|
|
475
|
+
this.apiInfo = {};
|
|
476
|
+
this.server = options.server;
|
|
477
|
+
this.username = options.username;
|
|
478
|
+
this.password = options.password;
|
|
479
|
+
this.baseUrl = `${this.server}/webapi/`;
|
|
480
|
+
}
|
|
481
|
+
connect() {
|
|
482
|
+
return __async(this, null, function* () {
|
|
483
|
+
if (!isHttpUrl(this.server)) {
|
|
484
|
+
this.server = yield getServerInfo(this.server);
|
|
485
|
+
this.baseUrl = `${this.server}/webapi/`;
|
|
486
|
+
}
|
|
487
|
+
try {
|
|
488
|
+
const result = yield login(this);
|
|
489
|
+
this.authInfo = result.data;
|
|
490
|
+
this.isConnecting = true;
|
|
491
|
+
yield this._getApiInfo();
|
|
492
|
+
return true;
|
|
493
|
+
} catch (err) {
|
|
494
|
+
console.error(err);
|
|
495
|
+
return false;
|
|
496
|
+
}
|
|
497
|
+
});
|
|
498
|
+
}
|
|
499
|
+
disconnect() {
|
|
500
|
+
return __async(this, null, function* () {
|
|
501
|
+
try {
|
|
502
|
+
yield logout(this);
|
|
503
|
+
this.authInfo = null;
|
|
504
|
+
this.apiInfo = {};
|
|
505
|
+
this.isConnecting = false;
|
|
506
|
+
return true;
|
|
507
|
+
} catch (err) {
|
|
508
|
+
console.error(err);
|
|
509
|
+
return false;
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
}
|
|
513
|
+
_getApiInfo() {
|
|
514
|
+
return __async(this, null, function* () {
|
|
515
|
+
try {
|
|
516
|
+
const result = yield getApiInfo(this);
|
|
517
|
+
this.apiInfo = result.data;
|
|
518
|
+
} catch (err) {
|
|
519
|
+
console.error(err);
|
|
520
|
+
}
|
|
521
|
+
});
|
|
522
|
+
}
|
|
523
|
+
hasApi(apiName) {
|
|
524
|
+
if (!this.isConnecting) {
|
|
525
|
+
throw new Error("Not connected");
|
|
526
|
+
}
|
|
527
|
+
return Object.prototype.hasOwnProperty.call(this.apiInfo, apiName);
|
|
528
|
+
}
|
|
529
|
+
run(apiName, options) {
|
|
530
|
+
return __async(this, null, function* () {
|
|
531
|
+
if (!this.isConnecting) {
|
|
532
|
+
const res = yield this.connect();
|
|
533
|
+
if (!res) {
|
|
534
|
+
throw new Error("Not connected");
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (!this.hasApi(apiName)) {
|
|
538
|
+
throw new Error(`${apiName} not found`);
|
|
539
|
+
}
|
|
540
|
+
const { method = "get", params, data, headers } = options;
|
|
541
|
+
const api = this.apiInfo[apiName];
|
|
542
|
+
const url = `${this.baseUrl}${api.path}`;
|
|
543
|
+
const externalParams = __spreadValues({
|
|
544
|
+
api: apiName,
|
|
545
|
+
version: api.maxVersion,
|
|
546
|
+
_sid: this.authInfo.sid
|
|
547
|
+
}, params);
|
|
548
|
+
let result = null;
|
|
549
|
+
if (method === "get") {
|
|
550
|
+
result = yield import_axios4.default.get(url, { params: externalParams, data, headers });
|
|
551
|
+
}
|
|
552
|
+
if (method === "post") {
|
|
553
|
+
result = yield import_axios4.default.post(url, { params: externalParams, data, headers });
|
|
554
|
+
}
|
|
555
|
+
const apiKey = getApiKey(apiName);
|
|
556
|
+
if (!isUndfined(apiKey)) {
|
|
557
|
+
result.data = resWithErrorCode(apiKey, result.data);
|
|
558
|
+
}
|
|
559
|
+
return result;
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
};
|
|
563
|
+
|
|
564
|
+
// src/cli/index.ts
|
|
565
|
+
var import_fs_extra2 = __toESM(require("fs-extra"));
|
|
566
|
+
var import_path2 = __toESM(require("path"));
|
|
567
|
+
var import_commander3 = require("commander");
|
|
568
|
+
|
|
569
|
+
// src/cli/config.ts
|
|
570
|
+
var import_fs_extra = __toESM(require("fs-extra"));
|
|
571
|
+
var import_path = __toESM(require("path"));
|
|
572
|
+
var import_os = __toESM(require("os"));
|
|
573
|
+
var import_commander = require("commander");
|
|
574
|
+
var import_chalk2 = __toESM(require("chalk"));
|
|
575
|
+
|
|
576
|
+
// src/cli/helper.ts
|
|
577
|
+
var import_chalk = __toESM(require("chalk"));
|
|
578
|
+
function printMessages(messages) {
|
|
579
|
+
console.log(messages.join("\n"));
|
|
580
|
+
}
|
|
581
|
+
function isLowerCaseEqual(str1, str2) {
|
|
582
|
+
if (str1 && str2) {
|
|
583
|
+
return str1.toLowerCase() === str2.toLowerCase();
|
|
584
|
+
}
|
|
585
|
+
return !str1 && !str2;
|
|
586
|
+
}
|
|
587
|
+
function padding(message = "", before = 1, after = 1) {
|
|
588
|
+
return new Array(before).fill(" ").join("") + message + new Array(after).fill(" ").join("");
|
|
589
|
+
}
|
|
590
|
+
function geneDashLine(message, length) {
|
|
591
|
+
const finalMessage = new Array(Math.max(2, length - message.length + 2)).join(
|
|
592
|
+
"-"
|
|
593
|
+
);
|
|
594
|
+
return padding(import_chalk.default.dim(finalMessage));
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/cli/config.ts
|
|
598
|
+
var CONFIG_FILE_PATH = import_path.default.join(import_os.default.homedir(), "./.synology-api.json");
|
|
599
|
+
var loadConfig = () => __async(null, null, function* () {
|
|
600
|
+
if (!(yield import_fs_extra.default.pathExists(CONFIG_FILE_PATH))) {
|
|
601
|
+
yield import_fs_extra.default.writeJSON(CONFIG_FILE_PATH, {
|
|
602
|
+
used: "",
|
|
603
|
+
connections: {}
|
|
604
|
+
});
|
|
605
|
+
}
|
|
606
|
+
const config = yield import_fs_extra.default.readJSON(CONFIG_FILE_PATH);
|
|
607
|
+
return config;
|
|
608
|
+
});
|
|
609
|
+
var updateConfig = (config) => __async(null, null, function* () {
|
|
610
|
+
yield import_fs_extra.default.writeJSON(CONFIG_FILE_PATH, config);
|
|
611
|
+
});
|
|
612
|
+
var configCmdRegister = () => {
|
|
613
|
+
const configCmd = import_commander.program.command("config").description("synology api config management");
|
|
614
|
+
configCmd.command("ls").description("List all the connection config").action(() => __async(null, null, function* () {
|
|
615
|
+
const config = yield loadConfig();
|
|
616
|
+
const keys = Object.keys(config.connections);
|
|
617
|
+
const dashLineLength = Math.max(...keys.map((key) => key.length)) + 3;
|
|
618
|
+
const messages = keys.map((key) => {
|
|
619
|
+
const connection = config.connections[key];
|
|
620
|
+
const prefix = isLowerCaseEqual(key, config.used) ? import_chalk2.default.green.bold("* ") : ":";
|
|
621
|
+
return prefix + key + geneDashLine(key, dashLineLength) + connection.server + ":" + connection.username + ":" + connection.password;
|
|
622
|
+
});
|
|
623
|
+
printMessages(messages);
|
|
624
|
+
}));
|
|
625
|
+
configCmd.command("add [name]").description("Add connection config").requiredOption("-s, --server <server>", "Synology server domain or QuickConnect ID ").requiredOption("-u, --username <username>", "username").requiredOption("-p, --password <password>", "password").action((name, options) => __async(null, null, function* () {
|
|
626
|
+
if (!name.trim()) throw new Error("Plaease input connection name");
|
|
627
|
+
const config = yield loadConfig();
|
|
628
|
+
const newConfig = __spreadProps(__spreadValues({}, config), {
|
|
629
|
+
connections: __spreadProps(__spreadValues({}, config.connections), {
|
|
630
|
+
[name]: {
|
|
631
|
+
server: options.server,
|
|
632
|
+
username: options.username,
|
|
633
|
+
password: options.password
|
|
634
|
+
}
|
|
635
|
+
})
|
|
636
|
+
});
|
|
637
|
+
yield updateConfig(newConfig);
|
|
638
|
+
}));
|
|
639
|
+
configCmd.command("use [name]").description("Change current connection").action((name) => __async(null, null, function* () {
|
|
640
|
+
const config = yield loadConfig();
|
|
641
|
+
if (config.used === name) return;
|
|
642
|
+
if (!config.connections[name]) {
|
|
643
|
+
console.log("Connection not found");
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
config.used = name;
|
|
647
|
+
yield updateConfig(config);
|
|
648
|
+
}));
|
|
649
|
+
configCmd.command("del [name]").description("Remove a connection").action((name) => __async(null, null, function* () {
|
|
650
|
+
console.log("Remove a connection", name);
|
|
651
|
+
const config = yield loadConfig();
|
|
652
|
+
if (!config.connections[name]) {
|
|
653
|
+
console.log("Connection not found");
|
|
654
|
+
return;
|
|
655
|
+
}
|
|
656
|
+
delete config.connections[name];
|
|
657
|
+
if (config.used === name) {
|
|
658
|
+
config.used = "";
|
|
659
|
+
}
|
|
660
|
+
yield updateConfig(config);
|
|
661
|
+
}));
|
|
662
|
+
configCmd.command("rename <name> <newName>").description("Change connection name").action((name, newName) => __async(null, null, function* () {
|
|
663
|
+
const config = yield loadConfig();
|
|
664
|
+
if (!config.connections[name]) {
|
|
665
|
+
console.log("Connection not found");
|
|
666
|
+
return;
|
|
667
|
+
}
|
|
668
|
+
config.connections[newName] = config.connections[name];
|
|
669
|
+
delete config.connections[name];
|
|
670
|
+
if (config.used === name) {
|
|
671
|
+
config.used = newName;
|
|
672
|
+
}
|
|
673
|
+
yield updateConfig(config);
|
|
674
|
+
}));
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
// src/cli/apis.ts
|
|
678
|
+
var import_commander2 = require("commander");
|
|
679
|
+
var onMethodsCall = (module2) => (method, options) => __async(null, null, function* () {
|
|
680
|
+
var _a, _b;
|
|
681
|
+
const config = yield loadConfig();
|
|
682
|
+
const params = JSON.parse(options.params || "{}");
|
|
683
|
+
const pretty = options.pretty;
|
|
684
|
+
const synologyApi = new SynologyApi(config.connections[config.used]);
|
|
685
|
+
if ((_a = synologyApi[module2]) == null ? void 0 : _a[method]) {
|
|
686
|
+
const result = yield (_b = synologyApi[module2]) == null ? void 0 : _b[method](params);
|
|
687
|
+
if (pretty) {
|
|
688
|
+
console.log(JSON.stringify(result, null, 2));
|
|
689
|
+
} else {
|
|
690
|
+
console.log(JSON.stringify(result));
|
|
691
|
+
}
|
|
692
|
+
}
|
|
693
|
+
synologyApi.disconnect();
|
|
694
|
+
process.exit(0);
|
|
695
|
+
});
|
|
696
|
+
var apisCmdRegisterInfo = [
|
|
697
|
+
{
|
|
698
|
+
cmd: SynologyApiKeys.FileStation,
|
|
699
|
+
alias: SynologyApiKeys.fs
|
|
700
|
+
},
|
|
701
|
+
{
|
|
702
|
+
cmd: SynologyApiKeys.AudioStation,
|
|
703
|
+
alias: SynologyApiKeys.as
|
|
704
|
+
}
|
|
705
|
+
];
|
|
706
|
+
var apiCmdRegister = () => {
|
|
707
|
+
apisCmdRegisterInfo.forEach((info) => {
|
|
708
|
+
import_commander2.program.command(`${info.cmd} [methods]`).alias(info.alias).option("-p,--params <params>", `${info.cmd} methods params`).option("--pretty", "Prettyprint JSON Output").description(`Synology ${info.cmd} method call`).action(onMethodsCall(info.cmd));
|
|
709
|
+
});
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
// src/cli/index.ts
|
|
713
|
+
function loadCli() {
|
|
714
|
+
return __async(this, null, function* () {
|
|
715
|
+
const pkg = yield import_fs_extra2.default.readJSON(import_path2.default.join(__dirname, "../../package.json"));
|
|
716
|
+
import_commander3.program.name("synology").usage("<command> [options]").description("synology api cli tool").version(pkg.version);
|
|
717
|
+
configCmdRegister();
|
|
718
|
+
apiCmdRegister();
|
|
719
|
+
import_commander3.program.parse(process.argv);
|
|
720
|
+
});
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
// src/index.ts
|
|
724
|
+
var index_default = SynologyApi;
|
|
725
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
726
|
+
0 && (module.exports = {
|
|
727
|
+
AudioStationApi,
|
|
728
|
+
FileStationApi,
|
|
729
|
+
SynologyApi,
|
|
730
|
+
SynologyApiInfo,
|
|
731
|
+
loadCli
|
|
732
|
+
});
|