// ==UserScript==
// @name acfun统计
// @description acfun统计(目前只包含送出礼物和收到礼物的统计)
// @namespace syachiku
// @author syachiku
// @match https://www.acfun.cn/member*
// @run-at document-end
// @grant GM_addStyle
// @grant GM_xmlhttpRequest
// @version 0.0.1
// @require https://cdnjs.cloudflare.com/ajax/libs/qs/6.9.4/qs.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.20/lodash.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.29.1/moment.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js
// @require https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.14.1/index.min.js
// @downloadURL none
// ==/UserScript==
;(async function(){
Vue.use(ELEMENT);
Vue.prototype.$message = ELEMENT.Message;
const config = {
ACFUN_SERVER : 'https://www.acfun.cn',
ACFUN_MOBILE_SERVER : 'https://m.acfun.cn',
ACFUNLIVE_SERVER : 'https://live.acfun.cn',
URLS : {
ACFUN_USER : {
INFO : '/rest/pc-direct/user/userInfo',
SPACE : '/u'
},
WALLET : {
SEND_GIFT : '/rest/apph5-direct/pay/reward/giveRecords',
RECEIVE_GIFT : '/rest/apph5-direct/pay/reward/receiveRecords',
}
},
};
// 是否为空
function isNullOrEmpty(val){
return _.isUndefined(val) || _.isNull(val) || _.isNaN(val) || (((_.isObject(val) && !_.isDate(val)) || _.isArray(val) || _.isString(val)) && _.isEmpty(val))
}
// 通用请求
function commonRequrest(url, method, form, raw, callback, headers){
var isSuccess = false;
var data = null;
if(!headers){
headers = {};
}
if(!raw){
if(method == 'post'){
headers['Content-Type'] = 'application/x-www-form-urlencoded';
if(form){
form = Qs.stringify(form);
}
}
}
if(method == 'get' && form){
form = Qs.stringify(form);
url += '?' + form;
}
// 获取了token
if(config.TOKEN){
headers['Authorization'] = `Token ${config.TOKEN}`;
}
GM_xmlhttpRequest({
synchronous : !_.isFunction(callback),
method : method,
url : url,
data : form,
headers : headers,
onload : function(res){
// 200
if(res.status==200){
if(raw){
callback(true, res.responseText);
}
else{
res = JSON.parse(res.responseText);
isSuccess = res[config.RESPONSE.FIELD.STATUS] == config.RESPONSE.STATUS.SUCCESS;
data = res[config.RESPONSE.FIELD.DATA];
if(_.isFunction(callback)){
callback(isSuccess, data);
}
}
}
else{
if(_.isFunction(callback)){
callback(isSuccess, data);
}
}
},
onerror : function(){
if(_.isFunction(callback)){
callback(isSuccess, data);
}
},
onabort : function(){
if(_.isFunction(callback)){
callback(isSuccess, data);
}
},
});
return [isSuccess, data];
}
function addCssResource(url){
commonRequrest(url, 'get', null, true, function(isSuccess, css){
if(isSuccess){
GM_addStyle(css);
}
})
}
// 添加element-ui样式
addCssResource('https://cdnjs.cloudflare.com/ajax/libs/element-ui/2.14.1/theme-chalk/index.min.css');
// 加载Vue实例
function loadVue(){
var vue = null;
// 容器
var navEle = document.querySelector('#list-guide-left');
// 添加导航选项
var navItem = document.createElement('div');
navItem.classList.add('part-guide-left');
navItem.innerHTML = `
`;
// 监听点击事件
navItem.addEventListener('click', function(){
// 修改展示内容
document.querySelector('#area-main-right').innerHTML = `
正在获取送出礼物记录。已获取{{totalSendGiftList.length}}条记录
正在获取收到礼物记录。已获取{{totalReceiveGiftList.length}}条记录
送出礼物价值{{send}}AC币
用户送出礼物价值的AC币总和
收到礼物价值{{receive}}钻石
用户收到礼物价值的钻石总和
{{switchToSendGiftList?'送出礼物详情':'收到礼物详情'}}
{{switchToSendGiftList?'切换至收到礼物详情':'切换至送出礼物详情'}}
{{userInfo[scope.row.userId].userName}}
{{userInfo[scope.row.userId].userName}}
提交
`;
history.replaceState(null, null, '/member/#area=acfunstat');
// 已初始化vue实例
if(vue){
return;
}
// 初始化实例
new Vue({
el : '#acfunstat-container',
data : function(){
return {
totalSend : 0,
totalReceive : 0,
send : 0,
receive : 0,
totalSendGiftList : [],
totalReceiveGiftList : [],
sendGiftList : [],
receiveGiftList : [],
sendUserList : [],
receiveUserList : [],
userInfo : {},
isGettingSendGiftList : false,
isGettingReceiveGiftList : false,
hasGetReceiveGiftList : false,
hasGetSendGiftList : false,
filterText : '',
settingFormDialogVisible : false,
settingFormData : {
isContainPeach : true,
},
settingFormRules : {
},
settingFormPickerOptions : {
shortcuts : [{
text : '本周',
onClick(picker) {
const end = moment().endOf('week').add(1, 'days')._d;
const start = moment().startOf('week').add(1, 'days')._d;
picker.$emit('pick', [start, end]);
},
},{
text : '上周',
onClick(picker) {
const end = moment().subtract(1, 'weeks').endOf('week').add(1, 'days')._d;
const start = moment().subtract(1, 'weeks').startOf('week').add(1, 'days')._d;
picker.$emit('pick', [start, end]);
},
},{
text : '本月',
onClick(picker) {
const end = moment().endOf('month')._d;
const start = moment().startOf('month')._d;
picker.$emit('pick', [start, end]);
},
},{
text : '上月',
onClick(picker) {
const end = moment().subtract(1, 'months').endOf('month')._d;
const start = moment().subtract(1, 'months').startOf('month')._d;
picker.$emit('pick', [start, end]);
},
},]
},
switchToSendGiftList : true,
};
},
methods : {
getUserInfo : function(uid, callback){
var vue = this;
if(uid in this.userInfo){
if(_.isFunction(callback)){
callback(true, this.userInfo[uid]);
}
return;
}
// 获取用户信息
commonRequrest(config.ACFUNLIVE_SERVER + config.URLS.ACFUN_USER.INFO + `?userId=${uid}`, 'get', null, true, function(isSuccess, data){
var userInfo = null;
if(data){
data = JSON.parse(data);
if(data.result == 0){
userInfo = {
uid : uid,
photo : data.profile.headUrl,
userName : data.profile.name,
};
}
}
vue.userInfo[uid] = userInfo;
if(_.isFunction(callback)){
callback(isSuccess, userInfo);
}
});
},
getSendGiftList : function(callback){
// 已经获取过礼物列表
if(this.hasGetSendGiftList){
if(_.isFunction(callback)){
callback();
}
return;
}
var vue = this;
// 获取数据时的游标
var pcursor = "0";
var getSendGiftList = function(){
vue.isGettingSendGiftList = true;
if(pcursor == 'no_more'){
// 统计送出礼物总ac币
vue.totalSend = _.sumBy(_.flatMap(vue.userInfo), 'totalSend');
vue.send = vue.totalSend;
// 讲用户按送出ac币价值倒序
vue.sendUserList = _.sortBy(_.filter(vue.userInfo, (userInfo)=>{return userInfo.totalSend>0;}), function(userInfo){
return -userInfo.totalSend;
});
vue.sendGiftList = vue.totalSendGiftList;
vue.isGettingSendGiftList = false;
vue.hasGetSendGiftList = true;
if(_.isFunction(callback)){
callback();
}
return;
}
else{
commonRequrest(config.ACFUN_MOBILE_SERVER + config.URLS.WALLET.SEND_GIFT, 'get',{pcursor : pcursor,},true,
function(isSuccess, data){
// 获取数据失败
if(!isSuccess){
vue.$message({
type : 'error',
message : '获取送出礼物列表失败',
});
pcursor = 'no_more';
return;
}
data = JSON.parse(data);
pcursor = data['pcursor'];
if(data.records){
var uids = {};
// 获取用户信息
data.records.forEach(function(record){
if(!(record.userId in uids)){
uids[record.userId] = [];
}
// 设置送出时间
record.createTimeText = moment(record.createTime).format('YYYY-MM-DD hh:mm:ss');
record.giftText = `${record.giftCount}个${record.giftName}`;
uids[record.userId].push(record);
vue.totalSendGiftList.push(record);
});
var nextGetSendGiftList = _.after(Object.keys(uids).length, getSendGiftList);
for(var uid in uids){
vue.getUserInfo(uid, function(isSuccess, userInfo){
// 无法获取用户信息
if(!isSuccess || userInfo==null){
return;
}
// 统计送出给用户AC币
if(userInfo.totalSendGiftList == null){
userInfo.totalSendGiftList = [];
userInfo.sendGiftList = [];
}
if(userInfo.totalSend==null){
userInfo.totalSend = 0;
userInfo.send = 0;
}
userInfo.totalSendGiftList.splice(userInfo.totalSendGiftList.length, 0, ...uids[userInfo.uid]);
userInfo.sendGiftList.splice(userInfo.sendGiftList.length, 0, ...uids[userInfo.uid]);
userInfo.totalSend += _.sumBy(uids[userInfo.uid], 'acoin');
userInfo.send = userInfo.totalSend;
nextGetSendGiftList();
});
}
}
else{
getSendGiftList();
}
},
);
}
}
getSendGiftList();
},
getReceiveGiftList : function(callback){
// 已经获取过礼物列表
if(this.hasGetReceiveGiftList){
if(_.isFunction(callback)){
callback();
}
return;
}
var vue = this;
// 获取数据时的游标
var pcursor = "0";
var getReceiveGiftList = function(){
vue.isGettingReceiveGiftList = true;
if(pcursor == 'no_more'){
// 统计送出礼物总ac币
vue.totalReceive = _.sumBy(_.flatMap(vue.userInfo), 'totalReceive');
vue.receive = vue.totalReceive;
// 讲用户按送出ac币价值倒序
vue.receiveUserList = _.sortBy(_.filter(vue.userInfo, (userInfo)=>{return userInfo.totalReceive>0;}), function(userInfo){
return -userInfo.totalReceive;
});
vue.receiveGiftList = vue.totalReceiveGiftList;
vue.isGettingReceiveGiftList = false;
vue.hasGetReceiveGiftList = true;
if(_.isFunction(callback)){
callback();
}
return;
}
else{
commonRequrest(config.ACFUN_MOBILE_SERVER + config.URLS.WALLET.RECEIVE_GIFT, 'get',{pcursor : pcursor,},true,
function(isSuccess, data){
// 获取数据失败
if(!isSuccess){
vue.$message({
type : 'error',
message : '获取送出礼物列表失败',
});
pcursor = 'no_more';
return;
}
data = JSON.parse(data);
pcursor = data['pcursor'];
if(data.records){
var uids = {};
// 获取用户信息
data.records.forEach(function(record){
if(!(record.userId in uids)){
uids[record.userId] = [];
}
record.createTimeText = moment(record.createTime).format('YYYY-MM-DD hh:mm:ss');
record.giftText = `${record.giftCount}个${record.giftName}`;
uids[record.userId].push(record);
vue.totalReceiveGiftList.push(record);
});
var nextGetReceiveGiftList = _.after(Object.keys(uids).length, getReceiveGiftList);
for(var uid in uids){
vue.getUserInfo(uid, function(isSuccess, userInfo){
// 无法获取用户信息
if(!isSuccess || userInfo==null){
return;
}
// 统计送出给用户AC币
if(userInfo.totalReceiveGiftList == null){
userInfo.totalReceiveGiftList = [];
userInfo.receiveGiftList = [];
}
if(userInfo.totalReceive==null){
userInfo.totalReceive = 0;
userInfo.receive = 0;
}
userInfo.totalReceiveGiftList.splice(userInfo.totalReceiveGiftList.length, 0, ...uids[userInfo.uid]);
userInfo.receiveGiftList.splice(userInfo.receiveGiftList.length, 0, ...uids[userInfo.uid]);
userInfo.totalReceive += _.sumBy(uids[userInfo.uid], 'azuanAmount');
userInfo.receive = userInfo.totalReceive;
nextGetReceiveGiftList();
});
}
}
else{
getReceiveGiftList();
}
},
);
}
}
getReceiveGiftList();
},
// 打开设置弹窗
openSettingDialog : function(){
this.settingFormDialogVisible = true;
},
// 更改设置提交
handleSettingFormSubmit : function(){
var vue = this;
this.$refs.settingForm.validate((valid) => {
// 通过校验
if(valid){
var startDate = null,endDate=null;
// 筛选了时间范围
if(this.settingFormData.dateRegion && this.settingFormData.dateRegion.length==2){
startDate = this.settingFormData.dateRegion[0].getTime();
endDate = this.settingFormData.dateRegion[1].getTime();
}
this.sendGiftList = _.filter(this.totalSendGiftList, function(record){
var flag = null;
// 指定了起始时间
if(startDate && record.createTimeendDate){
flag = false;
}
// 不包含桃子
else if(!vue.settingFormData.isContainPeach && record.giftName == '桃子'){
flag = false;
}
else{
flag = true;
}
record.flag = flag;
return flag;
});
this.receiveGiftList = _.filter(this.totalReceiveGiftList, function(record){
var flag = null;
// 指定了起始时间
if(startDate && record.createTimeendDate){
flag = false;
}
// 不包含桃子
else if(!vue.settingFormData.isContainPeach && record.giftName == '桃子'){
flag = false;
}
else{
flag = true;
}
record.flag = flag;
return flag;
});
// 重新计算收到礼物和送出礼物
for(uid in this.userInfo){
this.userInfo[uid].send = 0;
this.userInfo[uid].receive = 0;
this.userInfo[uid].sendGiftList = _.filter(this.userInfo[uid].totalSendGiftList, function(record){
if(record.flag){
vue.userInfo[uid].send += record.acoin;
}
return record.flag;
});
this.userInfo[uid].receiveGiftList = _.filter(this.userInfo[uid].totalReceiveGiftList, function(record){
if(record.flag){
vue.userInfo[uid].receive += record.azuanAmount;
}
return record.flag;
});
}
// 重新排名
// 统计送出礼物总ac币
this.send = _.sumBy(_.flatMap(this.userInfo), 'send');
// 讲用户按送出ac币价值倒序
this.sendUserList = _.sortBy(_.filter(this.userInfo, (userInfo)=>{return userInfo.send>0;}), function(userInfo){
return -userInfo.send;
});
// 统计收到礼物总ac币
this.receive = _.sumBy(_.flatMap(this.userInfo), 'receive');
// 讲用户按收到ac币价值倒序
this.receiveUserList = _.sortBy(_.filter(this.userInfo, (userInfo)=>{return userInfo.receive>0;}), function(userInfo){
return -userInfo.receive;
});
// 生成筛选文字
this.filterText = this.formatFilterText();
this.settingFormDialogVisible = false;
}
});
},
// 跳转至用户主页
toUserSpace : function(userInfo){
window.open(config.ACFUN_SERVER + config.URLS.ACFUN_USER.SPACE + `/${userInfo.uid}`);
},
formatFilterText : function(){
var dateRegionText = null,isContainPeachText=null;
// 筛选了时间范围
if(this.settingFormData.dateRegion && this.settingFormData.dateRegion.length==2){
dateRegionText = `${moment(this.settingFormData.dateRegion[0]).format('YYYY-MM-DD')} 至 ${moment(this.settingFormData.dateRegion[1]).format('YYYY-MM-DD')}`;
}
if(!this.settingFormData.isContainPeach){
isContainPeachText = '不包含桃子';
}
var texts = _.filter([dateRegionText, isContainPeachText]).join('、');
if(isNullOrEmpty(texts)){
return '';
}
else{
return '(' + texts + ')';
}
},
},
computed : {
},
mounted : function(){
var vue = this;
this.getSendGiftList(function(){
vue.getReceiveGiftList();
});
},
});
});
navEle.append(navItem);
return true;
}
window.onload = function(){
var intervalHandler = window.setInterval(function(){
if(loadVue()){
window.clearInterval(intervalHandler);
}
}, 500);
};
})();