mirror of
https://github.com/JimLiu/baoyu-skills.git
synced 2026-07-12 22:09:48 +08:00
Compare commits
2 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| c5c54e26da | |||
| 2a0bba6161 |
@@ -6,7 +6,7 @@
|
||||
},
|
||||
"metadata": {
|
||||
"description": "Skills shared by Baoyu for improving daily work efficiency",
|
||||
"version": "1.90.0"
|
||||
"version": "1.90.1"
|
||||
},
|
||||
"plugins": [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
English | [中文](./CHANGELOG.zh.md)
|
||||
|
||||
## 1.90.1 - 2026-04-05
|
||||
|
||||
### Fixes
|
||||
- `baoyu-post-to-wechat`: detect actual image format from buffer magic bytes to fix CDN content-type mismatches (e.g. WebP served for .png URLs); treat WebP as PNG-preferred for transparency handling
|
||||
|
||||
## 1.89.1 - 2026-04-01
|
||||
|
||||
### Features
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
[English](./CHANGELOG.md) | 中文
|
||||
|
||||
## 1.90.1 - 2026-04-05
|
||||
|
||||
### 修复
|
||||
- `baoyu-post-to-wechat`:通过 magic bytes 检测实际图片格式,修复 CDN 返回与 URL 扩展名不一致的 content-type 问题(如 .png URL 实际返回 WebP);WebP 格式按 PNG 策略处理以保留透明度
|
||||
|
||||
## 1.89.1 - 2026-04-01
|
||||
|
||||
### 新功能
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# CLAUDE.md
|
||||
|
||||
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.90.0**.
|
||||
Claude Code marketplace plugin providing AI-powered content generation skills. Version: **1.90.1**.
|
||||
|
||||
## Architecture
|
||||
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
type WechatUploadAsset,
|
||||
prepareWechatBodyImageUpload,
|
||||
needsWechatBodyImageProcessing,
|
||||
detectImageFormatFromBuffer,
|
||||
} from "./wechat-image-processor.ts";
|
||||
|
||||
interface AccessTokenResponse {
|
||||
@@ -138,6 +139,16 @@ async function loadUploadAsset(
|
||||
contentType = mimeTypes[fileExt] || "image/jpeg";
|
||||
}
|
||||
|
||||
// Detect actual format from magic bytes to fix extension/content-type mismatches
|
||||
// (e.g. CDNs serving WebP for URLs with .png extension)
|
||||
const detected = detectImageFormatFromBuffer(fileBuffer);
|
||||
if (detected && detected.contentType !== contentType) {
|
||||
console.error(`[wechat-api] Format mismatch: ${filename} declared as ${contentType}, actual ${detected.contentType}`);
|
||||
contentType = detected.contentType;
|
||||
fileExt = detected.fileExt;
|
||||
filename = `${path.basename(filename, path.extname(filename))}${detected.fileExt}`;
|
||||
}
|
||||
|
||||
return {
|
||||
buffer: fileBuffer,
|
||||
filename,
|
||||
|
||||
@@ -52,6 +52,39 @@ const MIME_TO_EXT: Record<string, string> = {
|
||||
const JPEG_QUALITY_STEPS = [82, 74, 66, 58, 50, 42, 34];
|
||||
const MAX_WIDTH_STEPS = [2560, 2048, 1600, 1280, 1024, 800, 640, 480];
|
||||
|
||||
/**
|
||||
* Detect actual image format from buffer magic bytes.
|
||||
* Returns corrected { contentType, fileExt } or null if unknown.
|
||||
*/
|
||||
export function detectImageFormatFromBuffer(buffer: Buffer): { contentType: string; fileExt: string } | null {
|
||||
if (buffer.length < 12) return null;
|
||||
|
||||
// WebP: RIFF....WEBP
|
||||
if (
|
||||
buffer[0] === 0x52 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x46 &&
|
||||
buffer[8] === 0x57 && buffer[9] === 0x45 && buffer[10] === 0x42 && buffer[11] === 0x50
|
||||
) {
|
||||
return { contentType: "image/webp", fileExt: ".webp" };
|
||||
}
|
||||
// PNG: 89 50 4E 47
|
||||
if (buffer[0] === 0x89 && buffer[1] === 0x50 && buffer[2] === 0x4e && buffer[3] === 0x47) {
|
||||
return { contentType: "image/png", fileExt: ".png" };
|
||||
}
|
||||
// JPEG: FF D8 FF
|
||||
if (buffer[0] === 0xff && buffer[1] === 0xd8 && buffer[2] === 0xff) {
|
||||
return { contentType: "image/jpeg", fileExt: ".jpg" };
|
||||
}
|
||||
// GIF: GIF8
|
||||
if (buffer[0] === 0x47 && buffer[1] === 0x49 && buffer[2] === 0x46 && buffer[3] === 0x38) {
|
||||
return { contentType: "image/gif", fileExt: ".gif" };
|
||||
}
|
||||
// BMP: BM
|
||||
if (buffer[0] === 0x42 && buffer[1] === 0x4d) {
|
||||
return { contentType: "image/bmp", fileExt: ".bmp" };
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
let webpDecoderReady: Promise<void> | undefined;
|
||||
|
||||
type JimpImage = Awaited<ReturnType<typeof Jimp.read>>;
|
||||
@@ -209,7 +242,8 @@ export async function prepareWechatBodyImageUpload(
|
||||
|
||||
const image = await loadImageForProcessing(asset);
|
||||
const widths = buildCandidateWidths(image.bitmap.width);
|
||||
const preferPng = imageHasTransparency(image) || ensureFileExt(asset) === ".png";
|
||||
const ext = ensureFileExt(asset);
|
||||
const preferPng = imageHasTransparency(image) || ext === ".png" || ext === ".webp";
|
||||
const processingNotes = buildProcessingNotes(asset);
|
||||
|
||||
for (const width of widths) {
|
||||
|
||||
Reference in New Issue
Block a user