相册接入Memos实现自动更新

更新记录

本教程基于anzhiyu二改,如果是小白建议先按照鱼佬文档教程搭建好基本页面在看此教程

相册支持Memos地址

相册细节优化(type为2展示时间)

album_listurl问题

初衷:
更新相册为了更方便一点,按照鱼的主题教程来搭建的目前只支持手动在 album.yml 文件中更新照片数据
更新完之后还需要 在编译在提交博客到仓库,为了方便更新相册数据因此接入Memos,省去在博客中操作的繁琐步骤
让页面看起来更顺我心意,看不顺眼那就魔改一下下吧~

  1. 这里在详细说明一下关于 album_list的问题,在鱼佬的相册页面配置教程中,有一个album_list和一个url属性,
    album_listurl同时存在的时候,会将url中的数据覆盖掉album_list中的数据,所以我觉得要么就都展示,要么就严谨一点做个断言处理,如果url存在链接地址,将会直接忽略album_list
    这个只是一个小问题,可以忽略,但是作为强迫症患者的我受不了一点…到时候在做修改吧

效果预览

  1. 图片展示无时间显示
    type为2时页面图片无时间展示
    鱼佬效果图
    但是 type为1时就有时间….. 本人强迫症看到此时此景非常的不爽,要么都有,要么都没有,这里忍不住吐槽一番吧~
    鱼佬效果图

相册

  1. 图片展示时间
    SerMs相册展示
  2. 接入Memos,前面四张一样的是memos做测试用的
    Memos链接

前提说明

本文不对Memos搭建做说明,如果您还未搭建自己的Memos地址请移步到hi-memos
也可以使用可以使用小N和杜老师维护的公益服务:memos纯公益代部署服务

修改步骤

修改main.js

文件地址 themes/anzhiyu/source/js/main.js,搜代码justified-gallery 圖庫排版,改动较多建议直接全部复制替换这个方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
/**
* justified-gallery 圖庫排版
*/
const runJustifiedGallery = function (ele) {
const htmlStr = arr => {
let str = "";
const replaceDq = str => str.replace(/"/g, """); // replace double quotes to "
arr.forEach(i => {
const alt = i.alt ? `alt="${replaceDq(i.alt)}"` : "";
const title = i.title ? `title="${replaceDq(i.title)}"` : "";
const dateTime = i.date ? `${new Date(i.date).toISOString()}` : "";
const address = i.address ? i.address : "";
const galleryItem = `
<div class="fj-gallery-item" id="serms-fj-gallery-item">
${address ? `<div class="tag-address">${address}</div>` : ""}
<img src="${i.url}" ${alt + title} class="card_cover">
<div class="serms-album-info-time">
<time class="datatime" datatime=${i.date} style="display: inline;">${i.date}</time>
</div>
</div>
`;
str += galleryItem;
});

return str;
};

const lazyloadFn = (i, arr, limit) => {
const loadItem = Number(limit);
const arrLength = arr.length;
if (arrLength > loadItem) i.insertAdjacentHTML("beforeend", htmlStr(arr.splice(0, loadItem)));
else {
i.insertAdjacentHTML("beforeend", htmlStr(arr));
i.classList.remove("lazyload");
}
window.lazyLoadInstance && window.lazyLoadInstance.update();
return arrLength > loadItem ? loadItem : arrLength;
};

function imageInfo(input) {
const lines = input.split('\n').filter(line => line.trim() !== ''); // 分割成每行,并过滤掉空行
const result = [];

lines.forEach(line => {
const regex = /\!\[(.*?)\]\((.*?)\)/;
const match = line.match(regex);
if (match) {
const [, titlePart, url] = match;
const [, date, address, title] = titlePart.trim().match(/(\d{4}-\d{2}-\d{2})\s(.*?)\s(.*)/);
const infoObject = {
"url": url.trim(),
"address": address.trim(),
"date": date.trim(),
"title": title.trim(),
};
result.push(infoObject);
}
});

return result;
}

const fetchUrl = async url => {
try {
const [dUrl, mUrl] = url.split("https://").slice(1);
const [dUrlResponse, mUrlResponse] = await Promise.all([
fetch(`https://${dUrl}`),
fetch(`https://${mUrl}`)
]);
if (!dUrlResponse.ok || !mUrlResponse.ok) {
throw new Error('Network response was not ok');
}
const [dUrlData, mUrlData] = await Promise.all([
dUrlResponse.json(),
mUrlResponse.json()
]);
const mUrlArryData = imageInfo(mUrlData[0].content);
return mUrlArryData.concat(dUrlData);
} catch (error) {
console.error('Error occurred:', error);
return []; // 返回空数组或者其他错误处理策略
}
};
const runJustifiedGallery = (item, arr) => {
const limit = item.getAttribute("data-limit") ?? arr.length;
if (!item.classList.contains("lazyload") || arr.length < limit) {
// 不懒加载
item.innerHTML = htmlStr(arr);
item.nextElementSibling.style.display = "none";
} else {
if (!item.classList.contains("btn_album_detail_lazyload") || item.classList.contains("page_img_lazyload")) {
// 滚动懒加载
lazyloadFn(item, arr, limit);
const clickBtnFn = () => {
const lastItemLength = lazyloadFn(item, arr, limit);
fjGallery(
item,
"appendImages",
item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)
);
anzhiyu.loadLightbox(item.querySelectorAll("img"));
if (lastItemLength < Number(limit)) {
observer.unobserve(item.nextElementSibling);
}
};

// 创建IntersectionObserver实例
const observer = new IntersectionObserver((entries, observer) => {
entries.forEach(entry => {
// 如果元素进入视口
if (entry.isIntersecting) {
// 执行clickBtnFn函数
setTimeout(clickBtnFn(), 100);
}
});
});
observer.observe(item.nextElementSibling);
} else {
// 相册详情 按钮懒加载
lazyloadFn(item, arr, limit);
const clickBtnFn = () => {
const lastItemLength = lazyloadFn(item, arr, limit);
fjGallery(
item,
"appendImages",
item.querySelectorAll(`.fj-gallery-item:nth-last-child(-n+${lastItemLength})`)
);
anzhiyu.loadLightbox(item.querySelectorAll("img"));
lastItemLength < limit && item.nextElementSibling.removeEventListener("click", clickBtnFn);
};
item.nextElementSibling.addEventListener("click", clickBtnFn);
}
}

anzhiyu.initJustifiedGallery(item);
anzhiyu.loadLightbox(item.querySelectorAll("img"));
window.lazyLoadInstance && window.lazyLoadInstance.update();
};

const addJustifiedGallery = () => {
ele.forEach(item => {
item.classList.contains("url") ? fetchUrl(item.textContent).then(res => {
runJustifiedGallery(item, res);
})
: runJustifiedGallery(item, JSON.parse(item.textContent));
});
};

if (window.fjGallery) {
addJustifiedGallery();
return;
}

getCSS(`${GLOBAL_CONFIG.source.justifiedGallery.css}`);
getScript(`${GLOBAL_CONFIG.source.justifiedGallery.js}`).then(addJustifiedGallery);
};

修改album_detail.css

文件地址 themes/anzhiyu/source/css/_extra/album/album_detail.css,新增以下代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.fj-gallery-item > .serms-album-info-time{
display: flex;
position: absolute;
left: 8px;
bottom: 10px;
padding: 4px 6px;
border-radius: 8px;
background: var(--anzhiyu-black-op);
font-size: 12px;
color: var(--anzhiyu-white);
transition: 0.3s;
z-index: 1;
user-select: none;
}
#serms-fj-gallery-item:hover {
cursor: pointer;
z-index: 2;
transform: scale(1.5) translateZ(0);
filter: saturate(1.2) contrast(1);
}

修改album_detail.pug

文件地址 themes/anzhiyu/layout/includes/page/album_detail.pug, 只需新增带+号的代码即可

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
可在此文件中搜全局搜  else if type == 2  请不要复制这行到代码中
else if type == 2
.type-gallery
- const rowHeight = i.rowHeight != "undefined" ? i.rowHeight : 220
- const limit = i.limit != "undefined" ? i.limit : 10
- const lazyload = i.lazyload != "undefined" ? i.lazyload : true
- const lazyloadClass = lazyload == true ? "lazyload" : "";
- const btn = i.btnLazyload != "undefined" ? i.btnLazyload : false
- const btnLazyloadClass = btn == true ? " btn_album_detail_lazyload" : "";
- const imgType = i.url ? " url" : " data";
- let dataStr = []
- const durl = i.url ?? false
+ - const murl = i.murl ?? false
each item, index in i.album_list
each iten, indey in item.image
- let obj = {}
- obj.url = iten
- obj.alt = item.content
- obj.title = item.content
- obj.address = item.address
- obj.date = item.date
- dataStr.push(obj)
.gallery
.fj-gallery(data-rowHeight=rowHeight data-limit=limit class=`${lazyloadClass + btnLazyloadClass + imgType}`)
if durl
span.gallery-data=durl
else
span.gallery-data=JSON.stringify(dataStr)
+ if murl
+ span.gallery-data=murl
if btn
button.gallery-load-more
span=_p('load_more')
i.anzhiyufont.anzhiyu-icon-arrow-down
else
#album_detail_gallery_load_more

最后在album.yml添加murl即可

文件地址 source/_data/album.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
    - class_name: 世界各地夕阳与风景
path_name: /wordScenery
type: 2
description: 因为到不了世界各地,所以请网友们发来了各地的夕阳与风景🌇。
cover: https://bu.dusays.com/2023/10/09/6523a7789ed31.jpg
top_background: https://jsd.onmicrosoft.cn/gh/Ser-MingShao/HexoPublicStaiciImg/serms/202303271231748.jpg
rowHeight: 260
limit: 10
lazyload: false
btnLazyload: false
url: https://img.serms.top/static/js/wordScenery.json
+ murl: https://memos.serms.top/api/v1/memo?creatorId=1&tag=wordScenery (这里添加你自己的memos地址)
top_link: /album
top_btn_text: 返回
album_list:
- date: 2022/10/26 01:00:00
content: 湘潭的一角。
address: 湖南湘潭
from: 再吃一口就减肥
image:
- https://bu.dusays.com/2023/04/09/64329399db122.webp
- date: 2022-10-25
content: 洛阳暴雨后的天空。
address: 河南洛阳
from: SerMs
image:
- https://bu.dusays.com/2023/04/09/64329399db122.webp
- https://bu.dusays.com/2023/04/09/64329399db2e1.webp

memos演示


我这里是有三个细分相册,所以创建memostag的时候根据细分相册名称来定义的,这里没有强制性要求,自己自定义即可

书写格式如上,将你的memosApi放入album.yaml文件中,在上文中有说明

如果不想让图片在memos上展示,可以使用Markdown中代码块的写法,一样适用