Compare commits
3 Commits
a6883c5ce7
...
16e91b835e
Author | SHA1 | Date |
---|---|---|
|
16e91b835e | |
|
9671712412 | |
|
4df85ae062 |
|
@ -6,6 +6,8 @@
|
|||
|
||||
|
||||
## 更新日志 & 预览
|
||||
### 0.7.2
|
||||
- 优化页面加载速度,自动裁切封面,并压缩为`webp`格式,并保存在主题目录`assets`-`images`-`covers`下,使用前必须开启`php`的`GD拓展`和主题目录的写入权限
|
||||
|
||||
### 0.7.1
|
||||
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
is_single = false;
|
||||
post_id = 0;
|
||||
is_archive = false;
|
||||
VERSION = "0.7.1";
|
||||
VERSION = "0.7.2";
|
||||
constructor() {
|
||||
super();
|
||||
this.initCopyright();
|
||||
|
@ -46,7 +46,7 @@
|
|||
}
|
||||
initCopyright() {
|
||||
const copyright = `<div class="site--footer__info">由<a href="https://www.typecho.org" target="_blank">Typecho</a> 驱动 <br>
|
||||
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa <br>Made with<a href="https://www.imsun.org" target="_blank">jkjoy</a> / version ${this.VERSION}
|
||||
Theme <a href="https://fatesinger.com/101971" target="_blank">farallon</a> by bigfa <br>Made with <a href="https://www.imsun.org" target="_blank">老孙博客</a> / version ${this.VERSION}
|
||||
</div>`;
|
||||
document.querySelector(".site--footer__content").insertAdjacentHTML("afterend", copyright);
|
||||
document.querySelector(".icon--copryrights").addEventListener("click", () => {
|
||||
|
|
186
functions.php
186
functions.php
|
@ -24,23 +24,23 @@ function themeConfig($form) {
|
|||
$form->addInput($mastodonurl);
|
||||
$showProfile = new Typecho_Widget_Helper_Form_Element_Radio('showProfile',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否在文章页面显示作者信息'), _t('选择“是”将在文章页面包含显示作者信息。'));
|
||||
'0', _t('是否在文章页面显示作者信息'), _t('选择"是"将在文章页面包含显示作者信息。'));
|
||||
$form->addInput($showProfile);
|
||||
$showcate = new Typecho_Widget_Helper_Form_Element_Radio('showcate',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否在文章页面显示文章分类'), _t('选择“是”将在文章页面显示文章的分类信息。'));
|
||||
'0', _t('是否在文章页面显示文章分类'), _t('选择"是"将在文章页面显示文章的分类信息。'));
|
||||
$form->addInput($showcate);
|
||||
$showrelated = new Typecho_Widget_Helper_Form_Element_Radio('showrelated',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示相关文章'), _t('选择“是”将在文章页面显示相关文章。'));
|
||||
'0', _t('是否显示相关文章'), _t('选择"是"将在文章页面显示相关文章。'));
|
||||
$form->addInput($showrelated);
|
||||
$showshare = new Typecho_Widget_Helper_Form_Element_Radio('showshare',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示复制链接'), _t('选择“是”将在文章页面显示复制链接。'));
|
||||
'0', _t('是否显示复制链接'), _t('选择"是"将在文章页面显示复制链接。'));
|
||||
$form->addInput($showshare);
|
||||
$showtime = new Typecho_Widget_Helper_Form_Element_Radio('showtime',
|
||||
array('0'=> _t('否'), '1'=> _t('是')),
|
||||
'0', _t('是否显示页面加载时间'), _t('选择“是”将在页脚显示加载时间。'));
|
||||
'0', _t('是否显示页面加载时间'), _t('选择"是"将在页脚显示加载时间。'));
|
||||
$form->addInput($showtime);
|
||||
$loadmore = new Typecho_Widget_Helper_Form_Element_Radio('loadmore',
|
||||
array('0'=> _t('加载更多'), '1'=> _t('页码模式')),
|
||||
|
@ -111,6 +111,17 @@ $options = Typecho_Widget::widget('Widget_Options');
|
|||
$gravatarPrefix = empty($options->cnavatar) ? 'https://cravatar.cn/avatar/' : $options->cnavatar;
|
||||
define('__TYPECHO_GRAVATAR_PREFIX__', $gravatarPrefix);
|
||||
|
||||
// 初始化主题
|
||||
function init_theme() {
|
||||
// 检查并创建封面图片目录
|
||||
$coversDir = dirname(__FILE__) . '/assets/images/covers';
|
||||
if (!is_dir($coversDir)) {
|
||||
@mkdir($coversDir, 0755, true);
|
||||
}
|
||||
}
|
||||
// 在主题加载时执行初始化
|
||||
init_theme();
|
||||
|
||||
/**
|
||||
* 页面加载时间
|
||||
*/
|
||||
|
@ -138,6 +149,19 @@ function timer_start() {
|
|||
*/
|
||||
function img_postthumb($cid) {
|
||||
$db = Typecho_Db::get();
|
||||
|
||||
// 首先检查是否设置了自定义封面
|
||||
$cover = $db->fetchRow($db->select('str_value')
|
||||
->from('table.fields')
|
||||
->where('cid = ?', $cid)
|
||||
->where('name = ?', 'cover'));
|
||||
|
||||
// 如果找到自定义封面,直接返回
|
||||
if ($cover && !empty($cover['str_value'])) {
|
||||
return $cover['str_value'];
|
||||
}
|
||||
|
||||
// 否则尝试从文章内容中获取第一张图片
|
||||
$rs = $db->fetchRow($db->select('table.contents.text')
|
||||
->from('table.contents')
|
||||
->where('table.contents.cid=?', $cid)
|
||||
|
@ -168,8 +192,11 @@ function getPermalinkFromCoid($coid) {
|
|||
* 图片灯箱
|
||||
*/
|
||||
class ImageStructureProcessor {
|
||||
public static function processContent($content, $widget) {
|
||||
// 首先检查内容是否为空
|
||||
public static function processContent($content, $widget, $lastResult = null) {
|
||||
// 首先应用之前的过滤器结果
|
||||
$content = empty($lastResult) ? $content : $lastResult;
|
||||
|
||||
// 检查内容是否为空
|
||||
if (empty($content) || !is_string($content)) {
|
||||
return $content;
|
||||
}
|
||||
|
@ -236,15 +263,130 @@ class ImageStructureProcessor {
|
|||
} catch (Exception $e) {
|
||||
// 记录错误但返回原始内容
|
||||
error_log('Image processing error: ' . $e->getMessage());
|
||||
return $content;
|
||||
// 如果发生错误,返回上一个过滤器结果或原始内容
|
||||
return empty($lastResult) ? $content : $lastResult;
|
||||
}
|
||||
}
|
||||
return $content;
|
||||
}
|
||||
}
|
||||
Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
|
||||
return ImageStructureProcessor::processContent($content, $widget);
|
||||
};
|
||||
// u6ce8u91cau6389u8fd9u884cuff0cu9632u6b62u8986u76d6u8fd9u4e2au94a9u5b50u7684u5176u4ed6u6ce8u518c
|
||||
// Typecho_Plugin::factory('Widget_Abstract_Contents')->contentEx = function($content, $widget) {
|
||||
// return ImageStructureProcessor::processContent($content, $widget);
|
||||
// };
|
||||
|
||||
/**
|
||||
* 处理图片为封面图(裁剪为5:3,最大宽度500px,转换为webp)
|
||||
*
|
||||
* @param string $imageUrl 原始图片URL
|
||||
* @return string 处理后的图片URL
|
||||
*/
|
||||
function process_cover_image($imageUrl) {
|
||||
// 检查GD库是否可用
|
||||
if (!function_exists('imagecreatetruecolor')) {
|
||||
return $imageUrl; // 如果GD库不可用,返回原图
|
||||
}
|
||||
|
||||
// 分析URL
|
||||
$parsed = parse_url($imageUrl);
|
||||
|
||||
// 如果图片是外部链接,需要下载
|
||||
$isExternalUrl = !empty($parsed['host']) && $parsed['host'] !== $_SERVER['HTTP_HOST'];
|
||||
|
||||
// 生成唯一的文件名(使用MD5哈希)
|
||||
$filename = md5($imageUrl) . '.webp';
|
||||
|
||||
// 处理后图片的保存路径
|
||||
$themeDir = dirname(__FILE__);
|
||||
$savePath = $themeDir . '/assets/images/covers/' . $filename;
|
||||
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
|
||||
|
||||
// 如果缓存文件已存在,直接返回
|
||||
if (file_exists($savePath)) {
|
||||
return $webPath;
|
||||
}
|
||||
|
||||
// 获取原始图片内容
|
||||
if ($isExternalUrl) {
|
||||
// 外部图片,需要下载
|
||||
$imageContent = @file_get_contents($imageUrl);
|
||||
if (!$imageContent) {
|
||||
return $imageUrl; // 无法下载,返回原图
|
||||
}
|
||||
} else {
|
||||
// 本地图片
|
||||
$localPath = $_SERVER['DOCUMENT_ROOT'] . $parsed['path'];
|
||||
if (!file_exists($localPath)) {
|
||||
return $imageUrl; // 无法找到本地文件,返回原图
|
||||
}
|
||||
$imageContent = @file_get_contents($localPath);
|
||||
}
|
||||
|
||||
// 创建图像资源
|
||||
$originalImage = @imagecreatefromstring($imageContent);
|
||||
if (!$originalImage) {
|
||||
return $imageUrl; // 无法创建图像资源,返回原图
|
||||
}
|
||||
|
||||
// 获取原始图片尺寸
|
||||
$originalWidth = imagesx($originalImage);
|
||||
$originalHeight = imagesy($originalImage);
|
||||
|
||||
// 计算目标尺寸(5:3比例,最大宽度500px)
|
||||
$targetWidth = min(500, $originalWidth);
|
||||
$targetHeight = intval($targetWidth * 3 / 5);
|
||||
|
||||
// 计算裁剪坐标(居中裁剪)
|
||||
$cropX = 0;
|
||||
$cropY = 0;
|
||||
$cropWidth = $originalWidth;
|
||||
$cropHeight = $originalHeight;
|
||||
|
||||
// 计算比例
|
||||
$originalRatio = $originalWidth / $originalHeight;
|
||||
$targetRatio = 5 / 3;
|
||||
|
||||
if ($originalRatio > $targetRatio) {
|
||||
// 原图过宽,需要裁剪宽度
|
||||
$cropWidth = intval($originalHeight * $targetRatio);
|
||||
$cropX = intval(($originalWidth - $cropWidth) / 2);
|
||||
} else {
|
||||
// 原图过高,需要裁剪高度
|
||||
$cropHeight = intval($originalWidth / $targetRatio);
|
||||
$cropY = intval(($originalHeight - $cropHeight) / 2);
|
||||
}
|
||||
|
||||
// 创建目标图像
|
||||
$targetImage = imagecreatetruecolor($targetWidth, $targetHeight);
|
||||
|
||||
// 裁剪并调整大小
|
||||
imagecopyresampled(
|
||||
$targetImage,
|
||||
$originalImage,
|
||||
0, 0,
|
||||
$cropX, $cropY,
|
||||
$targetWidth, $targetHeight,
|
||||
$cropWidth, $cropHeight
|
||||
);
|
||||
|
||||
// 保存为webp格式
|
||||
if (!function_exists('imagewebp')) {
|
||||
// 如果不支持webp,保存为png
|
||||
$filename = md5($imageUrl) . '.png';
|
||||
$savePath = $themeDir . '/assets/images/covers/' . $filename;
|
||||
$webPath = Helper::options()->themeUrl . '/assets/images/covers/' . $filename;
|
||||
imagepng($targetImage, $savePath, 9); // 9是最高压缩质量
|
||||
} else {
|
||||
// 保存为webp
|
||||
imagewebp($targetImage, $savePath, 80); // 80是质量参数
|
||||
}
|
||||
|
||||
// 释放资源
|
||||
imagedestroy($originalImage);
|
||||
imagedestroy($targetImage);
|
||||
|
||||
return $webPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* *获取文章卡片
|
||||
|
@ -297,6 +439,9 @@ function get_article_info($atts) {
|
|||
$imageToDisplay = img_postthumb($post['cid']);
|
||||
if (empty($imageToDisplay)) {
|
||||
$imageToDisplay = $default_thumbnail;
|
||||
} else {
|
||||
// 处理封面图片
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
}
|
||||
// 构建输出
|
||||
$output = '<div class="graph--mixtapeEmbed">';
|
||||
|
@ -315,11 +460,16 @@ class ContentFilter
|
|||
{
|
||||
// 首先运行之前的过滤器结果
|
||||
$content = empty($lastResult) ? $content : $lastResult;
|
||||
|
||||
// 处理图片灯箱
|
||||
$content = ImageStructureProcessor::processContent($content, $widget, $content);
|
||||
|
||||
// 然后处理我们的文章短代码
|
||||
$content = preg_replace_callback('/\[article\s+([^\]]+)\]/', function($matches) {
|
||||
$atts = self::parse_atts($matches[1]);
|
||||
return get_article_info($atts);
|
||||
}, $content);
|
||||
|
||||
return $content;
|
||||
}
|
||||
// 解析短代码属性
|
||||
|
@ -377,8 +527,11 @@ EOF;
|
|||
}
|
||||
}
|
||||
// 注册编辑器按钮钩子
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
|
||||
// 避免重复注册,在最后执行
|
||||
if (!Typecho_Plugin::exists('Widget_Abstract_Contents', 'editor')) {
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('EditorButton', 'render');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('EditorButton', 'render');
|
||||
}
|
||||
|
||||
/**
|
||||
* 评论者认证等级 + 身份
|
||||
|
@ -455,8 +608,11 @@ function commentApprove($widget, $email = NULL)
|
|||
* 修改附件插入功能
|
||||
*/
|
||||
// 添加批量插入按钮的JavaScript
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
// 避免重复注册,使用条件判断
|
||||
if (!Typecho_Plugin::exists('admin/write-post.php', 'bottom')) {
|
||||
Typecho_Plugin::factory('admin/write-post.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
Typecho_Plugin::factory('admin/write-page.php')->bottom = array('MyHelper', 'addBatchInsertButton');
|
||||
}
|
||||
|
||||
class MyHelper {
|
||||
public static function addBatchInsertButton() {
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
* 一款单栏主题. 移植自HUGO主题 Farallon 原作者 bigfa
|
||||
* @package Farallon
|
||||
* @author 老孙
|
||||
* @version 0.7.1
|
||||
* @version 0.7.2
|
||||
* @link https://www.imsun.org
|
||||
*/
|
||||
if (!defined('__TYPECHO_ROOT_DIR__')) exit; ?>
|
||||
|
|
|
@ -75,6 +75,7 @@
|
|||
$cover = $this->fields->cover;
|
||||
$imageToDisplay = !empty($cover) ? $cover : $firstImage;
|
||||
if($imageToDisplay):
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
?>
|
||||
<a href="<?php $this->permalink() ?>" class="cover--link">
|
||||
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>
|
||||
|
|
|
@ -12,6 +12,9 @@
|
|||
if (empty($imageToDisplay)) {
|
||||
$imageToDisplay = $firstImage;
|
||||
}
|
||||
if (!empty($imageToDisplay) && $imageToDisplay != $default_thumbnail) {
|
||||
$imageToDisplay = process_cover_image($imageToDisplay);
|
||||
}
|
||||
?>
|
||||
<article class="post--card" id="loadpost" itemscope itemtype="http://schema.org/Article">
|
||||
<img src="<?php echo $imageToDisplay; ?>" alt="<?php $this->title() ?>" class="cover" itemprop="image"/>
|
||||
|
|
Loading…
Reference in New Issue