Greasy Fork 还支持 简体中文。

Push creators to Feishu

Show and update Feishu Table ID with a floating box (Persistent Storage)

  1. // ==UserScript==
  2. // @name Push creators to Feishu
  3. // @namespace http://tampermonkey.net/
  4. // @version 1.3
  5. // @description Show and update Feishu Table ID with a floating box (Persistent Storage)
  6. // @match *://pgy.xiaohongshu.com/solar/*
  7. // @grant GM_setValue
  8. // @grant GM_getValue
  9. // @grant GM_xmlhttpRequest
  10. // ==/UserScript==
  11.  
  12. (async function () {
  13. "use strict";
  14.  
  15. // Create the display box for Table ID
  16. const box = document.createElement("div");
  17. box.id = "tableIdBox";
  18. box.style.position = "fixed";
  19. box.style.bottom = "120px"; // Adjust to fit both buttons
  20. box.style.right = "30px";
  21. box.style.zIndex = "999999";
  22. box.style.padding = "10px";
  23. box.style.fontSize = "14px";
  24. box.style.background = "#fff";
  25. box.style.color = "#333";
  26. box.style.border = "1px solid #007bff";
  27. box.style.borderRadius = "5px";
  28. box.style.boxShadow = "2px 2px 10px rgba(0,0,0,0.2)";
  29. box.style.textAlign = "center";
  30. box.style.minWidth = "200px";
  31. document.body.appendChild(box);
  32.  
  33. // Create the "Set Feishu Table ID" button
  34. const btnSet = document.createElement("button");
  35. btnSet.textContent = "Set Feishu Table ID";
  36. btnSet.style.position = "fixed";
  37. btnSet.style.bottom = "70px"; // Adjusted
  38. btnSet.style.right = "20px";
  39. btnSet.style.zIndex = "999999";
  40. btnSet.style.padding = "0.7em 1.2em";
  41. btnSet.style.fontSize = "1.5rem";
  42. btnSet.style.background = "#007bff";
  43. btnSet.style.color = "#fff";
  44. btnSet.style.border = "none";
  45. btnSet.style.borderRadius = "5px";
  46. btnSet.style.cursor = "pointer";
  47. btnSet.style.boxShadow = "2px 2px 10px rgba(0,0,0,0.2)";
  48. // Create the "Send Data to Feishu" button
  49. const btnSend = document.createElement("button");
  50. btnSend.textContent = "Send Data to Feishu";
  51. btnSend.style.position = "fixed";
  52. btnSend.style.bottom = "20px";
  53. btnSend.style.right = "20px";
  54. btnSend.style.zIndex = "999999";
  55. btnSend.style.padding = "0.5em 1.2em";
  56. btnSend.style.fontSize = "1.5rem";
  57. btnSend.style.background = "#28a745"; // Green color
  58. btnSend.style.color = "#fff";
  59. btnSend.style.border = "none";
  60. btnSend.style.borderRadius = "5px";
  61. btnSend.style.cursor = "pointer";
  62. btnSend.style.boxShadow = "2px 2px 10px rgba(0,0,0,0.2)";
  63. // Hover effect
  64. // Hover effects
  65. btnSet.addEventListener(
  66. "mouseover",
  67. () => (btnSet.style.background = "#0056b3")
  68. );
  69. btnSet.addEventListener(
  70. "mouseout",
  71. () => (btnSet.style.background = "#007bff")
  72. );
  73. btnSend.addEventListener(
  74. "mouseover",
  75. () => (btnSend.style.background = "#218838")
  76. );
  77. btnSend.addEventListener(
  78. "mouseout",
  79. () => (btnSend.style.background = "#28a745")
  80. );
  81.  
  82. // Function to update and display Table ID
  83. async function updateTableIdDisplay() {
  84. let savedTableId =
  85. (await GM_getValue("feishu_table_id", null)) ||
  86. localStorage.getItem("feishu_table_id") ||
  87. "Not Set";
  88. box.textContent = "Feishu Table ID: " + savedTableId;
  89. }
  90.  
  91. function askTableId() {
  92. let savedTableId = localStorage.getItem("feishu_table_id") || "";
  93.  
  94. let tableId = prompt("Enter your Feishu Table ID:", savedTableId);
  95.  
  96. if (tableId) {
  97. GM_setValue("feishu_table_id", tableId);
  98. localStorage.setItem("feishu_table_id", tableId);
  99. alert("✅ Table ID updated: " + tableId);
  100. updateTableIdDisplay(); // Update the box immediately
  101. } else {
  102. alert("❌ No Table ID entered. Keeping the old one.");
  103. }
  104. }
  105.  
  106. /// Fetch Feishu Auth Token with Tampermonkey CORS Bypass
  107. async function fetchAuth() {
  108. return new Promise((resolve, reject) => {
  109. GM_xmlhttpRequest({
  110. method: "POST",
  111. url: "https://open.feishu.cn/open-apis/auth/v3/tenant_access_token/internal",
  112. headers: {
  113. "Content-Type": "application/json",
  114. },
  115. data: JSON.stringify({
  116. app_id: "cli_a7ed50b93cf81013", // Replace with your real App ID
  117. app_secret: "UpfwudsU6XjexK12atBW2dHIJ8cpHoiO", // Replace with your real App Secret
  118. }),
  119. onload: function (response) {
  120. try {
  121. const data = JSON.parse(response.responseText);
  122. if (data.tenant_access_token) {
  123. resolve(data.tenant_access_token);
  124. } else {
  125. alert("❌ Failed to fetch auth token. Check your credentials.");
  126. reject(null);
  127. }
  128. } catch (error) {
  129. console.error("❌ JSON Parse Error:", error);
  130. reject(null);
  131. }
  132. },
  133. onerror: function (error) {
  134. console.error("❌ Feishu Auth API Request Error:", error);
  135. reject(null);
  136. },
  137. });
  138. });
  139. }
  140.  
  141. // ✅ Send Data to Feishu Table using GM_xmlhttpRequest (Bypass CORS)
  142. async function postToFeishu() {
  143. let tableId = localStorage.getItem("feishu_table_id");
  144. if (!tableId || tableId === "Not Set") {
  145. alert("❌ No Feishu Table ID saved. Please set one first.");
  146. return;
  147. }
  148.  
  149. const authToken = await fetchAuth();
  150. if (!authToken) return;
  151.  
  152. const url = `https://open.feishu.cn/open-apis/bitable/v1/apps/H6yybtp50azBCTsUMVNc8HD3nob/tables/${tableId}/records`;
  153.  
  154. const element = document.querySelector(
  155. "#body_wrapper > section > div > div > div > div.d-spinner-nested-loading > div > div > div.blogger-detail__left > div > div.blogger-info-cell > div.blogger-info-cell-content > div.blogger-base-info > div.base-info-list > div:nth-child(1) > div.blogger-name"
  156. );
  157. let extractedText = element ? element.textContent.trim() : "No Data Found"; // Default if element not found
  158.  
  159. // ✅ Get the current page URL
  160. const currentPageUrl = window.location.href;
  161.  
  162. return new Promise((resolve, reject) => {
  163. GM_xmlhttpRequest({
  164. method: "POST",
  165. url: url,
  166. headers: {
  167. "Content-Type": "application/json",
  168. Authorization: `Bearer ${authToken}`,
  169. },
  170. data: JSON.stringify({
  171. fields: {
  172. 达人昵称: extractedText,
  173. 其他备注: currentPageUrl,
  174. },
  175. }),
  176. onload: function (response) {
  177. try {
  178. const data = JSON.parse(response.responseText);
  179. if (data.code === 0) {
  180. alert("✅ Data successfully sent to Feishu Table!");
  181. console.log("📨 Response:", data);
  182. resolve(data);
  183. } else {
  184. alert(`❌ API Error: ${data.msg}`);
  185. console.error("❌ API Response:", data);
  186. reject(null);
  187. }
  188. } catch (error) {
  189. console.error("❌ JSON Parse Error:", error);
  190. reject(null);
  191. }
  192. },
  193. onerror: function (error) {
  194. console.error("❌ Feishu API Request Error:", error);
  195. alert("❌ Failed to send data.");
  196. reject(null);
  197. },
  198. });
  199. });
  200. }
  201.  
  202. // Update Table ID box on page load
  203. await updateTableIdDisplay();
  204.  
  205. // Button Click Events
  206. btnSet.addEventListener("click", askTableId);
  207. btnSend.addEventListener("click", postToFeishu);
  208.  
  209. // Add buttons to the webpage
  210. document.body.appendChild(btnSet);
  211. document.body.appendChild(btnSend);
  212. })();