Source code for bundle.youtube.browser
# Copyright 2026 HorusElohim
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you 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.
from __future__ import annotations
import asyncio
import json
from urllib.parse import parse_qsl, urlencode, urlparse, urlunparse
from playwright.async_api import Frame, Page, Request
from bundle.core import browser, data, entity, logger, tracer
log = logger.get_logger(__name__)
DEFAULT_EMBED_URL = "https://www.youtube-nocookie.com/embed/ouEl3qTLc0M?autoplay=1&mute=1"
REFERER_ORIGIN = "https://bundle.local"
REFERER_URL = f"{REFERER_ORIGIN}/youtube/token"
[docs]
def build_embed_url(embed_url: str) -> str:
parsed = urlparse(embed_url)
query = dict(parse_qsl(parsed.query, keep_blank_values=True))
query["origin"] = REFERER_ORIGIN
query.setdefault("enablejsapi", "1")
encoded_query = urlencode(query, doseq=True)
return urlunparse(parsed._replace(query=encoded_query))
[docs]
class PotoTokenEntity(entity.Entity):
"""Entity holding the extracted poto token and visitor data."""
name: str = data.Field(default="unknow")
potoken: str = data.Field(default="unknow")
visitor_data: str = data.Field(default="unknow")
[docs]
class PotoTokenBrowser(browser.Browser):
"""
Extension of the Playwright-based Browser that implements poto token extraction.
"""
# Initialize with a default empty token entity and an asyncio event to signal extraction.
token_info: PotoTokenEntity = data.Field(default_factory=PotoTokenEntity)
extraction_event: asyncio.Event = data.Field(default_factory=asyncio.Event)
[docs]
@tracer.Async.decorator.call_raise
async def handle_request(self, request: Request) -> None:
"""
Inspect outgoing requests and extract the poto token if the request matches the expected criteria.
"""
if request.method != "POST" or "/youtubei/v1/player" not in request.url:
return
post_data = request.post_data
if not post_data:
return
try:
payload = json.loads(post_data)
visitor_data = payload["context"]["client"]["visitorData"]
potoken = payload["serviceIntegrityDimensions"]["poToken"]
except (json.JSONDecodeError, KeyError, TypeError) as e:
log.warning(f"Token extraction failed: {e}")
return
# Update the token entity and signal that extraction is complete.
self.token_info = PotoTokenEntity(name="real", potoken=potoken, visitor_data=visitor_data)
log.info(f"Extracted new token: {self.token_info}")
self.extraction_event.set()
[docs]
@tracer.Async.decorator.call_raise
async def click_player(self, page: Page, timeout: float = 10_000) -> None:
"""
Wait for the video player element and click it to trigger the token request.
"""
search_contexts: list[Page | Frame] = [page]
search_contexts.extend(frame for frame in page.frames if frame != page.main_frame)
for context in search_contexts:
player, exception = await tracer.Async.call(context.wait_for_selector, "#movie_player", timeout=timeout)
if exception:
continue
await player.click()
return
log.warning("Unable to locate video player in any frame.")
if __name__ == "__main__":
async def run():
async with PotoTokenBrowser.chromium(headless=False) as ptb:
return await ptb.extract_token()
poto_token = asyncio.get_event_loop().run_until_complete(run())
log.info("PotoToken:\n%s", poto_token)