dorothea 1.9.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- dorothea-1.9.0/.gitattributes +7 -0
- dorothea-1.9.0/.github/workflows/ci.yml +84 -0
- dorothea-1.9.0/.github/workflows/release.yml +45 -0
- dorothea-1.9.0/.gitignore +55 -0
- dorothea-1.9.0/.pre-commit-config.yaml +38 -0
- dorothea-1.9.0/CONFIG.md +124 -0
- dorothea-1.9.0/LICENSE.txt +21 -0
- dorothea-1.9.0/MIGRATION.md +86 -0
- dorothea-1.9.0/Makefile +63 -0
- dorothea-1.9.0/PKG-INFO +303 -0
- dorothea-1.9.0/pyproject.toml +112 -0
- dorothea-1.9.0/readme.md +278 -0
- dorothea-1.9.0/src/dorothea/__init__.py +15 -0
- dorothea-1.9.0/src/dorothea/__main__.py +6 -0
- dorothea-1.9.0/src/dorothea/builder.py +369 -0
- dorothea-1.9.0/src/dorothea/cache.py +145 -0
- dorothea-1.9.0/src/dorothea/cli.py +147 -0
- dorothea-1.9.0/src/dorothea/config.py +379 -0
- dorothea-1.9.0/src/dorothea/encoder.py +800 -0
- dorothea-1.9.0/src/dorothea/generator.py +245 -0
- dorothea-1.9.0/src/dorothea/media/__init__.py +16 -0
- dorothea-1.9.0/src/dorothea/media/base.py +23 -0
- dorothea-1.9.0/src/dorothea/media/colors.py +45 -0
- dorothea-1.9.0/src/dorothea/media/colors_imagemagick.py +45 -0
- dorothea-1.9.0/src/dorothea/media/colors_pillow.py +58 -0
- dorothea-1.9.0/src/dorothea/media/ffmpeg.py +70 -0
- dorothea-1.9.0/src/dorothea/media/image.py +165 -0
- dorothea-1.9.0/src/dorothea/media/markdown.py +68 -0
- dorothea-1.9.0/src/dorothea/media/video.py +67 -0
- dorothea-1.9.0/src/dorothea/scanner.py +401 -0
- dorothea-1.9.0/src/dorothea/template.py +79 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/cookie.js +117 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/global.css +669 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/global.js +643 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/camera.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/camera_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/close.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/comment.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/comment_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/download.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/download_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/facebook.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/facebook_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/hackernews.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/hackernews_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/heart.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/heart_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/monitor.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/monitor_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/next.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/pinterest.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/pinterest_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/prev.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/reddit.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/reddit_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/text.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/text_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/twitter.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/img/twitter_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/json.js +1 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/post-template.html +11 -0
- dorothea-1.9.0/src/dorothea/themes/theme1/template.html +94 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/global.css +422 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/global.js +246 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/camera.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/camera_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/close.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/comment.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/comment_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/download.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/download_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/facebook.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/facebook_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/hackernews.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/hackernews_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/heart.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/heart_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/monitor.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/monitor_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/next.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/pinterest.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/pinterest_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/prev.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/reddit.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/reddit_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/text.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/text_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/twitter.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/img/twitter_mask.png +0 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/post-template.html +11 -0
- dorothea-1.9.0/src/dorothea/themes/theme2/template.html +69 -0
- dorothea-1.9.0/src/dorothea/themes.py +44 -0
- dorothea-1.9.0/src/dorothea/utils.py +54 -0
- dorothea-1.9.0/tests/__init__.py +0 -0
- dorothea-1.9.0/tests/conftest.py +90 -0
- dorothea-1.9.0/tests/data/test_run/01_Nature/01_Mountains/01_peak.jpg +0 -0
- dorothea-1.9.0/tests/data/test_run/01_Nature/01_Mountains/01_peak.txt +3 -0
- dorothea-1.9.0/tests/data/test_run/01_Nature/02_Oceans/01_wave.jpg +0 -0
- dorothea-1.9.0/tests/data/test_run/01_Nature/02_Oceans/01_wave.txt +4 -0
- dorothea-1.9.0/tests/data/test_run/02_Urban/01_city.jpg +0 -0
- dorothea-1.9.0/tests/data/test_run/02_Urban/01_city.txt +4 -0
- dorothea-1.9.0/tests/reference/Markdown_1.0.1/License.text +30 -0
- dorothea-1.9.0/tests/reference/Markdown_1.0.1/Markdown Readme.text +341 -0
- dorothea-1.9.0/tests/reference/Markdown_1.0.1/Markdown.pl +1450 -0
- dorothea-1.9.0/tests/reference/expose.sh +980 -0
- dorothea-1.9.0/tests/reference/oldexpose.py +1552 -0
- dorothea-1.9.0/tests/reference/test_parity.sh +207 -0
- dorothea-1.9.0/tests/test_download.py +126 -0
- dorothea-1.9.0/tests/test_edge_cases.py +156 -0
- dorothea-1.9.0/tests/test_final_parity.py +263 -0
- dorothea-1.9.0/tests/test_integration.py +312 -0
- dorothea-1.9.0/tests/test_main.py +171 -0
- dorothea-1.9.0/tests/test_more_coverage.py +183 -0
- dorothea-1.9.0/tests/test_parity.py +320 -0
- dorothea-1.9.0/tests/test_pure.py +93 -0
- dorothea-1.9.0/tests/test_video.py +387 -0
- dorothea-1.9.0/tests/unit/__init__.py +1 -0
- dorothea-1.9.0/tests/unit/media/__init__.py +1 -0
- dorothea-1.9.0/tests/unit/media/test_colors.py +196 -0
- dorothea-1.9.0/tests/unit/media/test_image.py +146 -0
- dorothea-1.9.0/tests/unit/media/test_markdown.py +53 -0
- dorothea-1.9.0/tests/unit/media/test_markdown_parity.py +87 -0
- dorothea-1.9.0/tests/unit/media/test_video.py +159 -0
- dorothea-1.9.0/tests/unit/test_cache.py +195 -0
- dorothea-1.9.0/tests/unit/test_config.py +232 -0
- dorothea-1.9.0/tests/unit/test_config_sh.py +113 -0
- dorothea-1.9.0/tests/unit/test_encoder_parallel.py +167 -0
- dorothea-1.9.0/tests/unit/test_parity_fixes.py +84 -0
- dorothea-1.9.0/tests/unit/test_template.py +256 -0
- dorothea-1.9.0/tests/unit/test_utils.py +134 -0
- dorothea-1.9.0/uv.lock +266 -0
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
name: CI
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
pull_request:
|
|
6
|
+
|
|
7
|
+
concurrency:
|
|
8
|
+
group: ${{ github.workflow }}-${{ github.ref }}
|
|
9
|
+
cancel-in-progress: true
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
lint:
|
|
13
|
+
name: Lint (ruff, format, ty)
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
- uses: actions/setup-python@v7
|
|
18
|
+
with:
|
|
19
|
+
python-version: "3.14"
|
|
20
|
+
- uses: astral-sh/setup-uv@v7
|
|
21
|
+
- run: uv sync
|
|
22
|
+
- run: uvx prek run --all-files --show-diff-on-failure
|
|
23
|
+
|
|
24
|
+
test-full:
|
|
25
|
+
# Everything installed, including expose.sh's own dependencies, so the parity tests
|
|
26
|
+
# run. Arch ships ImageMagick 7 and ffmpeg with x264 (like the dev machine); Ubuntu's
|
|
27
|
+
# ImageMagick 6 picks different JPEG chroma subsampling than the one we match.
|
|
28
|
+
name: Tests + parity (ImageMagick, ffmpeg, perl)
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
container: archlinux:latest
|
|
31
|
+
steps:
|
|
32
|
+
- name: Install system packages
|
|
33
|
+
run: >-
|
|
34
|
+
pacman -Syu --noconfirm --needed
|
|
35
|
+
git make bash which file rsync perl imagemagick ffmpeg uv
|
|
36
|
+
- uses: actions/checkout@v7
|
|
37
|
+
- run: uv sync
|
|
38
|
+
- run: make test-cov
|
|
39
|
+
|
|
40
|
+
test-minimal:
|
|
41
|
+
# No ffmpeg or ImageMagick on the system: proves `uv tool install` needs nothing else
|
|
42
|
+
# (the bundled imageio-ffmpeg binary and Pillow are used). Parity tests skip here.
|
|
43
|
+
name: Tests without system packages
|
|
44
|
+
runs-on: ubuntu-latest
|
|
45
|
+
container: ghcr.io/astral-sh/uv:python3.14-bookworm-slim
|
|
46
|
+
steps:
|
|
47
|
+
- uses: actions/checkout@v7
|
|
48
|
+
- name: Check the environment really is minimal
|
|
49
|
+
run: |
|
|
50
|
+
! command -v ffmpeg
|
|
51
|
+
! command -v convert
|
|
52
|
+
! command -v magick
|
|
53
|
+
- run: uv sync
|
|
54
|
+
- run: uv run pytest -m "not slow" --no-cov
|
|
55
|
+
|
|
56
|
+
package:
|
|
57
|
+
# Build the wheel and sdist and run them the way users will (`uvx dorothea`,
|
|
58
|
+
# `pipx run dorothea`), outside the source tree, with no ffmpeg or ImageMagick installed.
|
|
59
|
+
# Catches what the test suite can't: themes missing from the package, broken entry
|
|
60
|
+
# points, dependencies missing from pyproject.toml.
|
|
61
|
+
name: Package (uvx, pipx)
|
|
62
|
+
runs-on: ubuntu-latest
|
|
63
|
+
container: ghcr.io/astral-sh/uv:python3.14-bookworm-slim
|
|
64
|
+
steps:
|
|
65
|
+
- uses: actions/checkout@v7
|
|
66
|
+
- run: uv build
|
|
67
|
+
- name: Entry points
|
|
68
|
+
run: |
|
|
69
|
+
wheel=$(ls dist/*.whl)
|
|
70
|
+
uvx --isolated --from "$wheel" dorothea --version
|
|
71
|
+
uvx --isolated --from "$wheel" expose --version
|
|
72
|
+
uvx pipx run --no-cache --spec "$wheel" dorothea --version
|
|
73
|
+
- name: Build a gallery from the wheel and from the sdist
|
|
74
|
+
run: |
|
|
75
|
+
for dist in dist/*.whl dist/*.tar.gz; do
|
|
76
|
+
gallery=$(mktemp -d)
|
|
77
|
+
cp -r tests/data/test_run/. "$gallery"
|
|
78
|
+
rm -rf "$gallery/_site"
|
|
79
|
+
(cd "$gallery" && uvx --isolated --from "$GITHUB_WORKSPACE/$dist" dorothea -d)
|
|
80
|
+
test -s "$gallery/_site/index.html"
|
|
81
|
+
test -s "$gallery/_site/global.css"
|
|
82
|
+
test -s "$gallery/_site/nature/mountains/peak/1024.jpg"
|
|
83
|
+
echo "OK: $dist"
|
|
84
|
+
done
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
name: Release
|
|
2
|
+
|
|
3
|
+
# Publishes to PyPI when a GitHub release is published (tag like v1.9.0).
|
|
4
|
+
# Uses PyPI trusted publishing: no API token is stored in the repository. One-time setup on
|
|
5
|
+
# pypi.org: add a (pending) trusted publisher for project "dorothea" with owner
|
|
6
|
+
# "marcolussetti", repository "dorothea", workflow "release.yml", environment "pypi".
|
|
7
|
+
|
|
8
|
+
on:
|
|
9
|
+
release:
|
|
10
|
+
types: [published]
|
|
11
|
+
|
|
12
|
+
jobs:
|
|
13
|
+
build:
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
steps:
|
|
16
|
+
- uses: actions/checkout@v7
|
|
17
|
+
- uses: astral-sh/setup-uv@v7
|
|
18
|
+
- name: Check the tag matches the package version
|
|
19
|
+
env:
|
|
20
|
+
TAG: ${{ github.event.release.tag_name }}
|
|
21
|
+
run: |
|
|
22
|
+
version=$(uv version --short)
|
|
23
|
+
if [ "$TAG" != "v$version" ]; then
|
|
24
|
+
echo "Release tag $TAG does not match pyproject version v$version" >&2
|
|
25
|
+
exit 1
|
|
26
|
+
fi
|
|
27
|
+
- run: uv build
|
|
28
|
+
- uses: actions/upload-artifact@v7
|
|
29
|
+
with:
|
|
30
|
+
name: dist
|
|
31
|
+
path: dist/
|
|
32
|
+
|
|
33
|
+
publish:
|
|
34
|
+
needs: build
|
|
35
|
+
runs-on: ubuntu-latest
|
|
36
|
+
environment: pypi
|
|
37
|
+
permissions:
|
|
38
|
+
id-token: write # trusted publishing
|
|
39
|
+
steps:
|
|
40
|
+
- uses: actions/download-artifact@v7
|
|
41
|
+
with:
|
|
42
|
+
name: dist
|
|
43
|
+
path: dist/
|
|
44
|
+
- uses: astral-sh/setup-uv@v7
|
|
45
|
+
- run: uv publish --trusted-publishing always
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Windows image file caches
|
|
2
|
+
Thumbs.db
|
|
3
|
+
ehthumbs.db
|
|
4
|
+
|
|
5
|
+
# Folder config file
|
|
6
|
+
Desktop.ini
|
|
7
|
+
|
|
8
|
+
# Recycle Bin used on file shares
|
|
9
|
+
$RECYCLE.BIN/
|
|
10
|
+
|
|
11
|
+
# Windows Installer files
|
|
12
|
+
*.cab
|
|
13
|
+
*.msi
|
|
14
|
+
*.msm
|
|
15
|
+
*.msp
|
|
16
|
+
|
|
17
|
+
# Windows shortcuts
|
|
18
|
+
*.lnk
|
|
19
|
+
|
|
20
|
+
# =========================
|
|
21
|
+
# Operating System Files
|
|
22
|
+
# =========================
|
|
23
|
+
|
|
24
|
+
# OSX
|
|
25
|
+
# =========================
|
|
26
|
+
|
|
27
|
+
.DS_Store
|
|
28
|
+
.AppleDouble
|
|
29
|
+
.LSOverride
|
|
30
|
+
|
|
31
|
+
# Thumbnails
|
|
32
|
+
._*
|
|
33
|
+
|
|
34
|
+
# Files that might appear on external disk
|
|
35
|
+
.Spotlight-V100
|
|
36
|
+
.Trashes
|
|
37
|
+
|
|
38
|
+
# Directories potentially created on remote AFP share
|
|
39
|
+
.AppleDB
|
|
40
|
+
.AppleDesktop
|
|
41
|
+
Network Trash Folder
|
|
42
|
+
Temporary Items
|
|
43
|
+
.apdisk
|
|
44
|
+
|
|
45
|
+
# Python
|
|
46
|
+
__pycache__/
|
|
47
|
+
*.pyc
|
|
48
|
+
.venv/
|
|
49
|
+
_site/
|
|
50
|
+
plans/
|
|
51
|
+
|
|
52
|
+
# Personal gallery (local test data, not part of the project)
|
|
53
|
+
knowneuropean-photos/
|
|
54
|
+
.coverage
|
|
55
|
+
htmlcov/
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Pre-commit configuration for dorothea
|
|
2
|
+
# Excludes legacy theme files and expose.sh
|
|
3
|
+
|
|
4
|
+
# Hooks that parse Python (debug-statements) must run on the project's minimum version (3.14)
|
|
5
|
+
default_language_version:
|
|
6
|
+
python: python3.14
|
|
7
|
+
|
|
8
|
+
repos:
|
|
9
|
+
- repo: https://github.com/pre-commit/pre-commit-hooks
|
|
10
|
+
rev: v4.5.0
|
|
11
|
+
hooks:
|
|
12
|
+
- id: trailing-whitespace
|
|
13
|
+
exclude: ^(theme1/|theme2/|Markdown_1.0.1/|expose.sh)
|
|
14
|
+
- id: end-of-file-fixer
|
|
15
|
+
exclude: ^(theme1/|theme2/|Markdown_1.0.1/|expose.sh)
|
|
16
|
+
- id: check-yaml
|
|
17
|
+
- id: check-added-large-files
|
|
18
|
+
args: ['--maxkb=2000']
|
|
19
|
+
- id: check-merge-conflict
|
|
20
|
+
- id: debug-statements
|
|
21
|
+
|
|
22
|
+
- repo: https://github.com/astral-sh/ruff-pre-commit
|
|
23
|
+
rev: v0.16.9 # keep in sync with pyproject.toml dev group
|
|
24
|
+
hooks:
|
|
25
|
+
- id: ruff-check
|
|
26
|
+
args: [--fix, --exit-non-zero-on-fix]
|
|
27
|
+
exclude: ^(theme1/|theme2/|Markdown_1.0.1/|expose.sh)
|
|
28
|
+
- id: ruff-format
|
|
29
|
+
exclude: ^(theme1/|theme2/|Markdown_1.0.1/|expose.sh)
|
|
30
|
+
|
|
31
|
+
- repo: local
|
|
32
|
+
hooks:
|
|
33
|
+
- id: ty
|
|
34
|
+
name: ty check
|
|
35
|
+
entry: uv run ty check src
|
|
36
|
+
language: system
|
|
37
|
+
types: [python]
|
|
38
|
+
pass_filenames: false
|
dorothea-1.9.0/CONFIG.md
ADDED
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
# Dorothea configuration
|
|
2
|
+
|
|
3
|
+
Settings are read, in increasing order of precedence, from:
|
|
4
|
+
|
|
5
|
+
1. built-in defaults (below, the same as expose.sh's)
|
|
6
|
+
2. `_config.json` in the gallery folder, or `--config FILE` (`.json` or `.sh`). Without a
|
|
7
|
+
`_config.json`, expose.sh's `_config.sh` is read instead (see [MIGRATION.md](MIGRATION.md))
|
|
8
|
+
3. `--set KEY=VALUE` and `-j N` on the command line
|
|
9
|
+
4. draft mode (`-d`), which forces `resolution=[1024]`, `bitrate=[4]`, `video_formats=["h264"]`
|
|
10
|
+
and `download_button=false`
|
|
11
|
+
|
|
12
|
+
```json
|
|
13
|
+
{
|
|
14
|
+
"site_title": "Iceland 2022",
|
|
15
|
+
"theme_dir": "theme2",
|
|
16
|
+
"resolution": [2560, 1920, 1280, 640],
|
|
17
|
+
"jpeg_quality": 88
|
|
18
|
+
}
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Invalid values stop the build with a message naming each problem (exit code 2); unknown keys
|
|
22
|
+
only print a warning, since they're usually typos.
|
|
23
|
+
|
|
24
|
+
Changing a setting that affects image or video bytes (resolution, quality, bitrates, codec
|
|
25
|
+
speed, per-post options...) re-encodes just the affected files on the next run. There's no need
|
|
26
|
+
to delete `_site`.
|
|
27
|
+
|
|
28
|
+
## Site and theme
|
|
29
|
+
|
|
30
|
+
| Key | Default | Description |
|
|
31
|
+
|---|---|---|
|
|
32
|
+
| `site_title` | `"My Awesome Photos"` | Site name shown in every page. |
|
|
33
|
+
| `theme_dir` | `"theme1"` | Theme: a bundled one (`theme1`, `theme2`), a folder of that name in the gallery, or an absolute path. |
|
|
34
|
+
| `text_toggle` | `true` | Show a button to hide/show the text. |
|
|
35
|
+
| `social_button` | `true` | Show the social sharing button. |
|
|
36
|
+
| `disqus_shortname` | `""` | Disqus forum name for comments; empty disables them. |
|
|
37
|
+
|
|
38
|
+
## Images
|
|
39
|
+
|
|
40
|
+
| Key | Default | Description |
|
|
41
|
+
|---|---|---|
|
|
42
|
+
| `resolution` | `[3840, 2560, 1920, 1280, 1024, 640]` | Widths to generate (heights follow the source aspect ratio). Only sizes up to the source width are made, plus the smallest one always. |
|
|
43
|
+
| `jpeg_quality` | `92` | JPEG quality (1–100) for generated images. |
|
|
44
|
+
| `autorotate` | `true` | Apply EXIF orientation. |
|
|
45
|
+
|
|
46
|
+
## Colours
|
|
47
|
+
|
|
48
|
+
| Key | Default | Description |
|
|
49
|
+
|---|---|---|
|
|
50
|
+
| `extract_colors` | `true` | Extract a 7-colour palette from each photo/video for the theme (`color1`…`color7`, background, text). |
|
|
51
|
+
| `default_palette` | `["#000000", "#222222", "#444444", "#666666", "#999999", "#cccccc", "#ffffff"]` | Palette (background to foreground) used when `extract_colors` is false. |
|
|
52
|
+
| `backgroundcolor` | `"#000000"` | Slide background, visible before the image loads. |
|
|
53
|
+
| `textcolor` | `"#ffffff"` | Default text colour. |
|
|
54
|
+
| `override_textcolor` | `true` | Use `textcolor` for body text instead of the palette's last colour. |
|
|
55
|
+
|
|
56
|
+
## Video
|
|
57
|
+
|
|
58
|
+
Video needs ffmpeg: a system `ffmpeg` on `PATH` is used if present, otherwise the one bundled
|
|
59
|
+
with Dorothea (imageio-ffmpeg).
|
|
60
|
+
|
|
61
|
+
| Key | Default | Description |
|
|
62
|
+
|---|---|---|
|
|
63
|
+
| `video_formats` | `["h264", "vp8"]` | Formats to encode, in order of preference: `h264`, `h265`, `vp9`, `vp8`, `ogv`. |
|
|
64
|
+
| `bitrate` | `[40, 24, 12, 7, 4, 2]` | Target bitrate in Mbit/s for each entry in `resolution` (the last value repeats if the list is shorter). |
|
|
65
|
+
| `bitrate_maxratio` | `2` | Max bitrate as a multiple of the target (VBR). Must be ≥ 1; 1 means constant bitrate. |
|
|
66
|
+
| `disable_audio` | `true` | Strip audio (otherwise it's copied as-is). |
|
|
67
|
+
| `h264_encodespeed` | `"veryslow"` | x264/x265 preset: `ultrafast` … `veryslow`. Slower compresses better. |
|
|
68
|
+
| `vp9_encodespeed` | `1` | VP9 speed, 0 (best, very slow) to 4 (fastest). |
|
|
69
|
+
| `ffmpeg_threads` | `0` | ffmpeg `-threads` (0 = auto). Lower it to throttle CPU use. |
|
|
70
|
+
| `sequence_keyword` | `"imagesequence"` | A folder whose name contains this is compiled into a video from its images. |
|
|
71
|
+
| `sequence_framerate` | `24` | Frame rate of compiled image sequences. |
|
|
72
|
+
|
|
73
|
+
## Downloads
|
|
74
|
+
|
|
75
|
+
| Key | Default | Description |
|
|
76
|
+
|---|---|---|
|
|
77
|
+
| `download_button` | `false` | Offer each original in a zip with a readme. |
|
|
78
|
+
| `download_readme` | `"All rights reserved"` | Text of the `readme.txt` in each zip. |
|
|
79
|
+
|
|
80
|
+
## Dorothea-only
|
|
81
|
+
|
|
82
|
+
| Key | Default | Description |
|
|
83
|
+
|---|---|---|
|
|
84
|
+
| `jobs` | `0` | Parallel workers for reading and resizing images (0 = one per CPU). Same as `-j N`. Videos always encode one at a time, since ffmpeg already uses every core. |
|
|
85
|
+
|
|
86
|
+
## Command line
|
|
87
|
+
|
|
88
|
+
| Flag | Description |
|
|
89
|
+
|---|---|
|
|
90
|
+
| `-d`, `--draft` | Draft mode: one 1024px size, fast h264 only. |
|
|
91
|
+
| `-n`, `--dry-run` | List what would be built (and why) without writing anything. |
|
|
92
|
+
| `-c FILE`, `--config FILE` | Use this config file (`.json` or expose.sh `.sh`). |
|
|
93
|
+
| `-s KEY=VALUE`, `--set KEY=VALUE` | Override a setting; VALUE is JSON if it parses (`--set 'resolution=[1920,640]'`), else a string. Repeatable. |
|
|
94
|
+
| `-j N`, `--jobs N` | Parallel workers (see `jobs`). |
|
|
95
|
+
| `--convert-config` | Write `_config.json` from `_config.sh` and exit. |
|
|
96
|
+
| `--version` | Print the version. |
|
|
97
|
+
|
|
98
|
+
## Per-post metadata
|
|
99
|
+
|
|
100
|
+
A text file next to a photo or video with the same name (`01 Glacier.txt` or `.md`) holds its
|
|
101
|
+
caption. Lines before a `---` line are `key: value` metadata; the rest is Markdown. A
|
|
102
|
+
`metadata.txt` in a gallery folder applies to every post in it, and a post's own metadata wins.
|
|
103
|
+
|
|
104
|
+
```
|
|
105
|
+
image-options: -modulate 100,120
|
|
106
|
+
top: 30
|
|
107
|
+
left: 5
|
|
108
|
+
---
|
|
109
|
+
Caption in *Markdown*.
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
| Key | Description |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `image-options` | Extra ImageMagick `convert` arguments for this photo (needs ImageMagick installed; otherwise ignored with a warning). Not applied to video thumbnails. |
|
|
115
|
+
| `video-options` | Extra ffmpeg arguments, e.g. `-ss 10 -t 5` to cut a clip. |
|
|
116
|
+
| `video-filters` | ffmpeg filters appended after scaling, e.g. `hflip`. |
|
|
117
|
+
| anything else | Available to the theme as `{{key}}`. theme1 uses `top`, `left`, `width`, `height` (percent), `polygon` and `textcolor`; theme2 uses `width` and `class`. `color1`…`color7` come from the extracted palette. |
|
|
118
|
+
|
|
119
|
+
## Build cache
|
|
120
|
+
|
|
121
|
+
Dorothea keeps `.dorothea-cache.json` in the gallery folder. It holds extracted palettes, so
|
|
122
|
+
unchanged photos aren't re-analysed, and a fingerprint for every generated file, so changed
|
|
123
|
+
sources, settings or metadata rebuild exactly what they affect. It's safe to delete: the next
|
|
124
|
+
run re-analyses the photos and keeps any existing output that's newer than its source.
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2015 Jack Qiao
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
# Migrating from expose.sh to Dorothea
|
|
2
|
+
|
|
3
|
+
Dorothea is a Python port of [expose.sh](https://github.com/Jack000/Expose). For the same
|
|
4
|
+
photos and settings it produces the same site: its test suite builds galleries with both and
|
|
5
|
+
checks that the file lists match, HTML/CSS/JS are byte-identical, and every image and video has
|
|
6
|
+
the same file size. This page covers what you need to change, and the places where Dorothea
|
|
7
|
+
deliberately behaves differently.
|
|
8
|
+
|
|
9
|
+
## Install
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
uvx dorothea # run without installing (or: pipx run dorothea)
|
|
13
|
+
uv tool install dorothea # install the command (or: pipx install dorothea)
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
No system packages are required: Pillow resizes images and an ffmpeg binary is bundled.
|
|
17
|
+
Optional:
|
|
18
|
+
|
|
19
|
+
- a system **ffmpeg** on `PATH` is preferred over the bundled one
|
|
20
|
+
- **ImageMagick** is used for colour extraction (identical palettes to expose.sh) and for
|
|
21
|
+
per-post `image-options`
|
|
22
|
+
|
|
23
|
+
Run it the same way as before, inside the gallery folder: `dorothea` or `dorothea -d`. The
|
|
24
|
+
command is also installed as `expose`, so `expose -d` keeps working.
|
|
25
|
+
|
|
26
|
+
## Configuration
|
|
27
|
+
|
|
28
|
+
Your `_config.sh` keeps working: without a `_config.json`, Dorothea reads it. It's parsed,
|
|
29
|
+
never executed, so only plain assignments are supported:
|
|
30
|
+
|
|
31
|
+
```sh
|
|
32
|
+
site_title="Iceland 2022" # quoted or unquoted values, comments
|
|
33
|
+
resolution=(2560 1920 1280 640) # arrays on one line
|
|
34
|
+
autorotate=false # true/false become booleans, numbers become numbers
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Anything else (`$(...)`, `${VAR}`, `export`, `if`) is skipped with a warning naming the line.
|
|
38
|
+
To switch to JSON, the recommended format:
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
dorothea --convert-config # writes _config.json from _config.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
If both files exist, `_config.json` wins. Every setting is described in
|
|
45
|
+
[CONFIG.md](CONFIG.md).
|
|
46
|
+
|
|
47
|
+
> **Note:** expose.sh ignores `resolution`, `bitrate`, `video_formats` and `default_palette` set
|
|
48
|
+
> in `_config.sh` (it reassigns them after reading the file). Dorothea honours them, so a
|
|
49
|
+
> gallery that set them will now actually use those values.
|
|
50
|
+
|
|
51
|
+
## New in Dorothea
|
|
52
|
+
|
|
53
|
+
- **Incremental builds that notice changes.** expose.sh skips any output that already exists,
|
|
54
|
+
so edits needed a manual `rm -rf _site`. Dorothea rebuilds exactly the files whose source,
|
|
55
|
+
settings or per-post metadata changed. State lives in `.dorothea-cache.json` in the gallery
|
|
56
|
+
folder, which also caches colour palettes so re-runs are fast. An existing `_site` from
|
|
57
|
+
expose.sh is adopted as-is, and files newer than their source aren't re-encoded.
|
|
58
|
+
- `-n` / `--dry-run` lists what would be built and why.
|
|
59
|
+
- `--set KEY=VALUE` overrides a setting for one run; `--config FILE` picks a config file.
|
|
60
|
+
- `-j N` resizes images in parallel (default: one worker per CPU).
|
|
61
|
+
- Config values are validated, with a clear error instead of a broken build.
|
|
62
|
+
- A failed or interrupted encode never leaves a truncated file behind; it's retried next run.
|
|
63
|
+
- A corrupt photo is reported and skipped instead of aborting the build.
|
|
64
|
+
|
|
65
|
+
## Intentional differences
|
|
66
|
+
|
|
67
|
+
These are places where expose.sh has a bug or a platform quirk that Dorothea doesn't copy:
|
|
68
|
+
|
|
69
|
+
| expose.sh | Dorothea |
|
|
70
|
+
|---|---|
|
|
71
|
+
| Skips hidden folders only at the top level (`.foo/`). | Skips hidden folders at any depth (`gallery/.thumbs/`). |
|
|
72
|
+
| An image sequence mixing formats (JPEG + PNG) or extensions (`.JPG` + `.jpg`) silently loses frames. | Every frame is used; mixed formats are converted to lossless PNG first. |
|
|
73
|
+
| Download zips for image sequences fail (it `cp`s the folder). | The zip contains the compiled sequence video. |
|
|
74
|
+
| Unknown video extensions are checked with `file -ib`, using a path relative to the wrong directory, so effectively never. | Detected from the file extension's MIME type. |
|
|
75
|
+
| Leaves `ffmpeg2pass-*.log` in the current folder while encoding. | Keeps 2-pass logs in a temporary folder. |
|
|
76
|
+
| A non-text or non-UTF-8 caption file is skipped (`file` check). | Same, with a warning. Captions are always read and written as UTF-8. |
|
|
77
|
+
| Requires ImageMagick and `zip`; video needs ffmpeg and ffprobe. | Needs nothing beyond `pip`/`uv`; ffprobe isn't used. |
|
|
78
|
+
|
|
79
|
+
Caption Markdown is rendered by python-markdown and normalized to match expose.sh's
|
|
80
|
+
Markdown.pl output. One exception: Markdown.pl obfuscates email autolinks (`<me@x.com>`) with
|
|
81
|
+
random character entities, which by design can't be reproduced. Both versions display the same
|
|
82
|
+
address.
|
|
83
|
+
|
|
84
|
+
Resized JPEGs are made by Pillow rather than ImageMagick. File sizes match ImageMagick 7 (same
|
|
85
|
+
chroma subsampling rules) but the bytes aren't identical, so image files won't hash the same as
|
|
86
|
+
expose.sh's output; HTML, CSS and JS do.
|
dorothea-1.9.0/Makefile
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Dorothea Makefile
|
|
2
|
+
# Common development tasks using uv
|
|
3
|
+
|
|
4
|
+
.PHONY: help test test-cov test-fast clean install lint format typecheck
|
|
5
|
+
|
|
6
|
+
help:
|
|
7
|
+
@echo "Available commands:"
|
|
8
|
+
@echo " make test - Run all tests"
|
|
9
|
+
@echo " make test-cov - Run tests with coverage report"
|
|
10
|
+
@echo " make test-fast - Run tests without slow/parity tests"
|
|
11
|
+
@echo " make clean - Clean generated files and caches"
|
|
12
|
+
@echo " make install - Install dependencies with uv"
|
|
13
|
+
@echo " make lint - Run all pre-commit hooks (via prek): ruff, format, ty"
|
|
14
|
+
@echo " make typecheck - Type-check src/ with ty"
|
|
15
|
+
@echo " make format - Format code (via prek ruff-format)"
|
|
16
|
+
@echo " make install-hooks - Install prek hooks"
|
|
17
|
+
|
|
18
|
+
# Run all tests
|
|
19
|
+
test:
|
|
20
|
+
uv run pytest tests/ --no-cov
|
|
21
|
+
|
|
22
|
+
# Run tests with coverage
|
|
23
|
+
test-cov:
|
|
24
|
+
@rm -rf .coverage htmlcov
|
|
25
|
+
uv run pytest tests/ --cov=src/dorothea --cov-report=term --cov-report=html
|
|
26
|
+
|
|
27
|
+
# Run only fast tests (skip slow parity tests)
|
|
28
|
+
test-fast:
|
|
29
|
+
uv run pytest tests/ -m "not slow" --no-cov
|
|
30
|
+
|
|
31
|
+
# Run only parity tests
|
|
32
|
+
test-parity:
|
|
33
|
+
uv run pytest tests/ -m "slow" --no-cov
|
|
34
|
+
|
|
35
|
+
# Clean generated files
|
|
36
|
+
clean:
|
|
37
|
+
@rm -rf .coverage htmlcov .pytest_cache
|
|
38
|
+
@rm -rf tests/__pycache__ tests/.pytest_cache
|
|
39
|
+
@find tests -type d -name __pycache__ -exec rm -rf {} + 2>/dev/null || true
|
|
40
|
+
@find . -type f -name "*.pyc" -delete 2>/dev/null || true
|
|
41
|
+
|
|
42
|
+
# Install dependencies
|
|
43
|
+
install:
|
|
44
|
+
uv pip install -e ".[dev]"
|
|
45
|
+
|
|
46
|
+
# Install pre-commit hooks (via prek)
|
|
47
|
+
install-hooks:
|
|
48
|
+
prek install-hooks
|
|
49
|
+
|
|
50
|
+
# Run all pre-commit hooks on all files (via prek)
|
|
51
|
+
lint:
|
|
52
|
+
prek run --all-files
|
|
53
|
+
|
|
54
|
+
# Type-check with ty
|
|
55
|
+
typecheck:
|
|
56
|
+
uv run ty check src
|
|
57
|
+
|
|
58
|
+
# Format code only (via prek ruff-format hook)
|
|
59
|
+
format:
|
|
60
|
+
prek run ruff-format --all-files
|
|
61
|
+
|
|
62
|
+
# Run full CI checks locally
|
|
63
|
+
ci: clean lint test-cov
|