diff --git a/bun.lockb b/bun.lockb index 46c7db06..5c5541c5 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index a86da90f..4bb93f39 100644 --- a/package.json +++ b/package.json @@ -18,6 +18,7 @@ "preview-docs": "redocly preview-docs src/pms-spec.yaml --config=./redocly.yaml", "stats": "redocly stats ./src/pms-spec.yaml", "build": "swagger-cli bundle --dereference ./src/pms-spec.yaml -t yaml -o ./output/plex-media-server-spec-dereferenced.yaml", + "build-watch": "chokidar './src/**/*' -c 'bun run build'", "build-redocly": "redocly bundle ./src/pms-spec.yaml --ext yaml -o ./output/plex-media-server-spec-dereferenced.yaml", "test": "bun run build && vitest --run", "type-check": "tsc", @@ -31,6 +32,7 @@ "@modyfi/vite-plugin-yaml": "^1.1.0", "@redocly/cli": "latest", "@types/node": "^22.5.0", + "chokidar-cli": "^3.0.0", "prettier": "3.3.3", "swagger-cli": "^4.0.4", "typescript": "^5.5.4", diff --git a/src/models/PlexDevice.yaml b/src/models/PlexDevice.yaml index 453c2bdb..a558afdd 100644 --- a/src/models/PlexDevice.yaml +++ b/src/models/PlexDevice.yaml @@ -11,6 +11,20 @@ required: - createdAt - lastSeenAt - provides + - ownerId + - sourceTitle + - publicAddress + - accessToken + - owned + - home + - synced + - relay + - presence + - httpsRequired + - publicAddressMatches + - dnsRebindingProtection + - natLoopbackSupported + - connections properties: name: type: string @@ -19,11 +33,17 @@ properties: productVersion: type: string platform: - type: string + type: + - "null" + - string platformVersion: - type: string + type: + - "null" + - string device: - type: string + type: + - "null" + - string clientIdentifier: type: string createdAt: @@ -35,11 +55,14 @@ properties: provides: type: string ownerId: - type: string - format: nullable + description: ownerId is null when the device is owned by the token used to send the request + type: + - "null" + - integer sourceTitle: - type: string - format: nullable + type: + - "null" + - string publicAddress: type: string accessToken: @@ -66,6 +89,14 @@ properties: type: array items: type: object + required: + - protocol + - address + - port + - uri + - local + - relay + - IPv6 properties: protocol: type: string diff --git a/src/models/common/PlexBoolean.yaml b/src/models/common/PlexBoolean.yaml new file mode 100644 index 00000000..c13f3b6f --- /dev/null +++ b/src/models/common/PlexBoolean.yaml @@ -0,0 +1,8 @@ +type: integer +format: int32 +enum: + - 0 + - 1 +example: 1 +default: 0 + diff --git a/src/paths/identity.yaml b/src/paths/identity/identity.yaml similarity index 79% rename from src/paths/identity.yaml rename to src/paths/identity/identity.yaml index 1c5bedc5..d3df3e00 100644 --- a/src/paths/identity.yaml +++ b/src/paths/identity/identity.yaml @@ -2,8 +2,9 @@ get: tags: - Server summary: Get Server Identity - description: Get Server Identity - operationId: getServerIdentity + description: This request is useful to determine if the server is online or offline + operationId: get-server-identity + security: [] responses: "200": description: The Server Identity information @@ -26,7 +27,5 @@ get: version: type: string example: 1.31.3.6868-28fc46b27 - "400": - $ref: "../responses/400.yaml" - "401": - $ref: "../responses/401.yaml" + "408": + $ref: "../../responses/408.yaml" diff --git a/src/paths/resources/resources.yaml b/src/paths/resources/get-server-resources.yaml similarity index 58% rename from src/paths/resources/resources.yaml rename to src/paths/resources/get-server-resources.yaml index 75b36ad4..30bb583e 100644 --- a/src/paths/resources/resources.yaml +++ b/src/paths/resources/get-server-resources.yaml @@ -1,38 +1,32 @@ get: servers: - url: "https://plex.tv/api/v2" - security: [] tags: - Plex - summary: Get Resources - description: Get Resources - operationId: getResources + summary: Get Server Resources + description: Get Plex server access tokens and server connections + operationId: get-server-resources parameters: - $ref: "../../parameters/plex/x-plex-identifier.yaml" + - $ref: "../../parameters/plex/x-plex-token.yaml" - name: includeHttps in: query description: Include Https entries in the results schema: - type: integer - enum: - - 0 - - 1 + $ref: "../../models/common/PlexBoolean.yaml" - name: includeRelay in: query - description: Include Relay addresses in the results + description: | + Include Relay addresses in the results + E.g: https://10-0-0-25.bbf8e10c7fa20447cacee74cd9914cde.plex.direct:32400 schema: - type: integer - enum: - - 0 - - 1 + $ref: "../../models/common/PlexBoolean.yaml" - name: includeIPv6 in: query description: Include IPv6 entries in the results schema: - type: integer - enum: - - 0 - - 1 + $ref: "../../models/common/PlexBoolean.yaml" + - $ref: "../../parameters/accept-application-json.yaml" responses: "200": description: List of Plex Devices. This includes Plex hosted servers and clients diff --git a/src/pms-spec.yaml b/src/pms-spec.yaml index 0af8b4ca..da150e35 100644 --- a/src/pms-spec.yaml +++ b/src/pms-spec.yaml @@ -109,7 +109,7 @@ paths: $ref: "./paths/hubs/section.yaml" /identity: - $ref: "./paths/identity.yaml" + $ref: "./paths/identity/identity.yaml" # Library # Folder: pms/paths/library @@ -137,7 +137,6 @@ paths: /library/sections/{sectionKey}/search: $ref: "./paths/library/[sectionKey]/get-search-library.yaml" - /library/metadata/{ratingKey}: $ref: "./paths/library/metadata/[ratingKey]/get-meta-data-by-rating-key.yaml" /library/metadata/{ratingKey}/banner: @@ -154,7 +153,7 @@ paths: # Resources # Folder: pms/resources /resources: - $ref: "./paths/resources/resources.yaml" + $ref: "./paths/resources/get-server-resources.yaml" # Logs # Folder: pms/paths/logs @@ -239,8 +238,6 @@ paths: /users/signin: $ref: "./paths/users/post-sign-in.yaml" - - tags: - name: Activities description: | diff --git a/src/responses/408.yaml b/src/responses/408.yaml new file mode 100644 index 00000000..ebff08f4 --- /dev/null +++ b/src/responses/408.yaml @@ -0,0 +1,12 @@ +description: Request Timeout +content: + application/json: + schema: + type: object + properties: + code: + type: integer + example: 408 + message: + type: string + example: The server timed out waiting for the request. diff --git a/tests/paths/library/[sectionId]/get-library-details.spec.ts b/tests/paths/library/[sectionKey]/get-library-details.spec.ts similarity index 100% rename from tests/paths/library/[sectionId]/get-library-details.spec.ts rename to tests/paths/library/[sectionKey]/get-library-details.spec.ts diff --git a/tests/paths/library/[sectionId]/get-library-items.spec.ts b/tests/paths/library/[sectionKey]/get-library-items.spec.ts similarity index 100% rename from tests/paths/library/[sectionId]/get-library-items.spec.ts rename to tests/paths/library/[sectionKey]/get-library-items.spec.ts diff --git a/tests/paths/resources/get-server-resources.spec.ts b/tests/paths/resources/get-server-resources.spec.ts new file mode 100644 index 00000000..e89d1520 --- /dev/null +++ b/tests/paths/resources/get-server-resources.spec.ts @@ -0,0 +1,363 @@ +import { validateResponseSpec } from "@utils" +import { describe, it } from "vitest" + +describe("GET /resources", () => { + it("should validate the 200 response when includeHttps=1, includeRelay=1 and includeIPv6=1", () => { + const response = [ + { + name: "StreamMaster", + product: "Plex Media Server", + productVersion: "1.50.7.9541-913b34e21", + platform: "Linux", + platformVersion: "5.15.12-Unraid", + device: "Docker Container", + clientIdentifier: "8276c3fa6bc24e44b347e19c71fbb98b9287c1e9", + createdAt: "2020-01-12T15:30:18Z", + lastSeenAt: "2024-09-05T03:15:45Z", + provides: "server", + ownerId: null, + sourceTitle: null, + publicAddress: "54.231.109.34", + accessToken: "Hg7FGK9xVGdWZRa_sj76", + owned: true, + home: false, + synced: false, + relay: true, + presence: true, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: true, + natLoopbackSupported: false, + connections: [ + { + protocol: "https", + address: "192.168.1.150", + port: 32400, + uri: "https://192-168-1-150.fc6b48db927de7394036856ade1760b9.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "www.streammaster.com", + port: 45678, + uri: "https://www.streammaster.com:45678", + local: false, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "54.231.109.34", + port: 45678, + uri: "https://54-231-109-34.fc6b48db927de7394036856ade1760b9.plex.direct:45678", + local: false, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "162.243.175.222", + port: 8443, + uri: "https://162-243-175-222.fc6b48db927de7394036856ade1760b9.plex.direct:8443", + local: false, + relay: true, + IPv6: false + } + ] + }, + { + name: "PirateBay", + product: "Plex Media Server", + productVersion: "1.52.8.9931-936b74f82", + platform: "Linux", + platformVersion: "22.04 (Jammy Jellyfish)", + device: "PC", + clientIdentifier: "f76e7b49cd981f44e37f3128b6e9fca2db32bca1", + createdAt: "2019-12-05T08:50:12Z", + lastSeenAt: "2024-09-04T10:25:11Z", + provides: "server", + ownerId: 2639453, + sourceTitle: "kingpirate123", + publicAddress: "23.145.67.54", + accessToken: "yB3uFR1GQgM2qS47LGtY", + owned: false, + home: false, + synced: false, + relay: true, + presence: true, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: true, + natLoopbackSupported: true, + connections: [ + { + protocol: "https", + address: "10.1.1.45", + port: 32400, + uri: "https://10-1-1-45.d5e7f86fcace84ce8e19c7fa25347ce.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "10.98.1.2", + port: 32400, + uri: "https://10-98-1-2.d5e7f86fcace84ce8e19c7fa25347ce.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "23.145.67.54", + port: 32400, + uri: "https://23-145-67-54.d5e7f86fcace84ce8e19c7fa25347ce.plex.direct:32400", + local: false, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "162.243.175.222", + port: 8443, + uri: "https://162-243-175-222.d5e7f86fcace84ce8e19c7fa25347ce.plex.direct:8443", + local: false, + relay: true, + IPv6: false + } + ] + }, + { + name: "Plexify", + product: "Plex Media Server", + productVersion: "1.33.0.5930-7c2440c6", + platform: null, + platformVersion: null, + device: null, + clientIdentifier: "f4297e6a9bf4e642f41d33caabc7134d5634e078", + createdAt: "2021-03-12T02:21:19Z", + lastSeenAt: "2021-03-28T12:48:14Z", + provides: "server", + ownerId: 974224, + sourceTitle: "PlayerOne", + publicAddress: "87.64.72.96", + accessToken: "e7JvGmnGHyF3kYxV8qs2", + owned: false, + home: false, + synced: false, + relay: true, + presence: false, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: false, + natLoopbackSupported: false, + connections: [ + { + protocol: "http", + address: "87.64.72.96", + port: 23945, + uri: "http://87.64.72.96:23945", + local: false, + relay: false, + IPv6: false + } + ] + }, + { + name: "HouseOfFun", + product: "Plex Media Server", + productVersion: "1.42.0.8900-046c2e25", + platform: "Linux", + platformVersion: + "5.12.82-Unraid (#1 SMP PREEMPT_DYNAMIC Fri May 10 14:10:09 PDT 2024)", + device: "PC", + clientIdentifier: "ae35f677ff5689c9a56f4331f107f77957ab7feb", + createdAt: "2021-07-22T14:27:50Z", + lastSeenAt: "2024-09-05T05:33:23Z", + provides: "server", + ownerId: 4568124, + sourceTitle: "CoolUser201", + publicAddress: "172.156.190.56", + accessToken: "hIYSFzE3AOL8XrQT9r1w", + owned: false, + home: false, + synced: false, + relay: false, + presence: true, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: false, + natLoopbackSupported: false, + connections: [ + { + protocol: "https", + address: "192.168.0.123", + port: 32400, + uri: "https://192-168-0-123.7db256a875124f09cd9a9a4232bb2135.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "172.156.190.56", + port: 32400, + uri: "https://172-156-190-56.7db256a875124f09cd9a9a4232bb2135.plex.direct:32400", + local: false, + relay: false, + IPv6: false + } + ] + }, + { + name: "StreamerMaster", + product: "Plex Media Server", + productVersion: "1.45.2.7239-b797c8a8d", + platform: "Linux", + platformVersion: "5.18.20-Unraid", + device: "Docker Container", + clientIdentifier: "f6c462d7dd81c2cf78b1d6120b768f3b8d5ab521", + createdAt: "2022-08-23T11:08:49Z", + lastSeenAt: "2024-06-12T11:22:47Z", + provides: "server", + ownerId: 9321659, + sourceTitle: "AdminUser", + publicAddress: "162.214.65.132", + accessToken: "oGR9zJDwX5iQFZ7tE9zU", + owned: false, + home: false, + synced: false, + relay: true, + presence: false, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: false, + natLoopbackSupported: false, + connections: [ + { + protocol: "https", + address: "192.168.178.30", + port: 32400, + uri: "https://192-168-178-30.8bd4a832eea747d7aa569d2104f84f96.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "176.123.150.200", + port: 10500, + uri: "https://176-123-150-200.8bd4a832eea747d7aa569d2104f84f96.plex.direct:10500", + local: false, + relay: false, + IPv6: false + } + ] + }, + { + name: "desktop-mars", + product: "Plex Media Server", + productVersion: "1.55.7.9431-837d54f91", + platform: "Windows", + platformVersion: "10.0 (Build 20340)", + device: "PC", + clientIdentifier: "e5f4749ba349b07623246d861f35e1dbd6a29bc7", + createdAt: "2024-07-19T01:45:39Z", + lastSeenAt: "2024-09-05T07:12:46Z", + provides: "server", + ownerId: 856194, + sourceTitle: "AdminSuper", + publicAddress: "146.122.146.200", + accessToken: "sQ9weXnURfzLtLmnRz6q", + owned: false, + home: false, + synced: false, + relay: true, + presence: true, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: false, + natLoopbackSupported: true, + connections: [ + { + protocol: "https", + address: "192.168.2.21", + port: 32400, + uri: "https://192-168-2-21.9bd4a931f7b64b4b896f476f98b61d57.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "146.122.146.200", + port: 10901, + uri: "https://146-122-146-200.9bd4a931f7b64b4b896f476f98b61d57.plex.direct:10901", + local: false, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "162.243.175.222", + port: 8443, + uri: "https://162-243-175-222.9bd4a931f7b64b4b896f476f98b61d57.plex.direct:8443", + local: false, + relay: true, + IPv6: false + } + ] + }, + { + name: "MEDIA-HUB", + product: "Plex Media Server", + productVersion: "1.45.7.8739-e9821b72", + platform: "Windows", + platformVersion: "10.0 (Build 20040)", + device: "PC", + clientIdentifier: "d4e449bd664b2b93d8966b78323483be260e16c7", + createdAt: "2024-09-12T19:28:31Z", + lastSeenAt: "2024-09-05T08:12:37Z", + provides: "server", + ownerId: 32968462, + sourceTitle: "AdminHub", + publicAddress: "152.104.26.202", + accessToken: "-tH4rXWP91EDtrM7Mc5D", + owned: false, + home: false, + synced: false, + relay: true, + presence: false, + httpsRequired: false, + publicAddressMatches: false, + dnsRebindingProtection: true, + natLoopbackSupported: false, + connections: [ + { + protocol: "https", + address: "192.168.178.175", + port: 32400, + uri: "https://192-168-178-175.a5c471267784569e71505e1925ae56b6.plex.direct:32400", + local: true, + relay: false, + IPv6: false + }, + { + protocol: "https", + address: "152.104.26.202", + port: 13010, + uri: "https://152-104-26-202.a5c471267784569e71505e1925ae56b6.plex.direct:13010", + local: false, + relay: false, + IPv6: false + } + ] + } + ] + + validateResponseSpec("/resources", "get", 200, response) + }) +})