gffrt
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
# Copyright (c) Microsoft Corporation.
|
||||
#
|
||||
# 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.
|
||||
|
||||
import base64
|
||||
from pathlib import Path
|
||||
from typing import TYPE_CHECKING, Any, Callable, Literal, Optional, Union
|
||||
|
||||
from playwright._impl._api_structures import (
|
||||
ScreencastActionStyle,
|
||||
ScreencastFrame,
|
||||
ScreencastSize,
|
||||
)
|
||||
from playwright._impl._artifact import Artifact
|
||||
from playwright._impl._connection import from_nullable_channel
|
||||
from playwright._impl._disposable import DisposableStub
|
||||
from playwright._impl._errors import Error
|
||||
from playwright._impl._helper import locals_to_params
|
||||
|
||||
if TYPE_CHECKING: # pragma: no cover
|
||||
from playwright._impl._page import Page
|
||||
|
||||
|
||||
ScreencastFrameCallback = Callable[[ScreencastFrame], Any]
|
||||
ScreencastPosition = Literal[
|
||||
"bottom",
|
||||
"bottom-left",
|
||||
"bottom-right",
|
||||
"top",
|
||||
"top-left",
|
||||
"top-right",
|
||||
]
|
||||
ScreencastCursor = Literal[
|
||||
"none",
|
||||
"pointer",
|
||||
]
|
||||
|
||||
|
||||
class Screencast:
|
||||
def __init__(self, page: "Page") -> None:
|
||||
self._page = page
|
||||
self._loop = page._loop
|
||||
self._dispatcher_fiber = page._dispatcher_fiber
|
||||
self._started = False
|
||||
self._save_path: Optional[Union[str, Path]] = None
|
||||
self._on_frame: Optional[ScreencastFrameCallback] = None
|
||||
self._artifact: Optional[Artifact] = None
|
||||
page._channel.on("screencastFrame", self._dispatch_frame)
|
||||
|
||||
def _ack_frame(self, frame_id: int) -> None:
|
||||
try:
|
||||
self._page._channel.send_no_reply(
|
||||
"screencastFrameAck", None, {"frameId": frame_id}
|
||||
)
|
||||
except (Error, OSError):
|
||||
pass
|
||||
|
||||
async def _await_callback_and_ack(self, result: Any, frame_id: int) -> None:
|
||||
try:
|
||||
await result
|
||||
finally:
|
||||
self._ack_frame(frame_id)
|
||||
|
||||
def _dispatch_frame(self, params: dict) -> Any:
|
||||
result = None
|
||||
task = None
|
||||
try:
|
||||
if not self._on_frame:
|
||||
return
|
||||
data = params["data"]
|
||||
if isinstance(data, str):
|
||||
data = base64.b64decode(data)
|
||||
result = self._on_frame(
|
||||
{
|
||||
"data": data,
|
||||
"timestamp": params.get("timestamp", 0),
|
||||
"viewportWidth": params["viewportWidth"],
|
||||
"viewportHeight": params["viewportHeight"],
|
||||
}
|
||||
)
|
||||
finally:
|
||||
if hasattr(result, "__await__"):
|
||||
task = self._loop.create_task(
|
||||
self._await_callback_and_ack(result, params["frameId"])
|
||||
)
|
||||
else:
|
||||
self._ack_frame(params["frameId"])
|
||||
return task
|
||||
|
||||
async def start(
|
||||
self,
|
||||
onFrame: ScreencastFrameCallback = None,
|
||||
path: Union[str, Path] = None,
|
||||
quality: int = None,
|
||||
size: ScreencastSize = None,
|
||||
fps: int = None,
|
||||
) -> DisposableStub:
|
||||
if self._started:
|
||||
raise Error("Screencast is already started")
|
||||
self._started = True
|
||||
self._on_frame = onFrame
|
||||
result = await self._page._channel.send_return_as_dict(
|
||||
"screencastStart",
|
||||
None,
|
||||
{
|
||||
"size": size,
|
||||
"quality": quality,
|
||||
"fps": fps,
|
||||
"sendFrames": bool(onFrame),
|
||||
"record": bool(path),
|
||||
},
|
||||
)
|
||||
artifact_channel = (result or {}).get("artifact")
|
||||
if artifact_channel:
|
||||
self._artifact = from_nullable_channel(artifact_channel)
|
||||
self._save_path = path
|
||||
return DisposableStub(lambda: self.stop(), self._page)
|
||||
|
||||
async def stop(self) -> None:
|
||||
self._started = False
|
||||
self._on_frame = None
|
||||
await self._page._channel.send("screencastStop", None)
|
||||
if self._save_path and self._artifact:
|
||||
await self._artifact.save_as(self._save_path)
|
||||
self._artifact = None
|
||||
self._save_path = None
|
||||
|
||||
async def show_actions(
|
||||
self,
|
||||
duration: float = None,
|
||||
position: ScreencastPosition = None,
|
||||
fontSize: int = None,
|
||||
cursor: ScreencastCursor = None,
|
||||
style: ScreencastActionStyle = None,
|
||||
) -> DisposableStub:
|
||||
await self._page._channel.send(
|
||||
"screencastShowActions", None, locals_to_params(locals())
|
||||
)
|
||||
return DisposableStub(lambda: self.hide_actions(), self._page)
|
||||
|
||||
async def hide_actions(self) -> None:
|
||||
await self._page._channel.send("screencastHideActions", None)
|
||||
|
||||
async def show_overlay(self, html: str, duration: float = None) -> DisposableStub:
|
||||
result = await self._page._channel.send_return_as_dict(
|
||||
"screencastShowOverlay", None, locals_to_params(locals())
|
||||
)
|
||||
overlay_id = (result or {}).get("id")
|
||||
return DisposableStub(
|
||||
lambda: self._page._channel.send(
|
||||
"screencastRemoveOverlay", None, {"id": overlay_id}
|
||||
),
|
||||
self._page,
|
||||
)
|
||||
|
||||
async def show_chapter(
|
||||
self,
|
||||
title: str,
|
||||
description: str = None,
|
||||
duration: float = None,
|
||||
) -> None:
|
||||
await self._page._channel.send(
|
||||
"screencastChapter", None, locals_to_params(locals())
|
||||
)
|
||||
|
||||
async def show_overlays(self) -> None:
|
||||
await self._page._channel.send(
|
||||
"screencastSetOverlayVisible", None, {"visible": True}
|
||||
)
|
||||
|
||||
async def hide_overlays(self) -> None:
|
||||
await self._page._channel.send(
|
||||
"screencastSetOverlayVisible", None, {"visible": False}
|
||||
)
|
||||
Reference in New Issue
Block a user