neodb.social 是一个致力于为联邦宇宙居民提供一个自由开放互联的书籍、电影、音乐和游戏收藏评论空间。NeoDB的源代码来自NiceDB,NiceDB由里瓣社区众筹开发。

可以理解为开源版本的某瓣,具体使用参考官方教程(这里),数据迁移教程(这里)。

个人主页:lmm214@mastodon.social

最早听闻 NeoDB 来自 @eallion,那时某瓣标记记录还可以通过第三方 Docker API 和 GitHub Actions 获取调用。几天前,小伙伴发现图挂了一片一片一大片,哎,换轮子!

Hugo NeoDB 单条短代码

支持书、电影、剧集、游戏、播客,也支持豆瓣页面链接,源码见 shortcodes/neodb.html

7.8
进入社会工作至今的十年间,胡安焉走南闯北,辗转于广东、广西、云南、上海、北京等地,做过快递员、夜班拣货工人、便利店店员、保安、自行车店销售、服装店导购、加油站加油工……他将日常的点滴和工作的甘苦化作真诚的自述,记录了一个平凡人在生活中的辛劳、私心、温情、正气。 在物流公司夜间拣货的一年,给他留下了深刻的生理印记:“这份工作还会令人脾气变坏,因为长期熬夜以及过度劳累,人的情绪控制力会明显下降……我已经感到脑子不好使了,主要是反应变得迟钝,记忆力开始衰退。”在北京送快递的两年,他“把自己看作一个时薪30元的送货机器,一旦达不到额定产出值就恼羞成怒、气急败坏”…… 但他最终认识到,怀着怨恨的人生是不值得过的。这些在事后追忆中写成的工作经历,渗透着他看待生活和世界的态度与反思,旨在表达个人在有限的选择和局促的现实中,对生活意义的直面和肯定:生活中许多平凡隽永的时刻,要比现实困扰的方方面面对人生更具有决定意义。
book
8.8
演员过日子,举手投足就是一幕幕川剧,癫狂、苦涩、地道,烟火气刺鼻。百年的生活史,大大小小,就这样在舞台上下踉跄展开。
movie
7.9
该剧基于休·豪伊所著同名畅销科幻系列小说改编,设定在被破坏、有毒的未来,数百层楼深的一个巨大地下筒仓中存在一个 社区,男人和女人生活在一个充满规章制度的社会里,凡是和“出去”有关的一切都成为致命禁忌。 丽贝卡·弗格森饰演独立而勤奋的工程师朱丽叶,她也担任执行制作人。蒂姆·罗宾斯饰演IT主管伯纳德,加入了朱丽叶的队伍。
tv
9.4
《空洞骑士》是一部风格经典、跨越庞大且交错相通世界的 2D 动作冒险游戏。探索扭曲的洞穴、古老的城市和致命的废墟;对抗邪恶的生物,结识友好又奇异的臭虫;进入王国,去破解 远古谜题吧! 《空洞骑士》的世界以生动、多变的细节灵活展现,其洞穴里充满着奇异又可怕的生物,每个画面都以传统的 2D 风格手工打造。 你将发现的每一个新领域都非常独特和奇怪,充满了新的生物和角色。欣赏风景并发现隐藏在常规道路下的新奇迹。 如果你喜欢经典的游戏、可爱却又令人毛骨悚然的角色、史诗般的冒险和美丽的哥特式世界,《空洞骑士》在这里等你来战!
game
6.8
黑水公园是一档以电影、剧集、科幻、动漫为载体,畅谈人生的趣谈节目。(金花微信:zhaotie6969zhaotie;金花微博:黑水公园_金花)
podcast

如下调用(去除反斜杠):

\{\{< neodb "https://neodb.social/book/5SJvkuHNGL4XhBddW2J4EJ" >\}\}
\{\{< neodb "https://neodb.social/movie/1bgVODaWCBKlCQ1AuGlLzC" >\}\}
\{\{< neodb "https://neodb.social/tv/season/5es8Us1HHOhVz3UlLmTspr" >\}\}
\{\{< neodb "https://neodb.social/game/5pvs201VxbkldH4LOEtDVt" >\}\}
\{\{< neodb "https://neodb.social/podcast/5tlY7lSI0WfXcoHstz7u4S" >\}\}

豆瓣页面链接调用:

8.1
太白金星李长庚最近有点烦。 天庭和西天联合推出了“西天取经”的重大项目,他受命策划九九八十一难,确保唐僧能安全走完流程,平稳取经成佛。老神仙本以为一切尽在掌控中,谁知天大的麻烦才刚刚开始:费用报销、工作汇报、人事安排、各路大仙塞来的条子、各地妖怪暗藏的心思,捋不出的千头万缕,做不完的琐碎繁杂……当大闹天宫的真相重新浮出水面,牵扯出无数因果,李长庚发觉自己成就金仙的道路越加渺茫。 【编辑推荐】 这是每一个成年人应该重读的西游故事。 太白金星李长庚最近有点烦。天庭和西天联合推出了“西天取经”的重大项目,他受命策划九九八十一难,确保项目无虞。老神仙本以为一切尽在掌控中,谁知天大的麻烦才刚刚开始。 项目过程中,如何报销活动费用?如何写工作汇报?如何平衡不同上级的诉求?如何应对突发状况?如何解决人事纠纷?一系列问题在不改变经典著作《西游记》结局的基础上展开了丰富有趣的职场生态,即便李长庚锦囊无数,也不免常常陷入焦虑。 都说神仙要“超脱因果,太上忘情”,都说不要在职场里动感情,太白金星却说,“很多人间执念我们无法理解,但不代表那些痛苦就不存在。”即使得了“仙”“佛”之号,依旧抛不下一个人字,有人,就有抛不下的牵挂、因果与苦乐得失。 打碎无意义的追逐,才是真的得道。 延续《长安的荔枝》小开本双封设计,随书附10张著名画家施晓颉所绘创意插图。 【媒体推荐】 地下取经队伍降妖除魔百般威武,天上神界仙界各怀心思斗智斗勇。现代视角另类演绎西游故事,就算成仙也得讲究职场智慧。 ——《收获》杂志
book
\{\{< neodb "https://book.douban.com/subject/36328704/" >\}\}

首页「近期观影」和「近期阅读」

整体思路,通过 Cloudflare Workers 发起 Fetch 请求,这样可以避免 Access Token 暴露。

所以,如下三步走。

1. 获取 Access Token

参考 @eallion 《NeoDB 获取 Access Token》

2. 新建 Cloudflare Workers

worker.js 代码如下(记得修改密钥和绑定子域名):

const myBearer = '91…………………………………………wi'  //你的密钥

addEventListener('fetch', event => {
  event.respondWith(handleRequest(event.request))
})
 
async function handleRequest(request) {
  const url = new URL(request.url)
  const category = url.pathname.substring(1)
  console.log(category)
  let dbApiUrl = 'https://neodb.social/api/me/shelf/complete?category=' + category + '&page=1'
  return fetch(dbApiUrl ,{
    method:'get',
    headers: {
      'Accept': 'application/json',
      'Authorization': 'Bearer ' + myBearer
    }
  });
}

3. Hugo getJSON 调取

核心代码如下:

{{$movieitems := getJSON "https://db.immmmm.com/movie" }}
{{range $value := $movieitems.data}}
    {{ $item := $value.item }}
    {{ $item.title }}
    ……
{{end}}

https://db.immmmm.com/movie 获取到的数据其实是

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

相关代码备份

/* db-card -------- start*/
.db-card{margin:2rem 3rem;background:#fafafa;border-radius: 4px;box-shadow: 0 1px 2px rgb(0 0 0 / 25%), 0 0 1px rgb(0 0 0 / 25%)}
.db-card-subject{display: flex;align-items:flex-start;line-height:1.6;padding:12px;position:relative;}
.dark .db-card{background:#252627;}
.db-card-content {flex:1 1 auto;}
.db-card-post {width: 96px;margin-right: 15px;display: flex;flex: 0 0 auto;}
.db-card-title {margin-bottom: 5px;font-size: 18px;}
.db-card-title a{text-decoration: none!important}
.db-card-abstract,.db-card-comment{font-size:14px;overflow: hidden;max-height:3rem;}
.db-card-cate{position: absolute;top:0;right:0;background:#f99b01;padding:1px 8px;font-size:small;font-style:italic;border-radius:0 8px 0 8px;text-transform:capitalize;}
.db-card-post img{width: 96px!important;height: 96px!important;border-radius: 4px;-o-object-fit: cover;object-fit: cover;}
.rating{margin: 0 0 5px;font-size:13px;line-height: 1;display: flex;align-items: center;}
.rating .allstardark{position:relative;color: #f99b01;height: 16px;width: 80px;background-size: auto 100%;margin-right: 8px;background-repeat: repeat;background-image: url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiPjxwYXRoIGQ9Ik05MDguMSAzNTMuMWwtMjUzLjktMzYuOUw1NDAuNyA4Ni4xYy0zLjEtNi4zLTguMi0xMS40LTE0LjUtMTQuNS0xNS44LTcuOC0zNS0xLjMtNDIuOSAxNC41TDM2OS44IDMxNi4ybC0yNTMuOSAzNi45Yy03IDEtMTMuNCA0LjMtMTguMyA5LjMtMTIuMyAxMi43LTEyLjEgMzIuOS42IDQ1LjNsMTgzLjcgMTc5LjEtNDMuNCAyNTIuOWMtMS4yIDYuOS0uMSAxNC4xIDMuMiAyMC4zIDguMiAxNS42IDI3LjYgMjEuNyA0My4yIDEzLjRMNTEyIDc1NGwyMjcuMSAxMTkuNGM2LjIgMy4zIDEzLjQgNC40IDIwLjMgMy4yIDE3LjQtMyAyOS4xLTE5LjUgMjYuMS0zNi45bC00My40LTI1Mi45IDE4My43LTE3OS4xYzUtNC45IDguMy0xMS4zIDkuMy0xOC4zIDIuNy0xNy41LTkuNS0zMy43LTI3LTM2LjN6TTY2NC44IDU2MS42bDM2LjEgMjEwLjNMNTEyIDY3Mi43IDMyMy4xIDc3MmwzNi4xLTIxMC4zLTE1Mi44LTE0OUw0MTcuNiAzODIgNTEyIDE5MC43IDYwNi40IDM4MmwyMTEuMiAzMC43LTE1Mi44IDE0OC45eiIgZmlsbD0iI2Y5OWIwMSIvPjwvc3ZnPg==);
}
.rating .allstarlight{position: absolute;left: 0;color: #f99b01;height:16px;overflow: hidden;background-size: auto 100%;background-repeat: repeat;background-image: url(data:image/svg+xml;base64,PHN2ZyBjbGFzcz0iaWNvbiIgdmlld0JveD0iMCAwIDEwMjQgMTAyNCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB3aWR0aD0iMzIiIGhlaWdodD0iMzIiPjxwYXRoIGQ9Ik05MDguMSAzNTMuMWwtMjUzLjktMzYuOUw1NDAuNyA4Ni4xYy0zLjEtNi4zLTguMi0xMS40LTE0LjUtMTQuNS0xNS44LTcuOC0zNS0xLjMtNDIuOSAxNC41TDM2OS44IDMxNi4ybC0yNTMuOSAzNi45Yy03IDEtMTMuNCA0LjMtMTguMyA5LjMtMTIuMyAxMi43LTEyLjEgMzIuOS42IDQ1LjNsMTgzLjcgMTc5LjEtNDMuNCAyNTIuOWMtMS4yIDYuOS0uMSAxNC4xIDMuMiAyMC4zIDguMiAxNS42IDI3LjYgMjEuNyA0My4yIDEzLjRMNTEyIDc1NGwyMjcuMSAxMTkuNGM2LjIgMy4zIDEzLjQgNC40IDIwLjMgMy4yIDE3LjQtMyAyOS4xLTE5LjUgMjYuMS0zNi45bC00My40LTI1Mi45IDE4My43LTE3OS4xYzUtNC45IDguMy0xMS4zIDkuMy0xOC4zIDIuNy0xNy41LTkuNS0zMy43LTI3LTM2LjN6IiBmaWxsPSIjZjk5YjAxIi8+PC9zdmc+);}
@media (max-width:550px) {
	.db-card{margin:0.8rem 1rem;}
	.db-card-comment{display: none;}
}
/* db-card -------- end */
{{$movieitems := getJSON "https://db.immmmm.com/movie" }}
<div class="douban border-top sc-ksluID gFnzgG">
  <h3><a href="/movies/">近期观影</a></h3>
    <div class="items sc-dIsUp fIuTG">
        {{range $value := first 5 $movieitems.data}}
          {{ $item := $value.item }}
          {{ $itemRating := 0 }}{{ with $item.rating }}{{ $itemRating = . }}{{ end }}
          <div class="dfdORB">
            <div class="sc-hKFxyN HPRth"><div class="lazyload-wrapper"><img class="avatar" src="{{ $item.cover_image_url }}" referrer-policy="no-referrer" loading="lazy" alt=""  title="{{ $item.title }}" width="150" height="220"></div></div>
            <div class="sc-fujyAs eysHZq">
                <div class="rating"><span class="allstardark"><span class="allstarlight" style="width:{{ mul 10 $itemRating }}%"></span></span><span class="rating_nums">{{ $itemRating }}</span></div>
            </div>
            <div class="sc-iCoGMd kMthTr"><a rel="noreferrer" href="https://neodb.social{{ $item.url }}" target="_blank">{{ $item.title }}</a></div>
          </div>
        {{end}}
    </div>
</div>

{{$bookitems := getJSON "https://db.immmmm.com/book" }}
<div class="douban border-bottom sc-ksluID gFnzgG">
  <h3><a href="/books/">近期阅读</a></h3>
    <div class="items sc-dIsUp fIuTG">
        {{range $value := first 5 $bookitems.data}}
          {{ $item := $value.item }}
          {{ $itemRating := 0 }}{{ with $item.rating }}{{ $itemRating = . }}{{ end }}
          <div class="dfdORB">
            <div class="sc-hKFxyN HPRth"><div class="lazyload-wrapper"><img class="avatar" src="{{ $item.cover_image_url }}" referrer-policy="no-referrer" loading="lazy" alt=""  title="{{ $item.title }}" width="150" height="220"></div></div>
            <div class="sc-fujyAs eysHZq">
                <div class="rating"><span class="allstardark"><span class="allstarlight" style="width:{{ mul 10 $itemRating }}%"></span></span><span class="rating_nums">{{ $itemRating }}</span></div>
            </div>
            <div class="sc-iCoGMd kMthTr"><a rel="noreferrer" href="https://neodb.social{{ $item.url }}" target="_blank">{{ $item.title }}</a></div>
          </div>
        {{end}}
    </div>
</div>

后记

免费的就是贵啊,能用就用着先。