We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
[BUG] Execution hangs when trying to save video or delete video before calling page.close()
**Context:**
- Playwright Version: 1.23
- Operating System: Windows
- Python: 3.9
- Browser: All

**Code Snippet**

```from playwright.sync_api import Playwright, sync_playwright


def run(playwright: Playwright) -> None:
    browser = playwright.chromium.launch(headless=False)
    context = browser.new_context(
            viewport={"width": 1920, "height": 1080},
            record_video_dir="temp_videos/",
            record_video_size={"width": 1920, "height": 1080})

    # Open new page
    page = context.new_page()

    # ---------------------
    # page.video.save_as("test.webm")
    # OR
    # page.video.delete()
    context.close()
    browser.close()


with sync_playwright() as playwright:
    run(playwright)
```

**Describe the bug**

Execution will hang, no stack trace will be produced when user tries to save video or delete video before closing the page (page.close)

Uncomment line 15 or 17 to reproduce

The docs for save_as suggest that it should be possible:
"Saves the video to a user-specified path. It is safe to call this method while the video is still in progress, or after the page has closed. "

Still in progress suggests that I do not need to page.close() first

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `playwright/_impl/_video.py`
Content:
```
1 # Copyright (c) Microsoft Corporation.
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 
15 import pathlib
16 from typing import TYPE_CHECKING, Union
17 
18 from playwright._impl._artifact import Artifact
19 from playwright._impl._helper import Error
20 
21 if TYPE_CHECKING:  # pragma: no cover
22     from playwright._impl._page import Page
23 
24 
25 class Video:
26     def __init__(self, page: "Page") -> None:
27         self._loop = page._loop
28         self._dispatcher_fiber = page._dispatcher_fiber
29         self._page = page
30         self._artifact_future = page._loop.create_future()
31         if page.is_closed():
32             self._page_closed()
33         else:
34             page.on("close", lambda page: self._page_closed())
35 
36     def __repr__(self) -> str:
37         return f"<Video page={self._page}>"
38 
39     def _page_closed(self) -> None:
40         if not self._artifact_future.done():
41             self._artifact_future.set_exception(Error("Page closed"))
42 
43     def _artifact_ready(self, artifact: Artifact) -> None:
44         if not self._artifact_future.done():
45             self._artifact_future.set_result(artifact)
46 
47     async def path(self) -> pathlib.Path:
48         if self._page._connection.is_remote:
49             raise Error(
50                 "Path is not available when using browserType.connect(). Use save_as() to save a local copy."
51             )
52         artifact = await self._artifact_future
53         if not artifact:
54             raise Error("Page did not produce any video frames")
55         return artifact.absolute_path
56 
57     async def save_as(self, path: Union[str, pathlib.Path]) -> None:
58         artifact = await self._artifact_future
59         if not artifact:
60             raise Error("Page did not produce any video frames")
61         await artifact.save_as(path)
62 
63     async def delete(self) -> None:
64         artifact = await self._artifact_future
65         if not artifact:
66             raise Error("Page did not produce any video frames")
67         await artifact.delete()
68
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/playwright/_impl/_video.py b/playwright/_impl/_video.py
--- a/playwright/_impl/_video.py
+++ b/playwright/_impl/_video.py
@@ -55,6 +55,10 @@
         return artifact.absolute_path
 
     async def save_as(self, path: Union[str, pathlib.Path]) -> None:
+        if self._page._connection._is_sync and not self._page._is_closed:
+            raise Error(
+                "Page is not yet closed. Close the page prior to calling save_as"
+            )
         artifact = await self._artifact_future
         if not artifact:
             raise Error("Page did not produce any video frames")

{"golden_diff": "diff --git a/playwright/_impl/_video.py b/playwright/_impl/_video.py\n--- a/playwright/_impl/_video.py\n+++ b/playwright/_impl/_video.py\n@@ -55,6 +55,10 @@\n         return artifact.absolute_path\n \n     async def save_as(self, path: Union[str, pathlib.Path]) -> None:\n+        if self._page._connection._is_sync and not self._page._is_closed:\n+            raise Error(\n+                \"Page is not yet closed. Close the page prior to calling save_as\"\n+            )\n         artifact = await self._artifact_future\n         if not artifact:\n             raise Error(\"Page did not produce any video frames\")\n", "issue": "[BUG] Execution hangs when trying to save video or delete video before calling page.close()\n**Context:**\r\n- Playwright Version: 1.23\r\n- Operating System: Windows\r\n- Python: 3.9\r\n- Browser: All\r\n\r\n**Code Snippet**\r\n\r\n```from playwright.sync_api import Playwright, sync_playwright\r\n\r\n\r\ndef run(playwright: Playwright) -> None:\r\n    browser = playwright.chromium.launch(headless=False)\r\n    context = browser.new_context(\r\n            viewport={\"width\": 1920, \"height\": 1080},\r\n            record_video_dir=\"temp_videos/\",\r\n            record_video_size={\"width\": 1920, \"height\": 1080})\r\n\r\n    # Open new page\r\n    page = context.new_page()\r\n\r\n    # ---------------------\r\n    # page.video.save_as(\"test.webm\")\r\n    # OR\r\n    # page.video.delete()\r\n    context.close()\r\n    browser.close()\r\n\r\n\r\nwith sync_playwright() as playwright:\r\n    run(playwright)\r\n```\r\n\r\n**Describe the bug**\r\n\r\nExecution will hang, no stack trace will be produced when user tries to save video or delete video before closing the page (page.close)\r\n\r\nUncomment line 15 or 17 to reproduce\r\n\r\nThe docs for save_as suggest that it should be possible:\r\n\"Saves the video to a user-specified path. It is safe to call this method while the video is still in progress, or after the page has closed. \"\r\n\r\nStill in progress suggests that I do not need to page.close() first\n", "before_files": [{"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport pathlib\nfrom typing import TYPE_CHECKING, Union\n\nfrom playwright._impl._artifact import Artifact\nfrom playwright._impl._helper import Error\n\nif TYPE_CHECKING:  # pragma: no cover\n    from playwright._impl._page import Page\n\n\nclass Video:\n    def __init__(self, page: \"Page\") -> None:\n        self._loop = page._loop\n        self._dispatcher_fiber = page._dispatcher_fiber\n        self._page = page\n        self._artifact_future = page._loop.create_future()\n        if page.is_closed():\n            self._page_closed()\n        else:\n            page.on(\"close\", lambda page: self._page_closed())\n\n    def __repr__(self) -> str:\n        return f\"<Video page={self._page}>\"\n\n    def _page_closed(self) -> None:\n        if not self._artifact_future.done():\n            self._artifact_future.set_exception(Error(\"Page closed\"))\n\n    def _artifact_ready(self, artifact: Artifact) -> None:\n        if not self._artifact_future.done():\n            self._artifact_future.set_result(artifact)\n\n    async def path(self) -> pathlib.Path:\n        if self._page._connection.is_remote:\n            raise Error(\n                \"Path is not available when using browserType.connect(). Use save_as() to save a local copy.\"\n            )\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        return artifact.absolute_path\n\n    async def save_as(self, path: Union[str, pathlib.Path]) -> None:\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        await artifact.save_as(path)\n\n    async def delete(self) -> None:\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        await artifact.delete()\n", "path": "playwright/_impl/_video.py"}], "after_files": [{"content": "# Copyright (c) Microsoft Corporation.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n# http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n\nimport pathlib\nfrom typing import TYPE_CHECKING, Union\n\nfrom playwright._impl._artifact import Artifact\nfrom playwright._impl._helper import Error\n\nif TYPE_CHECKING:  # pragma: no cover\n    from playwright._impl._page import Page\n\n\nclass Video:\n    def __init__(self, page: \"Page\") -> None:\n        self._loop = page._loop\n        self._dispatcher_fiber = page._dispatcher_fiber\n        self._page = page\n        self._artifact_future = page._loop.create_future()\n        if page.is_closed():\n            self._page_closed()\n        else:\n            page.on(\"close\", lambda page: self._page_closed())\n\n    def __repr__(self) -> str:\n        return f\"<Video page={self._page}>\"\n\n    def _page_closed(self) -> None:\n        if not self._artifact_future.done():\n            self._artifact_future.set_exception(Error(\"Page closed\"))\n\n    def _artifact_ready(self, artifact: Artifact) -> None:\n        if not self._artifact_future.done():\n            self._artifact_future.set_result(artifact)\n\n    async def path(self) -> pathlib.Path:\n        if self._page._connection.is_remote:\n            raise Error(\n                \"Path is not available when using browserType.connect(). Use save_as() to save a local copy.\"\n            )\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        return artifact.absolute_path\n\n    async def save_as(self, path: Union[str, pathlib.Path]) -> None:\n        if self._page._connection._is_sync and not self._page._is_closed:\n            raise Error(\n                \"Page is not yet closed. Close the page prior to calling save_as\"\n            )\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        await artifact.save_as(path)\n\n    async def delete(self) -> None:\n        artifact = await self._artifact_future\n        if not artifact:\n            raise Error(\"Page did not produce any video frames\")\n        await artifact.delete()\n", "path": "playwright/_impl/_video.py"}]}