通过 GitHub doumark-action 保存豆瓣观影数据,并给 Hugo 博客添加豆瓣观影页面。

前言

Hexohexo-douban 项目,可以添加观影数据到页面,更换 Hugo 后也想添加一个观影页面,查找资料后发现有一个 doumark-action 项目可以将观影数据保存为本地文件,然后可以通过 Hugo 的函数获取数据,再前端展示,前面的文章中已经添加了豆瓣条目的短代码,这篇文章再补充两个,一个是近期观影的短代码,另外是添加一个海报墙页面。 最终实现的样式布局参考了一些博主的文章和仓库代码:

保存本地数据

由于豆瓣 API 的限制,之前的一些在线获取数据方式已经失效了,可以通过在线爬取标记的数据到本地,然后操作本地的数据文件,再前端展示数据。 用到的项目是 doumark-action。 首先在博客仓库的根目录新建一个 Workflow,新建 .github/workflows/douban.yml 文件,在其中写入自己想要保存的数据,影音、书籍,也可以保存到 Notion,项目有详细的说明,这里贴一下我的配置,其中将 id 改为自己的豆瓣 ID

 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
# .github/workflows/douban.yml
name: douban
on: 
  schedule:
  - cron: "30 * * * *"
  workflow_dispatch:

jobs:
  douban:
    name: Douban mark data sync
    runs-on: ubuntu-latest
    steps:
    - name: Checkout
      uses: actions/checkout@v2

    - name: movie
      uses: lizheming/doumark-action@master
      with:
        id: 222317686
        type: movie
        format: csv
        dir: ./doubanSync/douban
    
    - name: book
      uses: lizheming/doumark-action@master
      with:
        id: 222317686
        type: book
        format: csv
        dir: ./doubanSync/douban
  
    - name: Commit
      uses: EndBug/add-and-commit@v8
      with:
        message: 'chore: update douban data'
        add: './doubanSync/douban'

我这里将数据存放的目录改为了博客 ~/data 目录之外的地方,使用博客根目录下的 data 目录一直报错,发现之前也有人出现同类型的错误,更改目录后就正常了。

之后可以在仓库手动执行一下 action,完成后会在 ~/doubanSync/douban/ 生成 movie.csvbook.csv ,这就是用到的数据文件。

近期观影短代码

配置

要添加短代码需要在 ~/layouts/shortcodes/ 目录下新建短代码模板文件,这里为 recent-douban.html,在其中添加模板元素:

 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
{{ $type := .Get "type" }}
{{ $count := .Get "count" | default 4 }}
{{ $count = add $count 1 }}
{{ $items := slice }}

{{ if eq $type "movies" }}
    {{ $items = getCSV "," "doubanSync/douban/movie.csv" }}
{{ else if eq $type "books" }}
    {{ $items = getCSV "," "doubanSync/douban/book.csv" }}
{{ end }}



<div class="recent-items">
    {{ range $idx, $item := first $count $items }}
        {{ if ne $idx 0 }}
            {{ $rating := float (index $item 6) }}
            <div class="recent-item">
                <div class="recent-item-cover">
                    <img class="avatar" src="{{ index $item 3 }}" referrer-policy="no-referrer" loading="lazy" alt="{{ index $item 9 }}" title="{{ index $item 1 }}" width="150" height="220">
                </div>
                <div class="recent-douban-rating">
                    <div class="rating">
                        <span class="allstardark">
                            <span class="allstarlight" style="width:{{ mul 10 $rating }}%"></span>
                        </span>
                        <span class="rating_nums">{{ $rating }}</span>
                    </div>
                </div>
                <div class="recent-item-title">
                    <a rel="noreferrer" href="{{ index $item 5 }}" target="_blank">{{ index $item 1 }}</a>
                </div>
            </div>
        {{ end }}
    {{ end }}
</div>

然后添加一下样式代码,这里和之前的文章保持一致,添加到 shortcodes.scss 中:

1
2
3
4
5
6
7
8
9
.recent-items {
    display: flex;
    flex-wrap: wrap;
    justify-content: space-between;
    margin: 15px;
}
.recent-items .recent-item, .recent-items .recent-item img {
    margin-bottom: 10px;
}

之前的豆瓣条目短代码样式文件已经添加了评分星级的样式 allstarlight,所以这里不添加,如果之前没添加过的话需要添加相关的样式,在之前的文章可以找到。

使用

使用方法如下:

1
2
{\{< recent-douban type="movies" count=8 >}\}
{\{< recent-douban type="books" >}\}

默认展示四条数据,可以通过 count 参数指定显示的数量。

预览:

观影页面

配置

添加一个海报墙页面展示所有的观影信息,默认展示 18 条信息。 首先在 ~/lauouts/_default/ 文件夹下新建模板文件,这里为 posterwall.html,然后在其中添加页面元素:

 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
{{ define "main" }}
<div class="post-list-container post-list-container-shadow">
<div class="post-item-wrapper post-item-wrapper-no-hover">
    <div class="post-item post-item-no-gaps">
    <div class="post-item-info-wrapper">
        <div class="post-item-title post-item-title-small">
        {{.Title}}
        <div class="posterwall-description">
            {{ .Params.description | markdownify }}
        </div>
        <div class="movie-wall">
            {{ $items := getCSV "," "doubanSync/douban/movie.csv" }}
            {{ range $idx, $item := $items }}
                {{ if ne $idx 0 }}
                {{ $rating := float (index $item 6) }}
                <div class="movie-item" style="display: none;">
                    <div class="movie-cover">
                    <img src="{{ index $item 3 }}" alt="{{ index $item 1 }}" loading="lazy" width="200" referrer-policy="no-referrer">
                    <div class="movie-info">
                        <div class="movie-title"><a rel="noreferrer" href="{{ index $item 5 }}" target="_blank">{{ index $item 1 }}</a></div>
                        <div class="movie-rating">
                            <div class="rating">
                                <span class="allstardark">
                                    <span class="allstarlight" style="width:{{ mul 10 $rating }}%"></span>
                                </span>
                                <span class="rating_nums">{{ index $item 6 }}</span>
                            </div>
                        </div>


                        <div class="movie-card">{{ index $item 12 }}</div>
                        <div class="movie-comment">{{ index $item 9 }}</div>
                    </div>
                    </div>
                </div>
                {{ end }}
            {{ end }}
            </div>
            
            <button id="loadMore">加载更多</button>
        </div>
    </div>
    </div>
</div>
</div>


<script>
  let visibleMovies = 18;
  const movieItems = document.querySelectorAll('.movie-item');
  const loadMoreButton = document.getElementById('loadMore');

  function updateVisibility() {
    movieItems.forEach((movie, idx) => {
      movie.style.display = idx < visibleMovies ? 'block' : 'none';
    });

    if (visibleMovies >= movieItems.length) {
      loadMoreButton.style.display = 'none';
    }
  }

  loadMoreButton.addEventListener('click', () => {
    visibleMovies += 18;
    updateVisibility();
  });

  updateVisibility();
</script>
{{ end }}

代码中包括了页面元素和加载更多数据的 js 代码,并且在页面标题下添加了一个页面描述,方便在 markdown 文件中更改描述信息,也便于调整样式。同样页面中评分星级的命名 allstarlight 也是与之前豆瓣条目短代码一致,方便一起调整。

完成后在 custom.scss 中添加样式代码:

 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
// 电影海报墙样式
.posterwall-description {
  margin: 10px;
  text-align: center;
}
.movie-wall {
  display: grid;
  grid-template-columns: repeat(3, 1fr);
  grid-gap: 3px;
  padding: 3px;
}

.movie-item {
  width: 100%;
  margin-bottom: 0;
}

.movie-cover {
  position: relative;
  overflow: hidden;
  aspect-ratio: 2 / 3;
}

.movie-cover img {
  width: 100%;
  height: 100%;
  object-fit: cover;
  transition: transform 0.3s ease;
}

.movie-info {
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: rgba(0, 0, 0, 0.8);
  color: #fff;
  padding: 10px;
  opacity: 0;
  transition: opacity 0.3s ease;
  overflow: auto;
  display: flex;
  flex-direction: column;
  justify-content: center;
}

.movie-cover:hover img {
  transform: scale(1.1);
}

.movie-cover:hover .movie-info {
  opacity: 1;
}

#loadMore {
  display: block;
  margin: 20px auto;
  padding: 10px 20px;
  background-color: lighten($color-accent,0.1);
  color: white;
  border: none;
  cursor: pointer;
}

#loadMore:hover {
  background-color: gray;
}

.movie-info .movie-rating {
  display: flex;
  align-items: center;
  margin-top: 3px;
  margin-bottom: 3px;
}
.movie-info .movie-rating .rating .rating_nums {
  font-size: 1.0em;
  color: #fff;
}

.movie-info .movie-card {
  margin: 5px 0;
  font-size: 0.7em;
  color: #fff;
}

.movie-info .movie-comment {
  margin: 5px 0;
  font-size: 0.7em;
  color: #fff;
}

使用

content 目录下创建一个 posterwall.md 文件,Front Matter 信息填写如下,标题可描述可以自由更改:

1
2
3
4
5
---
title: 海报墙
layout: "posterwall"
description: "这里是我已观看电影的海报墙,数据来源于豆瓣。"
---

添加后就可以在配置文件中添加一个菜单页面来指向海报墙,最终效果可以访问 👉 观影页面

参考