Greasy Fork is available in English.

优书网 <=> 知轩藏书

[知轩藏书/早安电子书]添加优书网评分和直链,优书网书籍详情页添加[知轩藏书/早安电子书]下载链接

Version au 15/07/2018. Voir la dernière version.

// ==UserScript==
// @name         优书网 <=> 知轩藏书
// @namespace    http://tampermonkey.net/
// @description  [知轩藏书/早安电子书]添加优书网评分和直链,优书网书籍详情页添加[知轩藏书/早安电子书]下载链接
// @author       tianxin
// @match        *://zxcs8.com/sort/*
// @match        *://zxcs8.com/post/*
// @match        *://www.zxcs8.com/sort/*
// @match        *://www.zxcs8.com/post/*
// @match        *://www.yousuu.com/book/*
// @match        *://www.zadzs.com/txt/*
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM_getValue
// @grant        GM_setValue
// @connect      www.yousuu.com
// @connect      www.zxcs8.com
// @connect      www.zadzs.com
// @connect      www.nordfxs.com
// @version      0.4.4
// ==/UserScript==

// 请求类型 1:获取评分 2:获取下载
const REQUEST_TYPE_SOURCE = 1;
const REQUEST_TYPE_DOWNLOAD = 2;
// 下载链接缓存时间,默认7天
const DOWNLOAD_EXPIRED_TIME = 86400 * 7 * 1000;
// 优书网评分缓存时间,默认两小时
const SEARCH_EXPIRED_TIME = 2 * 3600 * 1000;
// 优书网最大搜索数目,默认5个
const MAX_SEARCH_NUM = 5;

// 简单封装GM_getValue和GM_setValue,支持过期时间
let storage = {
    setValue:(key,value) => {
        let data = JSON.stringify({value:value,time:new Date().getTime()});
        return GM_setValue(key, data);
    },
    getValue:(key,expired) => {
        let value = GM_getValue(key);
        if(value !== undefined){
            let dataObj = JSON.parse(value);
            if(new Date().getTime() - dataObj.time > expired){
                return undefined;
            }else{
                return dataObj.value;
            }
        }else{
            return undefined;
        }
    },
}
let getResponse = (options) => {
    return new Promise((resolve,reject) => {
       GM_xmlhttpRequest({
           method: options.method,
           url: options.url,
           data:options.data,
           synchronous:options.synchronous,
           onload: (response) => {
               if (response.status >= 200 && response.status < 400){
                   resolve(response.responseText);
               }
               else{
                   console.log(
                       'Error getting ' + options.url + ' (' + this.status + ' ' + this.statusText +
                       '): ' + this.responseText);
               }
           },
           onerror: (response) => {
               console.log('Error during GM_xmlhttpRequest to ' + options.url + ': ' + response.statusText);
           }
       });
    });
}
let getResult = (options) => {
    return new Promise((reslove,reject) => {
        options.data = !options.data ? '' : options.data;
        options.method = !options.method ? 'GET' : options.method;
        options.synchronous = !options.synchronous ? false : options.synchronous;
        let key = JSON.stringify(options);
        let value = storage.getValue(key,options.type === REQUEST_TYPE_DOWNLOAD ? DOWNLOAD_EXPIRED_TIME : SEARCH_EXPIRED_TIME);
        if(value !== undefined){
            reslove(value);
        }else{
           getResponse(options).then(response => { storage.setValue(key,response); reslove(response)});
        }
    });
}
let sourceConfig = {
    'zxcs8.post':{
        bookName:(item) => {
            return document.querySelector('h1').innerText.match('《(.*?)》')[1];
        },
        bookAuthor:(item) => {
            return document.querySelector('h1').innerText.split(':').pop();
        },
        maxNum:MAX_SEARCH_NUM,
        rateItem:(rate,rateNum,bookLink) => {
            return '<p class="yinyong"><span style="font-size:14px;color:#FF0000;font-weight:bold"><a href = "' + bookLink + '" target="_blank">优书网</a>评分: ' + rate + '</span><p><p class="yinyong"><span style="font-size:14px;color:#FF0000;font-weight:bold">评分人数: ' + rateNum + '</span><p>';
        },
        anchorObj:(item) => {
            let obj = document.querySelector('.yinyong');
            return !obj ? document.querySelector('.pagefujian') : obj;
        },
        anchorPos:'beforebegin',
    },
    'zxcs8.sort':{
        bookName:(item) => {
            return item.firstElementChild.innerText.match('《(.*?)》')[1];
        },
        bookAuthor:(item) => {
            return item.firstElementChild.innerText.split(':').pop();
        },
        maxNum:MAX_SEARCH_NUM,
        rateItem:(rate,rateNum,bookLink) => {
            return '<a href= "' + bookLink + '" target = "_blank">&nbsp;&nbsp;&nbsp;评分:' + rate + '&nbsp;&nbsp;&nbsp;人数:' + rateNum + '</a>'
        },
        anchorObj:(item) => {
            return item.lastElementChild.querySelector('div');
        },
        anchorPos:'beforebegin',
    },
    'zadzs':{
        bookName:(item) => {
            return document.querySelector('h3[title]').title;
        },
        bookAuthor:(item) => {
            return document.querySelector('h3[title]>span>a').innerText;
        },
        maxNum:MAX_SEARCH_NUM,
        rateItem:(rate,rateNum,bookLink) => {
            return '<tr><td width="42px"><a href="'+ bookLink + '" target = "blank">评分:</a></td><td>' + rate + '</td></tr><tr><td width="42px">人数:</td><td>' + rateNum + '</td></tr>';
        },
        anchorObj:(item) => {
            return document.querySelector('.m-bookstatus>table>tbody');
        },
        anchorPos:"afterbegin",
    }
};
let sourceHandle = {
    'zxcs8.post':function(site,callback){
        let option = {site:site,item:''};
        return callback(option);
    },
    'zxcs8.sort':function(site,callback){
        let bookList = Array.prototype.slice.call(document.querySelectorAll('#plist'));
        bookList.forEach(function(item){
             let option = {site:site,item:item};
             callback(option);
         });
    },
     'zadzs':function(site,callback){
         let option = {site:site,item:''};
         return callback(option);
    },
};
let sourceRoute = {
    'www.zxcs8.com':() => {
        let tag = location.pathname.split('/')[1];
        if(['sort','post'].includes(tag)){
            return 'zxcs8.' + tag;
        }
    },
    'zxcs8.com':() => {
        let tag = location.pathname.split('/')[1];
        if(['sort','post'].includes(tag)){
            return 'zxcs8.' + tag;
        }
    },
    'www.zadzs.com':() => {
        return 'zadzs';
    }
};
let downloadConfig = {
    "zxcs8":{
        'siteName':'知轩藏书',
        'searchConfig':(args) => {
            return {url:'http://www.zxcs8.com/index.php?keyword=' + args.bookName};
        },
        'bookList':(item) => {
            return Array.prototype.slice.call(item.getElementsByTagName('dl'));
        },
        'bookName':(item) => {
            return item.children["0"].innerText.match('《(.*?)》')[1];
        },
        'bookAuthor':(item) => {
            return item.children["0"].innerText.split(':').pop();
        },
        'bookLink':(item) => {
            return item.children["0"].getElementsByTagName('a')[0].href;
        },
        'downloadLink':(item) => {
            return item.querySelector('.down_2>a').href;
        },
    },
    "zadzs":{
        'siteName':'早安电子书',
        'searchConfig':(args) => {
            return {url:'http://www.zadzs.com/plus/search.php?kwtype=0&q=' + args.bookName};
        },
        'bookList':(item) => {
            return Array.prototype.slice.call(item.getElementsByClassName('searchItem'));
        },
        'bookName':(item) => {
            return item.querySelector('.book>h5>a').innerText;
        },
        'bookAuthor':(item) => {
            return item.querySelector('.book>.price').innerText.split(':').pop();
        },
        'bookLink':(item) => {
            return 'http://www.zadzs.com' + item.querySelector('.book>.cover').pathname;
        },
        'downloadLink':(item) => {
            return 'http://www.zadzs.com' + item.querySelector('.book>cover').href;
        },
    },
    "nordfxs":{
        'siteName':'龙凤互联',
        'searchConfig':(args) => {
            let form = new FormData();
            form.append("formhash","dfae824e");
            form.append("srchtxt",args.bookName);
            form.append("searchsubmit","yes");
            return {url:"http://www.nordfxs.com/search.php?mod=forum",data:form,method:"POST",'bookName':args.bookName};
        },
        'bookList':(item) => {
            return Array.prototype.slice.call(item.getElementsByClassName('pbw'));
        },
        'bookName':(item) => {
            return item.querySelector('.xs3>a').innerText.split('(').shift().replace(/[《,》]/g,'');
        },
        'bookAuthor':(item) => {
            return item.querySelector('.xs3>a').innerText.split(':').pop();
        },
        'bookLink':(item) => {
            return item.querySelector('.xs3>a').href;
        },
        'downloadLink':(item) => {
            return item.querySelector('.xs3>a').href;
        },
    },
};
let downloadHandle = {
    'zxcs8':(options) => {
        let siteConfig = downloadConfig[options.site];
        return new Promise((resolve,reject) => {
            getResult({url:options.bookLink,type:REQUEST_TYPE_DOWNLOAD}).then((response) => {
                let html = document.createElement( 'html' );
                html.innerHTML = response;
                let downloadLink = siteConfig.downloadLink(html);
                resolve({downloadLink:downloadLink,siteName:siteConfig.siteName})
            });
        });
    },
    'zadzs':(options) => {
        return new Promise((resolve,reject) => {
            let args = {downloadLink:options.bookLink,siteName:downloadConfig[options.site].siteName};
            resolve(args);
        });

    },
    'nordfxs':(options) => {
        return new Promise((resolve,reject) => {
            let args = {downloadLink:options.bookLink,siteName:downloadConfig[options.site].siteName};
            resolve(args);
        });
    }
};
let downloadRoute = {
    'www.yousuu.com':() => {
        return 'www.yousuu.com';
    }
};
let insertDownloadButton = () => {
    let select = '<div class="btn-group" id="download-list" style="display:none"><button type="button" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false" class="btn btn-warning dropdown-toggle"><span>去下载</span>&nbsp;<span class="caret"></span></button><ul class="dropdown-menu" id="download-items"></ul></div>';
    let obj = document.getElementsByClassName('sokk-book-button-groups')[0];
    obj.insertAdjacentHTML('beforeend',select);
}
let removeElement = element => {
    if(element){
        let parent = element.parentNode;
        if(parent){
            parent.removeChild(element);
        }
    }
}
let addDownLoadLink = (options,config) => {
    let siteConfig = config[options.site];
    let youBookName = document.getElementsByClassName('col-sm-7')[0].children[0].innerText;
    let youBookAuthor = document.getElementsByClassName('list-unstyled list-sm')["0"].firstChild.children["0"].innerText;
    getResult(Object.assign(siteConfig.searchConfig({bookName:youBookName}),{type:REQUEST_TYPE_DOWNLOAD})).then((response) => {
        let html = document.createElement( 'html' );
        html.innerHTML = response;
        let bookList = siteConfig.bookList(html)
        if(bookList.length > 0){
             bookList.some((item) => {
                 let bookLink = siteConfig.bookLink(item);
                 let matchBookName = siteConfig.bookName(item);
                 let matchBookAuthor = siteConfig.bookAuthor(item);
                 console.log(matchBookName + ':' + youBookName + ';' + matchBookAuthor + ':' + youBookAuthor)
                 if(matchBookName === youBookName && matchBookAuthor === youBookAuthor){
                     downloadHandle[options.site]({site:options.site,bookLink:bookLink}).then(insertDownLink);
                 }
             });
        }
    })
};
let insertDownLink = options => {
    let obj = document.querySelector('#download-items');
    let item = '<li><a href="'+ options.downloadLink +'" target="_blank">'+ options.siteName + '</a></li>';
    obj.insertAdjacentHTML('beforeend',item);
    if(obj.parentElement.style.display === 'none'){
        obj.parentElement.setAttribute('style', 'display:run-in');
    }
}
let getRate = args => {
    let bookName = args.bookName;
    let bookAuthor = args.bookAuthor;
    let maxNum = (args.maxNum === undefined) ? 1 : args.maxNum;
    return new Promise((resolve,reject) => {
        getResult({url:'http://www.yousuu.com/search/' + bookName + bookAuthor + '?type=all',type:REQUEST_TYPE_SOURCE}).then((response) => {
            let rate = 0;
            let rateNum = 0;
            let bookLink = '';
            let html = document.createElement( 'html' );
            html.innerHTML = response;
            //let matchBook = Array.slice(Array.prototype.slice.call(html.getElementsByClassName('col-lg-4 col-md-6 col-xs-12')),0,maxNum);
            let matchBook = Array.prototype.slice.call(html.getElementsByClassName('col-lg-4 col-md-6 col-xs-12')).slice(0,maxNum);
            matchBook.some((item) => {
                let matchTitle = item.querySelector('.title');
                let matchName = matchTitle.innerText;
                let matchAbstract = item.querySelector('.abstract').innerHTML.split('<br>');
                let matchAuthor = matchAbstract[0].split(':')[1].replace(/<\/?[^>]*>/g,'').trim();
                if(matchAuthor === bookAuthor && matchName === bookName){
                    rate = item.querySelector('.num2star').innerHTML;
                    rateNum = item.querySelector('.rating').innerText.replace(/[^0-9]/ig,"");
                    bookLink = 'http://www.yousuu.com' + matchTitle.querySelector('a').pathname;
                    return true;
                }
            });
            resolve({rate:rate,rateNum:rateNum,bookLink:bookLink});
        });
    });
}
let insertRate = options => {
    let siteConfig = sourceConfig[options.site];
    let args = {bookName:siteConfig.bookName(options.item),bookAuthor:siteConfig.bookAuthor(options.item),maxNum:siteConfig.maxNum};
    getRate(args).then((data) => {
        let rate = data.rate;
        let rateNum = data.rateNum;
        let bookLink = data.bookLink;
        if(rate !== 0 || rateNum !== 0){
            let rateItem = siteConfig.rateItem(rate,rateNum,bookLink);
            siteConfig.anchorObj(options.item).insertAdjacentHTML(siteConfig.anchorPos,rateItem);
        }
    });
}
(() => {
    'use strict';
    if(Object.keys(sourceRoute).includes(location.hostname)){
        let site = sourceRoute[location.hostname]();
        sourceHandle[site](site,insertRate);
    }
    if(Object.keys(downloadRoute).includes(location.hostname)){
        let sites = Object.keys(downloadConfig);
        insertDownloadButton();
        sites.forEach((item) => {
            let options = {site:item};
            addDownLoadLink(options,downloadConfig);
        });
    }
})();