Skip to content
Snippets Groups Projects
Verified Commit 704babea authored by Björn Eßwein's avatar Björn Eßwein
Browse files

split BrowserView.cs into separate classes

parent 21310b69
No related branches found
No related tags found
No related merge requests found
Showing
with 566 additions and 344 deletions
using ChromeDevToolsProtocol;
using ChromeDevToolsProtocol.WebSocketProtocol;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using Newtonsoft.Json.Serialization;
using System;
using System.IO;
using System.Text;
using System.Net.WebSockets;
using System.Threading;
using System.Threading.Tasks;
using System.Collections;
using System.Diagnostics;
using ChromeDevTools;
using UnityEngine;
using UnityEngine.Networking;
using UnityEngine.UI;
//using Unity.Networking.Transport;
public class BrowserView : MonoBehaviour
{
// each instance of this class gets its own tab in this browser
private static Process browserProcess;
private const string browserExecutablePath = "chrome";
private const bool headlessBrowser = false;
private const int debugPort = 9222;
private ClientWebSocket ws = new ClientWebSocket();
private PageTargetInfo pageTarget;
private CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
private JsonSerializer serializer;
private JsonSerializerSettings serializerSettings;
private Browser browser;
private BrowserTab tab;
private RawImage rawImage;
......@@ -43,24 +20,20 @@ public class BrowserView : MonoBehaviour
void OnEnable()
{
var camelCasePropertyNamesContractResolver = new CamelCasePropertyNamesContractResolver();
serializer = new JsonSerializer();
serializer.ContractResolver = camelCasePropertyNamesContractResolver;
serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = camelCasePropertyNamesContractResolver;
browser = Browser.getInstance();
//BrowserView.LaunchBrowser();
BrowserView.LaunchBrowser();
UnityEngine.Debug.Log($"ws State:\n{ws.State}");
//UnityEngine.Debug.Log($"ws State:\n{ws.State}");
//StartCoroutine(GetOpenTabs());
var c = StartCoroutine(OpenNewTab(delegate
var c = StartCoroutine(browser.OpenNewTab(targetUrl, (BrowserTab bt) =>
{
tab = bt;
StartCoroutine(tab.CreateScreenshot(1920, 1080, (screenshot) =>
{
UnityEngine.Debug.Log($"ws ConnectAsync State:\n{ws.State}");
UnityEngine.Debug.Log("pre get tabs");
StartCoroutine(GetOpenTabs());
UnityEngine.Debug.Log("post get tabs");
rawImage.texture = screenshot;
}));
StartCoroutine(CreateScreenshot());
}));
}
// Update is called once per frame
......@@ -68,322 +41,25 @@ public class BrowserView : MonoBehaviour
{
}
private IEnumerator GetOpenTabs()
{
yield return DevToolsApiRequest(false, "/json/list", (response) =>
{
UnityEngine.Debug.Log($"Currently open tabs:\n{response}");
});
}
private IEnumerator OpenNewTab(System.Action<Task> callback)
{
yield return DevToolsApiRequest(true, $"/json/new?{targetUrl}", (response) =>
{
pageTarget = JsonConvert.DeserializeObject<PageTargetInfo>(response, serializerSettings);
UnityEngine.Debug.Log($"tab WebSocket: '{pageTarget.WebSocketDebuggerUrl}'");
// open remote devtools websocket connection
/**
* Note: For webgl compatibility you need to use the JavaScript plugin, see also https://docs.unity3d.com/Manual/webgl-networking.html#UsingWebSockets
*/
var t = ws.ConnectAsync(new System.Uri(pageTarget.WebSocketDebuggerUrl), cancellationTokenSource.Token);
t.ContinueWith(callback);
});
//yield return new WaitUntil(() => t.IsCompleted);
}
private IEnumerator CreateScreenshot()
{
yield return new WaitUntil(() => ws.State == WebSocketState.Open);
var screenshotCommand = new CaptureScreenshotCommand();
screenshotCommand.Clip = new ChromeDevToolsProtocol.WebSocketProtocol.Types.Viewport();
screenshotCommand.Clip.Width = 620;
screenshotCommand.Clip.Height = 480;
//var sendTask = SendWsMessage(screenshotCommand);
var rect = this.GetComponent<RectTransform>().rect;
UnityEngine.Debug.Log($"pre, w: {rect.width} h: {rect.height}");
var sendTask = ws.SendAsync(Encoding.UTF8.GetBytes("{\"method\":\"Page.captureScreenshot\",\"id\":1,\"params\": {\"clip\":{\"x\":0,\"y\":0,\"width\":900,\"height\":560,\"scale\":1}}}"), WebSocketMessageType.Text, true, cancellationTokenSource.Token);
UnityEngine.Debug.Log("post");
yield return new WaitUntil(() => sendTask.IsCompleted);
var receiveTask = ReadWsMessage<CaptureScreenshotCommandResponse>();
yield return new WaitUntil(() => receiveTask.IsCompleted);
UnityEngine.Debug.Log($"screenshot result: '{receiveTask.Result["result"]["data"]}'");
//var screenshot = JsonConvert.DeserializeObject<CaptureScreenshotCommandResponse>(receiveTask.Result.Result, serializerSettings);
//UnityEngine.Debug.Log($"screenshot {receiveTask.Result.Id}: '{screenshot.Data}'");
byte[] imgBytes = Convert.FromBase64String(receiveTask.Result["result"]["data"].ToString());
UnityEngine.Debug.Log($"imgBytes.Length {imgBytes.Length}");
var myTexture = new Texture2D(1, 1);
myTexture.LoadImage(imgBytes);
//myTexture.Apply();
rawImage.texture = myTexture;
yield return StartCoroutine(CreateScreenshot());
}
/// <summary>
/// read and deserialize a json message from the devtools websocket
/// </summary>
/// <typeparam name="T">IDevtoolsCommandResponse</typeparam>
/// <returns></returns>
private async Task<JObject> ReadWsMessage<T>()
{
if (ws.State != WebSocketState.Open) throw new InvalidOperationException($"WebSocket is not open: ws.State = {ws.State}");
using (var ms = new MemoryStream())
{
WebSocketReceiveResult result;
do
{
var messageBuffer = WebSocket.CreateClientBuffer(1024, 16);
result = await ws.ReceiveAsync(messageBuffer, cancellationTokenSource.Token);
ms.Write(messageBuffer.Array, messageBuffer.Offset, result.Count);
}
while (!result.EndOfMessage);
if (result.MessageType == WebSocketMessageType.Text)
{
var msgString = Encoding.UTF8.GetString(ms.ToArray());
UnityEngine.Debug.Log($"ws received: {msgString}");
var response = JObject.Parse(msgString);
UnityEngine.Debug.Log($"ws received: {response["method"]}");
UnityEngine.Debug.Log($"ws received: {response["result"]}");
//return response.ToObject<DevtoolsCommandResponse<CaptureScreenshotCommandResponse>>(serializer);
return response;
}
else
{
throw new InvalidDataException($"Unexpected WebSocketMessageType: {result.MessageType}");
}
//ms.Seek(0, SeekOrigin.Begin);
//ms.Position = 0;
}
}
/// <summary>
/// send a json serializable message over the devtools websocket
/// </summary>
/// <typeparam name="T">IDevtoolsCommand</typeparam>
/// <param name="jsonSerializableMessage"></param>
/// <returns></returns>
private async Task SendWsMessage<T>(T jsonSerializableMessage)
{
if (ws.State != WebSocketState.Open) throw new InvalidOperationException($"WebSocket is not open: ws.State = {ws.State}");
var json = JsonConvert.SerializeObject(jsonSerializableMessage, serializerSettings);
UnityEngine.Debug.Log($"ws send: {json}");
await ws.SendAsync(Encoding.UTF8.GetBytes(json), WebSocketMessageType.Text, true, cancellationTokenSource.Token);
}
/**
* Launch headless chrome browser with remote-debugging enabled, if not already running.
*/
private static void LaunchBrowser()
{
// allow only one instance of chrome
if (BrowserView.browserProcess == null || BrowserView.browserProcess.HasExited)
{
BrowserView.browserProcess = new Process();
BrowserView.browserProcess.StartInfo.FileName = browserExecutablePath;
BrowserView.browserProcess.StartInfo.Arguments = $"--user-data-dir={Path.Join(Application.temporaryCachePath, "BrowserView")} --remote-debugging-port={debugPort} --remote-allow-origins=http://localhost:{debugPort}";
// set headlessBrowser to false to see the browser window
if (headlessBrowser)
{
BrowserView.browserProcess.StartInfo.Arguments = string.Concat(BrowserView.browserProcess.StartInfo.Arguments, "--headless");
}
else
{
BrowserView.browserProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
}
BrowserView.browserProcess.Start();
UnityEngine.Debug.Log("launched chrome");
}
}
private IEnumerator DevToolsApiRequest(bool isPUT, string apiAddress, System.Action<string> callback)
{
UnityEngine.Debug.Log($"DevTools api Request: {apiAddress}");
UnityWebRequest webRequest;
if (isPUT)
{
webRequest = UnityWebRequest.Put($"http://localhost:{debugPort}{apiAddress}", "");
}
else
{
webRequest = UnityWebRequest.Get($"http://localhost:{debugPort}{apiAddress}");
}
yield return webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.Success)
{
UnityEngine.Debug.LogError(webRequest.error);
//TODO: handle error
}
else
{
UnityEngine.Debug.Log($"DevTools api response (for {apiAddress}):\n{webRequest.downloadHandler.text}");
callback(webRequest.downloadHandler.text);
}
}
private void OnDisable()
{
// TODO: do we want to close the browser when not in use?
// close browser when recompiling
if (browserProcess != null && !browserProcess.HasExited)
{
browserProcess.Kill();
}
UnityEngine.Debug.Log("BrowserView OnDestroy called");
ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "BrowerView closed", CancellationToken.None)
.ContinueWith(delegate
{
UnityEngine.Debug.Log($"ws CloseAsync State:\n{ws.State}");
});
// TODO: fix close tab
// -> Coroutine couldn't be started because the the game object 'BrowserView' is inactive!
// consider using OnEnable and OnDisable
// see also https://stackoverflow.com/a/67699419
StartCoroutine(DevToolsApiRequest(false, $"/json/close/{pageTarget.Id}", (response) =>
{
UnityEngine.Debug.Log("browser tab has been closed");
}));
tab.Close();
browser.Close();
}
private void OnDestroy()
{
ws.Dispose();
cancellationTokenSource.Dispose();
tab.Close();
browser.Close();
}
/**
* Close all browser windows.
*/
void OnApplicationQuit()
{
if (browserProcess != null && !browserProcess.HasExited)
{
browserProcess.Kill();
}
}
}
/**
* Json structs used in the chrome devtools protocol
*/
namespace ChromeDevToolsProtocol
{
// suppress style warning, because names must correspond to json keys
//[System.Diagnostics.CodeAnalysis.SuppressMessage("Style", "IDE1006:Benennungsstile", Justification = "<Ausstehend>")]
public class PageTargetInfo
{
public string Description { get; set; }
public string DevtoolsFrontendUrl { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string WebSocketDebuggerUrl { get; set; }
}
namespace WebSocketProtocol
{
using Types;
public interface IDevtoolsCommand
{
long Id { get; }
string Method { get; }
}
///
/// Every devtools command has an id and a method
///
public class DevtoolsCommand : IDevtoolsCommand
{
private static long LAST_ID = 0;
public long Id { get; set; } = ++LAST_ID;
public string Method { get; set; }
}
///
/// Every devtools command response has the same id and a method as the corresponding command
///
public class DevtoolsCommandResponse<T>
{
public long Id { get; }
public string Method { get; }
public T Result { get; }
}
/// <summary>
/// Capture page screenshot.
/// </summary>
public class CaptureScreenshotCommand : DevtoolsCommand
{
public string Method { get; } = "Page.captureScreenshot";
/// <summary>
/// Gets or sets Image compression format (defaults to png).
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Format { get; set; }
/// <summary>
/// Gets or sets Compression quality from range [0..100] (jpeg only).
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public long? Quality { get; set; }
/// <summary>
/// Gets or sets Capture the screenshot of a given region only.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Viewport Clip { get; set; }
/// <summary>
/// Gets or sets Capture the screenshot from the surface, rather than the view. Defaults to true.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public bool? FromSurface { get; set; }
}
/// <summary>
/// Capture page screenshot response.
/// </summary>
public class CaptureScreenshotCommandResponse
{
/// <summary>
/// Gets or sets Base64-encoded image data.
/// </summary>
public string Data { get; }
}
namespace Types
{
/// <summary>
/// Viewport for capturing screenshot.
/// </summary>
public class Viewport
{
/// <summary>
/// Gets or sets X offset in CSS pixels.
/// </summary>
public double X { get; set; } = 0;
/// <summary>
/// Gets or sets Y offset in CSS pixels
/// </summary>
public double Y { get; set; } = 0;
/// <summary>
/// Gets or sets Rectangle width in CSS pixels
/// </summary>
public double Width { get; set; } = 1920;
/// <summary>
/// Gets or sets Rectangle height in CSS pixels
/// </summary>
public double Height { get; set; } = 1080;
/// <summary>
/// Gets or sets Page scale factor.
/// </summary>
public double Scale { get; set; } = 1;
}
}
tab.Close();
browser.Close();
}
}
fileFormatVersion: 2
guid: 55b01866b6fcd8543b11feed3428e70a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
using Newtonsoft.Json;
using Newtonsoft.Json.Serialization;
using System;
using System.Collections;
using System.Diagnostics;
using System.IO;
using System.Threading;
using UnityEngine;
using UnityEngine.Networking;
namespace ChromeDevTools
{
public class Browser
{
/* singleton */
private static Browser instance;
private static Process browserProcess;
/* browser settings */
private const string browserExecutablePath = "chrome";
private const bool headlessBrowser = false;
private const int debugPort = 9222;
/* JsonSerializer */
public static JsonSerializer serializer;
public static JsonSerializerSettings serializerSettings;
public static CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
/**
* get singleton instance
*/
public static Browser getInstance()
{
if (instance == null)
{
instance = new Browser();
instance.launchBrowser();
}
return instance;
}
/**
* constructor for the static fields
*/
static Browser()
{
// initialize the JsonSerializer
var camelCasePropertyNamesContractResolver = new CamelCasePropertyNamesContractResolver();
serializer = new JsonSerializer();
serializer.ContractResolver = camelCasePropertyNamesContractResolver;
serializerSettings = new JsonSerializerSettings();
serializerSettings.ContractResolver = camelCasePropertyNamesContractResolver;
}
/**
* Launch headless chrome browser with remote-debugging enabled, if not already running.
*/
private void launchBrowser()
{
// allow only one instance of chrome
if (Browser.browserProcess == null || Browser.browserProcess.HasExited)
{
Browser.browserProcess = new Process();
Browser.browserProcess.StartInfo.FileName = browserExecutablePath;
Browser.browserProcess.StartInfo.Arguments = $"--user-data-dir={Path.Join(Application.temporaryCachePath, "BrowserView")} --remote-debugging-port={debugPort} --remote-allow-origins=http://localhost:{debugPort}";
// set headlessBrowser to false to see the browser window
if (headlessBrowser)
{
Browser.browserProcess.StartInfo.Arguments = string.Concat(Browser.browserProcess.StartInfo.Arguments, "--headless");
}
else
{
Browser.browserProcess.StartInfo.WindowStyle = ProcessWindowStyle.Minimized;
}
Browser.browserProcess.Start();
UnityEngine.Debug.Log("launched chrome");
}
}
/**
* send web request to the devTools API
*/
private IEnumerator DevToolsApiRequest(bool isPUT, string apiAddress, System.Action<string> callback)
{
UnityEngine.Debug.Log($"DevTools api Request: {apiAddress}");
UnityWebRequest webRequest;
if (isPUT)
{
webRequest = UnityWebRequest.Put($"http://localhost:{debugPort}{apiAddress}", "");
}
else
{
webRequest = UnityWebRequest.Get($"http://localhost:{debugPort}{apiAddress}");
}
yield return webRequest.SendWebRequest();
if (webRequest.result != UnityWebRequest.Result.Success)
{
UnityEngine.Debug.LogError(webRequest.error);
//TODO: handle error
}
else
{
UnityEngine.Debug.Log($"DevTools api response (for {apiAddress}):\n{webRequest.downloadHandler.text}");
callback(webRequest.downloadHandler.text);
}
}
public IEnumerator OpenNewTab(string targetUrl, System.Action<BrowserTab> callback)
{
yield return DevToolsApiRequest(true, $"/json/new?{targetUrl}", (response) =>
{
PageTargetInfo pageTarget = JsonConvert.DeserializeObject<PageTargetInfo>(response, serializerSettings);
callback(new BrowserTab(pageTarget));
});
}
/**
* Not implemented.
*/
[Obsolete("Not implemented.", true)]
private IEnumerator GetOpenTabs()
{
yield return DevToolsApiRequest(false, "/json/list", (response) =>
{
UnityEngine.Debug.Log($"Currently open tabs:\n{response}");
});
}
/**
* Close the browser
*/
public void Close()
{
cancellationTokenSource.Cancel();
if (browserProcess != null && !browserProcess.HasExited)
{
browserProcess.Kill();
}
}
}
}
fileFormatVersion: 2
guid: 7d88cbe2d5d249843862fd01330b5f19
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
using ChromeDevTools.Protocol;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using System;
using System.Collections;
using System.IO;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UnityEngine;
namespace ChromeDevTools
{
public class BrowserTab
{
private ClientWebSocket ws = new ClientWebSocket();
private PageTargetInfo pageTarget;
public BrowserTab(PageTargetInfo pageTarget)
{
this.pageTarget = pageTarget;
Debug.Log($"tab WebSocket: '{pageTarget.WebSocketDebuggerUrl}'");
// open remote devtools websocket connection
/**
* Note: Forebg wl compatibility you need to use the JavaScript plugin, see also https://docs.unity3d.com/Manual/webgl-networking.html#UsingWebSockets
*/
var t = ws.ConnectAsync(new Uri(pageTarget.WebSocketDebuggerUrl), Browser.cancellationTokenSource.Token);
}
/// <summary>
/// send a json serializable message over the devtools websocket
/// </summary>
/// <typeparam name="T">IDevtoolsCommand</typeparam>
/// <param name="jsonSerializableMessage"></param>
/// <returns></returns>
private async Task SendWsMessage<T>(T jsonSerializableMessage)
{
if (ws.State != WebSocketState.Open) throw new InvalidOperationException($"WebSocket is not open: ws.State = {ws.State}");
var json = JsonConvert.SerializeObject(jsonSerializableMessage, Browser.serializerSettings);
UnityEngine.Debug.Log($"ws send: '{json}'");
//await ws.SendAsync(Encoding.UTF8.GetBytes(json), WebSocketMessageType.Text, true, Browser.cancellationTokenSource.Token);
}
/// <summary>
/// read and deserialize a json message from the devtools websocket
/// </summary>
/// <typeparam name="T">IDevtoolsCommandResponse</typeparam>
/// <returns></returns>
private async Task<JObject> ReadWsMessage<T>()
{
if (ws.State != WebSocketState.Open) throw new InvalidOperationException($"WebSocket is not open: ws.State = {ws.State}");
using (var ms = new MemoryStream())
{
WebSocketReceiveResult result;
do
{
var messageBuffer = WebSocket.CreateClientBuffer(1024, 16);
result = await ws.ReceiveAsync(messageBuffer, Browser.cancellationTokenSource.Token);
ms.Write(messageBuffer.Array, messageBuffer.Offset, result.Count);
}
while (!result.EndOfMessage);
if (result.MessageType == WebSocketMessageType.Text)
{
var msgString = Encoding.UTF8.GetString(ms.ToArray());
UnityEngine.Debug.Log($"ws received: {msgString}");
var response = JObject.Parse(msgString);
UnityEngine.Debug.Log($"ws received: {response["method"]}");
UnityEngine.Debug.Log($"ws received: {response["result"]}");
//return response.ToObject<DevtoolsCommandResponse<CaptureScreenshotCommandResponse>>(serializer);
return response;
}
else
{
throw new InvalidDataException($"Unexpected WebSocketMessageType: {result.MessageType}");
}
//ms.Seek(0, SeekOrigin.Begin);
//ms.Position = 0;
}
}
public IEnumerator CreateScreenshot(double width, double height, System.Action<Texture2D> callback)
{
yield return new WaitUntil(() => ws.State == WebSocketState.Open);
var screenshotCommand = new CaptureScreenshotCommand();
screenshotCommand.Clip = new Protocol.Types.Viewport();
screenshotCommand.Clip.Width = width;
screenshotCommand.Clip.Height = height;
//var sendTask =
SendWsMessage(screenshotCommand);
var screenshotCmd = "{\"method\":\"Page.captureScreenshot\",\"id\":1,\"params\": {\"clip\":{\"x\":0,\"y\":0,\"width\":900,\"height\":560,\"scale\":1}}}";
UnityEngine.Debug.Log($"SendAsy: '{screenshotCmd}'");
var sendTask = ws.SendAsync(Encoding.UTF8.GetBytes(screenshotCmd), WebSocketMessageType.Text, true, Browser.cancellationTokenSource.Token);
yield return new WaitUntil(() => sendTask.IsCompleted);
var receiveTask = ReadWsMessage<CaptureScreenshotCommandResponse>();
yield return new WaitUntil(() => receiveTask.IsCompleted);
Debug.Log($"screenshot result: '{receiveTask.Result["result"]["data"]}'");
//var screenshot = JsonConvert.DeserializeObject<CaptureScreenshotCommandResponse>(receiveTask.Result.Result, serializerSettings);
//UnityEngine.Debug.Log($"screenshot {receiveTask.Result.Id}: '{screenshot.Data}'");
byte[] imgBytes = Convert.FromBase64String(receiveTask.Result["result"]["data"].ToString());
Debug.Log($"imgBytes.Length {imgBytes.Length}");
var myTexture = new Texture2D(1, 1);
myTexture.LoadImage(imgBytes);
//myTexture.Apply();
callback(myTexture);
}
/**
* close this tab
*/
public void Close()
{
Debug.Log($"BrowserTab close called for: '{pageTarget.Url}'");
SendWsMessage(new CloseTargetCommand(pageTarget.Id))
.ContinueWith(delegate
{
ws.CloseAsync(WebSocketCloseStatus.NormalClosure, "tab closed", CancellationToken.None);
})
.ContinueWith(delegate
{
Debug.Log($"ws CloseAsync State:\n{ws.State}");
ws.Dispose();
});
}
}
}
fileFormatVersion: 2
guid: b6518649de7ad344c9be14d7bf1a4db7
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
/**
* Json structs used in the chrome devtools protocol
*/
namespace ChromeDevTools
{
public class PageTargetInfo
{
public string Description { get; set; }
public string DevtoolsFrontendUrl { get; set; }
public string Id { get; set; }
public string Title { get; set; }
public string Type { get; set; }
public string Url { get; set; }
public string WebSocketDebuggerUrl { get; set; }
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: 89cc7fb90858ca64bb12fb93dc432385
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 0dd7752c9faf69244aa677bdf6aa9d8e
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
using Newtonsoft.Json;
using ChromeDevTools.Protocol.Types;
namespace ChromeDevTools
{
namespace Protocol
{
/// <summary>
/// Capture page screenshot.
/// </summary>
public class CaptureScreenshotCommand : DevtoolsCommand
{
public string Method { get; } = "Page.captureScreenshot";
/// <summary>
/// Gets or sets Image compression format (defaults to png).
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public string Format { get; set; }
/// <summary>
/// Gets or sets Compression quality from range [0..100] (jpeg only).
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public long? Quality { get; set; }
/// <summary>
/// Gets or sets Capture the screenshot of a given region only.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public Viewport Clip { get; set; }
/// <summary>
/// Gets or sets Capture the screenshot from the surface, rather than the view. Defaults to true.
/// </summary>
[JsonProperty(NullValueHandling = NullValueHandling.Ignore)]
public bool? FromSurface { get; set; }
}
/// <summary>
/// Capture page screenshot response.
/// </summary>
public class CaptureScreenshotCommandResponse
{
/// <summary>
/// Gets or sets Base64-encoded image data.
/// </summary>
public string Data { get; }
}
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: bc86ea115d2a9514f838cecf8f84ccd0
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
namespace ChromeDevTools
{
namespace Protocol
{
///
/// Every devtools command has an id and a method
///
public class DevtoolsCommand
{
private static long LAST_ID = 0;
public long Id { get; } = ++LAST_ID;
public string Method { get; set; }
}
///
/// Every devtools command response has the same id and a method as the corresponding command
///
public class DevtoolsCommandResponse<T>
{
public long Id { get; }
public string Method { get; }
public T Result { get; }
}
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: 7a3faba1943f2cb46bb7219bf7893256
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: 9cc5d9c0c13f4904fa6b855e8a1f5f37
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
using Newtonsoft.Json;
using ChromeDevTools.Protocol.Types;
namespace ChromeDevTools
{
namespace Protocol
{
/// <summary>
/// Closes the target. If the target is a page that gets closed too.
/// </summary>
public class CloseTargetCommand : DevtoolsCommand
{
public string Method { get; } = "Target.closeTarget";
public CloseTargetCommand(string targetId) => TargetId = targetId;
/// <summary>
/// Gets or sets TargetId
/// </summary>
public string TargetId { get; set; }
}
/// <summary>
/// Closes the target. If the target is a page that gets closed too.
/// </summary>
public class CloseTargetCommandResponse
{
/// <summary>
/// Always set to true. If an error occurs, the response indicates protocol error.
/// </summary>
public bool Success { get; }
}
}
}
\ No newline at end of file
fileFormatVersion: 2
guid: c7dcb963b668c7b439ba6dd59dda9d53
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
fileFormatVersion: 2
guid: c939ea5aca9b41845bde1c648ba04625
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
namespace ChromeDevTools
{
namespace Protocol
{
namespace Types
{
/// <summary>
/// Viewport for capturing screenshot.
/// </summary>
public class Viewport
{
/// <summary>
/// Gets or sets X offset in CSS pixels.
/// </summary>
public double X { get; set; } = 0;
/// <summary>
/// Gets or sets Y offset in CSS pixels
/// </summary>
public double Y { get; set; } = 0;
/// <summary>
/// Gets or sets Rectangle width in CSS pixels
/// </summary>
public double Width { get; set; } = 1920;
/// <summary>
/// Gets or sets Rectangle height in CSS pixels
/// </summary>
public double Height { get; set; } = 1080;
/// <summary>
/// Gets or sets Page scale factor.
/// </summary>
public double Scale { get; set; } = 1;
}
}
}
}
fileFormatVersion: 2
guid: 19142ebe654b31e46b2b8b740d5093e1
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment