InsCNM

获取INS数据!

您需要先安裝使用者腳本管理器擴展,如 TampermonkeyGreasemonkeyViolentmonkey 之後才能安裝該腳本。

You will need to install an extension such as Tampermonkey to install this script.

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyViolentmonkey 後才能安裝該腳本。

您需要先安裝使用者腳本管理器擴充功能,如 TampermonkeyUserscripts 後才能安裝該腳本。

你需要先安裝一款使用者腳本管理器擴展,比如 Tampermonkey,才能安裝此腳本

您需要先安裝使用者腳本管理器擴充功能後才能安裝該腳本。

(我已經安裝了使用者腳本管理器,讓我安裝!)

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展,比如 Stylus,才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

你需要先安裝一款使用者樣式管理器擴展後才能安裝此樣式

(我已經安裝了使用者樣式管理器,讓我安裝!)

// ==UserScript==
// @name         InsCNM
// @namespace    http://tampermonkey.net/
// @version      5.7
// @description  获取INS数据!
// @author       Belugu
// @match        https://www.instagram.com/p/*
// @match        https://www.instagram.com/reel/*
// @match        https://www.instagram.com/*
// @grant        GM_xmlhttpRequest
// @grant        GM_getResourceText
// @grant        GM_addStyle
// @require      https://code.jquery.com/jquery-3.6.0.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/toastify-js/1.12.0/toastify.min.js
// @resource     TOASTIFY_CSS https://cdn.jsdelivr.net/npm/toastify-js/src/toastify.min.css
// @icon         https://iili.io/29TPCR1.jpg
// ==/UserScript==

(function() {
  'use strict';

  // 添加 Toastify 的 CSS 样式
  GM_addStyle(GM_getResourceText("TOASTIFY_CSS"));

  // Main logic
  $(document).ready(async function() {
  if (window.location.href.match(/^https:\/\/www\.instagram\.com\/(p|reel)\/[a-zA-Z0-9_-]+\/$/)) {
    const shortcode = extractShortcodeFromURL(window.location.href);
    if (shortcode) {
      const mediaInfo = await fetchMediaInfoByShortcode(shortcode);
      if (mediaInfo) {
        const { taken_at, comment_count, like_count } = mediaInfo.items[0];
        const mediaInfoHtml = `
          <p>发布时间: ${new Date(taken_at * 1000).toLocaleString()} <button class="copy-btn" data-copy="${new Date(taken_at * 1000).toLocaleString()}" style="background:none; border:none; cursor:pointer;">📋</button></p>
          <p>评论数: ${comment_count} <button class="copy-btn" data-copy="${comment_count}" style="background:none; border:none; cursor:pointer;">📋</button></p>
          <p>点赞数: ${like_count} <button class="copy-btn" data-copy="${like_count}" style="background:none; border:none; cursor:pointer;">📋</button></p>
        `;
        showMediaInfoUI(mediaInfoHtml);
      } else {
        showMediaInfoUI('<p>获取媒体信息失败。</p>');
      }
    }
  } else {
    // 如果不是特定的帖子页面,显示默认界面
    showMediaInfoUI('<p>输入网址后按 Enter 搜索。</p>');
  }
});

function showMediaInfoUI(mediaInfoHtml) {
  // 检查是否已经存在菜单界面
  if ($('#instagram-fetcher-ui').length) {
    // 如果存在,更新内容即可
    $('#media-info-output').html(mediaInfoHtml);
    return;
  }

  const container = $(
    `<div id="instagram-fetcher-ui" style="
      position:fixed;
      top:20px;
      right:-350px;
      background: rgba(255, 255, 255, 0.7);
      color:black;
      border:1px solid #ccc;
      padding:15px;
      z-index:10000;
      width:350px;
      border-radius:10px;
      backdrop-filter: blur(10px);
      box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
      cursor: move;
    ">
      <div style="display: flex; justify-content: space-between; align-items: center;">
        <h3 style="color:black; margin:0; text-align:center; width:100%;">insCNM</h3>
      </div>
      <div id="input-area" style="margin-top:10px; width: 100%;">
        <input type="text" id="instagram-url-input" placeholder="输入网址" style="
          width: 100%;
          padding:5px;
          margin: 0;
          border:1px solid #ccc;
          border-radius:5px;
          box-sizing: border-box; /* 添加这行 */
          background: rgba(255, 255, 255, 0.8);
        " />
      </div>
      <div id="media-info-output" style="
          margin-top:15px;
          font-size:14px;
          text-align: left;
          width: 100%;
        ">${mediaInfoHtml}</div>
    </div>`
  );

  $('body').append(container);
  $('#instagram-fetcher-ui').animate({ right: '20px' }, 400);

  // 调用函数使菜单可拖动
  dragElement(document.getElementById("instagram-fetcher-ui"));

    $('#instagram-url-input').on('click', function() {
      $(this).focus();
    });

    $('#instagram-url-input').on('keyup', async function(e) {
      if (e.which === 13) { // Enter key pressed
        const url = $('#instagram-url-input').val();
        console.log("User entered URL:", url);
        if (url) {
          const shortcode = extractShortcodeFromURL(url);
          if (shortcode) {
            $('#media-info-output').slideUp(200, async function() {
              $('#media-info-output').text('正在获取媒体信息...');
              $(this).slideDown(200);
            });
            const mediaInfo = await fetchMediaInfoByShortcode(shortcode);
            if (mediaInfo) {
              const { taken_at, comment_count, like_count } = mediaInfo.items[0];
              $('#media-info-output').slideUp(200, function() {
                $('#media-info-output').html(
                  `<p>发布时间: ${new Date(taken_at * 1000).toLocaleString()} <button class="copy-btn" data-copy="${new Date(taken_at * 1000).toLocaleString()}" style="background:none; border:none; cursor:pointer;">📋</button></p>
                   <p>评论数: ${comment_count} <button class="copy-btn" data-copy="${comment_count}" style="background:none; border:none; cursor:pointer;">📋</button></p>
                   <p>点赞数: ${like_count} <button class="copy-btn" data-copy="${like_count}" style="background:none; border:none; cursor:pointer;">📋</button></p>`
                );
                $(this).slideDown(400);
              });
            } else {
              $('#media-info-output').slideUp(200, function() {
                $('#media-info-output').text('获取媒体信息失败。').slideDown(400);
              });
            }
          } else {
            $('#media-info-output').slideUp(200, function() {
              $('#media-info-output').text('无效的 Instagram URL。').slideDown(400);
            });
          }
        }
      }
    });

    $(document).on('click', '.copy-btn', function() {
      const textToCopy = $(this).data('copy');
      navigator.clipboard.writeText(textToCopy).then(() => {
        showNotification("已复制到剪贴板");
      }).catch(err => {
        console.error('复制失败:', err);
      });
    });
  }

  function showNotification(message) {
    Toastify({
      text: message,
      duration: 3000,
      close: true,
      gravity: 'top',
      position: 'center',
      style: {
        background: getRandomGradientColor(),
        color: '#FFFFFF',
        borderRadius: '2px',
      },
      stopOnFocus: true,
    }).showToast();
  }

  function getRandomGradientColor() {
    const gradients = [
      'linear-gradient(120deg, #89f7fe 0%, #66a6ff 100%)',
      'linear-gradient(to right, #d4fc79, #96e6a1)',
      'linear-gradient(to right, #ff0844, #ffb199)',
      'linear-gradient(to right, #f83600, #f9d423)',
      'linear-gradient(to right, #00cdac, #8ddad5)',
      'linear-gradient(to right, #df89b5, #bfd9fe)',
      'linear-gradient(to right, #d7d2cc, #304352)',
      'linear-gradient(to right, #c1c161, #d4d4b1)',
      'linear-gradient(to right, #20E2D7, #F9FEA5)',
      'linear-gradient(to right, #8360c3, #2ebf91)'
    ];
    return gradients[Math.floor(Math.random() * gradients.length)];
  }

  document.addEventListener('keydown', function (e) {
    if (e.altKey && e.key === 'n') {
      const container = $('#instagram-fetcher-ui');
      if (container.length) {
        container.css({
          transition: 'all 0.5s ease',
          filter: 'blur(10px)',
          opacity: '0'
        });
        setTimeout(() => container.remove(), 500);
      } else {
        showMediaInfoUI('<p>输入网址后按 Enter 搜索。</p>');
      }
    }
  });

  function extractShortcodeFromURL(url) {
    try {
      const urlObj = new URL(url);
      const pathSegments = urlObj.pathname.split('/');
      console.log("URL Object:", urlObj);
      console.log("Path Segments:", pathSegments);
      if (pathSegments[1] === 'p' || pathSegments[1] === 'reel') {
        return pathSegments[2] ? pathSegments[2] : null;
      }
      return null;
    } catch (error) {
      console.error("Error extracting shortcode from URL:", error);
      return null;
    }
  }

  async function fetchMediaInfoByShortcode(shortcode) {
    const mediaId = await getMediaID(shortcode);
    if (!mediaId) {
      console.error("Failed to fetch media ID.");
      $('#media-info-output').text('获取媒体 ID 失败,请稍后重试。');
      return null;
    }

    try {
      const mediaInfo = await getMediaInfo(mediaId);
      console.log("Media Info:", mediaInfo);
      return mediaInfo;
    } catch (error) {
      console.error("Error retrieving media info:", error);
      return null;
    }
  }

  async function getMediaID(shortcode) {
    try {
      const response = await fetch(`https://www.instagram.com/p/${shortcode}/`, {
        headers: {
          "User-Agent": window.navigator.userAgent,
          "Accept": "text/html"
        }
      });
      if (!response.ok) {
        throw new Error(`HTTP error! status: ${response.status}`);
      }
      const html = await response.text();
      const mediaIdMatch = html.match(/"media_id":"(\d+)"/);
      if (mediaIdMatch) {
        return mediaIdMatch[1];
      } else {
        console.error("Media ID not found in page HTML.");
      }
    } catch (error) {
      console.error("Error fetching media ID:", error);
    }
    return null;
  }

  function getAppID() {
    let result = null;
    $('script[type="application/json"]').each(function() {
      const regexp = /"APP_ID":"([0-9]+)"/ig;
      const matcher = $(this).text().match(regexp);
      if (matcher != null && result == null) {
        result = [...$(this).text().matchAll(regexp)];
      }
    });
    return (result) ? result.at(0).at(-1) : null;
  }

  async function getMediaInfo(mediaId) {
    return new Promise((resolve, reject) => {
      let getURL = `https://i.instagram.com/api/v1/media/${mediaId}/info/`;

      if (mediaId == null) {
        console.error("Cannot call Media API because the media ID is invalid.");
        reject("Cannot call Media API because the media ID is invalid.");
        return;
      }

      GM_xmlhttpRequest({
        method: "GET",
        url: getURL,
        headers: {
          "User-Agent": window.navigator.userAgent,
          "Accept": "application/json",
          'X-IG-App-ID': getAppID()
        },
        onload: function (response) {
          try {
            if (response.finalUrl == getURL) {
              let obj = JSON.parse(response.responseText);
              resolve(obj);
            } else {
              let finalURL = new URL(response.finalUrl);
              if (finalURL.pathname.startsWith('/accounts/login')) {
                console.error("The account must be logged in to access Media API.");
              } else {
                console.error('Unable to retrieve content because the API was redirected to "' + response.finalUrl + '"');
              }
              reject(-1);
            }
          } catch (error) {
            console.error("Error parsing JSON response:", error);
            reject(error);
          }
        },
        onerror: function (err) {
          reject(err);
        }
      });
    });
  }

  // 使元素可拖动的函数
  function dragElement(element) {
    let pos1 = 0, pos2 = 0, pos3 = 0, pos4 = 0;
    if (element) {
      element.onmousedown = dragMouseDown;
    }

    function dragMouseDown(e) {
      e = e || window.event;
      e.preventDefault();
      // 获取鼠标的初始位置
      pos3 = e.clientX;
      pos4 = e.clientY;
      document.onmouseup = closeDragElement;
      document.onmousemove = elementDrag;
    }

    function elementDrag(e) {
      e = e || window.event;
      e.preventDefault();
      // 计算鼠标移动的距离
      pos1 = pos3 - e.clientX;
      pos2 = pos4 - e.clientY;
      pos3 = e.clientX;
      pos4 = e.clientY;
      // 设置元素的新位置
      element.style.top = (element.offsetTop - pos2) + "px";
      element.style.left = (element.offsetLeft - pos1) + "px";
    }

    function closeDragElement() {
      // 停止拖动时清除事件监听
      document.onmouseup = null;
      document.onmousemove = null;
    }
  }
})();