WWW.YOUINFO.SITE
标签聚合 篡改

/tag/篡改

IT之家 · 2026-05-22 10:47:59+08:00 · tech

IT之家 5 月 22 日消息,“微信派”官方公众号今日发文,解释了 微信为什么只能撤回 2 分钟内的消息 。 “微信派”官方表示, 2 分钟很短,但作为撤回刚刚好 。现实里说错话,你会马上补一句“当我没说”。但你一般都是纠正刚说出口的话,而不会对昨天、上周、上个月的话来一句“我撤回一下”。 还原到线上社交的微信中也是同理: 2 分钟内对方大概率还没读完。撤回 ≈ “我重新说”,聊天节奏不断层。 超过 2 分钟对方已经读完、甚至回复你了。这时候撤回,只会让双方更尴尬 ——“我明明看到了,你非要装没发过?” “微信派”还表示,如果撤回不限时, 发送者就能随意篡改聊天记录 。借钱记录、工作安排、商务承诺,谁都可以说删就删。 需要注意的是,在微信里,不同的消息类型,撤回时不一样: 2 分钟内可撤回: 文字、语音、表情包、图片、视频、公众号链接、视频号链接、小程序卡片等。 3 小时内可撤回: Word、Excel、PPT、PDF、MP3、压缩包等。 那么,微信的文件撤回为什么放宽到 3 小时呢? “微信派”表示, 因为查看文件天然有“时差” 。你下午两点发过去一份 PPT,对方可能正在开会、赶高铁,或者只是单纯地在带薪如厕。等他回到工位、下载、解压、通读完,大半个钟已经过去了。 这种场景下,2 分钟“形同虚设”, 3 小时,才有足够的缓冲带 。 另外,还有两个关于撤回的小细节: 重新编辑:文字消息撤回后, 在 5 分钟内可以点“重新编辑” ,对原文字直接进行修改。 撤回本次发送的全部消息:现在,你一次性转发的多条消息, 数量再多,也能全部撤回了 。 撤回消息为什么会有提醒? “微信派”解释称,现实世界里,聊天说错话,对方是完全知道的。线上也一样。 作为通信工具,首要保障的是送达的准确性 。一个人发送消息后,如果消息说没就没、毫无痕迹,那么“收到没有”、“发过什么”就会变成永远扯不清的无底洞。 而且还有一层“硬件”限制。 以 iOS 为例,手机操作系统对 App 新消息推送机制是这样的: 你在 App 上发消息给用户 A → App 把这条信息推给 iOS → iOS 找到用户 A 的设备 → iOS 把新消息推到用户 A 的手机通知栏 → A 看到“ xx 发来了一条消息” 整个过程都发生在手机系统上。比如这样: 此时再撤回消息,哪怕微信能无痕撤回,但手机通知栏的提醒无法撤回。 大家在 IT之家微信号 回复“ 微信 ”两字,即可获取当前最新官方内部版微信下载。

LinuxDo 最新话题 · 2026-05-18 20:08:35+08:00 · tech

自己折腾了一个 Tampermonkey 脚本,功能比较实用: 划词后出现 红点 ,点击直接翻译选中文字 旁边有 蓝点 ,点击可 全文翻译 全文翻译是 直接替换页面文本节点 支持 恢复原文 支持 多个 API 自动故障回退 点页面其它地方,红蓝点会自动消失 适合拿来自定义接第三方翻译/LLM API,用来看英文网页挺方便。 希望对大家有用,不用折腾沉浸式翻译了,这个就是沉浸式,简单方便好用。好用点赞啊。 // ==UserScript== // @name 划词翻译 + 全文翻译(红点/蓝点/恢复原文/自动回退) // @name:en Selection Translate + Full Page Translate // @namespace http://tampermonkey.net/ // @version 3.2 // @description 红点翻译划词,蓝点全文翻译。直接替换页面文本节点,支持恢复原文,支持多API自动故障回退。 // @author AI Assistant // @match *://*/* // @grant GM_xmlhttpRequest // @grant GM_addStyle // @connect * // @license MIT // ==/UserScript== (function () { 'use strict'; if (window.__AI_TRANSLATOR_FULLPAGE_RUNNING__) { console.log('翻译脚本已在运行,本次加载被阻止。'); return; } window.__AI_TRANSLATOR_FULLPAGE_RUNNING__ = true; const API_PROVIDERS = [ { endpoint: 'https://YOUR_API_ENDPOINT_1/chat/completions', key: 'YOUR_API_KEY_1', model: 'gemini-translate-pro', prompt: '{text}', batchPrompt: `Translate the following multiple text segments into simplified Chinese. Rules: 1. Keep the numbering markers EXACTLY as they are. 2. Do not add explanations. 3. Do not omit any item. 4. Preserve formatting as much as possible. 5. Output ONLY the translated result in the same marker format. {text}` }, { endpoint: 'https://YOUR_API_ENDPOINT_2/chat/completions', key: 'YOUR_API_KEY_2', model: 'gemini-2.5-flash', prompt: `Translate the following text into simplified Chinese, keeping the original formatting as much as possible. Provide only the translated content, without any extra explanations or introductory phrases.\n\nText to translate:\n"""\n{text}\n"""`, batchPrompt: `Translate the following multiple text segments into simplified Chinese. Rules: 1. Keep the numbering markers EXACTLY as they are. 2. Do not add explanations. 3. Do not omit any item. 4. Preserve formatting as much as possible. 5. Output ONLY the translated result in the same marker format. {text}` } ]; const REQUEST_TIMEOUT = 45000; const BATCH_MAX_ITEMS = 12; const BATCH_MAX_CHARS = 3200; const MIN_TEXT_LENGTH = 2; const MAIN_CONTENT_SELECTORS = [ 'article', 'main', '[role="main"]', '.article', '.post', '.entry-content', '.content', '.markdown-body', '.doc-content', '.main-content' ]; const EXCLUDED_TAGS = new Set([ 'SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'OPTION', 'CODE', 'PRE', 'KBD', 'SAMP', 'SVG', 'CANVAS' ]); const INLINE_UI_EXCLUDE_SELECTORS = [ '#ai-translator-btn', '#ai-fullpage-btn', '#ai-translator-popup', '#ai-translate-toolbar' ]; const isConfigIncomplete = API_PROVIDERS.some(p => p.endpoint.includes('YOUR_API_ENDPOINT') || p.key.includes('YOUR_API_KEY') ); if (isConfigIncomplete) { alert('【划词/全文翻译脚本】\n\n请先在脚本顶部“用户配置区”填入你的 API endpoint 和 API key。'); return; } GM_addStyle(` #ai-translator-btn, #ai-fullpage-btn { position: absolute; width: 10px; height: 10px; border-radius: 50%; cursor: pointer; z-index: 999999; box-shadow: 0 2px 6px rgba(0,0,0,0.25); border: 2px solid white; transform: translate(-50%, -50%); opacity: 0.72; transition: transform 0.2s ease, opacity 0.2s ease; } #ai-translator-btn:hover, #ai-fullpage-btn:hover { transform: translate(-50%, -50%) scale(1.2); opacity: 1; } #ai-translator-btn { background-color: #ff4757; } #ai-fullpage-btn { background-color: #1e90ff; } #ai-translator-popup { position: absolute; z-index: 999998; background-color: #FFFBEF; border: 1px solid #EAEAEA; border-radius: 8px; box-shadow: 0 5px 16px rgba(0, 0, 0, 0.14); padding: 14px 16px; max-width: 460px; min-width: 220px; font-size: 14px; line-height: 1.65; color: #333; text-align: left; white-space: pre-wrap; word-wrap: break-word; transform: translate(-50%, -50%); box-sizing: border-box; } #ai-translate-toolbar { position: fixed; right: 16px; bottom: 18px; z-index: 999999; display: flex; align-items: center; gap: 8px; padding: 8px 10px; background: rgba(28, 28, 32, 0.92); color: #fff; border-radius: 10px; box-shadow: 0 6px 24px rgba(0,0,0,0.28); font-size: 12px; user-select: none; backdrop-filter: blur(6px); } #ai-translate-toolbar button { border: none; border-radius: 8px; padding: 6px 10px; cursor: pointer; color: #fff; font-size: 12px; line-height: 1; } #ai-translate-toolbar button:hover { opacity: 0.9; } #ai-restore-btn { background: #ff6b6b; } #ai-retranslate-btn { background: #4dabf7; } #ai-toolbar-close-btn { background: #666; } #ai-translate-status { max-width: 220px; color: #f1f3f5; opacity: 0.95; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; } `); let translateBtn = null; let fullPageBtn = null; let translatePopup = null; let toolbar = null; let statusTextEl = null; let isFullPageTranslating = false; let pageTranslated = false; const originalTextMap = new WeakMap(); function cleanupDotsAndPopup() { if (translateBtn) { translateBtn.remove(); translateBtn = null; } if (fullPageBtn) { fullPageBtn.remove(); fullPageBtn = null; } if (translatePopup) { translatePopup.remove(); translatePopup = null; } } function clearSelection() { const selection = window.getSelection(); if (selection) { selection.removeAllRanges(); } } function ensureToolbar() { if (toolbar) return; toolbar = document.createElement('div'); toolbar.id = 'ai-translate-toolbar'; toolbar.innerHTML = ` <button id="ai-restore-btn" title="恢复原文">恢复原文</button> <button id="ai-retranslate-btn" title="翻译新增内容">翻译新增</button> <span id="ai-translate-status">未翻译</span> <button id="ai-toolbar-close-btn" title="关闭">×</button> `; document.body.appendChild(toolbar); statusTextEl = toolbar.querySelector('#ai-translate-status'); toolbar.querySelector('#ai-restore-btn').addEventListener('click', () => { restoreOriginalPage(); }); toolbar.querySelector('#ai-retranslate-btn').addEventListener('click', async () => { if (isFullPageTranslating) return; try { await translateEntirePage({ onlyUntranslated: true }); } catch (e) { setStatus('翻译新增失败:' + e.message); } }); toolbar.querySelector('#ai-toolbar-close-btn').addEventListener('click', () => { restoreOriginalPage(); toolbar.remove(); toolbar = null; statusTextEl = null; }); } function setStatus(text) { ensureToolbar(); if (statusTextEl) statusTextEl.textContent = text; console.log('[AI翻译]', text); } function showPopup(text, top, left) { if (translatePopup) translatePopup.remove(); translatePopup = document.createElement('div'); translatePopup.id = 'ai-translator-popup'; translatePopup.textContent = text; document.body.appendChild(translatePopup); translatePopup.style.top = `${top}px`; translatePopup.style.left = `${left}px`; } function sleep(ms) { return new Promise(resolve => setTimeout(resolve, ms)); } function chunkByRules(items, maxItems, maxChars) { const batches = []; let current = []; let currentChars = 0; for (const item of items) { const len = item.text.length; if ( current.length >= maxItems || (current.length > 0 && currentChars + len > maxChars) ) { batches.push(current); current = []; currentChars = 0; } current.push(item); currentChars += len; } if (current.length) batches.push(current); return batches; } function isElementVisible(el) { if (!el || !el.isConnected) return false; const style = window.getComputedStyle(el); if (style.display === 'none' || style.visibility === 'hidden') return false; return true; } function isInsideExcludedUI(node) { let el = node.parentElement; while (el) { for (const selector of INLINE_UI_EXCLUDE_SELECTORS) { if (el.matches && el.matches(selector)) return true; } el = el.parentElement; } return false; } function hasMeaningfulLatinText(text) { return /[A-Za-z\u00C0-\u024F]/.test(text); } function getMainContentRoot() { for (const selector of MAIN_CONTENT_SELECTORS) { const el = document.querySelector(selector); if (el && el.innerText && el.innerText.trim().length > 100) { return el; } } return document.body; } function extractCoreText(raw) { const leading = raw.match(/^\s*/)?.[0] || ''; const trailing = raw.match(/\s*$/)?.[0] || ''; const core = raw.trim(); return { leading, core, trailing }; } function getTranslatableTextNodes(root, onlyUntranslated = true) { const walker = document.createTreeWalker( root, NodeFilter.SHOW_TEXT, { acceptNode(node) { if (!node || !node.nodeValue) return NodeFilter.FILTER_REJECT; if (onlyUntranslated && originalTextMap.has(node)) return NodeFilter.FILTER_REJECT; const raw = node.nodeValue; const trimmed = raw.trim(); if (!trimmed || trimmed.length < MIN_TEXT_LENGTH) { return NodeFilter.FILTER_REJECT; } const parent = node.parentElement; if (!parent) return NodeFilter.FILTER_REJECT; if (EXCLUDED_TAGS.has(parent.tagName)) { return NodeFilter.FILTER_REJECT; } if (isInsideExcludedUI(node)) { return NodeFilter.FILTER_REJECT; } if (!isElementVisible(parent)) { return NodeFilter.FILTER_REJECT; } if (!/[^\d\s\p{P}]/u.test(trimmed) && !hasMeaningfulLatinText(trimmed)) { return NodeFilter.FILTER_REJECT; } if (trimmed.length < MIN_TEXT_LENGTH) { return NodeFilter.FILTER_REJECT; } if (!hasMeaningfulLatinText(trimmed)) { return NodeFilter.FILTER_REJECT; } return NodeFilter.FILTER_ACCEPT; } } ); const nodes = []; let current; while ((current = walker.nextNode())) { nodes.push(current); } return nodes; } function requestChatCompletion(provider, promptText) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: 'POST', url: provider.endpoint, timeout: REQUEST_TIMEOUT, headers: { 'Content-Type': 'application/json', 'Authorization': `Bearer ${provider.key}` }, data: JSON.stringify({ model: provider.model, messages: [{ role: 'user', content: promptText }], temperature: 0.1, stream: false }), onload: function (response) { try { const data = JSON.parse(response.responseText); const content = data?.choices?.[0]?.message?.content?.trim(); if (content) { resolve(content); } else { reject(new Error(`无有效返回内容,HTTP ${response.status}`)); } } catch (e) { reject(new Error('响应解析失败')); } }, onerror: function (response) { reject(new Error(`网络错误 ${response?.status || ''}`)); }, ontimeout: function () { reject(new Error('请求超时')); } }); }); } function fillTemplate(template, text) { return (template || '{text}').replace('{text}', text); } async function translateSingleText(text) { let lastErr = null; for (let i = 0; i < API_PROVIDERS.length; i++) { const provider = API_PROVIDERS[i]; const promptText = fillTemplate(provider.prompt, text); try { return await requestChatCompletion(provider, promptText); } catch (e) { console.warn(`单条翻译 API[${i}] 失败:`, e.message); lastErr = e; } } throw lastErr || new Error('单条翻译失败:所有API均不可用'); } function buildBatchPayload(items) { return items.map((item, idx) => { return `<<<ITEM_${idx + 1}>>>\n${item.text}`; }).join('\n\n'); } function parseBatchResponse(responseText, expectedCount) { const results = new Array(expectedCount).fill(''); const regex = /<<<ITEM_(\d+)>>>\s*([\s\S]*?)(?=\n\s*<<<ITEM_\d+>>>|$)/g; let match; while ((match = regex.exec(responseText)) !== null) { const index = parseInt(match[1], 10) - 1; if (index >= 0 && index < expectedCount) { results[index] = (match[2] || '').trim(); } } return results; } async function translateBatch(batchItems) { const batchText = buildBatchPayload(batchItems); let lastErr = null; for (let i = 0; i < API_PROVIDERS.length; i++) { const provider = API_PROVIDERS[i]; const prompt = fillTemplate(provider.batchPrompt, batchText); try { const response = await requestChatCompletion(provider, prompt); const parsed = parseBatchResponse(response, batchItems.length); const validCount = parsed.filter(Boolean).length; if (validCount < Math.ceil(batchItems.length * 0.7)) { throw new Error('批量解析质量过低,转下一个API或单条翻译'); } return parsed.map((t, idx) => t || batchItems[idx].text); } catch (e) { console.warn(`批量翻译 API[${i}] 失败:`, e.message); lastErr = e; } } console.warn('批量翻译全部失败,降级为单条翻译:', lastErr?.message || ''); const results = []; for (const item of batchItems) { try { const one = await translateSingleText(item.text); results.push(one || item.text); await sleep(120); } catch { results.push(item.text); } } return results; } async function handleSelectionTranslate(text, top, left) { showPopup('翻译中...', top, left); try { const translated = await translateSingleText(text); if (translatePopup) translatePopup.textContent = translated || '翻译失败'; } catch (e) { if (translatePopup) translatePopup.textContent = '翻译失败:' + e.message; } } async function translateEntirePage({ onlyUntranslated = true } = {}) { if (isFullPageTranslating) { setStatus('正在翻译中,请稍候...'); return; } isFullPageTranslating = true; ensureToolbar(); try { const root = getMainContentRoot(); const nodes = getTranslatableTextNodes(root, onlyUntranslated); if (!nodes.length) { setStatus(onlyUntranslated ? '没有发现新的可翻译内容' : '未找到可翻译文本'); return; } const items = nodes.map(node => { const raw = node.nodeValue; const { leading, core, trailing } = extractCoreText(raw); return { node, raw, leading, core, trailing, text: core }; }).filter(item => item.text && item.text.length >= MIN_TEXT_LENGTH); if (!items.length) { setStatus('未找到有效文本'); return; } const batches = chunkByRules(items, BATCH_MAX_ITEMS, BATCH_MAX_CHARS); setStatus(`准备翻译:${items.length} 段文本,${batches.length} 批`); let done = 0; for (let i = 0; i < batches.length; i++) { const batch = batches[i]; setStatus(`翻译中:第 ${i + 1}/${batches.length} 批`); const translatedTexts = await translateBatch(batch); batch.forEach((item, idx) => { const translated = translatedTexts[idx]; if (!translated) return; if (!originalTextMap.has(item.node)) { originalTextMap.set(item.node, item.raw); } item.node.nodeValue = item.leading + translated + item.trailing; done++; }); await sleep(150); } pageTranslated = true; setStatus(`全文翻译完成:已替换 ${done} 段文本`); } catch (e) { setStatus('全文翻译失败:' + e.message); throw e; } finally { isFullPageTranslating = false; } } function restoreOriginalPage() { const root = getMainContentRoot(); const walker = document.createTreeWalker( root, NodeFilter.SHOW_TEXT, null ); let count = 0; let node; while ((node = walker.nextNode())) { if (originalTextMap.has(node)) { node.nodeValue = originalTextMap.get(node); count++; } } pageTranslated = false; setStatus(`已恢复原文:${count} 处`); } document.addEventListener('mouseup', function (e) { if ( e.target?.id === 'ai-translator-btn' || e.target?.id === 'ai-fullpage-btn' || (translatePopup && translatePopup.contains(e.target)) || (toolbar && toolbar.contains(e.target)) ) { return; } cleanupDotsAndPopup(); const selection = window.getSelection(); if (!selection || selection.isCollapsed || !selection.toString().trim()) { return; } const selectedText = selection.toString().trim(); let range; try { range = selection.getRangeAt(0); } catch { return; } const rect = range.getBoundingClientRect(); if (!rect) return; const centerX = window.scrollX + rect.left + rect.width / 2; const centerY = window.scrollY + rect.top + rect.height / 2; translateBtn = document.createElement('div'); translateBtn.id = 'ai-translator-btn'; document.body.appendChild(translateBtn); translateBtn.style.top = `${centerY}px`; translateBtn.style.left = `${centerX}px`; fullPageBtn = document.createElement('div'); fullPageBtn.id = 'ai-fullpage-btn'; document.body.appendChild(fullPageBtn); fullPageBtn.style.top = `${centerY}px`; fullPageBtn.style.left = `${centerX + 18}px`; translateBtn.addEventListener('click', function (event) { event.stopPropagation(); handleSelectionTranslate(selectedText, centerY + 24, centerX); if (translateBtn) translateBtn.style.display = 'none'; if (fullPageBtn) fullPageBtn.style.display = 'none'; }); fullPageBtn.addEventListener('click', async function (event) { event.stopPropagation(); showPopup('全文翻译中,请稍候...', centerY + 24, centerX + 60); if (translateBtn) translateBtn.style.display = 'none'; if (fullPageBtn) fullPageBtn.style.display = 'none'; try { await translateEntirePage({ onlyUntranslated: true }); if (translatePopup) { translatePopup.textContent = '全文翻译完成'; setTimeout(() => { if (translatePopup) { translatePopup.remove(); translatePopup = null; } }, 1200); } } catch (e) { if (translatePopup) translatePopup.textContent = '全文翻译失败:' + e.message; } }); }); document.addEventListener('mousedown', function (e) { if ( (translatePopup && translatePopup.contains(e.target)) || (toolbar && toolbar.contains(e.target)) || e.target?.id === 'ai-translator-btn' || e.target?.id === 'ai-fullpage-btn' ) { return; } cleanupDotsAndPopup(); clearSelection(); }); })(); 2 个帖子 - 2 位参与者 阅读完整话题

IT之家 · 2026-05-15 11:42:36+08:00 · tech

IT之家 5 月 15 日消息,Wii U 模拟器 Cemu 于 5 月 12 日发布公告,称在 2026 年 5 月 6 日至 12 日期间, 项目 GitHub 上的 Ubuntu ZIP 和 AppImage 下载包被篡改,Windows、macOS 和 Flatpak 版本未受影响。 IT之家注: Cemu 是一款针对任天堂 Wii U 游戏机的电脑模拟器, 最初于 2015 年发布,由开发者 Exzap 制作,并于 2022 年宣布开源。该模拟器能够让用户在 PC 上高清且流畅地重温 Wii U 平台的诸多经典神作。 官方公告指出受影响文件由账号 MangelSpec 重新上传,而原始文件则由 github-actions [bot] 上传,两份被替换的文件分别是 cemu-2.6-ubuntu-22.04-x64.zip (下载约 1957 次)和 Cemu-2.6-x86_64.AppImage (下载约 19897 次)。 在恶意安装包文件中,被塞入了一个名为 startup.py 的脚本,受影响的文件会在系统中生成多个可疑条目,包括 /tmp/.transformers 、 /usr/bin/ pgmonitor.py 、 ~/.local/bin/ pgmonitor.py ,以及多个 systemd 服务文件。 如果用户在上述时间段下载过这些 Linux 包,开发团队不建议只靠“没看到异常文件”就判断安全。公告明确提到,恶意代码的完整功能仍未完全确认,因此最稳妥的做法是重装操作系统。 若暂时无法重装,至少要删除受影响的安装文件,并重置所有密码、GitHub Token、SSH 密钥,以及其他用于身份验证的凭据。 开发者还指出,这个木马包含一个较复杂的密码窃取模块,目标覆盖多个与编程和云服务相关的平台。团队推测,攻击者可能想借此继续渗透更多软件项目。公告同时建议,所有用户都应封锁 IP 地址 83.142.209.194(被硬编码为远程联络端点)。

LinuxDo 最新话题 · 2026-05-09 19:40:37+08:00 · tech

本人喜欢看一些油管上的播客,某句没听清楚的时候需要拉进度条,但是默认跳跃五秒有点多了。 这个好像是油猴论坛找的脚本忘记出处了,但是有点小bug,第一次加载视频不会生效,给优化了一下 // ==UserScript== // @name YouTube Skip Time Customizer Fixed // @namespace http://tampermonkey.net/ // @version 2.2 // @description Customize YouTube skip time by arrow key and block Numpad0~Numpad9 function // @author TrainingDummy1 // @match https://www.youtube.com/* // @run-at document-start // @grant none // @license MIT // ==/UserScript== (function() { 'use strict'; if (window.__ytSkipTimeCustomizerInstalled) return; window.__ytSkipTimeCustomizerInstalled = true; const step = 3; function isTargetPage() { return location.pathname === '/watch' || location.pathname.startsWith('/shorts/'); } function getVideo() { return ( document.querySelector('video.html5-main-video') || [...document.querySelectorAll('video')].find(v => Number.isFinite(v.duration)) || document.querySelector('video') ); } function isTypingTarget(target) { if (!(target instanceof Element)) return false; const tag = target.tagName; return ( tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable || target.closest('[contenteditable="true"]') || target.closest('[role="textbox"]') || target.id === 'contenteditable-root' ); } function stopEvent(event) { event.preventDefault(); event.stopPropagation(); event.stopImmediatePropagation(); } function seekVideo(direction) { const video = getVideo(); if (!video || !Number.isFinite(video.duration) || !Number.isFinite(video.currentTime)) { console.warn('没有找到可用的视频元素'); return; } const targetTime = Math.max( 0, Math.min(video.duration, video.currentTime + direction * step) ); let retries = 0; const maxRetries = 5; const tolerance = 0.15; function accurateSeek() { video.currentTime = targetTime; if ( Math.abs(video.currentTime - targetTime) < tolerance || retries >= maxRetries ) { return; } retries++; setTimeout(accurateSeek, 100); } accurateSeek(); } function onKeyDown(event) { if (!isTargetPage()) return; if (isTypingTarget(event.target)) return; if (event.key === 'ArrowRight' || event.key === 'ArrowLeft') { stopEvent(event); const direction = event.key === 'ArrowRight' ? 1 : -1; seekVideo(direction); return; } if (/^Numpad\d$/.test(event.code)) { stopEvent(event); } } window.addEventListener('keydown', onKeyDown, { capture: true, passive: false }); console.log(`YouTube 方向键 ${step} 秒快进/快退脚本已启用`); })(); 此处数字为自定义快进秒数 1 个帖子 - 1 位参与者 阅读完整话题

LinuxDo 最新话题 · 2026-05-08 16:48:15+08:00 · tech

五一期间站点被篡改跳转到菠菜网站,下面是一点防护措施,大佬们如果有其他防护措施欢迎补充 环境说明: linux , 宝塔,php环境 下面是shell脚本,root运行 #!/bin/bash # 网站总根目录 ROOT="/www/wwwroot" # ===================== 配置区域(以后只改这里) ===================== # 需要锁定的【网站根目录下的文件】 LOCK_FILES=("index.php" "test.php") # 需要锁定的【二级目录文件】格式:目录/文件 LOCK_SECOND_FILES=("public/index.php" "public/test.php") # 需要锁定的【网站根目录下的目录】(会自动 -R 递归) LOCK_DIRS=("config" "test") # ==================================================================== # 批量处理所有网站 for site in "${ROOT}"/*/; do site="${site%/}" [ ! -d "$site" ] && continue echo "========================================" echo "处理站点:$site" # 锁定根目录文件 for f in "${LOCK_FILES[@]}"; do path="$site/$f" [ -f "$path" ] && chattr +i "$path" && echo "✅ 锁定文件:$f" done # 锁定二级目录文件 for f in "${LOCK_SECOND_FILES[@]}"; do path="$site/$f" [ -f "$path" ] && chattr +i "$path" && echo "✅ 锁定文件:$f" done # 锁定目录(递归 -R) for d in "${LOCK_DIRS[@]}"; do path="$site/$d" [ -d "$path" ] && chattr -R +i "$path" && echo "✅ 锁定目录:$d" done done echo -e "\n🎉 全部锁定完成!" 清除目录不可变属性 sudo chattr -R -i 目录名 文件加不可变权限 sudo chattr +i 文件名 查看文件权限 lsattr -d 目录名 lsattr index.php 1 个帖子 - 1 位参与者 阅读完整话题

www.ithome.com · 2026-04-29 07:22:49+08:00 · tech

IT之家 4 月 29 日消息,漫步者官方微博昨晚发布严正声明,称发现有不法分子在社交平台及网络社群中,恶意篡改公司的媒体发布内容,制作并传播涉嫌污损伟人形象的伪造图片。漫步者微博配图显示,其已就此事向网络违法犯罪信息举报网站进行了举报。 IT之家附漫步者声明原文如下: 近日,我司发现有不法分子在社交平台及网络社群中,恶意篡改我司的媒体发布内容,制作并传播涉嫌污损伟人形象的伪造图片,同时捏造不实信息误导舆论,将不当行为归咎于我司,对我司品牌声誉造成了严重的负面影响。我司现严正声明如下: 1.网传相关篡改图片及不实信息,均系他人恶意伪造、传播。我司对任何污损、恶搞历史人物及国家象征的行为,持零容忍态度,坚决予以谴责和抵制。 2.针对此次恶意伪造、传播不实信息的行为,我司已委托专业机构对相关篡改图片及谣言的发布、传播路径进行了完整取证,并已向公安机关报案,同时也向各网络媒体平台、网信办等主管部门提出举报申诉。我司将采取一切必要的法律手段,追究相关责任人的民事、行政甚至刑事责任,绝不姑息。 3.在此郑重呼吁广大网友,提高信息辨识能力,切勿轻信、传播此类伪造图片及不实信息。相关信息请以我司官方平台发布内容为准,共同抵制损害国家形象、民族尊严和人民感情的行为,杜绝网络虚假信息传播,共同维护清朗网络空间。 我司始终秉持积极正向的社会主义价值观,坚守社会责任底线,致力于为用户提供优质的产品与服务。我司将坚决同损害国家形象、民族尊严和人民感情的行为作斗争,同时坚决依法维护自身合法权益。感谢大家的理解与支持。

linux.do · 2026-04-21 17:07:52+08:00 · tech

CPA AuthFiles Universal Cleaner 是个很好用的篡改猴脚本啊,官方那个已经很好,我自己用下来,经常有这么一个场景: 希望按照重置时间排序,尽量用掉将要重置的 token,这样我就可以把充值时间远的先禁用 直接能单个修改每一个 token 的“启用”“禁用状态” 所以在官方的基础上稍微改了改,加了这俩功能,发出来,希望对其他人也能有用吧 CPA AuthFiles Universal Cleaner-3.0.4.user.js.txt (120.2 KB) 1 个帖子 - 1 位参与者 阅读完整话题