// ==UserScript==
// @name Youtube直播在线人数记录
// @namespace http://tampermonkey.net/
// @namespace https://github.com/artyyin/YoutubeLiveOnline
// @version 0.41
// @description 绘制直播过程中的在线人数变化曲线,支持下载数据或图片
// @author [email protected]
// @match https://www.youtube.com/watch?v=*
// @require https://code.jquery.com/jquery-1.11.3.min.js
// @require https://code.highcharts.com/highcharts.js
// @require https://code.highcharts.com/modules/series-label.js
// @require https://code.highcharts.com/modules/exporting.js
// @require https://code.highcharts.com/modules/offline-exporting.js
// @require https://code.highcharts.com/modules/export-data.js
// @grant GM_getValue
// @grant GM_setValue
// @grant GM_deleteValue
// @grant GM_listValues
// ==/UserScript==
(function() {
//'use strict';
var mainkey ="monkey-youtube-number-online-123456789"
var prefixofdatakey='artyyby-';
var debug_switch = false;
var onlinedata =new Array()
var hisdata;
var HistroyVisible=true;
var chart;
var aq_interval=5*1000;
var n=0;
var datakey ;
var testdata = [
[new Date(2018,7,16,23,49,4).getTime(),7296]
];
var timer_2;
//deleteAllKeys();
//listAllKeys();
reset()
setTimeout(delay_init, 5*1000);
function reset()
{
if(timer_2!=undefined)
{
clearTimeout(timer_2)
timer_2=undefined
}
if(chart!=undefined)
{
$("#online_chartwin").remove()
chart=undefined
}
onlinedata =new Array()
hisdata=undefined
HistroyVisible=true
n=0;
datakey=undefined
testdata = [
[new Date(2018,7,16,23,49,4).getTime(),7296]
];
}
function delay_init()
{
if($('button.ytp-live-badge.ytp-button').length==0)
{
setTimeout(delay_init, 5*1000);
console.log('wait 5s , retry to find button');
return;
}
if($('button.ytp-live-badge.ytp-button').is(":visible")==false)
{
//alert("no live")
n+=1;
if(n<=4)
{
setTimeout(delay_init, 5*1000);
console.log('wait 5s , retry to live state');
}
else
{
console.log('not live stream, exit');
}
return
}
datakey = ceateAndAddKey();
add_chart_winnode()
showchartwin()
timer_2 = setTimeout(onTimer_2, aq_interval);
}
function add_chart_winnode()
{
var windivnode =$('<div id="online_chartwin"></div>')
windivnode.css({
/*希望窗口有边框*/
'border': '1px #0769ad solid',
/*希望窗口宽度和高度固定,不要太大*/
//'width': '500px',
//'height': '300px',
/*希望控制窗口的位置*/
//'position': 'absolute',
//'top': '100px',
//'left': '350px',
/*希望窗口开始时不可见*/
'display': 'none'
});
var titledivnode = $('<div id="online_charttitle">在线人数记录</div>')
titledivnode.css({
/*控制标题栏的背景色*/
'background-color': '#7cB5EC',
/*控制标题栏中文字的颜色*/
'color': 'white',
/*控制标题栏的左内边距*/
'padding-left':'3px'
})
var closebuttonnode = $('<span id="online_chartclose">[X]</span>')
closebuttonnode.css({
/*使关闭按钮向右侧移动*/
//'position':'relative',
'margin-right': '5px',
//'right':'-10px',
'float':'right',
/*让鼠标进入时可以显示小手,告知用户可以点击操作*/
'cursor': 'pointer'
})
closebuttonnode.click(onbuttonclick)
var contentdivnode = $('<div id="online_chartcontent">窗口</div>')
contentdivnode.css({
'padding-left': '3px',
'padding-top': '5px'
})
windivnode.append(titledivnode)
windivnode.append(contentdivnode)
titledivnode.append(closebuttonnode)
$("#meta-contents").after(windivnode)
addChart()
}
function addChart()
{
var dafaultMenuItem = Highcharts.getOptions().exporting.buttons.contextButton.menuItems;
var myMenuItem=[
{
separator: true
},
{
text:'隐藏历史数据',
onclick:hideHistoryData
},
{
text:'显示历史数据',
onclick:showHistoryData
},
{
text: '清除历史数据',
onclick:clearCurrentPageKey
},
{
text: '清除所有历史数据',
onclick:clearAppKeys//deleteAllKeys
}
]
dafaultMenuItem.pop();
dafaultMenuItem.pop();
myMenuItem = dafaultMenuItem.concat(myMenuItem);
//console.log(myMenuItem);
Highcharts.setOptions({
global: {
useUTC: false
}
});
//console.log('addChart')
chart = Highcharts.chart('online_chartcontent', {
chart: {
//type: 'scatter',
plotBorderWidth: 1,
zoomType: 'x'
},
title: {
text: 'youtube直播在线人数--'+$('#text > a').text()//document.title.substring(0,50)//'在线人数--youtube直播'
},
subtitle: {
useHTML:true,
text:getSubTitle()
},
xAxis: {
dateTimeLabelFormats: {
millisecond: '%H:%M:%S.%L',
second: '%H:%M:%S',
minute: '%H:%M',
hour: '%H:%M',
day: '%Y-%m-%d',
week: '%m-%d',
month: '%Y-%m',
year: '%Y'
},
title: {
text: '时间'
},
type: 'datetime'
},
yAxis: {
//min:0,
title: {
text: '人数'
}
},
legend:{enabled:false},
tooltip: {
headerFormat: '<b>时间:{point.x:%Y-%m-%d %H:%M:%S}</b><br>',
pointFormat : '<b>人数: {point.y:.0f} 人</b>'
},
plotOptions: {
line:{
lineWidth : 2,
marker: {radius:3}
}
},
exporting: {
buttons: {
contextButton: {
menuItems:myMenuItem
}
}
},
series: [{
name: '在线人数',
type: 'line',
data: testdata
}]
});
//console.log('addCHart() end')
hisdata = loadHistoryData();
if(hisdata.length>0)
{
var tmp=[]
tmp = tmp.concat(hisdata)
chart.series[0].setData(tmp)
}
else
{
chart.series[0].removePoint(0);
}
//console.log(chart.options.exporting.buttons.contextButton.menuItems)
}
function getSubTitle()
{
var s = $('#container > h1 > yt-formatted-string').text();
if(s.length>50)
{
s = s.substring(0,30)+' ... '+s.substring(s.length-15);
}
return '<p align="center">'+s+'</p>'
}
function onbuttonclick()
{
var winNode = $("#online_chartcontent");
if(winNode.is(":hidden"))
{
//winNode.show();
winNode.fadeIn("slow");
}
else
{
//winNode.hide();
winNode.fadeOut("slow");
}
}
//显示曲线窗口
function showchartwin() {
//lert("准备显示弹出窗口啦!!!");
//1.找到窗口对应的div节点
var winNode = $("#online_chartwin");
//2.让div对应的窗口显示出来
//方法1,修改节点的css值,让窗口显示出来
//winNode.css("display","block");
//方法2,利用Jqeury的show方法
//winNode.show("slow");
//方法3,利用JQuery的fadeIn方法
winNode.fadeIn("slow");
}
//定时采集数据
function onTimer_2()
{
var point = getNumberOfOnline()
var idx = onlinedata.length;
chart.series[0].addPoint(point, true, false);
//activeLastPointToolip(chart);
onlinedata[idx] = point
GM_setValue(datakey,onlinedata);
timer_2 = setTimeout(onTimer_2, aq_interval);
}
function activeLastPointToolip(chart) {
var points = chart.series[0].points;
chart.tooltip.refresh(points[points.length -1]);
}
function getTestData()
{
var currentdate = new Date().getTime();
var numofonline =5000+700*Math.sin(onlinedata.length/3.14) + Math.floor(Math.random()*700+1)
var result =new Array()
result[0]=currentdate
result[1]=numofonline
if(debug_switch)
{
var datestr = result[0]
var logmsg = datestr+" | "+result[1]
console.log(logmsg);
}
return result
}
//采集在线人数
function getNumberOfOnline()
{
let currentdate = (new Date()).getTime();
//var elm = $("div[id=info-text]>div[id=count]>ytd-video-view-count-renderer>span:first-child")
let elm = $("div[id=info-container]>yt-formatted-string[id=info]>span:first-child")
let numtext = elm.text()
let numstr=/[0-9,]+/.exec(numtext).toString();
let numofonline =parseInt(numstr.replace(',',''));
if(debug_switch)
{
let logmsg = currentdate+" | "+numofonline+" | "+ numtext
console.log(logmsg);
}
let result =new Array()
result[0]=currentdate
result[1]=numofonline
return result
}
function listAllKeys()
{
var allkey = GM_listValues();
for (var idx in allkey)
{
var data = GM_getValue(allkey[idx]);
console.log(idx,allkey[idx]);
console.log(data);
}
}
function deleteAllKeys()
{
var allkey = GM_listValues();
for (var idx in allkey)
{
GM_deleteValue(allkey[idx]);
}
}
function clearAppKeys()
{
var allurl = GM_getValue(mainkey,[]);
for (var u in allurl)
{
var url = allurl[u];
var alldatakey = GM_getValue(url,[])
for(var d in alldatakey)
{
GM_deleteValue(alldatakey[d])
}
GM_deleteValue(url)
}
GM_getValue(mainkey)
var allkey = GM_listValues();
for (var idx in allkey)
{
if(allkey[idx].indexOf(prefixofdatakey)==0)
{
GM_deleteValue(allkey[idx]);
}
}
}
function clearCurrentPageKey()
{
var alldatakey = GM_getValue(document.URL,[]);
for(var d in alldatakey)
{
GM_deleteValue(alldatakey[d])
}
}
function ceateAndAddKey()
{
var allurl = GM_getValue(mainkey,[])
var url = document.URL;
if(!allurl.includes(url))
{
allurl[allurl.length] = url
GM_setValue(mainkey,allurl)
}
var idx = url.indexOf('?v=')
var timestr = new Date().toLocaleString();
var dkey = prefixofdatakey+url.substring(idx+3)+timestr
var keyarray = GM_getValue(url,[])
keyarray[keyarray.length]=dkey
GM_setValue(url,keyarray)
return dkey
}
function loadHistoryData()
{
var url = document.URL;
var alldatakey = GM_getValue(url)
var result=[];
for(var i in alldatakey)
{
var cur_data = GM_getValue(alldatakey[i]);
if(cur_data!=undefined)
{
result = result.concat(cur_data);
}
}
return result;
}
function hideHistoryData()
{
if(HistroyVisible)
{
//alert(HistroyVisible)
var data=[];
console.log('hideHistoryData 0:', data.length, hisdata.length, onlinedata.length)
data = data.concat(onlinedata)
console.log('hideHistoryData 1:', data.length, hisdata.length, onlinedata.length)
chart.series [0].setData(data)//,true,new Highcharts.AnimationOptions({duration:1000}));
console.log('hideHistoryData 2:', data.length, hisdata.length, onlinedata.length)
//console.log(data)
HistroyVisible = false;
}
}
function showHistoryData()
{
if(!HistroyVisible)
{
clearTimeout(timer_2)
var tmp=[];
//console.log('showHistoryData 0:',tmp.length, hisdata.length, onlinedata.length)
tmp = tmp.concat(hisdata)
tmp = tmp.concat(onlinedata)
//console.log('showHistoryData 1:',tmp.length, hisdata.length, onlinedata.length)
//chart.series[0].setData([ [new Date(1970,1,1).getTime(),7296] ],false)
chart.series[0].setData(tmp)
timer_2 = setTimeout(onTimer_2, aq_interval);
HistroyVisible = true;
}
}
function getAbsoluteUrl(url){
var a = document.createElement('A');
a.href = url; // 设置相对路径给Image, 此时会发送出请求
url = a.href; // 此时相对路径已经变成绝对路径
return url;
}
})();