语雀编辑器远程图片本地化

将语雀文章里面的远程图片本地化,以免远程图片失效后不能预览。

  1. // ==UserScript==
  2. // @name 语雀编辑器远程图片本地化
  3. // @namespace YuQue_editor_pic_localization
  4. // @version 1.0.4
  5. // @description 将语雀文章里面的远程图片本地化,以免远程图片失效后不能预览。
  6. // @author 邓小明
  7. // @icon https://cdn.nlark.com/yuque/0/2021/png/191410/1617364659047-1f999db8-93f2-4264-b80a-58cd2d9d6eac.png
  8. // @require https://cdn.bootcdn.net/ajax/libs/jquery/2.1.4/jquery.min.js
  9. // @run-at document-end
  10. // @grant unsafeWindow
  11. // @include *://www.yuque.com/*/edit*
  12. // ==/UserScript==
  13.  
  14. function addDiv(dom, html) {
  15. var element = document.createElement('div');
  16. element.innerHTML = html;
  17. document.querySelector(dom).appendChild(element);
  18. }
  19.  
  20. $('body').append(
  21. '<div id="show_pic_number" style="position:fixed; bottom:145px; right: 25px; width:32px; z-index: 99999; background-color:#fff; padding: 5px; border-radius: 50%; cursor: pointer; box-shadow: 0px 1px 3px rgba(0,0,0,0.2);" title="本地化远程图片"><img src="https://cdn.nlark.com/yuque/0/2021/png/191410/1617382285933-47bdf44f-9ac5-477b-80d6-74d0e180d1b1.png" width="100%"></div>'
  22. );
  23. $('#show_pic_number').on('click', function() {
  24. show_pic_number();
  25. return false;
  26. });
  27.  
  28. addDiv('html',
  29. '<div id="request_log" style=" width: 100%; max-height: 300px; overflow-y: auto; font-size: 12px; background-color: rgba(0,0,0,0.8); color: #fff; line-height: 130%; z-index: 999999; left: 0; bottom: 0; position:fixed; word-break:break-all;" ondblclick="this.innerHTML=\'\'" title="双击清空"></div>'
  30. );
  31.  
  32.  
  33. var yuque_config = unsafeWindow.appData;
  34. var config = {
  35. id: yuque_config.doc.id,
  36. book: {
  37. id: yuque_config.book.id,
  38. creator_userid: yuque_config.book.creator_id,
  39. name: yuque_config.book.name,
  40. created_at: yuque_config.book.created_at,
  41. updated_at: yuque_config.book.updated_at
  42. },
  43. doc: {
  44. id: yuque_config.doc.book_id,
  45. creator_userid: yuque_config.doc.user_id,
  46. title: yuque_config.doc.title,
  47. slug: yuque_config.doc.slug,
  48. created_at: yuque_config.doc.created_at,
  49. updated_at: yuque_config.doc.updated_at
  50. },
  51. user: {
  52. id: yuque_config.me.id,
  53. login: yuque_config.me.login,
  54. nickname: yuque_config.me.name,
  55. avatar: yuque_config.me.avatar,
  56. email: yuque_config.me.email,
  57. mobile: yuque_config.me.mobile
  58. }
  59. };
  60. console.log('config', config);
  61.  
  62. var upload_url_param = {
  63. 'attachable_type': 'Doc',
  64. 'attachable_id': config.doc.id,
  65. 'ctoken': get_cookie('yuque_ctoken'),
  66. 'type': 'image',
  67. };
  68. var upload_url = 'https://www.yuque.com/api/upload/attach?' + $.param(upload_url_param);
  69.  
  70. /*
  71. console.log('url_param', upload_url);
  72. data.attachment_id
  73. data.filename
  74. data.url
  75. */
  76. var remote_pic_list = new Array();
  77. var remote_pic_list_original = new Array();
  78.  
  79. function show_pic_number() {
  80. remote_pic_list = [];
  81. remote_pic_list_original = [];
  82. $('.lake-content-editor-core .image').each(function() {
  83. if ($(this).attr('src').match(/^\/api\/filetransfer\/images\?url=/)) {
  84. if (!in_array($(this).data('raw-src'), remote_pic_list_original)) {
  85. remote_pic_list.push($(this).attr('src'));
  86. remote_pic_list_original.push($(this).data('raw-src'));
  87. $(this).attr('data-is-remote-pic', '1');
  88. }
  89. }
  90. });
  91. if (remote_pic_list.length > 0) {
  92. for (key in remote_pic_list) {
  93. replace_pic_url(remote_pic_list[key], remote_pic_list_original[key]);
  94. }
  95. } else {
  96. console.log('没有远程图片');
  97. }
  98. }
  99.  
  100. function get_cookie(cname) {
  101. var name = cname + '=';
  102. var ca = document.cookie.split(';');
  103. for (var i = 0; i < ca.length; i++) {
  104. var c = ca[i].trim();
  105. if (c.indexOf(name) == 0) return c.substring(name.length, c.length);
  106. }
  107. return '';
  108. }
  109.  
  110. function replace_pic_url(url, url_original) {
  111. fetch(url).then(response => {
  112. if (response.status == 200 && response.redirected == true) {
  113. var pic_dom = $('.lake-content-editor-core .image[data-raw-src="' + url_original + '"]');
  114. pic_dom.attr('data-raw-src', response.url).attr('src', response.url).removeAttr(
  115. 'data-is-remote-pic');
  116. var pic_dom_parent = pic_dom.parents('span[data-lake-card="image"]');
  117. var card_data = $.parseJSON(decodeURIComponent(pic_dom_parent.data('card-value').substring(
  118. 5)));
  119. card_data.src = response.url;
  120. pic_dom_parent.attr('data-card-value', 'data:' + encodeURIComponent(JSON.stringify(card_data)));
  121. pic_dom.parent('.lake-image-meta').siblings('.lake-image-editor').find('img').attr('src', response
  122. .url);
  123. if ($('.lake-content-editor-core .image[data-is-remote-pic=1]').size() == 0) {
  124. $('#lake-doc-publish-button').trigger("click");
  125. console.log('全部替换完,保存内容');
  126. }
  127. }
  128. });
  129. }
  130.  
  131. function in_array(search, array) {
  132. for (var i in array) {
  133. if (array[i] == search) {
  134. return true;
  135. }
  136. }
  137. return false;
  138. }