Duoshuo Admin

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

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, Greasemonkey alebo Violentmonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey, % alebo Violentmonkey.

Na nainštalovanie skriptu si budete musieť nainštalovať rozšírenie, ako napríklad Tampermonkey alebo Userscripts.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie, ako napríklad Tampermonkey.

Na inštaláciu tohto skriptu je potrebné nainštalovať rozšírenie správcu používateľských skriptov.

(Už mám správcu používateľských skriptov, nechajte ma ho nainštalovať!)

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie, ako napríklad Stylus.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

Na inštaláciu tohto štýlu je potrebné nainštalovať rozšírenie správcu používateľských štýlov.

(Už mám správcu používateľských štýlov, nechajte ma ho nainštalovať!)

// ==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();
			}
		});
});