// ==UserScript== // @name 花瓣网下载 // @namespace https://www.saintic.com/ // @version 1.4.0 // @description 花瓣网(huaban.com)用户画板图片批量下载到本地 // @author staugur // @match http*://huaban.com/boards/* // @match http*://huaban.com/user/* // @grant GM_setClipboard // @grant GM_info // @grant GM_download // @icon https://static.saintic.com/cdn/images/favicon-64.png // @license BSD 3-Clause License // @date 2018-05-25 // @modified 2025-11-24 // @github https://github.com/staugur/grab_huaban_board/blob/master/grab_huaban_board.js // @supportURL https://blog.saintic.com/blog/256.html // @downloadURL none // ==/UserScript== (function () { 'use strict'; //字符串是否包含子串 function isContains(str, substr) { //str是否包含substr return str.indexOf(substr) >= 0; } //数组是否包含某元素 function arrayContains(arr, obj) { let i = arr.length; while (i--) { if (arr[i] === obj) { return true; } } return false; } //判断页面中id是否存在 function hasId(id) { //有此id返回true,否则返回false let element = document.getElementById(id); if (element) { return true; } else { return false; } } //获取url查询参数 function getUrlQuery(key, acq) { /* 获取URL中?之后的查询参数,不包含锚部分,比如url为http://passport.saintic.com/user/message/?status=1&Action=getCount 若无查询的key,则返回整个查询参数对象,即返回{status: "1", Action: "getCount"}; 若有查询的key,则返回对象值,返回值可以指定默认值acq:如key=status, 返回1;key=test返回acq */ let str = location.search; let obj = {}; if (str) { str = str.substring(1, str.length); // 以&分隔字符串,获得类似name=xiaoli这样的元素数组 let arr = str.split('&'); //let obj = new Object(); // 将每一个数组元素以=分隔并赋给obj对象 for (let i = 0; i < arr.length; i++) { let tmp_arr = arr[i].split('='); obj[decodeURIComponent(tmp_arr[0])] = decodeURIComponent( tmp_arr[1], ); } } return key ? obj[key] || acq : obj; } //计算百分比 function calculatePercentage(num, total) { //小数点后两位百分比 return Math.round((num / total) * 10000) / 100.0 + '%'; } //加载css文件 function addCSS(href) { let link = document.createElement('link'); link.type = 'text/css'; link.rel = 'stylesheet'; link.href = href; document.getElementsByTagName('head')[0].appendChild(link); } //加载js文件 function addJS(src, cb) { let script = document.createElement('script'); script.type = 'text/javascript'; script.src = src; document.getElementsByTagName('head')[0].appendChild(script); script.onload = typeof cb === 'function' ? cb : function () {}; } //获取可使用域名 function getEffectiveHost() { let host = window.location.host; if (!host) { host = document.domain; } if (!host) { host = 'huaban.com'; } if (isContains(host, 'meiwu.co')) { host = 'login.meiwu.co'; } else if (isContains(host, 'huabanpro.com')) { host = 'huabanpro.com'; } else { host = 'huaban.com'; } return host; } //时间戳转化为日期格式 function formatUnixtimestamp(ts) { let unixtimestamp = new Date(ts * 1000); let year = 1900 + unixtimestamp.getYear(); let month = '0' + (unixtimestamp.getMonth() + 1); let date = '0' + unixtimestamp.getDate(); let hour = '0' + unixtimestamp.getHours(); let minute = '0' + unixtimestamp.getMinutes(); let second = '0' + unixtimestamp.getSeconds(); return ( year + '-' + month.substring(month.length - 2, month.length) + '-' + date.substring(date.length - 2, date.length) + ' ' + hour.substring(hour.length - 2, hour.length) + ':' + minute.substring(minute.length - 2, minute.length) ); } //加星隐藏部分 function setStarHidden(str) { if (str) { return str.substr(0, 4) + ' **** ' + str.substr(-4); } } //封装localStorage class StorageMix { constructor(key) { this.key = key; this.obj = window.localStorage; if (!this.obj) { console.error('浏览不支持localStorage'); return false; } } //设置或跟新本地存储数据 set(data) { if (data) { return this.obj.setItem(this.key, JSON.stringify(data)); } } //获取本地存储数据 get() { let data = null; try { data = JSON.parse(this.obj.getItem(this.key)); } catch (e) { console.error(e); } finally { return data; } } clear() { //清除对象 return this.obj.removeItem(this.key); } } //显示条款 function showTerms(cb, onlyShow = false) { let s = new StorageMix('userTermsVer'); if (s.get() !== 'yes') { let html = [ '
', '本使用条款及免责声明(以下简称“本声明”)适用于', '所有用户脚本(以下简称“此脚本”),', '在您阅读本声明后若不同意此声明中的任何条款,', '或对本声明存在质疑,请立刻停止使用此脚本。', '若您已经开始或正在使用此脚本,则表示您已阅读并同意本声明的所有条款。', '
', '

总则:使用过程中请遵守所在国家或地区的相关法律法规。

', '

1. 此脚本使用localStorage存储公告、阅读条款状态等,不使用cookie技术。

', '

2. 此脚本不记录除远程方式外的下载情况,第三方Tdi下载与此脚本和作者无关。

', '

3. 此脚本使用BSD 3-Clause许可证开源,请遵循许可协议条款。

', '

4. 此脚本请个人使用,勿用于商业用途!

', '

5. 用户使用此脚本导致的版权、知识产权、所在网站本身侵权,此脚本作者概不负责!

', '

6. 用户须自己承担使用此脚本访问网站的风险,', '并承担为此而造成的风险责任,与作者本人及相关服务无关!

', '

7. 本声明可随时修改条款,如有变更通过公告发布,声明立时生效。

', ].join(''); layer.open({ type: 1, title: '使用条款与免责声明', closeBtn: false, area: isMobilePhone ? '90%' : '550px', shade: 0.7, shadeClose: false, id: 'userTerm', //设定一个id,防止重复弹出 btn: onlyShow !== true ? ['我同意', '我不同意'] : ['关闭'], btnAlign: 'c', scrollbar: false, content: '
' + html + '
', zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { layer.close(index); if (onlyShow !== true) { s.set('yes'); typeof cb === 'function' && cb(); } }, }); } else { if (onlyShow !== true) { typeof cb === 'function' && cb(); } } } //由于@require方式引入jquery时layer使用异常,故引用cdn中jquery v1.10.1;加载完成后引用又拍云中layer v3.5.1 addJS( 'https://static.saintic.com/cdn/jquery/1.10.1/jquery.min.js', function () { $.noConflict(); addJS('https://static.saintic.com/cdn/layer/3.5.1/layer.js'); }, ); //当前URL var initUrl = window.location.href; //判断UA是否为移动端 var isMobilePhone = navigator.userAgent.match( /(phone|pad|pod|iPhone|iPod|ios|iPad|Android|Mobile|BlackBerry|IEMobile|MQQBrowser|JUC|Fennec|wOSBrowser|BrowserNG|WebOS|Symbian|Windows Phone|Opera Mini)/i, ) ? true : false; //加载优化 var loadingLayer = null; //正则 var isEmail = /^[\w.\-]+@(?:[a-z0-9]+(?:-[a-z0-9]+)*\.)+[a-z]{2,3}$/i; var isMobile = /^1\d{10}$/i; var space = '    '; console.debug('isMobilePhone:', isMobilePhone); // 设置提醒弹框 function setupRemind() { let email = getReceiveBy('email') || '', mobile = getReceiveBy('mobile') || '', token = getReceiveBy('token') || ''; let content_overview = [ '
', '

提醒设置:

', '
', '

仅供提交远程下载后查询下载进度、发送下载完成消息。

', `

保存邮箱

`, `

保存手机

`, `

保存密钥

`, `

微信扫描下发公众号,发送"@下载链接"即可查询状态。

`, '

', '
', '

服务公告:

', `

${space}点击重置状态:将已读公告标记为未读,下次请求会重新展示公告。

`, `

${space}重新阅读公告:手动查看花瓣网公告。

`, '

问题帮助:

', `

${space}查看FAQ:关于设置方面的问题说明,亦可阅读详细文档

`, `

${space}在线反馈。

`, '

捐赠支持:

', `

${space}如果您觉得此脚本对您有所裨益,您可以点此捐赠

`, '

查看使用条款与免责声明。

', '
', ].join(''); let content_help = [ '
', '

1. 什么是密钥?
  答:密钥是在您在诏预开放平台创建的Api Token,与用户一一对应,拥有它可以访问平台公共接口、处理您账号的相关事务等,此处仅作为您使用此脚本查询远端下载记录,以便及时下载完成的压缩包,省去了复制下载链接等步骤。切记密钥不可泄露,否则可能造成账号风险!

', '

2. 怎么创建密钥?
  答:请登录开放平台:https://open.saintic.com,在控制台处可以创建密钥(您可以使用QQ/微博/码云/GitHub等快捷登录)!

', '

3. 微信怎么查询下载进度?
  答:请使用微信APP扫描此二维码并关注,发送"@下载链接"即可,服务器会返回下载状态。

', '
', ].join(''); let donation_content = [ '
', '

支付宝:

', '

', '

微信:

', '

', '
', ].join(''); layer.open({ type: 1, area: isMobilePhone ? '90%' : ['500px', '530px'], maxmin: true, resize: true, closeBtn: false, shade: 0, title: '花瓣网下载脚本功能设置', btn: ['关闭'], btnAlign: 'c', moveType: 1, //拖拽模式,0或者1 content: content_overview, success: function (layero, index) { let body = layer.getChildFrame('body', index); body.context.getElementById('save_remind_email').onclick = function () { let value = body.context.getElementById( 'set_remind_email', ).value; if (value && !isEmail.test(value)) { layer.msg('请输入正确的邮箱地址'); return; } setupReceiveTo('email', value); }; body.context.getElementById('save_remind_mobile').onclick = function () { let value = body.context.getElementById( 'set_remind_mobile', ).value; if (value && !isMobile.test(value)) { layer.msg('请输入正确的手机号'); return; } setupReceiveTo('mobile', value); }; body.context.getElementById('save_remind_token').onclick = function () { let value = body.context.getElementById( 'set_remind_token', ).value; setupReceiveTo('token', value); }; body.context.getElementById('reset_notice_status').onclick = function () { let storage = new StorageMix('grab_huaban_board'); storage.clear(); layer.msg('重置成功', { icon: 1, }); }; body.context.getElementById('reshow_notice').onclick = function () { let storage = new StorageMix('grab_huaban_board'); storage.clear(); showNotice(); }; body.context.getElementById('grab_setting_help').onclick = function () { layer.open({ type: 1, area: '460px', title: 'FAQ', content: content_help, closeBtn: false, shadeClose: false, shade: 0, btn: '我知道了', btnAlign: 'c', zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { layer.close(index); }, }); }; body.context.getElementById('grab_setting_donation').onclick = function () { layer.open({ type: 1, shade: 0, area: '300px', title: '捐赠支持', closeBtn: false, shadeClose: false, btn: '关闭', btnAlign: 'c', content: donation_content, success: function (layero) { /* layero[0].querySelector( '.layui-layer-title' ).style.padding = '0px' */ }, }); }; body.context.getElementById('reshow_userterms').onclick = function () { let s = new StorageMix('userTermsVer'); s.clear(); showTerms(null, true); }; }, }); } /** * 设置接收信息 * @param type 参数: mobile|email|token */ function setupReceiveTo(type, value) { let es = new StorageMix('grab_huaban_board_remind_email'); let ms = new StorageMix('grab_huaban_board_remind_mobile'); let ts = new StorageMix('grab_huaban_board_token'); if (type === 'email') { if (value) { if (!isEmail.test(value)) { layer.msg('请输入正确的邮箱地址'); return; } es.set(value); layer.msg('邮箱:' + value + ',设置成功!', { icon: 1, }); } else { es.clear(); layer.msg('邮箱已清空!', { icon: 1, }); } } else if (type === 'mobile') { if (value) { if (!isMobile.test(value)) { layer.msg('请输入正确的手机号'); return; } ms.set(value); layer.msg('手机号:' + value + ',设置成功!', { icon: 1, }); } else { ms.clear(); layer.msg('手机号已清空!', { icon: 1, }); } } else if (type === 'token') { if (!value) { ts.clear(); layer.msg('密钥已清空!', { icon: 1, }); } else { ts.set(value); layer.msg('密钥:' + value + ',设置成功!', { icon: 1, }); } } else { layer.msg('暂不支持此方式!'); return; } } /** * 读取接收信息值 * @param type 参数: mobile|email|token */ function getReceiveBy(type) { let str = '', es = new StorageMix('grab_huaban_board_remind_email'), ms = new StorageMix('grab_huaban_board_remind_mobile'), ts = new StorageMix('grab_huaban_board_token'); if (type === 'email') { str = es.get(); } else if (type === 'mobile') { str = ms.get(); } else if (type === 'token') { str = ts.get(); } return str || ''; } //交互确定画板下载方式 function interactiveBoard(board_id, pins, pin_number, user_id) { /* board_id int: 画板id pins list: 包含所有程序加载到的图片数据 pin_number int: 这个画板总共有多少图片 user_id str: 这个画板所属的用户 */ layer.close(loadingLayer); let downloadMethod = 0, msg = [ `
当前画板共 ${pin_number} 张图片,抓取了 ${ pins.length } 张,抓取率:${calculatePercentage( pins.length, pin_number, )}!提示: 只有登录后才可以抓取几乎所有图片哦。
`, '请选择以下三种下载方式:
', `1. 文本
${space}即所有图片地址按行显示,提供复制,粘贴至下载工具批量下载即可(或这个工具),推荐使用此方式。
`, `2. 本地
${space}即所有图片直接保存到硬盘中,由于是批量下载,所以浏览器设置中请关闭"下载前询问每个文件的保存位置",并且允许浏览器下载多个文件的授权申请,以保证可以自动批量保存,否则每次保存时会弹出询问,对您造成困扰。
`, `3. 远程
${space}即所有图片将由远端服务器下载并压缩,提供压缩文件链接,直接下载此链接解压即可。
`, '

寻求帮助?请点击我!

', ].join(''); layer.open({ type: 1, area: '450px', title: '选择画板图片下载方式', content: msg, closeBtn: false, shadeClose: false, shade: 0, btn: ['文本', '本地', '远程'], btnAlign: 'c', zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { //文本方式下载,比如迅雷、QQ旋风 downloadMethod = 1; layer.close(index); layer.open({ type: 1, title: '文本方式下载', area: '360px', content: '
请点击复制按钮,粘贴到迅雷等工具中下载!
', closeBtn: false, shadeClose: false, shade: 0, btn: '复制', btnAlign: 'c', maxmin: true, zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { layer.close(index); GM_setClipboard( pins .map(function (pin) { return pin.imgUrl + '\n'; }) .join(''), ); layer.msg('复制成功', { icon: 1, }); }, }); }, btn2: function (index, layero) { //本地下载 downloadMethod = 2; layer.close(index); pins.map(function (pin) { GM_download(pin.imgUrl, pin.imgName); }); }, btn3: function (index, layero) { //远端下载 downloadMethod = 3; layer.close(index); // 提醒接收配置信息读取 let email = getUrlQuery('email', getReceiveBy('email')); let mobile = getUrlQuery('sms', getReceiveBy('mobile')); jQuery.ajax({ url: 'https://open.saintic.com/CrawlHuaban/', type: 'POST', data: { site: 1, version: GM_info.script.version, board_total: pin_number, board_id: board_id, user_id: user_id, pins: JSON.stringify(pins), email: email, sms: mobile, }, beforeSend: function (request) { request.setRequestHeader( 'Authorization', 'Token ' + getReceiveBy('token'), ); }, success: function (res) { if (res.success === true) { let msg = [ '
下载任务已经提交!
根据画板图片数量,所需时间不等,请稍等数分钟后访问下载链接:
', res.downloadUrl + '
它将于', res.expireTime + '过期,那时资源会被删除,请提前下载。', res.tip + '
', ].join(''); layer.open({ type: 1, title: '温馨提示', content: msg, closeBtn: false, shadeClose: false, shade: 0, area: '350px', btn: '我已知晓并复制下载链接', btnAlign: 'c', maxmin: true, zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { layer.close(index); GM_setClipboard(res.downloadUrl); let tips = '复制成功!'; if (email) { tips += ' 接收提醒邮箱:' + email; } if (mobile) { tips += ' 接收提醒手机:' + mobile; } layer.msg(tips, { icon: 1, }); }, }); } else { layer.msg('远端服务提示: ' + res.msg, { icon: 2, time: 8000, }); } }, }); }, }); } //交互确定用户下载方式 function interactiveUser(user_id, boards, board_number) { boards.map(function (board_id) { let msg = [ `
当前画板是:${board_id}!`, '提示: 只有登录后才可以抓取几乎所有画板哦。
', '请选择以下两种功能按钮:
', `1. 开始下载
${space}点击此按钮将开始抓取画板图片,抓取完成后弹出下载方式,请选择某种方式后完成当前画板下载。
`, `2. 跳过
${space}即忽略此画板,并关闭本窗口。
`, '

请注意:用户存在多个画板时会弹出多个窗口,请移动或最小化当前窗口以显示其他窗口。

', '

寻求帮助?请点击我!

', ].join(''); layer.open({ type: 1, area: '450px', title: `花瓣网用户抓取:${user_id}`, content: msg, closeBtn: false, shadeClose: false, shade: 0, btn: ['开始下载', '跳过'], btnAlign: 'c', maxmin: true, zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { //按钮【开始下载】的回调 layer.close(index); downloadBoard(board_id); }, btn2: function (index, layero) { //按钮【跳过】的回调 layer.close(index); }, }); }); let content = [ '
', `当前用户画板数量总共为 ${board_number},抓取了 ${ boards.length } 个,抓取率:${calculatePercentage( boards.length, board_number, )}!
`, '寻求帮助?Bug反馈?请点击我!', '
', ].join(''); layer.open({ type: 1, title: '温馨提示', content: content, closeBtn: false, shadeClose: false, shade: 0, btn: '我已知晓', btnAlign: 'c', zIndex: layer.zIndex, success: function (layero) { layer.setTop(layero); }, yes: function (index, layero) { //按钮【我已知晓】的回调 layer.close(index); }, }); } //画板解析与下载 function downloadBoard(board_id) { if (!board_id) { console.error('画板ID不能为空!'); return false; } console.group('花瓣网下载-当前画板:' + board_id); let limit = 100, loadingLayer = layer.load(0, { time: 5000, }); //get first pin data jQuery.ajax({ url: `/v3/boards/${board_id}/pins?limit=${limit}&sort=seq&fields=pins:PIN|board:BOARD_DETAIL|check`, async: false, success: function (res) { try { console.log(res); if (res.hasOwnProperty('board') === true) { let board_data = res.board, board_pins = res.pins; //画板图片总数 let pin_number = board_data.pin_count, user_id = board_data.user.urlname, //尝试向上取整,计算加载完画板图片需要的最大次数 retry = board_pins.length < pin_number ? Math.ceil(pin_number / limit) : 0; console.debug( `Current board ${board_id} pins number is ${pin_number}, first pins number is ${board_pins.length}, retry is ${retry}`, ); let bf = setInterval(function () { if (retry > 0) { //说明没有加载完画板图片,需要ajax请求 let last_pin = board_pins[board_pins.length - 1].pin_id; //get ajax pin data let board_next_url = `/v3/boards/${board_id}/pins?limit=${limit}&sort=seq&fields=pins:PIN|board:BOARD_DETAIL|check&max=${last_pin}`; jQuery.ajax({ url: board_next_url, async: false, success: function (res) { //console.log(res); let _pin_data = res.pins; board_pins = board_pins.concat(_pin_data); console.debug( `ajax load board with pin_id ${last_pin}, get pins number is ${_pin_data.length}, merged.`, ); if (_pin_data.length === 0) { retry = 0; return false; } last_pin = _pin_data[_pin_data.length - 1] .pin_id; }, }); retry--; } else { console.log( `画板 ${board_id} 共抓取 ${board_pins.length} 个pin`, ); let pins = board_pins.map(function (pin) { let suffix = !pin.file.type ? 'png' : pin.file.type.split('/')[1]; return { imgUrl: window.location.protocol + '//hbimg.huabanimg.com/' + pin.file.key, imgName: pin.pin_id + '.' + suffix, }; }); //交互确定下载方式 interactiveBoard( board_id, pins, pin_number, user_id, ); clearInterval(bf); } }, 200); } } catch (e) { console.error('下载画板发生错误:'); console.error(e); } }, }); console.groupEnd(); } //用户解析与下载 function downloadUser(user_id) { if (!user_id) { console.error('用户ID不能为空!'); return false; } console.group('花瓣网下载-当前用户:' + user_id); let limit = 10; //get first board data jQuery.ajax({ url: `/v3/${user_id}/boards?limit=${limit}&fields=boards:BOARD|user,total,page_num,page_size&joined=1&urlname=${user_id}`, async: false, success: function (res) { try { //console.log(res); if (res.hasOwnProperty('user') === true) { let user_data = res.user, board_number = user_data.board_count, board_ids = res.boards, retry = board_ids.length < board_number ? Math.ceil(board_number / limit) : 0; console.debug( `Current user ${user_id} boards number is ${board_number}, first boards number is ${board_ids.length}, retry is ${retry}`, ); let uf = setInterval(function () { if (retry > 0) { let last_board = board_ids[board_ids.length - 1].board_id; //get ajax board data let user_next_url = `/v3/${user_id}/boards?max=${last_board}&limit=${limit}&fields=boards:BOARD|user,total,page_num,page_size&joined=1&urlname=${user_id}&&wfl=1`; jQuery.ajax({ url: user_next_url, async: false, success: function (res) { //console.log(res); let user_next_data = res.boards; board_ids = board_ids.concat(user_next_data); console.debug( `ajax load user with board_id ${last_board}, get boards number is ${user_next_data.length}, merged`, ); if (user_next_data.length === 0) { retry = 0; return false; } last_board = user_next_data[ user_next_data.length - 1 ].board_id; }, }); retry--; } else { console.log( `用户 ${user_id} 共抓取 ${board_ids.length} 个board`, ); let boards = board_ids .filter(function (board) { if (board.pin_count > 0) { return true; } }) .map(function (board) { return board.board_id; }); //交互确定下载方式 interactiveUser(user_id, boards, board_number); clearInterval(uf); } }, 200); } } catch (e) { console.error(e); } }, }); console.groupEnd(); } //获取公告接口 function showNotice() { jQuery.ajax({ url: 'https://open.saintic.com/CrawlHuaban/notice?catalog=2', type: 'GET', success: function (res) { if (res.code === 0) { let notices = res.data; if (notices.length > 0) { let storage = new StorageMix('grab_huaban_board'); let localIds = storage.get() || []; let html = ''; notices.map(function (notice) { //notice{id, ctime, content} if (!arrayContains(localIds, notice.id) === true) { localIds.push(notice.id); html += '

@' + formatUnixtimestamp(notice.ctime) + ' 【 ' + notice.content + ' 】

'; } }); storage.set(localIds); if (!html) { return false; } layer.open({ type: 1, title: '诏预开放平台公告', closeBtn: false, area: 'auto', shade: 0, id: 'grab_huaban_board', //设定一个id,防止重复弹出 resize: true, maxmin: true, btn: ['我知道了'], btnAlign: 'c', moveType: 1, //拖拽模式,0或者1 content: '
' + html + '
', yes: function (index, layero) { layer.close(index); }, }); } } }, }); } /** * 主入口,分出不同模块:用户、画板,监听并刷新URL * */ function main() { if (window.location.pathname.split('/')[1] === 'boards') { //当前在画板地址下 let board_id = window.location.pathname.split('/')[2], board_text = '下载', board_mobile_text = '下载', setup_text = '设置'; if (isMobile && hasId('mobile_board_page')) { //当前是移动版 let bca = document .getElementById('board_card') .getElementsByTagName('a'), brpx = '10px', brpx_setup = '10px'; if (bca.length <= 1) { bca = bca[0]; } else { bca = bca[1]; if (isContains(bca.innerText, '已关注')) { (brpx = '116px'), (brpx_setup = '174px'); } else { (brpx = '103px'), (brpx_setup = '161px'); } } if (isContains(bca.innerText, board_mobile_text) === false) { bca.insertAdjacentHTML( 'afterEnd', '' + setup_text + '' + '' + board_mobile_text + '', ); } } else { //当前是PC版 let pab = document.querySelectorAll( `button[data-button-name="分享"][data-board-id="${board_id}"]`, )[1]; console.debug(pab); //插入下载画板按钮 if (pab) { let tmpHtml = [ ``, ``, ].join(''); pab.insertAdjacentHTML('beforebegin', tmpHtml); } else { console.error('未找到分享按钮,无法插入下载按钮!'); } } //监听画板点击下载事件 document.getElementById('downloadBoard').onclick = function () { showTerms(function () { //展示公告 showNotice(); downloadBoard(board_id); }); }; } else if (location.pathname.startsWith('/user') === true) { //判断是在用户主页 let user_id = window.location.pathname.split('/')[2], user_text = '下载', user_mobile_text = '下载', setup_text = '设置'; if ( arrayContains( [ 'all', 'discovery', 'favorite', 'categories', 'apps', 'about', 'search', 'activities', 'settings', 'users', 'friends', 'partner', 'message', 'muse', 'login', 'signup', 'go', 'explore', ], user_id, ) === false ) { //排除以上数组中的二级目录 if (isMobile && hasId('people_card')) { //当前是移动版 let pca = document .getElementById('people_card') .getElementsByTagName('a'), urpx = '10px', urpx_setup = '10px'; if (pca.length <= 2) { pca = pca[1]; } else { pca = pca[2]; if (isContains(pca.innerText, '已关注')) { (urpx = '85px'), (urpx_setup = '145px'); } else { (urpx = '68px'), (urpx_setup = '126px'); } } if (isContains(pca.innerText, user_mobile_text) === false) { pca.insertAdjacentHTML( 'afterEnd', ' ' + setup_text + '' + ' ' + user_mobile_text + '', ); } } else { //当前是PC版 let uca = document.querySelectorAll( 'button[data-button-name="分享"]', )[0]; //插入下载用户画板按钮 if (uca) { let tmpHtml = [ ``, ``, ].join(''); uca.insertAdjacentHTML('beforebegin', tmpHtml); } else { console.error('未找到分享按钮,无法插入下载按钮!'); } } //监听用户点击下载事件 document.getElementById('downloadUser').onclick = function () { showTerms(function () { //展示公告 showNotice(); downloadUser(user_id); }); }; } } // 监听设置提醒按钮 document.getElementById('setupRemind').onclick = function () { setupRemind(); }; //采用循环方式判断url变化 setInterval(function () { if (window.location.href != initUrl) { if ( hasId('downloadBoard') === false && hasId('downloadUser') === false ) { if (window.location.pathname.split('/')[1] != 'pins') { window.location.reload(); } } } }, 1000); } window.onload = function () { setTimeout(function () { main(); }, 2000); }; })();