Get Real Download URL

Get the real download URL by right-clicking on a download link while holding the left Alt key.

  1. // ==UserScript==
  2. // @name Get Real Download URL
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.0
  5. // @description Get the real download URL by right-clicking on a download link while holding the left Alt key.
  6. // @match *://*/*
  7. // @grant GM_setClipboard
  8. // @license MIT
  9. // ==/UserScript==
  10.  
  11. (function() {
  12. 'use strict';
  13.  
  14. document.addEventListener('contextmenu', function(event) {
  15. if (event.altKey) {
  16. const link = event.target.closest('a[href]');
  17. if (link) {
  18. // Create the custom menu item as a floating button
  19. const customMenuItem = document.createElement('div');
  20. customMenuItem.textContent = 'Get Real Download URL';
  21. customMenuItem.style.position = 'fixed';
  22. customMenuItem.style.backgroundColor = '#fff';
  23. customMenuItem.style.border = '1px solid #ccc';
  24. customMenuItem.style.padding = '5px';
  25. customMenuItem.style.cursor = 'pointer';
  26. customMenuItem.style.zIndex = '10000';
  27. customMenuItem.style.top = `${event.clientY}px`;
  28. customMenuItem.style.left = `${event.clientX}px`;
  29. customMenuItem.style.boxShadow = '0 2px 10px rgba(0,0,0,0.5)';
  30. customMenuItem.style.borderRadius = '3px';
  31.  
  32. const clickHandler = async function() {
  33. try {
  34. const response = await fetch(link.href, {
  35. method: 'HEAD',
  36. redirect: 'manual'
  37. });
  38.  
  39. const realUrl = response.headers.get('location') || link.href;
  40.  
  41. GM_setClipboard(realUrl);
  42. showTemporaryMessage(`Real download URL copied to clipboard: ${realUrl}`, true);
  43. } catch (error) {
  44. console.error('Error fetching the real download URL:', error);
  45. showTemporaryMessage('Failed to get the real download URL.', false);
  46. } finally {
  47. document.body.removeChild(customMenuItem);
  48. }
  49. };
  50.  
  51. customMenuItem.addEventListener('click', clickHandler);
  52.  
  53. document.body.appendChild(customMenuItem);
  54.  
  55. const cleanup = () => {
  56. if (customMenuItem.parentNode) {
  57. customMenuItem.removeEventListener('click', clickHandler);
  58. document.body.removeChild(customMenuItem);
  59. }
  60. };
  61.  
  62. // Cleanup after 5 seconds or when clicking elsewhere
  63. setTimeout(cleanup, 5000);
  64. document.addEventListener('click', cleanup, { once: true });
  65.  
  66. // Prevent propagation to avoid closing the default context menu
  67. customMenuItem.addEventListener('contextmenu', function(e) {
  68. e.stopPropagation();
  69. e.preventDefault();
  70. });
  71.  
  72. // Prevent default context menu from showing
  73. event.preventDefault();
  74. }
  75. }
  76. });
  77.  
  78. function showTemporaryMessage(message, success) {
  79. const msgDiv = document.createElement('div');
  80. msgDiv.textContent = message;
  81. msgDiv.style.position = 'fixed';
  82. msgDiv.style.bottom = '10px';
  83. msgDiv.style.right = '10px';
  84. msgDiv.style.backgroundColor = success ? 'green' : 'red';
  85. msgDiv.style.color = 'white';
  86. msgDiv.style.padding = '10px';
  87. msgDiv.style.borderRadius = '5px';
  88. msgDiv.style.zIndex = '10000';
  89. document.body.appendChild(msgDiv);
  90. setTimeout(() => {
  91. document.body.removeChild(msgDiv);
  92. }, 1000);
  93. }
  94. })();