mirror of
https://github.com/yume-chan/ya-webadb.git
synced 2025-10-06 03:50:18 +02:00
wip: add scrcpy module
This commit is contained in:
parent
20b914fe6f
commit
c02dea23e8
31 changed files with 2678 additions and 10 deletions
1
.vscode/settings.json
vendored
1
.vscode/settings.json
vendored
|
@ -60,6 +60,7 @@
|
||||||
"typeof",
|
"typeof",
|
||||||
"uifabric",
|
"uifabric",
|
||||||
"webadb",
|
"webadb",
|
||||||
|
"webcodecs",
|
||||||
"webpackbar",
|
"webpackbar",
|
||||||
"websockify",
|
"websockify",
|
||||||
"webusb",
|
"webusb",
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
"@yume-chan/adb-backend-ws": "^0.0.9",
|
"@yume-chan/adb-backend-ws": "^0.0.9",
|
||||||
"@yume-chan/async": "^2.1.4",
|
"@yume-chan/async": "^2.1.4",
|
||||||
"@yume-chan/event": "^0.0.9",
|
"@yume-chan/event": "^0.0.9",
|
||||||
|
"@yume-chan/scrcpy": "^0.0.9",
|
||||||
"@yume-chan/struct": "^0.0.9",
|
"@yume-chan/struct": "^0.0.9",
|
||||||
"mobx": "^6.3.3",
|
"mobx": "^6.3.3",
|
||||||
"mobx-react-lite": "^3.2.1",
|
"mobx-react-lite": "^3.2.1",
|
||||||
|
@ -39,6 +40,7 @@
|
||||||
"@types/react": "17.0.27",
|
"@types/react": "17.0.27",
|
||||||
"copy-webpack-plugin": "^9.0.1",
|
"copy-webpack-plugin": "^9.0.1",
|
||||||
"eslint": "7.32.0",
|
"eslint": "7.32.0",
|
||||||
|
"file-loader": "^6.2.0",
|
||||||
"eslint-config-next": "^11.1.3-canary.52",
|
"eslint-config-next": "^11.1.3-canary.52",
|
||||||
"typescript": "^4.4.3"
|
"typescript": "^4.4.3"
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,6 +29,10 @@ const ROUTES = [
|
||||||
url: '/shell',
|
url: '/shell',
|
||||||
name: 'Interactive Shell',
|
name: 'Interactive Shell',
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
url: '/scrcpy',
|
||||||
|
name: 'Scrcpy',
|
||||||
|
},
|
||||||
{
|
{
|
||||||
url: '/tcpip',
|
url: '/tcpip',
|
||||||
name: 'ADB over WiFi',
|
name: 'ADB over WiFi',
|
||||||
|
|
|
@ -43,7 +43,7 @@ One USB device can only be accessed by one application at a time. Please make su
|
||||||
Extra software is required to bridge the connection. See <ExternalLink href="https://github.com/yume-chan/ya-webadb/discussions/245#discussioncomment-384030">this discussion</ExternalLink>.
|
Extra software is required to bridge the connection. See <ExternalLink href="https://github.com/yume-chan/ya-webadb/discussions/245#discussioncomment-384030">this discussion</ExternalLink>.
|
||||||
|
|
||||||
export default ({children}) => (
|
export default ({children}) => (
|
||||||
<div style={{ padding: '0 16px' }}>
|
<div style={{ height: '100%', padding: '0 16px', overflow: 'auto' }}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>WebADB</title>
|
<title>WebADB</title>
|
||||||
</Head>
|
</Head>
|
||||||
|
|
94
apps/demo/pages/scrcpy.tsx
Normal file
94
apps/demo/pages/scrcpy.tsx
Normal file
|
@ -0,0 +1,94 @@
|
||||||
|
import { Stack } from "@fluentui/react";
|
||||||
|
import { EventEmitter } from "@yume-chan/event";
|
||||||
|
import serverUrl from 'file-loader!@yume-chan/scrcpy/bin/scrcpy-server';
|
||||||
|
import { observer } from "mobx-react-lite";
|
||||||
|
import { NextPage } from "next";
|
||||||
|
import Head from "next/head";
|
||||||
|
import React from "react";
|
||||||
|
import { RouteStackProps } from "../utils";
|
||||||
|
|
||||||
|
export const ScrcpyServerVersion = '1.17';
|
||||||
|
|
||||||
|
class FetchWithProgress {
|
||||||
|
public readonly promise: Promise<ArrayBuffer>;
|
||||||
|
|
||||||
|
private _downloaded = 0;
|
||||||
|
public get downloaded() { return this._downloaded; }
|
||||||
|
|
||||||
|
private _total = 0;
|
||||||
|
public get total() { return this._total; }
|
||||||
|
|
||||||
|
private progressEvent = new EventEmitter<[download: number, total: number]>();
|
||||||
|
public get onProgress() { return this.progressEvent.event; }
|
||||||
|
|
||||||
|
public constructor(url: string) {
|
||||||
|
this.promise = this.fetch(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async fetch(url: string) {
|
||||||
|
const response = await window.fetch(url);
|
||||||
|
this._total = Number.parseInt(response.headers.get('Content-Length') ?? '0', 10);
|
||||||
|
this.progressEvent.fire([this._downloaded, this._total]);
|
||||||
|
|
||||||
|
const reader = response.body!.getReader();
|
||||||
|
const chunks: Uint8Array[] = [];
|
||||||
|
while (true) {
|
||||||
|
const result = await reader.read();
|
||||||
|
if (result.done) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chunks.push(result.value);
|
||||||
|
this._downloaded += result.value.byteLength;
|
||||||
|
this.progressEvent.fire([this._downloaded, this._total]);
|
||||||
|
}
|
||||||
|
|
||||||
|
this._total = chunks.reduce((result, item) => result + item.byteLength, 0);
|
||||||
|
const result = new Uint8Array(this._total);
|
||||||
|
let position = 0;
|
||||||
|
for (const chunk of chunks) {
|
||||||
|
result.set(chunk, position);
|
||||||
|
position += chunk.byteLength;
|
||||||
|
}
|
||||||
|
return result.buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let cachedValue: FetchWithProgress | undefined;
|
||||||
|
function fetchServer(onProgress?: (e: [downloaded: number, total: number]) => void) {
|
||||||
|
if (!cachedValue) {
|
||||||
|
cachedValue = new FetchWithProgress(serverUrl);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (onProgress) {
|
||||||
|
cachedValue.onProgress(onProgress);
|
||||||
|
onProgress([cachedValue.downloaded, cachedValue.total]);
|
||||||
|
}
|
||||||
|
|
||||||
|
return cachedValue.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
const DECODERS: { name: string; factory: DecoderConstructor; }[] = [{
|
||||||
|
name: 'TinyH264 (Software)',
|
||||||
|
factory: TinyH264DecoderWrapper,
|
||||||
|
}];
|
||||||
|
|
||||||
|
if (typeof window.VideoDecoder === 'function') {
|
||||||
|
DECODERS.push({
|
||||||
|
name: 'WebCodecs',
|
||||||
|
factory: WebCodecsDecoder,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
const Scrcpy: NextPage = () => {
|
||||||
|
return (
|
||||||
|
<Stack {...RouteStackProps}>
|
||||||
|
<Head>
|
||||||
|
<title>Scrcpy - WebADB</title>
|
||||||
|
</Head>
|
||||||
|
|
||||||
|
|
||||||
|
</Stack>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default observer(Scrcpy);
|
4
apps/demo/types/file-loader.d.ts
vendored
Normal file
4
apps/demo/types/file-loader.d.ts
vendored
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
declare module "file-loader!*" {
|
||||||
|
const url: string;
|
||||||
|
export default url;
|
||||||
|
}
|
429
apps/demo/types/webcodecs.d.ts
vendored
Normal file
429
apps/demo/types/webcodecs.d.ts
vendored
Normal file
|
@ -0,0 +1,429 @@
|
||||||
|
/////////////////////////////
|
||||||
|
/// Window APIs
|
||||||
|
/////////////////////////////
|
||||||
|
|
||||||
|
interface AudioDataCopyToOptions {
|
||||||
|
format?: AudioSampleFormat;
|
||||||
|
frameCount?: number;
|
||||||
|
frameOffset?: number;
|
||||||
|
planeIndex: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioDataInit {
|
||||||
|
data: BufferSource;
|
||||||
|
format: AudioSampleFormat;
|
||||||
|
numberOfChannels: number;
|
||||||
|
numberOfFrames: number;
|
||||||
|
sampleRate: number;
|
||||||
|
timestamp: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioDecoderConfig {
|
||||||
|
codec: string;
|
||||||
|
description?: BufferSource;
|
||||||
|
numberOfChannels: number;
|
||||||
|
sampleRate: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioDecoderInit {
|
||||||
|
error: WebCodecsErrorCallback;
|
||||||
|
output: AudioDataOutputCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioDecoderSupport {
|
||||||
|
config?: AudioDecoderConfig;
|
||||||
|
supported?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioEncoderConfig {
|
||||||
|
bitrate?: number;
|
||||||
|
codec: string;
|
||||||
|
numberOfChannels?: number;
|
||||||
|
sampleRate?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioEncoderInit {
|
||||||
|
error: WebCodecsErrorCallback;
|
||||||
|
output: EncodedAudioChunkOutputCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioEncoderSupport {
|
||||||
|
config?: AudioEncoderConfig;
|
||||||
|
supported?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedAudioChunkInit {
|
||||||
|
data: BufferSource;
|
||||||
|
duration?: number;
|
||||||
|
timestamp: number;
|
||||||
|
type: EncodedAudioChunkType;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedAudioChunkMetadata {
|
||||||
|
decoderConfig?: AudioDecoderConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedVideoChunkInit {
|
||||||
|
data: BufferSource;
|
||||||
|
duration?: number;
|
||||||
|
timestamp: number;
|
||||||
|
type: EncodedVideoChunkType;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedVideoChunkMetadata {
|
||||||
|
alphaSideData?: BufferSource;
|
||||||
|
decoderConfig?: VideoDecoderConfig;
|
||||||
|
svc?: SvcOutputMetadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageDecodeOptions {
|
||||||
|
completeFramesOnly?: boolean;
|
||||||
|
frameIndex?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageDecodeResult {
|
||||||
|
complete: boolean;
|
||||||
|
image: VideoFrame;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageDecoderInit {
|
||||||
|
colorSpaceConversion?: ColorSpaceConversion;
|
||||||
|
data: ImageBufferSource;
|
||||||
|
desiredHeight?: number;
|
||||||
|
desiredWidth?: number;
|
||||||
|
preferAnimation?: boolean;
|
||||||
|
premultiplyAlpha?: PremultiplyAlpha;
|
||||||
|
type: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface PlaneLayout {
|
||||||
|
offset: number;
|
||||||
|
stride: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SvcOutputMetadata {
|
||||||
|
temporalLayerId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoColorSpaceInit {
|
||||||
|
fullRange?: boolean;
|
||||||
|
matrix?: VideoMatrixCoefficients;
|
||||||
|
primaries?: VideoColorPrimaries;
|
||||||
|
transfer?: VideoTransferCharacteristics;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoDecoderConfig {
|
||||||
|
codec: string;
|
||||||
|
codedHeight?: number;
|
||||||
|
codedWidth?: number;
|
||||||
|
colorSpace?: VideoColorSpaceInit;
|
||||||
|
description?: BufferSource;
|
||||||
|
displayAspectHeight?: number;
|
||||||
|
displayAspectWidth?: number;
|
||||||
|
hardwareAcceleration?: HardwareAcceleration;
|
||||||
|
optimizeForLatency?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoDecoderInit {
|
||||||
|
error: WebCodecsErrorCallback;
|
||||||
|
output: VideoFrameOutputCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoDecoderSupport {
|
||||||
|
config?: VideoDecoderConfig;
|
||||||
|
supported?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoEncoderConfig {
|
||||||
|
alpha?: AlphaOption;
|
||||||
|
bitrate?: number;
|
||||||
|
bitrateMode?: BitrateMode;
|
||||||
|
codec: string;
|
||||||
|
displayHeight?: number;
|
||||||
|
displayWidth?: number;
|
||||||
|
framerate?: number;
|
||||||
|
hardwareAcceleration?: HardwareAcceleration;
|
||||||
|
height: number;
|
||||||
|
latencyMode?: LatencyMode;
|
||||||
|
scalabilityMode?: string;
|
||||||
|
width: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoEncoderEncodeOptions {
|
||||||
|
keyFrame?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoEncoderInit {
|
||||||
|
error: WebCodecsErrorCallback;
|
||||||
|
output: EncodedVideoChunkOutputCallback;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoFrameBufferInit {
|
||||||
|
codedHeight: number;
|
||||||
|
codedWidth: number;
|
||||||
|
colorSpace?: VideoColorSpaceInit;
|
||||||
|
displayHeight?: number;
|
||||||
|
displayWidth?: number;
|
||||||
|
duration?: number;
|
||||||
|
format: VideoPixelFormat;
|
||||||
|
layout?: PlaneLayout[];
|
||||||
|
timestamp: number;
|
||||||
|
visibleRect?: DOMRectInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoFrameCopyToOptions {
|
||||||
|
layout?: PlaneLayout[];
|
||||||
|
rect?: DOMRectInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoFrameInit {
|
||||||
|
alpha?: AlphaOption;
|
||||||
|
displayHeight?: number;
|
||||||
|
displayWidth?: number;
|
||||||
|
duration?: number;
|
||||||
|
timestamp?: number;
|
||||||
|
visibleRect?: DOMRectInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface AudioData {
|
||||||
|
readonly duration: number;
|
||||||
|
readonly format: AudioSampleFormat | null;
|
||||||
|
readonly numberOfChannels: number;
|
||||||
|
readonly numberOfFrames: number;
|
||||||
|
readonly sampleRate: number;
|
||||||
|
readonly timestamp: number;
|
||||||
|
allocationSize(options: AudioDataCopyToOptions): number;
|
||||||
|
clone(): AudioData;
|
||||||
|
close(): void;
|
||||||
|
copyTo(destination: BufferSource, options: AudioDataCopyToOptions): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var AudioData: {
|
||||||
|
prototype: AudioData;
|
||||||
|
new(init: AudioDataInit): AudioData;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Available only in secure contexts. */
|
||||||
|
interface AudioDecoder {
|
||||||
|
readonly decodeQueueSize: number;
|
||||||
|
readonly state: CodecState;
|
||||||
|
close(): void;
|
||||||
|
configure(config: AudioDecoderConfig): void;
|
||||||
|
decode(chunk: EncodedAudioChunk): void;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var AudioDecoder: {
|
||||||
|
prototype: AudioDecoder;
|
||||||
|
new(init: AudioDecoderInit): AudioDecoder;
|
||||||
|
isConfigSupported(config: AudioDecoderConfig): Promise<AudioDecoderSupport>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Available only in secure contexts. */
|
||||||
|
interface AudioEncoder {
|
||||||
|
readonly encodeQueueSize: number;
|
||||||
|
readonly state: CodecState;
|
||||||
|
close(): void;
|
||||||
|
configure(config: AudioEncoderConfig): void;
|
||||||
|
encode(data: AudioData): void;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var AudioEncoder: {
|
||||||
|
prototype: AudioEncoder;
|
||||||
|
new(init: AudioEncoderInit): AudioEncoder;
|
||||||
|
isConfigSupported(config: AudioEncoderConfig): Promise<AudioEncoderSupport>;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface EncodedAudioChunk {
|
||||||
|
readonly byteLength: number;
|
||||||
|
readonly duration: number | null;
|
||||||
|
readonly timestamp: number;
|
||||||
|
readonly type: EncodedAudioChunkType;
|
||||||
|
copyTo(destination: BufferSource): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var EncodedAudioChunk: {
|
||||||
|
prototype: EncodedAudioChunk;
|
||||||
|
new(init: EncodedAudioChunkInit): EncodedAudioChunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface EncodedVideoChunk {
|
||||||
|
readonly byteLength: number;
|
||||||
|
readonly duration: number | null;
|
||||||
|
readonly timestamp: number;
|
||||||
|
readonly type: EncodedVideoChunkType;
|
||||||
|
copyTo(destination: BufferSource): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var EncodedVideoChunk: {
|
||||||
|
prototype: EncodedVideoChunk;
|
||||||
|
new(init: EncodedVideoChunkInit): EncodedVideoChunk;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Available only in secure contexts. */
|
||||||
|
interface ImageDecoder {
|
||||||
|
readonly complete: boolean;
|
||||||
|
readonly completed: Promise<undefined>;
|
||||||
|
readonly tracks: ImageTrackList;
|
||||||
|
close(): void;
|
||||||
|
decode(options?: ImageDecodeOptions): Promise<ImageDecodeResult>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var ImageDecoder: {
|
||||||
|
prototype: ImageDecoder;
|
||||||
|
new(init: ImageDecoderInit): ImageDecoder;
|
||||||
|
isTypeSupported(type: string): Promise<boolean>;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ImageTrackEventMap {
|
||||||
|
"change": Event;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ImageTrack extends EventTarget {
|
||||||
|
readonly animated: boolean;
|
||||||
|
readonly frameCount: number;
|
||||||
|
onchange: ((this: ImageTrack, ev: Event) => any) | null;
|
||||||
|
readonly repetitionCount: number;
|
||||||
|
selected: boolean;
|
||||||
|
addEventListener<K extends keyof ImageTrackEventMap>(type: K, listener: (this: ImageTrack, ev: ImageTrackEventMap[K]) => any, options?: boolean | AddEventListenerOptions): void;
|
||||||
|
addEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | AddEventListenerOptions): void;
|
||||||
|
removeEventListener<K extends keyof ImageTrackEventMap>(type: K, listener: (this: ImageTrack, ev: ImageTrackEventMap[K]) => any, options?: boolean | EventListenerOptions): void;
|
||||||
|
removeEventListener(type: string, listener: EventListenerOrEventListenerObject, options?: boolean | EventListenerOptions): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var ImageTrack: {
|
||||||
|
prototype: ImageTrack;
|
||||||
|
new(): ImageTrack;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ImageTrackList {
|
||||||
|
readonly length: number;
|
||||||
|
readonly ready: Promise<undefined>;
|
||||||
|
readonly selectedIndex: number;
|
||||||
|
readonly selectedTrack: ImageTrack | null;
|
||||||
|
[index: number]: ImageTrack;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var ImageTrackList: {
|
||||||
|
prototype: ImageTrackList;
|
||||||
|
new(): ImageTrackList;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface VideoColorSpace {
|
||||||
|
readonly fullRange: boolean | null;
|
||||||
|
readonly matrix: VideoMatrixCoefficients | null;
|
||||||
|
readonly primaries: VideoColorPrimaries | null;
|
||||||
|
readonly transfer: VideoTransferCharacteristics | null;
|
||||||
|
toJSON(): VideoColorSpaceInit;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var VideoColorSpace: {
|
||||||
|
prototype: VideoColorSpace;
|
||||||
|
new(init?: VideoColorSpaceInit): VideoColorSpace;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Available only in secure contexts. */
|
||||||
|
interface VideoDecoder {
|
||||||
|
readonly decodeQueueSize: number;
|
||||||
|
readonly state: CodecState;
|
||||||
|
close(): void;
|
||||||
|
configure(config: VideoDecoderConfig): void;
|
||||||
|
decode(chunk: EncodedVideoChunk): void;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var VideoDecoder: {
|
||||||
|
prototype: VideoDecoder;
|
||||||
|
new(init: VideoDecoderInit): VideoDecoder;
|
||||||
|
isConfigSupported(config: VideoDecoderConfig): Promise<VideoDecoderSupport>;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Available only in secure contexts. */
|
||||||
|
interface VideoEncoder {
|
||||||
|
readonly encodeQueueSize: number;
|
||||||
|
readonly state: CodecState;
|
||||||
|
close(): void;
|
||||||
|
configure(config: VideoEncoderConfig): void;
|
||||||
|
encode(frame: VideoFrame, options?: VideoEncoderEncodeOptions): void;
|
||||||
|
flush(): Promise<void>;
|
||||||
|
reset(): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var VideoEncoder: {
|
||||||
|
prototype: VideoEncoder;
|
||||||
|
new(init: VideoEncoderInit): VideoEncoder;
|
||||||
|
isConfigSupported(config: VideoEncoderConfig): Promise<boolean>;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface VideoFrame {
|
||||||
|
readonly codedHeight: number;
|
||||||
|
readonly codedRect: DOMRectReadOnly | null;
|
||||||
|
readonly codedWidth: number;
|
||||||
|
readonly colorSpace: VideoColorSpace;
|
||||||
|
readonly displayHeight: number;
|
||||||
|
readonly displayWidth: number;
|
||||||
|
readonly duration: number | null;
|
||||||
|
readonly format: VideoPixelFormat | null;
|
||||||
|
readonly timestamp: number | null;
|
||||||
|
readonly visibleRect: DOMRectReadOnly | null;
|
||||||
|
allocationSize(options?: VideoFrameCopyToOptions): number;
|
||||||
|
clone(): VideoFrame;
|
||||||
|
close(): void;
|
||||||
|
copyTo(destination: BufferSource, options?: VideoFrameCopyToOptions): Promise<PlaneLayout[]>;
|
||||||
|
}
|
||||||
|
|
||||||
|
declare var VideoFrame: {
|
||||||
|
prototype: VideoFrame;
|
||||||
|
new(image: CanvasImageSource, init?: VideoFrameInit): VideoFrame;
|
||||||
|
new(data: BufferSource, init: VideoFrameBufferInit): VideoFrame;
|
||||||
|
};
|
||||||
|
|
||||||
|
interface AudioDataOutputCallback {
|
||||||
|
(output: AudioData): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedAudioChunkOutputCallback {
|
||||||
|
(output: EncodedAudioChunk, metadata?: EncodedAudioChunkMetadata): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface EncodedVideoChunkOutputCallback {
|
||||||
|
(chunk: EncodedVideoChunk, metadata?: EncodedVideoChunkMetadata): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface VideoFrameOutputCallback {
|
||||||
|
(output: VideoFrame): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface WebCodecsErrorCallback {
|
||||||
|
(error: DOMException): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HTMLElementTagNameMap {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface HTMLElementDeprecatedTagNameMap {
|
||||||
|
}
|
||||||
|
|
||||||
|
interface SVGElementTagNameMap {
|
||||||
|
}
|
||||||
|
|
||||||
|
/** @deprecated Directly use HTMLElementTagNameMap or SVGElementTagNameMap as appropriate, instead. */
|
||||||
|
type ElementTagNameMap = HTMLElementTagNameMap & Pick<SVGElementTagNameMap, Exclude<keyof SVGElementTagNameMap, keyof HTMLElementTagNameMap>>;
|
||||||
|
|
||||||
|
type ImageBufferSource = BufferSource | ReadableStream;
|
||||||
|
type AlphaOption = "discard" | "keep";
|
||||||
|
type AudioSampleFormat = "f32" | "f32-planar" | "s16" | "s16-planar" | "s32" | "s32-planar" | "u8" | "u8-planar";
|
||||||
|
type CodecState = "closed" | "configured" | "unconfigured";
|
||||||
|
type EncodedAudioChunkType = "delta" | "key";
|
||||||
|
type EncodedVideoChunkType = "delta" | "key";
|
||||||
|
type HardwareAcceleration = "no-preference" | "prefer-hardware" | "prefer-software";
|
||||||
|
type LatencyMode = "quality" | "realtime";
|
||||||
|
type VideoColorPrimaries = "bt470bg" | "bt709" | "smpte170m";
|
||||||
|
type VideoMatrixCoefficients = "bt470bg" | "bt709" | "rgb" | "smpte170m";
|
||||||
|
type VideoPixelFormat = "BGRA" | "BGRX" | "I420" | "I420A" | "I422" | "I444" | "NV12" | "RGBA" | "RGBX";
|
||||||
|
type VideoTransferCharacteristics = "bt709" | "iec61966-2-1" | "smpte170m";
|
13
apps/demo/utils/decoder/types.ts
Normal file
13
apps/demo/utils/decoder/types.ts
Normal file
|
@ -0,0 +1,13 @@
|
||||||
|
import { Disposable } from "@yume-chan/event";
|
||||||
|
import { ValueOrPromise } from "@yume-chan/struct";
|
||||||
|
import { FrameSize } from "@yume-chan/scrcpy";
|
||||||
|
|
||||||
|
export interface Decoder extends Disposable {
|
||||||
|
configure(config: FrameSize): ValueOrPromise<void>;
|
||||||
|
|
||||||
|
decode(data: BufferSource): ValueOrPromise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface DecoderConstructor {
|
||||||
|
new(canvas: HTMLCanvasElement): Decoder;
|
||||||
|
}
|
48
apps/demo/utils/decoder/webcodes-decoder.ts
Normal file
48
apps/demo/utils/decoder/webcodes-decoder.ts
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
|
||||||
|
import { FrameSize } from "@yume-chan/scrcpy";
|
||||||
|
import { ValueOrPromise } from "@yume-chan/struct";
|
||||||
|
import { Decoder } from './types';
|
||||||
|
|
||||||
|
function toHex(value: number) {
|
||||||
|
return value.toString(16).padStart(2, '0').toUpperCase();
|
||||||
|
}
|
||||||
|
|
||||||
|
export class WebCodecsDecoder implements Decoder {
|
||||||
|
private decoder: VideoDecoder;
|
||||||
|
private context: CanvasRenderingContext2D;
|
||||||
|
|
||||||
|
public constructor(canvas: HTMLCanvasElement) {
|
||||||
|
this.context = canvas.getContext('2d')!;
|
||||||
|
this.decoder = new VideoDecoder({
|
||||||
|
output: (frame) => {
|
||||||
|
this.context.drawImage(frame, 0, 0);
|
||||||
|
frame.close();
|
||||||
|
},
|
||||||
|
error() { },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public configure(config: FrameSize): ValueOrPromise<void> {
|
||||||
|
const { sequenceParameterSet: { profile_idc, constraint_set, level_idc } } = config;
|
||||||
|
|
||||||
|
// https://www.rfc-editor.org/rfc/rfc6381#section-3.3
|
||||||
|
// ISO Base Media File Format Name Space
|
||||||
|
const codec = `avc1.${[profile_idc, constraint_set, level_idc].map(toHex).join('')}`;
|
||||||
|
this.decoder.configure({
|
||||||
|
codec: codec,
|
||||||
|
optimizeForLatency: true,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
decode(data: BufferSource): ValueOrPromise<void> {
|
||||||
|
this.decoder.decode(new EncodedVideoChunk({
|
||||||
|
type: 'key',
|
||||||
|
timestamp: 0,
|
||||||
|
data,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
this.decoder.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -182,6 +182,15 @@
|
||||||
"enableParallelism": true,
|
"enableParallelism": true,
|
||||||
"incremental": true,
|
"incremental": true,
|
||||||
"watchForChanges": true
|
"watchForChanges": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"commandKind": "bulk",
|
||||||
|
"name": "postinstall",
|
||||||
|
"summary": "Run all postinstall scripts",
|
||||||
|
"ignoreMissingScript": true,
|
||||||
|
"enableParallelism": true,
|
||||||
|
"ignoreDependencyOrder": true,
|
||||||
|
"safeForSimultaneousRushProcesses": true
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
/**
|
/**
|
||||||
|
|
567
common/config/rush/pnpm-lock.yaml
generated
567
common/config/rush/pnpm-lock.yaml
generated
|
@ -13,20 +13,23 @@ dependencies:
|
||||||
'@rush-temp/adb-backend-ws': file:projects/adb-backend-ws.tgz
|
'@rush-temp/adb-backend-ws': file:projects/adb-backend-ws.tgz
|
||||||
'@rush-temp/demo': file:projects/demo.tgz_@mdx-js+react@1.6.22
|
'@rush-temp/demo': file:projects/demo.tgz_@mdx-js+react@1.6.22
|
||||||
'@rush-temp/event': file:projects/event.tgz
|
'@rush-temp/event': file:projects/event.tgz
|
||||||
|
'@rush-temp/scrcpy': file:projects/scrcpy.tgz
|
||||||
'@rush-temp/struct': file:projects/struct.tgz
|
'@rush-temp/struct': file:projects/struct.tgz
|
||||||
'@rush-temp/ts-package-builder': file:projects/ts-package-builder.tgz
|
'@rush-temp/ts-package-builder': file:projects/ts-package-builder.tgz
|
||||||
'@rush-temp/unofficial-adb-book': file:projects/unofficial-adb-book.tgz_@types+react@17.0.27
|
'@rush-temp/unofficial-adb-book': file:projects/unofficial-adb-book.tgz_@types+react@17.0.27
|
||||||
'@svgr/webpack': 5.5.0
|
'@svgr/webpack': 5.5.0
|
||||||
|
'@types/dom-webcodecs': 0.1.2
|
||||||
'@types/jest': 26.0.24
|
'@types/jest': 26.0.24
|
||||||
'@types/node': 16.9.1
|
'@types/node': 16.9.1
|
||||||
'@types/react': 17.0.27
|
'@types/react': 17.0.27
|
||||||
'@types/w3c-web-usb': 1.0.5
|
'@types/w3c-web-usb': 1.0.5
|
||||||
'@types/wicg-file-system-access': 2020.9.4
|
|
||||||
'@yume-chan/async': 2.1.4
|
'@yume-chan/async': 2.1.4
|
||||||
clsx: 1.1.1
|
clsx: 1.1.1
|
||||||
|
copy-webpack-plugin: 9.0.1
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-next: 11.1.3-canary.52_eslint@7.32.0+next@11.1.2
|
eslint-config-next: 11.1.3-canary.52_eslint@7.32.0+next@11.1.2
|
||||||
file-loader: 6.2.0
|
file-loader: 6.2.0
|
||||||
|
gh-release-fetch: 2.0.4
|
||||||
jest: 26.6.3
|
jest: 26.6.3
|
||||||
json5: 2.2.0
|
json5: 2.2.0
|
||||||
mini-svg-data-uri: 1.3.3
|
mini-svg-data-uri: 1.3.3
|
||||||
|
@ -37,6 +40,7 @@ dependencies:
|
||||||
plantuml-encoder: 1.4.0
|
plantuml-encoder: 1.4.0
|
||||||
react: 17.0.2
|
react: 17.0.2
|
||||||
react-dom: 17.0.2_react@17.0.2
|
react-dom: 17.0.2_react@17.0.2
|
||||||
|
streamsaver: 2.0.5
|
||||||
tinyh264: 0.0.7
|
tinyh264: 0.0.7
|
||||||
tslib: 2.3.1
|
tslib: 2.3.1
|
||||||
unist-util-visit: 2.0.3
|
unist-util-visit: 2.0.3
|
||||||
|
@ -2716,6 +2720,12 @@ packages:
|
||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
|
integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==
|
||||||
|
/@sindresorhus/is/0.7.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-ONhaKPIufzzrlNbqtWFFd+jlnemX6lJAgq9ZeiZtS7I1PIf/la7CW4m83rTXRnVnsMbW2k56pGYu7AUFJD9Pow==
|
||||||
/@sinonjs/commons/1.8.3:
|
/@sinonjs/commons/1.8.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
type-detect: 4.0.8
|
type-detect: 4.0.8
|
||||||
|
@ -2904,6 +2914,24 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==
|
integrity: sha512-K2waXdXBi2302XUdcHcR1jCeU0LL4TD9HRs/gk0N2Xvrht+G/BfJa4QObBQZfhMdxiCpV3COl5Nfq4uKTeTnJA==
|
||||||
|
/@types/decompress/4.2.4:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 16.9.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-/C8kTMRTNiNuWGl5nEyKbPiMv6HA+0RbEXzFhFBEzASM6+oa4tJro9b8nj7eRlOFfuLdzUU+DS/GPDlvvzMOhA==
|
||||||
|
/@types/dom-webcodecs/0.1.2:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-e5DuY7mZedrV8rrgEnm1gPmy4h2x11ryUTnkjmbdR6SWGCS3Qvz1ZJudtBIrbPNEhnpGM634SL7ZHQDz7dsBCg==
|
||||||
|
/@types/download/8.0.1:
|
||||||
|
dependencies:
|
||||||
|
'@types/decompress': 4.2.4
|
||||||
|
'@types/got': 8.3.6
|
||||||
|
'@types/node': 16.9.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-t5DjMD6Y1DxjXtEHl7Kt+nQn9rOmVLYD8p4Swrcc5QpgyqyqR2gXTIK6RwwMnNeFJ+ZIiIW789fQKzCrK7AOFA==
|
||||||
/@types/eslint-scope/3.7.1:
|
/@types/eslint-scope/3.7.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/eslint': 7.28.0
|
'@types/eslint': 7.28.0
|
||||||
|
@ -2943,6 +2971,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
|
integrity: sha512-w+LsMxKyYQm347Otw+IfBXOv9UWVjpHpCDdbBMt8Kz/xbvCYNjP+0qPh91Km3iKfSRLBB0P7fAMf0KHrPu+MyA==
|
||||||
|
/@types/got/8.3.6:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 16.9.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-nvLlj+831dhdm4LR2Ly+HTpdLyBaMynoOr6wpIxS19d/bPeHQxFU5XQ6Gp6ohBpxvCWZM1uHQIC2+ySRH1rGrQ==
|
||||||
/@types/graceful-fs/4.1.5:
|
/@types/graceful-fs/4.1.5:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 15.14.2
|
'@types/node': 15.14.2
|
||||||
|
@ -3000,6 +3034,13 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
|
integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==
|
||||||
|
/@types/node-fetch/2.5.12:
|
||||||
|
dependencies:
|
||||||
|
'@types/node': 16.9.1
|
||||||
|
form-data: 3.0.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-MKgC4dlq4kKNa/mYrwpKfzQMB5X3ee5U6fSprkKpToBqBmX4nFZL9cW5jl6sWn+xpRJ7ypWh2yyqqr8UUCstSw==
|
||||||
/@types/node/15.14.2:
|
/@types/node/15.14.2:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -3050,6 +3091,10 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
|
integrity: sha512-hppQEBDmlwhFAXKJX2KnWLYu5yMfi91yazPb2l+lbJiwW+wdo1gNeRA+3RgNSO39WYX2euey41KEwnqesU2Jew==
|
||||||
|
/@types/semver/7.3.8:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-D/2EJvAlCEtYFEYmmlGwbGXuK886HzyCc3nZX/tkFTQdEU8jZDAgiv08P162yB17y4ZXZoq7yFAnW4GDBb9Now==
|
||||||
/@types/stack-utils/2.0.1:
|
/@types/stack-utils/2.0.1:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -3532,6 +3577,14 @@ packages:
|
||||||
node: '>= 8'
|
node: '>= 8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
integrity: sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==
|
||||||
|
/archive-type/4.0.0:
|
||||||
|
dependencies:
|
||||||
|
file-type: 4.4.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-+S5yIzBW38aWlHJ0nCZ72wRrHXA=
|
||||||
/arg/5.0.0:
|
/arg/5.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -3958,6 +4011,13 @@ packages:
|
||||||
optional: true
|
optional: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==
|
||||||
|
/bl/1.2.3:
|
||||||
|
dependencies:
|
||||||
|
readable-stream: 2.3.7
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-pvcNpa0UU69UT341rO6AYy4FVAIkUHuZXRIWbq+zHnsVcRzDDjIAhGuuYoi0d//cwIwtt4pkpKycWEfjdV+vww==
|
||||||
/bluebird/3.7.2:
|
/bluebird/3.7.2:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -4143,6 +4203,25 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
|
integrity: sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==
|
||||||
|
/buffer-alloc-unsafe/1.1.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
|
||||||
|
/buffer-alloc/1.2.0:
|
||||||
|
dependencies:
|
||||||
|
buffer-alloc-unsafe: 1.1.0
|
||||||
|
buffer-fill: 1.0.0
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
|
||||||
|
/buffer-crc32/0.2.13:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI=
|
||||||
|
/buffer-fill/1.0.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-+PeLdniYiO858gXNY39o5wISKyw=
|
||||||
/buffer-from/1.1.1:
|
/buffer-from/1.1.1:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -4202,6 +4281,18 @@ packages:
|
||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
|
integrity: sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==
|
||||||
|
/cacheable-request/2.1.4:
|
||||||
|
dependencies:
|
||||||
|
clone-response: 1.0.2
|
||||||
|
get-stream: 3.0.0
|
||||||
|
http-cache-semantics: 3.8.1
|
||||||
|
keyv: 3.0.0
|
||||||
|
lowercase-keys: 1.0.0
|
||||||
|
normalize-url: 2.0.1
|
||||||
|
responselike: 1.0.2
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-DYCIAbY0KtM8kd+dC0TcCbkeXD0=
|
||||||
/cacheable-request/6.1.0:
|
/cacheable-request/6.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
clone-response: 1.0.2
|
clone-response: 1.0.2
|
||||||
|
@ -5229,6 +5320,64 @@ packages:
|
||||||
node: '>=4'
|
node: '>=4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
|
integrity: sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=
|
||||||
|
/decompress-tar/4.1.1:
|
||||||
|
dependencies:
|
||||||
|
file-type: 5.2.0
|
||||||
|
is-stream: 1.1.0
|
||||||
|
tar-stream: 1.6.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-JdJMaCrGpB5fESVyxwpCx4Jdj2AagLmv3y58Qy4GE6HMVjWz1FeVQk1Ct4Kye7PftcdOo/7U7UKzYBJgqnGeUQ==
|
||||||
|
/decompress-tarbz2/4.1.1:
|
||||||
|
dependencies:
|
||||||
|
decompress-tar: 4.1.1
|
||||||
|
file-type: 6.2.0
|
||||||
|
is-stream: 1.1.0
|
||||||
|
seek-bzip: 1.0.6
|
||||||
|
unbzip2-stream: 1.4.3
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-s88xLzf1r81ICXLAVQVzaN6ZmX4A6U4z2nMbOwobxkLoIIfjVMBg7TeguTUXkKeXni795B6y5rnvDw7rxhAq9A==
|
||||||
|
/decompress-targz/4.1.1:
|
||||||
|
dependencies:
|
||||||
|
decompress-tar: 4.1.1
|
||||||
|
file-type: 5.2.0
|
||||||
|
is-stream: 1.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-4z81Znfr6chWnRDNfFNqLwPvm4db3WuZkqV+UgXQzSngG3CEKdBkw5jrv3axjjL96glyiiKjsxJG3X6WBZwX3w==
|
||||||
|
/decompress-unzip/4.0.1:
|
||||||
|
dependencies:
|
||||||
|
file-type: 3.9.0
|
||||||
|
get-stream: 2.3.1
|
||||||
|
pify: 2.3.0
|
||||||
|
yauzl: 2.10.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-3qrM39FK6vhVePczroIQ+bSEj2k=
|
||||||
|
/decompress/4.2.1:
|
||||||
|
dependencies:
|
||||||
|
decompress-tar: 4.1.1
|
||||||
|
decompress-tarbz2: 4.1.1
|
||||||
|
decompress-targz: 4.1.1
|
||||||
|
decompress-unzip: 4.0.1
|
||||||
|
graceful-fs: 4.2.6
|
||||||
|
make-dir: 1.3.0
|
||||||
|
pify: 2.3.0
|
||||||
|
strip-dirs: 2.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-e48kc2IjU+2Zw8cTb6VZcJQ3lgVbS4uuB1TfCHbiZIP/haNXm+SVyhu+87jts5/3ROpd82GSVCoNs/z8l4ZOaQ==
|
||||||
/deep-equal/1.1.1:
|
/deep-equal/1.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-arguments: 1.1.0
|
is-arguments: 1.1.0
|
||||||
|
@ -5553,6 +5702,24 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
|
integrity: sha512-QM8q3zDe58hqUqjraQOmzZ1LIH9SWQJTlEKCH4kJ2oQvLZk7RbQXvtDM2XEq3fwkV9CCvvH4LA0AV+ogFsBM2Q==
|
||||||
|
/download/8.0.0:
|
||||||
|
dependencies:
|
||||||
|
archive-type: 4.0.0
|
||||||
|
content-disposition: 0.5.3
|
||||||
|
decompress: 4.2.1
|
||||||
|
ext-name: 5.0.0
|
||||||
|
file-type: 11.1.0
|
||||||
|
filenamify: 3.0.0
|
||||||
|
get-stream: 4.1.0
|
||||||
|
got: 8.3.2
|
||||||
|
make-dir: 2.1.0
|
||||||
|
p-event: 2.3.1
|
||||||
|
pify: 4.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-ASRY5QhDk7FK+XrQtQyvhpDKanLluEEQtWl/J7Lxuf/b+i8RYh997QeXvL85xitrmRKVlx9c7eTrcRdq2GS4eA==
|
||||||
/duplexer/0.1.2:
|
/duplexer/0.1.2:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -6250,6 +6417,23 @@ packages:
|
||||||
node: '>= 0.10.0'
|
node: '>= 0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
|
integrity: sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g==
|
||||||
|
/ext-list/2.2.2:
|
||||||
|
dependencies:
|
||||||
|
mime-db: 1.48.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-u+SQgsubraE6zItfVA0tBuCBhfU9ogSRnsvygI7wht9TS510oLkBRXBsqopeUG/GBOIQyKZO9wjTqIu/sf5zFA==
|
||||||
|
/ext-name/5.0.0:
|
||||||
|
dependencies:
|
||||||
|
ext-list: 2.2.2
|
||||||
|
sort-keys-length: 1.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-yblEwXAbGv1VQDmow7s38W77hzAgJAO50ztBLMcUyUBfxv1HC+LGwtiEN+Co6LtlqT/5uwVOxsD4TNIilWhwdQ==
|
||||||
/extend-shallow/2.0.1:
|
/extend-shallow/2.0.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
is-extendable: 0.1.1
|
is-extendable: 0.1.1
|
||||||
|
@ -6358,6 +6542,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==
|
integrity: sha512-dJd4PiDOFuhe7vk4F80Mba83Vr2QuK86FoxtgPmzBqEJahncp+13YCmfoa53KHCo6OnlXLG7eeMWPfB5CrpVKg==
|
||||||
|
/fd-slicer/1.1.0:
|
||||||
|
dependencies:
|
||||||
|
pend: 1.2.0
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-JcfInLH5B3+IkbvmHY85Dq4lbx4=
|
||||||
/feed/4.2.2:
|
/feed/4.2.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
xml-js: 1.6.11
|
xml-js: 1.6.11
|
||||||
|
@ -6405,11 +6595,57 @@ packages:
|
||||||
webpack: ^4.0.0 || ^5.0.0
|
webpack: ^4.0.0 || ^5.0.0
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
|
integrity: sha512-qo3glqyTa61Ytg4u73GultjHGjdRyig3tG6lPtyX/jOEJvHif9uB0/OCI2Kif6ctF3caQTW2G5gym21oAsI4pw==
|
||||||
|
/file-type/11.1.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-rM0UO7Qm9K7TWTtA6AShI/t7H5BPjDeGVDaNyg9BjHAj3PysKy7+8C8D137R88jnR3rFJZQB/tFgydl5sN5m7g==
|
||||||
|
/file-type/3.9.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-JXoHg4TR24CHvESdEH1SpSZyuek=
|
||||||
|
/file-type/4.4.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-G2AOX8ofvcboDApwxxyNul95BsU=
|
||||||
|
/file-type/5.2.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-LdvqfHP/42No365J3DOMBYwritY=
|
||||||
|
/file-type/6.2.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-YPcTBDV+2Tm0VqjybVd32MHdlEGAtuxS3VAYsumFokDSMG+ROT5wawGlnHDoz7bfMcMDt9hxuXvXwoKUx2fkOg==
|
||||||
/file-uri-to-path/1.0.0:
|
/file-uri-to-path/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
optional: true
|
optional: true
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==
|
||||||
|
/filename-reserved-regex/2.0.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-q/c9+rc10EVECr/qLZHzieu/oik=
|
||||||
|
/filenamify/3.0.0:
|
||||||
|
dependencies:
|
||||||
|
filename-reserved-regex: 2.0.0
|
||||||
|
strip-outer: 1.0.1
|
||||||
|
trim-repeated: 1.0.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-5EFZ//MsvJgXjBAFJ+Bh2YaCTRF/VP1YOmGrgt+KJ4SFRLjI87EIdwLLuT6wQX0I4F9W41xutobzczjsOKlI/g==
|
||||||
/filesize/6.1.0:
|
/filesize/6.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -6588,6 +6824,17 @@ packages:
|
||||||
node: '>= 0.6'
|
node: '>= 0.6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
integrity: sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac=
|
||||||
|
/from2/2.3.0:
|
||||||
|
dependencies:
|
||||||
|
inherits: 2.0.4
|
||||||
|
readable-stream: 2.3.7
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=
|
||||||
|
/fs-constants/1.0.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
|
||||||
/fs-extra/10.0.0:
|
/fs-extra/10.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
graceful-fs: 4.2.6
|
graceful-fs: 4.2.6
|
||||||
|
@ -6669,6 +6916,21 @@ packages:
|
||||||
node: '>=8.0.0'
|
node: '>=8.0.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
|
integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==
|
||||||
|
/get-stream/2.3.1:
|
||||||
|
dependencies:
|
||||||
|
object-assign: 4.1.1
|
||||||
|
pinkie-promise: 2.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-Xzj5PzRgCWZu4BUKBUFn+Rvdld4=
|
||||||
|
/get-stream/3.0.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-jpQ9E1jcN1VQVOy+LtsFqhdO3hQ=
|
||||||
/get-stream/4.1.0:
|
/get-stream/4.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
pump: 3.0.0
|
pump: 3.0.0
|
||||||
|
@ -6706,6 +6968,20 @@ packages:
|
||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
integrity: sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=
|
||||||
|
/gh-release-fetch/2.0.4:
|
||||||
|
dependencies:
|
||||||
|
'@types/download': 8.0.1
|
||||||
|
'@types/node-fetch': 2.5.12
|
||||||
|
'@types/semver': 7.3.8
|
||||||
|
download: 8.0.0
|
||||||
|
make-dir: 3.1.0
|
||||||
|
node-fetch: 2.6.1
|
||||||
|
semver: 7.3.5
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=10'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-PALrCv6MuxEKsj5Oz9G81iU6pxvoxgpSnwbtIqAkQ6m6fioFicNznZUl/aOW92rK2k8cuaM48Rd59G7eV2QsTA==
|
||||||
/github-slugger/1.3.0:
|
/github-slugger/1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
emoji-regex: 6.1.1
|
emoji-regex: 6.1.1
|
||||||
|
@ -6828,6 +7104,30 @@ packages:
|
||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
|
integrity: sha1-9abXDoOV4hyFj7BInWTfAkJNUGw=
|
||||||
|
/got/8.3.2:
|
||||||
|
dependencies:
|
||||||
|
'@sindresorhus/is': 0.7.0
|
||||||
|
cacheable-request: 2.1.4
|
||||||
|
decompress-response: 3.3.0
|
||||||
|
duplexer3: 0.1.4
|
||||||
|
get-stream: 3.0.0
|
||||||
|
into-stream: 3.1.0
|
||||||
|
is-retry-allowed: 1.2.0
|
||||||
|
isurl: 1.0.0
|
||||||
|
lowercase-keys: 1.0.1
|
||||||
|
mimic-response: 1.0.1
|
||||||
|
p-cancelable: 0.4.1
|
||||||
|
p-timeout: 2.0.1
|
||||||
|
pify: 3.0.0
|
||||||
|
safe-buffer: 5.2.1
|
||||||
|
timed-out: 4.0.1
|
||||||
|
url-parse-lax: 3.0.0
|
||||||
|
url-to-options: 1.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-qjUJ5U/hawxosMryILofZCkm3C84PLJS/0grRIpjAwu+Lkxxj5cxeCU25BG0/3mDSpXKTyZr8oh8wIgLaH0QCw==
|
||||||
/got/9.6.0:
|
/got/9.6.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@sindresorhus/is': 0.14.0
|
'@sindresorhus/is': 0.14.0
|
||||||
|
@ -6903,12 +7203,22 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
|
||||||
|
/has-symbol-support-x/1.4.2:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-3ToOva++HaW+eCpgqZrCfN51IPB+7bJNVT6CUATzueB5Heb8o6Nam0V3HG5dlDvZU1Gn5QLcbahiKw/XVk5JJw==
|
||||||
/has-symbols/1.0.2:
|
/has-symbols/1.0.2:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
node: '>= 0.4'
|
node: '>= 0.4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
|
integrity: sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
|
||||||
|
/has-to-string-tag-x/1.4.1:
|
||||||
|
dependencies:
|
||||||
|
has-symbol-support-x: 1.4.2
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-vdbKfmw+3LoOYVr+mtxHaX5a96+0f3DljYd8JOqvOLsf5mw2Otda2qCDT9qRqLAhrjyQ0h7ual5nOiASpsGNFw==
|
||||||
/has-tostringtag/1.0.0:
|
/has-tostringtag/1.0.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
has-symbols: 1.0.2
|
has-symbols: 1.0.2
|
||||||
|
@ -7195,6 +7505,10 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
integrity: sha512-gyyPk6rgonLFEDGoeRgQNaEUvdJ4ktTmmUh/h2t7s+M8oPpIPxgNACWa+6ESR57kXstwqPiCut0V8NRpcwgU7A==
|
||||||
|
/http-cache-semantics/3.8.1:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-5ai2iksyV8ZXmnZhHH4rWPoxxistEexSi5936zIQ1bnNTW5VnA85B6P/VpXiRM017IgRvb2kKo1a//y+0wSp3w==
|
||||||
/http-cache-semantics/4.1.0:
|
/http-cache-semantics/4.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -7468,6 +7782,15 @@ packages:
|
||||||
node: '>= 0.10'
|
node: '>= 0.10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
|
integrity: sha512-agE4QfB2Lkp9uICn7BAqoscw4SZP9kTE2hxiFI3jBPmXJfdqiahTbUuKGsMoN2GtqL9AxhYioAcVvgsb1HvRbA==
|
||||||
|
/into-stream/3.1.0:
|
||||||
|
dependencies:
|
||||||
|
from2: 2.3.0
|
||||||
|
p-is-promise: 1.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-lvsKk2wSur1v8XUqF9BWFqvQlMY=
|
||||||
/ip-regex/2.1.0:
|
/ip-regex/2.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -7740,6 +8063,10 @@ packages:
|
||||||
node: '>= 0.4'
|
node: '>= 0.4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
|
integrity: sha512-E+zBKpQ2t6MEo1VsonYmluk9NxGrbzpeeLC2xIViuO2EjU2xsXsBPwTr3Ykv9l08UYEVEdWeRZNouaZqF6RN0w==
|
||||||
|
/is-natural-number/4.0.1:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-q5124dtM7VHjXeDHLr7PCfc0zeg=
|
||||||
/is-negative-zero/2.0.1:
|
/is-negative-zero/2.0.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -7784,6 +8111,10 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
|
integrity: sha512-drqDG3cbczxxEJRoOXcOjtdp1J/lyp1mNn0xaznRs8+muBhgQcrnbspox5X5fOw0HnMnbfDzvnEMEtqDEJEo8w==
|
||||||
|
/is-object/1.0.2:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-2rRIahhZr2UWb45fIOuvZGpFtz0TyOZLf32KxBbSoUCeZR495zCKlWUKKUByk3geS2eAs7ZAABt0Y/Rx0GiQGA==
|
||||||
/is-path-cwd/2.2.0:
|
/is-path-cwd/2.2.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -7812,6 +8143,12 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
integrity: sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==
|
||||||
|
/is-plain-obj/1.1.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
|
||||||
/is-plain-obj/2.1.0:
|
/is-plain-obj/2.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -7858,6 +8195,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
|
integrity: sha512-qgDYXFSR5WvEfuS5dMj6oTMEbrrSaM0CrFk2Yiq/gXnBvD9pMa2jGXxyhGLfvhZpuMZe18CJpFxAt3CRs42NMg==
|
||||||
|
/is-retry-allowed/1.2.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-RUbUeKwvm3XG2VYamhJL1xFktgjvPzL0Hq8C+6yrWIswDy3BIXGqCxhxkc30N9jqK311gVU137K8Ei55/zVJRg==
|
||||||
/is-root/2.1.0:
|
/is-root/2.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -8028,6 +8371,15 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
|
integrity: sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw==
|
||||||
|
/isurl/1.0.0:
|
||||||
|
dependencies:
|
||||||
|
has-to-string-tag-x: 1.4.1
|
||||||
|
is-object: 1.0.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-1P/yWsxPlDtn7QeRD+ULKQPaIaN6yF368GZ2vDfv0AL0NwpStafjWCDDdn0k8wgFMWpVAqG7oJhxHnlud42i9w==
|
||||||
/jest-changed-files/26.6.2:
|
/jest-changed-files/26.6.2:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@jest/types': 26.6.2
|
'@jest/types': 26.6.2
|
||||||
|
@ -8605,6 +8957,12 @@ packages:
|
||||||
node: '>=4.0'
|
node: '>=4.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==
|
integrity: sha512-uP5vu8xfy2F9A6LGC22KO7e2/vGTS1MhP+18f++ZNlf0Ohaxbc9nIEwHAsejlJKyzfZzU5UIhe5ItYkitcZnZA==
|
||||||
|
/keyv/3.0.0:
|
||||||
|
dependencies:
|
||||||
|
json-buffer: 3.0.0
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-eguHnq22OE3uVoSYG0LVWNP+4ppamWr9+zWBe1bsNcovIMy6huUJFPgy4mGwCd/rnl3vOLGW1MTlu4c57CT1xA==
|
||||||
/keyv/3.1.0:
|
/keyv/3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
json-buffer: 3.0.0
|
json-buffer: 3.0.0
|
||||||
|
@ -8889,6 +9247,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
|
integrity: sha512-7fm3l3NAF9WfN6W3JOmf5drwpVqX78JtoGJ3A6W0a6ZnldM41w2fV5D490psKFTpMds8TJse/eHLFFsNHHjHgg==
|
||||||
|
/lowercase-keys/1.0.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-TjNms55/VFfjXxMkvfb4jQv8cwY=
|
||||||
/lowercase-keys/1.0.1:
|
/lowercase-keys/1.0.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -8909,6 +9273,23 @@ packages:
|
||||||
node: '>=10'
|
node: '>=10'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==
|
||||||
|
/make-dir/1.3.0:
|
||||||
|
dependencies:
|
||||||
|
pify: 3.0.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-2w31R7SJtieJJnQtGc7RVL2StM2vGYVfqUOvUDxH6bC6aJTxPxTF0GnIgCyu7tjockiUWAYQRbxa7vKn34s5sQ==
|
||||||
|
/make-dir/2.1.0:
|
||||||
|
dependencies:
|
||||||
|
pify: 4.0.1
|
||||||
|
semver: 5.7.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==
|
||||||
/make-dir/3.1.0:
|
/make-dir/3.1.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
semver: 6.3.0
|
semver: 6.3.0
|
||||||
|
@ -9568,6 +9949,16 @@ packages:
|
||||||
node: '>=0.10.0'
|
node: '>=0.10.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
|
integrity: sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=
|
||||||
|
/normalize-url/2.0.1:
|
||||||
|
dependencies:
|
||||||
|
prepend-http: 2.0.0
|
||||||
|
query-string: 5.1.1
|
||||||
|
sort-keys: 2.0.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-D6MUW4K/VzoJ4rJ01JFKxDrtY1v9wrgzCX5f2qj/lzH1m/lW6MhUZFKerVsnyjOhOsYzI9Kqqak+10l4LvLpMw==
|
||||||
/normalize-url/4.5.1:
|
/normalize-url/4.5.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -9815,6 +10206,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
|
integrity: sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=
|
||||||
|
/p-cancelable/0.4.1:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-HNa1A8LvB1kie7cERyy21VNeHb2CWJJYqyyC2o3klWFfMGlFmWv2Z7sFgZH8ZiaYL95ydToKTFVXgMV/Os0bBQ==
|
||||||
/p-cancelable/1.1.0:
|
/p-cancelable/1.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -9827,12 +10224,26 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==
|
integrity: sha512-ycIL2+1V32th+8scbpTvyHNaHe02z0sjgh91XXjAk+ZeXoPN4Z46DVUnzdso0aX4KckKw0FNNFHdjZ2UsZvxiA==
|
||||||
|
/p-event/2.3.1:
|
||||||
|
dependencies:
|
||||||
|
p-timeout: 2.0.1
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=6'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-NQCqOFhbpVTMX4qMe8PF8lbGtzZ+LCiN7pcNrb/413Na7+TRoe1xkKUzuWa/YEJdGQ0FvKtj35EEbDoVPO2kbA==
|
||||||
/p-finally/1.0.0:
|
/p-finally/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
node: '>=4'
|
node: '>=4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
integrity: sha1-P7z7FbiZpEEjs0ttzBi3JDNqLK4=
|
||||||
|
/p-is-promise/1.1.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-nJRWmJ6fZYgBewQ01WCXZ1w9oF4=
|
||||||
/p-limit/1.3.0:
|
/p-limit/1.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
p-try: 1.0.0
|
p-try: 1.0.0
|
||||||
|
@ -9911,6 +10322,14 @@ packages:
|
||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==
|
integrity: sha512-XE6G4+YTTkT2a0UWb2kjZe8xNwf8bIbnqpc/IS/idOBVhyves0mK5OJgeocjx7q5pvX/6m23xuzVPYT1uGM73w==
|
||||||
|
/p-timeout/2.0.1:
|
||||||
|
dependencies:
|
||||||
|
p-finally: 1.0.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-88em58dDVB/KzPEx1X0N3LwFfYZPyDc4B6eF38M1rk9VTZMbxXXgjugz8mmwpS9Ox4BDZ+t6t3QP5+/gazweIA==
|
||||||
/p-try/1.0.0:
|
/p-try/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -10115,6 +10534,10 @@ packages:
|
||||||
node: '>=0.12'
|
node: '>=0.12'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==
|
integrity: sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==
|
||||||
|
/pend/1.2.0:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-elfrVQpng/kRUzH89GY9XI4AelA=
|
||||||
/picomatch/2.3.0:
|
/picomatch/2.3.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -10892,6 +11315,16 @@ packages:
|
||||||
node: '>=0.6'
|
node: '>=0.6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
integrity: sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ==
|
||||||
|
/query-string/5.1.1:
|
||||||
|
dependencies:
|
||||||
|
decode-uri-component: 0.2.0
|
||||||
|
object-assign: 4.1.1
|
||||||
|
strict-uri-encode: 1.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-gjWOsm2SoGlgLEdAGt7a6slVOk9mGiXmPFMqrEhLQ68rhQuBnpfs3+EmlvqKyxnCo9/PPlF+9MtY02S1aFg+Jw==
|
||||||
/querystring-es3/0.2.1:
|
/querystring-es3/0.2.1:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -11734,6 +12167,13 @@ packages:
|
||||||
node: '>=4'
|
node: '>=4'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
|
integrity: sha512-vfD3pmTzGpufjScBh50YHKzEu2lxBWhVEHsNGoEXmCmn2hKGfeNLYMzCJpe8cD7gqX7TJluOVpBkAequ6dgMmA==
|
||||||
|
/seek-bzip/1.0.6:
|
||||||
|
dependencies:
|
||||||
|
commander: 2.20.3
|
||||||
|
dev: false
|
||||||
|
hasBin: true
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-e1QtP3YL5tWww8uKaOCQ18UxIT2laNBXHjV/S2WYCiK4udiv8lkG89KRIoCjUagnAmCBurjF4zEVX2ByBbnCjQ==
|
||||||
/select-hose/2.0.0:
|
/select-hose/2.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -12044,6 +12484,30 @@ packages:
|
||||||
node: '>= 6.3.0'
|
node: '>= 6.3.0'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-YP5W/h4Sid/YP7Lp87ejJ5jP13/Mtqt2vx33XyhO+IAugKlufRPbOrPlIiEUuxmpNBSBd3EeeQpFhdu3RfI2Ag==
|
integrity: sha512-YP5W/h4Sid/YP7Lp87ejJ5jP13/Mtqt2vx33XyhO+IAugKlufRPbOrPlIiEUuxmpNBSBd3EeeQpFhdu3RfI2Ag==
|
||||||
|
/sort-keys-length/1.0.1:
|
||||||
|
dependencies:
|
||||||
|
sort-keys: 1.1.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-nLb09OnkgVWmqgZx7dM2/xR5oYg=
|
||||||
|
/sort-keys/1.1.2:
|
||||||
|
dependencies:
|
||||||
|
is-plain-obj: 1.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-RBttTTRnmPG05J6JIK37oOVD+a0=
|
||||||
|
/sort-keys/2.0.0:
|
||||||
|
dependencies:
|
||||||
|
is-plain-obj: 1.1.0
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-ZYU1WEhh7JfXMNbPQYIuH1ZoQSg=
|
||||||
/source-list-map/2.0.1:
|
/source-list-map/2.0.1:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -12254,6 +12718,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-KIWtBvi8A6FiFZGNSyuIZRZM6C8AvnWTiCx/TYa7so420vC5sQwcBKkdqInuGWoWMfeWy/P+/cRqMtWVf4RW9w==
|
integrity: sha512-KIWtBvi8A6FiFZGNSyuIZRZM6C8AvnWTiCx/TYa7so420vC5sQwcBKkdqInuGWoWMfeWy/P+/cRqMtWVf4RW9w==
|
||||||
|
/strict-uri-encode/1.1.0:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-J5siXfHVgrH1TmWt3UNS4Y+qBxM=
|
||||||
/string-hash/1.1.3:
|
/string-hash/1.1.3:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -12396,6 +12866,12 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
|
integrity: sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==
|
||||||
|
/strip-dirs/2.1.0:
|
||||||
|
dependencies:
|
||||||
|
is-natural-number: 4.0.1
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-JOCxOeKLm2CAS73y/U4ZeZPTkE+gNVCzKt7Eox84Iej1LT/2pTWYpZKJuxwQpvX1LiZb1xokNR7RLfuBAa7T3g==
|
||||||
/strip-eof/1.0.0:
|
/strip-eof/1.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -12420,6 +12896,14 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==
|
||||||
|
/strip-outer/1.0.1:
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 1.0.5
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==
|
||||||
/style-to-object/0.3.0:
|
/style-to-object/0.3.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
inline-style-parser: 0.1.1
|
inline-style-parser: 0.1.1
|
||||||
|
@ -12582,6 +13066,20 @@ packages:
|
||||||
node: '>=6'
|
node: '>=6'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
|
integrity: sha512-FBk4IesMV1rBxX2tfiK8RAmogtWn53puLOQlvO8XuwlgxcYbP4mVPS9Ph4aeamSyyVjOl24aYWAuc8U5kCVwMw==
|
||||||
|
/tar-stream/1.6.2:
|
||||||
|
dependencies:
|
||||||
|
bl: 1.2.3
|
||||||
|
buffer-alloc: 1.2.0
|
||||||
|
end-of-stream: 1.4.4
|
||||||
|
fs-constants: 1.0.0
|
||||||
|
readable-stream: 2.3.7
|
||||||
|
to-buffer: 1.1.1
|
||||||
|
xtend: 4.0.2
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 0.8.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A==
|
||||||
/terminal-link/2.1.1:
|
/terminal-link/2.1.1:
|
||||||
dependencies:
|
dependencies:
|
||||||
ansi-escapes: 4.3.2
|
ansi-escapes: 4.3.2
|
||||||
|
@ -12647,10 +13145,20 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
|
integrity: sha512-fcwX4mndzpLQKBS1DVYhGAcYaYt7vsHNIvQV+WXMvnow5cgjPphq5CaayLaGsjRdSCKZFNGt7/GYAuXaNOiYCA==
|
||||||
|
/through/2.3.8:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=
|
||||||
/thunky/1.1.0:
|
/thunky/1.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
|
integrity: sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==
|
||||||
|
/timed-out/4.0.1:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-8y6srFoXW+ol1/q1Zas+2HQe9W8=
|
||||||
/timers-browserify/2.0.12:
|
/timers-browserify/2.0.12:
|
||||||
dependencies:
|
dependencies:
|
||||||
setimmediate: 1.0.5
|
setimmediate: 1.0.5
|
||||||
|
@ -12683,6 +13191,10 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
integrity: sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=
|
||||||
|
/to-buffer/1.1.1:
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg==
|
||||||
/to-fast-properties/2.0.0:
|
/to-fast-properties/2.0.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -12767,6 +13279,14 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
|
integrity: sha512-15Ih7phfcdP5YxqiB+iDtLoaTz4Nd35+IiAv0kQ5FNKHzXgdWqPoTIqEDDJmXceQt4JZk6lVPT8lnDlPpGDppw==
|
||||||
|
/trim-repeated/1.0.0:
|
||||||
|
dependencies:
|
||||||
|
escape-string-regexp: 1.0.5
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>=0.10.0'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-42RqLqTokTEr9+rObPsFOAvAHCE=
|
||||||
/trim-trailing-lines/1.1.4:
|
/trim-trailing-lines/1.1.4:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
|
@ -12948,6 +13468,13 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
|
integrity: sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==
|
||||||
|
/unbzip2-stream/1.4.3:
|
||||||
|
dependencies:
|
||||||
|
buffer: 5.6.0
|
||||||
|
through: 2.3.8
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-mlExGW4w71ebDJviH16lQLtZS32VKqsSfk80GCfUlwT/4/hNRFsoscrF/c++9xinkMzECL1uL9DDwXqFWkruPg==
|
||||||
/unherit/1.1.3:
|
/unherit/1.1.3:
|
||||||
dependencies:
|
dependencies:
|
||||||
inherits: 2.0.4
|
inherits: 2.0.4
|
||||||
|
@ -13194,6 +13721,12 @@ packages:
|
||||||
dev: false
|
dev: false
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==
|
integrity: sha512-HOfCOUJt7iSYzEx/UqgtwKRMC6EU91NFhsCHMv9oM03VJcVo2Qrp8T8kI9D7amFf1cu+/3CEhgb3rF9zL7k85Q==
|
||||||
|
/url-to-options/1.0.1:
|
||||||
|
dev: false
|
||||||
|
engines:
|
||||||
|
node: '>= 4'
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-FQWgOiiaSMvXpDTvuu7FBV9WM6k=
|
||||||
/url/0.11.0:
|
/url/0.11.0:
|
||||||
dependencies:
|
dependencies:
|
||||||
punycode: 1.3.2
|
punycode: 1.3.2
|
||||||
|
@ -13912,6 +14445,13 @@ packages:
|
||||||
node: '>=8'
|
node: '>=8'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
|
integrity: sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==
|
||||||
|
/yauzl/2.10.0:
|
||||||
|
dependencies:
|
||||||
|
buffer-crc32: 0.2.13
|
||||||
|
fd-slicer: 1.1.0
|
||||||
|
dev: false
|
||||||
|
resolution:
|
||||||
|
integrity: sha1-x+sXyT4RLLEIb6bY5R+wZnt5pfk=
|
||||||
/yocto-queue/0.1.0:
|
/yocto-queue/0.1.0:
|
||||||
dev: false
|
dev: false
|
||||||
engines:
|
engines:
|
||||||
|
@ -13973,6 +14513,7 @@ packages:
|
||||||
'@fluentui/react-hooks': 8.3.4_b094b78811fc8d2f00a90f13d0251fb6
|
'@fluentui/react-hooks': 8.3.4_b094b78811fc8d2f00a90f13d0251fb6
|
||||||
'@mdx-js/loader': 1.6.22_react@17.0.2
|
'@mdx-js/loader': 1.6.22_react@17.0.2
|
||||||
'@next/mdx': 11.1.2_f56c41adb6190c4680be4a1c0222355d
|
'@next/mdx': 11.1.2_f56c41adb6190c4680be4a1c0222355d
|
||||||
|
'@types/dom-webcodecs': 0.1.2
|
||||||
'@types/filesystem': 0.0.32
|
'@types/filesystem': 0.0.32
|
||||||
'@types/react': 17.0.27
|
'@types/react': 17.0.27
|
||||||
'@types/wicg-file-system-access': 2020.9.4
|
'@types/wicg-file-system-access': 2020.9.4
|
||||||
|
@ -13980,6 +14521,7 @@ packages:
|
||||||
copy-webpack-plugin: 9.0.1
|
copy-webpack-plugin: 9.0.1
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-next: 11.1.3-canary.52_82ad98da5e129ae9d310451a179848d9
|
eslint-config-next: 11.1.3-canary.52_82ad98da5e129ae9d310451a179848d9
|
||||||
|
file-loader: 6.2.0
|
||||||
mobx: 6.3.3
|
mobx: 6.3.3
|
||||||
mobx-react-lite: 3.2.1_8aec6830c9f393111667240500a3b25c
|
mobx-react-lite: 3.2.1_8aec6830c9f393111667240500a3b25c
|
||||||
next: 11.1.2_bd7797d63db473de6e2318609a63c933
|
next: 11.1.2_bd7797d63db473de6e2318609a63c933
|
||||||
|
@ -14000,7 +14542,7 @@ packages:
|
||||||
peerDependencies:
|
peerDependencies:
|
||||||
'@mdx-js/react': '*'
|
'@mdx-js/react': '*'
|
||||||
resolution:
|
resolution:
|
||||||
integrity: sha512-adqQuE89q3q1oZWmQOhxsd1fcXBx1/1W+uaXNPvI2Rz+vpz1CkDacSaZbgm84Ohp2L7yncyD+cJbcB8enibhpQ==
|
integrity: sha512-yQ64kuvfu4zYm4ZajZmSBH/mu4xK54yOuKLfQXbX1UDDxM/Kn3hj2ZWuqXMqrCUf64R1t9PP8/XFKYgsvJkvew==
|
||||||
tarball: file:projects/demo.tgz
|
tarball: file:projects/demo.tgz
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
file:projects/event.tgz:
|
file:projects/event.tgz:
|
||||||
|
@ -14015,6 +14557,19 @@ packages:
|
||||||
integrity: sha512-xKXpC79xXSyXj/rzUHlyCAFT5X9mUejkCcF2DarGiRw+gT7tug6na+EvUz2dZUVCtIzyUJFtuhbS39n0qy0A+g==
|
integrity: sha512-xKXpC79xXSyXj/rzUHlyCAFT5X9mUejkCcF2DarGiRw+gT7tug6na+EvUz2dZUVCtIzyUJFtuhbS39n0qy0A+g==
|
||||||
tarball: file:projects/event.tgz
|
tarball: file:projects/event.tgz
|
||||||
version: 0.0.0
|
version: 0.0.0
|
||||||
|
file:projects/scrcpy.tgz:
|
||||||
|
dependencies:
|
||||||
|
'@yume-chan/async': 2.1.4
|
||||||
|
gh-release-fetch: 2.0.4
|
||||||
|
jest: 26.6.3
|
||||||
|
tslib: 2.3.1
|
||||||
|
typescript: 4.4.3
|
||||||
|
dev: false
|
||||||
|
name: '@rush-temp/scrcpy'
|
||||||
|
resolution:
|
||||||
|
integrity: sha512-46RuBeh15le2Jo335bNRl46u4ZKAVqX7chrduwiY2i1wqP2Uiw7w3pa0Ygkdb3zIbOoZG6FpTX3xPI+MzJAjhQ==
|
||||||
|
tarball: file:projects/scrcpy.tgz
|
||||||
|
version: 0.0.0
|
||||||
file:projects/struct.tgz:
|
file:projects/struct.tgz:
|
||||||
dependencies:
|
dependencies:
|
||||||
'@types/node': 16.9.1
|
'@types/node': 16.9.1
|
||||||
|
@ -14078,20 +14633,23 @@ specifiers:
|
||||||
'@rush-temp/adb-backend-ws': file:./projects/adb-backend-ws.tgz
|
'@rush-temp/adb-backend-ws': file:./projects/adb-backend-ws.tgz
|
||||||
'@rush-temp/demo': file:./projects/demo.tgz
|
'@rush-temp/demo': file:./projects/demo.tgz
|
||||||
'@rush-temp/event': file:./projects/event.tgz
|
'@rush-temp/event': file:./projects/event.tgz
|
||||||
|
'@rush-temp/scrcpy': file:./projects/scrcpy.tgz
|
||||||
'@rush-temp/struct': file:./projects/struct.tgz
|
'@rush-temp/struct': file:./projects/struct.tgz
|
||||||
'@rush-temp/ts-package-builder': file:./projects/ts-package-builder.tgz
|
'@rush-temp/ts-package-builder': file:./projects/ts-package-builder.tgz
|
||||||
'@rush-temp/unofficial-adb-book': file:./projects/unofficial-adb-book.tgz
|
'@rush-temp/unofficial-adb-book': file:./projects/unofficial-adb-book.tgz
|
||||||
'@svgr/webpack': ^5.5.0
|
'@svgr/webpack': ^5.5.0
|
||||||
|
'@types/dom-webcodecs': ^0.1.2
|
||||||
'@types/jest': ^26.0.23
|
'@types/jest': ^26.0.23
|
||||||
'@types/node': ^16.9.1
|
'@types/node': ^16.9.1
|
||||||
'@types/react': ^17.0.27
|
'@types/react': 17.0.27
|
||||||
'@types/w3c-web-usb': ^1.0.4
|
'@types/w3c-web-usb': ^1.0.4
|
||||||
'@types/wicg-file-system-access': ^2020.9.4
|
|
||||||
'@yume-chan/async': ^2.1.4
|
'@yume-chan/async': ^2.1.4
|
||||||
clsx: ^1.1.1
|
clsx: ^1.1.1
|
||||||
|
copy-webpack-plugin: ^9.0.1
|
||||||
eslint: 7.32.0
|
eslint: 7.32.0
|
||||||
eslint-config-next: ^11.1.3-canary.52
|
eslint-config-next: ^11.1.3-canary.52
|
||||||
file-loader: ^6.2.0
|
file-loader: ^6.2.0
|
||||||
|
gh-release-fetch: ^2.0.4
|
||||||
jest: ^26.6.3
|
jest: ^26.6.3
|
||||||
json5: ^2.2.0
|
json5: ^2.2.0
|
||||||
mini-svg-data-uri: ~1.3.3
|
mini-svg-data-uri: ~1.3.3
|
||||||
|
@ -14102,6 +14660,7 @@ specifiers:
|
||||||
plantuml-encoder: ~1.4.0
|
plantuml-encoder: ~1.4.0
|
||||||
react: ^17.0.2
|
react: ^17.0.2
|
||||||
react-dom: ^17.0.2
|
react-dom: ^17.0.2
|
||||||
|
streamsaver: ^2.0.5
|
||||||
tinyh264: ^0.0.7
|
tinyh264: ^0.0.7
|
||||||
tslib: ^2.3.1
|
tslib: ^2.3.1
|
||||||
unist-util-visit: ^2.0.0
|
unist-util-visit: ^2.0.0
|
||||||
|
|
|
@ -42,7 +42,7 @@ function _getRushVersion() {
|
||||||
console.log(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`);
|
console.log(`Using Rush version from environment variable ${RUSH_PREVIEW_VERSION}=${rushPreviewVersion}`);
|
||||||
return rushPreviewVersion;
|
return rushPreviewVersion;
|
||||||
}
|
}
|
||||||
const rushJsonFolder = install_run_1.findRushJsonFolder();
|
const rushJsonFolder = (0, install_run_1.findRushJsonFolder)();
|
||||||
const rushJsonPath = path.join(rushJsonFolder, install_run_1.RUSH_JSON_FILENAME);
|
const rushJsonPath = path.join(rushJsonFolder, install_run_1.RUSH_JSON_FILENAME);
|
||||||
try {
|
try {
|
||||||
const rushJsonContents = fs.readFileSync(rushJsonPath, 'utf-8');
|
const rushJsonContents = fs.readFileSync(rushJsonPath, 'utf-8');
|
||||||
|
@ -76,10 +76,10 @@ function _run() {
|
||||||
}
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
install_run_1.runWithErrorAndStatusCode(() => {
|
(0, install_run_1.runWithErrorAndStatusCode)(() => {
|
||||||
const version = _getRushVersion();
|
const version = _getRushVersion();
|
||||||
console.log(`The rush.json configuration requests Rush version ${version}`);
|
console.log(`The rush.json configuration requests Rush version ${version}`);
|
||||||
return install_run_1.installAndRun(PACKAGE_NAME, version, bin, packageBinArgs);
|
return (0, install_run_1.installAndRun)(PACKAGE_NAME, version, bin, packageBinArgs);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
_run();
|
_run();
|
||||||
|
|
1
libraries/scrcpy/.gitignore
vendored
Normal file
1
libraries/scrcpy/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
bin
|
14
libraries/scrcpy/.npmignore
Normal file
14
libraries/scrcpy/.npmignore
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
.rush
|
||||||
|
|
||||||
|
# Test
|
||||||
|
coverage
|
||||||
|
**/*.spec.ts
|
||||||
|
**/*.spec.js
|
||||||
|
**/*.spec.js.map
|
||||||
|
**/__helpers__
|
||||||
|
jest.config.js
|
||||||
|
|
||||||
|
tsconfig.json
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
21
libraries/scrcpy/LICENSE
Normal file
21
libraries/scrcpy/LICENSE
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
MIT License
|
||||||
|
|
||||||
|
Copyright (c) 2020 Simon Chan
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in all
|
||||||
|
copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||||
|
SOFTWARE.
|
5
libraries/scrcpy/README.md
Normal file
5
libraries/scrcpy/README.md
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
# @yume-chan/scrcpy
|
||||||
|
|
||||||
|
TypeScript implementation of [Scrcpy](https://github.com/Genymobile/scrcpy) client.
|
||||||
|
|
||||||
|
It uses the official Scrcpy server releases.
|
4
libraries/scrcpy/jest.config.js
Normal file
4
libraries/scrcpy/jest.config.js
Normal file
|
@ -0,0 +1,4 @@
|
||||||
|
module.exports = {
|
||||||
|
testMatch: ['<rootDir>/cjs/**/*.spec.js'],
|
||||||
|
testEnvironment: 'node',
|
||||||
|
};
|
48
libraries/scrcpy/package.json
Normal file
48
libraries/scrcpy/package.json
Normal file
|
@ -0,0 +1,48 @@
|
||||||
|
{
|
||||||
|
"name": "@yume-chan/scrcpy",
|
||||||
|
"version": "0.0.9",
|
||||||
|
"description": "TypeScript implementation of Scrcpy.",
|
||||||
|
"keywords": [
|
||||||
|
"adb",
|
||||||
|
"android-phone",
|
||||||
|
"scrcpy"
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"author": {
|
||||||
|
"name": "Simon Chan",
|
||||||
|
"email": "cnsimonchan@live.com",
|
||||||
|
"url": "https://chensi.moe/blog"
|
||||||
|
},
|
||||||
|
"homepage": "https://github.com/yume-chan/ya-webadb/tree/master/packages/scrcpy#readme",
|
||||||
|
"repository": {
|
||||||
|
"type": "git",
|
||||||
|
"url": "git+https://github.com/yume-chan/ya-webadb.git",
|
||||||
|
"directory": "packages/scrcpy"
|
||||||
|
},
|
||||||
|
"bugs": {
|
||||||
|
"url": "https://github.com/yume-chan/ya-webadb/issues"
|
||||||
|
},
|
||||||
|
"main": "cjs/index.js",
|
||||||
|
"module": "esm/index.js",
|
||||||
|
"types": "dts/index.d.ts",
|
||||||
|
"scripts": {
|
||||||
|
"postinstall": "node scripts/fetch-server",
|
||||||
|
"build": "build-ts-package",
|
||||||
|
"build:watch": "build-ts-package --incremental",
|
||||||
|
"test": "jest --coverage",
|
||||||
|
"prepublishOnly": "npm run build"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@yume-chan/adb": "^0.0.9",
|
||||||
|
"@yume-chan/async": "^2.1.4",
|
||||||
|
"@yume-chan/event": "^0.0.9",
|
||||||
|
"@yume-chan/struct": "^0.0.9",
|
||||||
|
"tslib": "^2.3.1"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@yume-chan/ts-package-builder": "^1.0.0",
|
||||||
|
"gh-release-fetch": "^2.0.4",
|
||||||
|
"jest": "^26.6.3",
|
||||||
|
"typescript": "^4.4.3"
|
||||||
|
}
|
||||||
|
}
|
203
libraries/scrcpy/scrcpy.LICENSE
Normal file
203
libraries/scrcpy/scrcpy.LICENSE
Normal file
|
@ -0,0 +1,203 @@
|
||||||
|
|
||||||
|
Apache License
|
||||||
|
Version 2.0, January 2004
|
||||||
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
|
1. Definitions.
|
||||||
|
|
||||||
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
|
other entities that control, are controlled by, or are under common
|
||||||
|
control with that entity. For the purposes of this definition,
|
||||||
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
|
direction or management of such entity, whether by contract or
|
||||||
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
|
including but not limited to software source code, documentation
|
||||||
|
source, and configuration files.
|
||||||
|
|
||||||
|
"Object" form shall mean any form resulting from mechanical
|
||||||
|
transformation or translation of a Source form, including but
|
||||||
|
not limited to compiled object code, generated documentation,
|
||||||
|
and conversions to other media types.
|
||||||
|
|
||||||
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
|
Object form, made available under the License, as indicated by a
|
||||||
|
copyright notice that is included in or attached to the work
|
||||||
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
|
form, that is based on (or derived from) the Work and for which the
|
||||||
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
|
of this License, Derivative Works shall not include works that remain
|
||||||
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
|
"Contribution" shall mean any work of authorship, including
|
||||||
|
the original version of the Work and any modifications or additions
|
||||||
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
|
means any form of electronic, verbal, or written communication sent
|
||||||
|
to the Licensor or its representatives, including but not limited to
|
||||||
|
communication on electronic mailing lists, source code control systems,
|
||||||
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
|
excluding communication that is conspicuously marked or otherwise
|
||||||
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
|
(except as stated in this section) patent license to make, have made,
|
||||||
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
|
where such license applies only to those patent claims licensable
|
||||||
|
by such Contributor that are necessarily infringed by their
|
||||||
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
|
institute patent litigation against any entity (including a
|
||||||
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
|
or contributory patent infringement, then any patent licenses
|
||||||
|
granted to You under this License for that Work shall terminate
|
||||||
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
|
modifications, and in Source or Object form, provided that You
|
||||||
|
meet the following conditions:
|
||||||
|
|
||||||
|
(a) You must give any other recipients of the Work or
|
||||||
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
|
(b) You must cause any modified files to carry prominent notices
|
||||||
|
stating that You changed the files; and
|
||||||
|
|
||||||
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
|
that You distribute, all copyright, patent, trademark, and
|
||||||
|
attribution notices from the Source form of the Work,
|
||||||
|
excluding those notices that do not pertain to any part of
|
||||||
|
the Derivative Works; and
|
||||||
|
|
||||||
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
|
distribution, then any Derivative Works that You distribute must
|
||||||
|
include a readable copy of the attribution notices contained
|
||||||
|
within such NOTICE file, excluding those notices that do not
|
||||||
|
pertain to any part of the Derivative Works, in at least one
|
||||||
|
of the following places: within a NOTICE text file distributed
|
||||||
|
as part of the Derivative Works; within the Source form or
|
||||||
|
documentation, if provided along with the Derivative Works; or,
|
||||||
|
within a display generated by the Derivative Works, if and
|
||||||
|
wherever such third-party notices normally appear. The contents
|
||||||
|
of the NOTICE file are for informational purposes only and
|
||||||
|
do not modify the License. You may add Your own attribution
|
||||||
|
notices within Derivative Works that You distribute, alongside
|
||||||
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
|
that such additional attribution notices cannot be construed
|
||||||
|
as modifying the License.
|
||||||
|
|
||||||
|
You may add Your own copyright statement to Your modifications and
|
||||||
|
may provide additional or different license terms and conditions
|
||||||
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
|
the conditions stated in this License.
|
||||||
|
|
||||||
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
|
this License, without any additional terms or conditions.
|
||||||
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
|
the terms of any separate license agreement you may have executed
|
||||||
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
|
except as required for reasonable and customary use in describing the
|
||||||
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
|
implied, including, without limitation, any warranties or conditions
|
||||||
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
|
appropriateness of using or redistributing the Work and assume any
|
||||||
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
|
unless required by applicable law (such as deliberate and grossly
|
||||||
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
|
liable to You for damages, including any direct, indirect, special,
|
||||||
|
incidental, or consequential damages of any character arising as a
|
||||||
|
result of this License or out of the use or inability to use the
|
||||||
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
|
other commercial damages or losses), even if such Contributor
|
||||||
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
|
or other liability obligations and/or rights consistent with this
|
||||||
|
License. However, in accepting such obligations, You may act only
|
||||||
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
|
defend, and hold each Contributor harmless for any liability
|
||||||
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
|
To apply the Apache License to your work, attach the following
|
||||||
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
|
replaced with your own identifying information. (Don't include
|
||||||
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
|
comment syntax for the file format. We also recommend that a
|
||||||
|
file or class name and description of purpose be included on the
|
||||||
|
same "printed page" as the copyright notice for easier
|
||||||
|
identification within third-party archives.
|
||||||
|
|
||||||
|
Copyright (C) 2018 Genymobile
|
||||||
|
Copyright (C) 2018-2021 Romain Vimont
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
26
libraries/scrcpy/scripts/fetch-server.js
Normal file
26
libraries/scrcpy/scripts/fetch-server.js
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
const { fetchVersion } = require('gh-release-fetch');
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs').promises;
|
||||||
|
|
||||||
|
const SERVER_VERSION = '1.19';
|
||||||
|
|
||||||
|
(async () => {
|
||||||
|
console.log('Downloading scrcpy server binary...');
|
||||||
|
|
||||||
|
const binFolder = path.resolve(__dirname, '..', 'bin');
|
||||||
|
|
||||||
|
await fetchVersion({
|
||||||
|
repository: 'Genymobile/scrcpy',
|
||||||
|
version: `v${SERVER_VERSION}`,
|
||||||
|
package: `scrcpy-server-v${SERVER_VERSION}`,
|
||||||
|
destination: binFolder,
|
||||||
|
extract: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
await fs.rename(
|
||||||
|
path.resolve(binFolder, `scrcpy-server-v${SERVER_VERSION}`),
|
||||||
|
path.resolve(binFolder, 'scrcpy-server')
|
||||||
|
);
|
||||||
|
|
||||||
|
fs.writeFile(path.resolve(__dirname, '..', 'src', 'version.ts'), `export const BUNDLED_SERVER_VERSION = "${SERVER_VERSION}";`);
|
||||||
|
})();
|
599
libraries/scrcpy/src/client.ts
Normal file
599
libraries/scrcpy/src/client.ts
Normal file
|
@ -0,0 +1,599 @@
|
||||||
|
import { Adb, AdbBufferedStream, AdbLegacyShell, AdbShell, DataEventEmitter } from '@yume-chan/adb';
|
||||||
|
import { PromiseResolver } from '@yume-chan/async';
|
||||||
|
import { EventEmitter } from '@yume-chan/event';
|
||||||
|
import Struct from '@yume-chan/struct';
|
||||||
|
import { AndroidCodecLevel, AndroidCodecProfile } from './codec';
|
||||||
|
import { ScrcpyClientConnection, ScrcpyClientForwardConnection, ScrcpyClientReverseConnection } from "./connection";
|
||||||
|
import { AndroidKeyEventAction, AndroidMotionEventAction, ScrcpyControlMessageType, ScrcpyInjectKeyCodeControlMessage, ScrcpyInjectTextControlMessage, ScrcpyInjectTouchControlMessage, ScrcpySimpleControlMessage } from './message';
|
||||||
|
import { DEFAULT_SERVER_PATH, pushServer, PushServerOptions } from "./push-server";
|
||||||
|
import { parse_sequence_parameter_set, SequenceParameterSet } from './sps';
|
||||||
|
|
||||||
|
export enum ScrcpyLogLevel {
|
||||||
|
Debug = 'debug',
|
||||||
|
Info = 'info',
|
||||||
|
Warn = 'warn',
|
||||||
|
Error = 'error',
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScrcpyError {
|
||||||
|
type: string;
|
||||||
|
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
stackTrace: string[];
|
||||||
|
}
|
||||||
|
|
||||||
|
interface ScrcpyOutput {
|
||||||
|
level: ScrcpyLogLevel;
|
||||||
|
|
||||||
|
message: string;
|
||||||
|
|
||||||
|
error?: ScrcpyError;
|
||||||
|
}
|
||||||
|
|
||||||
|
class LineReader {
|
||||||
|
private readonly text: string;
|
||||||
|
|
||||||
|
private start = 0;
|
||||||
|
|
||||||
|
private peekLine: string | undefined;
|
||||||
|
|
||||||
|
private peekEnd = 0;
|
||||||
|
|
||||||
|
constructor(text: string) {
|
||||||
|
this.text = text;
|
||||||
|
}
|
||||||
|
|
||||||
|
public next(): string | undefined {
|
||||||
|
let result = this.peek();
|
||||||
|
this.start = this.peekEnd;
|
||||||
|
this.peekEnd = 0;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public peek(): string | undefined {
|
||||||
|
if (this.peekEnd) {
|
||||||
|
return this.peekLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
const index = this.text.indexOf('\n', this.start);
|
||||||
|
if (index === -1) {
|
||||||
|
this.peekLine = undefined;
|
||||||
|
this.peekEnd = this.text.length;
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
|
||||||
|
const line = this.text.substring(this.start, index);
|
||||||
|
this.peekLine = line;
|
||||||
|
this.peekEnd = index + 1;
|
||||||
|
return line;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function* parseScrcpyOutput(text: string): Generator<ScrcpyOutput> {
|
||||||
|
const lines = new LineReader(text);
|
||||||
|
let line: string | undefined;
|
||||||
|
while (line = lines.next()) {
|
||||||
|
if (line === '') {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith('[server] ')) {
|
||||||
|
line = line.substring('[server] '.length);
|
||||||
|
|
||||||
|
if (line.startsWith('DEBUG: ')) {
|
||||||
|
yield {
|
||||||
|
level: ScrcpyLogLevel.Debug,
|
||||||
|
message: line.substring('DEBUG: '.length),
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith('INFO: ')) {
|
||||||
|
yield {
|
||||||
|
level: ScrcpyLogLevel.Info,
|
||||||
|
message: line.substring('INFO: '.length),
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (line.startsWith('ERROR: ')) {
|
||||||
|
line = line.substring('ERROR: '.length);
|
||||||
|
const message = line;
|
||||||
|
|
||||||
|
let error: ScrcpyError | undefined;
|
||||||
|
if (line.startsWith('Exception on thread')) {
|
||||||
|
if (line = lines.next()) {
|
||||||
|
const [errorType, errorMessage] = line.split(': ', 2);
|
||||||
|
const stackTrace: string[] = [];
|
||||||
|
while (line = lines.peek()) {
|
||||||
|
if (line.startsWith('\t')) {
|
||||||
|
stackTrace.push(line.trim());
|
||||||
|
lines.next();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
error = {
|
||||||
|
type: errorType,
|
||||||
|
message: errorMessage,
|
||||||
|
stackTrace,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield {
|
||||||
|
level: ScrcpyLogLevel.Error,
|
||||||
|
message,
|
||||||
|
error,
|
||||||
|
};
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
yield {
|
||||||
|
level: ScrcpyLogLevel.Info,
|
||||||
|
message: line,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum ScrcpyScreenOrientation {
|
||||||
|
Unlocked = -1,
|
||||||
|
Portrait = 0,
|
||||||
|
Landscape = 1,
|
||||||
|
PortraitFlipped = 2,
|
||||||
|
LandscapeFlipped = 3,
|
||||||
|
}
|
||||||
|
|
||||||
|
const Size =
|
||||||
|
new Struct()
|
||||||
|
.uint16('width')
|
||||||
|
.uint16('height');
|
||||||
|
|
||||||
|
const VideoPacket =
|
||||||
|
new Struct()
|
||||||
|
.int64('pts')
|
||||||
|
.uint32('size')
|
||||||
|
.arrayBuffer('data', { lengthField: 'size' });
|
||||||
|
|
||||||
|
export const NoPts = BigInt(-1);
|
||||||
|
|
||||||
|
export type VideoPacket = typeof VideoPacket['TDeserializeResult'];
|
||||||
|
|
||||||
|
const ClipboardMessage =
|
||||||
|
new Struct()
|
||||||
|
.uint32('length')
|
||||||
|
.string('content', { lengthField: 'length' });
|
||||||
|
|
||||||
|
export interface ScrcpyClientOptions {
|
||||||
|
device: Adb;
|
||||||
|
|
||||||
|
path?: string;
|
||||||
|
|
||||||
|
version: string;
|
||||||
|
|
||||||
|
logLevel?: ScrcpyLogLevel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The maximum value of both width and height.
|
||||||
|
*/
|
||||||
|
maxSize?: number | undefined;
|
||||||
|
|
||||||
|
bitRate: number;
|
||||||
|
|
||||||
|
maxFps?: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The orientation of the video stream.
|
||||||
|
*
|
||||||
|
* It will not keep the device screen in specific orientation,
|
||||||
|
* only the captured video will in this orientation.
|
||||||
|
*/
|
||||||
|
orientation?: ScrcpyScreenOrientation;
|
||||||
|
|
||||||
|
tunnelForward?: boolean;
|
||||||
|
|
||||||
|
profile?: AndroidCodecProfile;
|
||||||
|
|
||||||
|
level?: AndroidCodecLevel;
|
||||||
|
|
||||||
|
encoder?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface FrameSize {
|
||||||
|
sequenceParameterSet: SequenceParameterSet;
|
||||||
|
|
||||||
|
width: number;
|
||||||
|
height: number;
|
||||||
|
|
||||||
|
cropLeft: number;
|
||||||
|
cropRight: number;
|
||||||
|
|
||||||
|
cropTop: number;
|
||||||
|
cropBottom: number;
|
||||||
|
|
||||||
|
croppedWidth: number;
|
||||||
|
croppedHeight: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ENCODER_REGEX = /^\s+scrcpy --encoder-name '(.*?)'/;
|
||||||
|
|
||||||
|
export class ScrcpyClient {
|
||||||
|
public static pushServer(
|
||||||
|
device: Adb,
|
||||||
|
file: ArrayBuffer,
|
||||||
|
options?: PushServerOptions
|
||||||
|
) {
|
||||||
|
pushServer(device, file, options);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static async getEncoders(options: ScrcpyClientOptions): Promise<string[]> {
|
||||||
|
const client = new ScrcpyClient({
|
||||||
|
...options,
|
||||||
|
// Provide an invalid encoder name
|
||||||
|
// So the server will return all available encoders
|
||||||
|
encoder: '_',
|
||||||
|
});
|
||||||
|
|
||||||
|
const resolver = new PromiseResolver<string[]>();
|
||||||
|
const encoders: string[] = [];
|
||||||
|
client.onError(({ message, error }) => {
|
||||||
|
if (error && error.type !== 'com.genymobile.scrcpy.InvalidEncoderException') {
|
||||||
|
resolver.reject(new Error(`${error.type}: ${error.message}`));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const match = message.match(ENCODER_REGEX);
|
||||||
|
if (match) {
|
||||||
|
encoders.push(match[1]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
client.onClose(() => {
|
||||||
|
resolver.resolve(encoders);
|
||||||
|
});
|
||||||
|
|
||||||
|
// Scrcpy server will open connections, before initializing encoder
|
||||||
|
// Thus although an invalid encoder name is given, the start process will success
|
||||||
|
await client.start();
|
||||||
|
|
||||||
|
return resolver.promise;
|
||||||
|
}
|
||||||
|
|
||||||
|
private readonly options: ScrcpyClientOptions;
|
||||||
|
|
||||||
|
public get backend() { return this.options.device.backend; }
|
||||||
|
|
||||||
|
private process: AdbShell | undefined;
|
||||||
|
|
||||||
|
private videoStream: AdbBufferedStream | undefined;
|
||||||
|
|
||||||
|
private controlStream: AdbBufferedStream | undefined;
|
||||||
|
|
||||||
|
private readonly debugEvent = new EventEmitter<string>();
|
||||||
|
public get onDebug() { return this.debugEvent.event; }
|
||||||
|
|
||||||
|
private readonly infoEvent = new EventEmitter<string>();
|
||||||
|
public get onInfo() { return this.infoEvent.event; }
|
||||||
|
|
||||||
|
private readonly errorEvent = new EventEmitter<ScrcpyOutput>();
|
||||||
|
public get onError() { return this.errorEvent.event; }
|
||||||
|
|
||||||
|
private readonly closeEvent = new EventEmitter<void>();
|
||||||
|
public get onClose() { return this.closeEvent.event; }
|
||||||
|
|
||||||
|
private _running = false;
|
||||||
|
public get running() { return this._running; }
|
||||||
|
|
||||||
|
private _screenWidth: number | undefined;
|
||||||
|
public get screenWidth() { return this._screenWidth; }
|
||||||
|
|
||||||
|
private _screenHeight: number | undefined;
|
||||||
|
public get screenHeight() { return this._screenHeight; }
|
||||||
|
|
||||||
|
private readonly sizeChangedEvent = new EventEmitter<FrameSize>();
|
||||||
|
public get onSizeChanged() { return this.sizeChangedEvent.event; }
|
||||||
|
|
||||||
|
private readonly videoDataEvent = new DataEventEmitter<VideoPacket>();
|
||||||
|
public get onVideoData() { return this.videoDataEvent.event; }
|
||||||
|
|
||||||
|
private readonly clipboardChangeEvent = new EventEmitter<string>();
|
||||||
|
public get onClipboardChange() { return this.clipboardChangeEvent.event; }
|
||||||
|
|
||||||
|
private sendingTouchMessage = false;
|
||||||
|
|
||||||
|
public constructor(options: ScrcpyClientOptions) {
|
||||||
|
this.options = options;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async start(): Promise<void> {
|
||||||
|
const {
|
||||||
|
device,
|
||||||
|
path = DEFAULT_SERVER_PATH,
|
||||||
|
version,
|
||||||
|
logLevel = ScrcpyLogLevel.Error,
|
||||||
|
maxSize = 0,
|
||||||
|
bitRate,
|
||||||
|
maxFps = 0,
|
||||||
|
orientation = ScrcpyScreenOrientation.Unlocked,
|
||||||
|
tunnelForward = false,
|
||||||
|
profile = AndroidCodecProfile.Baseline,
|
||||||
|
level = AndroidCodecLevel.Level4,
|
||||||
|
encoder = '-',
|
||||||
|
} = this.options;
|
||||||
|
|
||||||
|
let connection: ScrcpyClientConnection | undefined;
|
||||||
|
let process: AdbShell | undefined;
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (tunnelForward) {
|
||||||
|
connection = new ScrcpyClientForwardConnection(device);
|
||||||
|
} else {
|
||||||
|
connection = new ScrcpyClientReverseConnection(device);
|
||||||
|
}
|
||||||
|
await connection.initialize();
|
||||||
|
|
||||||
|
process = await device.childProcess.spawn([
|
||||||
|
`CLASSPATH=${path}`,
|
||||||
|
'app_process',
|
||||||
|
/* unused */ '/',
|
||||||
|
'com.genymobile.scrcpy.Server',
|
||||||
|
version,
|
||||||
|
logLevel,
|
||||||
|
maxSize.toString(), // (0: unlimited)
|
||||||
|
bitRate.toString(),
|
||||||
|
maxFps.toString(),
|
||||||
|
orientation.toString(),
|
||||||
|
tunnelForward.toString(),
|
||||||
|
/* crop */ '-',
|
||||||
|
/* send_frame_meta */ 'true', // always send frame meta (packet boundaries + timestamp)
|
||||||
|
/* control */ 'true',
|
||||||
|
/* display_id */ '0',
|
||||||
|
/* show_touches */ 'false',
|
||||||
|
/* stay_awake */ 'true',
|
||||||
|
/* codec_options */ `profile=${profile},level=${level}`,
|
||||||
|
encoder,
|
||||||
|
], {
|
||||||
|
// Disable Shell Protocol to simplify processing
|
||||||
|
shells: [AdbLegacyShell],
|
||||||
|
});
|
||||||
|
|
||||||
|
process.onStdout(this.handleProcessOutput, this);
|
||||||
|
|
||||||
|
const resolver = new PromiseResolver<never>();
|
||||||
|
const removeExitListener = process.onExit(() => {
|
||||||
|
resolver.reject(new Error('scrcpy server exited prematurely'));
|
||||||
|
});
|
||||||
|
|
||||||
|
const [videoStream, controlStream] = await Promise.race([
|
||||||
|
resolver.promise,
|
||||||
|
connection.getStreams(),
|
||||||
|
]);
|
||||||
|
|
||||||
|
removeExitListener();
|
||||||
|
this.process = process;
|
||||||
|
this.process.onExit(this.handleProcessClosed, this);
|
||||||
|
this.videoStream = videoStream;
|
||||||
|
this.controlStream = controlStream;
|
||||||
|
|
||||||
|
this._running = true;
|
||||||
|
this.receiveVideo();
|
||||||
|
this.receiveControl();
|
||||||
|
} catch (e) {
|
||||||
|
await process?.kill();
|
||||||
|
throw e;
|
||||||
|
} finally {
|
||||||
|
connection?.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleProcessOutput(data: ArrayBuffer) {
|
||||||
|
const string = this.options.device.backend.decodeUtf8(data);
|
||||||
|
for (const output of parseScrcpyOutput(string)) {
|
||||||
|
switch (output.level) {
|
||||||
|
case ScrcpyLogLevel.Debug:
|
||||||
|
this.debugEvent.fire(output.message);
|
||||||
|
break;
|
||||||
|
case ScrcpyLogLevel.Info:
|
||||||
|
this.infoEvent.fire(output.message);
|
||||||
|
break;
|
||||||
|
case ScrcpyLogLevel.Error:
|
||||||
|
this.errorEvent.fire(output);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private handleProcessClosed() {
|
||||||
|
this._running = false;
|
||||||
|
this.closeEvent.fire();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async receiveVideo() {
|
||||||
|
if (!this.videoStream) {
|
||||||
|
throw new Error('receiveVideo started before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// Device name, we don't need it
|
||||||
|
await this.videoStream.read(64);
|
||||||
|
|
||||||
|
// Initial video size
|
||||||
|
const { width, height } = await Size.deserialize(this.videoStream);
|
||||||
|
this._screenWidth = width;
|
||||||
|
this._screenHeight = height;
|
||||||
|
|
||||||
|
let buffer: ArrayBuffer | undefined;
|
||||||
|
while (this._running) {
|
||||||
|
const { pts, data } = await VideoPacket.deserialize(this.videoStream);
|
||||||
|
if (!data || data.byteLength === 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pts === NoPts) {
|
||||||
|
const sequenceParameterSet = parse_sequence_parameter_set(data.slice(0));
|
||||||
|
|
||||||
|
const {
|
||||||
|
pic_width_in_mbs_minus1,
|
||||||
|
pic_height_in_map_units_minus1,
|
||||||
|
frame_mbs_only_flag,
|
||||||
|
frame_crop_left_offset,
|
||||||
|
frame_crop_right_offset,
|
||||||
|
frame_crop_top_offset,
|
||||||
|
frame_crop_bottom_offset,
|
||||||
|
} = sequenceParameterSet;
|
||||||
|
const width = (pic_width_in_mbs_minus1 + 1) * 16;
|
||||||
|
const height = (pic_height_in_map_units_minus1 + 1) * (2 - frame_mbs_only_flag) * 16;
|
||||||
|
const cropLeft = frame_crop_left_offset * 2;
|
||||||
|
const cropRight = frame_crop_right_offset * 2;
|
||||||
|
const cropTop = frame_crop_top_offset * 2;
|
||||||
|
const cropBottom = frame_crop_bottom_offset * 2;
|
||||||
|
|
||||||
|
const screenWidth = width - cropLeft - cropRight;
|
||||||
|
const screenHeight = height - cropTop - cropBottom;
|
||||||
|
this._screenWidth = screenWidth;
|
||||||
|
this._screenHeight = screenHeight;
|
||||||
|
|
||||||
|
this.sizeChangedEvent.fire({
|
||||||
|
sequenceParameterSet,
|
||||||
|
width,
|
||||||
|
height,
|
||||||
|
cropLeft: cropLeft,
|
||||||
|
cropRight: cropRight,
|
||||||
|
cropTop: cropTop,
|
||||||
|
cropBottom: cropBottom,
|
||||||
|
croppedWidth: screenWidth,
|
||||||
|
croppedHeight: screenHeight,
|
||||||
|
});
|
||||||
|
|
||||||
|
buffer = data;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
let array: Uint8Array;
|
||||||
|
if (buffer) {
|
||||||
|
array = new Uint8Array(buffer.byteLength + data!.byteLength);
|
||||||
|
array.set(new Uint8Array(buffer));
|
||||||
|
array.set(new Uint8Array(data!), buffer.byteLength);
|
||||||
|
buffer = undefined;
|
||||||
|
} else {
|
||||||
|
array = new Uint8Array(data!);
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.videoDataEvent.fire({
|
||||||
|
pts,
|
||||||
|
size: array.byteLength,
|
||||||
|
data: array.buffer,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (!this._running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async receiveControl() {
|
||||||
|
if (!this.controlStream) {
|
||||||
|
throw new Error('receiveControl started before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
while (true) {
|
||||||
|
const type = await this.controlStream.read(1);
|
||||||
|
switch (new Uint8Array(type)[0]) {
|
||||||
|
case 0:
|
||||||
|
const { content } = await ClipboardMessage.deserialize(this.controlStream);
|
||||||
|
this.clipboardChangeEvent.fire(content!);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new Error('unknown control message type');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
if (!this._running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async injectKeyCode(message: Omit<ScrcpyInjectKeyCodeControlMessage, 'type' | 'action'>) {
|
||||||
|
if (!this.controlStream) {
|
||||||
|
throw new Error('injectKeyCode called before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.controlStream.write(ScrcpyInjectKeyCodeControlMessage.serialize({
|
||||||
|
...message,
|
||||||
|
type: ScrcpyControlMessageType.InjectKeycode,
|
||||||
|
action: AndroidKeyEventAction.Down,
|
||||||
|
}, this.backend));
|
||||||
|
|
||||||
|
await this.controlStream.write(ScrcpyInjectKeyCodeControlMessage.serialize({
|
||||||
|
...message,
|
||||||
|
type: ScrcpyControlMessageType.InjectKeycode,
|
||||||
|
action: AndroidKeyEventAction.Up,
|
||||||
|
}, this.backend));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async injectText(text: string) {
|
||||||
|
if (!this.controlStream) {
|
||||||
|
throw new Error('injectText called before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
await this.controlStream.write(ScrcpyInjectTextControlMessage.serialize({
|
||||||
|
type: ScrcpyControlMessageType.InjectText,
|
||||||
|
text,
|
||||||
|
}, this.backend));
|
||||||
|
}
|
||||||
|
|
||||||
|
public async injectTouch(message: Omit<ScrcpyInjectTouchControlMessage, 'type' | 'screenWidth' | 'screenHeight'>) {
|
||||||
|
if (!this.controlStream) {
|
||||||
|
throw new Error('injectTouch called before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!this.screenWidth || !this.screenHeight) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// ADB streams are actually pretty low-bandwidth and laggy
|
||||||
|
// Re-sample move events to avoid flooding the connection
|
||||||
|
if (this.sendingTouchMessage &&
|
||||||
|
message.action === AndroidMotionEventAction.Move) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.sendingTouchMessage = true;
|
||||||
|
const buffer = ScrcpyInjectTouchControlMessage.serialize({
|
||||||
|
...message,
|
||||||
|
type: ScrcpyControlMessageType.InjectTouch,
|
||||||
|
screenWidth: this.screenWidth,
|
||||||
|
screenHeight: this.screenHeight,
|
||||||
|
}, this.backend);
|
||||||
|
await this.controlStream.write(buffer);
|
||||||
|
this.sendingTouchMessage = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async pressBackOrTurnOnScreen() {
|
||||||
|
if (!this.controlStream) {
|
||||||
|
throw new Error('pressBackOrTurnOnScreen called before initialization');
|
||||||
|
}
|
||||||
|
|
||||||
|
const buffer = ScrcpySimpleControlMessage.serialize(
|
||||||
|
{ type: ScrcpyControlMessageType.BackOrScreenOn },
|
||||||
|
this.backend
|
||||||
|
);
|
||||||
|
await this.controlStream.write(buffer);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async close() {
|
||||||
|
if (!this._running) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this._running = false;
|
||||||
|
this.videoStream?.close();
|
||||||
|
this.controlStream?.close();
|
||||||
|
await this.process?.kill();
|
||||||
|
}
|
||||||
|
}
|
36
libraries/scrcpy/src/codec.ts
Normal file
36
libraries/scrcpy/src/codec.ts
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
|
||||||
|
// See https://developer.android.com/reference/android/media/MediaCodecInfo.CodecProfileLevel
|
||||||
|
export enum AndroidCodecProfile {
|
||||||
|
Baseline = 0x01,
|
||||||
|
Main = 0x02,
|
||||||
|
Extended = 0x04,
|
||||||
|
High = 0x08,
|
||||||
|
High10 = 0x10,
|
||||||
|
High422 = 0x20,
|
||||||
|
High444 = 0x40,
|
||||||
|
ConstrainedBaseline = 0x10000,
|
||||||
|
ConstrainedHigh = 0x80000,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AndroidCodecLevel {
|
||||||
|
Level1 = 0x01,
|
||||||
|
Level1b = 0x02,
|
||||||
|
Level11 = 0x04,
|
||||||
|
Level12 = 0x08,
|
||||||
|
Level13 = 0x10,
|
||||||
|
Level2 = 0x20,
|
||||||
|
Level21 = 0x40,
|
||||||
|
Level22 = 0x80,
|
||||||
|
Level3 = 0x100,
|
||||||
|
Level31 = 0x200,
|
||||||
|
Level32 = 0x400,
|
||||||
|
Level4 = 0x800,
|
||||||
|
Level41 = 0x1000,
|
||||||
|
Level42 = 0x2000,
|
||||||
|
Level5 = 0x4000,
|
||||||
|
Level51 = 0x8000,
|
||||||
|
Level52 = 0x10000,
|
||||||
|
Level6 = 0x20000,
|
||||||
|
Level61 = 0x40000,
|
||||||
|
Level62 = 0x80000,
|
||||||
|
}
|
89
libraries/scrcpy/src/connection.ts
Normal file
89
libraries/scrcpy/src/connection.ts
Normal file
|
@ -0,0 +1,89 @@
|
||||||
|
import { Adb, AdbBufferedStream, AdbSocket, EventQueue } from "@yume-chan/adb";
|
||||||
|
import { Disposable } from "@yume-chan/event";
|
||||||
|
import { ValueOrPromise } from "@yume-chan/struct";
|
||||||
|
import { delay } from "./utils";
|
||||||
|
|
||||||
|
export abstract class ScrcpyClientConnection implements Disposable {
|
||||||
|
protected device: Adb;
|
||||||
|
|
||||||
|
public constructor(device: Adb) {
|
||||||
|
this.device = device;
|
||||||
|
}
|
||||||
|
|
||||||
|
public initialize(): ValueOrPromise<void> { }
|
||||||
|
|
||||||
|
public abstract getStreams(): ValueOrPromise<[videoSteam: AdbBufferedStream, controlStream: AdbBufferedStream]>;
|
||||||
|
|
||||||
|
public dispose(): void { }
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScrcpyClientForwardConnection extends ScrcpyClientConnection {
|
||||||
|
private async connect(): Promise<AdbBufferedStream> {
|
||||||
|
return new AdbBufferedStream(await this.device.createSocket('localabstract:scrcpy'));
|
||||||
|
}
|
||||||
|
|
||||||
|
private async connectAndRetry(): Promise<AdbBufferedStream> {
|
||||||
|
for (let i = 0; i < 100; i++) {
|
||||||
|
try {
|
||||||
|
return await this.connect();
|
||||||
|
} catch (e) {
|
||||||
|
await delay(100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Error(`Can't connect to server after 100 retries`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async connectAndReadByte(): Promise<AdbBufferedStream> {
|
||||||
|
const stream = await this.connectAndRetry();
|
||||||
|
// server will write a `0` to signal connection success
|
||||||
|
await stream.read(1);
|
||||||
|
return stream;
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getStreams(): Promise<[videoSteam: AdbBufferedStream, controlStream: AdbBufferedStream]> {
|
||||||
|
return [
|
||||||
|
await this.connectAndReadByte(),
|
||||||
|
await this.connectAndRetry()
|
||||||
|
];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ScrcpyClientReverseConnection extends ScrcpyClientConnection {
|
||||||
|
private streams!: EventQueue<AdbSocket>;
|
||||||
|
|
||||||
|
private address!: string;
|
||||||
|
|
||||||
|
public async initialize(): Promise<void> {
|
||||||
|
// try to unbind first
|
||||||
|
try {
|
||||||
|
await this.device.reverse.remove('localabstract:scrcpy');
|
||||||
|
} catch {
|
||||||
|
// ignore error
|
||||||
|
}
|
||||||
|
|
||||||
|
this.streams = new EventQueue<AdbSocket>();
|
||||||
|
this.address = await this.device.reverse.add('localabstract:scrcpy', 27183, {
|
||||||
|
onSocket: (packet, stream) => {
|
||||||
|
this.streams.enqueue(stream);
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
private async accept(): Promise<AdbBufferedStream> {
|
||||||
|
return new AdbBufferedStream(await this.streams.dequeue());
|
||||||
|
}
|
||||||
|
|
||||||
|
public async getStreams(): Promise<[videoSteam: AdbBufferedStream, controlStream: AdbBufferedStream]> {
|
||||||
|
return [
|
||||||
|
await this.accept(),
|
||||||
|
await this.accept(),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
public dispose() {
|
||||||
|
// Don't await this!
|
||||||
|
// `reverse.remove`'s response will never arrive
|
||||||
|
// before we read all pending data from `videoStream`
|
||||||
|
this.device.reverse.remove(this.address);
|
||||||
|
}
|
||||||
|
}
|
7
libraries/scrcpy/src/index.ts
Normal file
7
libraries/scrcpy/src/index.ts
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
export * from './client';
|
||||||
|
export * from './codec';
|
||||||
|
export * from './connection';
|
||||||
|
export * from './message';
|
||||||
|
export * from './push-server';
|
||||||
|
export * from './utils';
|
||||||
|
export * from './version';
|
114
libraries/scrcpy/src/message.ts
Normal file
114
libraries/scrcpy/src/message.ts
Normal file
|
@ -0,0 +1,114 @@
|
||||||
|
import Struct, { placeholder } from '@yume-chan/struct';
|
||||||
|
|
||||||
|
export enum ScrcpyControlMessageType {
|
||||||
|
InjectKeycode,
|
||||||
|
InjectText,
|
||||||
|
InjectTouch,
|
||||||
|
InjectScroll,
|
||||||
|
BackOrScreenOn,
|
||||||
|
ExpandNotificationPanel,
|
||||||
|
CollapseNotificationPanel,
|
||||||
|
GetClipboard,
|
||||||
|
SetClipboard,
|
||||||
|
SetScreenPowerMode,
|
||||||
|
RotateDevice,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ScrcpySimpleControlMessage =
|
||||||
|
new Struct()
|
||||||
|
.uint8('type', placeholder<ScrcpyControlMessageType.BackOrScreenOn>());
|
||||||
|
|
||||||
|
export type ScrcpySimpleControlMessage = typeof ScrcpySimpleControlMessage['TInit'];
|
||||||
|
|
||||||
|
export enum AndroidMotionEventAction {
|
||||||
|
Down,
|
||||||
|
Up,
|
||||||
|
Move,
|
||||||
|
Cancel,
|
||||||
|
Outside,
|
||||||
|
PointerDown,
|
||||||
|
PointerUp,
|
||||||
|
HoverMove,
|
||||||
|
Scroll,
|
||||||
|
HoverEnter,
|
||||||
|
HoverExit,
|
||||||
|
ButtonPress,
|
||||||
|
ButtonRelease,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ScrcpyInjectTouchControlMessage =
|
||||||
|
new Struct()
|
||||||
|
.uint8('type', ScrcpyControlMessageType.InjectTouch as const)
|
||||||
|
.uint8('action', placeholder<AndroidMotionEventAction>())
|
||||||
|
.uint64('pointerId')
|
||||||
|
.uint32('pointerX')
|
||||||
|
.uint32('pointerY')
|
||||||
|
.uint16('screenWidth')
|
||||||
|
.uint16('screenHeight')
|
||||||
|
.uint16('pressure')
|
||||||
|
.uint32('buttons');
|
||||||
|
|
||||||
|
export type ScrcpyInjectTouchControlMessage = typeof ScrcpyInjectTouchControlMessage['TInit'];
|
||||||
|
|
||||||
|
export const ScrcpyInjectTextControlMessage =
|
||||||
|
new Struct()
|
||||||
|
.uint8('type', ScrcpyControlMessageType.InjectText as const)
|
||||||
|
.uint32('length')
|
||||||
|
.string('text', { lengthField: 'length' });
|
||||||
|
|
||||||
|
export type ScrcpyInjectTextControlMessage =
|
||||||
|
typeof ScrcpyInjectTextControlMessage['TInit'];
|
||||||
|
|
||||||
|
export enum AndroidKeyEventAction {
|
||||||
|
Down = 0,
|
||||||
|
Up = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum AndroidKeyCode {
|
||||||
|
Home = 3,
|
||||||
|
Back = 4,
|
||||||
|
A = 29,
|
||||||
|
B,
|
||||||
|
C,
|
||||||
|
D,
|
||||||
|
E,
|
||||||
|
F,
|
||||||
|
G,
|
||||||
|
H,
|
||||||
|
I,
|
||||||
|
J,
|
||||||
|
K,
|
||||||
|
L,
|
||||||
|
M,
|
||||||
|
N,
|
||||||
|
O,
|
||||||
|
P,
|
||||||
|
Q,
|
||||||
|
R,
|
||||||
|
S,
|
||||||
|
T,
|
||||||
|
U,
|
||||||
|
V,
|
||||||
|
W,
|
||||||
|
X,
|
||||||
|
Y,
|
||||||
|
Z,
|
||||||
|
Delete = 67,
|
||||||
|
AppSwitch = 187,
|
||||||
|
}
|
||||||
|
|
||||||
|
export const ScrcpyInjectKeyCodeControlMessage =
|
||||||
|
new Struct()
|
||||||
|
.uint8('type', ScrcpyControlMessageType.InjectKeycode as const)
|
||||||
|
.uint8('action', placeholder<AndroidKeyEventAction>())
|
||||||
|
.uint32('keyCode')
|
||||||
|
.uint32('repeat')
|
||||||
|
.uint32('metaState');
|
||||||
|
|
||||||
|
export type ScrcpyInjectKeyCodeControlMessage =
|
||||||
|
typeof ScrcpyInjectKeyCodeControlMessage['TInit'];
|
||||||
|
|
||||||
|
export type ScrcpyControlMessage =
|
||||||
|
ScrcpySimpleControlMessage |
|
||||||
|
ScrcpyInjectTouchControlMessage |
|
||||||
|
ScrcpyInjectKeyCodeControlMessage;
|
28
libraries/scrcpy/src/push-server.ts
Normal file
28
libraries/scrcpy/src/push-server.ts
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
import { Adb } from "@yume-chan/adb";
|
||||||
|
|
||||||
|
export const DEFAULT_SERVER_PATH = '/data/local/tmp/scrcpy-server.jar';
|
||||||
|
|
||||||
|
export interface PushServerOptions {
|
||||||
|
path?: string;
|
||||||
|
onProgress?: (progress: number) => void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export async function pushServer(
|
||||||
|
device: Adb,
|
||||||
|
file: ArrayBuffer,
|
||||||
|
options: PushServerOptions = {}
|
||||||
|
) {
|
||||||
|
const {
|
||||||
|
path = DEFAULT_SERVER_PATH,
|
||||||
|
onProgress,
|
||||||
|
} = options;
|
||||||
|
|
||||||
|
const sync = await device.sync();
|
||||||
|
return sync.write(
|
||||||
|
path,
|
||||||
|
file,
|
||||||
|
undefined,
|
||||||
|
undefined,
|
||||||
|
onProgress
|
||||||
|
);
|
||||||
|
}
|
284
libraries/scrcpy/src/sps.ts
Normal file
284
libraries/scrcpy/src/sps.ts
Normal file
|
@ -0,0 +1,284 @@
|
||||||
|
class BitReader {
|
||||||
|
private buffer: Uint8Array;
|
||||||
|
|
||||||
|
private bytePosition = 0;
|
||||||
|
|
||||||
|
private bitPosition = 0;
|
||||||
|
|
||||||
|
public constructor(buffer: Uint8Array) {
|
||||||
|
this.buffer = buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
public read(length: number): number {
|
||||||
|
let result = 0;
|
||||||
|
for (let i = 0; i < length; i += 1) {
|
||||||
|
result = (result << 1) | this.next();
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
public next(): number {
|
||||||
|
const value = (this.buffer[this.bytePosition] >> (7 - this.bitPosition)) & 1;
|
||||||
|
this.bitPosition += 1;
|
||||||
|
if (this.bitPosition === 8) {
|
||||||
|
this.bytePosition += 1;
|
||||||
|
this.bitPosition = 0;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public decodeExponentialGolombNumber(): number {
|
||||||
|
let length = 0;
|
||||||
|
while (this.next() === 0) {
|
||||||
|
length += 1;
|
||||||
|
}
|
||||||
|
if (length === 0) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return (1 << length | this.read(length)) - 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function* iterateNalu(buffer: Uint8Array): Generator<Uint8Array> {
|
||||||
|
// -1 means we haven't found the first start code
|
||||||
|
let start = -1;
|
||||||
|
let writeIndex = 0;
|
||||||
|
|
||||||
|
// How many `0x00`s in a row we have counted
|
||||||
|
let zeroCount = 0;
|
||||||
|
|
||||||
|
let inEmulation = false;
|
||||||
|
|
||||||
|
for (const byte of buffer) {
|
||||||
|
buffer[writeIndex] = byte;
|
||||||
|
writeIndex += 1;
|
||||||
|
|
||||||
|
if (inEmulation) {
|
||||||
|
if (byte > 0x03) {
|
||||||
|
// `0x00000304` or larger are invalid
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
inEmulation = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte == 0x00) {
|
||||||
|
zeroCount += 1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const lastZeroCount = zeroCount;
|
||||||
|
zeroCount = 0;
|
||||||
|
|
||||||
|
if (start === -1) {
|
||||||
|
// 0x000001 is the start code
|
||||||
|
// But it can be preceded by any number of zeros
|
||||||
|
// So 2 is the minimal
|
||||||
|
if (lastZeroCount >= 2 && byte === 0x01) {
|
||||||
|
// Found start of first NAL unit
|
||||||
|
writeIndex = 0;
|
||||||
|
start = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Not begin with start code
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastZeroCount < 2) {
|
||||||
|
// zero or one `0x00`s are acceptable
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (byte === 0x01) {
|
||||||
|
// Remove all leading `0x00`s and this `0x01`
|
||||||
|
writeIndex -= lastZeroCount + 1;
|
||||||
|
|
||||||
|
// Found another NAL unit
|
||||||
|
yield buffer.subarray(start, writeIndex);
|
||||||
|
|
||||||
|
start = writeIndex;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lastZeroCount > 2) {
|
||||||
|
// Too much `0x00`s
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (byte) {
|
||||||
|
case 0x02:
|
||||||
|
// Didn't find why, but 7.4.1 NAL unit semantics forbids `0x000002` appearing in NAL units
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
case 0x03:
|
||||||
|
// `0x000003` is the "emulation_prevention_three_byte"
|
||||||
|
// `0x00000300`, `0x00000301`, `0x00000302` and `0x00000303` represent
|
||||||
|
// `0x000000`, `0x000001`, `0x000002` and `0x000003` respectively
|
||||||
|
|
||||||
|
// Remove current byte
|
||||||
|
writeIndex -= 1;
|
||||||
|
|
||||||
|
inEmulation = true;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
// `0x000004` or larger are ok
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inEmulation || zeroCount !== 0) {
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
yield buffer.subarray(start, writeIndex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 7.3.2.1.1 Sequence parameter set data syntax
|
||||||
|
export function parse_sequence_parameter_set(buffer: ArrayBuffer) {
|
||||||
|
for (const nalu of iterateNalu(new Uint8Array(buffer))) {
|
||||||
|
const reader = new BitReader(nalu);
|
||||||
|
if (reader.next() !== 0) {
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
const nal_ref_idc = reader.read(2);
|
||||||
|
const nal_unit_type = reader.read(5);
|
||||||
|
|
||||||
|
if (nal_unit_type !== 7) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nal_ref_idc === 0) {
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
const profile_idc = reader.read(8);
|
||||||
|
const constraint_set = reader.read(8);
|
||||||
|
|
||||||
|
const constraint_set_reader = new BitReader(new Uint8Array([constraint_set]));
|
||||||
|
const constraint_set0_flag = !!constraint_set_reader.next();
|
||||||
|
const constraint_set1_flag = !!constraint_set_reader.next();
|
||||||
|
const constraint_set2_flag = !!constraint_set_reader.next();
|
||||||
|
const constraint_set3_flag = !!constraint_set_reader.next();
|
||||||
|
const constraint_set4_flag = !!constraint_set_reader.next();
|
||||||
|
const constraint_set5_flag = !!constraint_set_reader.next();
|
||||||
|
|
||||||
|
// reserved_zero_2bits
|
||||||
|
if (constraint_set_reader.read(2) !== 0) {
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
const level_idc = reader.read(8);
|
||||||
|
const seq_parameter_set_id = reader.decodeExponentialGolombNumber();
|
||||||
|
|
||||||
|
if (profile_idc === 100 || profile_idc === 110 ||
|
||||||
|
profile_idc === 122 || profile_idc === 244 || profile_idc === 44 ||
|
||||||
|
profile_idc === 83 || profile_idc === 86 || profile_idc === 118 ||
|
||||||
|
profile_idc === 128 || profile_idc === 138 || profile_idc === 139 ||
|
||||||
|
profile_idc === 134) {
|
||||||
|
const chroma_format_idc = reader.decodeExponentialGolombNumber();
|
||||||
|
if (chroma_format_idc === 3) {
|
||||||
|
const separate_colour_plane_flag = !!reader.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const bit_depth_luma_minus8 = reader.decodeExponentialGolombNumber();
|
||||||
|
const bit_depth_chroma_minus8 = reader.decodeExponentialGolombNumber();
|
||||||
|
|
||||||
|
const qpprime_y_zero_transform_bypass_flag = !!reader.next();
|
||||||
|
|
||||||
|
const seq_scaling_matrix_present_flag = !!reader.next();
|
||||||
|
if (seq_scaling_matrix_present_flag) {
|
||||||
|
const seq_scaling_list_present_flag: boolean[] = [];
|
||||||
|
for (let i = 0; i < ((chroma_format_idc !== 3) ? 8 : 12); i++) {
|
||||||
|
seq_scaling_list_present_flag[i] = !!reader.next();
|
||||||
|
if (seq_scaling_list_present_flag[i])
|
||||||
|
if (i < 6) {
|
||||||
|
// TODO
|
||||||
|
// scaling_list( ScalingList4x4[ i ], 16,
|
||||||
|
// UseDefaultScalingMatrix4x4Flag[ i ])
|
||||||
|
} else {
|
||||||
|
// TODO
|
||||||
|
// scaling_list( ScalingList8x8[ i − 6 ], 64,
|
||||||
|
// UseDefaultScalingMatrix8x8Flag[ i − 6 ] )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const log2_max_frame_num_minus4 = reader.decodeExponentialGolombNumber();
|
||||||
|
const pic_order_cnt_type = reader.decodeExponentialGolombNumber();
|
||||||
|
if (pic_order_cnt_type === 0) {
|
||||||
|
const log2_max_pic_order_cnt_lsb_minus4 = reader.decodeExponentialGolombNumber();
|
||||||
|
} else if (pic_order_cnt_type === 1) {
|
||||||
|
const delta_pic_order_always_zero_flag = reader.next();
|
||||||
|
const offset_for_non_ref_pic = reader.decodeExponentialGolombNumber();
|
||||||
|
const offset_for_top_to_bottom_field = reader.decodeExponentialGolombNumber();
|
||||||
|
const num_ref_frames_in_pic_order_cnt_cycle = reader.decodeExponentialGolombNumber();
|
||||||
|
const offset_for_ref_frame: number[] = [];
|
||||||
|
for (let i = 0; i < num_ref_frames_in_pic_order_cnt_cycle; i++) {
|
||||||
|
offset_for_ref_frame[i] = reader.decodeExponentialGolombNumber();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const max_num_ref_frames = reader.decodeExponentialGolombNumber();
|
||||||
|
const gaps_in_frame_num_value_allowed_flag = reader.next();
|
||||||
|
const pic_width_in_mbs_minus1 = reader.decodeExponentialGolombNumber();
|
||||||
|
const pic_height_in_map_units_minus1 = reader.decodeExponentialGolombNumber();
|
||||||
|
|
||||||
|
const frame_mbs_only_flag = reader.next();
|
||||||
|
if (!frame_mbs_only_flag) {
|
||||||
|
const mb_adaptive_frame_field_flag = !!reader.next();
|
||||||
|
}
|
||||||
|
|
||||||
|
const direct_8x8_inference_flag = reader.next();
|
||||||
|
|
||||||
|
const frame_cropping_flag = !!reader.next();
|
||||||
|
let frame_crop_left_offset: number;
|
||||||
|
let frame_crop_right_offset: number;
|
||||||
|
let frame_crop_top_offset: number;
|
||||||
|
let frame_crop_bottom_offset: number;
|
||||||
|
if (frame_cropping_flag) {
|
||||||
|
frame_crop_left_offset = reader.decodeExponentialGolombNumber();
|
||||||
|
frame_crop_right_offset = reader.decodeExponentialGolombNumber();
|
||||||
|
frame_crop_top_offset = reader.decodeExponentialGolombNumber();
|
||||||
|
frame_crop_bottom_offset = reader.decodeExponentialGolombNumber();
|
||||||
|
} else {
|
||||||
|
frame_crop_left_offset = 0;
|
||||||
|
frame_crop_right_offset = 0;
|
||||||
|
frame_crop_top_offset = 0;
|
||||||
|
frame_crop_bottom_offset = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
const vui_parameters_present_flag = !!reader.next();
|
||||||
|
if (vui_parameters_present_flag) {
|
||||||
|
// TODO
|
||||||
|
// vui_parameters( )
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
profile_idc,
|
||||||
|
constraint_set,
|
||||||
|
constraint_set0_flag,
|
||||||
|
constraint_set1_flag,
|
||||||
|
constraint_set2_flag,
|
||||||
|
constraint_set3_flag,
|
||||||
|
constraint_set4_flag,
|
||||||
|
constraint_set5_flag,
|
||||||
|
level_idc,
|
||||||
|
seq_parameter_set_id,
|
||||||
|
pic_width_in_mbs_minus1,
|
||||||
|
pic_height_in_map_units_minus1,
|
||||||
|
frame_mbs_only_flag,
|
||||||
|
frame_cropping_flag,
|
||||||
|
frame_crop_left_offset,
|
||||||
|
frame_crop_right_offset,
|
||||||
|
frame_crop_top_offset,
|
||||||
|
frame_crop_bottom_offset,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error('Invalid data');
|
||||||
|
}
|
||||||
|
|
||||||
|
export type SequenceParameterSet = ReturnType<typeof parse_sequence_parameter_set>;
|
5
libraries/scrcpy/src/utils.ts
Normal file
5
libraries/scrcpy/src/utils.ts
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
export function delay(time: number): Promise<void> {
|
||||||
|
return new Promise(resolve => {
|
||||||
|
(globalThis as any).setTimeout(resolve, time);
|
||||||
|
});
|
||||||
|
}
|
1
libraries/scrcpy/src/version.ts
Normal file
1
libraries/scrcpy/src/version.ts
Normal file
|
@ -0,0 +1 @@
|
||||||
|
export const BUNDLED_SERVER_VERSION = "1.19";
|
14
libraries/scrcpy/tsconfig.json
Normal file
14
libraries/scrcpy/tsconfig.json
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
{
|
||||||
|
"extends": "./node_modules/@yume-chan/ts-package-builder/tsconfig.base.json",
|
||||||
|
"compilerOptions": {
|
||||||
|
"target": "ES2016",
|
||||||
|
},
|
||||||
|
"references": [
|
||||||
|
{
|
||||||
|
"path": "../event/tsconfig.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"path": "../struct/tsconfig.json"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
10
rush.json
10
rush.json
|
@ -16,7 +16,7 @@
|
||||||
* path segment in the "$schema" field for all your Rush config files. This will ensure
|
* path segment in the "$schema" field for all your Rush config files. This will ensure
|
||||||
* correct error-underlining and tab-completion for editors such as VS Code.
|
* correct error-underlining and tab-completion for editors such as VS Code.
|
||||||
*/
|
*/
|
||||||
"rushVersion": "5.46.1",
|
"rushVersion": "5.55.1",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The next field selects which package manager should be installed and determines its version.
|
* The next field selects which package manager should be installed and determines its version.
|
||||||
|
@ -319,7 +319,9 @@
|
||||||
/**
|
/**
|
||||||
* The list of shell commands to run after the Rush installation finishes
|
* The list of shell commands to run after the Rush installation finishes
|
||||||
*/
|
*/
|
||||||
"postRushInstall": [],
|
"postRushInstall": [
|
||||||
|
"rush postinstall"
|
||||||
|
],
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The list of shell commands to run before the Rush build command starts
|
* The list of shell commands to run before the Rush build command starts
|
||||||
|
@ -482,6 +484,10 @@
|
||||||
"projectFolder": "libraries/adb-backend-ws"
|
"projectFolder": "libraries/adb-backend-ws"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
"packageName": "@yume-chan/scrcpy",
|
||||||
|
"projectFolder": "libraries/scrcpy"
|
||||||
|
},
|
||||||
|
{
|
||||||
"packageName": "demo",
|
"packageName": "demo",
|
||||||
"projectFolder": "apps/demo"
|
"projectFolder": "apps/demo"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue