@fett/synology-api 0.1.0 → 0.1.2

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 CHANGED
@@ -7,7 +7,8 @@
7
7
 
8
8
  ![NPM Version](https://img.shields.io/npm/v/%40fett%2Fsynology-api) ![NPM Downloads](https://img.shields.io/npm/dm/%40fett%2Fsynology-api) ![GitHub](https://img.shields.io/github/license/chrissong1994/synology-api) ![vitest](https://img.shields.io/badge/tested_with-vitest-brightgreen)
9
9
 
10
- 👉🏻 [API Document ](https://chrissong1994.github.io/synology-api)
10
+ 📖 [中文 README](./README_zh.md)
11
+ 🔎 [API Document ](https://chrissong1994.github.io/synology-api)
11
12
 
12
13
  Synology Api Javascript wrapper can be used in Browser、CLI or Nodejs to interact with Synology NAS.
13
14
  You can use domain or ip address, also supports Synology Quick Connect connect Synology server.
@@ -27,6 +28,7 @@ npm install @fett/synology-api
27
28
  | :--------------------: | :-----------------: | :----------------------------------------------------------- | :-----: |
28
29
  | server | string | Synology NAS address or QuickConnectId | - |
29
30
  | quickConnectServerType | proxy \| wan \| lan | QuickConnect server type when connecting via QuickConnect ID | proxy |
31
+ | lanPriority | boolean | Prioritize LAN IP when quickConnectServerType is not lan | false |
30
32
  | username | string | Synology NAS username | - |
31
33
  | password | string | Synology NAS password | - |
32
34
 
package/lib/cli/apis.js CHANGED
@@ -42,7 +42,7 @@ export const onMethodCall = (module) => async (method, options) => {
42
42
  }
43
43
  if (options.output) {
44
44
  try {
45
- let out_path = path.resolve(options.output);
45
+ const out_path = path.resolve(options.output);
46
46
  if (!fse.existsSync(out_path)) {
47
47
  fse.ensureFileSync(out_path);
48
48
  console.log(chalk.yellowBright(`Output file created: ${out_path}`));
package/lib/core.d.ts CHANGED
@@ -17,6 +17,7 @@ export interface SynologyApiOptions {
17
17
  password: string;
18
18
  quickConnectServerType?: QuickConnectServerType;
19
19
  agent?: Agent;
20
+ lanPriority?: boolean;
20
21
  }
21
22
  export interface SynologyApiInfoData {
22
23
  maxVersion: number;
@@ -38,6 +39,7 @@ export declare class SynologyApi extends BaseModuleSynologyApi {
38
39
  baseUrl: string;
39
40
  isConnecting: boolean;
40
41
  quickConnectServerType?: QuickConnectServerType;
42
+ lanPriority?: boolean;
41
43
  private authInfo;
42
44
  private apiInfo;
43
45
  constructor(options: SynologyApiOptions);
@@ -52,12 +54,14 @@ export declare class SynologyApi extends BaseModuleSynologyApi {
52
54
  params?: Record<string, any>;
53
55
  data?: Record<string, any>;
54
56
  headers?: Record<string, any>;
57
+ responseType?: AxiosRequestConfig["responseType"];
55
58
  }): Promise<AxiosRequestConfig>;
56
59
  protected run(apiName: string, options: {
57
60
  method?: "get" | "post";
58
61
  params?: Record<string, any>;
59
62
  data?: Record<string, any>;
60
63
  headers?: Record<string, any>;
64
+ responseType?: AxiosRequestConfig["responseType"];
61
65
  }): Promise<any>;
62
66
  }
63
67
  export {};
package/lib/core.js CHANGED
@@ -17,13 +17,14 @@ export class SynologyApi extends BaseModuleSynologyApi {
17
17
  this.username = options.username;
18
18
  this.password = options.password;
19
19
  this.quickConnectServerType = options.quickConnectServerType ?? QuickConnectServerType.proxy;
20
+ this.lanPriority = options.lanPriority ?? false;
20
21
  this.baseUrl = `${this.server}/webapi/`;
21
22
  this.agent = options.agent ?? undefined;
22
23
  }
23
24
  async connect() {
24
25
  // if quickconnect id
25
26
  if (!isHttpUrl(this.server)) {
26
- this.server = await getServerInfo(this.server, this.quickConnectServerType);
27
+ this.server = await getServerInfo(this.server, this.quickConnectServerType, this.lanPriority);
27
28
  this.baseUrl = `${this.server}/webapi/`;
28
29
  }
29
30
  try {
@@ -103,6 +104,9 @@ export class SynologyApi extends BaseModuleSynologyApi {
103
104
  },
104
105
  data: options.data ?? null,
105
106
  };
107
+ if (options.responseType) {
108
+ requestOptions.responseType = options.responseType;
109
+ }
106
110
  // https agent for node
107
111
  if (isNode) {
108
112
  if (this.agent?.https) {
package/lib/helpers.d.ts CHANGED
@@ -16,5 +16,5 @@ export type ServerInfo = {
16
16
  relay_port: number;
17
17
  };
18
18
  };
19
- export declare const getServerInfo: (quickConnectId: string, quickConnectServerType: QuickConnectServerType) => Promise<any>;
19
+ export declare const getServerInfo: (quickConnectId: string, quickConnectServerType: QuickConnectServerType, lanPriority?: boolean) => Promise<any>;
20
20
  export declare const pingpang: (server: string) => Promise<boolean>;
package/lib/helpers.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import Axios from "axios";
2
2
  import { GLOBAL_QUICK_CONNECT_URL, QUICK_CONNECT_PINGPANG_API } from "./constants.js";
3
3
  import { QuickConnectServerType } from "./types/index.js";
4
- const getServersFromServerInfo = async (serverInfo, quickConnectServerType) => {
4
+ const getServersFromServerInfo = async (serverInfo, quickConnectServerType, lanPriority) => {
5
5
  const serverMap = {
6
6
  [QuickConnectServerType.proxy]: undefined,
7
7
  [QuickConnectServerType.lan]: undefined,
@@ -23,6 +23,12 @@ const getServersFromServerInfo = async (serverInfo, quickConnectServerType) => {
23
23
  `http://${serverInfo.server.interface?.[0].ip}:${serverInfo.service.port}`;
24
24
  }
25
25
  const server = serverMap[quickConnectServerType];
26
+ if (lanPriority && serverMap[QuickConnectServerType.lan]) {
27
+ const lanServer = serverMap[QuickConnectServerType.lan];
28
+ if (lanServer && (await pingpang(lanServer))) {
29
+ return lanServer;
30
+ }
31
+ }
26
32
  if (!server) {
27
33
  return Promise.reject(`${quickConnectServerType} server not found`);
28
34
  }
@@ -34,7 +40,7 @@ const getServersFromServerInfo = async (serverInfo, quickConnectServerType) => {
34
40
  return server;
35
41
  }
36
42
  };
37
- export const getServerInfo = async (quickConnectId, quickConnectServerType) => {
43
+ export const getServerInfo = async (quickConnectId, quickConnectServerType, lanPriority) => {
38
44
  const params = {
39
45
  version: 1,
40
46
  id: "dsm",
@@ -53,10 +59,10 @@ export const getServerInfo = async (quickConnectId, quickConnectServerType) => {
53
59
  };
54
60
  // get replay tunnel
55
61
  const result = (await Axios.post(`https://${serverInfo.env.control_host}/Serv.php`, relayRequestParams)).data;
56
- return getServersFromServerInfo(result, quickConnectServerType);
62
+ return getServersFromServerInfo(result, quickConnectServerType, lanPriority);
57
63
  }
58
64
  else {
59
- return getServersFromServerInfo(serverInfo, quickConnectServerType);
65
+ return getServersFromServerInfo(serverInfo, quickConnectServerType, lanPriority);
60
66
  }
61
67
  };
62
68
  // pingpang
@@ -1,7 +1,5 @@
1
- import { SynologyApiResponse } from "../../types/index.js";
2
1
  export type DownloadFileParams = {
3
2
  path: string;
4
- mode?: "download" | "open";
5
3
  };
6
- export type DownloadFileResponse = SynologyApiResponse<string>;
7
- export declare function getDownloadFile(params: DownloadFileParams): Promise<DownloadFileResponse>;
4
+ export type DownloadFileResponse = Buffer;
5
+ export declare function getDownload(params: DownloadFileParams): Promise<DownloadFileResponse>;
@@ -1,19 +1,35 @@
1
1
  import { FileStationApi } from "../../types/index.js";
2
- import { buildUrlWithQuery } from "../../utils/index.js";
3
- export async function getDownloadFile(params) {
4
- const { path, mode = "download" } = params;
5
- const api = this.getApiInfoByName(FileStationApi.Download);
6
- const query = {
7
- method: "download",
8
- path,
9
- mode,
10
- version: api.maxVersion,
11
- api: FileStationApi.Download,
12
- _sid: this.authInfo.sid,
13
- };
14
- const url = buildUrlWithQuery(`${this.baseUrl}${api.path}`, query);
15
- return {
16
- data: url,
17
- success: true,
18
- };
2
+ import { isNode } from "../../utils/index.js";
3
+ export async function getDownload(params) {
4
+ const { path } = params;
5
+ const res = await this.run(FileStationApi.Download, {
6
+ responseType: "arraybuffer",
7
+ params: {
8
+ path,
9
+ mode: "download",
10
+ },
11
+ });
12
+ return isNode ? Buffer.from(res) : res;
19
13
  }
14
+ // export async function getFileOpenUrl(params: DownloadFileParams): Promise<{
15
+ // data: string;
16
+ // success: boolean;
17
+ // }> {
18
+ // if (!this.isConnecting) {
19
+ // await this.connect();
20
+ // }
21
+ // const { path } = params;
22
+ // const apiInfo = this.getApiInfoByName(FileStationApi.Download);
23
+ // const url = buildUrlWithQuery(`${this.baseUrl}${apiInfo.path}`, {
24
+ // api: FileStationApi.Download,
25
+ // method:"download",
26
+ // path,
27
+ // mode: "open",
28
+ // version: apiInfo.maxVersion,
29
+ // _sid: this.authInfo?.sid,
30
+ // });
31
+ // return {
32
+ // data: url,
33
+ // success: true,
34
+ // };
35
+ // }
@@ -1,4 +1,3 @@
1
- import { SynologyApiResponse } from "../../types/index.js";
2
1
  export type GetThumbRequest = {
3
2
  path: string;
4
3
  size?: "small" | "medium" | "large" | "original";
@@ -14,5 +13,5 @@ export type GetThumbRequest = {
14
13
  */
15
14
  rotate?: 0 | 1 | 2 | 3 | 4;
16
15
  };
17
- export type GetThumbResponse = SynologyApiResponse<{}>;
18
- export declare function getThumbUrl(params: GetThumbRequest): Promise<GetThumbResponse>;
16
+ export type GetThumbResponse = Buffer;
17
+ export declare function getThumb(params: GetThumbRequest): Promise<GetThumbResponse>;
@@ -1,18 +1,14 @@
1
1
  import { FileStationApi } from "../../types/index.js";
2
- import { buildUrlWithQuery } from "../../utils/index.js";
3
- export async function getThumbUrl(params) {
2
+ import { isNode } from "../../utils/index.js";
3
+ export async function getThumb(params) {
4
4
  const { path, size = "small", rotate = 0 } = params;
5
- const options = await this.genRequestOptions(FileStationApi.Thumb, {
6
- method: "get",
5
+ const res = await this.run(FileStationApi.Thumb, {
6
+ responseType: "arraybuffer",
7
7
  params: {
8
8
  path,
9
9
  size,
10
10
  rotate,
11
11
  },
12
12
  });
13
- const thumbUrl = buildUrlWithQuery(options.url, options.params);
14
- return {
15
- success: true,
16
- data: thumbUrl,
17
- };
13
+ return isNode ? Buffer.from(res) : res;
18
14
  }
@@ -12,7 +12,7 @@ export async function uploadFile(params) {
12
12
  }
13
13
  const api = this.getApiInfoByName(FileStationApi.Upload);
14
14
  const { path, file, overwrite = OverwriteEnum.OVERWRITE, create_parents = true } = params;
15
- let formData = createFormData();
15
+ const formData = createFormData();
16
16
  formData.append("method", "upload");
17
17
  formData.append("version", String(api?.maxVersion));
18
18
  formData.append("api", FileStationApi.Upload);
@@ -11,7 +11,7 @@ export async function uploadFile(params) {
11
11
  }
12
12
  const api = this.getApiInfoByName(FileStationApi.Upload);
13
13
  const { path, file, overwrite = OverwriteEnum.OVERWRITE, create_parents = true } = params;
14
- let formData = createFormData();
14
+ const formData = createFormData();
15
15
  formData.append("method", "upload");
16
16
  formData.append("version", String(api?.maxVersion));
17
17
  formData.append("api", FileStationApi.Upload);
@@ -6,9 +6,9 @@ import { getFileList, getShareFileList, getVirtualFolderList } from "./List.js";
6
6
  import { addFavorite, deleteFavorite, getFavoriteList, clearBrokenFavorite, editFavorite } from "./Favorite.js";
7
7
  import { startSearch, stopSearch, getSearchList, cleanSearch } from "./Search.js";
8
8
  import { createFolder } from "./CreateFolder.js";
9
- import { getDownloadFile } from "./Download.js";
9
+ import { getDownload } from "./Download.js";
10
10
  import { stopDeleteFile, startDeleteFile, getDeleteFileStatus } from "./Delete.js";
11
- import { getThumbUrl } from "./Thumb.js";
11
+ import { getThumb } from "./Thumb.js";
12
12
  import { startDirSizeCalc, stopDirSizeCalc, getDirSizeCalcStatus } from "./DirSize.js";
13
13
  import { startMD5Calc, stopMD5Calc, getMD5CalcStatus } from "./MD5.js";
14
14
  import { checkPermission } from "./CheckPermission.js";
@@ -31,11 +31,11 @@ export declare const METHODS: {
31
31
  getSearchList: typeof getSearchList;
32
32
  cleanSearch: typeof cleanSearch;
33
33
  createFolder: typeof createFolder;
34
- getDownloadFile: typeof getDownloadFile;
34
+ getDownload: typeof getDownload;
35
35
  stopDeleteFile: typeof stopDeleteFile;
36
36
  startDeleteFile: typeof startDeleteFile;
37
37
  getDeleteFileStatus: typeof getDeleteFileStatus;
38
- getThumbUrl: typeof getThumbUrl;
38
+ getThumb: typeof getThumb;
39
39
  startDirSizeCalc: typeof startDirSizeCalc;
40
40
  stopDirSizeCalc: typeof stopDirSizeCalc;
41
41
  getDirSizeCalcStatus: typeof getDirSizeCalcStatus;
@@ -6,9 +6,9 @@ import { getFileList, getShareFileList, getVirtualFolderList } from "./List.js";
6
6
  import { addFavorite, deleteFavorite, getFavoriteList, clearBrokenFavorite, editFavorite, } from "./Favorite.js";
7
7
  import { startSearch, stopSearch, getSearchList, cleanSearch } from "./Search.js";
8
8
  import { createFolder } from "./CreateFolder.js";
9
- import { getDownloadFile } from "./Download.js";
9
+ import { getDownload } from "./Download.js";
10
10
  import { stopDeleteFile, startDeleteFile, getDeleteFileStatus } from "./Delete.js";
11
- import { getThumbUrl } from "./Thumb.js";
11
+ import { getThumb } from "./Thumb.js";
12
12
  import { startDirSizeCalc, stopDirSizeCalc, getDirSizeCalcStatus } from "./DirSize.js";
13
13
  import { startMD5Calc, stopMD5Calc, getMD5CalcStatus } from "./MD5.js";
14
14
  import { checkPermission } from "./CheckPermission.js";
@@ -32,11 +32,12 @@ export const METHODS = {
32
32
  getSearchList,
33
33
  cleanSearch,
34
34
  createFolder,
35
- getDownloadFile,
35
+ getDownload,
36
+ // getFileOpenUrl,
36
37
  stopDeleteFile,
37
38
  startDeleteFile,
38
39
  getDeleteFileStatus,
39
- getThumbUrl,
40
+ getThumb,
40
41
  startDirSizeCalc,
41
42
  stopDirSizeCalc,
42
43
  getDirSizeCalcStatus,
@@ -15,11 +15,11 @@ export declare const METHODS: {
15
15
  getSearchList: typeof import("./Search.js").getSearchList;
16
16
  cleanSearch: typeof import("./Search.js").cleanSearch;
17
17
  createFolder: typeof import("./CreateFolder.js").createFolder;
18
- getDownloadFile: typeof import("./Download.js").getDownloadFile;
18
+ getDownload: typeof import("./Download.js").getDownload;
19
19
  stopDeleteFile: typeof import("./Delete.js").stopDeleteFile;
20
20
  startDeleteFile: typeof import("./Delete.js").startDeleteFile;
21
21
  getDeleteFileStatus: typeof import("./Delete.js").getDeleteFileStatus;
22
- getThumbUrl: typeof import("./Thumb.js").getThumbUrl;
22
+ getThumb: typeof import("./Thumb.js").getThumb;
23
23
  startDirSizeCalc: typeof import("./DirSize.js").startDirSizeCalc;
24
24
  stopDirSizeCalc: typeof import("./DirSize.js").stopDirSizeCalc;
25
25
  getDirSizeCalcStatus: typeof import("./DirSize.js").getDirSizeCalcStatus;
@@ -15,11 +15,11 @@ export declare const METHODS: {
15
15
  getSearchList: typeof import("./Search.js").getSearchList;
16
16
  cleanSearch: typeof import("./Search.js").cleanSearch;
17
17
  createFolder: typeof import("./CreateFolder.js").createFolder;
18
- getDownloadFile: typeof import("./Download.js").getDownloadFile;
18
+ getDownload: typeof import("./Download.js").getDownload;
19
19
  stopDeleteFile: typeof import("./Delete.js").stopDeleteFile;
20
20
  startDeleteFile: typeof import("./Delete.js").startDeleteFile;
21
21
  getDeleteFileStatus: typeof import("./Delete.js").getDeleteFileStatus;
22
- getThumbUrl: typeof import("./Thumb.js").getThumbUrl;
22
+ getThumb: typeof import("./Thumb.js").getThumb;
23
23
  startDirSizeCalc: typeof import("./DirSize.js").startDirSizeCalc;
24
24
  stopDirSizeCalc: typeof import("./DirSize.js").stopDirSizeCalc;
25
25
  getDirSizeCalcStatus: typeof import("./DirSize.js").getDirSizeCalcStatus;
@@ -21,7 +21,8 @@ export async function getStreamUrl(params) {
21
21
  allow_api: VideoStationApi.Streaming,
22
22
  allow_methods: ["stream"],
23
23
  });
24
- const url = `${this.baseUrl}entry.cgi/1.mp4`;
24
+ const apiInfo = this.getApiInfoByName(VideoStationApi.Streaming);
25
+ const url = `${this.baseUrl}${apiInfo.path}/1.mp4`;
25
26
  const query = {
26
27
  ...params,
27
28
  api: VideoStationApi.Streaming,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fett/synology-api",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "synology api for nodejs",
5
5
  "main": "./lib/index.js",
6
6
  "types": "./lib/index.d.ts",
@@ -58,6 +58,7 @@
58
58
  "pub": "npm publish --access=public",
59
59
  "pub:beta": "npm publish --access=public --tag=beta",
60
60
  "test": "vitest",
61
+ "test:debug": "node --inspect-brk=9230 ./node_modules/vitest/vitest.mjs run --pool=forks",
61
62
  "coverage": "vitest run --coverage"
62
63
  },
63
64
  "devDependencies": {