ns-rss-spider 1.2.6 → 1.2.8

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -39,6 +39,7 @@ var import_html_entities = require("html-entities");
39
39
  var import_generateSsrContent = require("./generateSsrContent");
40
40
  var import_getBasicFromItem = require("./getBasicFromItem");
41
41
  var import_getArticleImage = require("../utils/getArticleImage");
42
+ var import_analyzeCoverImage = require("../utils/analyzeCoverImage");
42
43
  async function parseContent($, $element, item, strategy) {
43
44
  var _a;
44
45
  const srcs = [];
@@ -80,7 +81,7 @@ async function parseContent($, $element, item, strategy) {
80
81
  title: item2.title
81
82
  });
82
83
  } else {
83
- images.push({
84
+ const imageData = {
84
85
  url: item2.src,
85
86
  title: item2.title,
86
87
  width: result.width,
@@ -89,7 +90,24 @@ async function parseContent($, $element, item, strategy) {
89
90
  widthUnit: result.wUnits !== "px" ? result.wUnits : void 0,
90
91
  heightUnit: result.hUnits !== "px" ? result.hUnits : void 0,
91
92
  realUrl: result.url !== item2.src ? result.url : void 0
92
- });
93
+ };
94
+ if (result.width >= 400 && result.width <= 2e3 && result.height <= 2e3) {
95
+ try {
96
+ console.log(import_zx.chalk.blue("正在分析封面特征", item2.src));
97
+ const response = await fetch(result.url || item2.src);
98
+ const buffer = Buffer.from(await response.arrayBuffer());
99
+ const analysis = await (0, import_analyzeCoverImage.analyzeCoverImage)(buffer);
100
+ if (analysis) {
101
+ imageData.coverAnalysis = analysis;
102
+ console.log(import_zx.chalk.blue(`封面特征: stddev=${analysis.stddev}, entropy=${analysis.entropy}, edgeScore=${analysis.edgeScore}`));
103
+ } else {
104
+ console.log(import_zx.chalk.yellow("未能分析出封面特征"));
105
+ }
106
+ } catch (e) {
107
+ console.error("分析封面失败", (e == null ? void 0 : e.message) || e);
108
+ }
109
+ }
110
+ images.push(imageData);
93
111
  }
94
112
  }
95
113
  $($element).find("img").each((_, img) => {
@@ -47,6 +47,15 @@ export interface RichArticleImage {
47
47
  widthUnit?: string;
48
48
  heightUnit?: string;
49
49
  title?: string;
50
+ /** 图片特征分析 */
51
+ coverAnalysis?: {
52
+ /** 标准差,像素明暗对比程度 (0-100) */
53
+ stddev: number;
54
+ /** 信息熵,颜色分布均匀程度 (0-100) */
55
+ entropy: number;
56
+ /** 边缘复杂度,文字/线条密度 (0-100) */
57
+ edgeScore: number;
58
+ };
50
59
  }
51
60
  export interface RichArticle extends Omit<SimpleArticle, 'type'> {
52
61
  type: 'rich';
@@ -13,7 +13,7 @@ export declare function uploadContent({ app, getUploadApi, items, }: {
13
13
  } & ServerInfo): Promise<Article[] | {
14
14
  images?: RichArticleImage[] | undefined;
15
15
  storePath: any;
16
- type: "simple" | "rich" | "newsletter";
16
+ type: "newsletter" | "simple" | "rich";
17
17
  guid: string;
18
18
  title: string;
19
19
  link: string;
@@ -49,7 +49,7 @@ function filterImages(images) {
49
49
  return true;
50
50
  });
51
51
  }
52
- return filtered;
52
+ return filtered.slice(0, 5);
53
53
  }
54
54
  async function uploadContent({
55
55
  app,
@@ -0,0 +1,14 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ export interface CoverAnalysisResult {
4
+ stddev: number;
5
+ entropy: number;
6
+ edgeScore: number;
7
+ }
8
+ /**
9
+ * 分析图片特征,返回三个指标供客户端判断是否适合做封面
10
+ * - stddev: 标准差,像素明暗对比程度 (0-100)
11
+ * - entropy: 信息熵,颜色分布均匀程度 (0-100)
12
+ * - edgeScore: 边缘复杂度,文字/线条密度 (0-100)
13
+ */
14
+ export declare function analyzeCoverImage(imageBuffer: Buffer): Promise<CoverAnalysisResult | null>;
@@ -0,0 +1,102 @@
1
+ var __create = Object.create;
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __getProtoOf = Object.getPrototypeOf;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __export = (target, all) => {
8
+ for (var name in all)
9
+ __defProp(target, name, { get: all[name], enumerable: true });
10
+ };
11
+ var __copyProps = (to, from, except, desc) => {
12
+ if (from && typeof from === "object" || typeof from === "function") {
13
+ for (let key of __getOwnPropNames(from))
14
+ if (!__hasOwnProp.call(to, key) && key !== except)
15
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
16
+ }
17
+ return to;
18
+ };
19
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
20
+ // If the importer is in node compatibility mode or this is not an ESM
21
+ // file that has been converted to a CommonJS file using a Babel-
22
+ // compatible transform (i.e. "__esModule" has not been set), then set
23
+ // "default" to the CommonJS "module.exports" for node compatibility.
24
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
25
+ mod
26
+ ));
27
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
28
+
29
+ // src/utils/analyzeCoverImage.ts
30
+ var analyzeCoverImage_exports = {};
31
+ __export(analyzeCoverImage_exports, {
32
+ analyzeCoverImage: () => analyzeCoverImage
33
+ });
34
+ module.exports = __toCommonJS(analyzeCoverImage_exports);
35
+ var import_sharp = __toESM(require("sharp"));
36
+ var TARGET_SIZE = 64;
37
+ async function analyzeCoverImage(imageBuffer) {
38
+ try {
39
+ const resized = (0, import_sharp.default)(imageBuffer).resize(TARGET_SIZE, TARGET_SIZE, { fit: "inside" }).grayscale();
40
+ const { data: rawBuffer, info } = await resized.clone().raw().toBuffer({ resolveWithObject: true });
41
+ const width = info.width;
42
+ const height = info.height;
43
+ const totalPixels = width * height;
44
+ let sum = 0;
45
+ for (let i = 0; i < rawBuffer.length; i++) {
46
+ sum += rawBuffer[i];
47
+ }
48
+ const mean = sum / totalPixels;
49
+ let sqDiffSum = 0;
50
+ for (let i = 0; i < rawBuffer.length; i++) {
51
+ sqDiffSum += (rawBuffer[i] - mean) ** 2;
52
+ }
53
+ const stddev = Math.sqrt(sqDiffSum / totalPixels) / 255 * 100;
54
+ const hist = new Array(256).fill(0);
55
+ for (let i = 0; i < rawBuffer.length; i++) {
56
+ hist[rawBuffer[i]]++;
57
+ }
58
+ let entropyRaw = 0;
59
+ for (let i = 0; i < 256; i++) {
60
+ const p = hist[i] / totalPixels;
61
+ if (p > 0) {
62
+ entropyRaw -= p * Math.log2(p);
63
+ }
64
+ }
65
+ const entropy = entropyRaw / 8 * 100;
66
+ let edgeSum = 0;
67
+ let edgeSqSum = 0;
68
+ let count = 0;
69
+ for (let y = 0; y < height; y++) {
70
+ for (let x = 0; x < width; x++) {
71
+ const idx = y * width + x;
72
+ if (x < width - 1) {
73
+ const diff = Math.abs(rawBuffer[idx] - rawBuffer[idx + 1]);
74
+ edgeSum += diff;
75
+ edgeSqSum += diff * diff;
76
+ count++;
77
+ }
78
+ if (y < height - 1) {
79
+ const diff = Math.abs(rawBuffer[idx] - rawBuffer[idx + width]);
80
+ edgeSum += diff;
81
+ edgeSqSum += diff * diff;
82
+ count++;
83
+ }
84
+ }
85
+ }
86
+ const edgeMean = count > 0 ? edgeSum / count : 0;
87
+ const edgeVariance = count > 0 ? edgeSqSum / count - edgeMean * edgeMean : 0;
88
+ const edgeScore = Math.min(edgeVariance / 1e3 * 100, 100);
89
+ return {
90
+ stddev: Math.round(stddev * 100) / 100,
91
+ entropy: Math.round(entropy * 100) / 100,
92
+ edgeScore: Math.round(edgeScore * 100) / 100
93
+ };
94
+ } catch (error) {
95
+ console.error("分析封面图片失败", error);
96
+ return null;
97
+ }
98
+ }
99
+ // Annotate the CommonJS export names for ESM import in node:
100
+ 0 && (module.exports = {
101
+ analyzeCoverImage
102
+ });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ns-rss-spider",
3
- "version": "1.2.6",
3
+ "version": "1.2.8",
4
4
  "description": "",
5
5
  "main": "dist/cjs/index.js",
6
6
  "types": "dist/cjs/index.d.ts",
@@ -29,6 +29,7 @@
29
29
  "devDependencies": {
30
30
  "@types/lodash": "^4.14.202",
31
31
  "@types/probe-image-size": "^7.2.4",
32
+ "@types/sharp": "^0.31.1",
32
33
  "cnpm": "^9.4.0",
33
34
  "father": "^4.4.0",
34
35
  "vitest": "^1.2.2"
@@ -42,6 +43,7 @@
42
43
  "playwright": "1.41.2",
43
44
  "probe-image-size": "^7.2.3",
44
45
  "rss-parser": "^3.13.0",
46
+ "sharp": "^0.34.5",
45
47
  "yargs-parser": "^21.1.1",
46
48
  "zx": "4.x"
47
49
  }