Greasy Fork is available in English.

View the entire image on Twitter

Display the entire vertical image that would otherwise be cropped in the preview

  1. // ==UserScript==
  2. // @name View the entire image on Twitter
  3. // @name:ja Twitter 縦長画像Previewerやつ
  4. // @namespace http://tampermonkey.net/
  5. // @version 1.2.3
  6. // @description Display the entire vertical image that would otherwise be cropped in the preview
  7. // @description:ja Twitterでプレビューではトリミングされてしまう縦長の画像を拡大して表示させます
  8. // @author Nogaccho
  9. // @match https://twitter.com/*
  10. // @match https://x.com/*
  11. // @grant none
  12. // @license MIT
  13. // ==/UserScript==
  14.  
  15. (function() {
  16. 'use strict';
  17.  
  18. const isMediaUrl = () => {
  19. return /https:\/\/twitter\.com\/.*\/media/.test(window.location.href);
  20. };
  21.  
  22. const previewImage = (imgSrc) => {
  23. const largeImageUrl = imgSrc.split('?')[0] + '?format=jpg&name=medium';
  24.  
  25. const previewDiv = document.createElement('div');
  26. previewDiv.style.position = 'fixed';
  27. previewDiv.style.top = '10px';
  28. previewDiv.style.bottom = '10px';
  29. previewDiv.style.left = `calc(50%)`;
  30. previewDiv.style.right = '10px';
  31. previewDiv.style.zIndex = '9999';
  32. previewDiv.style.pointerEvents = 'none';
  33. previewDiv.style.backgroundImage = `url(${largeImageUrl})`;
  34. previewDiv.style.backgroundSize = 'contain';
  35. previewDiv.style.backgroundRepeat = 'no-repeat';
  36. previewDiv.style.backgroundPosition = 'center';
  37. document.body.appendChild(previewDiv);
  38.  
  39. return previewDiv;
  40. };
  41.  
  42. const isTallImage = (img) => {
  43. return img.naturalHeight / img.naturalWidth > 4 / 3;
  44. };
  45.  
  46. let currentPreview = null;
  47.  
  48. const observer = new MutationObserver(mutations => {
  49. mutations.forEach(mutation => {
  50. if (isMediaUrl()) {
  51. // URLがhttps://twitter.com/*/mediaの場合、機能を無効化
  52. if (currentPreview) {
  53. currentPreview.remove();
  54. currentPreview = null;
  55. }
  56. observer.disconnect();
  57. }
  58. });
  59. });
  60.  
  61. observer.observe(document.body, { childList: true, subtree: true });
  62.  
  63. document.addEventListener('mouseover', (e) => {
  64. if (!isMediaUrl() && e.target.tagName === 'IMG' && isTallImage(e.target) && !currentPreview) {
  65. currentPreview = previewImage(e.target.src);
  66. }
  67. });
  68.  
  69. document.addEventListener('mouseout', (e) => {
  70. if (!isMediaUrl() && e.target.tagName === 'IMG' && currentPreview) {
  71. currentPreview.remove();
  72. currentPreview = null;
  73. }
  74. });
  75. })();