修复inoreader图片异常

修复inoreader的图片加载问题

当前为 2023-06-01 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name fix-image-error at inoreader
  3. // @name:zh-CN 修复inoreader图片异常
  4. // @version 0.1.0
  5. // @namespace https://github.com/mengtao-code
  6. // @description Fix image load error caused by CSP(Content Security Policy)
  7. // @description:zh-CN 修复inoreader的图片加载问题
  8. // @author Mengtao Xin
  9. // @license MIT
  10. // @supportURL https://github.com/mengtao-code/tampermonkey-scripts
  11. // @include http*://*.inoreader.com/*
  12. // @icon http://www.inoreader.com/favicon.ico
  13. // @grant GM_xmlhttpRequest
  14. // @connect *
  15. // ==/UserScript==
  16. const config = {
  17. name: "fix-image-error",
  18. data: [ // weibo images prefix
  19. {
  20. imageServer: 'sinaimg.cn',
  21. customHeader: {
  22. Referer: 'https://weibo.com'
  23. }
  24. }
  25. ]
  26. }
  27.  
  28. /**
  29. *
  30. * @link https://stackoverflow.com/questions/8778863/downloading-an-image-using-xmlhttprequest-in-a-userscript
  31. * @param {*} inputStr
  32. * @returns {string}
  33. */
  34. function customBase64Encode(inputStr) {
  35. var
  36. bbLen = 3,
  37. enCharLen = 4,
  38. inpLen = inputStr.length,
  39. inx = 0,
  40. jnx,
  41. keyStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
  42. + "0123456789+/=",
  43. output = "",
  44. paddingBytes = 0;
  45. var
  46. bytebuffer = new Array(bbLen),
  47. encodedCharIndexes = new Array(enCharLen);
  48.  
  49. while (inx < inpLen) {
  50. for (jnx = 0; jnx < bbLen; ++jnx) {
  51. if (inx < inpLen)
  52. bytebuffer[jnx] = inputStr.charCodeAt(inx++) & 0xff;
  53. else
  54. bytebuffer[jnx] = 0;
  55. }
  56. encodedCharIndexes[0] = bytebuffer[0] >> 2;
  57. encodedCharIndexes[1] = ((bytebuffer[0] & 0x3) << 4) | (bytebuffer[1] >> 4);
  58. encodedCharIndexes[2] = ((bytebuffer[1] & 0x0f) << 2) | (bytebuffer[2] >> 6);
  59. encodedCharIndexes[3] = bytebuffer[2] & 0x3f;
  60. paddingBytes = inx - (inpLen - 1);
  61. switch (paddingBytes) {
  62. case 1:
  63. // Set last character to padding char
  64. encodedCharIndexes[3] = 64;
  65. break;
  66. case 2:
  67. // Set last 2 characters to padding char
  68. encodedCharIndexes[3] = 64;
  69. encodedCharIndexes[2] = 64;
  70. break;
  71. default:
  72. break; // No padding - proceed
  73. }
  74. for (jnx = 0; jnx < enCharLen; ++jnx)
  75. output += keyStr.charAt(encodedCharIndexes[jnx]);
  76. }
  77. return output;
  78. }
  79.  
  80. /**
  81. *
  82. * @param data data from http request
  83. * @returns {string}
  84. */
  85. const getImageUrl = (data) => {
  86. var binResp = customBase64Encode(data.responseText);
  87. let src = `data:image/jpeg;base64,${binResp}`
  88. return src;
  89. }
  90.  
  91. /**
  92. * send get http request
  93. * @param url
  94. * @param customHeader
  95. * @returns {Promise<unknown>}
  96. */
  97. const httpGetRequest = (url, customHeader) => {
  98. return new Promise((resolve, reject) => {
  99. GM.xmlHttpRequest({
  100. method: "GET",
  101. url: url,
  102. headers: {
  103. "Accept": "*/*",
  104. "referrerPolicy": "no-referrer",
  105. ...customHeader
  106. },
  107. onload: resolve,
  108. onerror: reject,
  109. overrideMimeType: 'text/plain; charset=x-user-defined'
  110. });
  111. })
  112. }
  113.  
  114. const processImage = (dom, customHeader) => {
  115. if (dom.getAttribute('processed-tag') !== 'true') {
  116. dom.setAttribute('alt', 'loading...')
  117. const originalSrc = dom.getAttribute("data-original-src");
  118. httpGetRequest(originalSrc, customHeader)
  119. .then(data => {
  120. dom.setAttribute('src', getImageUrl(data))
  121. })
  122. .catch(e => console.error(`${config.name} load image failed! ${e}`))
  123. .finally(() => dom.setAttribute('processed-tag', 'true'))
  124. }
  125. }
  126.  
  127. /**
  128. * 检测到有异常图片,就调整成正常的图片
  129. */
  130. const main = () => {
  131. config.data.forEach(({ imageServer, customHeader }) => {
  132. Array.from(
  133. document.querySelectorAll(`.article_content img[data-original-src*='${imageServer}']`))
  134. .forEach(image => processImage(image, customHeader));
  135. })
  136. }
  137.  
  138. setInterval(main, 3000)