如何在 Gitea 上渲染 Jupyter Notebooks
本指南将展示如何配置外部渲染器以显示 Jupyter Notebooks。不过,本指南也适用于其他类型的文件,甚至二进制文件!只有想不到,没有做不到。
Gitea 如何原生显示 .ipynb 文件
让我们在 Gitea 实例上创建一个新仓库,并向其中推送一个 示例 notebook:

如我们所见,Gitea 只是渲染文件的原始内容——高效但难以阅读。
如何生成用于显示的 HTML
为了向用户显示更有吸引力的内容,我们需要一些 HTML,幸运的是 Jupyter 有一个名为 nbconvert 的模块:
在 Gitea 机器上安装我们选择的转换软件:
sudo apt install python3-pip
pip3 install nbconvert
如果需要,我们可以通过运行测试命令来测试:
jupyter nbconvert --to html --template full path/to/some/test/notebook.ipynb
如果我们在浏览器中打开生成的 .html 文件,会看到类似这样的内容:

看起来很有希望……
配置 Gitea 使用转换器
与大多数选项一样,我们只需使用 app.ini 配置 Gitea 实例。
将其添加到 custom/conf/app.ini 中:
; Gitea looks for markup.xxxxx and will apply both "markup" and "xxxxx" as a class to the parent <div>
[markup.jupyter]
ENABLED = true
; all the file extensions we want to convert, comma separated.
FILE_EXTENSIONS = .ipynb
; Lets use out nbconvert command from earlier - making to sure to convert to HTML and to output to stdout
RENDER_COMMAND = "jupyter nbconvert --stdout --to html --template full "
; nbconvert accepts a path to a file and not stdin
IS_INPUT_FILE = true
; the name after sanitizer doesn't really matter
[markup.sanitizer.jupyter0]
; Jupyter chiefly uses divs
ELEMENT = div
; we will need access to html classes later
ALLOW_ATTR = class
; we don't mind which classes we keep, so let's keep all of them
REGEXP =
现在让我们看看重启 Gitea 后会得到什么。

如你所见,这更好了,但与之前打开 HTML 文件时不一样。这是因为 Gitea 出于安全需要移除了内联样式表。现有的样式继承自包裹代码的 <div> 中的 markup 类。
找回我们的样式
如果我们查看之前创建的 HTML 文件的内容,可以看到几个内联样式表
<style type="text/css">
/*!
*
* Twitter Bootstrap
*
*/
/*!
* Bootstrap v3.3.7 (http://getbootstrap.com)
* Copyright 2011-2016 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*! normalize.css v3.0.3 | MIT License | github.com/necolas/normalize.css */
html {
font-family: sans-serif;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
}
body {
margin: 0;
}
[...]
</stlye>
那么,让我们把所有样式表剥离出来,合并到一个 jupyter.less 中,确保删除所有类似 <style></style> 的 HTML 标签。现在我们有了一个包含所有漂亮样式的样式表。但它有很多通用选择器,例如:
body {
margin: 0;
}
这肯定与 Gitea 的默认样式冲突。所以我们需要确保限制样式的范围。幸运的是,Gitea 和 Less 可以帮助我们。
在 Less 中
.someclass {
body {
margin: 0;
}
summary {
display: block;
}
}
等价于 CSS:
.someclass body {
margin: 0;
}
.someclass summary {
display: block;
}
并且 Gitea 已经将 app.ini 中的 markup 和 jupyter 类赋予了包裹代码的 <div>。

那么,让我们把 jupyter.less 的全部内容包裹在 .markup.jupyter {} 中,生成类似 这样 的内容。
现在,让我们把这个文件放到我们的 'custom' 目录中,在我的例子中是 /root/custom/public/css/jupyter.less。
然后我添加到 /root/custom/templates/header.tmpl 中
<!-- lets import the less stylesheet {{AppSubUrl}} is a variable that gitea will autofill -->
<link rel="stylesheet/less" type="text/css" href="{{AppSubUrl}}/css/jupyter.less" />
<!-- we need the javascript to compile the less into css -->
<script src="//cdn.jsdelivr.net/npm/less" ></script>
现在让我们重启 Gitea,看看会得到什么。
使用 .markup.jupyter 自定义样式后的最终效果

看起来不错,但我们遇到了一些文本溢出边框边缘的问题。这是由一些麻烦的 CSS at-rules 引起的,所以让我们从 jupyter.less 中删除以下内容
@media (min-width: 768px) {
.container {
width: 768px;
}
}
@media (min-width: 992px) {
.container {
width: 940px;
}
}
@media (min-width: 1200px) {
.container {
width: 1140px;
}
}

大功告成!样式完美的 Jupyter Notebooks。
