ip-checker

显示当前使用的公网IP地址,并带有折叠展开功能和刷新功能,以及IP风险查询功能

  1. // ==UserScript==
  2. // @name ip-checker
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.6
  5. // @description 显示当前使用的公网IP地址,并带有折叠展开功能和刷新功能,以及IP风险查询功能
  6. // @author https://linux.do/u/snaily
  7. // @match http://*/*
  8. // @match https://*/*
  9. // @grant GM_xmlhttpRequest
  10. // @grant GM_setValue
  11. // @grant GM_getValue
  12. // @connect api.ipify.org
  13. // @connect api64.ipify.org
  14. // @connect ip-api.com
  15. // @connect scamalytics.com
  16. // @connect ping0.cc
  17. // @license MIT
  18. // ==/UserScript==
  19.  
  20. (function () {
  21. "use strict";
  22.  
  23. // 检查是否为顶级窗口
  24. if (window !== top) {
  25. console.log("Not in top window, exiting script.");
  26. return;
  27. }
  28.  
  29. function fetchCurrentIP() {
  30. console.log("Fetching current IP...");
  31. const refreshButton = document.getElementById("refreshIpInfo");
  32. if (refreshButton) {
  33. refreshButton.disabled = true;
  34. refreshButton.innerHTML = "正在刷新...";
  35. }
  36.  
  37. let ipv6 = null;
  38. // Fetch IPv6
  39. GM_xmlhttpRequest({
  40. method: "GET",
  41. url: "https://api64.ipify.org?format=json",
  42. onload: function (response) {
  43. console.log("IPv6 fetched:", response.responseText);
  44. const ipInfo = JSON.parse(response.responseText);
  45. ipv6 = isIPv6(ipInfo.ip) ? ipInfo.ip : null;
  46. console.log(ipv6);
  47. },
  48. onerror: function (error) {
  49. console.log("Error fetching IPv6:", error);
  50. if (refreshButton) {
  51. refreshButton.disabled = false;
  52. refreshButton.innerHTML = "刷新IP信息";
  53. }
  54. },
  55. });
  56.  
  57. // Fetch IPv4
  58. GM_xmlhttpRequest({
  59. method: "GET",
  60. url: "https://api.ipify.org?format=json",
  61. onload: function (response) {
  62. console.log("IPv4 fetched:", response.responseText);
  63. const ipInfo = JSON.parse(response.responseText);
  64. fetchIPDetails(ipInfo.ip, ipv6);
  65. },
  66. onerror: function (error) {
  67. console.log("Error fetching IPv4:", error);
  68. if (refreshButton) {
  69. refreshButton.disabled = false;
  70. refreshButton.innerHTML = "刷新IP信息";
  71. }
  72. },
  73. });
  74. }
  75.  
  76. function isIPv6(ip) {
  77. // IPv6正则表达式
  78. const ipv6Pattern = new RegExp(
  79. "^([0-9a-fA-F]{1,4}:){7}([0-9a-fA-F]{1,4}|:)$|^([0-9a-fA-F]{1,4}:){1,7}:$|^([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}$|^([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}$|^([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}$|^([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}$|^([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}$|^[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})$|^:((:[0-9a-fA-F]{1,4}){1,7}|:)$|^fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}$|^::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])$|^([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9]).){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9])?[0-9])$"
  80. );
  81. return ipv6Pattern.test(ip);
  82. }
  83.  
  84. function fetchIPDetails(ip, ipv6, callback) {
  85. console.log("Fetching IP details for:", ip);
  86. console.log(ipv6);
  87. GM_xmlhttpRequest({
  88. method: "GET",
  89. url: "http://ip-api.com/json/" + ip,
  90. onload: function (response) {
  91. console.log("IP details fetched:", response.responseText);
  92. const ipDetails = JSON.parse(response.responseText);
  93. fetchIPRisk(ip, ipv6, ipDetails, callback);
  94. },
  95. onerror: function (error) {
  96. console.log("Error fetching IP details:", error);
  97. const refreshButton = document.getElementById("refreshIpInfo");
  98. if (refreshButton) {
  99. refreshButton.disabled = false;
  100. refreshButton.innerHTML = "刷新IP信息";
  101. }
  102. if (callback) {
  103. callback(); // 查询失败后恢复按钮状态
  104. }
  105. },
  106. });
  107. }
  108.  
  109. function fetchIPRisk(ip, ipv6, details, callback) {
  110. console.log("Fetching IP risk for:", ip);
  111. console.log(ipv6);
  112. GM_xmlhttpRequest({
  113. method: "GET",
  114. url: `https://scamalytics.com/ip/${ip}`,
  115. onload: function (response) {
  116. console.log("IP risk fetched:", response.responseText);
  117. const riskData = parseIPRisk(response.responseText);
  118. fetchPing0Risk(ip, ipv6, details, riskData);
  119. if (callback) {
  120. callback(); // 查询成功后恢复按钮状态
  121. }
  122. },
  123. onerror: function (error) {
  124. console.log("Error fetching IP risk:", error);
  125. displayIPDetails(ipv6, details, null, null);
  126. const refreshButton = document.getElementById("refreshIpInfo");
  127. if (refreshButton) {
  128. refreshButton.disabled = false;
  129. refreshButton.innerHTML = "刷新IP信息";
  130. }
  131. },
  132. });
  133. }
  134.  
  135. function fetchPing0Risk(ip, ipv6, details, riskData) {
  136. console.log("Fetching Ping0 risk for:", ip);
  137. console.log(ipv6);
  138. GM_xmlhttpRequest({
  139. method: "GET",
  140. url: `https://ping0.cc/ip/${ip}`,
  141. headers: {
  142. "User-Agent":
  143. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
  144. },
  145. onload: function (response) {
  146. console.log("Initial Ping0 response:", response.responseText);
  147. const windowX = parseWindowX(response.responseText);
  148. if (windowX) {
  149. console.log("Parsed window.x value:", windowX);
  150. GM_xmlhttpRequest({
  151. method: "GET",
  152. url: `https://ping0.cc/ip/${ip}`,
  153. headers: {
  154. "User-Agent":
  155. "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36",
  156. Cookie: `jskey=${windowX}`,
  157. },
  158. onload: function (response) {
  159. console.log("Final Ping0 response:", response.responseText);
  160. const ping0Data = parsePing0Risk(response.responseText);
  161. displayIPDetails(ipv6, details, riskData, ping0Data);
  162. const refreshButton = document.getElementById("refreshIpInfo");
  163. if (refreshButton) {
  164. refreshButton.disabled = false;
  165. refreshButton.innerHTML = "刷新IP信息";
  166. }
  167. },
  168. onerror: function (error) {
  169. console.log("Error fetching final Ping0 risk:", error);
  170. displayIPDetails(ipv6, details, riskData, null);
  171. const refreshButton = document.getElementById("refreshIpInfo");
  172. if (refreshButton) {
  173. refreshButton.disabled = false;
  174. refreshButton.innerHTML = "刷新IP信息";
  175. }
  176. },
  177. });
  178. } else {
  179. console.log("Failed to retrieve window.x value.");
  180. displayIPDetails(ipv6, details, riskData, null);
  181. const refreshButton = document.getElementById("refreshIpInfo");
  182. if (refreshButton) {
  183. refreshButton.disabled = false;
  184. refreshButton.innerHTML = "刷新IP信息";
  185. }
  186. }
  187. },
  188. onerror: function (error) {
  189. console.log("Error fetching initial Ping0 page:", error);
  190. displayIPDetails(ipv6, details, riskData, null);
  191. const refreshButton = document.getElementById("refreshIpInfo");
  192. if (refreshButton) {
  193. refreshButton.disabled = false;
  194. refreshButton.innerHTML = "刷新IP信息";
  195. }
  196. },
  197. });
  198. }
  199.  
  200. function parseIPRisk(html) {
  201. console.log("Parsing IP risk data...");
  202. const scoreMatch = html.match(/"score":"(.*?)"/);
  203. const riskMatch = html.match(/"risk":"(.*?)"/);
  204. if (riskMatch) {
  205. const riskData = {
  206. score: scoreMatch[1],
  207. risk: riskMatch[1],
  208. };
  209. console.log("Parsed risk data:", riskData);
  210. return riskData;
  211. }
  212. console.log("Failed to parse risk data.");
  213. return null;
  214. }
  215.  
  216. function parseWindowX(html) {
  217. console.log("Parsing window.x value...");
  218. const match = html.match(/window\.x\s*=\s*'([^']+)'/);
  219. const windowX = match ? match[1] : null;
  220. console.log("Parsed window.x:", windowX);
  221. return windowX;
  222. }
  223.  
  224. function parsePing0Risk(html) {
  225. console.log("Parsing Ping0 risk data...");
  226. const parser = new DOMParser();
  227. const doc = parser.parseFromString(html, "text/html");
  228.  
  229. const ipType = doc.evaluate(
  230. "/html/body/div[2]/div[2]/div[1]/div[2]/div[8]/div[2]/span",
  231. doc,
  232. null,
  233. XPathResult.STRING_TYPE,
  234. null
  235. ).stringValue;
  236. const nativeIP = doc.evaluate(
  237. "/html/body/div[2]/div[2]/div[1]/div[2]/div[10]/div[2]/span",
  238. doc,
  239. null,
  240. XPathResult.STRING_TYPE,
  241. null
  242. ).stringValue;
  243. const element = doc.querySelector(
  244. "#check > div.container > div.info > div.content > div.line.line-risk > div.content > div > div.riskitem.riskcurrent > span.value"
  245. );
  246. const riskValue = element.textContent;
  247.  
  248. const ping0Data = {
  249. riskValue: riskValue.trim(),
  250. ipType: ipType.trim(),
  251. nativeIP: nativeIP.trim(),
  252. };
  253. console.log("Parsed Ping0 data:", ping0Data);
  254. return ping0Data;
  255. }
  256.  
  257. function displayIPDetails(ipv6, details, riskData, ping0Data) {
  258. console.log("Displaying IP details...");
  259. let ipElement = document.getElementById("ipInfo");
  260. if (!ipElement) {
  261. ipElement = document.createElement("div");
  262. ipElement.id = "ipInfo";
  263. ipElement.style.position = "fixed";
  264. ipElement.style.top = GM_getValue("ipInfoTop", "10px");
  265. ipElement.style.right = "-1000px";
  266. ipElement.style.backgroundColor = "#0a0a0a";
  267. ipElement.style.padding = "15px";
  268. ipElement.style.borderRadius = "0 0 0 10px";
  269. ipElement.style.boxShadow = "0 0 20px rgba(0,255,255,0.3)";
  270. ipElement.style.fontSize = "14px";
  271. ipElement.style.color = "#00ffff";
  272. ipElement.style.zIndex = "9999";
  273. ipElement.style.transition = "right 0.3s ease, box-shadow 0.3s ease";
  274. ipElement.style.fontFamily = "'Orbitron', sans-serif";
  275. ipElement.style.border = "1px solid #00ffff";
  276. const title = document.createElement("div");
  277. title.style.fontWeight = "bold";
  278. title.style.marginBottom = "10px";
  279. title.style.fontSize = "18px";
  280. title.style.textShadow = "0 0 5px #00ffff";
  281. title.innerText = "IP检测信息";
  282.  
  283. const refreshButton = createButton("刷新IP信息", fetchCurrentIP);
  284. refreshButton.id = "refreshIpInfo";
  285. const toggleButton = createButton("展开信息", toggleIpInfo);
  286. toggleButton.id = "toggleIpInfo";
  287. toggleButton.style.display = "none";
  288. const inputContainer = document.createElement("div");
  289. inputContainer.style.marginTop = "10px";
  290. const ipInput = document.createElement("input");
  291. ipInput.id = "queryIpInput";
  292. ipInput.type = "text";
  293. ipInput.placeholder = "输入IP地址";
  294. ipInput.style.marginRight = "5px";
  295. ipInput.style.marginRight = "5px";
  296. ipInput.style.width = "auto";
  297. ipInput.style.color = "#00ffff";
  298. ipInput.style.border = "1px solid #00ffff";
  299. ipInput.style.padding = "5px";
  300. const queryButton = createButton("查询IP", queryIpInfo);
  301.  
  302. queryButton.id = "queryIpButton";
  303. queryButton.innerHTML = "查询IP";
  304. queryButton.style.width = "auto";
  305. queryButton.style.backgroundColor = "#1a1a1a";
  306. queryButton.style.color = "#00ffff";
  307. queryButton.style.border = "1px solid #00ffff";
  308. queryButton.style.borderRadius = "0";
  309. queryButton.style.padding = "5px 10px";
  310. queryButton.style.cursor = "pointer";
  311. queryButton.style.fontSize = "12px";
  312. queryButton.style.transition = "background-color 0.3s, box-shadow 0.3s";
  313. queryButton.onclick = queryIpInfo;
  314.  
  315. const dragHandle = document.createElement("div");
  316. dragHandle.style.width = "100%";
  317. dragHandle.style.height = "10px";
  318. dragHandle.style.backgroundColor = "#00ffff";
  319. dragHandle.style.cursor = "move";
  320. dragHandle.style.marginBottom = "10px";
  321. dragHandle.onmousedown = startDragging;
  322. const content = document.createElement("div");
  323. content.id = "ipInfoContent";
  324. title.appendChild(refreshButton);
  325. title.appendChild(toggleButton);
  326. inputContainer.appendChild(ipInput);
  327. inputContainer.appendChild(queryButton);
  328. title.appendChild(inputContainer);
  329. ipElement.appendChild(title);
  330. ipElement.appendChild(dragHandle);
  331. ipElement.appendChild(content);
  332. document.body.appendChild(ipElement);
  333.  
  334. // 创建展开按钮
  335. const expandButton = createButton("展开信息", toggleIpInfo);
  336. expandButton.id = "expandIpInfo";
  337. expandButton.style.position = "fixed";
  338.  
  339. expandButton.style.top = GM_getValue("ipInfoTop", "10px");
  340. expandButton.style.right = "0";
  341. expandButton.style.display = "block";
  342. document.body.appendChild(expandButton);
  343. expandButton.style.zIndex = "999999999";
  344. }
  345.  
  346. let contentElement = document.getElementById("ipInfoContent");
  347. if (!contentElement) {
  348. contentElement = document.createElement("div");
  349. contentElement.id = "ipInfoContent";
  350. ipElement.appendChild(contentElement);
  351. }
  352.  
  353. const content = `
  354. <div>
  355. <strong>IPv4:</strong> ${
  356. details.query
  357. } <span id="copyButtonContainer1"></span>
  358. </div>
  359. <div>
  360. <strong>IPv6:</strong> ${
  361. ipv6 ? ipv6 : "N/A"
  362. } <span id="copyButtonContainer2"></span>
  363. </div>
  364. <div style="word-wrap: break-word; max-width: 300px;">
  365. <strong>城市:</strong> ${details.city}, ${details.regionName}
  366. </div>
  367. <div>
  368. <strong>zip:</strong> ${details.zip ? details.zip : "N/A"}
  369. </div>
  370. <div>
  371. <strong>国家:</strong> ${details.country}
  372. </div>
  373. <div style="word-wrap: break-word; max-width: 300px;">
  374. <strong>ISP:</strong> ${details.isp}
  375. </div>
  376. <div style="word-wrap: break-word; max-width: 300px;">
  377. <strong>AS:</strong> ${details.as}
  378. </div>
  379. <div>
  380. <strong>风险评分:</strong> ${
  381. riskData ? riskData.score : "N/A"
  382. }
  383. </div>
  384. <div>
  385. <strong>风险类型:</strong> ${riskData ? riskData.risk : "N/A"}
  386. </div>
  387. <div>
  388. <strong>Ping0风险值:</strong> ${
  389. ping0Data ? ping0Data.riskValue : "N/A"
  390. }
  391. </div>
  392. <div>
  393. <strong>IP类型:</strong> ${
  394. ping0Data ? ping0Data.ipType : "N/A"
  395. }
  396. </div>
  397. <div>
  398. <strong>原生IP:</strong> ${
  399. ping0Data ? ping0Data.nativeIP : "N/A"
  400. }
  401. </div>
  402. <hr>
  403. `;
  404. contentElement.innerHTML = content; // Use innerHTML instead of insertAdjacentHTML to replace old content
  405. // 添加复制按钮到 copyButtonContainer
  406. const copyButtonContainer1 = document.getElementById(
  407. "copyButtonContainer1"
  408. );
  409. copyButtonContainer1.appendChild(createCopyButton(details.query));
  410. const copyButtonContainer2 = document.getElementById(
  411. "copyButtonContainer2"
  412. );
  413. copyButtonContainer2.appendChild(createCopyButton(ipv6));
  414. }
  415.  
  416. function isValidIPv4(ip) {
  417. const ipv4Pattern =
  418. /^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}$/;
  419. return ipv4Pattern.test(ip);
  420. }
  421.  
  422. function queryIpInfo() {
  423. const queryIp = document.getElementById("queryIpInput").value.trim();
  424. const queryButton = document.getElementById("queryIpButton");
  425.  
  426. if (!queryIp) {
  427. alert("请输入一个有效的IP地址");
  428. return;
  429. }
  430.  
  431. if (!isValidIPv4(queryIp)) {
  432. alert("请输入一个有效的IPv4地址");
  433. return;
  434. }
  435.  
  436. console.log("Querying IP info for:", queryIp);
  437.  
  438. // 禁用查询按钮并显示“正在查询”
  439. queryButton.disabled = true;
  440. queryButton.innerHTML = "正在查询...";
  441.  
  442. // 调用 fetchIPDetails 并传递回调函数以恢复按钮状态
  443. fetchIPDetails(queryIp, null, function () {
  444. // 查询完成后恢复按钮状态
  445. queryButton.disabled = false;
  446. queryButton.innerHTML = "查询IP";
  447. });
  448. }
  449. function createButton(text, onClick) {
  450. const button = document.createElement("button");
  451. button.innerHTML = text;
  452. button.style.backgroundColor = "#1a1a1a";
  453. button.style.width = "auto";
  454. button.style.color = "#00ffff";
  455. button.style.border = "1px solid #00ffff";
  456. button.style.borderRadius = "0";
  457. button.style.padding = "5px 10px";
  458. button.style.cursor = "pointer";
  459. button.style.fontSize = "12px";
  460. button.style.marginLeft = "5px";
  461. button.style.transition = "background-color 0.3s, box-shadow 0.3s";
  462. button.style.fontFamily = "'Orbitron', sans-serif";
  463. button.onclick = onClick;
  464. button.onmouseover = function () {
  465. this.style.backgroundColor = "#00ffff";
  466. this.style.color = "#1a1a1a";
  467. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  468. };
  469. button.onmouseout = function () {
  470. this.style.backgroundColor = "#1a1a1a";
  471. this.style.color = "#00ffff";
  472. this.style.boxShadow = "none";
  473. };
  474. return button;
  475. }
  476. function createCopyButton(text) {
  477. const button = document.createElement("button");
  478. button.innerHTML = "复制";
  479. button.style.width = "auto";
  480. button.style.backgroundColor = "#1a1a1a";
  481. button.style.color = "#00ffff";
  482. button.style.border = "1px solid #00ffff";
  483. button.style.borderRadius = "0";
  484. button.style.padding = "2px 5px";
  485. button.style.cursor = "pointer";
  486. button.style.fontSize = "12px";
  487. button.style.marginLeft = "5px";
  488. button.style.transition = "background-color 0.3s, box-shadow 0.3s";
  489. button.style.fontFamily = "'Orbitron', sans-serif";
  490. button.onclick = (event) => {
  491. event.stopPropagation();
  492. navigator.clipboard
  493. .writeText(text)
  494. .then(() => {
  495. button.innerHTML = "已复制";
  496. setTimeout(() => {
  497. button.innerHTML = "复制";
  498. }, 500);
  499. })
  500. .catch((err) => {
  501. console.error("复制失败: ", err);
  502. });
  503. };
  504. button.onmouseover = function () {
  505. this.style.backgroundColor = "#00ffff";
  506. this.style.color = "#1a1a1a";
  507. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  508. };
  509. button.onmouseout = function () {
  510. this.style.backgroundColor = "#1a1a1a";
  511. this.style.color = "#00ffff";
  512. this.style.boxShadow = "none";
  513. };
  514. return button;
  515. }
  516.  
  517. function showQueryButton(ip, event) {
  518. let queryButton = document.getElementById("floatingQueryButton");
  519. if (!queryButton) {
  520. queryButton = document.createElement("button");
  521. queryButton.id = "floatingQueryButton";
  522. queryButton.innerHTML = "查询IP";
  523. queryButton.style.position = "fixed";
  524. queryButton.style.width = "auto";
  525. queryButton.style.zIndex = "10000";
  526. queryButton.style.padding = "5px 10px";
  527. queryButton.style.backgroundColor = "#1a1a1a";
  528. queryButton.style.color = "#00ffff";
  529. queryButton.style.border = "1px solid #00ffff";
  530. queryButton.style.borderRadius = "0";
  531. queryButton.style.cursor = "pointer";
  532. queryButton.style.fontSize = "12px";
  533. queryButton.style.fontFamily = "'Orbitron', sans-serif";
  534. queryButton.style.transition = "background-color 0.3s, box-shadow 0.3s";
  535. document.body.appendChild(queryButton);
  536. }
  537. queryButton.style.left = `${event.clientX + 10}px`;
  538. queryButton.style.top = `${event.clientY + 10}px`;
  539. queryButton.style.display = "block";
  540. queryButton.onclick = function () {
  541. document.getElementById("queryIpInput").value = ip;
  542. const ipElement = document.getElementById("ipInfo");
  543. if (ipElement.style.right !== "0px") {
  544. toggleIpInfo();
  545. }
  546. queryIpInfo();
  547. this.style.display = "none";
  548. };
  549. queryButton.onmouseover = function () {
  550. this.style.backgroundColor = "#00ffff";
  551. this.style.color = "#1a1a1a";
  552. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  553. };
  554. queryButton.onmouseout = function () {
  555. this.style.backgroundColor = "#1a1a1a";
  556. this.style.color = "#00ffff";
  557. this.style.boxShadow = "none";
  558. };
  559. }
  560. // 添加选择文本和显示查询按钮的功能
  561. document.addEventListener("mouseup", handleTextSelection);
  562.  
  563. function handleTextSelection(event) {
  564. // 检查点击是否发生在 IP 信息面板内
  565. const ipElement = document.getElementById("ipInfo");
  566. const expandIpButton = document.getElementById("expandIpInfo");
  567. if (
  568. (ipElement && ipElement.contains(event.target)) ||
  569. (expandIpButton && expandIpButton.contains(event.target))
  570. ) {
  571. return; // 如果点击在 IP 信息面板内,不执行后续操作
  572. }
  573.  
  574. const selectedText = window.getSelection().toString().trim();
  575. if (isValidIPv4(selectedText)) {
  576. showQueryButton(selectedText, event);
  577. }
  578. }
  579.  
  580. // 修改 toggleIpInfo 函数
  581. function toggleIpInfo() {
  582. const ipElement = document.getElementById("ipInfo");
  583. const expandButton = document.getElementById("expandIpInfo");
  584. const toggleButton = document.getElementById("toggleIpInfo");
  585. if (ipElement.style.right === "0px") {
  586. ipElement.style.right = "-1000px";
  587. toggleButton.innerHTML = "展开信息";
  588. toggleButton.style.display = "none";
  589. expandButton.style.display = "block";
  590. } else {
  591. ipElement.style.right = "0px";
  592. toggleButton.innerHTML = "隐藏信息";
  593. toggleButton.style.display = "inline-block";
  594. expandButton.style.display = "none";
  595. }
  596. }
  597.  
  598. let initialTop = 10;
  599. let initialY = 0;
  600. let dragging = false;
  601.  
  602. function startDragging(e) {
  603. console.log("Start dragging...");
  604. dragging = true;
  605. initialY = e.clientY;
  606. const ipElement = document.getElementById("ipInfo");
  607. const expandButton = document.getElementById("expandIpInfo");
  608. initialTop = parseInt(ipElement.style.top, 10);
  609. expandButton.style.top = ipElement.style.top; // 同步expandButton的位置
  610. document.addEventListener("mousemove", handleDragging);
  611. document.addEventListener("mouseup", stopDragging);
  612. }
  613.  
  614. function handleDragging(e) {
  615. if (dragging) {
  616. console.log("Dragging...");
  617. const deltaY = e.clientY - initialY;
  618. const newTop = initialTop + deltaY;
  619. const ipElement = document.getElementById("ipInfo");
  620. const expandButton = document.getElementById("expandIpInfo");
  621. ipElement.style.top = newTop + "px";
  622. expandButton.style.top = newTop + "px"; // 同步expandButton的位置
  623. }
  624. }
  625.  
  626. function stopDragging() {
  627. console.log("Stop dragging...");
  628. dragging = false;
  629. document.removeEventListener("mousemove", handleDragging);
  630. document.removeEventListener("mouseup", stopDragging);
  631.  
  632. const ipElement = document.getElementById("ipInfo");
  633. GM_setValue("ipInfoTop", ipElement.style.top);
  634.  
  635. const expandButton = document.getElementById("expandIpInfo");
  636. GM_setValue("expandButtonTop", expandButton.style.top); // 同步保存expandButton的位置
  637. }
  638.  
  639. // 添加全局样式
  640. const style = document.createElement("style");
  641. style.textContent = `
  642. // @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
  643. #ipInfo, #expandIpInfo, #floatingQueryButton, #queryIpInput, #queryIpButton {
  644. font-family: 'Arial', sans-serif;
  645. }
  646. #ipInfo:hover {
  647. box-shadow: 0 0 30px rgba(0,255,255,0.5);
  648. }
  649. #queryIpInput {
  650. background-color: #1a1a1a;
  651. color: #00ffff;
  652. border: 1px solid #00ffff;
  653. padding: 5px;
  654. font-size: 12px;
  655. }
  656. #queryIpButton {
  657. background-color: #1a1a1a;
  658. color: #00ffff;
  659. border: 1px solid #00ffff;
  660. border-radius: 0;
  661. padding: 5px 10px;
  662. cursor: pointer;
  663. font-size: 12px;
  664. transition: background-color 0.3s, box-shadow 0.3s;
  665. }
  666. #queryIpButton:hover {
  667. background-color: #00ffff;
  668. color: #1a1a1a;
  669. box-shadow: 0 0 10px rgba(0,255,255,0.5);
  670. }
  671. `;
  672. document.head.appendChild(style);
  673. // 初始创建ipElement,但不触发数据获取
  674. displayIPDetails(null, null, null, null);
  675. })();