Site icon 老张博客

typecho插件-MemosSync,Memos 同步插件

文章目录 「隐藏」
  1. 插件功能特点:
  2. 安装和使用说明
  3. 注意事项
  4. 插件结构

这款插件是我找deepseek写的,主要功能是把typecho发布的内容自动同步到Memos上。应该是绝大部分博主都用不上,各取所需吧!也是想说,AI成熟了,我们每位都是程序员,都可以让AI写出自己想要的功能的代码!

一直以来,除老张博客外,还有一个后花园,老张随笔。老张随笔就是每天记一些点滴,发一点牢骚!字数都是在一两百字,到目前为止,也记录了近一千五百篇日志了。老张随笔最初选用的是较轻量的Typecho程序,后来Memos在博客圈流行的时候,老张随笔便换成了Memos程序,这样能更好的和五木大佬开发的哔哔广场融合。Typecho数据导入到Memos数据库中也非常的简单,这篇《简单几步,Typecho博客文章轻松导入到Memos》教程,便可以教大家很方便的把Typecho的文章导入到Memos中。Memos也使用了两三年吧,但是由于作者的任性更新,版本一直还停留在0.18.1上。加之大家对Memos热度的减少,现在玩Memos的人很少了,原来五木大佬的哔哔广场,每天都好几十条哔文,现在基本上很少有人发了。种种原因,老张随笔又换回了Typecho程序,但是老张又舍不得Memos,所以在Typecho上发布一篇文章后,便手动复制到Memos上,也算是做为备份吧!每天手动甚是麻烦,便有了这款Typecho插件-MemosSync,Memos同步插件。

插件功能特点:

安装和使用说明

1.安装插件

将下面的文件上传到 /usr/plugins/MemosSync/ 目录

在Typecho后台启用插件

2.配置插件:

进入插件设置页面

填写Memos地址(例如:https://memos.example.com)

输入Access Token(在Memos设置中生成)

选择可见性设置

启用同步功能

3.获取Access Token:

登录您的Memos实例

进入设置 → 权限 → Access Tokens

生成新的Token并复制到插件设置中

注意事项

  1. 确保您的Typecho服务器可以访问Memos实例

  2. 如果同步失败,会在Typecho日志中记录错误信息

  3. 标签会自动过滤特殊字符,只保留字母、数字、中文和下划线

插件结构

/usr/plugins/MemosSync/

├── Plugin.php ├── config.xml └── form.php

1. config.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin>
<name>MemosSync</name>
<description>将Typecho文章同步到Memos</description>
<author>Your Name</author>
<version>1.0.0</version>
<module>MemosSync</module>
</plugin>

2. form.php

<?php if(!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
<h2>Memos 同步设置</h2>

<div class="typecho-page-title">
    <h2>Memos 配置</h2>
</div>

<div class="typecho-option">
    <label class="typecho-label" for="memos_url">Memos 地址</label>
    <input type="text" class="text" name="memos_url" id="memos_url" value="<?php $this->options->memos_url(); ?>" />
    <p class="description">请输入完整的Memos地址,例如:https://memos.example.com</p>
</div>

<div class="typecho-option">
    <label class="typecho-label" for="memos_token">Access Token</label>
    <input type="text" class="text" name="memos_token" id="memos_token" value="<?php $this->options->memos_token(); ?>" />
    <p class="description">在Memos设置中生成的Access Token</p>
</div>

<div class="typecho-option">
    <label class="typecho-label" for="memos_visibility">可见性</label>
    <select name="memos_visibility" id="memos_visibility">
        <option value="PUBLIC" <?php if($this->options->memos_visibility == 'PUBLIC') echo 'selected'; ?>>公开</option>
        <option value="PROTECTED" <?php if($this->options->memos_visibility == 'PROTECTED') echo 'selected'; ?>>受保护</option>
        <option value="PRIVATE" <?php if($this->options->memos_visibility == 'PRIVATE') echo 'selected'; ?>>私有</option>
    </select>
    <p class="description">选择同步到Memos的可见性设置</p>
</div>

<div class="typecho-option">
    <label class="typecho-label">
        <input type="checkbox" name="memos_enable_sync" value="1" <?php if($this->options->memos_enable_sync == '1') echo 'checked'; ?> />
        启用同步功能
    </label>
    <p class="description">启用后,发布文章时会自动同步到Memos</p>
</div>

<div class="typecho-option">
    <label class="typecho-label">
        <input type="checkbox" name="memos_include_tags" value="1" <?php if($this->options->memos_include_tags == '1') echo 'checked'; ?> />
        包含分类作为标签
    </label>
    <p class="description">将文章分类作为Memos的标签</p>
</div>

3. Plugin.php

<?php
/**
 * MemosSync - Typecho文章同步到Memos插件
 * 
 * @package MemosSync
 * @author Your Name
 * @version 1.0.0
 * @link https://yourblog.com
 */
class MemosSync_Plugin implements Typecho_Plugin_Interface
{
    /**
     * 激活插件
     */
    public static function activate()
    {
        Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishPublish = array('MemosSync_Plugin', 'syncToMemos');
        Typecho_Plugin::factory('Widget_Contents_Post_Edit')->finishSave = array('MemosSync_Plugin', 'syncToMemos');
        
        return _t('插件已激活,请配置Memos设置');
    }

 /**
     * 禁用插件
     */
    public static function deactivate()
    {
        return _t('插件已禁用');
    }

    /**
     * 插件配置面板
     */
    public static function config(Typecho_Widget_Helper_Form $form)
    {
        require_once 'form.php';
    }

    /**
     * 个人用户的配置面板
     */
    public static function personalConfig(Typecho_Widget_Helper_Form $form) {}

/**
     * 同步到Memos
     */
    public static function syncToMemos($contents, $post)
    {
        // 获取插件配置
        $options = Typecho_Widget::widget('Widget_Options');
        $memosUrl = $options->plugin('MemosSync')->memos_url;
        $memosToken = $options->plugin('MemosSync')->memos_token;
        $memosVisibility = $options->plugin('MemosSync')->memos_visibility;
        $enableSync = $options->plugin('MemosSync')->memos_enable_sync;
        $includeTags = $options->plugin('MemosSync')->memos_include_tags;
        
        // 检查是否启用同步
        if (!$enableSync) {
            return;
        }
        
        // 验证必要配置
        if (empty($memosUrl) || empty($memosToken)) {
            return;
        }
        
        try {
            // 准备请求数据
            $apiUrl = rtrim($memosUrl, '/') . '/api/v1/memos';
            
            $content = $contents['text'];
            
            // 如果启用了标签功能,获取分类作为标签
            $tags = array();
            if ($includeTags && isset($contents['category'])) {
                $category = $contents['category'];
                if (is_array($category)) {
                    $tags = $category;
                } else {
                    $tags = array($category);
                }
            }
            
            // 构建内容,包含标签
            $memoContent = $content;
            if (!empty($tags)) {
                $tagString = '';
                foreach ($tags as $tag) {
                    $tagString .= ' #' . self::formatTag($tag);
                }
                $memoContent .= "\n\n" . $tagString;
            }

// 准备请求数据
           $postData = array(
                'content' => $memoContent,
                'visibility' => $memosVisibility
            );
            
            // 发送请求到Memos
            $http = Typecho_Http_Client::get();
            if ($http) {
                $http->setHeader('Authorization', 'Bearer ' . $memosToken)
                     ->setHeader('Content-Type', 'application/json')
                     ->setData(json_encode($postData))
                     ->setTimeout(30)
                     ->send($apiUrl);
                
                $response = $http->getResponseBody();
                $status = $http->getResponseStatus();
                
                if ($status != 200) {
                    throw new Exception('Memos API 返回错误: ' . $status . ' - ' . $response);
                }
            }
            
        } catch (Exception $e) {
            // 记录错误日志,但不影响文章发布
            Typecho_Log::write('MemosSync Error: ' . $e->getMessage(), Typecho_Log::WARN);
        }
    }
    
    /**
     * 格式化标签
     */
    private static function formatTag($tag)
    {
        // 移除特殊字符,只保留字母、数字、中文、下划线
        $tag = preg_replace('/[^\p{L}\p{N}_]/u', '', $tag);
        return $tag;
    }
}
Exit mobile version