ip-checker

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

当前为 2024-07-26 提交的版本,查看 最新版本

  1. // ==UserScript==
  2. // @name ip-checker
  3. // @namespace http://tampermonkey.net/
  4. // @version 2.2
  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 riskValue = doc.evaluate(
  230. "/html/body/div[2]/div[2]/div[1]/div[2]/div[9]/div[2]/span",
  231. doc,
  232. null,
  233. XPathResult.STRING_TYPE,
  234. null
  235. ).stringValue;
  236. const ipType = doc.evaluate(
  237. "/html/body/div[2]/div[2]/div[1]/div[2]/div[8]/div[2]/span",
  238. doc,
  239. null,
  240. XPathResult.STRING_TYPE,
  241. null
  242. ).stringValue;
  243. const nativeIP = doc.evaluate(
  244. "/html/body/div[2]/div[2]/div[1]/div[2]/div[11]/div[2]/span",
  245. doc,
  246. null,
  247. XPathResult.STRING_TYPE,
  248. null
  249. ).stringValue;
  250.  
  251. const ping0Data = {
  252. riskValue: riskValue.trim(),
  253. ipType: ipType.trim(),
  254. nativeIP: nativeIP.trim(),
  255. };
  256. console.log("Parsed Ping0 data:", ping0Data);
  257. return ping0Data;
  258. }
  259.  
  260. function displayIPDetails(ipv6, details, riskData, ping0Data) {
  261. console.log("Displaying IP details...");
  262. let ipElement = document.getElementById("ipInfo");
  263. if (!ipElement) {
  264. ipElement = document.createElement("div");
  265. ipElement.id = "ipInfo";
  266. ipElement.style.position = "fixed";
  267. ipElement.style.top = GM_getValue("ipInfoTop", "10px");
  268. ipElement.style.right = "-500px";
  269. ipElement.style.backgroundColor = "#0a0a0a";
  270. ipElement.style.padding = "15px";
  271. ipElement.style.borderRadius = "0 0 0 10px";
  272. ipElement.style.boxShadow = "0 0 20px rgba(0,255,255,0.3)";
  273. ipElement.style.fontSize = "14px";
  274. ipElement.style.color = "#00ffff";
  275. ipElement.style.zIndex = "9999";
  276. ipElement.style.transition = "right 0.3s ease, box-shadow 0.3s ease";
  277. ipElement.style.fontFamily = "'Orbitron', sans-serif";
  278. ipElement.style.border = "1px solid #00ffff";
  279. const title = document.createElement("div");
  280. title.style.fontWeight = "bold";
  281. title.style.marginBottom = "10px";
  282. title.style.fontSize = "18px";
  283. title.style.textShadow = "0 0 5px #00ffff";
  284. title.innerText = "IP检测信息";
  285.  
  286. const refreshButton = createButton("刷新IP信息", fetchCurrentIP);
  287. refreshButton.id = "refreshIpInfo";
  288. const toggleButton = createButton("展开信息", toggleIpInfo);
  289. toggleButton.id = "toggleIpInfo";
  290. toggleButton.style.display = "none";
  291. const inputContainer = document.createElement("div");
  292. inputContainer.style.marginTop = "10px";
  293. const ipInput = document.createElement("input");
  294. ipInput.id = "queryIpInput";
  295. ipInput.type = "text";
  296. ipInput.placeholder = "输入IP地址";
  297. ipInput.style.marginRight = "5px";
  298. ipInput.style.backgroundColor = "#1a1a1a";
  299. ipInput.style.color = "#00ffff";
  300. ipInput.style.border = "1px solid #00ffff";
  301. ipInput.style.padding = "5px";
  302. const queryButton = createButton("查询IP", queryIpInfo);
  303.  
  304. queryButton.id = "queryIpButton";
  305. queryButton.innerHTML = "查询IP";
  306. queryButton.style.width = "auto";
  307. queryButton.style.backgroundColor = "#1a1a1a";
  308. queryButton.style.color = "#00ffff";
  309. queryButton.style.border = "1px solid #00ffff";
  310. queryButton.style.borderRadius = "0";
  311. queryButton.style.padding = "5px 10px";
  312. queryButton.style.cursor = "pointer";
  313. queryButton.style.fontSize = "12px";
  314. queryButton.style.transition = "background-color 0.3s, box-shadow 0.3s";
  315. queryButton.onclick = queryIpInfo;
  316.  
  317. const dragHandle = document.createElement("div");
  318. dragHandle.style.width = "100%";
  319. dragHandle.style.height = "10px";
  320. dragHandle.style.backgroundColor = "#00ffff";
  321. dragHandle.style.cursor = "move";
  322. dragHandle.style.marginBottom = "10px";
  323. dragHandle.onmousedown = startDragging;
  324. const content = document.createElement("div");
  325. content.id = "ipInfoContent";
  326. title.appendChild(refreshButton);
  327. title.appendChild(toggleButton);
  328. inputContainer.appendChild(ipInput);
  329. inputContainer.appendChild(queryButton);
  330. title.appendChild(inputContainer);
  331. ipElement.appendChild(title);
  332. ipElement.appendChild(dragHandle);
  333. ipElement.appendChild(content);
  334. document.body.appendChild(ipElement);
  335.  
  336. // 创建展开按钮
  337. const expandButton = createButton("展开信息", toggleIpInfo);
  338. expandButton.id = "expandIpInfo";
  339. expandButton.style.position = "fixed";
  340. expandButton.style.top = GM_getValue("ipInfoTop", "10px");
  341. expandButton.style.right = "0";
  342. expandButton.style.display = "block";
  343. document.body.appendChild(expandButton);
  344. expandButton.style.zIndex = "999999999";
  345. }
  346.  
  347. let contentElement = document.getElementById("ipInfoContent");
  348. if (!contentElement) {
  349. contentElement = document.createElement("div");
  350. contentElement.id = "ipInfoContent";
  351. ipElement.appendChild(contentElement);
  352. }
  353.  
  354. const content = `
  355. <div>
  356. <strong>IPv4:</strong> ${
  357. details.query
  358. } <span id="copyButtonContainer1"></span>
  359. </div>
  360. <div>
  361. <strong>IPv6:</strong> ${
  362. ipv6 ? ipv6 : "N/A"
  363. } <span id="copyButtonContainer2"></span>
  364. </div>
  365. <div>
  366. <strong>城市:</strong> ${details.city}, ${details.regionName}
  367. </div>
  368. <div>
  369. <strong>zip:</strong> ${details.zip ? details.zip : "N/A"}
  370. </div>
  371. <div>
  372. <strong>国家:</strong> ${details.country}
  373. </div>
  374. <div>
  375. <strong>ISP:</strong> ${details.isp}
  376. </div>
  377. <div>
  378. <strong>AS:</strong> ${details.as}
  379. </div>
  380. <div>
  381. <strong>风险评分:</strong> ${riskData ? riskData.score : "N/A"}
  382. </div>
  383. <div>
  384. <strong>风险类型:</strong> ${riskData ? riskData.risk : "N/A"}
  385. </div>
  386. <div>
  387. <strong>Ping0风险值:</strong> ${
  388. ping0Data ? ping0Data.riskValue : "N/A"
  389. }
  390. </div>
  391. <div>
  392. <strong>IP类型:</strong> ${ping0Data ? ping0Data.ipType : "N/A"}
  393. </div>
  394. <div>
  395. <strong>原生IP:</strong> ${
  396. ping0Data ? ping0Data.nativeIP : "N/A"
  397. }
  398. </div>
  399. <hr>
  400. `;
  401. contentElement.innerHTML = content; // Use innerHTML instead of insertAdjacentHTML to replace old content
  402. // 添加复制按钮到 copyButtonContainer
  403. const copyButtonContainer1 = document.getElementById(
  404. "copyButtonContainer1"
  405. );
  406. copyButtonContainer1.appendChild(createCopyButton(details.query));
  407. const copyButtonContainer2 = document.getElementById(
  408. "copyButtonContainer2"
  409. );
  410. copyButtonContainer2.appendChild(createCopyButton(ipv6));
  411. }
  412.  
  413. function isValidIPv4(ip) {
  414. const ipv4Pattern =
  415. /^(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}$/;
  416. return ipv4Pattern.test(ip);
  417. }
  418.  
  419. function queryIpInfo() {
  420. const queryIp = document.getElementById("queryIpInput").value.trim();
  421. const queryButton = document.getElementById("queryIpButton");
  422.  
  423. if (!queryIp) {
  424. alert("请输入一个有效的IP地址");
  425. return;
  426. }
  427.  
  428. if (!isValidIPv4(queryIp)) {
  429. alert("请输入一个有效的IPv4地址");
  430. return;
  431. }
  432.  
  433. console.log("Querying IP info for:", queryIp);
  434.  
  435. // 禁用查询按钮并显示“正在查询”
  436. queryButton.disabled = true;
  437. queryButton.innerHTML = "正在查询...";
  438.  
  439. // 调用 fetchIPDetails 并传递回调函数以恢复按钮状态
  440. fetchIPDetails(queryIp, null, function () {
  441. // 查询完成后恢复按钮状态
  442. queryButton.disabled = false;
  443. queryButton.innerHTML = "查询IP";
  444. });
  445. }
  446. function createButton(text, onClick) {
  447. const button = document.createElement("button");
  448. button.innerHTML = text;
  449. button.style.backgroundColor = "#1a1a1a";
  450. button.style.color = "#00ffff";
  451. button.style.border = "1px solid #00ffff";
  452. button.style.borderRadius = "0";
  453. button.style.padding = "5px 10px";
  454. button.style.cursor = "pointer";
  455. button.style.fontSize = "12px";
  456. button.style.marginLeft = "5px";
  457. button.style.transition = "background-color 0.3s, box-shadow 0.3s";
  458. button.style.fontFamily = "'Orbitron', sans-serif";
  459. button.onclick = onClick;
  460. button.onmouseover = function () {
  461. this.style.backgroundColor = "#00ffff";
  462. this.style.color = "#1a1a1a";
  463. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  464. };
  465. button.onmouseout = function () {
  466. this.style.backgroundColor = "#1a1a1a";
  467. this.style.color = "#00ffff";
  468. this.style.boxShadow = "none";
  469. };
  470. return button;
  471. }
  472.  
  473. function createCopyButton(text) {
  474. const button = document.createElement("button");
  475. button.innerHTML = "复制";
  476. button.style.backgroundColor = "#1a1a1a";
  477. button.style.color = "#00ffff";
  478. button.style.border = "1px solid #00ffff";
  479. button.style.borderRadius = "0";
  480. button.style.padding = "2px 5px";
  481. button.style.cursor = "pointer";
  482. button.style.fontSize = "12px";
  483. button.style.marginLeft = "5px";
  484. button.style.transition = "background-color 0.3s, box-shadow 0.3s";
  485. button.style.fontFamily = "'Orbitron', sans-serif";
  486. button.onclick = (event) => {
  487. event.stopPropagation();
  488. navigator.clipboard
  489. .writeText(text)
  490. .then(() => {
  491. button.innerHTML = "已复制";
  492. setTimeout(() => {
  493. button.innerHTML = "复制";
  494. }, 500);
  495. })
  496. .catch((err) => {
  497. console.error("复制失败: ", err);
  498. });
  499. };
  500. button.onmouseover = function () {
  501. this.style.backgroundColor = "#00ffff";
  502. this.style.color = "#1a1a1a";
  503. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  504. };
  505. button.onmouseout = function () {
  506. this.style.backgroundColor = "#1a1a1a";
  507. this.style.color = "#00ffff";
  508. this.style.boxShadow = "none";
  509. };
  510. return button;
  511. }
  512.  
  513. function showQueryButton(ip, event) {
  514. let queryButton = document.getElementById("floatingQueryButton");
  515. if (!queryButton) {
  516. queryButton = document.createElement("button");
  517. queryButton.id = "floatingQueryButton";
  518. queryButton.innerHTML = "查询IP";
  519. queryButton.style.position = "fixed";
  520. queryButton.style.zIndex = "10000";
  521. queryButton.style.padding = "5px 10px";
  522. queryButton.style.backgroundColor = "#1a1a1a";
  523. queryButton.style.color = "#00ffff";
  524. queryButton.style.border = "1px solid #00ffff";
  525. queryButton.style.borderRadius = "0";
  526. queryButton.style.cursor = "pointer";
  527. queryButton.style.fontSize = "12px";
  528. queryButton.style.fontFamily = "'Orbitron', sans-serif";
  529. queryButton.style.transition = "background-color 0.3s, box-shadow 0.3s";
  530. document.body.appendChild(queryButton);
  531. }
  532. queryButton.style.left = `${event.clientX + 10}px`;
  533. queryButton.style.top = `${event.clientY + 10}px`;
  534. queryButton.style.display = "block";
  535. queryButton.onclick = function () {
  536. document.getElementById("queryIpInput").value = ip;
  537. const ipElement = document.getElementById("ipInfo");
  538. if (ipElement.style.right !== "0px") {
  539. toggleIpInfo();
  540. }
  541. queryIpInfo();
  542. this.style.display = "none";
  543. };
  544. queryButton.onmouseover = function () {
  545. this.style.backgroundColor = "#00ffff";
  546. this.style.color = "#1a1a1a";
  547. this.style.boxShadow = "0 0 10px rgba(0,255,255,0.5)";
  548. };
  549. queryButton.onmouseout = function () {
  550. this.style.backgroundColor = "#1a1a1a";
  551. this.style.color = "#00ffff";
  552. this.style.boxShadow = "none";
  553. };
  554. }
  555. // 添加选择文本和显示查询按钮的功能
  556. document.addEventListener("mouseup", handleTextSelection);
  557.  
  558. function handleTextSelection(event) {
  559. // 检查点击是否发生在 IP 信息面板内
  560. const ipElement = document.getElementById("ipInfo");
  561. const expandIpButton = document.getElementById("expandIpInfo");
  562. if (
  563. (ipElement && ipElement.contains(event.target)) ||
  564. (expandIpButton && expandIpButton.contains(event.target))
  565. ) {
  566. return; // 如果点击在 IP 信息面板内,不执行后续操作
  567. }
  568.  
  569. const selectedText = window.getSelection().toString().trim();
  570. if (isValidIPv4(selectedText)) {
  571. showQueryButton(selectedText, event);
  572. }
  573. }
  574.  
  575. // 修改 toggleIpInfo 函数
  576. function toggleIpInfo() {
  577. const ipElement = document.getElementById("ipInfo");
  578. const expandButton = document.getElementById("expandIpInfo");
  579. const toggleButton = document.getElementById("toggleIpInfo");
  580. if (ipElement.style.right === "0px") {
  581. ipElement.style.right = "-500px";
  582. toggleButton.innerHTML = "展开信息";
  583. toggleButton.style.display = "none";
  584. expandButton.style.display = "block";
  585. } else {
  586. ipElement.style.right = "0px";
  587. toggleButton.innerHTML = "隐藏信息";
  588. toggleButton.style.display = "inline-block";
  589. expandButton.style.display = "none";
  590. }
  591. }
  592.  
  593. let initialTop = 10;
  594. let initialY = 0;
  595. let dragging = false;
  596.  
  597. function startDragging(e) {
  598. console.log("Start dragging...");
  599. dragging = true;
  600. initialY = e.clientY;
  601. const ipElement = document.getElementById("ipInfo");
  602. const expandButton = document.getElementById("expandIpInfo");
  603. initialTop = parseInt(ipElement.style.top, 10);
  604. expandButton.style.top = ipElement.style.top; // 同步expandButton的位置
  605. document.addEventListener("mousemove", handleDragging);
  606. document.addEventListener("mouseup", stopDragging);
  607. }
  608.  
  609. function handleDragging(e) {
  610. if (dragging) {
  611. console.log("Dragging...");
  612. const deltaY = e.clientY - initialY;
  613. const newTop = initialTop + deltaY;
  614. const ipElement = document.getElementById("ipInfo");
  615. const expandButton = document.getElementById("expandIpInfo");
  616. ipElement.style.top = newTop + "px";
  617. expandButton.style.top = newTop + "px"; // 同步expandButton的位置
  618. }
  619. }
  620.  
  621. function stopDragging() {
  622. console.log("Stop dragging...");
  623. dragging = false;
  624. document.removeEventListener("mousemove", handleDragging);
  625. document.removeEventListener("mouseup", stopDragging);
  626.  
  627. const ipElement = document.getElementById("ipInfo");
  628. GM_setValue("ipInfoTop", ipElement.style.top);
  629.  
  630. const expandButton = document.getElementById("expandIpInfo");
  631. GM_setValue("expandButtonTop", expandButton.style.top); // 同步保存expandButton的位置
  632. }
  633.  
  634. // 添加全局样式
  635. const style = document.createElement("style");
  636. style.textContent = `
  637. @import url('https://fonts.googleapis.com/css2?family=Orbitron:wght@400;700&display=swap');
  638. #ipInfo, #expandIpInfo, #floatingQueryButton, #queryIpInput, #queryIpButton {
  639. font-family: 'Orbitron', sans-serif;
  640. }
  641. #ipInfo:hover {
  642. box-shadow: 0 0 30px rgba(0,255,255,0.5);
  643. }
  644. #queryIpInput {
  645. background-color: #1a1a1a;
  646. color: #00ffff;
  647. border: 1px solid #00ffff;
  648. padding: 5px;
  649. font-size: 12px;
  650. }
  651. #queryIpButton {
  652. background-color: #1a1a1a;
  653. color: #00ffff;
  654. border: 1px solid #00ffff;
  655. border-radius: 0;
  656. padding: 5px 10px;
  657. cursor: pointer;
  658. font-size: 12px;
  659. transition: background-color 0.3s, box-shadow 0.3s;
  660. }
  661. #queryIpButton:hover {
  662. background-color: #00ffff;
  663. color: #1a1a1a;
  664. box-shadow: 0 0 10px rgba(0,255,255,0.5);
  665. }
  666. `;
  667. document.head.appendChild(style);
  668. // 初始创建ipElement,但不触发数据获取
  669. displayIPDetails(null, null, null, null);
  670. //fetchCurrentIP();
  671. })();