Initial commit
Some checks failed
定时更新GitHub源插件 / 自动更新GitHub插件 (push) Has been cancelled

This commit is contained in:
chorblack
2026-03-07 11:19:25 +08:00
commit e75f275ef4
4484 changed files with 645480 additions and 0 deletions

381
CSDN/Plugin.php Normal file
View File

@@ -0,0 +1,381 @@
<?php
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
/**
* CSDN博客导入插件
* @author MDY
* @package CSDN
* @version 1.0.0
* @license GNU General Public License 2.0
*/
class CSDN_Plugin extends Widget_Abstract_Contents implements Typecho_Plugin_Interface
{
//爬虫的header
protected static $context;
//文章id的正则
protected static $r_article_id = '/^https\:\/\/blog\.csdn\.net\/.+\/article\/details\//';
//文章链接的正则
protected static $r_article;
//博客列表的地址
protected static $source_url;
//博客的地址
protected static $article_url;
/**
* 启用插件方法,如果启用失败,直接抛出异常
*
* @static
* @access public
* @return void
*/
public static function activate()
{
// TODO: Implement activate() method.
Typecho_Plugin::factory('admin/menu.php')->navBar = array('CSDN_Plugin', 'render');
Typecho_Plugin::factory('admin/menu.php')->navBar = array('CSDN_Plugin', 'header');
Helper::addRoute('get-articles-id', '/get-articles-id', 'CSDN_Plugin', 'get_articles_id');
Helper::addRoute('add-article', '/add-article', 'CSDN_Plugin', 'add_article');
}
/**
* 禁用插件方法,如果禁用失败,直接抛出异常
*
* @static
* @access public
* @return void
*/
public static function deactivate()
{
// TODO: Implement deactivate() method.
Helper::removeRoute('get-articles-id');
Helper::removeRoute('add-article');
}
/**
* 获取插件配置面板
*
* @static
* @access public
* @param Typecho_Widget_Helper_Form $form 配置面板
* @return void
*/
public static function config(Typecho_Widget_Helper_Form $form)
{
// TODO: Implement config() method.
$UserName = new Typecho_Widget_Helper_Form_Element_Text('UserName', NULL, '', _t('UserName(在浏览器开发者模式下csdn的网站找到这个cookie下同)'));
$UserToken = new Typecho_Widget_Helper_Form_Element_Text('UserToken', NULL, '', _t('UserToken'));
$UserInfo = new Typecho_Widget_Helper_Form_Element_Text('UserInfo', NULL, '', _t('UserInfo'));
$form->addInput($UserName);
$form->addInput($UserToken);
$form->addInput($UserInfo);
}
/**
* 个人用户的配置面板
*
* @access public
* @param Typecho_Widget_Helper_Form $form
* @return void
*/
public static function personalConfig(Typecho_Widget_Helper_Form $form)
{
// TODO: Implement personalConfig() method.
}
/**
* 插件实现方法
*
* @access public
* @return void
*/
public static function render()
{
echo '<a href="#" onclick="add_post();return false;" style="color: #ff0007">点击导入博文'
. '</a>';
}
/**
* 添加文章
*/
public function add_article()
{
header('Content-Type:text/json;charset=utf-8');
//得到config的输入框的值
$csdn = Helper::options()->plugin('CSDN');
$username = $csdn->UserName;
$usertoken = $csdn->UserToken;
$userinfo = $csdn->UserInfo;
//初始化cookie
CSDN_Plugin::$context = CSDN_Plugin::init_header($username, $userinfo, $usertoken);
$aid = $_POST['aid'];
$date = $_POST['date'];
try {
$result = CSDN_Plugin::get_post_info($aid, $date);
if (gettype($result) == 'array') {
//数据库获取
$db = Typecho_Db::get();
$user = Typecho_Widget::widget('Widget_User');
$user->execute();
$userId = $user->uid;
$result['post']['allowComment'] = "1";
$result['post']['allowPing'] = "1";
$result['post']['allowFeed'] = "1";
$result['post']['authorId'] = $userId;
$result['post']['slug'] = $result['post']['cid'];
//文章是否存在
$temp = $db->fetchRow($db->select('cid')
->from('table.contents')
->where('table.contents.cid = ?', $result['post']['cid'])->limit(1));
if ($temp) {
$update = $db->update('table.contents')->rows($result['post'])->where('table.contents.cid = ?', $result['post']['cid'])->limit(1);
$db->query($update);
} else {
$insert = $db->insert('table.contents')
->rows($result['post']);
$db->query($insert);
}
//插入tag
Widget_Abstract_Comments::widget('Widget_Contents_Post_Edit')->setTags($result["post"]["cid"], $result['tags']);
//插入分类得到分类id
foreach ($result['categories'] as &$category) {
$t = $db->fetchRow($db->select('table.metas.mid')
->from('table.metas')->where('name <=> ? and type <=> ?', $category, 'category')->limit(1));
if (!$t) {
$options['name'] = $category;
$options['slug'] = $category;
$options['type'] = 'category';
$options['order'] = 0;
$category = $db->query($db->insert('table.metas')->rows($options));
} else {
$category = $t['mid'];
}
}
Widget_Abstract_Comments::widget('Widget_Contents_Post_Edit')->setCategories($result["post"]["cid"], $result['categories']);
$str = array('msg' => "success", 'code' => 1, 'data' => $aid);
} else {
if ($result != null) {
$str = array('msg' => $result . "(如果是没有操作权限请查看是否为cookie错误或者过期)", 'code' => 0, 'data' => $aid);
} else {
$str = array('msg' => "result is null", 'code' => 0, 'data' => $aid);
@error_log(json_encode($result));
}
}
} catch (Error $e) {
$str = array('msg' => $e->getMessage(), 'code' => 0, 'data' => $aid);
} catch (Typecho_Exception $e) {
$str = array('msg' => $e->getMessage(), 'code' => 0, 'data' => $aid);
} catch (Exception $e) {
$str = array('msg' => $e->getMessage(), 'code' => 0, 'data' => $aid);
}
//返回json数据
$json = json_encode($str);
echo $json;
}
/**
* 添加文章id列表
* @throws Typecho_Exception
* @throws Typecho_Plugin_Exception
*/
public function get_articles_id()
{
header('Content-Type:text/json;charset=utf-8');
$user = Typecho_Widget::widget('Widget_User');
if (!$user->pass('administrator', false)) {
return;
}
$user->execute();
//得到config的输入框的值
$csdn = Helper::options()->plugin('CSDN');
$username = $csdn->UserName;
$usertoken = $csdn->UserToken;
$userinfo = $csdn->UserInfo;
if ($username == null || $usertoken == null || $userinfo == null) {
$str = array('msg' => '请在设置界面填写所需参数', 'code' => 0);
//返回json数据
$jsonencode = json_encode($str);
echo $jsonencode;
return;
}
//初始化cookie
CSDN_Plugin::$context = CSDN_Plugin::init_header($username, $userinfo, $usertoken);
//得到文章链接的正则
CSDN_Plugin::$r_article = '/https\:\/\/blog\.csdn\.net\/' . $username . '\/article\/details\/[0-9]+/';
//得到文章id的正则
CSDN_Plugin::$source_url = "https://blog.csdn.net/$username/phoenix/article/list/";
CSDN_Plugin::$article_url = "https://blog.csdn.net/$username/article/details/";
//博客页面页数
$i = 1;
$str = null;
$a_list = array();
do {
$content = file_get_contents(CSDN_Plugin::$source_url . $i);
// $json = CSDN_Plugin::decodeUnicode($content);
$json = json_decode($content, true);
if ($json['status'] == 1) {
$article_list = $json['data']['article_list'];
//取得页数
$page_num = ceil($json['data']['total'] / 20);
foreach ($article_list as $article) {
$a_list = array_merge($a_list, array(array($article['ArticleId'], $article['PostTime'])));
}
$i += 1;
} else {
$str = array('msg' => '用户不存在或者网络不好', 'code' => 0);
break;
}
} while ($page_num >= $i);
//返回博客id的列表
if (!$str) {
$str = array('data' => $a_list, 'code' => 1);
}
//返回json数据
$jsonencode = json_encode($str);
echo $jsonencode;
}
/**
* 得到要输入数据库中的文章信息
* @param $aid
* @param $date
* @return array 文章的信息
*/
function get_post_info($aid, $date)
{
//得到日期
$create_date = strtotime($date);
//获取markdown格式的字符串
$content = file_get_contents("https://blog-console-api.csdn.net/v1/editor/getArticle?id=$aid", false, CSDN_Plugin::$context);
$json = json_decode($content, true);
//解析
if (strcmp($json["msg"], "success") == 0) {
$description = $json["data"]["description"];
$markdown = '<!--markdown-->' . $description . '<!--more-->' . $json["data"]["markdowncontent"];
$title = $json["data"]["title"];
$categories = $json['data']['categories'];
str_replace('', ',', $categories);
$categories = array_unique(array_map('trim', explode(',', $categories)));
$tags = $json['data']['tags'];
$post = array('title' => $title, 'type' => 'post', 'cid' => $aid, 'text' => $markdown, 'created' => $create_date, 'modified' => time());
return array('post' => $post, "tags" => $tags, "categories" => $categories, "description" => $description);
} else {
return $json['msg'];
}
}
/**
* 用到的js和css
*
* @access public
* @return void
*/
public
static function header()
{
$Path = Helper::options()->pluginUrl . '/CSDN/';
echo '<link rel="stylesheet" type="text/css" href="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.css" />';
echo '<link rel="stylesheet" type="text/css" href="' . $Path . 'css/my_bar.css"/>' . "\n\r";;
echo '<script src="https://cdnjs.cloudflare.com/ajax/libs/nanobar/0.4.2/nanobar.min.js" integrity="sha512-1Al+dnfE+1gI7IBmpUZ8XnZ3l3Nv6cyA+XgdtlaptVNxJcWWRzHxOPzT+2pbp52qtXa2jkwk0MWYSmxslMsHCQ==" crossorigin="anonymous"></script>' . "\n\r";
echo '<script type="text/javascript" src="' . $Path . 'js/add_post.js"></script>' . "\n\r";
echo '<script type="text/javascript" src="https://cdn.bootcss.com/jquery/3.3.1/jquery.min.js"></script>' . "\n\r";
echo '<script type="text/javascript" src="https://cdnjs.cloudflare.com/ajax/libs/toastr.js/latest/toastr.min.js"></script>' . "\n\r";
}
/**
* 初始化header
* @param $username
* @param $userinfo
* @param $usertoken
* @return resource
*/
static function init_header($username, $userinfo, $usertoken)
{
$cookie = "UserName=$username;UserInfo=$userinfo;UserToken=$usertoken;";
$opts = array(
'http' => array(
'method' => "GET",
'header' => "Accept-language: en\r\n" .
"Cookie:" . $cookie . "\r\n"
)
);
return stream_context_create($opts);
}
/**
* unicode解码
* @param $str
* @return null|string|string[]
*/
static function decodeUnicode($str)
{
$callbacks[$str] = function ($matches) use ($str) {
return iconv("UCS-2BE", "UTF-8", pack("H*", $matches[1]));
};
return preg_replace_callback('/\\\\u([0-9a-f]{4})/i', $callbacks[$str], $str);
}
// 失败
// function publish($result)
// {
// //填充文章的相关字段信息。
// $contents =
// array(
// 'title' => $result["post"]["title"],
// 'text' => $result["post"]["title"],
// 'fieldNames' => array(),
// 'fieldTypes' => array(),
// 'fieldValues' => array(),
// 'cid' => '',
// 'do' => 'publish',
// 'markdown' => '1',
// 'date' => $result["post"]["data"],
// 'category' => array($result["post"]["categories"]),
// 'tags' => $result["post"]["tags"],
// 'visibility' => 'publish',
// 'password' => '',
// 'allowComment' => '1',
// 'allowPing' => '1',
// 'allowFeed' => '1',
// 'trackback' => '',
// );
//
// $request = Typecho_Request::getInstance();
// //设置token绕过安全限制
// $security = Typecho_Widget::widget('Widget_Security');
// $request->setParam('_', $security->getToken($this->request->getReferer()));
// $request->setParams($contents);
// //设置时区否则文章的发布时间会查8H
// date_default_timezone_set('PRC');
//
// //执行添加文章操作
// $widgetName = 'Widget_Contents_Post_Edit';
// $reflectionWidget = new ReflectionClass($widgetName);
// if ($reflectionWidget->implementsInterface('Widget_Interface_Do')) {
// Typecho_Widget::widget($widgetName)->action();
// return true;
// } else {
// return false;
// }
//
// }
}

42
CSDN/README.md Normal file
View File

@@ -0,0 +1,42 @@
# Typecho_Plugin_CSDN
Typecho插件--将CSDN的博文迁移进Typecho
---
## 使用说明
1. 需要到自己已经登录的CSDN下的任意一个网页使用开发者模式将三个cookieUserNameUserInfoUserToekn拷贝下来粘贴进插件配置文本框中
2. 点击导入即可
----
## 可能遇到的问题的解决方法
1. PHP版本最好7以上。。。
2. 记得装完整php的插件像是xml什么的
3. 如果你使用的是nginx代理那么可能会出现php的pathinfo报404即点击了上面的导入报404错误可尝试下面的配置
```
if (!-e $request_filename) {
rewrite ^(.*)$ /index.php$1 last;
}
location ~ .*\.php(\/.*)*$ {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
fastcgi_pass localhost:9000;
set $path_info "";
set $real_script_name $fastcgi_script_name;
if ($fastcgi_script_name ~ "^(.+?\.php)(/.+)$") {
set $real_script_name $1;
set $path_info $2;
}
fastcgi_param SCRIPT_NAME $real_script_name;
fastcgi_param PATH_INFO $path_info;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
```

13
CSDN/css/my_bar.css Normal file
View File

@@ -0,0 +1,13 @@
.nanobar {
width: 100%;
height: 6px;
z-index: 9999;
top: 0
}
.bar {
width: 0;
height: 100%;
transition: height .3s;
background: #59d
}

88
CSDN/js/add_post.js Normal file
View File

@@ -0,0 +1,88 @@
const nanoBar = new Nanobar();
function add_post() {
function error(XMLHttpRequest, textStatus, errorThrown) {
toastr.error('出现未知异常 ' + errorThrown + '可以使用开发者模式查看改请求add-post的reponse确认出错信息')
}
function beforeSend() {
toastr.options = {
"closeButton": true,
"newestOnTop": true,
"positionClass": "toast-top-center",
"preventDuplicates": false,
"onclick": null,
// "showDuration": "0",
"hideDuration": "0",
"timeOut": "0",
"extendedTimeOut": "0",
"showEasing": "swing",
"hideEasing": "linear",
"showMethod": "fadeIn",
"hideMethod": "fadeOut"
}
toastr.info('正在导入数据中,请耐心等待,不要离开当前页面,如果文章太多,将会需要很长一段时间,。。。')
}
function get_list() {
return new Promise((resolve) => {
$.ajax(
{
type: "GET",//通常会用到两种GET,POST。默认是GET
url: "../get-articles-id",//(默认: 当前页地址) 发送请求的地址
dataType: "json",//预期服务器返回的数据类型。
beforeSend: beforeSend, //发送请求
success: function (msg) {
if (msg.code !== 1) {
toastr.remove()
toastr.error('发生了错误:' + msg.msg)
} else {
resolve(msg)
}
}, //请求成功
error: error,//请求出错
});
})
}
get_list().then(function (data) {
if (data.code === 1) {
total = data.data.length
data.data.some((e, index) => {
aid = e[0]
date = e[1]
$.ajax(
{
type: "POST",//通常会用到两种GET,POST。默认是GET
url: "../add-article",//(默认: 当前页地址) 发送请求的地址
dataType: "json",//预期服务器返回的数据类型。
data: {
'aid': aid,
'date': date,
},
// async: false,
success: function (msg) {
let temp;
if (msg.code == 1) {
temp = (index + 1) / total * 100
nanoBar.go(temp)
if (temp == 100) {
toastr.remove()
toastr.info('导入完成')
}
} else {
toastr.error('发生了错误:' + msg.msg)
}
}, //请求成功
error: error,//请求出错
});
})
} else {
toastr.remove()
toastr.error(data.msg)
}
})
}