Integrate NeoDB page in Hugo

This article explains how to create a movie viewing page in Hugo using the NeoDB API and Shortcode.

NeoDB is dedicated to providing a free and open interconnected space for residents of the federated universe to collect and review books, movies, music, and games.

– NeoDB

What is NeoDB

NeoDB

NeoDB is a decentralized, open-source community platform that supports a variety of collections including books, movies, series, podcasts, games, and performances.

Compared to DouBan in China, NeoDB:

  • Has no censorship system and no ads.
  • Offers a more comprehensive collection of foreign books and niche content.
  • Data can be easily imported from DouBan and also exported.

Fetching Data from NeoDB via API

NeoDB offers an open API to access users’ book and movie records.

Usage of API
  • URL: https://neodb.social/api/me/shelf
  • Bearer Token required.
  • Specify Path Variable type as one of wishlist, progress, complete
  • (Optional) Specify Query Param category as one of book, movie, tv, podcast, music, game, performance
  • (Optional) Specify Query Param page for pagination

For example: https://neodb.social/api/me/shelf/complete?category=book&page=1

To get the Access Token:NeoDB Developer#How to authorize, or generate a Test Access Token for testing.

For convenience and to encapsulate TOKEN information, the API retrieval can be deployed as a Cloudflare Worker.

 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
const myBearer = NEODB_TOKEN; // Assuming 'NEODB_TOKEN' is set in your Cloudflare Worker's environment variables

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})

async function handleRequest(request) {
  try {
    console.log(myBearer)
    const url = new URL(request.url);
    const category = url.pathname.substring(1);

    // Optionally, handle query parameters (e.g., page number)
    const page = url.searchParams.get('page') || '1';
    // Available values : wishlist, progress, complete
    const type = url.searchParams.get('type') || 'complete';

    let dbApiUrl = `https://neodb.social/api/me/shelf/${type}?category=${category}&page=${page}`;
    const response = await fetch(dbApiUrl, {
      method: 'get',
      headers: {
        'Accept': 'application/json',
        'Authorization': `Bearer ${myBearer}`
      }
    });

    // Check if the response from the API is OK (status code 200-299)
    if (!response.ok) {
      throw new Error(`API returned status ${response.status}`);
    }

    // Optionally, modify or just forward the API's response
    const data = await response.json();
    return new Response(JSON.stringify(data), {
      headers: { 'Content-Type': 'application/json' },
      status: response.status
    });

  } catch (error) {
    // Handle any errors that occurred during the fetch
    return new Response(error.message, { status: 500 });
  }
}

Integrating Data into Hugo with Hugo Shortcode

Create neodb.html in /layouts/shortcodes, replacing with your Cloudflare Worker URL:

 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
<!--Available categories: book, movie, tv, podcast, music, game, performance-->
{{ $category := .Get 0 }}
<!--Available types: wishlist, progress, complete-->
{{ $type := .Get 1 }}

{{ if eq $type "" }}
{{ $type = "complete" }}
{{ end }}

{{ $url := printf "https://your-worker-url/%s?type=%s" $category $type }}

{{ $json := getJSON $url}}

<div class="item-gallery">
    {{ range $value := first 10 $json.data }}
    {{ $item := $value.item }}
    <div class="item-card">
        <a class="item-card-upper" href="{{ $item.id }}" target="_blank" rel="noreferrer">
            <img class="item-cover" src="{{ .item.cover_image_url }}" alt="{{ .item.display_title }}">
        </a>
        {{ if .item.rating }}
        <div class="rate">
            <span><b>{{ .item.rating }}</b>🌟</span>
            <br>
            <span class="rating-count"> {{.item.rating_count}}人评分</span>
        </div>
        {{ else}}
        <div class="rate">
            <span>暂无🌟</span>
            <br>
            <span class="rating-count"> {{.item.rating_count}}人评分</span>
        </div>
        {{ end }}
        <h3 class="item-title">{{ .item.display_title }}</h3>
    </div>
    {{ end }}
</div>

<style>
    .item-gallery {
        display: flex;
        padding: 0 1rem;
        overflow-x: scroll;
        align-items: baseline;
    }

    .item-card {
        display: flex;
        flex-direction: column;
        flex: 0 0 17%;
        margin: 0 0.5rem 1rem;
        border-radius: 5px;
        transition: transform 0.2s;
        width: 8rem;
    }

    .item-card:hover {
        transform: translateY(-5px);
    }

    .rate {
        text-align: center;
    }

    .rating-count {
        font-size: 0.8rem;
        color: grey;
    }

    .item-cover {
        width: 100%;
        min-height: 3rem;
        border: 2px solid transparent;
    }

    .item-title {
        font-size: 1rem;
        text-align: center;
        margin: 0;
    }

</style>

Then use the shortcode in your page:

1
2
3
4
5
6
7
8
9
(Remove `\` below)

## Books Want to Read

\{\{< neodb book wishlist>\}\}

## Books Have read

\{\{< neodb book complete>\}\}

Sample Effect

NeoDB Sample

0%