您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展(如 Stylus)后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
您需要先安装一款用户样式管理器扩展后才能安装此样式。
(我已经安装了用户样式管理器,让我安装!)
// ==UserScript==
// @name InsCNM
// @namespace http://tampermonkey.net/
// @version 4.4
// @description Automatically fetch media information from Instagram URLs.
// @author Belugu
// @match https://www.instagram.com/p/*
// @grant GM_xmlhttpRequest
// @require https://code.jquery.com/jquery-3.6.0.min.js
// @icon https://iili.io/29TPCR1.jpg
// ==/UserScript==
(function() {
// Main logic
$(document).ready(async function() {
if (window.location.href.match(/^https:\/\/www\.instagram\.com\/p\/[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];
showMediaInfoUI(`
<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>
`);
} else {
showMediaInfoUI('<p>获取媒体信息失败。</p>');
}
}
}
});
function showMediaInfoUI(mediaInfoHtml) {
const container = $(
`<div id="instagram-fetcher-ui" style="position:fixed; top:20px; right:-350px; background:white; color:black; border:1px solid #ccc; padding:15px; z-index:10000; width:300px; border-radius:10px;">
<div style="display: flex; justify-content: space-between; align-items: center;">
<h3 style="color:black; margin:0;">输入网址后按 Enter 搜索</h3>
<button id="close-ui-button" style="background:none; border:none; font-size:20px; cursor:pointer; color:black;">×</button>
</div>
<div id="input-area" style="display: flex; align-items: center; margin-top:10px;">
<input type="text" id="instagram-url-input" placeholder="输入网址" style="width:80%; padding:5px; color:black; border:1px solid #ccc; border-radius:5px; box-shadow:none; outline:none;"/>
</div>
<div id="media-info-output" style="margin-top:15px; font-size:14px;">${mediaInfoHtml}</div>
</div>`
);
$('body').append(container);
$('#instagram-fetcher-ui').animate({ right: '20px' }, 400);
$('#instagram-url-input').on('keypress', async function(e) {
if (e.which === 13) { // Enter key pressed
const url = $('#instagram-url-input').val();
if (url) {
const shortcode = extractShortcodeFromURL(url);
if (shortcode) {
$('#media-info-output').text('正在获取媒体信息...');
const mediaInfo = await fetchMediaInfoByShortcode(shortcode);
if (mediaInfo) {
const { taken_at, comment_count, like_count } = mediaInfo.items[0];
$('#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>`
);
} else {
$('#media-info-output').text('获取媒体信息失败。');
}
} else {
$('#media-info-output').text('无效的 Instagram URL。');
}
}
}
});
$('#close-ui-button').click(function() {
$(this).css({ transform: 'scale(0.95)' });
setTimeout(() => $(this).css({ transform: 'scale(1)' }), 100);
$('#instagram-fetcher-ui').animate({ right: '-350px' }, 400, function() {
$(this).remove();
});
});
$(document).on('click', '.copy-btn', function() {
const textToCopy = $(this).data('copy');
navigator.clipboard.writeText(textToCopy).then(() => {
showNotification("已复制到剪贴板");
}).catch(err => {
console.error('复制失败:', err);
});
});
}
// Function to get a random gradient color
function getRandomGradient() {
const gradients = [
'#6a11cb, #2575fc', // Blue gradient
'#11998e, #38ef7d', // Green gradient
'#ff7e5f, #feb47b', // Original orange gradient
'#ff6a00, #ee0979', // Red gradient
'#43cea2, #185a9d' // Aqua gradient
];
return gradients[Math.floor(Math.random() * gradients.length)];
}
// Function to show a simple notification with animation
function showNotification(message) {
const gradient = getRandomGradient(); // Get the gradient before usage
const notification = $(
`<div class="notification" style="position:fixed; bottom:-60px; right:20px; background: linear-gradient(to right, ${gradient}); color:white; padding:10px; border-radius:5px; z-index:10001; opacity:0.9;">
${message}
</div>`
);
// Adjust the position of existing notifications
$('.notification').each(function() {
const currentBottom = parseInt($(this).css('bottom'));
$(this).css('bottom', currentBottom + 60 + 'px');
});
$('body').append(notification);
notification.animate({ bottom: '40px', opacity: 1 }, 400).delay(3000).animate({ opacity: 0 }, 400, function() {
$(this).remove();
});
}
// Listen for Alt+N to toggle the input UI
document.addEventListener('keydown', function (e) {
if (e.altKey && e.key === 'n') {
const container = $('#instagram-fetcher-ui');
if (container.length) {
container.find('#close-ui-button').click();
} else {
showMediaInfoUI('<p>输入网址后按 Enter 搜索。</p>');
}
}
});
// Function to extract the shortcode from a given URL
function extractShortcodeFromURL(url) {
try {
const urlObj = new URL(url);
const pathSegments = urlObj.pathname.split('/');
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;
}
}
// Function to fetch media info by shortcode
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;
}
}
// Function to fetch media ID using shortcode
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 to get app ID
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;
}
// Function to get media info using media ID
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);
}
});
});
}
})();