I'm making a Chrome extension from redirecting youtube.com/shorts/... to youtube.com/watch?v=...

Everything works fine when I open those shorts links in new tabs or when I type them out but when I click from the homepage itself, they don't get redirected.

Here is my rules.json file:

[
    {
      "id": 1,
      "priority": 1,
      "action": { "type": "redirect", "redirect": { "regexSubstitution":"https://youtube.com/watch?v=\\1" } },
      "condition": { "regexFilter": "^.*youtube\\.com/shorts/(.*)", "resourceTypes": ["main_frame"] }
    }
  ]

Here is my manifest.json file:

{
    "manifest_version": 3,
    "name": "No Shorts",
    "version": "0.5",
    "description": "Play YT shorts as regular videos instead of in a separate player",
    "action": {
        "default_icon": "images/no-shorts-ico.png"
    },
    "declarative_net_request": {
        "rule_resources": [{
          "id": "ruleset_1",
          "enabled": true,
          "path": "rules.json"
        }]
      },

    "icons":{
        "16": "images/16.png",
        "48": "images/48.png",
        "128": "images/128.png"

    },
    "permissions":[ "declarativeNetRequest"],
    "host_permissions":["*://*.youtube.com/*"]

  }

I clicked on a short video from the homepage and it did not get redirected. However, when I refreshed it, it did get redirected. It also got redirected when I clicked open in new tab or typed out the url myself.

If I had to guess, I think it is happening because of something that is similar to client-side navigation but I really can't say for sure. Is there a fix for this?

1

There are 1 best solutions below

0
On BEST ANSWER

There is no network request to intercept in such inner navigation as it uses the history API in JS.

You can run a script on the entire youtube domain and intercept the click event:

// page.js:

addEventListener('click', e => {
  const thumb = e.target.closest('ytd-thumbnail');
  const cmd = thumb?.__data.data.navigationEndpoint.commandMetadata.webCommandMetadata;
  if (cmd?.webPageType !== 'WEB_PAGE_TYPE_SHORTS') return;
  cmd.webPageType = 'WEB_PAGE_TYPE_WATCH';
  cmd.url = cmd.url.replace('/shorts/', '/watch?v=');
  for (const a of thumb.querySelectorAll('a'))
    a.href = a.href.replace('/shorts/', '/watch?v='); 
}, true);

// manifest.json:

  "background": { "service_worker": "bg.js" },
  "permissions": ["scripting"],
  "host_permissions": ["*://www.youtube.com/"],

// bg.js

chrome.runtime.onInstalled.addListener(async () => {
  const scripts = [{
    id: 'page',
    world: 'MAIN',
    matches: ['*://www.youtube.com/*'],
    runAt: 'document_start',
    js: ['page.js'],
  }];
  await chrome.scripting.unregisterContentScripts({ids: scripts.map(s => s.id)})
    .catch(() => {});
  await chrome.scripting.registerContentScripts(scripts);
  for (const script of scripts) {
    const execCfg = {
      target: {},
      files: script.js,
      injectImmediately: true,
      world: script.world,
    };
    for (const tab of await chrome.tabs.query({url: script.matches})) {
      execCfg.target.tabId = tab.id;
      chrome.scripting.executeScript(execCfg);
    }
  }
});