您需要先安装一个扩展,例如 篡改猴、Greasemonkey 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 暴力猴,之后才能安装此脚本。
您需要先安装一个扩展,例如 篡改猴 或 Userscripts ,之后才能安装此脚本。
您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey,才能安装此脚本。
您需要先安装用户脚本管理器扩展后才能安装此脚本。
让Google页面中的币值历史走线图可以拨放音乐并显示视觉化 没有任何实际有用的功能
当前为
// ==UserScript== // @name Google Music Visualization // @name:zh-TW Google 音樂視覺化 // @name:zh-CN Google 音乐视觉化 // @namespace https://github.com/maplelan/Maplelan_Tampermonkey_Script/blob/main/Google%20%E8%A6%96%E8%A6%BA%E5%8C%96.user.js // @version 1.0 // @description Let Google's currency historical chart in the webpage to play music and display visualizations, unuseful tool. // @description:zh-TW 讓Google頁面中的幣值歷史走線圖可以撥放音樂並顯示視覺化 沒有任何實際有用的功能 // @description:zh-CN 让Google页面中的币值历史走线图可以拨放音乐并显示视觉化 没有任何实际有用的功能 // @author Maplelan // @license MIT // @match https://www.google.com/search?q=* // @icon https://www.google.com/s2/favicons?sz=64&domain=google.com // @grant none // ==/UserScript== (function() { setTimeout(()=>{ let svg = document.getElementsByClassName("uch-psvg"); console.log(svg); for(let i=0;i<svg.length;i++){ let svg_item = svg[i]; let path = svg_item.getElementsByTagName("path"); if(path.length >= 2){ let main_path = path[1]; let vb = svg_item.getAttribute("viewBox").split(" "); let vb_w = parseFloat(vb[2]),vb_h = parseFloat(vb[3]); let d = main_path.getAttribute("d"); let L = d.split("L"); let header = {},content = [],end = []; for(let j=0;j<L.length;j++){ if(L[j].startsWith("M")){ let M = L[j].trim().split(" "); header.x = parseFloat(M[1]); header.y = parseFloat(M[2]); }else{ let C = L[j].trim().split(" "); let item = {}; item.x = parseFloat(C[0]); item.y = parseFloat(C[1]); if(item.x <= vb_w && item.x >= 0){ content.push(item); }else{ end.push(item); } } } console.log(d); let top = svg_item.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode; let btpos = top.firstChild.firstChild; let numb_place = top.parentNode.firstChild.firstChild.lastChild.firstChild; const or_num = parseFloat(numb_place.innerText); console.log(or_num); console.log(btpos); const file = document.createElement('input'); file.type = "file"; file.accept="audio/*"; btpos.append(file); const audio = document.createElement('audio'); audio.controls = true;; btpos.append(audio); const select = document.createElement('select'); select.innerHTML = `<option value="FloatFrequency">FloatFrequency</option> <option value="FloatTimeDomain">FloatTimeDomain</option> <option value="ByteFrequency">ByteFrequency</option> <option value="ByteTimeDomain">ByteTimeDomain</option>`; btpos.append(select); let aniID = null; file.onchange = function() { console.log("file"); if(aniID != null){ cancelAnimationFrame(aniID); } let files = this.files; audio.src = URL.createObjectURL(files[0]); audio.load(); audio.play(); let vis_type = "FloatFrequency"; let context = new AudioContext(); let src = context.createMediaElementSource(audio); let analyser = context.createAnalyser(); src.connect(analyser); analyser.connect(context.destination); console.log(select.value); vis_type = select.value; switch(vis_type){ case "FloatFrequency":{ analyser.fftSize = 2048; break; } case "ByteFrequency":{ analyser.fftSize = 128; break; } case "FloatTimeDomain": case "ByteTimeDomain":{ analyser.fftSize = 8192; break; } } let bufferLength = analyser.frequencyBinCount; console.log(bufferLength); let dataArray = new Uint8Array(bufferLength); switch(vis_type){ case "FloatFrequency": case "FloatTimeDomain":{ dataArray = new Float32Array(bufferLength); break; } case "ByteFrequency": case "ByteTimeDomain":{ dataArray = new Uint8Array(bufferLength); break; } } function renderFrame() { requestAnimationFrame(renderFrame); let start = 0,to_end = bufferLength; switch(vis_type){ case "FloatFrequency":{ analyser.getFloatFrequencyData(dataArray); break; } case "FloatTimeDomain":{ analyser.getFloatTimeDomainData(dataArray); start = 512; to_end = bufferLength-start; break; } case "ByteFrequency":{ analyser.getByteFrequencyData(dataArray); break; } case "ByteTimeDomain":{ analyser.getByteTimeDomainData(dataArray); start = 1024; to_end = bufferLength-start; break; } } //console.log(dataArray); let evn = 0,a_max,a_min; let H,C=[]; for (let i = start; i < to_end; i++) { let barHeight = dataArray[i]; let item = {}; item.x = map_range(i,start,to_end-1,0,vb_w); //console.log(i + " " + item.x); switch(vis_type){ case "FloatFrequency":{ item.y = vb_h - map_range(barHeight,-170,-10,0,vb_h); break; } case "FloatTimeDomain":{ const v = dataArray[i] * 50; item.y = (vb_h / 2) + v; break; } case "ByteFrequency":{ item.y = vb_h - map_range(barHeight,0,255,0,vb_h); break; } case "ByteTimeDomain":{ const v = dataArray[i] / 128.0; item.y = vb_h - (v * (vb_h / 2)); break; } } evn += barHeight; if(i==start){ H = item; a_max = dataArray[i]; a_min = dataArray[i]; }else{ C.push(item); if(dataArray[i] > a_max){ a_max = dataArray[i]; } if(dataArray[i] < a_min){ a_min = dataArray[i]; } } } switch(vis_type){ case "ByteFrequency": case "ByteTimeDomain":{ evn = (evn/(to_end-start))/255; a_max = a_max - 128; a_min = a_min - 128; break; } case "FloatFrequency": case "FloatTimeDomain":{ evn = map_range(evn/(to_end-start),-150,-30,0,100); a_max = a_max - ((a_max+a_min)/2); a_min = a_min - ((a_max+a_min)/2); break; } } let svg_r = document.getElementsByClassName("uch-psvg"); for(let i_r=0;i_r<svg_r.length;i_r++){ let svg_item_r = svg_r[i_r]; let path_r = svg_item_r.getElementsByTagName("path"); if(path_r.length >= 2){ let main_path_r = path_r[1]; main_path_r.setAttribute("d",merg(H,C,end)); let top_r = svg_item_r.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode.parentNode; let numb_place_r = top_r.parentNode.firstChild.firstChild.lastChild.firstChild; const max = parseFloat(svg_item_r.parentNode.parentNode.firstChild.childNodes[2].lastChild.textContent); const min = parseFloat(svg_item_r.parentNode.parentNode.firstChild.firstChild.lastChild.textContent); //console.log(max); let range = 0; switch(vis_type){ case "FloatFrequency":{ range = (evn*(max-min)); break; } case "FloatTimeDomain":{ range = (((Math.abs(a_max) > Math.abs(a_min)) ? a_max : a_min)*(max-min))*8; break; } case "ByteFrequency":{ range = (evn*100*(max-min))*0.7; break; } case "ByteTimeDomain":{ range = (((Math.abs(a_max) > Math.abs(a_min)) ? a_max : a_min)*(max-min))*0.1; break; } } numb_place_r.textContent = (or_num+range).toFixed(2); //console.log((or_num+range).toFixed(2)); } } } audio.play(); aniID = window.requestAnimationFrame(renderFrame()); }; //console.log(header); //console.log(content); //console.log(end); //randC(header,content,vb_h); /*setTimeout(()=>{ console.log(merg(header,content,end)); main_path.setAttribute("d",merg(header,content,end)); }, 3000);*/ } } }, 1000); })(); function merg(H,C,E){ let str = "M " + xystr(H); C.forEach(item => { str += " L " + xystr(item); }); E.forEach(item => { str += " L " + xystr(item); }); return str; } function xystr(xy){ return xy.x + " " + xy.y; } function randC(H,C,max){ H.y = random(0,max,2); for(let i=0;i<C.length;i++){ C[i].y = random(0,max,2); } } function random(min, max, dec = 0){//隨機函式 min=最小值 max=最大值 dec=小數點後的位數(預設為0) let usedec = Math.pow(10, dec); let maxc = Math.floor(max * usedec); let minc = min < max ? Math.floor(min * usedec) : 0; return (Math.floor(Math.random() * (maxc - minc + 1)) + minc) / usedec; } function map_range(value, low1, high1, low2, high2) { if(value < low1){ return low2; } return low2 + (high2 - low2) * (value - low1) / (high1 - low1); }