您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
可以下载AC视频稿件、免费番剧、用户视频稿件和视频合辑的视频m3u8链接
// ==UserScript== // @name AcFun - 视频m3u8链接下载 // @namespace http://tampermonkey.net/ // @version 1.0.3 // @description 可以下载AC视频稿件、免费番剧、用户视频稿件和视频合辑的视频m3u8链接 // @author dareomaewa // @match https://www.acfun.cn/v/0.0 // @match https://www.acfun.cn/bangumi/0.0 // @match https://www.acfun.cn/v/0.0/ // @match https://www.acfun.cn/bangumi/0.0/ // @icon https://www.google.com/s2/favicons?sz=64&domain=acfun.cn // @grant GM_xmlhttpRequest // @grant GM_download // @license MIT // ==/UserScript== function waitElement(selector, times, interval, flag=true){ var _times = times || -1, _interval = interval || 1, _selector = selector, _iIntervalID, _flag = flag; return new Promise(function(resolve, reject){ _iIntervalID = setInterval(function() { if(!_times) { clearInterval(_iIntervalID); reject(); } _times <= 0 || _times--; var _self = $(_selector); if( (_flag && _self.length) || (!_flag && !_self.length) ) { clearInterval(_iIntervalID); resolve(_iIntervalID); } }, _interval); }); } function addChild(fatherNode, childNode, innerHtmlStr, type) { childNode.innerHTML = innerHtmlStr; if (type) { fatherNode.appendChild(childNode); }else { fatherNode.appendChild(childNode.childNodes[0]); } } function addChildDiv(fatherNode, innerHtmlStr) { addChild(fatherNode, document.createElement("div"), innerHtmlStr); } function replaceText(selector, newText) { waitElement(selector).then(function() {document.querySelector(selector).innerText = newText;}); } function replaceTip(color, newText) { const selector = '#tips'; waitElement(selector).then(function() { replaceText(selector, newText); if(color) { const styleColor = document.querySelector(selector).style; styleColor.color = color; } }); } function awk(text, startStr, endStr) { const lines = text.split(/\r?\n/); let startIndex = -1; let endIndex = -1; // 查找起始行 for (let i = 0; i < lines.length; i++) { if (lines[i].includes(startStr)) { startIndex = i; break; } } // 如果找到起始行,查找结束行 if (startIndex !== -1) { for (let i = startIndex; i < lines.length; i++) { if (lines[i].includes(endStr)) { endIndex = i; break; } } } // 返回结果 if (startIndex === -1) { return ""; // 未找到起始行 } else if (endIndex === -1) { return lines.slice(startIndex).join("\n"); // 未找到结束行,返回起始行到最后 } else { return lines.slice(startIndex, endIndex + 1).join("\n"); } } window.onload = function() { console.log('window.onload'); let downloadText = ''; let fileName = ''; let isPnum = false; let isBangumiNum = false; let isDownlodOne = false; function GM_fetch(url) { return new Promise((resolve, reject) => { GM_xmlhttpRequest({ method: "GET", url: url, onload: resolve, onerror: reject }); }); } function appendDownloadText(text, title) { downloadText += (text + '\n'); if(!fileName) { fileName = title; } } function clearDownloadText() { downloadText = ''; fileName = ''; } function appendM3u8Url(htmlText, infoName, pTitle) { const pageInfoText = awk(htmlText, 'window.pageInfo', '};'); if(!pageInfoText) { throw new Error('找不到页面,请检查并重试'); } console.log('count'); const pageInfoStr = pageInfoText.replace(`window.pageInfo = window.${infoName} = `,'').replace('};', '}'); const pageInfo = JSON.parse(pageInfoStr); if(!pageInfo.currentVideoInfo) { throw new Error('找不到资源,请检查并重试'); } const ksPlayJsonStr = pageInfo.currentVideoInfo.ksPlayJson; const ksPlayJson = JSON.parse(ksPlayJsonStr); const video = ksPlayJson.adaptationSet[0].representation[0]; const videoName = `${pageInfo.showTitle ? pageInfo.showTitle : pageInfo.title}${pTitle && !pageInfo.showTitle ? (' - ' + pTitle) : ''}${pageInfo.user ? '【' + pageInfo.user.name + '】' : ''}`; const videoInfo = `${videoName}【${video.qualityLabel}】,${video.url}`; appendDownloadText(videoInfo, isDownlodOne ? `【${pageInfo.bangumiTitle ? '番剧' : '视频'}】${videoName}` : `${pageInfo.bangumiTitle ? `【番剧】${pageInfo.bangumiTitle}` : `【视频】${pageInfo.title}`}${pageInfo.user ? '【' + pageInfo.user.name + '】' : ''}`); } async function getM3u8(url, infoName, pTitle) { const response = await GM_fetch(url); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const htmlText = response.responseText; appendM3u8Url(htmlText, infoName, pTitle); } async function getP(url, infoName, getDocText) { const response = await GM_fetch(url); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const responseText = response.responseText; const docText = getDocText(responseText); const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const multipleP = doc.querySelectorAll('.single-p'); multipleP.forEach(function(p) { console.log(p.getAttribute('data-href')); }); if((isDownlodOne && isBangumiNum) || multipleP.length === 0) { appendM3u8Url(responseText, infoName); } else if(isDownlodOne && isPnum) { let p; for (var j = 0; j < multipleP.length; j++) { const currp = multipleP[j]; const purl = currp.getAttribute('data-href'); if(url === purl) { p = currp; break; } } const purl = p.getAttribute('data-href'); const pTitle = p.getAttribute('title'); await getM3u8(purl, infoName, pTitle); } else { if(isDownlodOne && !isPnum && !isBangumiNum) { const p = multipleP[0]; const purl = p.getAttribute('data-href'); const pTitle = p.getAttribute('title'); await getM3u8(purl, infoName, pTitle); } else { for (var i = 0; i < multipleP.length; i++) { const p = multipleP[i]; const purl = p.getAttribute('data-href'); const pTitle = p.getAttribute('title'); await getM3u8(purl, infoName, pTitle); } } } } async function downloadM3u8Text() { console.log(downloadText); const gmdownload = GM_download({ url: "data:text/plain," + encodeURIComponent(downloadText), name: `${fileName}-${new Date().getTime()}.txt`, saveAs: true }); console.log('startclear gmdownload'); setTimeout(() => {gmdownload.abort();console.log('endclear gmdownload');}, 10000); } async function getVideo(acNo) { await getP(`/v/${acNo}`, 'videoInfo', function(responseText) { return responseText; }); await downloadM3u8Text(); clearDownloadText(); } async function getBangumiItem(aaNo) { const timestamp = new Date().getTime(); await getP(`/bangumi/${aaNo}?pagelets=pagelet_partlist&reqID=0&ajaxpipe=1&t=${timestamp}`, 'bangumiData', function(responseText) { const response = JSON.parse(responseText.replace('/*<!-- fetch-stream -->*/', '')); const parser = new DOMParser(); const doc = parser.parseFromString(response.html, 'text/html'); const overParts = doc.querySelectorAll('ul'); if(overParts.length === 0) { throw new Error('找不到此番剧号'); } return response.html; }); } async function getBangumi(aaNo) { const response = await GM_fetch(`/bangumi/${aaNo}`); if (response.status !== 200) { throw new Error('找不到此番剧号'); } const responseText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(responseText, 'text/html'); const multipleItem = doc.querySelectorAll('.bangumi-item'); console.log(multipleItem); if(multipleItem.length === 0) { await getBangumiItem(aaNo); } else { for (var i = 0; i < multipleItem.length; i++) { const item = multipleItem[i]; const dataId = item.getAttribute('data-id'); await getBangumiItem('aa' + dataId); } } await downloadM3u8Text(); clearDownloadText(); } async function downloadBtn(promiseFunction) { await promiseFunction.then(function() { replaceTip('darkgreen', '已完成!'); }).catch(function(err) { console.log(err) replaceTip('red', err.message); }).finally(() => { const acaabutton = document.getElementById('acaaDownloadBtn'); acaabutton.disabled = false; const uidaabutton = document.getElementById('uidaaDownloadBtn'); uidaabutton.disabled = false; clearDownloadText(); }); } async function getVideoPromise(acNo) { return new Promise((resolve, reject) => { try { resolve(getVideo(acNo)); } catch (error) { reject(error); } }); } async function getBangumiPromise(aaNo) { return new Promise((resolve, reject) => { try { resolve(getBangumi(aaNo)); } catch (error) { reject(error); } }); } async function getOneBangumi(aaNo) { await getP(`/bangumi/${aaNo}`, 'bangumiData', function(responseText) { return responseText; }); await downloadM3u8Text(); clearDownloadText(); } async function getOneBangumiPromise(aaNo) { return new Promise((resolve, reject) => { try { resolve(getOneBangumi(aaNo)); } catch (error) { reject(error); } }); } window.downloadLink = async function downloadLink() { var acaaNumEle = document.getElementById('acaaNum'); const number = acaaNumEle.value.replace(/\s/g, ''); console.log(number); isPnum = number.includes('_'); console.log(`isPnumisPnum: ${isPnum}`); isDownlodOne = document.getElementById('downOne').checked; console.log(`isDownlodOne: ${isDownlodOne}`); replaceTip('black', '请勿离开页面,正在处理中.....'); const acaabutton = document.getElementById('acaaDownloadBtn'); acaabutton.disabled = true; const uidaabutton = document.getElementById('uidaaDownloadBtn'); uidaabutton.disabled = true; if(number.startsWith("ac")){ isBangumiNum = false; await downloadBtn(getVideoPromise(number)); } else if(number.startsWith("aa")){ isBangumiNum = true; if(isDownlodOne) { await downloadBtn(getOneBangumiPromise(number)); } else { await downloadBtn(getBangumiPromise(number)); } } else { console.log('Invalid number'); replaceTip('red', '无效AC号或番剧号'); acaabutton.disabled = false; uidaabutton.disabled = false; clearDownloadText(); } } async function getUidPageInfoVideo(uid, page, pageSize) { isDownlodOne = false; const timestamp = new Date().getTime(); const response = await GM_fetch(`/u/${uid}?quickViewId=ac-space-video-list&reqID=0&ajaxpipe=1&type=video&order=newest&page=${page}&pageSize=${pageSize}&t=${timestamp}`); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const responseText = response.responseText; const res = JSON.parse(responseText.replace('/*<!-- fetch-stream -->*/', '')); const parser = new DOMParser(); const doc = parser.parseFromString(res.html, 'text/html'); const videos = doc.querySelectorAll('a.ac-space-video'); if(videos.length === 0) { throw new Error('没有用户稿件'); } for (var j = 0; j < videos.length; j++) { const video = videos[j]; const wbinfo = JSON.parse(video.dataset.wbinfo); await getP(`/v/ac${wbinfo.mediaId}`, 'videoInfo', function(responseText) { return responseText; }); } } async function getUidVideo(uid) { const response = await GM_fetch(`/u/${uid}`); if (response.status !== 200) { throw new Error('找不到用户,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const spanname = doc.querySelector('span.name .text-overflow'); const unmae = spanname.innerHTML; const videoCountNode = doc.querySelector('.tags li.active span'); const videoCount = videoCountNode.innerHTML; fileName = `【用户】${unmae}的全部稿件(共${videoCount})`; if(videoCount === 0) { throw new Error('没有用户稿件'); } let forCount; if(videoCount <= 20) { forCount = 1; } else { if(videoCount % 20 === 0) { forCount = videoCount / 20; } else { forCount = Math.floor(videoCount / 20) + 1; } } console.log('videoPageCount: ' + forCount); for (var i = 1; i <= forCount; i++) { console.log('videoPage: ' + i); await getUidPageInfoVideo(uid, i, 20); } await downloadM3u8Text(); clearDownloadText(); } async function getUidUpdateVideo(uid, updateNum) { const response = await GM_fetch(`/u/${uid}`); if (response.status !== 200) { throw new Error('找不到用户,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const spanname = doc.querySelector('span.name .text-overflow'); const unmae = spanname.innerHTML; fileName = `【用户】${unmae}的更新稿件(共${updateNum})`; if(updateNum > 100) { throw new Error('更新数量不能超过100'); } await getUidPageInfoVideo(uid, 1, updateNum); await downloadM3u8Text(); clearDownloadText(); } async function getUidPageVideo(uid, page) { const response = await GM_fetch(`/u/${uid}`); if (response.status !== 200) { throw new Error('找不到用户,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const spanname = doc.querySelector('span.name .text-overflow'); const unmae = spanname.innerHTML; fileName = `【用户】${unmae}的第${page}页稿件`; await getUidPageInfoVideo(uid, page, 20); await downloadM3u8Text(); clearDownloadText(); } async function getFilterUidPageVideo(filteredFeed) { isDownlodOne = false; for (var j = 0; j < filteredFeed.length; j++) { const feedItem = filteredFeed[j]; const videoList = feedItem.videoList; for (var i = 0; i < videoList.length; i++) { console.log('count'); const videoItem = videoList[i]; const response = await GM_fetch(`https://api-ipv6.app.acfun.cn/rest/app/play/playInfo/m3u8V2?videoId=${videoItem.id}&resourceId=${feedItem.dougaId}&resourceType=2&mkey=mkey&product=ACFUN_APP&appMode=0`); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const responseText = response.responseText; const res = JSON.parse(responseText); const playInfo = res.playInfo; if(!playInfo) { throw new Error('找不到资源,请检查并重试'); } const videoName = `${feedItem.title}${videoItem.title ? (' - ' + videoItem.title) : ''}${feedItem.user ? '【' + feedItem.user.name + '】' : ''}`; let videoInfo; if(playInfo.isKsManifest) { const ksPlayJsonStr = playInfo.ksPlayJson; const ksPlayJson = JSON.parse(ksPlayJsonStr); const video = ksPlayJson.adaptationSet[0].representation[0]; videoInfo = `${videoName}【${video.qualityLabel}】,${video.url.includes('://tx') ? video.backupUrl : video.url}`; } else { const video = playInfo.streams[0]; videoInfo = `${videoName}【${video.qualityLabel}】,${video.playUrls[0].includes('://tx') ? video.playUrls[1] : video.playUrls[0]}`; } appendDownloadText(videoInfo, '') } } } async function getFilterUidVideo(uid) { const response = await GM_fetch(`https://api-ipv6.app.acfun.cn/rest/app/user/resource/query?count=1&authorId=${uid}&resourceType=2&sortType=3&status=1&pcursor=0&product=ACFUN_APP&sys_version=10&app_version=6.77.0.1306&sys_name=android&appMode=0`); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const responseText = response.responseText; const res = JSON.parse(responseText); const videos = res.feed; console.log(videos); if(videos.length === 0) { throw new Error('没有用户稿件'); } const videoCount = res.totalNum; if(videoCount === 0) { throw new Error('没有用户稿件'); } let forCount; if(videoCount <= 20) { forCount = 1; } else { if(videoCount % 20 === 0) { forCount = videoCount / 20; } else { forCount = Math.floor(videoCount / 20) + 1; } } console.log('videoPageCount: ' + forCount); const parentChannel = document.getElementById('parentChannel'); const parentChannelId = parentChannel.value; var parentChannelIndex = parentChannel.selectedIndex; var parentChannelText = parentChannel.options[parentChannelIndex].text; const channel = document.getElementById(`channel_${parentChannelId}`); const channelId = channel.value; var channelIndex = channel.selectedIndex; var channeText = channel.options[channelIndex].text; const filteredFeed = []; const channelData = { parentId: parseInt(parentChannelId), parentName: parentChannelText, id: parseInt(channelId), name: channeText } for (var i = 0; i < forCount; i++) { console.log('videoPage: ' + i); const response = await GM_fetch(`https://api-ipv6.app.acfun.cn/rest/app/user/resource/query?count=${20}&authorId=${uid}&resourceType=2&sortType=3&status=1&pcursor=${i}&product=ACFUN_APP&appMode=0`); if (response.status !== 200) { throw new Error('找不到资源,请检查并重试'); } const responseText = response.responseText; const res = JSON.parse(responseText); const feed = res.feed; if(feed.length === 0) { throw new Error('没有用户稿件'); } feed.forEach(function(feedItem) { if(channelData.id) { if(feedItem.channel.id === channelData.id) { filteredFeed.push(feedItem); } } else if(channelData.parentId) { if(feedItem.channel.parentId === channelData.parentId) { filteredFeed.push(feedItem); } } else { filteredFeed.push(feedItem); } }); } if(filteredFeed.length === 0) { throw new Error('没有相关稿件'); } let channelName = '全部'; if(channelData.id){ channelName = `【${channelData.name}】分区`; } else if(channelData.parentId){ channelName = `【${channelData.parentName}】分区`; } const unmae = filteredFeed[0].user.name; fileName = `【用户】${unmae}的${channelName}稿件(共${filteredFeed.length})`; await getFilterUidPageVideo(filteredFeed); await downloadM3u8Text(); clearDownloadText(); } async function getAlbumPageInfoVideo(arubamuId, page, pageSize) { const arubamuResponse = await GM_fetch(`/rest/pc-direct/arubamu/content/list?page=${page}&size=${pageSize}&arubamuId=${arubamuId}`); if (arubamuResponse.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const arubamuRes = JSON.parse(arubamuResponse.responseText); const videos = arubamuRes.contents; if (videos.length === 0) { throw new Error('找不到合辑,请检查并重试'); } if(arubamuRes.totalSize === 0) { throw new Error('没有合辑稿件'); } for (var j = 0; j <videos.length; j++) { const video = videos[j]; await getP(`/v/ac${video.resourceId}`, 'videoInfo', function(responseText) { return responseText; }); } } async function getAlbumVideo(aaNo) { const response = await GM_fetch(`/a/${aaNo}`); if (response.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const h1album = doc.querySelector('h1.album-title'); if (!h1album) { throw new Error('找不到合辑,请检查并重试'); } const albumTitle = h1album.innerHTML; const arubamuId = aaNo.slice(2, aaNo.length); console.log(arubamuId); const restresponse = await GM_fetch(`/rest/pc-direct/arubamu/content/list?page=1&size=1&arubamuId=${arubamuId}`); if (restresponse.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const res = JSON.parse(restresponse.responseText); if (res.contents.length === 0) { throw new Error('找不到合辑,请检查并重试'); } if (res.contents[0].resourceTypeValue !== 2) { throw new Error('只支持视频合辑'); } const totalSize = res.totalSize; fileName = `【合辑】${albumTitle}的全部稿件(共${totalSize})`; if(totalSize === 0) { throw new Error('没有合辑稿件'); } let forCount; if(totalSize <= 30) { forCount = 1; } else { if(totalSize % 30 === 0) { forCount = totalSize / 30; } else { forCount = Math.floor(totalSize / 30) + 1; } } console.log('arubamuPageCount: ' + forCount); for (var i = 1; i <= forCount; i++) { console.log('arubamuPage: ' + i); await getAlbumPageInfoVideo(arubamuId, i, 30); } await downloadM3u8Text(); clearDownloadText(); } async function getAlbumUpdateVideo(aaNo, updateNum) { const response = await GM_fetch(`/a/${aaNo}`); if (response.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const h1album = doc.querySelector('h1.album-title'); if (!h1album) { throw new Error('找不到合辑,请检查并重试'); } const albumTitle = h1album.innerHTML; const arubamuId = aaNo.slice(2, aaNo.length); console.log(arubamuId); const restresponse = await GM_fetch(`/rest/pc-direct/arubamu/content/list?page=1&size=1&arubamuId=${arubamuId}`); if (restresponse.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const res = JSON.parse(restresponse.responseText); if (res.contents.length === 0) { throw new Error('找不到合辑,请检查并重试'); } if (res.contents[0].resourceTypeValue !== 2) { throw new Error('只支持视频合辑'); } const totalSize = res.totalSize; fileName = `【合辑】${albumTitle}的更新稿件(共${updateNum})`; if(updateNum > 100) { throw new Error('更新数量不能超过100'); } await getAlbumPageInfoVideo(arubamuId, 1, updateNum); await downloadM3u8Text(); clearDownloadText(); } async function getAlbumPageVideo(aaNo, page) { const response = await GM_fetch(`/a/${aaNo}`); if (response.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const docText = response.responseText; const parser = new DOMParser(); const doc = parser.parseFromString(docText, 'text/html'); const h1album = doc.querySelector('h1.album-title'); if (!h1album) { throw new Error('找不到合辑,请检查并重试'); } const albumTitle = h1album.innerHTML; const arubamuId = aaNo.slice(2, aaNo.length); console.log(arubamuId); const restresponse = await GM_fetch(`/rest/pc-direct/arubamu/content/list?page=1&size=1&arubamuId=${arubamuId}`); if (restresponse.status !== 200) { throw new Error('找不到合辑,请检查并重试'); } const res = JSON.parse(restresponse.responseText); if (res.contents.length === 0) { throw new Error('找不到合辑,请检查并重试'); } if (res.contents[0].resourceTypeValue !== 2) { throw new Error('只支持视频合辑'); } const totalSize = res.totalSize; fileName = `【合辑】${albumTitle}的第${page}页稿件`; await getAlbumPageInfoVideo(arubamuId, page, 30); await downloadM3u8Text(); clearDownloadText(); } async function getUidVideoPromise(uid) { return new Promise((resolve, reject) => { try { resolve(getUidVideo(uid)); } catch (error) { reject(error); } }); } async function getFilterUidVideoPromise(uid) { return new Promise((resolve, reject) => { try { resolve(getFilterUidVideo(uid)); } catch (error) { reject(error); } }); } async function getUidUpdateVideoPromise(uid, updateNum) { return new Promise((resolve, reject) => { try { resolve(getUidUpdateVideo(uid, updateNum)); } catch (error) { reject(error); } }); } async function getUidPageVideoPromise(uid, page) { return new Promise((resolve, reject) => { try { resolve(getUidPageVideo(uid, page)); } catch (error) { reject(error); } }); } async function getAlbumVideoPromise(aaNo) { return new Promise((resolve, reject) => { try { resolve(getAlbumVideo(aaNo)); } catch (error) { reject(error); } }); } async function getAlbumUpdateVideoPromise(aaNo, updateNum) { return new Promise((resolve, reject) => { try { resolve(getAlbumUpdateVideo(aaNo, updateNum)); } catch (error) { reject(error); } }); } async function getAlbumPageVideoPromise(aaNo, page) { return new Promise((resolve, reject) => { try { resolve(getAlbumPageVideo(aaNo, page)); } catch (error) { reject(error); } }); } window.downloadUidArubamuLink = async function downloadUidArubamuLink() { var uidaaNum = document.getElementById('uidaaNum'); const number = uidaaNum.value.replace(/\s/g, ''); console.log(number); if (number.length === 0) { replaceTip('red', '无效UID或合辑号'); return; } var uidaaUpdateNum = document.getElementById('uidaaUpdateNum'); const updateNum = uidaaUpdateNum.value.replace(/\s/g, ''); console.log(updateNum); if (!(/^\d+$/.test(updateNum))) { replaceTip('red', '更新数量:请输入整数'); return; } const updateNumInt = parseInt(updateNum); var uidaaListPage = document.getElementById('uidaaListPage'); const pageNum = uidaaListPage.value.replace(/\s/g, ''); console.log(pageNum); if (!(/^\d+$/.test(pageNum))) { replaceTip('red', '稿件页次:请输入整数'); return; } const pageNumInt = parseInt(pageNum); replaceTip('black', '请勿离开页面,正在处理中.....'); const acaabutton = document.getElementById('acaaDownloadBtn'); acaabutton.disabled = true; const uidaabutton = document.getElementById('uidaaDownloadBtn'); uidaabutton.disabled = true; if(number.startsWith("aa")){ if(updateNumInt) { await downloadBtn(getAlbumUpdateVideoPromise(number, updateNumInt)); } else if(pageNumInt) { await downloadBtn(getAlbumPageVideoPromise(number, pageNumInt)); } else { await downloadBtn(getAlbumVideoPromise(number)); } } else { if(updateNumInt) { await downloadBtn(getUidUpdateVideoPromise(number, updateNumInt)); } else if(pageNumInt) { await downloadBtn(getUidPageVideoPromise(number, pageNumInt)); } else { const parentChannel = document.getElementById('parentChannel'); const parentChannelId = parseInt(parentChannel.value); const channel = document.getElementById(`channel_${parentChannelId}`); const channelId = parseInt(channel.value); if(parentChannelId || channelId) { await downloadBtn(getFilterUidVideoPromise(number)); } else { await downloadBtn(getUidVideoPromise(number)); } } } } } replaceText('title', 'm3u8链接下载'); waitElement('.errimg').then(function() { const errimg =document.querySelector('.errimg'); errimg.remove(); }); waitElement('.err-box').then(function() { const reasonNode =document.querySelector('.reason'); reasonNode.remove(); const errBoxNode =document.querySelector('.err-box'); addChildDiv(errBoxNode, `<div class="reason fl"> <h3>m3u8链接下载</h3> <div class="tabs"> <div class="tab-links"> <a href="#tab1" class="active">视频&番剧</a> <a href="#tab2">用户&合辑</a> <a href="#tab3">免责声明</a> </div> <div class="tab-content"> <div id="tab1" class="tab active"> <span style="font-size: medium;padding-bottom: 1px;border-bottom: 2px solid #26B963;" id="acaaDesc"><a javascript:void(0);>使用说明</a></span> <div style="padding-top: 10px"> <label>下载单个</label><input type="radio" id="downOne" name="downType" value="downOne"> <label>下载全部</label><input type="radio" id="downAll" name="downType" value="downAll" checked> </div> <p class="p2">请输入AC号或番剧号:</p> <div> <input type="text" name="acaaNumber" placeholder="ac123或aa456" id="acaaNum" style="margin-right: 5px;"><button id="acaaDownloadBtn">下载链接文件</button> </div> <div> </div> <div id="acaaDescDiv" style=" display: none; position: fixed; top: 45%; left: 50%; transform: translate(-50%, -50%); background-color: white; padding: 20px; border: 1px solid black;"> <div> <span style="padding: 10px 0 5px 0;font-size: 15px;"> <a href="https://github.com/nilaoda/N_m3u8DL-CLI/releases" target="_blank"><span style="color: rgb(38, 185, 99);">【N_m3u8DL-CLI】</span>视频下载工具地址</a> </span> </div> <div> <span style="padding: 10px 0 5px 0;font-size: 15px;"> <a href="https://nilaoda.github.io/N_m3u8DL-CLI/SimpleGUI" target="_blank"><span style="color: rgb(38, 185, 99);">【N_m3u8DL-CLI】</span>视频下载工具使用说明</a> </span> </div> <br/> <p>下载的m3u8链接会失效,请尽快使用。失效后可以重新下载新的m3u8链接</p> <br/> <p>【下载全部】</p> <p>视频举例:</p> <p>ac号:ac1234567;p1:ac1234567_1;p2:ac1234567_2</p> <p>以上3个号码填入其中一个都会下载全部分P的视频信息</p> <p>番剧举例:</p> <p>A番第1季番剧号:aa1234567;第1话:ac1234567_XXX_01;第2话:ac1234567_XXX_02</p> <p>A番第2季番剧号:aa4567123;第1话:ac4567123_XXX_01;第2话:ac4567123_XXX_02</p> <p>以上6个号码填入其中一个都会下载A番剧全部两季的视频信息</p> <br/> <p>【下载单个】</p> <p>视频举例:</p> <p>填入ac号:ac1234567,下载p1的视频信息</p> <p>填入ac号:ac1234567_1,下载p1的视频信息</p> <p>填入ac号:ac1234567_2,下载p2的视频信息</p> <p>番剧举例:</p> <p>填入番剧号:aa1234567,如果有登录并且之前观看到第2话,则下载第2话的视频信息;如果之前并未观看,则下载第1话的视频信息</p> <p>填入番剧号:aa1234567,如果没有登录,则下载第1话的视频信息</p> <p>填入番剧号第1话:ac1234567_XXX_01,则下载第1话的视频信息</p> <p>填入番剧号第2话:ac4567123_XXX_02,则下载第2话的视频信息</p> </div> </div> <div id="tab2" class="tab"> <span style="font-size: medium;padding-bottom: 1px;border-bottom: 2px solid #26B963;" id="uidaaDesc"><a javascript:void(0);>使用说明</a></span> <div style="padding-top: 10px"> <span class="p2">更新稿件的数量:</span> <input type="number" name="uidaaUpdateNumer" step="1" min="0" max="100" id="uidaaUpdateNum" style="margin-right: 5px;text-align: right;" value="0"> </div> <div style="padding-top: 10px"> <span class="p2">稿件列表的页次:</span> <input type="number" name="uidaaListPage" step="1" min="0" max="999" id="uidaaListPage" style="margin-right: 5px;text-align: right;" value="0"> </div> <div style="padding-top: 10px"> <span class="p2">用户稿件分区:</span> <select name="parentChannel" id="parentChannel"> <option value="0">请选择</option> <option value="1">动画</option> <option value="58">音乐</option> <option value="123">舞蹈·偶像</option> <option value="59">游戏</option> <option value="60">娱乐</option> <option value="201">生活</option> <option value="70">科技</option> <option value="68">影视</option> <option value="69">体育</option> <option value="125">鱼塘</option> </select> </div> <div style="padding-top: 10px"> <span class="p2">用户稿件子分区:</span> <select name="channel_0" id="channel_0"> <option value="0">请选择</option> </select> <select name="channel_1" id="channel_1" style="display: none;"> <option value="0">请选择</option> <option value="190">短片·手书·配音</option> <option value="99">特摄</option> <option value="133">COSPLAY·声优</option> <option value="159">动画资讯</option> <option value="207">虚拟偶像</option> <option value="108">MMD·3D</option> <option value="107">MAD·AMV</option> <option value="106">动画综合</option> <option value="212">番剧二创</option> </select> <select name="channel_58" id="channel_58" style="display: none;"> <option value="0">请选择</option> <option value="215">治愈系</option> <option value="103">Vocaloid</option> <option value="136">原创·翻唱</option> <option value="137">演奏·乐器</option> <option value="139">综合音乐</option> <option value="185">音乐选集·电台</option> </select> <select name="channel_123" id="channel_123" style="display: none;"> <option value="0">请选择</option> <option value="218">颜值</option> <option value="129">偶像</option> <option value="134">宅舞</option> <option value="135">综合舞蹈</option> <option value="208">中国舞</option> </select> <select name="channel_59" id="channel_59" style="display: none;"> <option value="0">请选择</option> <option value="214">王者荣耀</option> <option value="216">和平精英</option> <option value="85">英雄联盟</option> <option value="210">我的世界</option> <option value="187">手机游戏</option> <option value="217">第五人格</option> <option value="145">电子竞技</option> <option value="186">网络游戏</option> <option value="84">主机单机</option> <option value="165">桌游卡牌</option> </select> <select name="channel_60" id="channel_60" style="display: none;"> <option value="0">请选择</option> <option value="87">鬼畜</option> <option value="188">明星</option> <option value="206">搞笑</option> </select> <select name="channel_201" id="channel_201" style="display: none;"> <option value="0">请选择</option> <option value="86>"生活日常</option> <option value="88>"萌宠</option> <option value="89>"美食</option> <option value="204>"旅行</option> <option value="205>"美妆·造型</option> <option value="127>"手工·绘画</option> </select> <select name="channel_70" id="channel_70" style="display: none;"> <option value="0">请选择</option> <option value="209">手办模玩</option> <option value="90">科技制造</option> <option value="91">数码家电</option> <option value="122">汽车</option> <option value="149">广告</option> <option value="151">演讲·公开课</option> <option value="189">人文科普</option> </select> <select name="channel_68" id="channel_68" style="display: none;"> <option value="0">请选择</option> <option value="219">影视混剪</option> <option value="192">预告·花絮</option> <option value="193">电影杂谈</option> <option value="194">追剧社</option> <option value="195">综艺Show</option> <option value="196">纪录片·短片</option> </select> <select name="channel_69" id="channel_69" style="display: none;"> <option value="0">请选择</option> <option value="93">极限·竞速</option> <option value="94">足球</option> <option value="95">篮球</option> <option value="152">综合体育</option> <option value="153">搏击·健身</option> </select> <select name="channel_125" id="channel_125" style="display: none;"> <option value="0">请选择</option> <option value="132">新鲜事</option> <option value="131">历史</option> <option value="92">国防军事</option> <option value="183">普法安全</option> </select> </div> <p class="p2">请输入UID或合辑号:</p> <div> <input type="text" name="uidaaNumber" placeholder="1234或aa789" id="uidaaNum" style="margin-right: 5px;"><button id="uidaaDownloadBtn">下载链接文件</button> </div> <div> </div> <div id="uidaaDescDiv" style=" display: none; position: fixed; top: 45%; left: 50%; transform: translate(-50%, -50%); background-color: white; padding: 20px; border: 1px solid black;"> <div> <span style="padding: 10px 0 5px 0;font-size: 15px;"> <a href="https://github.com/nilaoda/N_m3u8DL-CLI/releases" target="_blank"><span style="color: rgb(38, 185, 99);">【N_m3u8DL-CLI】</span>视频下载工具地址</a> </span> </div> <div> <span style="padding: 10px 0 5px 0;font-size: 15px;"> <a href="https://nilaoda.github.io/N_m3u8DL-CLI/SimpleGUI" target="_blank"><span style="color: rgb(38, 185, 99);">【N_m3u8DL-CLI】</span>视频下载工具使用说明</a> </span> </div> <br/> <p>下载的m3u8链接会失效,请尽快使用。失效后可以重新下载新的m3u8链接</p> <br/> <p>3个条件之间互不关联。优先级:【更新视频的数量】 > 【稿件列表的页次】 > 【用户稿件(子)分区】</p> <br/> <p>【更新视频的数量】</p> <p>更新视频的数量最大不能超过100</p> <p>举例:</p> <p>如果更新视频的数量为0,则下载用户或合辑全部稿件的视频信息</p> <p>如果更新视频的数量为2,则下载用户或合辑前2个稿件的视频信息</p> <p>如果更新视频的数量为5,则下载用户或合辑前5个稿件的视频信息</p> <br/> <p>【稿件列表的页次】</p> <p>下载用户或合辑稿件列表中的某一页</p> <p>举例:</p> <p>如果稿件列表的页次为0,则下载用户或合辑全部稿件的视频信息</p> <p>如果稿件列表的页次为2,则下载用户或合辑稿件列表中第2页的全部稿件的视频信息</p> <p>如果稿件列表的页次为5,则下载用户或合辑稿件列表中第5页的全部稿件的视频信息</p> <br/> <p>【用户稿件(子)分区】</p> <p style="color: red;">此过滤条件需要在油猴弹出的提示页面中点击允许外部链接,否则无法使用</p> <p style="color: red;">外部链接域名为:api-ipv6.app.acfun.cn,请认真对照清楚再允许</p> <p style="color: red;">如果在提示页面上点错或者超时未允许,可以备份此脚本再删除,然后重新安装,后续提示页面会重新弹出</p> <p style="color: red;">下载用户稿件所属分区的稿件,只对用户有效,合辑不生效</p> <p>举例:</p> <p>如果不选择(子)分区,则下载用户全部稿件的视频信息</p> <p>如果只选择【动画】分区,则下载用户【动画】分区的全部稿件的视频信息</p> <p>如果选择【动画综合】子分区,则下载用户【动画综合】子分区的全部稿件的视频信息</p> </div> </div> <div id="tab3" class="tab"> <p>本脚本不提供下载视频功能,只是解析下载m3u8地址。</p> <p>后续使用m3u8地址下载的视频版权归视频所有者所有,除非视频所有者同意,否则下载的视频仅限作离线播放用途。</p> <p>任何未经授权的剪辑和再发布等行为均为侵犯版权的行为,请尊重创作者的劳动成果。</p> <p>本脚本作者对下载者本人因使用此脚本下载m3u8地址,后续使用m3u8地址下载视频后剪辑、再发布等任何侵权行而产生的法律纠纷概不负责。</p> </div> </div> </div> <p class="p2" id="tips"></p> <style> .tabs .tab-links a { padding: 10px; text-decoration: none; color: #000; background: #eee; border: 1px solid #ddd; display: inline-block; } .tabs .tab-links a.active { background: #fff; border-bottom: none; } .tabs .tab-content .tab { display: none; padding: 10px; border: 1px solid #ddd; } .tabs .tab-content .tab.active { display: block; } </style> </div>` ); }); waitElement('#acaaDownloadBtn').then(function() { const btn = document.getElementById('acaaDownloadBtn'); btn.addEventListener('click', () => { window.downloadLink(); }); }); waitElement('#uidaaDownloadBtn').then(function() { const btn = document.getElementById('uidaaDownloadBtn'); btn.addEventListener('click', () => { window.downloadUidArubamuLink(); }); }); waitElement('#acaaDesc').then(function() { const div = document.getElementById('acaaDesc'); div.addEventListener('click', () => { const div2 = document.getElementById('acaaDescDiv'); if(div2.style.display === 'block') { div2.style.display = 'none'; } else { div2.style.display = 'block'; } }); }); waitElement('#acaaDesc').then(function() { document.addEventListener('click', function(event) { var isClickInside = document.getElementById('acaaDescDiv').contains(event.target) || document.getElementById('acaaDesc').contains(event.target); if (!isClickInside) { const div2 = document.getElementById('acaaDescDiv'); div2.style.display = 'none'; } }); }); waitElement('#uidaaDesc').then(function() { const div = document.getElementById('uidaaDesc'); div.addEventListener('click', () => { const div2 = document.getElementById('uidaaDescDiv'); if(div2.style.display === 'block') { div2.style.display = 'none'; } else { div2.style.display = 'block'; } }); }); waitElement('#uidaaDesc').then(function() { document.addEventListener('click', function(event) { var isClickInside = document.getElementById('uidaaDescDiv').contains(event.target) || document.getElementById('uidaaDesc').contains(event.target); if (!isClickInside) { const div2 = document.getElementById('uidaaDescDiv'); div2.style.display = 'none'; } }); }); waitElement('.tab-links').then(function() { var tabs = document.querySelectorAll('.tab-links a'); var contentDivs = document.querySelectorAll('.tab-content .tab'); tabs.forEach(function(tab) { tab.addEventListener('click', function(e) { e.preventDefault(); var target = document.querySelector(this.getAttribute('href')); tabs.forEach(function(t) { t.classList.remove('active'); }); contentDivs.forEach(function(c) { c.classList.remove('active'); }); this.classList.add('active'); target.classList.add('active'); }); }); }); waitElement('#parentChannel').then(function() { let selectElement = document.getElementById('parentChannel'); let previousValue = selectElement.value; selectElement.addEventListener('change', function() { let currentValue = this.value; let preChildSelectElement = document.getElementById(`channel_${previousValue}`); preChildSelectElement.style.display = 'none'; let currChildSelectElement = document.getElementById(`channel_${currentValue}`); currChildSelectElement.style.display = ''; previousValue = currentValue; }); });