@yume-chan/scrcpy 0.0.18 → 0.0.20
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/CHANGELOG.json +33 -0
- package/CHANGELOG.md +18 -1
- package/README.md +157 -183
- package/bin/scrcpy-server +0 -0
- package/bin/version.d.ts +1 -1
- package/bin/version.js +1 -1
- package/esm/codec/av1.d.ts +33 -0
- package/esm/codec/av1.d.ts.map +1 -0
- package/esm/codec/av1.js +35 -0
- package/esm/codec/av1.js.map +1 -0
- package/esm/codec/h264.d.ts +78 -0
- package/esm/codec/h264.d.ts.map +1 -0
- package/esm/codec/h264.js +256 -0
- package/esm/codec/h264.js.map +1 -0
- package/esm/codec/h265.d.ts +490 -0
- package/esm/codec/h265.d.ts.map +1 -0
- package/esm/codec/h265.js +1098 -0
- package/esm/codec/h265.js.map +1 -0
- package/esm/codec/index.d.ts +5 -0
- package/esm/codec/index.d.ts.map +1 -0
- package/esm/codec/index.js +5 -0
- package/esm/codec/index.js.map +1 -0
- package/esm/codec/nalu.d.ts +44 -0
- package/esm/codec/nalu.d.ts.map +1 -0
- package/esm/codec/nalu.js +310 -0
- package/esm/codec/nalu.js.map +1 -0
- package/esm/control/back-or-screen-on.d.ts +2 -2
- package/esm/control/back-or-screen-on.d.ts.map +1 -1
- package/esm/control/back-or-screen-on.js +1 -1
- package/esm/control/basic.d.ts +5 -0
- package/esm/control/basic.d.ts.map +1 -0
- package/esm/control/basic.js +3 -0
- package/esm/control/basic.js.map +1 -0
- package/esm/control/hover-helper.d.ts +17 -17
- package/esm/control/hover-helper.d.ts.map +1 -1
- package/esm/control/hover-helper.js +43 -43
- package/esm/control/hover-helper.js.map +1 -1
- package/esm/control/index.d.ts +13 -11
- package/esm/control/index.d.ts.map +1 -1
- package/esm/control/index.js +13 -11
- package/esm/control/index.js.map +1 -1
- package/esm/control/inject-keycode.d.ts +193 -60
- package/esm/control/inject-keycode.d.ts.map +1 -1
- package/esm/control/inject-keycode.js +198 -61
- package/esm/control/inject-keycode.js.map +1 -1
- package/esm/control/inject-scroll.d.ts +2 -2
- package/esm/control/inject-scroll.d.ts.map +1 -1
- package/esm/control/inject-scroll.js +1 -1
- package/esm/control/inject-text.d.ts +7 -8
- package/esm/control/inject-text.d.ts.map +1 -1
- package/esm/control/inject-text.js +5 -6
- package/esm/control/inject-text.js.map +1 -1
- package/esm/control/inject-touch.d.ts +32 -37
- package/esm/control/inject-touch.d.ts.map +1 -1
- package/esm/control/inject-touch.js +35 -62
- package/esm/control/inject-touch.js.map +1 -1
- package/esm/control/rotate-device.d.ts +4 -6
- package/esm/control/rotate-device.d.ts.map +1 -1
- package/esm/control/rotate-device.js +2 -4
- package/esm/control/rotate-device.js.map +1 -1
- package/esm/control/serializer.d.ts +25 -33
- package/esm/control/serializer.d.ts.map +1 -1
- package/esm/control/serializer.js +53 -78
- package/esm/control/serializer.js.map +1 -1
- package/esm/control/set-clipboard.d.ts +2 -2
- package/esm/control/set-clipboard.d.ts.map +1 -1
- package/esm/control/set-clipboard.js +1 -1
- package/esm/control/set-screen-power-mode.d.ts +10 -11
- package/esm/control/set-screen-power-mode.d.ts.map +1 -1
- package/esm/control/set-screen-power-mode.js +10 -11
- package/esm/control/set-screen-power-mode.js.map +1 -1
- package/esm/control/type.d.ts +28 -14
- package/esm/control/type.d.ts.map +1 -1
- package/esm/control/type.js +40 -18
- package/esm/control/type.js.map +1 -1
- package/esm/control/writer.d.ts +28 -0
- package/esm/control/writer.d.ts.map +1 -0
- package/esm/control/writer.js +53 -0
- package/esm/control/writer.js.map +1 -0
- package/esm/device-message/ack-clipboard.d.ts +8 -8
- package/esm/device-message/ack-clipboard.d.ts.map +1 -1
- package/esm/device-message/ack-clipboard.js +5 -5
- package/esm/device-message/clipboard.d.ts +9 -9
- package/esm/device-message/clipboard.d.ts.map +1 -1
- package/esm/device-message/clipboard.js +6 -6
- package/esm/device-message/index.d.ts +4 -4
- package/esm/device-message/index.js +4 -4
- package/esm/device-message/stream.d.ts +7 -7
- package/esm/device-message/stream.d.ts.map +1 -1
- package/esm/device-message/stream.js +34 -19
- package/esm/device-message/stream.js.map +1 -1
- package/esm/device-message/type.d.ts +4 -4
- package/esm/device-message/type.js +6 -6
- package/esm/index.d.ts +4 -5
- package/esm/index.d.ts.map +1 -1
- package/esm/index.js +4 -5
- package/esm/index.js.map +1 -1
- package/esm/options/1_16/codec-options.d.ts +19 -19
- package/esm/options/1_16/codec-options.d.ts.map +1 -1
- package/esm/options/1_16/codec-options.js +25 -25
- package/esm/options/1_16/codec-options.js.map +1 -1
- package/esm/options/1_16/float-to-uint16.d.ts +5 -0
- package/esm/options/1_16/float-to-uint16.d.ts.map +1 -0
- package/esm/options/1_16/float-to-uint16.js +27 -0
- package/esm/options/1_16/float-to-uint16.js.map +1 -0
- package/esm/options/1_16/index.d.ts +6 -4
- package/esm/options/1_16/index.d.ts.map +1 -1
- package/esm/options/1_16/index.js +6 -4
- package/esm/options/1_16/index.js.map +1 -1
- package/esm/options/1_16/init.d.ts +66 -0
- package/esm/options/1_16/init.d.ts.map +1 -0
- package/esm/options/1_16/init.js +16 -0
- package/esm/options/1_16/init.js.map +1 -0
- package/esm/options/1_16/message.d.ts +32 -0
- package/esm/options/1_16/message.d.ts.map +1 -0
- package/esm/options/1_16/message.js +37 -0
- package/esm/options/1_16/message.js.map +1 -0
- package/esm/options/1_16/options.d.ts +48 -93
- package/esm/options/1_16/options.d.ts.map +1 -1
- package/esm/options/1_16/options.js +152 -189
- package/esm/options/1_16/options.js.map +1 -1
- package/esm/options/1_16/scroll.d.ts +26 -26
- package/esm/options/1_16/scroll.d.ts.map +1 -1
- package/esm/options/1_16/scroll.js +54 -55
- package/esm/options/1_16/scroll.js.map +1 -1
- package/esm/options/1_17.d.ts +33 -0
- package/esm/options/1_17.d.ts.map +1 -0
- package/esm/options/1_17.js +42 -0
- package/esm/options/1_17.js.map +1 -0
- package/esm/options/1_18.d.ts +59 -19
- package/esm/options/1_18.d.ts.map +1 -1
- package/esm/options/1_18.js +78 -45
- package/esm/options/1_18.js.map +1 -1
- package/esm/options/1_21.d.ts +41 -20
- package/esm/options/1_21.d.ts.map +1 -1
- package/esm/options/1_21.js +51 -36
- package/esm/options/1_21.js.map +1 -1
- package/esm/options/1_22/index.d.ts +3 -2
- package/esm/options/1_22/index.d.ts.map +1 -1
- package/esm/options/1_22/index.js +3 -2
- package/esm/options/1_22/index.js.map +1 -1
- package/esm/options/1_22/init.d.ts +17 -0
- package/esm/options/1_22/init.d.ts.map +1 -0
- package/esm/options/1_22/init.js +2 -0
- package/esm/options/1_22/init.js.map +1 -0
- package/esm/options/1_22/options.d.ts +35 -28
- package/esm/options/1_22/options.d.ts.map +1 -1
- package/esm/options/1_22/options.js +36 -25
- package/esm/options/1_22/options.js.map +1 -1
- package/esm/options/1_22/scroll.d.ts +16 -16
- package/esm/options/1_22/scroll.d.ts.map +1 -1
- package/esm/options/1_22/scroll.js +14 -14
- package/esm/options/1_23.d.ts +36 -11
- package/esm/options/1_23.d.ts.map +1 -1
- package/esm/options/1_23.js +44 -34
- package/esm/options/1_23.js.map +1 -1
- package/esm/options/1_24.d.ts +34 -8
- package/esm/options/1_24.d.ts.map +1 -1
- package/esm/options/1_24.js +22 -12
- package/esm/options/1_24.js.map +1 -1
- package/esm/options/1_25/index.d.ts +2 -2
- package/esm/options/1_25/index.js +2 -2
- package/esm/options/1_25/options.d.ts +10 -5
- package/esm/options/1_25/options.d.ts.map +1 -1
- package/esm/options/1_25/options.js +21 -7
- package/esm/options/1_25/options.js.map +1 -1
- package/esm/options/1_25/scroll.d.ts +19 -18
- package/esm/options/1_25/scroll.d.ts.map +1 -1
- package/esm/options/1_25/scroll.js +33 -32
- package/esm/options/1_25/scroll.js.map +1 -1
- package/esm/options/2_0.d.ts +91 -0
- package/esm/options/2_0.d.ts.map +1 -0
- package/esm/options/2_0.js +244 -0
- package/esm/options/2_0.js.map +1 -0
- package/esm/options/codec.d.ts +52 -0
- package/esm/options/codec.d.ts.map +1 -0
- package/esm/options/codec.js +26 -0
- package/esm/options/codec.js.map +1 -0
- package/esm/options/index.d.ts +12 -8
- package/esm/options/index.d.ts.map +1 -1
- package/esm/options/index.js +12 -8
- package/esm/options/index.js.map +1 -1
- package/esm/options/latest.d.ts +12 -0
- package/esm/options/latest.d.ts.map +1 -0
- package/esm/options/latest.js +8 -0
- package/esm/options/latest.js.map +1 -0
- package/esm/options/types.d.ts +86 -46
- package/esm/options/types.d.ts.map +1 -1
- package/esm/options/types.js +69 -17
- package/esm/options/types.js.map +1 -1
- package/package.json +10 -16
- package/src/codec/av1.ts +33 -0
- package/src/codec/h264.ts +317 -0
- package/src/codec/h265.ts +1375 -0
- package/src/codec/index.ts +4 -0
- package/src/codec/nalu.ts +373 -0
- package/src/control/back-or-screen-on.ts +1 -1
- package/src/control/basic.ts +3 -0
- package/src/control/hover-helper.ts +2 -4
- package/src/control/index.ts +2 -0
- package/src/control/inject-keycode.ts +194 -51
- package/src/control/inject-scroll.ts +1 -1
- package/src/control/inject-text.ts +6 -9
- package/src/control/inject-touch.ts +16 -55
- package/src/control/rotate-device.ts +3 -7
- package/src/control/serializer.ts +49 -105
- package/src/control/set-clipboard.ts +1 -1
- package/src/control/set-screen-power-mode.ts +6 -9
- package/src/control/type.ts +32 -0
- package/src/control/writer.ts +87 -0
- package/src/device-message/ack-clipboard.ts +1 -1
- package/src/device-message/clipboard.ts +1 -1
- package/src/device-message/stream.ts +32 -12
- package/src/index.ts +4 -5
- package/src/options/1_16/codec-options.ts +5 -8
- package/src/options/1_16/float-to-uint16.ts +33 -0
- package/src/options/1_16/index.ts +3 -1
- package/src/options/1_16/init.ts +80 -0
- package/src/options/1_16/message.ts +55 -0
- package/src/options/1_16/options.ts +152 -256
- package/src/options/1_16/scroll.ts +2 -5
- package/src/options/1_17.ts +66 -0
- package/src/options/1_18.ts +106 -42
- package/src/options/1_21.ts +51 -30
- package/src/options/1_22/index.ts +1 -0
- package/src/options/1_22/init.ts +19 -0
- package/src/options/1_22/options.ts +40 -46
- package/src/options/1_22/scroll.ts +2 -2
- package/src/options/1_23.ts +33 -23
- package/src/options/1_24.ts +25 -11
- package/src/options/1_25/options.ts +25 -6
- package/src/options/1_25/scroll.ts +5 -7
- package/src/options/2_0.ts +342 -0
- package/src/options/codec.ts +98 -0
- package/src/options/index.ts +7 -3
- package/src/options/latest.ts +14 -0
- package/src/options/types.ts +158 -48
- package/tsconfig.build.json +9 -1
- package/tsconfig.build.tsbuildinfo +1 -1
- package/esm/adb/client.d.ts +0 -41
- package/esm/adb/client.d.ts.map +0 -1
- package/esm/adb/client.js +0 -243
- package/esm/adb/client.js.map +0 -1
- package/esm/adb/connection.d.ts +0 -47
- package/esm/adb/connection.d.ts.map +0 -1
- package/esm/adb/connection.js +0 -110
- package/esm/adb/connection.js.map +0 -1
- package/esm/adb/index.d.ts +0 -4
- package/esm/adb/index.d.ts.map +0 -1
- package/esm/adb/index.js +0 -4
- package/esm/adb/index.js.map +0 -1
- package/esm/adb/options/1_16.d.ts +0 -8
- package/esm/adb/options/1_16.d.ts.map +0 -1
- package/esm/adb/options/1_16.js +0 -20
- package/esm/adb/options/1_16.js.map +0 -1
- package/esm/adb/options/1_22.d.ts +0 -8
- package/esm/adb/options/1_22.d.ts.map +0 -1
- package/esm/adb/options/1_22.js +0 -17
- package/esm/adb/options/1_22.js.map +0 -1
- package/esm/adb/options/index.d.ts +0 -4
- package/esm/adb/options/index.d.ts.map +0 -1
- package/esm/adb/options/index.js +0 -4
- package/esm/adb/options/index.js.map +0 -1
- package/esm/adb/options/types.d.ts +0 -24
- package/esm/adb/options/types.d.ts.map +0 -1
- package/esm/adb/options/types.js +0 -37
- package/esm/adb/options/types.js.map +0 -1
- package/esm/codec.d.ts +0 -34
- package/esm/codec.d.ts.map +0 -1
- package/esm/codec.js +0 -37
- package/esm/codec.js.map +0 -1
- package/esm/options/1_16/h264-configuration.d.ts +0 -49
- package/esm/options/1_16/h264-configuration.d.ts.map +0 -1
- package/esm/options/1_16/h264-configuration.js +0 -414
- package/esm/options/1_16/h264-configuration.js.map +0 -1
- package/esm/options/1_16/sps.d.ts +0 -22
- package/esm/options/1_16/sps.d.ts.map +0 -1
- package/esm/options/1_16/sps.js +0 -263
- package/esm/options/1_16/sps.js.map +0 -1
- package/src/adb/client.ts +0 -345
- package/src/adb/connection.ts +0 -192
- package/src/adb/index.ts +0 -3
- package/src/adb/options/1_16.ts +0 -30
- package/src/adb/options/1_22.ts +0 -26
- package/src/adb/options/index.ts +0 -3
- package/src/adb/options/types.ts +0 -75
- package/src/codec.ts +0 -35
- package/src/options/1_16/h264-configuration.ts +0 -485
package/CHANGELOG.json
CHANGED
|
@@ -1,6 +1,39 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yume-chan/scrcpy",
|
|
3
3
|
"entries": [
|
|
4
|
+
{
|
|
5
|
+
"version": "0.0.20",
|
|
6
|
+
"tag": "@yume-chan/scrcpy_v0.0.20",
|
|
7
|
+
"date": "Mon, 05 Jun 2023 02:51:41 GMT",
|
|
8
|
+
"comments": {
|
|
9
|
+
"none": [
|
|
10
|
+
{
|
|
11
|
+
"comment": "Add support for Scrcpy 2.0. New features including audio forwarding (supports PCM, AAC and OPUS encoding) and other video codecs (supports H.264 and H.265, AV1 not supported). Read the PR for new options and breaking changes. ([#495](https://github.com/yume-chan/ya-webadb/pull/495))"
|
|
12
|
+
},
|
|
13
|
+
{
|
|
14
|
+
"comment": "Move ADB related code to `@yume-chan/adb-scrcpy` package. This package now only implements the Scrcpy protocol."
|
|
15
|
+
}
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
{
|
|
20
|
+
"version": "0.0.19",
|
|
21
|
+
"tag": "@yume-chan/scrcpy_v0.0.19",
|
|
22
|
+
"date": "Sun, 09 Apr 2023 05:55:33 GMT",
|
|
23
|
+
"comments": {
|
|
24
|
+
"none": [
|
|
25
|
+
{
|
|
26
|
+
"comment": "Change `AdbScrcpyClient#pushServer` to take a `ReadableStream<Uint8Array>` instead of returning a `WritableStream<Uint8Array>`"
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"comment": "Add `AdbReverseNotSupportedError` handling and automatically switch to forward tunnel in `AdbScrcpyClient`."
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
"comment": "Update `AndroidKeyCode` enum to align with Web `KeyboardEvent.code`"
|
|
33
|
+
}
|
|
34
|
+
]
|
|
35
|
+
}
|
|
36
|
+
},
|
|
4
37
|
{
|
|
5
38
|
"version": "0.0.18",
|
|
6
39
|
"tag": "@yume-chan/scrcpy_v0.0.18",
|
package/CHANGELOG.md
CHANGED
|
@@ -1,6 +1,23 @@
|
|
|
1
1
|
# Change Log - @yume-chan/scrcpy
|
|
2
2
|
|
|
3
|
-
This log was last generated on
|
|
3
|
+
This log was last generated on Mon, 05 Jun 2023 02:51:41 GMT and should not be manually modified.
|
|
4
|
+
|
|
5
|
+
## 0.0.20
|
|
6
|
+
Mon, 05 Jun 2023 02:51:41 GMT
|
|
7
|
+
|
|
8
|
+
### Updates
|
|
9
|
+
|
|
10
|
+
- Add support for Scrcpy 2.0. New features including audio forwarding (supports PCM, AAC and OPUS encoding) and other video codecs (supports H.264 and H.265, AV1 not supported). Read the PR for new options and breaking changes. ([#495](https://github.com/yume-chan/ya-webadb/pull/495))
|
|
11
|
+
- Move ADB related code to `@yume-chan/adb-scrcpy` package. This package now only implements the Scrcpy protocol.
|
|
12
|
+
|
|
13
|
+
## 0.0.19
|
|
14
|
+
Sun, 09 Apr 2023 05:55:33 GMT
|
|
15
|
+
|
|
16
|
+
### Updates
|
|
17
|
+
|
|
18
|
+
- Change `AdbScrcpyClient#pushServer` to take a `ReadableStream<Uint8Array>` instead of returning a `WritableStream<Uint8Array>`
|
|
19
|
+
- Add `AdbReverseNotSupportedError` handling and automatically switch to forward tunnel in `AdbScrcpyClient`.
|
|
20
|
+
- Update `AndroidKeyCode` enum to align with Web `KeyboardEvent.code`
|
|
4
21
|
|
|
5
22
|
## 0.0.18
|
|
6
23
|
Wed, 25 Jan 2023 21:33:49 GMT
|
package/README.md
CHANGED
|
@@ -1,79 +1,94 @@
|
|
|
1
1
|
# @yume-chan/scrcpy
|
|
2
2
|
|
|
3
|
-
TypeScript
|
|
3
|
+
TypeScript library to communicate with [Scrcpy](https://github.com/Genymobile/scrcpy) server.
|
|
4
4
|
|
|
5
5
|
It's compatible with the official Scrcpy server binaries.
|
|
6
6
|
|
|
7
|
-
**WARNING:** The public API is UNSTABLE.
|
|
7
|
+
**WARNING:** The public API is UNSTABLE. Open a GitHub discussion if you have any questions.
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
-
|
|
19
|
-
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
- [Always read the streams](#always-read-the-streams)
|
|
27
|
-
- [Video stream](#video-stream)
|
|
28
|
-
- [Decode video stream](#decode-video-stream)
|
|
9
|
+
- [How does Scrcpy work](#how-does-scrcpy-work)
|
|
10
|
+
- [What does this package do](#what-does-this-package-do)
|
|
11
|
+
- [Prepare server binary](#prepare-server-binary)
|
|
12
|
+
- [`fetch-scrcpy-server`](#fetch-scrcpy-server)
|
|
13
|
+
- [Use the server binary](#use-the-server-binary)
|
|
14
|
+
- [Node.js CommonJS](#nodejs-commonjs)
|
|
15
|
+
- [Node.js ES module](#nodejs-es-module)
|
|
16
|
+
- [Webpack 4](#webpack-4)
|
|
17
|
+
- [Webpack 5](#webpack-5)
|
|
18
|
+
- [Server versions](#server-versions)
|
|
19
|
+
- [Reading and writing packets](#reading-and-writing-packets)
|
|
20
|
+
- [Reading video/audio packets](#reading-videoaudio-packets)
|
|
21
|
+
- [Sending control messages](#sending-control-messages)
|
|
22
|
+
- [Reading device messages](#reading-device-messages)
|
|
23
|
+
- [Always read all streams](#always-read-all-streams)
|
|
24
|
+
- [Video/audio stream](#videoaudio-stream)
|
|
25
|
+
- [Decode video stream](#decode-video-stream)
|
|
29
26
|
|
|
30
|
-
##
|
|
27
|
+
## How does Scrcpy work
|
|
31
28
|
|
|
32
|
-
|
|
29
|
+
Scrcpy has two parts: a client and a server.
|
|
33
30
|
|
|
34
|
-
|
|
31
|
+
The server is a Java application (but not an Android app) that runs on the device to capture the video and audio, and send them to the client.
|
|
35
32
|
|
|
36
|
-
|
|
33
|
+
The client receives captured video and audio data, and renders them on computer.
|
|
37
34
|
|
|
38
|
-
|
|
35
|
+
The official Scrcpy client also spawns Google ADB executable to set up the reverse tunnel, push the server binary to the device, and start the server.
|
|
39
36
|
|
|
40
|
-
|
|
37
|
+
## What does this package do
|
|
38
|
+
|
|
39
|
+
This package can't push nor start the server, nor render the video and audio. It only provides APIs to communicate with the server.
|
|
40
|
+
|
|
41
|
+
`@yume-chan/adb-scrcpy` package is a wrapper of this package, provides integration with `@yume-chan/adb` package, and can push, start, and stop the server.
|
|
41
42
|
|
|
42
43
|
## Prepare server binary
|
|
43
44
|
|
|
44
|
-
This package
|
|
45
|
+
This package is compatible with many versions of the official server binary, but it doesn't include the server binary itself.
|
|
45
46
|
|
|
46
|
-
You can download the server binary from official releases (https://github.com/Genymobile/scrcpy/releases), or use the
|
|
47
|
+
You can download the server binary from official releases (https://github.com/Genymobile/scrcpy/releases), or use the included `fetch-scrcpy-server` script to automate the process.
|
|
47
48
|
|
|
48
49
|
The server binary is subject to [Apache License 2.0](https://github.com/Genymobile/scrcpy/blob/master/LICENSE).
|
|
49
50
|
|
|
50
51
|
### `fetch-scrcpy-server`
|
|
51
52
|
|
|
52
|
-
This
|
|
53
|
+
This script downloads the server binary from official releases for you.
|
|
53
54
|
|
|
54
|
-
|
|
55
|
+
Before using this script, install `gh-release-fetch@3` package separately:
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
npm install --save-dev gh-release-fetch@3
|
|
59
|
+
```
|
|
55
60
|
|
|
56
61
|
Usage:
|
|
57
62
|
|
|
58
63
|
```
|
|
59
|
-
|
|
64
|
+
npx fetch-scrcpy-server <version>
|
|
60
65
|
```
|
|
61
66
|
|
|
62
67
|
For example:
|
|
63
68
|
|
|
64
69
|
```
|
|
65
|
-
|
|
70
|
+
npx fetch-scrcpy-server 1.25
|
|
66
71
|
```
|
|
67
72
|
|
|
68
|
-
|
|
73
|
+
Add it to `scripts.postinstall` in your `package.json`, so running `npm install` automatically invokes the script:
|
|
69
74
|
|
|
70
75
|
```json
|
|
71
|
-
|
|
72
|
-
"
|
|
73
|
-
|
|
76
|
+
{
|
|
77
|
+
"scripts": {
|
|
78
|
+
"postinstall": "fetch-scrcpy-server 1.25"
|
|
79
|
+
}
|
|
80
|
+
}
|
|
74
81
|
```
|
|
75
82
|
|
|
76
|
-
The server binary will be
|
|
83
|
+
The server binary will be saved to `bin/scrcpy-server` in this package's installation directory (usually in `node_modules`).
|
|
84
|
+
|
|
85
|
+
It will also save the version number to `bin/version.js`.
|
|
86
|
+
|
|
87
|
+
```js
|
|
88
|
+
import SCRCPY_SERVER_VERSION from "@yume-chan/scrcpy/bin/version.js";
|
|
89
|
+
|
|
90
|
+
console.log(SCRCPY_SERVER_VERSION); // "1.25"
|
|
91
|
+
```
|
|
77
92
|
|
|
78
93
|
### Use the server binary
|
|
79
94
|
|
|
@@ -84,27 +99,34 @@ To name a few:
|
|
|
84
99
|
#### Node.js CommonJS
|
|
85
100
|
|
|
86
101
|
```ts
|
|
87
|
-
const fs = require(
|
|
88
|
-
const path: string = require.resolve(
|
|
102
|
+
const fs = require("fs");
|
|
103
|
+
const path: string = require.resolve("@yume-chan/scrcpy/bin/scrcpy-server"); // Or your own server binary path
|
|
89
104
|
const buffer: Buffer = fs.readFileSync(path);
|
|
90
105
|
```
|
|
91
106
|
|
|
92
107
|
#### Node.js ES module
|
|
93
108
|
|
|
109
|
+
Without the `import.meta.resolve` feature:
|
|
110
|
+
|
|
94
111
|
```ts
|
|
95
|
-
import fs from
|
|
96
|
-
import { createRequire } from
|
|
112
|
+
import fs from "node:fs/promises";
|
|
113
|
+
import { createRequire } from "node:module";
|
|
97
114
|
|
|
98
|
-
const path: string = createRequire(import.meta.url).resolve(
|
|
115
|
+
const path: string = createRequire(import.meta.url).resolve(
|
|
116
|
+
"@yume-chan/scrcpy/bin/scrcpy-server"
|
|
117
|
+
); // Or your own server binary path
|
|
99
118
|
const buffer: Buffer = await fs.readFile(path);
|
|
100
119
|
```
|
|
101
120
|
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
`import.meta.resolve` (https://github.com/whatwg/html/pull/5572) is a proposal that fills this gap. Node.js already has experimental support for it behind a flag. See https://nodejs.org/api/esm.html#importmetaresolvespecifier-parent for more information.
|
|
121
|
+
With `import.meta.resolve` feature (requires `--experimental-import-meta-resolve` command line flag for Node.js 12.6.0+):
|
|
105
122
|
|
|
106
123
|
```ts
|
|
107
|
-
|
|
124
|
+
import fs from "node:fs/promises";
|
|
125
|
+
|
|
126
|
+
const path: string = await import.meta.resolve(
|
|
127
|
+
"@yume-chan/scrcpy/bin/scrcpy-server"
|
|
128
|
+
);
|
|
129
|
+
const buffer: Buffer = await fs.readFile(path);
|
|
108
130
|
```
|
|
109
131
|
|
|
110
132
|
#### Webpack 4
|
|
@@ -112,8 +134,10 @@ const path: string = import.meta.resolve('@yume-chan/scrcpy/bin/scrcpy-server');
|
|
|
112
134
|
Requires installing and configuring file-loader (https://v4.webpack.js.org/loaders/file-loader/)
|
|
113
135
|
|
|
114
136
|
```ts
|
|
115
|
-
import SCRCPY_SERVER_URL from
|
|
116
|
-
const buffer: ArrayBuffer = await fetch(SCRCPY_SERVER_URL).then(
|
|
137
|
+
import SCRCPY_SERVER_URL from "@yume-chan/scrcpy/bin/scrcpy-server"; // Or your own server binary path
|
|
138
|
+
const buffer: ArrayBuffer = await fetch(SCRCPY_SERVER_URL).then((response) =>
|
|
139
|
+
response.arrayBuffer()
|
|
140
|
+
);
|
|
117
141
|
```
|
|
118
142
|
|
|
119
143
|
#### Webpack 5
|
|
@@ -121,127 +145,64 @@ const buffer: ArrayBuffer = await fetch(SCRCPY_SERVER_URL).then(res => res.array
|
|
|
121
145
|
Requires configuring Asset Modules (https://webpack.js.org/guides/asset-modules/)
|
|
122
146
|
|
|
123
147
|
```ts
|
|
124
|
-
const SCRCPY_SERVER_URL = new URL(
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
```js
|
|
133
|
-
import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version.js';
|
|
134
|
-
|
|
135
|
-
console.log(SCRCPY_SERVER_VERSION); // "1.25"
|
|
148
|
+
const SCRCPY_SERVER_URL = new URL(
|
|
149
|
+
"@yume-chan/scrcpy/bin/scrcpy-server",
|
|
150
|
+
import.meta.url
|
|
151
|
+
); // Or your own server binary path
|
|
152
|
+
const buffer: ArrayBuffer = await fetch(SCRCPY_SERVER_URL).then((response) =>
|
|
153
|
+
response.arrayBuffer()
|
|
154
|
+
);
|
|
136
155
|
```
|
|
137
156
|
|
|
138
157
|
## Server versions
|
|
139
158
|
|
|
140
|
-
Scrcpy protocol
|
|
159
|
+
Scrcpy protocol changes over time, and are usually not backwards compatible. This package supports multiple server versions (ranges), and uses different option types to choose different behaviors. Using incorrect option version usually results in errors.
|
|
141
160
|
|
|
142
161
|
The latest one may continue to work for future server versions, but there is no guarantee.
|
|
143
162
|
|
|
144
163
|
| Version | Type |
|
|
145
164
|
| --------- | ------------------- |
|
|
146
|
-
| 1.16
|
|
165
|
+
| 1.16 | `ScrcpyOptions1_16` |
|
|
166
|
+
| 1.17 | `ScrcpyOptions1_17` |
|
|
147
167
|
| 1.18~1.20 | `ScrcpyOptions1_18` |
|
|
148
168
|
| 1.21 | `ScrcpyOptions1_21` |
|
|
149
169
|
| 1.22 | `ScrcpyOptions1_22` |
|
|
150
170
|
| 1.23 | `ScrcpyOptions1_23` |
|
|
151
171
|
| 1.24 | `ScrcpyOptions1_24` |
|
|
152
172
|
| 1.25 | `ScrcpyOptions1_25` |
|
|
173
|
+
| 2.0 | `ScrcpyOptions2_0` |
|
|
153
174
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
| Version | Type |
|
|
157
|
-
| --------- | ---------------------- |
|
|
158
|
-
| 1.16~1.21 | `AdbScrcpyOptions1_16` |
|
|
159
|
-
| 1.22~1.25 | `AdbScrcpyOptions1_22` |
|
|
160
|
-
|
|
161
|
-
## Use with `@yume-chan/adb`
|
|
162
|
-
|
|
163
|
-
`@yume-chan/adb` is a TypeScript ADB implementation that can run on Web browser. It can be used to bootstrap the server on a device.
|
|
175
|
+
## Reading and writing packets
|
|
164
176
|
|
|
165
|
-
|
|
177
|
+
This packets operates on Web Streams API streams.
|
|
166
178
|
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
This package also provides the `AdbScrcpyClient.pushServer()` static method as a shortcut, plus it will automatically close the `AdbSync` object on completion.
|
|
170
|
-
|
|
171
|
-
Example using `write()`:
|
|
172
|
-
|
|
173
|
-
```ts
|
|
174
|
-
import { AdbScrcpyClient } from '@yume-chan/scrcpy';
|
|
179
|
+
**NOTE:** Web Streams API streams usually can't pipe between different implementations. This package by default uses the native implementation on `globalThis`, and `web-streams-polyfill` otherwise. If you are using another implementation, or simply not sure, wrap your streams using the `WrapReadableStream` and `WrapWritableStream` types from `@yume-chan/stream-extra` package.
|
|
175
180
|
|
|
176
|
-
|
|
177
|
-
const writer = stream.getWriter();
|
|
178
|
-
await writer.write(new Uint8Array(buffer));
|
|
179
|
-
await writer.close();
|
|
180
|
-
```
|
|
181
|
+
### Reading video/audio packets
|
|
181
182
|
|
|
182
|
-
|
|
183
|
+
Requires a `ReadableStream<Uint8Array>` that reads from the video socket.
|
|
183
184
|
|
|
184
185
|
```ts
|
|
185
|
-
import {
|
|
186
|
-
import { AdbScrcpyClient } from '@yume-chan/scrcpy';
|
|
187
|
-
|
|
188
|
-
await fetch(SCRCPY_SERVER_URL)
|
|
189
|
-
// `WrapReadableStream` is required because native `ReadableStream` (from `fetch`)
|
|
190
|
-
// doesn't support `pipeTo()` non-native `WritableStream`s
|
|
191
|
-
// (`@yume-chan/adb` is using `web-streams-polyfill`)
|
|
192
|
-
.then(response => new WrapReadableStream(response.body))
|
|
193
|
-
.then(stream => stream.pipeTo(AdbScrcpyClient.pushServer(adb)));
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
### Start server on device
|
|
197
|
-
|
|
198
|
-
To start the server, use the `AdbScrcpyClient.start()` method. It automatically sets up port forwarding, launches the server, and connects to it.
|
|
199
|
-
|
|
200
|
-
```js
|
|
201
|
-
import { AdbScrcpyClient, AdbScrcpyOptions1_22, DEFAULT_SERVER_PATH, ScrcpyOptions1_24 } from '@yume-chan/scrcpy';
|
|
202
|
-
import SCRCPY_SERVER_VERSION from '@yume-chan/scrcpy/bin/version.js';
|
|
203
|
-
|
|
204
|
-
const client: AdbScrcpyClient = await AdbScrcpyClient.start(
|
|
205
|
-
adb,
|
|
206
|
-
DEFAULT_SERVER_PATH,
|
|
207
|
-
SCRCPY_SERVER_VERSION, // If server binary was downloaded manually, must provide the correct version
|
|
208
|
-
new AdbScrcpyOptions1_22(ScrcpyOptions1_24({
|
|
209
|
-
// options
|
|
210
|
-
}))
|
|
211
|
-
);
|
|
212
|
-
|
|
213
|
-
const stdout: ReadableStream<string> = client.stdout;
|
|
214
|
-
const videoPacketStream: ReadableStream<ScrcpyVideoStreamPacket> = client.videoStream;
|
|
215
|
-
const controlMessageSerializer: ScrcpyControlMessageSerializer | undefined = client.controlMessageSerializer;
|
|
216
|
-
const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> | undefined = client.deviceMessageStream;
|
|
186
|
+
import { ScrcpyOptions1_25, ScrcpyVideoStreamPacket } from "@yume-chan/scrcpy";
|
|
217
187
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
## Using other transportation
|
|
223
|
-
|
|
224
|
-
If you push, start and connect to the server yourself, you can still use this package to serialize/deserialize packets.
|
|
225
|
-
|
|
226
|
-
### Parsing video packets
|
|
227
|
-
|
|
228
|
-
Requires a `ReadableStream<Uint8Array>` that reads from the video socket, preserving packet boundaries.
|
|
229
|
-
|
|
230
|
-
**NOTE:** Because this package uses `web-streams-polyfill` NPM package's Web Streams API implementation, the provided `ReadableStream` must also be from `web-streams-polyfill` (or another polyfill that doesn't check object prototype when piping).
|
|
231
|
-
|
|
232
|
-
```ts
|
|
233
|
-
import { ScrcpyOptions1_24, ScrcpyVideoStreamPacket } from '@yume-chan/scrcpy';
|
|
188
|
+
const options = new ScrcpyOptions1_25({
|
|
189
|
+
// use the same version and options when starting the server
|
|
190
|
+
});
|
|
234
191
|
|
|
235
192
|
const videoStream: ReadableStream<Uint8Array>; // get the stream yourself
|
|
236
193
|
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
}
|
|
194
|
+
// Parse video socket metadata
|
|
195
|
+
// Use `videoStream2` instead of `videoStream` from now on
|
|
196
|
+
const { metadata, stream: videoStream2 } =
|
|
197
|
+
await options.parseVideoStreamMetadata(videoStream);
|
|
240
198
|
|
|
241
|
-
const videoPacketStream: ReadableStream<
|
|
199
|
+
const videoPacketStream: ReadableStream<ScrcpyMediaStreamPacket> =
|
|
200
|
+
videoStream2.pipeThrough(options.createMediaStreamTransformer());
|
|
242
201
|
// Read from `videoPacketStream`
|
|
243
202
|
```
|
|
244
203
|
|
|
204
|
+
Read audio stream is similar, but uses `parseVideoStreamMetadata` instead.
|
|
205
|
+
|
|
245
206
|
### Sending control messages
|
|
246
207
|
|
|
247
208
|
Requires a `WritableStream<Uint8Array>` that writes to the control socket.
|
|
@@ -249,38 +210,47 @@ Requires a `WritableStream<Uint8Array>` that writes to the control socket.
|
|
|
249
210
|
Control socket is optional if control is not enabled. Video socket and control socket can run completely separately.
|
|
250
211
|
|
|
251
212
|
```ts
|
|
252
|
-
import {
|
|
253
|
-
|
|
254
|
-
|
|
213
|
+
import {
|
|
214
|
+
ScrcpyControlMessageWriter,
|
|
215
|
+
ScrcpyOptions1_25,
|
|
216
|
+
} from "@yume-chan/scrcpy";
|
|
255
217
|
|
|
256
|
-
const options = new
|
|
257
|
-
// use the same version and options
|
|
218
|
+
const options = new ScrcpyOptions1_25({
|
|
219
|
+
// use the same version and options when starting the server
|
|
258
220
|
});
|
|
259
221
|
|
|
260
|
-
const
|
|
261
|
-
|
|
262
|
-
|
|
222
|
+
const controlStream: ReadableWritablePair<Uint8Array, Uint8Array>; // get the stream yourself
|
|
223
|
+
|
|
224
|
+
const controlMessageWriter = new ScrcpyControlMessageWriter(
|
|
225
|
+
controlStream.writable.getWriter(),
|
|
226
|
+
options
|
|
227
|
+
);
|
|
228
|
+
|
|
229
|
+
// Call methods on `controlMessageWriter`
|
|
230
|
+
controlMessageWriter.injectText("Hello World!");
|
|
263
231
|
```
|
|
264
232
|
|
|
265
233
|
### Reading device messages
|
|
266
234
|
|
|
267
235
|
Requires a `ReadableStream<Uint8Array>` that reads from the control socket.
|
|
268
236
|
|
|
269
|
-
**NOTE:** Because this package uses `web-streams-polyfill` NPM package's Web Streams API implementation, the provided `ReadableStream` must also be from `web-streams-polyfill` (or another polyfill that doesn't check object prototype when piping).
|
|
270
|
-
|
|
271
237
|
```ts
|
|
272
|
-
import {
|
|
238
|
+
import {
|
|
239
|
+
ScrcpyDeviceMessageDeserializeStream,
|
|
240
|
+
ScrcpyOptions1_24,
|
|
241
|
+
} from "@yume-chan/scrcpy";
|
|
273
242
|
|
|
274
|
-
const controlStream: ReadableWritablePair<Uint8Array, Uint8Array
|
|
243
|
+
const controlStream: ReadableWritablePair<Uint8Array, Uint8Array>; // get the stream yourself
|
|
275
244
|
|
|
276
|
-
const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> =
|
|
245
|
+
const deviceMessageStream: ReadableStream<ScrcpyDeviceMessage> =
|
|
246
|
+
controlStream.readable.pipeThrough(
|
|
247
|
+
new ScrcpyDeviceMessageDeserializeStream()
|
|
248
|
+
);
|
|
277
249
|
```
|
|
278
250
|
|
|
279
|
-
## Always read
|
|
251
|
+
## Always read all streams
|
|
280
252
|
|
|
281
|
-
In Web Streams API,
|
|
282
|
-
|
|
283
|
-
For Scrcpy, usually all streams are originated from the same ADB connection (either USB or TCP), so it's important to always read from all streams, even if you don't care about their data.
|
|
253
|
+
In Web Streams API, pipes will block its upstream when downstream's queue is full (back-pressure mechanism). If multiple streams are separated from the same source (for example, all Scrcpy streams are from the same USB or TCP connection), blocking one stream means blocking all of them, so it's important to always read from all streams, even if you don't care about their data.
|
|
284
254
|
|
|
285
255
|
```ts
|
|
286
256
|
// when using `AdbScrcpyClient`
|
|
@@ -290,7 +260,7 @@ stdout
|
|
|
290
260
|
write: (line) => {
|
|
291
261
|
// Handle or ignore the stdout line
|
|
292
262
|
},
|
|
293
|
-
})
|
|
263
|
+
})
|
|
294
264
|
)
|
|
295
265
|
.catch(() => {})
|
|
296
266
|
.then(() => {
|
|
@@ -298,47 +268,51 @@ stdout
|
|
|
298
268
|
});
|
|
299
269
|
|
|
300
270
|
videoPacketStream
|
|
301
|
-
.pipeTo(
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
271
|
+
.pipeTo(
|
|
272
|
+
new WritableStream<ScrcpyVideoStreamPacket>({
|
|
273
|
+
write: (packet) => {
|
|
274
|
+
// Handle or ignore the video packet
|
|
275
|
+
},
|
|
276
|
+
})
|
|
277
|
+
)
|
|
306
278
|
.catch(() => {});
|
|
307
279
|
|
|
308
280
|
deviceMessageStream
|
|
309
|
-
.pipeTo(
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
281
|
+
.pipeTo(
|
|
282
|
+
new WritableStream<ScrcpyDeviceMessage>({
|
|
283
|
+
write: (message) => {
|
|
284
|
+
// Handle or ignore the device message
|
|
285
|
+
},
|
|
286
|
+
})
|
|
287
|
+
)
|
|
314
288
|
.catch(() => {});
|
|
315
289
|
```
|
|
316
290
|
|
|
317
|
-
## Video stream
|
|
291
|
+
## Video/audio stream
|
|
318
292
|
|
|
319
|
-
The data from `
|
|
293
|
+
The data from `createMediaStreamTransformer()` has two types: `configuration` and `data`.
|
|
320
294
|
|
|
321
295
|
```ts
|
|
322
|
-
export interface
|
|
323
|
-
type:
|
|
324
|
-
data:
|
|
296
|
+
export interface ScrcpyMediaStreamConfigurationPacket {
|
|
297
|
+
type: "configuration";
|
|
298
|
+
data: Uint8Array;
|
|
325
299
|
}
|
|
326
300
|
|
|
327
|
-
export interface
|
|
328
|
-
type:
|
|
329
|
-
keyframe?: boolean
|
|
330
|
-
pts?: bigint
|
|
301
|
+
export interface ScrcpyMediaStreamDataPacket {
|
|
302
|
+
type: "data";
|
|
303
|
+
keyframe?: boolean;
|
|
304
|
+
pts?: bigint;
|
|
331
305
|
data: Uint8Array;
|
|
332
306
|
}
|
|
333
307
|
```
|
|
334
308
|
|
|
335
|
-
When `sendFrameMeta: false` is set,
|
|
309
|
+
When `sendFrameMeta: false` is set, there will be no `configuration` packets, and no `keyframe` and `pts` fields in `data` packets. It's commonly used with decoders that can parse the media stream itself like FFmpeg, or saved unprocessed.
|
|
336
310
|
|
|
337
|
-
Otherwise, both `configuration` and `
|
|
311
|
+
Otherwise, both `configuration` and `data` packets are available.
|
|
338
312
|
|
|
339
|
-
|
|
340
|
-
|
|
313
|
+
- `configuration` packet will be the first packet, and contains codec information. It will occasionally be sent again if the stream configuration changes.
|
|
314
|
+
- `pts` (and `keyframe` field from server version 1.23) fields in `data` packets are available to help decode the stream.
|
|
341
315
|
|
|
342
316
|
## Decode video stream
|
|
343
317
|
|
|
344
|
-
`@yume-chan/scrcpy-decoder-tinyh264` and `@yume-chan/scrcpy-decoder-webcodecs` can be used to decode and render the video stream in
|
|
318
|
+
`@yume-chan/scrcpy-decoder-tinyh264` and `@yume-chan/scrcpy-decoder-webcodecs` can be used to decode and render the video stream in browsers. Refer to their README files for compatibility and usage information.
|
package/bin/scrcpy-server
CHANGED
|
Binary file
|
package/bin/version.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '
|
|
1
|
+
export default '2.0';
|
package/bin/version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export default '
|
|
1
|
+
export default '2.0';
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
export declare enum AndroidAv1Profile {
|
|
2
|
+
Main8 = 1,
|
|
3
|
+
Main10 = 2,
|
|
4
|
+
Main10Hdr10 = 4096,
|
|
5
|
+
Main10Hdr10Plus = 8192
|
|
6
|
+
}
|
|
7
|
+
export declare enum AndroidAv1Level {
|
|
8
|
+
Level2 = 1,
|
|
9
|
+
Level21 = 2,
|
|
10
|
+
Level22 = 4,
|
|
11
|
+
Level23 = 8,
|
|
12
|
+
Level3 = 16,
|
|
13
|
+
Level31 = 32,
|
|
14
|
+
Level32 = 64,
|
|
15
|
+
Level33 = 128,
|
|
16
|
+
Level4 = 256,
|
|
17
|
+
Level41 = 512,
|
|
18
|
+
Level42 = 1024,
|
|
19
|
+
Level43 = 2048,
|
|
20
|
+
Level5 = 4096,
|
|
21
|
+
Level51 = 8192,
|
|
22
|
+
Level52 = 16384,
|
|
23
|
+
Level53 = 32768,
|
|
24
|
+
Level6 = 65536,
|
|
25
|
+
Level61 = 131072,
|
|
26
|
+
Level62 = 262144,
|
|
27
|
+
Level63 = 524288,
|
|
28
|
+
Level7 = 1048576,
|
|
29
|
+
Level71 = 2097152,
|
|
30
|
+
Level72 = 4194304,
|
|
31
|
+
Level73 = 8388608
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=av1.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"av1.d.ts","sourceRoot":"","sources":["../../src/codec/av1.ts"],"names":[],"mappings":"AAAA,oBAAY,iBAAiB;IACzB,KAAK,IAAS;IACd,MAAM,IAAS;IACf,WAAW,OAAU;IACrB,eAAe,OAAU;CAC5B;AAED,oBAAY,eAAe;IACvB,MAAM,IAAS;IACf,OAAO,IAAS;IAChB,OAAO,IAAS;IAChB,OAAO,IAAS;IAChB,MAAM,KAAS;IACf,OAAO,KAAS;IAChB,OAAO,KAAS;IAChB,OAAO,MAAS;IAChB,MAAM,MAAS;IACf,OAAO,MAAS;IAChB,OAAO,OAAU;IACjB,OAAO,OAAU;IACjB,MAAM,OAAU;IAChB,OAAO,OAAU;IACjB,OAAO,QAAU;IACjB,OAAO,QAAU;IACjB,MAAM,QAAU;IAChB,OAAO,SAAU;IACjB,OAAO,SAAU;IACjB,OAAO,SAAU;IACjB,MAAM,UAAU;IAChB,OAAO,UAAU;IACjB,OAAO,UAAU;IACjB,OAAO,UAAU;CACpB"}
|