Greasy Fork

来自缓存

Greasy Fork is available in English.

💡WebPreview - 信息直达

支持国内主流搜索引擎的搜索结果快速预览(直达网页大纲)。只需点击搜索结果旁的小灯泡按钮,即可在右侧速览窗中快速查看目标网站所含的图片、链接、标题大纲、文本。

当前为 2024-01-28 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         💡WebPreview - 信息直达
// @namespace    https://ez118.github.io/
// @version      0.13
// @description  支持国内主流搜索引擎的搜索结果快速预览(直达网页大纲)。只需点击搜索结果旁的小灯泡按钮,即可在右侧速览窗中快速查看目标网站所含的图片、链接、标题大纲、文本。
// @author       ZZY_WISU
// @match        https://*.bing.com/*
// @match        https://www.google.com/*
// @match        https://www.baidu.com/*
// @match        https://www.so.com/*
// @match        https://www.sogou.com/*
// @connect      *
// @license      GNU GPLv3
// @icon         https://cn.bing.com/sa/simg/favicon-trans-bg-blue-mg.ico
// @run-at document-end
// @grant        GM_xmlhttpRequest
// @grant        GM_download
// @grant        GM_registerMenuCommand
// @grant        GM_addStyle
// @grant        GM_setValue
// @grant        GM_getValue
// @require https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js
// ==/UserScript==


/* ============================================= */

/**
 * 生成随机数
 * @param len 长度
 * @constructor
 */
function randomString(len) {
    len = len || 32;
    /****默认去掉了容易混淆的字符oOLl,9gq,Vv,Uu,I1****/
    var $chars = 'ABCDEFGHJKMNPQRSTWXYZabcdefhijkmnprstwxyz2345678';
    var maxPos = $chars.length;
    var pwd = '';
    for (let i = 0; i < len; i++) { pwd += $chars.charAt(Math.floor(Math.random() * maxPos)); }
    return pwd;
}
/**
 * 标题元素
 * @param tag 标签,h1 ==> 1 , h2 ==> 2
 * @param title 标题
 * @param level 层级
 * @param id 随机生成的id
 * @constructor
 */
function TitleElement(tag, title, level, id) {
    this.tag = tag;
    this.title = title;
    this.level = level;
    this.id = id;
}
/* 是否是标题元素 */
function isTitleTag(tag) {
    if (tag.is("h1")) { return true }
    if (tag.is("h2")) { return true }
    if (tag.is("h3")) { return true }
    if (tag.is("h4")) { return true }
    if (tag.is("h5")) { return true }
    if (tag.is("h6")) { return true }
    if (tag.is("h7")) { return true }
    return false
}
/**
 * 生成大纲
 * @param $articleContent 文章容器
 * @constructor
 */
function getOutline($articleContent) {
    /** 全部元素 */
    var $eles = $articleContent.find("*");
    /** 标题元素列表 */
    var titleElementArr = new Array();
    /** 上一个元素 */
    var preTitleElement = null;

    $.each($eles, function(index, item) {
        if (isTitleTag($(item))) {
            var id = randomString(20);
            var level = 1;
            var tag = parseInt($(item).get(0).tagName.replace('h', "").replace('H', ""));
            var title = $(item).text();

            if (null != preTitleElement) {
                var tagPre = preTitleElement.tag;
                var levelPre = preTitleElement.level;

                if (tagPre > tag) { level = levelPre - 1; }
                else if (tagPre < tag) { level = levelPre + 1; }
                else { level = levelPre; }

            }

            if (title.trim().length > 0) {
                $(item).attr("id", id);
                var titleElement = new TitleElement(tag, title, level, id);
                titleElementArr.push(titleElement);
                preTitleElement = titleElement;
            }
        }
    })
    console.log(titleElementArr);
    return titleElementArr;
}
/* ============================================= */



var ReaderFlag1 = false; /* 用于存储阅读器元素是否被创建 */
var ReaderFlag2 = false; /* 用于存储阅读器是否为开启状态 */
var VideoSupport = [
	["https://v.youku.com/v_show/*.html", "https://player.youku.com/embed/*"],
	["https://v.qq.com/x/page/*.html", "http://v.qq.com/txp/iframe/player.html?vid=*"],
	["https://www.bilibili.com/video/BV*/", "https://www.bilibili.com/blackboard/html5mobileplayer.html?bvid=*"],
	["https://www.bilibili.com/video/av*/", "https://www.bilibili.com/blackboard/html5mobileplayer.html?aid=*"]
]; /* 用于存储阅读器支持直接播放视频的网站及其嵌入播放器代码 */

function stringToHtml(str) {
	var parser = new DOMParser();
    var doc = parser.parseFromString(str, 'text/html');
    return doc;
};

function runAsync(url,send_type,data_ry) {
    var p = new Promise((resolve, reject)=> {
        GM_xmlhttpRequest({
            method: send_type, url: url, headers: {"Content-Type": "application/x-www-form-urlencoded;charset=utf-8"}, data: data_ry,
            onload: function(response){resolve(response.responseText);}, onerror: function(response){reject("请求失败");}
        });
    });
    return p;
}

function escapeHtml(str) {
    return str.replace(/[&<>"']/g, function(match) {
        switch (match) {
           case '&':
              //return '&amp;';
              return '&';
           case '<':
              return '&lt;';
           case '>':
              return '&gt;';
           case '"':
              return '&quot;';
           case '\'':
              return '&#39;';
           default:
              return '';
        }
    });
}

function JudgeVideoSupport(url) {
	var previewFlag = 0;
	/* 判断是否为支持预览视频的网站 */
	for(let i = 0; i < VideoSupport.length; i ++){
		if( url.includes( VideoSupport[i][0].split("*")[0] ) ){
			return { "state":true, "data":i };
			break;
		}
	}

	return { "state":false, "data":-1 };
}


function getWebContents(txt) {
    var links;
    var images;
    var content;
    var outline;
    /* 获取所有链接 */
    /*links = txt.match(/href\=\"(https?|http|ftp|file):\/\/[-A-Za-z0-9+&@#/%?=~_|!:,.;]+[-A-Za-z0-9+&@#/%=~_|]/g);
    for(let i = 0; i < links.length; i ++) {
        links[i] = links[i].replace("href=\"", "");
    }*/
    links = [];
    txt.replace(/<a [^>]*href=['"]([^'"]+)[^>]*>/g,function(match, capture){
        links.push(capture);
    });
    //console.log(links);

    /* 获取所有图片 */
    //images = txt.match(/<img[^<>]*src=[\"]([^\"]+)[\"][^<>]*>/im);
    images = [];
    txt.replace(/<img [^>]*src=['"]([^'"]+)[^>]*>/g,function(match, capture){
        images.push(capture);
    });
    //console.log(images);

    /* 获取文本 */
    content = txt.replace(/<\/div>/g, "</div>\n").replace(/<\/table>/g, "</table>\n")
    content = content.replace(/<\/h3>/g, "</h3>\n").replace(/<\/p>/g, "</p>\n")
    content = content.replace(/<\/li>/g, "</li>\n").replace(/<br>/g, "\n")
    content = content.replace(/<br\/>/g, "\n").replace(/<script(.*?)<\/script>/gis, "")
    content = content.replace(/<style(.*?)<\/style>/gis, "").replace(/<nav(.*?)<\/nav>/gis, "");

    // 现在代码:
    //content = content.replace(/<(?!\/?a\b)[^>]+>/g, ''); /* 删除除了a以外的标签 */
    content = content.replace(/<(?!\/?(a|img)\b)[^>]+>/g, ''); /* 删除除了a和img以外的标签 */

    // 原先代码:
    //content = content.replace(/<[^>]+>/g, ""); /* 删除所有标签 */
    //content = escapeHtml(content); /* 转义 */

    var content_len = content.length;
    content = content.substring(0, content_len);
    const search_txt = ["  ", "  ", "\n\n", "\r\r", "\t\t", "\n\r\n\r", "\r\n\r\n", "\t\r\n"];
    const replace_txt = ["", "", "", "", "", "", "", ""];
    for (let i = 0; i < search_txt.length; i++) {
        content = content.split(search_txt[i]).join(replace_txt[i]);
    }
    
    content = content.replace(/\r\n/g,"<br/>").replace(/\n/g,"<br/>").replace(/<br\/><br\/><br\/>/g, "");
    //console.log(content);

    outline = getOutline($(txt));

    return {"link":links,"image":images,"content":content,"outline":outline};
}

function openReader(url) {
    /* 打开阅读器 */

    /* 判断阅读器元素是否已经被创建过 */
    if (ReaderFlag1 != true) {
        /* 若元素不存在,则创建元素 */
        let previewReader = document.createElement("div");
        previewReader.setAttribute("class", "userscript-webPreviewReader"); previewReader.setAttribute("style", "display:block;"); previewReader.setAttribute("id", "userscript-webPreviewReader");
        document.body.appendChild(previewReader);
        ReaderFlag1 = true; ReaderFlag2 = true;
    } else {
        /* 若存在,则显示元素 */
        let previewReader = document.getElementById("userscript-webPreviewReader");
        previewReader.setAttribute("style", "display:block;");
        ReaderFlag2 = true;
    }

    /* 阅读器加载提示 */
    var previewReader = document.getElementById("userscript-webPreviewReader");
    previewReader.innerHTML = "<p style='font-size:22px;margin-top:33%;' align='center'>加载中...<br/><span>" + url + "</span></p>";

    /* 判断当前链接是支持预览的视频网站,并作出对应处理 */
    var SoN = JudgeVideoSupport(url);
    if(SoN.state == true){
        /* 被支持的视频网站的处理 */
        var origUrl = url;
        var frameUrl = "";

        url = url.replace(VideoSupport[SoN.data][0].split("*")[0], "");
		url = url + "?#";
		url = url.split("#")[0].split("?")[0];
		url = url.replace(VideoSupport[SoN.data][0].split("*")[1], "");

        frameUrl = VideoSupport[SoN.data][1].replace("*", url);

        previewReader.innerHTML = `
        <div id="FadeInContainer" style="display:none; height:100%;">
	    	<button class="CloseButton" style="margin:5px;" onclick='this.parentNode.parentNode.setAttribute("style", "display:none;");'>关闭</button>

	    	<center style="height: calc(100% - 120px)">
	    		<iframe id="videoFrame" style="min-height:300px;" src="` + frameUrl + `"></iframe>
	    	</center>
	    	<br>

	    	<a href="` + origUrl + `" class="link" id="GoToLink" target="_blank">在原网站中继续 &nbsp; ▶ </a><br/>
            <a href="` + frameUrl + `" class="link" id="GoToLink" target="_blank">在播放器中继续 &nbsp; 🎦 </a>
        </div> `;

        /* 淡入 */
        $("#FadeInContainer").fadeIn(700);
    } else {
        /* 普通网站的处理 */
        runAsync(url, "GET", "").then((result)=>{ return result; }).then(function(result){
            var rh;
            if (url.split("/")[2] == "blog.csdn.net"){
                try{ result = stringToHtml(result).getElementById("article_content").innerHTML; }catch(e){}
            }else if (url.split("/")[2] == "zhuanlan.zhihu.com"){
                try{ result = stringToHtml(result).getElementsByClass("Post-RichTextContainer")[0].innerHTML; }catch(e){}
            }else if (url.split("/")[2] == "jingyan.baidu.com"){
                try{ result = stringToHtml(result).getElementById("format-exp").innerHTML; }catch(e){}
            }else if (url.split("/")[2] == "www.bilibili.com"){
                try{ result = stringToHtml(result).getElementById("article-content").innerHTML; }catch(e){}
            }

            /* 用函数解析网页 */
            let reslist = getWebContents(result);
            let linkhtml = "", imghtml = "", outlinehtml = "";

            /* 处理链接列表 */
            for(let i = 0; i < reslist.link.length; i ++){
                let link_tmp = reslist.link[i];
                if(/*link_tmp.includes("https://") || link_tmp.includes("http://")*/link_tmp.includes("//")){
                    linkhtml += "<a class='link' target='_blank' href='" + link_tmp + "'> 🔗&nbsp;" + link_tmp + " </a><br>";
                }
            }

            /* 处理图片列表 */
            for(let i = 0; i < reslist.image.length; i ++){
                imghtml += "<a href='" + reslist.image[i] + "' target='_blank'><img class='image' src='" + reslist.image[i] + "' onerror='this.remove()'/></a>";
            }

            /* 处理大纲 */
            for(let i = 0; i < reslist.outline.length; i ++){
                let space = "";
                for(let j = 1; j < reslist.outline[i].level; j ++){ space += "&emsp;&emsp;"; }
                outlinehtml += space + "+&nbsp;" + reslist.outline[i].title + "<br/>"
            }

            /* 将所有结果添加进阅读器,并显示 */
            previewReader.innerHTML = `
            <div id="FadeInContainer" style="display:none;">
                <button class="CloseButton" onclick='this.parentNode.parentNode.setAttribute("style", "display:none;");'>关闭</button>
                <div class="ImageList" style="max-height:103px;">
                    <p class='ShowImgList' align='right' style='' onclick='this.parentNode.setAttribute("style", "");'>所有图片</p>
                    ` + imghtml + `
	        	</div>

		        <div class="LinkList" style="max-height:286px;">
                    <p class='ShowImgList' align='right' style='' onclick='this.parentNode.setAttribute("style", "");'>所有链接</p>
                    ` + linkhtml + `
	        	</div>

                <div class="ImageList">
	        		<b>大纲: </b><br/>
                    ` + outlinehtml + `
	        	</div>

	        	<div class="ContentShow">
	        		<b>文本: </b>
                    ` + reslist.content + `
	        	</div>
            </div>`;

            /* 淡入 */
            $("#FadeInContainer").fadeIn(250);
        });
    }
    /* 执行结束 */
}

(function() {
    'use strict';
    var url = window.location.href;
    var paths = url.split("/");

    GM_addStyle(`.userscript-webPreviewBtn{ background:#FFF; padding:3px 13px; margin-left:5px; border-radius:10px; border:2px solid #555; cursor:pointer; }
                 .userscript-webPreviewBtn:active{ background:#111; border:2px solid #AAA; }
                 .userscript-webPreviewReader{ position:fixed; top:8%; right:10px; bottom:0px; z-index:9999; width:35%; height:calc(100% - 8%); min-width:350px; background:#FFF; color:#333; overflow:hidden; box-shadow:0px 2px 5px #000; border-radius:15px 15px 0px 0px; }
                 .userscript-webPreviewReader img.error{ display:none; }
                 .ShowImgList{ margin:0;padding:0;width:100%;cursor:pointer;color:#138AF1;user-select:none; }
                 .image{ height:85px; margin-bottom:8px; margin-right:5px; border-radius:15px; object-fit:contain; max-width:calc(100% - 20px); }
                 .link{ text-decoration:none; color:#001ba0; margin-left: 5px; }
                 .link:hover{ text-decoration:underline; }
                 .ImageList{ padding:10px; margin:5px; border:2px solid #f4effb; background:#f4effb; border-radius:15px; overflow:hidden; }
                 .LinkList{ padding:10px; margin:5px; border:2px solid #f4f1f6; background:#f4f1f6; border-radius:15px; overflow:hidden; }
                 .ContentShow{ padding:10px; margin:5px; border:2px solid #f2f2f2; background:#f2f2f2; border-radius:15px; }
                 .ContentShow img{ max-width:90%!important; position:relative!important; top:0!important; left:0!important; }
                 .ContentShow img::after{ content: ""; display: block; clear: both; }
                 .CloseButton{ background:#FFF; color:#000; padding:3px 13px; margin:5px 5px; margin-bottom:0px; border-radius:10px; border:2px solid #555; cursor:pointer; }
                 .CloseButton:hover{ background:#138AF1; border:2px solid #106ebe; color:#FFF; }
                 #videoFrame{ width: calc(100% - 10px); height: calc(100% - 0px); border:1px solid #CCC; border-radius:15px; }

                 #FadeInContainer { overflow-y:auto; overflow-x:hidden; border-radius:15px 15px 0px 0px; width:100%; height:100%; }
                 `);

    if (paths[2].includes("bing.com") && paths[3].includes("search")) {
        let resultItems = document.getElementsByClassName("b_algo");
        for(let i = 0; i < resultItems.length; i ++) {
            let resultItemLink = resultItems[i].getElementsByTagName("a")[0].href;
            let resultItemTitleEle = resultItems[i].getElementsByTagName("h2")[0];

            /* 向每一个搜索结果的标题部分添加按钮 */
            let previewBtn = document.createElement("button");
            let previewBtnTxt = document.createTextNode("💡");
            previewBtn.setAttribute("class", "userscript-webPreviewBtn");
            previewBtn.setAttribute("link-data", resultItemLink);
            resultItemTitleEle.appendChild(previewBtn);
            previewBtn.appendChild(previewBtnTxt);

            previewBtn.addEventListener("click", function(evt){
                let linkData = previewBtn.getAttribute("link-data");
                openReader(linkData);
            }, true);
        }
    } else if (paths[2].includes("google.com")) {
        let resultItems = document.getElementsByClassName("MjjYud");
        for(let i = 0; i < resultItems.length; i ++) {
            try{
                let resultItemLink = resultItems[i].getElementsByTagName("a")[1].getAttribute("href");
                let resultItemTitleEle = resultItems[i].getElementsByTagName("h3")[0];

                if(resultItemLink == null || resultItemLink == "" || resultItemLink == undefined){ continue; }

                /* 向每一个搜索结果的标题部分添加按钮 */
                let previewBtn = document.createElement("button");
                let previewBtnTxt = document.createTextNode("💡");
                previewBtn.setAttribute("class", "userscript-webPreviewBtn");
                previewBtn.setAttribute("link-data", resultItemLink);
                resultItemTitleEle.parentNode.parentNode.appendChild(previewBtn);
                previewBtn.appendChild(previewBtnTxt);

                previewBtn.addEventListener("click", function(evt){
                    let linkData = previewBtn.getAttribute("link-data");
                    openReader(linkData);
                }, true);
            } catch(e) {
                console.log("[ERROR] ELE(" + i + ")");
            }
        }
    } else if (paths[2].includes("baidu.com") && paths[3].includes("s?")) {
        let resultItems = document.getElementsByClassName("c-container");
        //let resultItems = document.getElementsByClassName("c-container new-pmd");
        for(let i = 0; i < resultItems.length; i ++) {
            try{
                let resultItemLink = resultItems[i].getAttribute("mu");
                let resultItemTitleEle = resultItems[i].getElementsByTagName("h3")[0];

                if(resultItemLink == null || resultItemLink == "" || resultItemLink == undefined){ continue; }

                /* 向每一个搜索结果的标题部分添加按钮 */
                let previewBtn = document.createElement("button");
                let previewBtnTxt = document.createTextNode("💡");
                previewBtn.setAttribute("class", "userscript-webPreviewBtn");
                previewBtn.setAttribute("link-data", resultItemLink);
                resultItemTitleEle.appendChild(previewBtn);
                previewBtn.appendChild(previewBtnTxt);

                previewBtn.addEventListener("click", function(evt){
                    let linkData = previewBtn.getAttribute("link-data");
                    openReader(linkData);
                }, true);
            } catch(e) {
                console.log("[ERROR] ELE(" + i + ")");
            }
        }
    } else if (paths[2].includes("so.com") && paths[3].includes("s?")) {
        let resultItems = document.getElementsByClassName("res-list");
        for(let i = 0; i < resultItems.length; i ++) {
            try{
                let resultItemLink = resultItems[i].getElementsByTagName("a")[0].getAttribute("data-mdurl");
                let resultItemTitleEle = resultItems[i].getElementsByTagName("h3")[0];

                /* 向每一个搜索结果的标题部分添加按钮 */
                let previewBtn = document.createElement("button");
                let previewBtnTxt = document.createTextNode("💡");
                previewBtn.setAttribute("class", "userscript-webPreviewBtn");
                previewBtn.setAttribute("link-data", resultItemLink);
                resultItemTitleEle.appendChild(previewBtn);
                previewBtn.appendChild(previewBtnTxt);

                previewBtn.addEventListener("click", function(evt){
                    let linkData = previewBtn.getAttribute("link-data");
                    openReader(linkData);
                }, true);
            } catch(e) {
                console.log("[ERROR] ELE(" + i + ") \n" + e);
            }
        }
    } else if (paths[2].includes("sogou.com")) {
        let resultItems = document.getElementsByClassName("vrwrap");

        for(let i = 0; i < resultItems.length; i ++) {
            try{
                let resultItemLink = resultItems[i].getElementsByClassName("ext_query")[0].getAttribute("data-url");
                let resultItemTitleEle = resultItems[i].getElementsByTagName("h3")[0];

                /* 向每一个搜索结果的标题部分添加按钮 */
                let previewBtn = document.createElement("button");
                let previewBtnTxt = document.createTextNode("💡");
                previewBtn.setAttribute("class", "userscript-webPreviewBtn");
                previewBtn.setAttribute("link-data", resultItemLink);
                resultItemTitleEle.appendChild(previewBtn);
                previewBtn.appendChild(previewBtnTxt);

                previewBtn.addEventListener("click", function(evt){
                    let linkData = previewBtn.getAttribute("link-data");
                    openReader(linkData);
                }, true);
            } catch(e) {
                console.log("[ERROR] ELE(" + i + ")");
            }
        }
    }
})();