Links for Game Editions in PlayStation Store

Add hyperlink to the other editions in playstation store

  1. // ==UserScript==
  2. // @name Links for Game Editions in PlayStation Store
  3. // @namespace https://github.com/rod24574575
  4. // @description Add hyperlink to the other editions in playstation store
  5. // @version 1.1.0
  6. // @license MIT
  7. // @author rod24574575
  8. // @homepage https://github.com/rod24574575/PsStoreEditionLink
  9. // @homepageURL https://github.com/rod24574575/PsStoreEditionLink
  10. // @supportURL https://github.com/rod24574575/PsStoreEditionLink/issues
  11. // @match *://store.playstation.com/*/product/*
  12. // @match *://store.playstation.com/*/concept/*
  13. // @match *://www.playstation.com/*/games/*
  14. // @run-at document-idle
  15. // ==/UserScript==
  16.  
  17. // @ts-check
  18. 'use strict';
  19.  
  20. (function() {
  21. function run() {
  22. /**
  23. * @param {string} trackString
  24. * @returns {string | null}
  25. */
  26. function findSkuId(trackString) {
  27. /** @type {string} */
  28. let rawSku;
  29. try {
  30. const track = JSON.parse(trackString);
  31. if (!track || typeof track !== 'object') {
  32. return null;
  33. }
  34.  
  35. const sku = track?.attributes?.sku;
  36. if (typeof sku !== 'string') {
  37. return null;
  38. }
  39.  
  40. rawSku = sku;
  41. } catch {
  42. return null;
  43. }
  44.  
  45. const lastDashIndex = rawSku.lastIndexOf('-');
  46. if (lastDashIndex < 0) {
  47. return null;
  48. }
  49.  
  50. return rawSku.slice(0, lastDashIndex);
  51. }
  52.  
  53. /**
  54. * @param {string} id
  55. * @returns {string}
  56. */
  57. function createProductUrl(id) {
  58. const match = location.href.match(/\.playstation\.com\/([^/]+)\//i);
  59. if (!match) {
  60. return '';
  61. }
  62. const locale = match[1];
  63. return `${location.protocol}//store.playstation.com/${locale}/product/${id}`;
  64. }
  65.  
  66. for (const productEditionEl of document.querySelectorAll('article[data-qa^="mfeUpsell#productEdition"]')) {
  67. const editorTitleEl = productEditionEl.querySelector('[data-qa*="editionName"]')?.parentElement;
  68. if (!editorTitleEl) {
  69. continue;
  70. }
  71.  
  72. const parent = editorTitleEl.parentElement;
  73. if (!parent) {
  74. continue;
  75. }
  76.  
  77. const addCartEl = productEditionEl.querySelector('button[data-track]');
  78. if (!addCartEl) {
  79. continue;
  80. }
  81.  
  82. const skuId = findSkuId(addCartEl.getAttribute('data-track') ?? '');
  83. if (!skuId) {
  84. continue;
  85. }
  86.  
  87. const anchor = document.createElement('a');
  88. anchor.href = createProductUrl(skuId);
  89. Object.assign(anchor.style, {
  90. display: 'block',
  91. });
  92.  
  93. parent.insertBefore(anchor, editorTitleEl);
  94. anchor.appendChild(editorTitleEl);
  95. }
  96. }
  97.  
  98. /** @type {number | undefined} */
  99. let timer = window.setInterval(() => {
  100. if (!document.querySelector('[data-qa="mfeUpsell"]:not([data-reactroot])')) {
  101. return;
  102. }
  103.  
  104. run();
  105. window.clearInterval(timer);
  106. timer = undefined;
  107. }, 100);
  108. })();