merge develop & 手动注释

pull/12/head
guqi 4 months ago
parent 0317e952e1
commit 632ac9139e

@ -11,7 +11,7 @@ from djangoblog.plugin_manage import hooks
# 从常量定义文件导入文章内容钩子的名称
# 使用常量可以避免硬编码字符串,增加代码的可读性和可维护性
# ARTICLE_CONTENT_HOOK_NAME 的值很可能就是 'article_content' 或类似的字符串
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
# 2. 定义插件主类

@ -1,48 +1,76 @@
# 导入正则表达式模块用于匹配和处理HTML中的<a>标签
import re
# 导入URL解析模块用于解析链接的域名等信息
from urllib.parse import urlparse
# 导入Django博客系统的插件基类当前插件需继承此类实现标准化功能
from djangoblog.plugin_manage.base_plugin import BasePlugin
# 导入插件钩子管理模块,用于注册和触发插件功能
from djangoblog.plugin_manage import hooks
# 导入文章内容钩子常量,指定插件要作用的具体钩子位置
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
# 定义外部链接处理插件类继承自插件基类BasePlugin
class ExternalLinksPlugin(BasePlugin):
# 插件名称,用于在插件管理界面展示
PLUGIN_NAME = '外部链接处理器'
# 插件功能描述,说明插件的核心作用
PLUGIN_DESCRIPTION = '自动为文章中的外部链接添加 target="_blank" 和 rel="noopener noreferrer" 属性。'
# 插件版本号,用于版本管理和更新识别
PLUGIN_VERSION = '0.1.0'
# 插件作者信息
PLUGIN_AUTHOR = 'liangliangyy'
# 注册插件钩子的方法,插件加载时会自动调用
def register_hooks(self):
# 将当前插件的process_external_links方法注册到文章内容处理钩子上
# 意味着文章内容渲染前,会自动执行该方法处理链接
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.process_external_links)
# 核心方法:处理文章内容中的外部链接
# 参数content为文章原始HTML内容*args和**kwargs用于接收额外参数预留扩展性
def process_external_links(self, content, *args, **kwargs):
# 导入Django工具函数用于获取当前网站的域名如example.com
from djangoblog.utils import get_current_site
# 获取当前网站的域名,用于判断链接是否为"外部链接"
site_domain = get_current_site().domain
# 正则表达式查找所有 <a> 标签
# 定义正则表达式用于匹配HTML中的<a>标签
# 匹配规则:<a 开头 + 任意属性(可选) + href=" + 链接地址 + " + 剩余属性及闭合标签
# re.IGNORECASE表示忽略大小写如<A>和<a>都能匹配)
link_pattern = re.compile(r'(<a\s+(?:[^>]*?\s+)?href=")([^"]*)(".*?/a>)', re.IGNORECASE)
# 定义正则替换的回调函数,每匹配到一个<a>标签就会执行一次
def replacer(match):
# match.group(1) 是 <a ... href="
# match.group(2) 是链接 URL
# match.group(3) 是 ">...</a>
# 拆分匹配结果为3个分组
# group(1)<a 到 href=" 的部分
# group(2)href属性中的链接地址
# group(3)href=" 之后到 </a> 的部分
href = match.group(2)
# 如果链接已经有 target 属性,则不处理
# 检查当前<a>标签是否已包含target属性不区分大小写如Target或TARGET
# 若已存在target属性则不做处理直接返回原标签
if 'target=' in match.group(0).lower():
return match.group(0)
# 解析链接
# 解析当前链接地址,获取其域名、路径等结构化信息
parsed_url = urlparse(href)
# 如果链接是外部的 (有域名且域名不等于当前网站域名)
# 判断链接是否为外部链接:
# 1. parsed_url.netloc不为空排除无域名的链接如相对路径 /about
# 2. 链接的域名netloc不等于当前网站域名site_domain
if parsed_url.netloc and parsed_url.netloc != site_domain:
# 添加 target 和 rel 属性
# 若为外部链接在href闭合后添加 target="_blank"(新窗口打开)
# 和 rel="noopener noreferrer"(安全属性,防止窗口劫持)
return f'{match.group(1)}{href}" target="_blank" rel="noopener noreferrer"{match.group(3)}'
# 否则返回原样
# 若为内部链接(或无域名链接),不做修改,直接返回原标签
return match.group(0)
# 使用正则表达式替换文章内容中的所有<a>标签执行replacer回调函数
# 返回处理后的文章内容
return link_pattern.sub(replacer, content)
plugin = ExternalLinksPlugin()
# 实例化插件类,使插件系统能识别并加载该插件
plugin = ExternalLinksPlugin()

@ -1,43 +1,69 @@
# 导入数学运算模块,用于向上取整计算
import math
# 导入正则表达式模块用于处理HTML内容和文本分词
import re
# 导入Django博客插件基类当前插件需继承此类
from djangoblog.plugin_manage.base_plugin import BasePlugin
# 导入插件钩子管理模块,用于注册插件功能
from djangoblog.plugin_manage import hooks
# 导入文章内容钩子常量,指定插件作用的位置
from djangoblog.plugin_manage.hook_constants import ARTICLE_CONTENT_HOOK_NAME
class ReadingTimePlugin(BasePlugin):
# 插件名称,用于插件管理界面展示
PLUGIN_NAME = '阅读时间预测'
# 插件功能描述,说明核心作用
PLUGIN_DESCRIPTION = '估算文章阅读时间并显示在文章开头。'
# 插件版本号
PLUGIN_VERSION = '0.1.0'
# 插件作者信息
PLUGIN_AUTHOR = 'liangliangyy'
def register_hooks(self):
"""注册插件钩子,将处理方法绑定到文章内容钩子"""
# 当文章内容被渲染时触发add_reading_time方法
hooks.register(ARTICLE_CONTENT_HOOK_NAME, self.add_reading_time)
def add_reading_time(self, content, *args, **kwargs):
"""
计算阅读时间并添加到内容开头
计算文章阅读时间并添加到内容开头
参数:
content: 文章原始HTML内容
*args, **kwargs: 预留参数用于接收额外信息
返回:
添加了阅读时间信息的HTML内容
"""
# 移除HTML标签和空白字符以获得纯文本
# 1. 清理内容使用正则移除所有HTML标签<...>格式),保留纯文本
clean_content = re.sub(r'<[^>]*>', '', content)
# 移除文本前后的空白字符(空格、换行等)
clean_content = clean_content.strip()
# 中文和英文单词混合计数的一个简单方法
# 匹配中文字符或连续的非中文字符(视为单词)
# 2. 计数单词/字符:
# 正则匹配规则:匹配单个中文字符([\u4e00-\u9fa5])或连续的非中文字符(视为英文单词,\w+
# 这样处理中英文混合的内容,兼顾两种语言的计数逻辑
words = re.findall(r'[\u4e00-\u9fa5]|\w+', clean_content)
# 统计匹配到的元素数量(中文按单个字算,英文按单词算)
word_count = len(words)
# 按平均每分钟200字的速度计算
# 3. 计算阅读时间:
# 设定平均阅读速度为每分钟200字中英文通用的经验值
reading_speed = 200
# 总字数除以阅读速度,向上取整得到分钟数
reading_minutes = math.ceil(word_count / reading_speed)
# 如果阅读时间少于1分钟显示为1分钟
# 处理边界情况如果计算结果小于1分钟强制显示为1分钟
if reading_minutes < 1:
reading_minutes = 1
# 4. 生成阅读时间的HTML片段
# 使用浅灰色文字,斜体样式,显示在段落中
reading_time_html = f'<p style="color: #888;"><em>预计阅读时间:{reading_minutes} 分钟</em></p>'
# 将阅读时间信息添加到文章内容开头并返回
return reading_time_html + content
plugin = ReadingTimePlugin()
# 实例化插件,使插件系统能够识别并加载
plugin = ReadingTimePlugin()
Loading…
Cancel
Save