论坛列表显示图片0.6
适配了空间页面@Name @Match // ==UserScript==
// @name 显示图片
// @version 0.6
// @description论坛列表显示图片(适配空间
// @author M&U
// @match https://www.gamemale.com/*
// @exclude https://www.gamemale.com/forum.php
// @grant GM_addStyle
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_xmlhttpRequest
// ==/UserScript==
(function () {
'use strict';
const TYPE_HANDLERS = [
{
name: "discuz",
articleListSelector: 'tbody:not()',
articleLinkSelector: '.icn a',
postContentSelector: 'div .plc',
postImageLinkCallback: function (element) {
return element.getAttribute('file') || element.getAttribute('src');
}
},
{
name: "discuz_search",
articleListSelector: '.slst.mtw li.pbw:not()',
articleLinkSelector: 'h3.xs3 a',
postContentSelector: 'div .plc',
postImageLinkCallback: function (element) {
return element.getAttribute('file') || element.getAttribute('src');
}
},
{
name: "discuz_user_threads",
articleListSelector: '#delform table tbody tr:not(.th):not()',
articleLinkSelector: 'th a:first-child',
postContentSelector: 'div .plc',
postImageLinkCallback: function (element) {
return element.getAttribute('file') || element.getAttribute('src');
}
}
];
const IGNORE_IMAGES = [
/smile|avatar|icon|face|emoji|emoticon/i,
/uc_server|static\/image|data\/avatar/i,
/\.gif(\?|$)/i
];
let previewEnabled = typeof GM_getValue !== 'undefined' ? GM_getValue('previewEnabled', true) : true;
let loadedPosts = new Set();
const toggleButton = document.createElement('button');
toggleButton.textContent = previewEnabled ? '关闭预览' : '开启预览';
toggleButton.style.position = 'fixed';
toggleButton.style.bottom = '20px';
toggleButton.style.right = '20px';
toggleButton.style.zIndex = '9999';
toggleButton.style.padding = '5px 10px';
toggleButton.style.background = previewEnabled ? '#4CAF50' : '#f44336';
toggleButton.style.color = 'white';
toggleButton.style.border = 'none';
toggleButton.style.borderRadius = '3px';
document.body.appendChild(toggleButton);
GM_addStyle(`
.image-row-container {
width: 100%;
clear: both;
margin: 10px 0;
}
.image-row {
display: flex;
width: 100%;
flex-wrap: nowrap;
justify-content: flex-start;
gap: 10px;
}
.image-item {
flex: 0 0 auto;
height: 150px;
}
.preview-image {
height: 100%;
width: auto;
max-width: 300px;
object-fit: contain;
cursor: pointer;
border: 1px solid #ddd;
background: #f5f5f5;
border-radius: 3px;
}
.image-modal {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0,0,0,0.8);
display: none;
justify-content: center;
align-items: center;
z-index: 10000;
}
.image-modal.active {
display: flex;
}
.image-modal img {
max-width: 90%;
max-height: 90%;
object-fit: contain;
}
`);
const modal = document.createElement('div');
modal.className = 'image-modal';
document.body.appendChild(modal);
function isPostHidden(post) {
return post.style.display === 'none';
}
toggleButton.addEventListener('click', function() {
previewEnabled = !previewEnabled;
if (typeof GM_setValue !== 'undefined') {
GM_setValue('previewEnabled', previewEnabled);
}
toggleButton.textContent = previewEnabled ? '关闭预览' : '开启预览';
toggleButton.style.background = previewEnabled ? '#4CAF50' : '#f44336';
document.querySelectorAll('.image-row-container').forEach(container => {
container.remove();
});
document.querySelectorAll('').forEach(post => {
post.removeAttribute('data-enhanced');
});
loadedPosts.clear();
if (previewEnabled) {
init();
}
});
function init() {
if (!previewEnabled) {
document.querySelectorAll('.image-row-container').forEach(container => {
container.remove();
});
return;
}
if (document.getElementById('delform') && document.querySelector('#delform table tbody tr th a')) {
handleForum('discuz_user_threads');
} else if (location.href.includes('forum') && !location.href.includes('search')) {
handleForum('discuz');
} else if (location.href.includes('search')) {
handleForum('discuz_search');
}
}
function handleForum(type) {
if (!previewEnabled) return;
const handler = TYPE_HANDLERS.find(h => h.name === type);
if (!handler) return;
document.querySelectorAll(handler.articleListSelector).forEach(post => {
if (post.hasAttribute('data-enhanced')) return;
if (isPostHidden(post)) return;
post.setAttribute('data-enhanced', 'true');
const link = post.querySelector(handler.articleLinkSelector)?.href;
if (link) loadImages(link, handler, post);
});
}
function shouldIgnoreImage(src) {
return IGNORE_IMAGES.some(regex => regex.test(src));
}
async function loadImages(url, handler, post) {
if (!previewEnabled) return;
const postId = url.split('tid=') || url;
if (loadedPosts.has(postId)) return;
try {
const html = await fetch(url).then(r => r.text());
const doc = new DOMParser().parseFromString(html, 'text/html');
const content = doc.querySelector(handler.postContentSelector);
if (!content) return;
const existingContainer = post.nextElementSibling?.classList?.contains('image-row-container')
? post.nextElementSibling
: null;
if (existingContainer) return;
const container = document.createElement('div');
container.className = 'image-row-container';
const row = document.createElement('div');
row.className = 'image-row';
const uniqueImages = new Set();
const images = Array.from(content.querySelectorAll('img'))
.map(img => handler.postImageLinkCallback(img))
.filter(src => src && !shouldIgnoreImage(src) && !uniqueImages.has(src))
.slice(0, 3);
images.forEach(src => uniqueImages.add(src));
images.forEach(src => {
const item = document.createElement('div');
item.className = 'image-item';
const image = document.createElement('img');
image.className = 'preview-image';
image.src = src;
image.loading = 'lazy';
image.addEventListener('click', () => {
modal.innerHTML = '';
const modalImg = document.createElement('img');
modalImg.src = src;
modal.appendChild(modalImg);
modal.classList.add('active');
});
item.appendChild(image);
row.appendChild(item);
});
if (row.children.length > 0) {
container.appendChild(row);
loadedPosts.add(postId);
if (post.nextElementSibling) {
post.parentNode.insertBefore(container, post.nextElementSibling);
} else {
post.parentNode.appendChild(container);
}
}
} catch (error) {
}
}
modal.addEventListener('click', () => {
modal.classList.remove('active');
});
if (previewEnabled) {
setTimeout(() => init(), 100);
}
let mutationTimeout = null;
new MutationObserver(function(mutations) {
if (!previewEnabled) {
document.querySelectorAll('.image-row-container').forEach(container => {
container.remove();
});
return;
}
clearTimeout(mutationTimeout);
mutationTimeout = setTimeout(() => {
const hasNewPosts = mutations.some(mutation =>
Array.from(mutation.addedNodes).some(node =>
node.nodeType === 1 &&
(node.matches(TYPE_HANDLERS.articleListSelector) ||
node.matches(TYPE_HANDLERS.articleListSelector) ||
node.matches(TYPE_HANDLERS.articleListSelector))
)
);
if (hasNewPosts) {
init();
}
}, 500);
}).observe(document.body, { childList: true, subtree: true });
})();
U老师又出镜了,适配空间页面感觉浏览更方便了惹{:6_169:} 适配空间页面也是很方便集中查看资源大佬的所有帖子的概况了 不需要点进去就可以查看,很方便浏览呢 能在空间显示真的有点厉害的说,这下可以看特定用户的发帖图了;P 又升级了 好勤快啊 老师 喔喔,这个插件好厉害,可以直接看到预览画面好方便 好哦,直接预览图片筛选帖子 太实用了,这样就可以一览大佬所有的图片了,现在才到0.6吗,很难想象到1.0功能会有多么强大{:6_197:} 好用,装上直接对makima的主题进行一个查看测试,上次放大预览图也一起修复了,很好用了 好实用的插件,这下使用起来更方便了 这个插件看着挺方便的,不打开帖子直接能预览里面内容。 期待1.0版本,大佬做的一代更比一代强 感觉这个越做越好了,看起来效果非常棒 其实还是因为思念U狼吧,真希望他能回来,或者至少和大家说一下,告诉我们他在生活里一切都好:) 很棒的插件不用点进去就可以浏览图片了,谢谢楼主分享 好耶,大佬的资源一般都是同类的,根据贝叶斯统计,喜欢其中一个就很可能会喜欢其他{:6_197:}
mkm老师还是忘不了他的u狼{:6_169:} 确实都是很实用的小工具,论坛用起来越来越方便了 之前看有些论坛觉得这个功能真的很方便 现在终于我们论坛也有了 才意识到是从别人空间看的,又进化了这是{:6_167:}