您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
Greasy Fork is available in English.
解析快手视频
当前为
// ==UserScript== // @name 快手下载 // @namespace http://tampermonkey.net/ // @version 0.1.3 // @description 解析快手视频 // @author xelicev963 // @run-at document-start // @license MIT License // @grant GM_invokeFn // @include *://*.kuaishou.com/* // @inject-into page // @require https://cdn.bootcdn.net/ajax/libs/blueimp-md5/2.18.0/js/md5.min.js // @require https://cdn.bootcdn.net/ajax/libs/jquery/1.7.2/jquery.min.js // ==/UserScript== var metaCache = {}; //hook fetch var fetchListKeys = ['brilliantData', 'visionSearchPhoto', 'brilliantTypeData', 'gameLiveCardList', 'visionProfilePhotoList'] var originFetch = fetch unsafeWindow.fetch = async (url, request) => { var response = await originFetch(url, request) if (url && url.indexOf('graphql') > -1) { try { var text = await response.text() response.text = () => { return new Promise((resolve) => { resolve(text) }) } var res = JSON.parse(text) for (i in fetchListKeys) { var key = fetchListKeys[i]; if (res?.data[key] && res.data[key].feeds && res.data[key].feeds.length > 0) { var feeds = res.data[key].feeds; for (var i = 0; i < feeds.length; i++) { var itemData = feeds[i].photo; itemData.author = feeds[i].author metaCache[itemData.id] = itemData } // console.log(feeds) } } } catch (e) { console.error(e) } } return response } //hook xhr var xhrListKeys = ['hotPhotoInfos', 'inspiredAds'] var origOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function() { this.addEventListener('load', function() { if (this.responseType && this.responseType !== "text") return; var res = JSON.parse(this.responseText) for (i in xhrListKeys) { var key = xhrListKeys[i]; if (res?.data && typeof res.data === 'object' && key in res.data && res.data[key].length > 0) { var feeds = res.data[key]; for (var i = 0; i < feeds.length; i++) { var url = new URL(feeds[i].coverThumbnailUrls[0].url); var id = url.searchParams.get('clientCacheKey')?.replace('.jpg', ''); // console.log(id, feeds[i]) feeds[i].id = id; metaCache[id] = feeds[i]; } // console.log(feeds) } } }); // console.log(arguments) origOpen.apply(this, arguments); }; (function () { var getItemByMeta = (meta, pselector='', pclass='') => { var id = `mona-${md5(meta.id)}` if ($(`#${id}`).length > 0) return null; var dom = $(`<div id='${id}' style="z-index:100"></div>`); var url = meta.photoUrl; meta.title = meta.caption; meta.cover = meta.coverUrl; meta.filename = `${meta.id}.mp4`; let pdom = null; if (pselector) pdom = $(pselector) if (pdom.length > 0 && pclass) { var ps = pdom.parentsUntil(pclass); if (ps.length > 0) pdom = $(ps[ps.length - 1]) } return { id, url, dom, pdom, meta } }; var pageParsers = { detail: async () => { var url = new URL(window.location.href); var video_id = url.pathname.replace("/short-video/", ''); if (video_id in metaCache) { var item = getItemByMeta(metaCache[video_id], '.kwai-player-container-video') return item ? [item] : []; } return []; }, list: async () => { var items = [] for (var [id, meta] of Object.entries(metaCache)) { var pselector = `img[src*='clientCacheKey=${id}']` var item = getItemByMeta(meta, pselector, '.video-card') if (item) items.push(item); } return items }, cc: async () => { var items = []; for (var [id, meta] of Object.entries(metaCache)) { var pselector = `.cc-player-poster[style*='clientCacheKey=${id}']` var item = getItemByMeta(meta, pselector, '.common-video-item') if (!item) continue; item.url = meta.mainMvUrls[0].url; item.meta.cover = meta.coverThumbnailUrls[0].url; if (item) items.push(item); } return items } } var getPageParser = () => { var url = new URL(window.location.href); var paths = url.pathname.split('/'); var path = paths[1]; if (path === "short-video") { return pageParsers.detail; } else if (!path || ["search", "brilliant", "profile"].includes(path)) { return pageParsers.list; } else if (url.host === 'cc.e.kuaishou.com' && ["/inspiration/ads", "/inspiration/hot"].includes(url.pathname)) { return pageParsers.cc; } else { throw 999; } } var parser = { parseItems: async () => { var pr = getPageParser() if (!pr) return [] return pr() } } GM_invokeFn("regParser", parser) })()