15 Commits

24 changed files with 499 additions and 217 deletions

1
.gitignore vendored
View File

@@ -1 +1,2 @@
.hugo_build.lock .hugo_build.lock
tags

3
.gitmodules vendored
View File

@@ -1,3 +1,6 @@
[submodule "public"] [submodule "public"]
path = public path = public
url = https://gitea.balki.me/balki/blog-op url = https://gitea.balki.me/balki/blog-op
[submodule "themes/mytheme"]
path = themes/mytheme
url = https://gitea.balki.me/balki/no-js-hugo-theme.git

View File

@@ -1,21 +1,20 @@
ASCIINEMA_VERSION=3.7.1 .PHONY: pulltheme
pulltheme:
.PHONY: update-bootstrap git -C themes/mytheme pull
update-bootstrap:
curl -L "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/css/bootstrap.min.css" -o static/assets/bootstrap.min.css
curl -L "https://cdn.jsdelivr.net/npm/bootstrap@5/dist/js/bootstrap.min.js" -o static/assets/bootstrap.min.js
.PHONY: update-asciinema
update-asciinema:
curl -L "https://github.com/asciinema/asciinema-player/releases/download/v$(ASCIINEMA_VERSION)/asciinema-player.css" -o static/assets/asciinema-player.css
curl -L "https://github.com/asciinema/asciinema-player/releases/download/v$(ASCIINEMA_VERSION)/asciinema-player.min.js" -o static/assets/asciinema-player.min.js
.PHONY: deploy .PHONY: deploy
deploy: deploy:
rsync -av public desk:/var/www/balki.me git -C public push
ssh desk git -C /var/www/balki.me/public pull
.PHONY: build
build: build:
rm -rf public/*
hugo --logLevel debug hugo --logLevel debug
.PHONY: serve
serve: serve:
hugo server -D --bind "0.0.0.0" --navigateToChanged hugo server -D --bind "0.0.0.0" --navigateToChanged -p 2323
tags:
~/projects/mine/hugotags/hugotags.sh ~/projects/notmine/hugoDocs/content/en > tags

View File

@@ -1,3 +0,0 @@
baseURL: http://balki.me/
languageCode: en-us
title: Balki's Blog

View File

@@ -1,9 +1,11 @@
--- ---
title: "Home" title: "Home"
date: 2023-05-31T09:14:56-04:00 date: 2023-05-31T09:14:56-04:00
draft: false
--- ---
Balki's Blog Just another dev blog.
============
* git: https://gitea.balki.me/balki
* github: https://github.com/balki
* Fediverse: {{< myfedilink >}} `@balki@balki.me`
* RSS: https://blog.balki.me/index.xml

View File

@@ -10,3 +10,26 @@ asciinema: true
{{< asciinema key="demo" >}} {{< asciinema key="demo" >}}
There should be a asciinema cast above! There should be a asciinema cast above!
{{< details title="Click to see sample json" >}}
```json
{
"external_tracker_url": "https://github.com/caddyserver/caddy/issues",
"external_tracker_format": "https://github.com/caddyserver/caddy/issues/{index}",
"external_tracker_style": "numeric",
"external_tracker_regexp_pattern": ""
}
```
{{< /details >}}
SWBrqK9fAC6XuZ7eUl3xwnW8SOfekv01TntKdNl/0+noC4Xel+A2elveBYSxh4gWBtMqXR0mT7+8
N1jVF/o/Q19m8JF8UC9SiJP01CGDJoROcN2ijdyguLg76A0B2tltU+eqlbm46Pml+Ukndda1wxdY
eWs1favc/qsN2txx5jL/6srrEEVIKr3p6ov4hOVtju0dswaseknxZagMfaBwbk6KNGS9r5Nmk+MY
0jdYOfcBIHGB/IxvifV+ux5l/C7VK/PBFOm6t/qtVbczDiPtzngOcsR/CQOej5Qfi+2mXEVbci53
GMois/cjJF4vSU7/OcdxCkkLpN42UKyFOPiR3TczXrsM0kt1Zl/y8huf9KLkRC61MD2Zn/FOvl4U
Jsd9CsVNqN2DO5ABxHqSJ5oI9d03rJilWFunJ6jURH8CyfQv5vJ8ORQmMZdBF1DaeXm6K7/R26lY
ArRpYtgWNhzDWhyGSM2E3/XGvE1w4iZ/u8ml8K6R+tInxYRd1+6ScdTr0NgweuXbnk/27G66+NVv
LX3t9d+rWvwdJBzibimLzy6Rnxq6XO1CSmBVTagr4edyJe76GqSS2RMhk3zbdUyP5gyPrYyCDQn5
/0rQsHmzGd9izC6Gjuk7hu10Y3eWi5DCfrDGfyrADO90uYqXrW2tjliwdRJuZtSuRxbOVaY3G3UX
MPG6pRH/byyKTduN2RS4VNo73ZkQOOooQ3NQErGPc29yeWdvLoA7DB5rsMf7V0XZcpLrUVM6SoQf
<!-- vim: set lw=DETAILS_FDM: -->

View File

@@ -0,0 +1,209 @@
---
title: "Mirroring git repositories with Gitea"
date: 2024-06-27T10:05:46-04:00
draft: true
tags:
- gitea
- curl
- yq
categories:
- development
---
[Gitea][1] is an awesome self hosted git forge. I use the [pull-mirror][2]
feature to mirror many git repos (mostly from github). In this post, I want to
share few maintenance scripts I ran that connects to [gitea-api][14] using
[yq][] and [curl][].
<!--more-->
# TODO
* Change mirror interval
* Disable for mirror repos by default actions
* use jo https://github.com/jpmens/jo
* get just latest mirror and apply the settings
## Setup
### API token
Go to `https://gitea.balki.me/user/settings/applications` and Generate new
Token with write permission for repositories.
# TODO
set base url
## Why Mirror?
1. Remote sites may disappear one day.
2. Better local code search. Github does not allow code search without signing
in.
3. Tools like vim-plugins can use the local urls which is better for privacy.
4. Setup notification when a repository creates a new tag.
## Dumb crawlers problem
My gitea [instance][3] is public and had all mirror repos public as well. This
caused a huge network traffic from bots.
I created an [organization][4] without public visibility and made it own all
the mirror repos.
```
yq --version
yq (https://github.com/mikefarah/yq/) version v4.44.1
curl -V | head -c 11
curl 8.8.0
```
## API token
## Hooks for notification
[Hooks][5]
Lets first download the list of all mirror repos
```bash
TOKEN=d88446542e844f4da4ba75bbb85bd694a71907b5
curl "https://gitea.balki.me/api/v1/repos/search?limit=100&mode=mirror" \
-H "accept: application/json" \
-H "Authorization: token $TOKEN" \
-o mirror-repos.json
```
References
1. API doc: https://gitea.balki.me/api/swagger#/repository/repoSearch
Create a [hook][5] manually in one repo and get the hook using the API
```bash
curl -s "https://gitea.balki.me/api/v1/repos/MirrorWatch/snac2/hooks?page=1&limit=10" \
-H "Authorization: token $TOKEN" | yq -P -oj
```
Sample Output:
```json
[
{
"id": 32,
"type": "telegram",
"branch_filter": "tag",
"config": {
"content_type": "json",
"url": "https://api.telegram.org/bot1169894068:J1JVbV3f2vEQpdnPqFANfhjWZrFuUCJs1EW/sendMessage?chat_id=-1008910751069"
},
"events": [
"create"
],
"authorization_header": "",
"active": true,
"updated_at": "2024-06-20T20:54:33-04:00",
"created_at": "2024-06-20T20:54:33-04:00"
}
]
```
Now loop through all mirror repos and add the same webook. Remove unwanted fields like `id`, `created_at`, etc.,
```bash
yq -r '.data[] | .full_name' mirror-repos.json | while read -r repo; do
echo "$repo"
curl "https://gitea.balki.me/api/v1/repos/$repo/hooks" \
-H "Authorization: token $TOKEN" \
--json @- <<-EOM
{
"active": true,
"branch_filter": "tag",
"config": {
"content_type": "json",
"url": "https://api.telegram.org/bot1169894068:J1JVbV3f2vEQpdnPqFANfhjWZrFuUCJs1EW/sendMessage?chat_id=-1008910751069"
},
"events": [
"create"
],
"type": "telegram"
}
EOM
echo "============"
done
```
## Fixing issues and pr links
Fix the issue url setting in first repo as shown [here][7].
Get the json representataion.
```bash
yq '.data[] | .external_tracker ' mirror-repos.json | head
```
Sample output
```json
{
"external_tracker_url": "https://github.com/caddyserver/caddy/issues",
"external_tracker_format": "https://github.com/caddyserver/caddy/issues/{index}",
"external_tracker_style": "numeric",
"external_tracker_regexp_pattern": ""
}
```
Now loop throug all repos and update. Making sure only add to github repos and
they are not already updated
```bash
yq -r '.data[]
| select(.original_url == "*github*" and has("internal_tracker") )
| "\(.full_name) \(.original_url)"' mirror-repos.json | while read -r repo og; do
echo "Repo is $repo and github origin url is $og"
curl "https://gitea.balki.me/api/v1/repos/$repo" \
-H "Authorization: token $TOKEN" \
-X PATCH \
--json @- <<-EOM
{
"external_tracker": {
"external_tracker_url": "${og%.git}/issues",
"external_tracker_format": "${og%.git}/issues/{index}",
"external_tracker_style": "numeric",
"external_tracker_regexp_pattern": ""
}
}
EOM
done
yq -r '.data[] | .full_name' mirror-repos.json | while read -r repo; do
echo "$repo"
jo has_actions=false | curl "https://gitea.balki.me/api/v1/repos/$repo" \
-H "Authorization: token $TOKEN" \
-X PATCH \
--json @-
done
```
### Doc links
* yq: [select][8], [has][9], [string interpolation][10]
* bash: [parameter expansion][11], [here-doc][12]
* curl: [`--json`][13]
[1]: https://github.com/go-gitea/gitea
[2]: https://docs.gitea.com/usage/repo-mirror#pulling-from-a-remote-repository
[3]: https://gitea.balki.me
[4]: https://docs.gitea.com/usage/permissions#organization-repository
[5]: https://docs.gitea.com/usage/webhooks
[6]: https://docs.gitea.com/development/api-usage
[7]: https://github.com/go-gitea/gitea/issues/18986
[8]: https://mikefarah.gitbook.io/yq/operators/select
[9]: https://mikefarah.gitbook.io/yq/operators/has#select-checking-for-existence-of-deep-paths
[10]: https://mikefarah.gitbook.io/yq/operators/string-operators#interpolation
[11]: https://www.gnu.org/software/bash/manual/html_node/Shell-Parameter-Expansion.html
[12]: https://www.gnu.org/software/bash/manual/html_node/Redirections.html#Here-Documents
[13]: https://everything.curl.dev/http/post/json.html
[14]: https://gitea.balki.me/api/swagger#/repository/repoSearch

View File

@@ -0,0 +1,7 @@
---
title: "Revive Blog"
date: 2025-05-29T18:26:59-04:00
draft: true
---
{{% gitea repo=balki/hugotags path=hugotags.sh lang=bash %}}

View File

@@ -0,0 +1,74 @@
---
title: "Securing communication between webserver and app"
date: 2024-04-19T17:31:06-04:00
tags:
- unix-sockets
- tmpfiles.d
- webserver
categories:
- sysadmin
---
Webapps usually listen on a random tcp port and a web server forwards the
requests to it. Webserver handles tls, static asset serving and sometimes
authentication, bruteforce check etc., However any local user in the system can
directly connect to the app's listen port bypassing the web server and thus
loose the protections offered by the webserver.
### Unix sockets
Unix sockets are special files in filesystem that processes can use to
communicate instead of tcp ports. Since they are files, filesytem ownership and
permissions can be used to restrict which system-users can listen or connect to
them
### Caddy ↔ Gitea
I use [Caddy][1] web server which reverse-proxies to [Gitea][2] server. For
caddy to connect to gitea and also disallow anyother user to connect, we want a
socket like below
```bash
srw-rw---- 1 gitea caddy 0 Apr 17 21:24 /run/gitea.sock
```
Unfortunately neither `user caddy` nor `user gitea`, can create such socket.
Regular users can only create files owned by themselves. Only root can
create/change ownership of files and folders.
### `tmpfiles.d` to rescue
[tmpfiles.d][3] provides a way to do it. Since it is run as root, it can create
files and directories as any user.
```bash
cat /etc/tmpfiles.d/caddy-run-unix.conf
d /run/gitea-caddy 0750 gitea caddy -
```
Above config creates below directory every time on startup.
```bash
sudo ls -ld /run/gitea-caddy/
drwxr-x--- 2 gitea caddy 60 Apr 17 21:24 /run/gitea-caddy/
```
With those permissions and ownership, only `user gitea` can create the socket
in `/run/gitea-caddy` and only `user caddy` can `cd` into that directory.
```bash
sudo ls -l /run/gitea-caddy/web.sock
srw-rw-rw- 1 gitea gitea 0 Apr 17 21:24 /run/gitea-caddy/web.sock
```
The socket file permission can be more liberal as no other user can read into
the `/run/gitea-caddy` directory
### Bonus!
If your app does not connect to any external services, it can even be run in a
[private network][4].
[1]: https://caddyserver.com
[2]: https://gitea.com
[3]: https://man.archlinux.org/man/tmpfiles.d.5
[4]: https://www.freedesktop.org/software/systemd/man/latest/systemd.exec.html#PrivateNetwork=

View File

@@ -15,7 +15,7 @@ categories:
Sometimes, fully automating a task is not worth the effort. So I end up running Sometimes, fully automating a task is not worth the effort. So I end up running
a set of commands usually from a cheat sheet text file slightly modifying the a set of commands usually from a cheat sheet text file slightly modifying the
arguments each time. I used the below in vim to send line under cursor to vim's arguments each time. I used the below in vim to send line under cursor to vim's
`:terminal` open in a split `:terminal` open in a split
```vim ```vim
:call term_list()[0]->term_sendkeys(getline('.') .. "\<CR>") :call term_list()[0]->term_sendkeys(getline('.') .. "\<CR>")
``` ```
@@ -101,7 +101,7 @@ autocmd BufNewFile,BufRead cheat.sh nnoremap <buffer> <silent><2-LeftMouse> :Sen
### Demo ### Demo
{{< asciinema key="vimstt" >}} {{< asciinema key="vimstt" poster="npt:0:23" startAt="0:18" >}}
### Using ### Using

32
hugo.yaml Normal file
View File

@@ -0,0 +1,32 @@
baseURL: https://blog.balki.me/
languageCode: en-us
title: Balki's Blog
theme: mytheme
markup:
highlight:
# This setting makes code highlighting use theme's colors instead of hugo's default
noClasses: false
params:
themeStyleSwitcher: true
footerText: "[theme](https://gitea.balki.me/balki/no-js-hugo-theme)"
showTagList: false
menu:
main:
- identifier: home
name: Home
pageRef: /
weight: 1
- identifier: gitea
name: Gitea
url: https://gitea.balki.me/balki
weight: 2
- identifier: github
name: Github
url: https://github.com/balki
weight: 3
- identifier: rss
name: RSS
url: https://blog.balki.me/index.xml
weight: 4

View File

@@ -1,58 +0,0 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta http-equiv="Content-Security-Policy" content="default-src 'self' 'unsafe-inline' data: ;{{ if .Params.asciinema }}script-src 'self' 'unsafe-inline' 'unsafe-eval';{{ end }}">
<link rel="alternate" type="application/rss+xml" href="/posts/index.xml">
<title>
{{- block "title" . -}}
{{ .Site.Title }}
{{- end -}}
</title>
<!-- Diable favicon requests: https://stackoverflow.com/a/13416784 -->
<link rel="icon" href="data:;base64,iVBORw0KGgo=">
<link href="/assets/bootstrap.min.css" rel="stylesheet" >
{{ if .Params.asciinema }}
<link rel="stylesheet" type="text/css" href="/assets/asciinema-player.css" />
{{ end }}
<style>
{{ block "styles" . }}
{{ end }}
div.highlight pre {
{{/* code highlighting */}}
padding: 1rem;
}
</style>
<script src="/assets/bootstrap.min.js" defer></script>
</head>
<body>
<div class="container" >
<aside>
<nav>
<ul class="nav">
<li class="nav-item"><a class="nav-link" href="/"> Home </a></li>
<li class="nav-item"><a class="nav-link" href="/posts"> Blog </a></li>
<li class="nav-item"><a class="nav-link" href="https://gitea.balki.me/balki"> Gitea </a></li>
<li class="nav-item"><a class="nav-link" href="https://github.com/balki"> Github </a></li>
<!-- TODO
<li class="nav-item"><a class="nav-link" href="/about"> About </a></li>
-->
</ul>
</nav>
</aside>
<main>
{{ block "main" . }}
{{ end }}
</main>
<hr>
<div style="height: 300px;"><!-- This space is intentionally left blank --></div>
</div>
</body>
</html>

View File

@@ -1,6 +0,0 @@
{{ define "main" }}
<h1 class="text-center">Posts</h1>
{{ range .Pages }}
{{ partial "postcard" . }}
{{ end }}
{{ end }}

View File

@@ -1,24 +0,0 @@
{{ define "title" }}
{{ .Title }} &ndash; {{ .Site.Title }}
{{ end }}
{{ define "main" }}
<article>
<h1 class="display-3 text-center">{{ .Title }}</h1>
<p class="text-center"><time datetime="{{ .Date }}">{{ .Date.Format "2006-01-02" }}</time>
{{ if .Params.tags }}
{{range .Params.tags}}
<a class="btn btn-primary" href="/tags/{{ . | urlize }}" role="button">{{ . }}</a>
{{end}}
{{end}}
{{ if .Params.categories }}
{{range .Params.categories}}
<a class="btn btn-secondary" href="/categories/{{ . | urlize }}" role="button">{{ . }}</a>
{{end}}
{{end}}
</p>
{{ .Content }}
</article>
{{ end }}

View File

@@ -0,0 +1,12 @@
{{- $url := "" -}}
{{- with .Get "url" -}}
{{- $url = . -}}
{{- else -}}
{{- $url = urls.JoinPath "http://gitea.balki.me" (.Get "repo") "raw/branch/main" (.Get "path") -}}
{{- end -}}
```{{ .Get "lang" }}
{{ with resources.GetRemote $url }}
{{- .Content -}}
{{ end }}
```
[source]({{ $url }})

View File

@@ -0,0 +1 @@
<a href="https://social.balki.me/@balki" rel="me" >https://social.balki.me/@balki</a>

View File

@@ -1,16 +0,0 @@
{{ define "main" }}
<article>
<div class="text-center m-4">
{{ .Content }}
</div>
<p class="text-center">Under construction. Come back later! :)</p>
<div>
<h4>Recent posts</h4>
{{ range .Pages }}
{{ range .Pages }}
{{ partial "postcard" . }}
{{ end }}
{{ end }}
</div>
</article>
{{ end }}

View File

@@ -1,12 +0,0 @@
{{ define "styles" }}
a.title-link {
text-decoration: none;
}
{{ end }}
<div class="card mb-4">
<div class="card-body">
<a class="title-link link-primary" href="{{ .RelPermalink }}" ><h3 class="card-title">{{ .Title }}</h3></a>
<p> {{ .Date.Format "2006-01-02" }} </p>
<p class="card-text"> {{ .Summary }} </p>
</div>
</div>

View File

@@ -1,20 +0,0 @@
<div id='{{ with .Get "key" }}{{ . }}{{ end }}'></div>
<script src="/assets/asciinema-player.min.js"></script>
<script>
AsciinemaPlayer.create('/casts/{{ with .Get "key" }}{{ . }}{{ end }}.cast', document.getElementById('{{ with .Get "key" }}{{ . }}{{ end }}'), {
{{ if .Get "cols" }}cols: "{{ .Get "cols" }}",{{ end }}
{{ if .Get "rows" }}rows: "{{ .Get "rows" }}",{{ end }}
{{ if .Get "autoPlay" }}autoPlay: "{{ .Get "autoPlay" }}",{{ end }}
{{ if .Get "preload" }}preload: "{{ .Get "preload" }}",{{ end }}
{{ if .Get "loop" }}loop: "{{ .Get "loop" }}",{{ end }}
{{ if .Get "startAt" }}startAt: "{{ .Get "startAt" }}",{{ end }}
{{ if .Get "speed" }}speed: "{{ .Get "speed" }}",{{ end }}
{{ if .Get "idleTimeLimit" }}idleTimeLimit: "{{ .Get "idleTimeLimit" }}",{{ end }}
{{ if .Get "theme" }}theme: "{{ .Get "theme" }}",{{ end }}
{{ if .Get "poster" }}poster: "{{ .Get "poster" }}",{{ end }}
{{ if .Get "fit" }}fit: "{{ .Get "fit" }}",{{ end }}
{{ if .Get "terminalFontSize" }}terminalFontSize: "{{ .Get "terminalFontSize" }}",{{ end }}
{{ if .Get "terminalFontFamily" }}terminalFontFamily: "{{ .Get "terminalFontFamily" }}",{{ end }}
{{ if .Get "terminalLineHeight" }}terminalLineHeight: "{{ .Get "terminalLineHeight" }}",{{ end }}
});
</script>

2
public

Submodule public updated: 2810706e99...e03e9e4c2c

View File

@@ -36,9 +36,6 @@ div.ap-wrapper:fullscreen {
width: 100%; width: 100%;
align-items: center; align-items: center;
} }
div.ap-wrapper:fullscreen div.ap-player {
position: static;
}
div.ap-wrapper:fullscreen .title-bar { div.ap-wrapper:fullscreen .title-bar {
display: initial; display: initial;
} }
@@ -200,6 +197,7 @@ pre.ap-terminal {
background-color: var(--term-color-background); background-color: var(--term-color-background);
border-color: var(--term-color-background); border-color: var(--term-color-background);
outline: none; outline: none;
line-height: var(--term-line-height);
font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols'; font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols';
font-variant-ligatures: none; font-variant-ligatures: none;
} }
@@ -215,10 +213,12 @@ pre.ap-terminal .ap-line span {
pre.ap-terminal .ap-line { pre.ap-terminal .ap-line {
display: block; display: block;
width: 100%; width: 100%;
height: var(--term-line-height);
position: relative; position: relative;
} }
pre.ap-terminal .ap-line span { pre.ap-terminal .ap-line span {
position: absolute; position: absolute;
left: calc(100% * var(--offset) / var(--term-cols));
color: var(--fg); color: var(--fg);
background-color: var(--bg); background-color: var(--bg);
} }
@@ -227,35 +227,35 @@ pre.ap-terminal .ap-line .ap-inverse {
background-color: var(--fg); background-color: var(--fg);
} }
pre.ap-terminal .ap-line .cp-2580 { pre.ap-terminal .ap-line .cp-2580 {
border-top: calc(0.5em * var(--term-line-height)) solid var(--fg); border-top: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2581 { pre.ap-terminal .ap-line .cp-2581 {
border-bottom: calc(0.125em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.125 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2582 { pre.ap-terminal .ap-line .cp-2582 {
border-bottom: calc(0.25em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.25 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2583 { pre.ap-terminal .ap-line .cp-2583 {
border-bottom: calc(0.375em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.375 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2584 { pre.ap-terminal .ap-line .cp-2584 {
border-bottom: calc(0.5em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2585 { pre.ap-terminal .ap-line .cp-2585 {
border-bottom: calc(0.625em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.625 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2586 { pre.ap-terminal .ap-line .cp-2586 {
border-bottom: calc(0.75em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.75 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2587 { pre.ap-terminal .ap-line .cp-2587 {
border-bottom: calc(0.875em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.875 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2588 { pre.ap-terminal .ap-line .cp-2588 {
@@ -303,7 +303,7 @@ pre.ap-terminal .ap-line .cp-2593 {
background-color: color-mix(in srgb, var(--fg) 75%, var(--bg)); background-color: color-mix(in srgb, var(--fg) 75%, var(--bg));
} }
pre.ap-terminal .ap-line .cp-2594 { pre.ap-terminal .ap-line .cp-2594 {
border-top: calc(0.125em * var(--term-line-height)) solid var(--fg); border-top: calc(0.125 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2595 { pre.ap-terminal .ap-line .cp-2595 {
@@ -312,25 +312,25 @@ pre.ap-terminal .ap-line .cp-2595 {
} }
pre.ap-terminal .ap-line .cp-2596 { pre.ap-terminal .ap-line .cp-2596 {
border-right: 0.5ch solid var(--bg); border-right: 0.5ch solid var(--bg);
border-top: calc(0.5em * var(--term-line-height)) solid var(--bg); border-top: calc(0.5 * var(--term-line-height)) solid var(--bg);
background-color: var(--fg); background-color: var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2597 { pre.ap-terminal .ap-line .cp-2597 {
border-left: 0.5ch solid var(--bg); border-left: 0.5ch solid var(--bg);
border-top: calc(0.5em * var(--term-line-height)) solid var(--bg); border-top: calc(0.5 * var(--term-line-height)) solid var(--bg);
background-color: var(--fg); background-color: var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2598 { pre.ap-terminal .ap-line .cp-2598 {
border-right: 0.5ch solid var(--bg); border-right: 0.5ch solid var(--bg);
border-bottom: calc(0.5em * var(--term-line-height)) solid var(--bg); border-bottom: calc(0.5 * var(--term-line-height)) solid var(--bg);
background-color: var(--fg); background-color: var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-2599 { pre.ap-terminal .ap-line .cp-2599 {
border-left: 0.5ch solid var(--fg); border-left: 0.5ch solid var(--fg);
border-bottom: calc(0.5em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-259a { pre.ap-terminal .ap-line .cp-259a {
@@ -341,7 +341,7 @@ pre.ap-terminal .ap-line .cp-259a::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 0.5ch; width: 0.5ch;
height: calc(0.5em * var(--term-line-height)); height: calc(0.5 * var(--term-line-height));
background-color: var(--fg); background-color: var(--fg);
} }
pre.ap-terminal .ap-line .cp-259a::before { pre.ap-terminal .ap-line .cp-259a::before {
@@ -354,17 +354,17 @@ pre.ap-terminal .ap-line .cp-259a::after {
} }
pre.ap-terminal .ap-line .cp-259b { pre.ap-terminal .ap-line .cp-259b {
border-left: 0.5ch solid var(--fg); border-left: 0.5ch solid var(--fg);
border-top: calc(0.5em * var(--term-line-height)) solid var(--fg); border-top: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-259c { pre.ap-terminal .ap-line .cp-259c {
border-right: 0.5ch solid var(--fg); border-right: 0.5ch solid var(--fg);
border-top: calc(0.5em * var(--term-line-height)) solid var(--fg); border-top: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-259d { pre.ap-terminal .ap-line .cp-259d {
border-left: 0.5ch solid var(--bg); border-left: 0.5ch solid var(--bg);
border-bottom: calc(0.5em * var(--term-line-height)) solid var(--bg); border-bottom: calc(0.5 * var(--term-line-height)) solid var(--bg);
background-color: var(--fg); background-color: var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
@@ -376,7 +376,7 @@ pre.ap-terminal .ap-line .cp-259e::after {
content: ''; content: '';
position: absolute; position: absolute;
width: 0.5ch; width: 0.5ch;
height: calc(0.5em * var(--term-line-height)); height: calc(0.5 * var(--term-line-height));
background-color: var(--fg); background-color: var(--fg);
} }
pre.ap-terminal .ap-line .cp-259e::before { pre.ap-terminal .ap-line .cp-259e::before {
@@ -389,19 +389,19 @@ pre.ap-terminal .ap-line .cp-259e::after {
} }
pre.ap-terminal .ap-line .cp-259f { pre.ap-terminal .ap-line .cp-259f {
border-right: 0.5ch solid var(--fg); border-right: 0.5ch solid var(--fg);
border-bottom: calc(0.5em * var(--term-line-height)) solid var(--fg); border-bottom: calc(0.5 * var(--term-line-height)) solid var(--fg);
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-e0b0 { pre.ap-terminal .ap-line .cp-e0b0 {
border-left: 1ch solid var(--fg); border-left: 1ch solid var(--fg);
border-top: calc(0.5em * var(--term-line-height)) solid transparent; border-top: calc(0.5 * var(--term-line-height)) solid transparent;
border-bottom: calc(0.5em * var(--term-line-height)) solid transparent; border-bottom: calc(0.5 * var(--term-line-height)) solid transparent;
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal .ap-line .cp-e0b2 { pre.ap-terminal .ap-line .cp-e0b2 {
border-right: 1ch solid var(--fg); border-right: 1ch solid var(--fg);
border-top: calc(0.5em * var(--term-line-height)) solid transparent; border-top: calc(0.5 * var(--term-line-height)) solid transparent;
border-bottom: calc(0.5em * var(--term-line-height)) solid transparent; border-bottom: calc(0.5 * var(--term-line-height)) solid transparent;
box-sizing: border-box; box-sizing: border-box;
} }
pre.ap-terminal.ap-cursor-on .ap-line .ap-cursor { pre.ap-terminal.ap-cursor-on .ap-line .ap-cursor {
@@ -441,8 +441,7 @@ div.ap-player div.ap-control-bar {
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
align-items: stretch; align-items: stretch;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0.5) 0%, #000000 25%, #000000 100%); color: var(--term-color-foreground);
color: #bbb;
box-sizing: content-box; box-sizing: content-box;
line-height: 1; line-height: 1;
position: absolute; position: absolute;
@@ -451,19 +450,17 @@ div.ap-player div.ap-control-bar {
opacity: 0; opacity: 0;
transition: opacity 0.15s linear; transition: opacity 0.15s linear;
user-select: none; user-select: none;
border-top: 2px solid color-mix(in oklab, black 33%, var(--term-color-background));
z-index: 30; z-index: 30;
} }
div.ap-player div.ap-control-bar * { div.ap-player div.ap-control-bar * {
box-sizing: inherit; box-sizing: inherit;
font-size: 0;
font-family: Helvetica, Arial, sans-serif;
font-weight: bold;
} }
div.ap-control-bar svg.ap-icon path { div.ap-control-bar svg.ap-icon path {
fill: #bbb; fill: var(--term-color-foreground);
} }
div.ap-control-bar span.ap-playback-button { div.ap-control-bar span.ap-playback-button {
display: block; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
cursor: pointer; cursor: pointer;
height: 12px; height: 12px;
@@ -475,19 +472,21 @@ div.ap-control-bar span.ap-playback-button svg {
width: 12px; width: 12px;
} }
div.ap-control-bar span.ap-timer { div.ap-control-bar span.ap-timer {
display: block; display: flex;
flex: 0 0 auto; flex: 0 0 auto;
min-width: 50px; min-width: 50px;
margin: 0 10px; margin: 0 10px;
height: 100%; height: 100%;
text-align: center; text-align: center;
font-size: 11px; font-size: 13px;
line-height: 34px; line-height: 100%;
cursor: default; cursor: default;
} }
div.ap-control-bar span.ap-timer span { div.ap-control-bar span.ap-timer span {
display: inline-block; font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace;
font-size: inherit; font-size: inherit;
font-weight: 600;
margin: auto;
} }
div.ap-control-bar span.ap-timer .ap-time-remaining { div.ap-control-bar span.ap-timer .ap-time-remaining {
display: none; display: none;
@@ -496,7 +495,7 @@ div.ap-control-bar span.ap-timer:hover .ap-time-elapsed {
display: none; display: none;
} }
div.ap-control-bar span.ap-timer:hover .ap-time-remaining { div.ap-control-bar span.ap-timer:hover .ap-time-remaining {
display: inline; display: flex;
} }
div.ap-control-bar .ap-progressbar { div.ap-control-bar .ap-progressbar {
display: block; display: block;
@@ -518,14 +517,15 @@ div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter {
left: 0; left: 0;
right: 0; right: 0;
height: 3px; height: 3px;
background-color: #333;
} }
div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter .ap-gutter-fill { div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter-empty {
display: inline-block; background-color: color-mix(in oklab, var(--term-color-foreground) 20%, var(--term-color-background));
height: 100%; }
background-color: #bbb; div.ap-control-bar .ap-progressbar .ap-bar .ap-gutter-full {
width: 100%;
transform-origin: left center;
background-color: var(--term-color-foreground);
border-radius: 3px; border-radius: 3px;
z-index: 10;
} }
div.ap-control-bar.ap-seekable .ap-progressbar .ap-bar { div.ap-control-bar.ap-seekable .ap-progressbar .ap-bar {
cursor: pointer; cursor: pointer;
@@ -537,24 +537,30 @@ div.ap-control-bar .ap-fullscreen-button {
height: 14px; height: 14px;
padding: 9px; padding: 9px;
cursor: pointer; cursor: pointer;
position: relative;
} }
div.ap-control-bar .ap-fullscreen-button svg { div.ap-control-bar .ap-fullscreen-button svg {
width: 14px; width: 14px;
height: 14px; height: 14px;
} }
div.ap-control-bar .ap-fullscreen-button svg:first-child { div.ap-control-bar .ap-fullscreen-button svg.ap-icon-fullscreen-on {
display: inline; display: inline;
} }
div.ap-control-bar .ap-fullscreen-button svg:last-child { div.ap-control-bar .ap-fullscreen-button svg.ap-icon-fullscreen-off {
display: none; display: none;
} }
div.ap-control-bar .ap-fullscreen-button .ap-tooltip {
right: 5px;
left: initial;
transform: none;
}
div.ap-wrapper.ap-hud .ap-control-bar { div.ap-wrapper.ap-hud .ap-control-bar {
opacity: 1; opacity: 1;
} }
div.ap-wrapper:fullscreen .ap-fullscreen-button svg:first-child { div.ap-wrapper:fullscreen .ap-fullscreen-button svg.ap-icon-fullscreen-on {
display: none; display: none;
} }
div.ap-wrapper:fullscreen .ap-fullscreen-button svg:last-child { div.ap-wrapper:fullscreen .ap-fullscreen-button svg.ap-icon-fullscreen-off {
display: inline; display: inline;
} }
span.ap-progressbar span.ap-marker-container { span.ap-progressbar span.ap-marker-container {
@@ -564,7 +570,6 @@ span.ap-progressbar span.ap-marker-container {
width: 21px; width: 21px;
position: absolute; position: absolute;
margin-left: -10px; margin-left: -10px;
z-index: 9;
} }
span.ap-marker-container span.ap-marker { span.ap-marker-container span.ap-marker {
display: block; display: block;
@@ -572,40 +577,42 @@ span.ap-marker-container span.ap-marker {
bottom: 12px; bottom: 12px;
left: 7px; left: 7px;
right: 7px; right: 7px;
background-color: #555; background-color: color-mix(in oklab, var(--term-color-foreground) 33%, var(--term-color-background));
position: absolute; position: absolute;
transition: top 0.1s, bottom 0.1s, left 0.1s, right 0.1s, background-color 0.1s; transition: top 0.1s, bottom 0.1s, left 0.1s, right 0.1s, background-color 0.1s;
border-radius: 50%; border-radius: 50%;
} }
span.ap-marker-container span.ap-marker.ap-marker-past { span.ap-marker-container span.ap-marker.ap-marker-past {
background-color: #bbb; background-color: var(--term-color-foreground);
} }
span.ap-marker-container span.ap-marker:hover, span.ap-marker-container span.ap-marker:hover,
span.ap-marker-container:hover span.ap-marker { span.ap-marker-container:hover span.ap-marker {
background-color: #bbb; background-color: var(--term-color-foreground);
top: 11px; top: 11px;
bottom: 10px; bottom: 10px;
left: 5px; left: 5px;
right: 5px; right: 5px;
} }
span.ap-marker-container span.ap-marker-tooltip { .ap-tooltip-container span.ap-tooltip {
visibility: hidden; visibility: hidden;
background-color: #333; background-color: var(--term-color-foreground);
color: #bbb; color: var(--term-color-background);
font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace;
font-weight: bold;
text-align: center; text-align: center;
padding: 2px 8px 0px 8px; padding: 0 0.5em;
border-radius: 4px; border-radius: 4px;
position: absolute; position: absolute;
z-index: 1; z-index: 1;
white-space: nowrap; white-space: nowrap;
/* Prevents the text from wrapping and makes sure the tooltip width adapts to the text length */ /* Prevents the text from wrapping and makes sure the tooltip width adapts to the text length */
font-size: 11px; font-size: 13px;
line-height: 2em; line-height: 2em;
bottom: 100%; bottom: 100%;
left: 50%; left: 50%;
transform: translateX(-50%); transform: translateX(-50%);
} }
span.ap-marker-container:hover span.ap-marker-tooltip { .ap-tooltip-container:hover span.ap-tooltip {
visibility: visible; visibility: visible;
} }
.ap-player .ap-overlay { .ap-player .ap-overlay {
@@ -680,6 +687,56 @@ span.ap-marker-container:hover span.ap-marker-tooltip {
display: inline-block; display: inline-block;
height: 100%; height: 100%;
} }
.ap-player .ap-overlay-help {
background-color: rgba(0, 0, 0, 0.8);
container-type: inline-size;
}
.ap-player .ap-overlay-help > div {
font-family: Consolas, Menlo, 'Bitstream Vera Sans Mono', monospace, 'Powerline Symbols';
font-variant-ligatures: none;
max-width: 85%;
max-height: 85%;
font-size: 18px;
color: var(--term-color-foreground);
background-color: var(--term-color-background);
border-radius: 6px;
box-sizing: border-box;
margin-bottom: 32px;
}
.ap-player .ap-overlay-help > div .ap-line {
letter-spacing: normal;
overflow: hidden;
}
.ap-player .ap-overlay-help > div .ap-line span {
padding: 0;
display: inline-block;
height: 100%;
}
.ap-player .ap-overlay-help > div div {
padding: calc(min(4cqw, 40px));
font-size: calc(min(1.9cqw, 18px));
}
.ap-player .ap-overlay-help > div div p {
font-weight: bold;
margin: 0 0 2em 0;
}
.ap-player .ap-overlay-help > div div ul {
list-style: none;
padding: 0;
}
.ap-player .ap-overlay-help > div div ul li {
margin: 0 0 0.75em 0;
}
.ap-player .ap-overlay-help > div div kbd {
color: var(--term-color-background);
background-color: var(--term-color-foreground);
padding: 0.2em 0.5em;
border-radius: 0.2em;
font-family: inherit;
font-size: 0.85em;
border: none;
margin: 0;
}
.ap-player .ap-overlay-error span { .ap-player .ap-overlay-error span {
font-size: 8em; font-size: 8em;
} }

File diff suppressed because one or more lines are too long

1
themes/mytheme Submodule

Submodule themes/mytheme added at da512608d9