Duoshuo Admin

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

Terá de instalar uma extensão como Tampermonkey, Greasemonkey ou Violentmonkey para instalar este script.

You will need to install an extension such as Tampermonkey or Violentmonkey to install this script.

Terá de instalar uma extensão como Tampermonkey ou Violentmonkey para instalar este script.

Terá de instalar uma extensão como Tampermonkey ou Userscripts para instalar este script.

Terá de instalar uma extensão como Tampermonkey para instalar este script.

Terá de instalar uma extensão de gestão de scripts de utilizador para instalar este script.

(Já tenho um gestor de scripts de utilizador, deixe-me instalá-lo!)

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão como Stylus para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

Terá de instalar uma extensão de gestão de estilos de utilizador para instalar este estilo.

(Já tenho um gestor de estilos de utilizador, deixe-me instalá-lo!)

// ==UserScript==
// @name Duoshuo Admin
// @name:zh-CN 多说评论管理
// @namespace http://gerald.top
// @homepage https://gerald.top/code/DuoshuoAdmin
// @author Gerald <[email protected]>
// @icon	http://cn.gravatar.com/avatar/a0ad718d86d21262ccd6ff271ece08a3?s=80
// @description 更加强大的多说评论管理脚本,可以自动分析所有有评论的页面,方便地修改thread_key,避免评论丢失。
// @version 0.3
// @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:3px;box-shadow:0 0 5px rgba(0,0,0,.1);}
.dsa-dialog{background:white;position:absolute;top:50px;right:600px;width:400px;z-index:10;box-shadow:0 0 5px rgba(0,0,0,.1);border:1px solid gray;padding:10px;border-radius:3px;}
.dsa-dialog label{display:block;}
.dsa-dialog input[type=text],.dsa-dialog input[type=url]{display:block;width:100%;}
.dsa-panel{background:white;position:fixed;top:50px;right:0;bottom:0;width:600px;box-shadow:-2px 0 5px gray;}
.dsa-panel-body{position:absolute;top:30px;left:10px;right:10px;bottom:10px;overflow:auto;}
.dsa-panel table{width:100%;border-spacing:5px;border-collapse:separate;table-layout:fixed;}
.dsa-panel td>*{padding:5px;}
.dsa-panel .key{cursor:pointer;}
.dsa-panel .key:hover{background:olive;color:white;}
`)
.appendTo(document.head);

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

$('<li><a href="https://gerald.top/code/DuoshuoAdmin" target=_blank>使用须知</a></li>')
.appendTo(menu);

function EditPanel(thread) {
	this.thread = thread;
	[
		'onSubmit',
		'onClose',
		'onVisitURL',
		'onSolveConflict',
	].forEach(key => {
		this[key] = this[key].bind(this);
	});
	this.dialog = $('<form class="dsa-dialog">').appendTo(document.body)
	.html(`
	<h3>修改Thread</h3>
	<label>
		thread_key:
		<input type=text data-id=thread_key>
	</label>
	<label>
		title:
		<input type=text data-id=title>
	</label>
	<label>
		url: <a href="#" data-id=visit_url>[Go]</a>
		<input type=url data-id=url>
	</label>
	<label>
		<input type=checkbox data-id=post_enable>
		post_enable
	</label>
	<button class="btn btn-primary" type="submit">保存</button>
	<button class="btn btn-default" type="button" data-id=cancel>关闭</button>
	<button class="btn btn-default" data-id=conflict style="display:none">修改冲突</button>
	<div data-id=msg></div>
	`)
	.submit(this.onSubmit)
	.on('click', '[data-id=visit_url]', this.onVisitURL)
	.on('click', '[data-id=cancel]', this.onClose)
	.on('click', '[data-id=conflict]', this.onSolveConflict)
	;
	this.find('thread_key').val(thread.thread_key);
	this.find('title').val(thread.title);
	this.find('url').val(thread.url);
	this.find('post_enable').prop('checked', thread.post_enable);
}
EditPanel.panels = {};
EditPanel.open = function (thread) {
	var panel = EditPanel.panels[thread.thread_id];
	if (!panel) {
		panel = EditPanel.panels[thread.thread_id] = new EditPanel(thread);
	}
	panel.dialog.appendTo(document.body);
	return panel;
};
EditPanel.prototype.find = function (key) {
	return this.dialog.find(`[data-id=${JSON.stringify(key)}]`);
};
EditPanel.prototype.onSubmit = function (e) {
	e.preventDefault();
	$.post('/api/threads/update.json', {
		thread_id: this.thread.thread_id,
		thread_key: this.find('thread_key').val(),
		title: this.find('title').val(),
		url: this.find('url').val(),
		post_enable: this.find('post_enable').prop('checked') ? 1 : 0,
	}, r => {
		const thread = r.response;
		if (thread) {
			this.thread = thread;
			const i = threads.findIndex(_thread => _thread.thread_id === thread.thread_id);
			if (~i) threads[i] = thread;
			save();
			this.find('msg').html('修改成功!');
		} else {
			this.find('msg').html('<span style="color:red">修改失败!</span>');
			const conflict = this.find('conflict').show();
			this.find('thread_key').one('change', () => conflict.hide());
		}
	});
};
EditPanel.prototype.onVisitURL = function (e) {
	window.open(this.find('url').val());
};
EditPanel.prototype.onSolveConflict = function (e) {
	$.get('/api/threads/listPosts.json', {
		thread_key: this.find('thread_key').val(),
		limit: 1,
	}, r => {
		EditPanel.open(r.thread);
	});
};
EditPanel.prototype.onClose = function (e) {
	this.dialog.remove();
};

function getThreadByKey(key, cb) {
}
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="dsa-panel-body">').appendTo(panel);
$('<a href>显示文章列表</a>')
.appendTo($('<li>').appendTo(menu))
.click(function(e){
	e.preventDefault();
	panel.area.html('');
	var table=$('<table>').appendTo(panel.area);
	$('<colgroup><col width=100><col width=200><col></colgroup>').appendTo(table);
	$('<tr><th>thread_key</th><th>title</th><th>url</th></tr>').appendTo(table);
	threads.forEach(thread => {
		const row = $('<tr>').appendTo(table);
		$('<span class="key">')
		.text(thread.thread_key)
		.click(() => EditPanel.open(thread))
		.wrap('<td>').parent().appendTo(row);
		$('<td>').text(thread.title).appendTo(row);
		$('<a target=_blank>')
		.attr('href', thread.url)
		.text(thread.url)
		.wrap('<td>').parent().appendTo(row);
	});
	panel.show();
});

$('<a href>自动分析评论</a>')
.appendTo($('<li>').appendTo(menu))
.click(function(e){
	e.preventDefault();
	var dthreads={};
	var limit=100,n=~~(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();
			}
		});
});