ClarkKentSG-1

Untitled

Nov 9th, 2026
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.63 KB | None | 0 0
  1. // ==UserScript==
  2. // @name Jigsaw Explorer - qualité d'image (haute résolution)
  3. // @namespace local
  4. // @version 0.2
  5. // @description Fait travailler le jeu avec plus de pixels que ta fenêtre n'en affiche (×1,5 ou ×2) : image du puzzle et pièces plus détaillées, loupe plus nette. Bouton « HD » dans la barre pour changer (la page se recharge).
  6. // @match https://www.jigsawexplorer.com/*
  7. // @run-at document-start
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. (function () {
  12. 'use strict';
  13.  
  14. var FACTORS = [1, 1.5, 2]; // 1 = comportement normal du site
  15. var DEFAULT = 1.5;
  16. var STORE = 'jigex-quality-factor';
  17. var MAX_SIDE = 8192; // au-delà, certains navigateurs/cartes graphiques refusent le canvas
  18.  
  19. function load() {
  20. try { var v = parseFloat(localStorage.getItem(STORE)); return FACTORS.indexOf(v) !== -1 ? v : DEFAULT; }
  21. catch (e) { return DEFAULT; }
  22. }
  23. function save(v) { try { localStorage.setItem(STORE, String(v)); } catch (e) {} }
  24.  
  25. var factor = load();
  26. var desc = Object.getOwnPropertyDescriptor(window, 'devicePixelRatio');
  27. var realGet = desc && desc.get ? desc.get : function () { return 1; };
  28. var applied = 1;
  29.  
  30. // Le jeu lit window.devicePixelRatio au démarrage pour fixer la taille de son canvas : on lui annonce un ratio plus grand.
  31. try {
  32. Object.defineProperty(window, 'devicePixelRatio', {
  33. configurable: true,
  34. get: function () {
  35. var real = realGet.call(window);
  36. var side = Math.max(window.innerWidth, window.innerHeight) || 1000;
  37. var f = Math.min(factor, MAX_SIDE / (side * real)); // limite de sécurité
  38. f = Math.max(1, f);
  39. applied = f;
  40. return real * f;
  41. }
  42. });
  43. } catch (e) { return; }
  44.  
  45. function label() {
  46. var real = realGet.call(window);
  47. return 'Qualité : ×' + factor + (applied < factor - 0.01 ? ' (limitée à ×' + applied.toFixed(2) + ')' : '') + ' · écran ×' + real;
  48. }
  49.  
  50. // ---- Bouton dans la barre du site + petit panneau ----
  51. var btn = null, panel = null, sel = null, info = null, note = null;
  52. function mk(tag, css, txt) { var e = document.createElement(tag); if (css) e.style.cssText = css; if (txt) e.textContent = txt; return e; }
  53. function refresh() {
  54. var tip = 'Qualité d\'image ×' + factor + (applied < factor - 0.01 ? ' (limitée à ×' + applied.toFixed(2) + ')' : '');
  55. if (btn) { btn.setAttribute('data-tooltip', tip); btn.title = tip; var l = btn.querySelector('.jq-lvl'); if (l) l.textContent = '×' + factor; }
  56. if (info) info.textContent = 'Écran : ×' + realGet.call(window).toFixed(2) + ' · appliqué : ×' + (realGet.call(window) * applied).toFixed(2);
  57. }
  58. function buildPanel() {
  59. panel = mk('div', 'position:fixed;z-index:2147483000;width:270px;padding:12px 14px;border-radius:10px;background:rgb(36,38,42);color:#eee;' +
  60. 'font:13px Arial,sans-serif;box-shadow:0 6px 24px rgba(0,0,0,.45);display:none;');
  61. panel.appendChild(mk('div', 'font-weight:bold;font-size:14px;margin-bottom:6px;', 'Qualité d\'image'));
  62. var r = mk('label', 'display:flex;align-items:center;justify-content:space-between;gap:8px;margin:7px 0;');
  63. r.appendChild(mk('span', '', 'Résolution'));
  64. sel = mk('select', ''); FACTORS.forEach(function (v) { var o = mk('option', '', v === 1 ? '×1 (normal)' : '×' + v); o.value = v; sel.appendChild(o); });
  65. sel.value = String(factor); r.appendChild(sel); panel.appendChild(r);
  66. info = mk('div', 'opacity:.75;font-size:12px;margin:4px 0;'); panel.appendChild(info);
  67. note = mk('div', 'opacity:.6;font-size:11px;margin-top:6px;', 'Un changement recharge la page. Plus haut = pièces et image plus détaillées, mais plus de mémoire.');
  68. panel.appendChild(note);
  69. sel.addEventListener('change', function () {
  70. factor = parseFloat(sel.value); save(factor); note.textContent = 'Rechargement…';
  71. setTimeout(function () { location.reload(); }, 500);
  72. });
  73. ['pointerdown', 'mousedown', 'click', 'wheel', 'keydown', 'contextmenu'].forEach(function (t) { panel.addEventListener(t, function (e) { e.stopPropagation(); }); });
  74. document.body.appendChild(panel);
  75. }
  76. // Reprend l'apparence des panneaux du site (menu du programme) pour que nos panneaux aient le même style
  77. function applyTheme(el) {
  78. try {
  79. var src = document.getElementById('jigex-prog-menu-tb') || document.getElementById('jigex-prog-menu');
  80. if (!src) return;
  81. var cs = getComputedStyle(src), bg = cs.backgroundColor;
  82. if (!bg || /rgba\(.*,\s*0\)$/.test(bg) || bg === 'transparent') { var tb = document.getElementById('jigex-prog-menu-tb'); if (tb) bg = getComputedStyle(tb).backgroundColor; }
  83. if (bg && !/rgba\(.*,\s*0\)$/.test(bg) && bg !== 'transparent') {
  84. var m = bg.match(/[\d.]+/g); // fond toujours opaque, même si celui du site est translucide
  85. el.style.background = m && m.length >= 3 ? 'rgb(' + m[0] + ',' + m[1] + ',' + m[2] + ')' : bg;
  86. }
  87. if (cs.color) el.style.color = cs.color;
  88. if (cs.fontFamily) el.style.fontFamily = cs.fontFamily;
  89. if (cs.borderRadius && cs.borderRadius !== '0px') el.style.borderRadius = cs.borderRadius;
  90. if (cs.boxShadow && cs.boxShadow !== 'none') el.style.boxShadow = cs.boxShadow;
  91. } catch (e) {}
  92. }
  93. function toggle(force) {
  94. if (!panel) buildPanel();
  95. var show = force === undefined ? panel.style.display === 'none' : force;
  96. if (show) {
  97. var br = btn.getBoundingClientRect();
  98. panel.style.top = Math.round(br.bottom + 6) + 'px';
  99. panel.style.left = Math.max(8, Math.min(window.innerWidth - 280, Math.round(br.right - 270))) + 'px';
  100. applyTheme(panel); refresh();
  101. }
  102. panel.style.display = show ? 'block' : 'none';
  103. }
  104. function buildBtn() {
  105. var clock = document.getElementById('jigex-clock'), bar = clock && clock.parentElement;
  106. btn = document.createElement('div');
  107. btn.id = 'jigex-quality-btn'; btn.className = 'niftybar-icon-button main-tb-btn'; btn.style.cssText = 'display:block;position:relative;cursor:pointer;';
  108. btn.innerHTML = '<svg class="niftybar-icon" width="24" height="24" viewBox="0 0 24 24" style="color:rgb(232,230,227)"><g style="fill:none;stroke:currentColor;stroke-width:2;stroke-linejoin:round">' +
  109. '<rect x="3" y="6" width="18" height="12" rx="2"/></g><text x="12" y="15" text-anchor="middle" style="fill:currentColor;font:bold 7px Arial,sans-serif">HD</text></svg>' +
  110. '<span class="jq-lvl" style="position:absolute;right:1px;bottom:1px;font:bold 9px Arial,sans-serif;color:rgb(232,230,227);pointer-events:none;"></span>';
  111. btn.addEventListener('click', function (e) { e.stopPropagation(); toggle(); });
  112. if (bar) bar.insertBefore(btn, clock);
  113. else { btn.style.cssText = 'position:fixed;left:8px;bottom:34px;z-index:100000;width:36px;height:36px;color:#fff;background:rgba(0,0,0,.55);border-radius:18px;'; document.body.appendChild(btn); }
  114. document.addEventListener('mousedown', function (e) { if (panel && panel.style.display !== 'none' && !panel.contains(e.target) && !btn.contains(e.target)) toggle(false); }, true);
  115. refresh();
  116. }
  117. function start() {
  118. var tries = 0;
  119. (function wait() {
  120. if (document.getElementById('jigex-clock') || ++tries > 60) { if (!document.getElementById('jigex-quality-btn')) buildBtn(); }
  121. else setTimeout(wait, 500);
  122. })();
  123. }
  124. if (document.readyState === 'loading') document.addEventListener('DOMContentLoaded', start); else start();
  125. setInterval(function () { var c = document.getElementById('jigex-clock'); if (btn && c && !btn.isConnected && c.parentElement) c.parentElement.insertBefore(btn, c); }, 2000);
  126. })();
Advertisement
Add Comment
Please, Sign In to add comment