Duoshuo Admin

更加强大的多说评论管理脚本,可以自动分析所有有评论的页面,方便地修改thread_key,避免评论丢失。

目前为 2015-04-12 提交的版本。查看 最新版本

// ==UserScript==
// @name Duoshuo Admin
// @name:zh-CN 多说评论管理
// @namespace http://gerald.top
// @author Gerald <[email protected]>
// @description 更加强大的多说评论管理脚本,可以自动分析所有有评论的页面,方便地修改thread_key,避免评论丢失。
// @version 0.1
// @match http://*.duoshuo.com/admin/*
// @grant none
// ==/UserScript==

var threads;
try {
	threads=JSON.parse(localStorage.threadData);
} catch(e) {
	threads=[];
}
function save(){
	localStorage.threadData=JSON.stringify(threads);
}

$('<style>')
.html('\
.dsa-popup{background:white;position:fixed;top:70px;right:70px;padding:10px;border-radius:5px;box-shadow:1px 2px 5px gray;}\
.dsa-dialog{background:white;position:absolute;top:50px;right:500px;width:400px;z-index:10;box-shadow:4px 4px 5px gray;border:1px solid gray;padding:10px;border-radius:10px;}\
.dsa-dialog h4{color:purple;}\
.dsa-panel{background:white;position:fixed;top:50px;right:0;bottom:0;width:500px;box-shadow:-2px 0 5px gray;}\
.dsa-panel .area{position:absolute;top:30px;left:10px;right:10px;bottom:10px;overflow:auto;}\
.dsa-panel table{width:100%;border-spacing:5px;border-collapse:separate;}\
.dsa-panel td>*{padding:5px;}\
.dsa-panel .key{cursor:pointer;}\
.dsa-panel .key:hover{background:purple;color:white;}\
').appendTo(document.head);

var menu=$('<ul class="dropdown-menu">')
.appendTo(
	$('<li class="dropdown">')
	.prependTo('.navbar-nav')
	.html('<a href class="dropdown-toggle" data-toggle="dropdown">评论管理<b class="caret"></b>')
);

var notice=$('<div class="dsa-dialog">').appendTo(document.body).hide()
.css({
	right:300,
	width:500,
}).html('\
<h3>多说评论管理脚本使用须知</h3>\
<h4>为什么要有这个脚本?</h4>\
<p>因为多说自己的管理界面很多bug而且官方似乎不打算改进了的样子。使用这个脚本可以将所有评论对应的页面提取出来,避免修改过程中有遗漏导致评论丢失的情况。</p>\
<h4>什么是自动分析评论?</h4>\
<p>脚本将自动分析该站点下所有的评论,将所有有评论的页面提取并保存下来,然后可以通过显示文章列表看到,并方便地对页面的thread_key进行管理和修改。</p>\
<h4>如何操作比较好?</h4>\
<p>先使用此脚本修改thread_key,然后修改网站页面的thread_key。(这样可以避免网站页面修改后、多说旧thread_key修改前,多说自动生成为新thread_key生成对应的新thread的问题。这么拗口不知道能不能看明白。。)</p>\
<h4>为什么有时候修改thread_key会失败?</h4>\
<p>首先要知道,多说的文章管理中,对文章的删除其实并不是真正的删除,<b>只是隐藏而已</b>,所以如果一篇被“删除”的文章占用了你想修改的thread_key,那么修改就会失败,这时需要先把旧的被“删除”的文章改一个其他的(没用的)thread_key,然后再改现在这个才能成功。</p>\
<p>如果在使用脚本修改thread_key时失败,脚本会自动弹出旧的thread让你修改。将旧的thread改成一个没用的thread_key再来改当前thread就没有问题了。</p>\
');
$('<a href>关闭</a>').prependTo(notice).css('float','right').click(function(e){
	e.preventDefault();
	notice.hide();
});
$('<a href>使用须知</a>')
.appendTo($('<li>').appendTo(menu))
.click(function(e){
	e.preventDefault();
	notice.show();
});

function getThreadByKey(key,cb){
	$.get('/api/threads/listPosts.json',{
		thread_key:key,
		limit:1
	},function(r){
		cb(r.thread);
	});
}
function updateKey(id,key,cb){
	$.post('/api/threads/update.json',{
		thread_id:id,
		thread_key:key,
	},function(r){
		cb(r.response);
	});
}
function editKey(e){
	var cur=$(e.target);
	var i=cur.data('num');
	var thread=threads[i];
	if(!thread) return;
	current=cur;
	editPanel.current.threadKey.val(thread.thread_key);
	editPanel.current.find('.title').html($('<a target=_blank>').attr('href',thread.url).text(thread.title));
	editPanel.other.hide();
	editPanel.show();
}
function saveKey(e){
	var i=current.data('num');
	var thread=threads[i];
	if(!thread) return;
	updateKey(thread.thread_id,editPanel.current.threadKey.val(),function(r){
		if(r){
			threads[i]=r;
			current.text(r.thread_key);
			closeEdit();
		} else {
			getThreadByKey(editPanel.current.threadKey.val(),function(r){
				var other=editPanel.other;
				other.data('id',r.thread_id);
				other.threadKey.val(r.thread_key);
				other.find('.title').html($('<a target=_blank>').attr('href',r.url).text(r.title));
				editPanel.current.find('.msg').html('您要使用的thread_key被以下thread占用,请先修改之。');
				other.show();
			});
		}
	});
}
function saveOtherKey(e){
	var other=editPanel.other;
	updateKey(other.data('id'),other.threadKey.val(),function(r){
		if(r){
			editPanel.current.find('.msg').html('占用thread已修改,可以继续修改当前thread。');
			other.hide();
		} else {
			other.find('.msg').html('thread_key修改失败,请换一个thread_key试试。');
		}
	});
}
function closeEdit(e){
	if(e) e.preventDefault();
	current=null;
	editPanel.fadeOut();
}
var current=null;
var editPanel=$('<div class="dsa-dialog">').appendTo(document.body).hide()
.html('\
<h3>修改Thread</h3>\
<div class=current>\
<h4>thread_key</h4>\
<div><input type=text class=thread-key style="width:100%"></div>\
<h4>title</h4>\
<p class=title></p>\
<button class="btn btn-primary save">修改</button>\
<span class=msg></span>\
</div><div class=other><hr>\
<h3>占用此thread_key的Thread</h3>\
<h4>thread_key</h4>\
<div><input type=text class=thread-key style="width:100%"></div>\
<h4>title</h4>\
<p class=title></p>\
<button class="btn btn-primary save">修改</button>\
<span class="msg"></span>\
</div>\
');
editPanel.current=editPanel.find('.current');
editPanel.current.threadKey=editPanel.current.find('.thread-key');
editPanel.current.find('.save').click(saveKey);
editPanel.other=editPanel.find('.other');
editPanel.other.threadKey=editPanel.other.find('.thread-key');
editPanel.other.find('.save').click(saveOtherKey);
$('<a href>关闭</a>').prependTo(editPanel).css('float','right').click(closeEdit);
var panel=$('<div class="dsa-panel">').appendTo(document.body).hide();
$('<a href>关闭</a>').appendTo(panel).css({
	position:'absolute',
	top:10,
	right:20,
}).click(function(e){
	e.preventDefault();
	panel.hide();
});
panel.area=$('<div class="area">').appendTo(panel);
$('<a href>显示文章列表</a>')
.appendTo($('<li>').appendTo(menu))
.click(function(e){
	e.preventDefault();
	panel.area.html('');
	var table=$('<table>').appendTo(panel.area);
	$('<tr><th>thread_key</th><th>title</th></tr>').appendTo(table);
	$.each(threads,function(i,o){
		var row=$('<tr>').appendTo(table);
		$('<span class="key">').data('num',i).text(o.thread_key).appendTo($('<td>').appendTo(row)).click(editKey);
		$('<a target=_blank>').attr('href',o.url).text(o.title).appendTo($('<td>').appendTo(row));
	});
	panel.show();
});

$('<a href>自动分析评论</a>')
.appendTo($('<li>').appendTo(menu))
.click(function(e){
	e.preventDefault();
	var dthreads={};
	var limit=100,n=Math.ceil(DUOSHUO.site.comments/limit),i;
	var finished=0;
	var popup=$('<div class="dsa-popup">').html('正在分析评论:<span></span>/'+n).appendTo(document.body);
	var prog=popup.find('span').html(finished);
	for(i=0;i<n;i++)
		$.get('/api/posts/list.json',{
			order:'desc',
			source:'duoshuo,repost',
			max_depth:1,
			limit:limit,
			'related[]':'thread',
			nonce:DUOSHUO.nonce,
			status:'all',
			page:i+1,
		},function(r){
			$.each(r.response,function(i,p){
				var t=p.thread;
				dthreads[t.thread_id]=t;
			});
			prog.html(++finished);
			if(finished==n) {
				popup.html('评论分析完成!');
				popup.fadeOut(5000,function(){
					popup.remove();
				});
				threads=[];
				for(var i in dthreads) threads.push(dthreads[i]);
				threads.sort(function(a,b){return a.thread_id>b.thread_id;});
				save();
			}
		});
});

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址