Duoshuo Admin

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

Bu betiği kurabilmeniz için Tampermonkey, Greasemonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

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

Bu betiği kurabilmeniz için Tampermonkey ya da Violentmonkey gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği kurabilmeniz için Tampermonkey ya da Userscripts gibi bir kullanıcı betiği eklentisini kurmanız gerekmektedir.

Bu betiği indirebilmeniz için ayrıca Tampermonkey gibi bir eklenti kurmanız gerekmektedir.

Bu komut dosyasını yüklemek için bir kullanıcı komut dosyası yöneticisi uzantısı yüklemeniz gerekecek.

(Zaten bir kullanıcı komut dosyası yöneticim var, kurmama izin verin!)

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install an extension such as Stylus to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

You will need to install a user style manager extension to install this style.

(Zateb bir user-style yöneticim var, yükleyeyim!)

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