Skip to main content

all: initial commit; create the project skeleton

ID
b17f22e
date
2026-09-12 19:39:58+00:00
author
Alex Chan <alex@alexwlchan.net>
message
all: initial commit; create the project skeleton
changed files
11 files, 156 additions

Changed files

.gitignore (0 → 10)

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..6350e98
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1 @@
+.coverage

LICENSE (0 → 1053)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..e732212
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2026 Alex Chan
+
+Permission is hereby granted, free of charge, to any person obtaining a
+copy of this software and associated documentation files (the "Software"),
+to deal in the Software without restriction, including without limitation
+the rights to use, copy, modify, merge, publish, distribute, sublicense,
+and/or sell copies of the Software, and to permit persons to whom the Software
+is furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.

README.md (0 → 275)

diff --git a/README.md b/README.md
new file mode 100644
index 0000000..8910b29
--- /dev/null
+++ b/README.md
@@ -0,0 +1,4 @@
+# glancecast
+
+glancecast is a script that converts a video file into an MP3 file which has frames from the video stored as chapters.
+This allows you to listen to a video in an audio-only podcast player like Overcast, and glance at the screen if you need some visual context.

dev_requirements.in (0 → 45)

diff --git a/dev_requirements.in b/dev_requirements.in
new file mode 100644
index 0000000..26794a2
--- /dev/null
+++ b/dev_requirements.in
@@ -0,0 +1,6 @@
+-r requirements.txt
+
+coverage
+pytest
+ruff
+ty

dev_requirements.txt (0 → 571)

diff --git a/dev_requirements.txt b/dev_requirements.txt
new file mode 100644
index 0000000..39da9e4
--- /dev/null
+++ b/dev_requirements.txt
@@ -0,0 +1,20 @@
+# This file was autogenerated by uv via the following command:
+#    uv pip compile dev_requirements.in --output-file=dev_requirements.txt --exclude-newer=P7D --exclude-newer-package alexwlchan-chives=false
+coverage==7.16.0
+    # via -r dev_requirements.in
+iniconfig==2.3.0
+    # via pytest
+mutagen==1.48.1
+    # via -r requirements.txt
+packaging==26.3
+    # via pytest
+pluggy==1.6.0
+    # via pytest
+pygments==2.21.0
+    # via pytest
+pytest==9.1.1
+    # via -r dev_requirements.in
+ruff==0.16.6
+    # via -r dev_requirements.in
+ty==0.0.78
+    # via -r dev_requirements.in

glancecast.py (0 → 518)

diff --git a/glancecast.py b/glancecast.py
new file mode 100644
index 0000000..50c76c3
--- /dev/null
+++ b/glancecast.py
@@ -0,0 +1,20 @@
+"""
+glancecast converts a video file into an MP3 file which has frames from
+the video stored as chapters.
+
+This allows you to listen to a video in an audio-only podcast player like
+Overcast, and glance at the screen if you need some visual context.
+"""
+
+import shutil
+import sys
+
+
+def ensure_tool_installed(name: str):
+    """
+    Ensure that a tool with the given name is installed and available
+    in the PATH.
+    """
+    p = shutil.which(name)
+    if p is None:
+        sys.exit(f"missing required tool: {name}")

pyproject.toml (0 → 503)

diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..8fd6be1
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,21 @@
+[tool.coverage.run]
+branch = true
+include = ["glancecast.py", "test_glancecast.py"]
+
+[tool.coverage.report]
+show_missing = true
+skip_covered = true
+fail_under = 100
+
+[tool.pytest.ini_options]
+filterwarnings = ["error"]
+
+[tool.ruff.lint]
+select = ["D", "E", "F"]
+ignore = [
+    "D200",  # unnecessary-multiline-docstring
+    "D203",  # incorrect-blank-line-before-class
+    "D205",  # missing-blank-line-after-summary
+    "D211",  # blank-line-before-class
+    "D212",  # multi-line-summary-first-line
+]

requirements.in (0 → 8)

diff --git a/requirements.in b/requirements.in
new file mode 100644
index 0000000..26ced3f
--- /dev/null
+++ b/requirements.in
@@ -0,0 +1 @@
+mutagen

requirements.txt (0 → 243)

diff --git a/requirements.txt b/requirements.txt
new file mode 100644
index 0000000..ce28608
--- /dev/null
+++ b/requirements.txt
@@ -0,0 +1,4 @@
+# This file was autogenerated by uv via the following command:
+#    uv pip compile requirements.in --output-file=requirements.txt --exclude-newer=P7D --exclude-newer-package alexwlchan-chives=false
+mutagen==1.48.1
+    # via -r requirements.in

scripts/run_glancecast_tests.sh (0 → 671)

diff --git a/scripts/run_glancecast_tests.sh b/scripts/run_glancecast_tests.sh
new file mode 100755
index 0000000..e2e4b61
--- /dev/null
+++ b/scripts/run_glancecast_tests.sh
@@ -0,0 +1,34 @@
+#!/usr/bin/env bash
+
+set -o errexit
+set -o nounset
+
+# Print a command in blue, then run the command
+run_command() {
+    echo ""
+    echo -e "\033[34m-> $@\033[0m"
+    bash -c "$@"
+}
+
+report_coverage() {
+    echo ""
+    echo -e "\033[34m-> python3 -m coverage report\033[0m"
+    if [[ $(python3 -m coverage report --format=total) = "100" ]]
+    then
+        echo "100% coverage!"
+    else
+        python3 -m coverage report
+    fi
+}
+
+run_command 'ruff format'
+
+if [[ "${CI:-}" == "true" ]]
+then
+  run_command 'git diff --exit-code'
+fi
+
+run_command 'ruff check'
+run_command 'ty check .'
+run_command "python3 -m coverage run -m pytest -q test_glancecast.py"
+report_coverage

test_glancecast.py (0 → 622)

diff --git a/test_glancecast.py b/test_glancecast.py
new file mode 100644
index 0000000..ed85144
--- /dev/null
+++ b/test_glancecast.py
@@ -0,0 +1,26 @@
+"""
+Tests for glancecast.
+"""
+
+import pytest
+
+from glancecast import ensure_tool_installed
+
+
+class TestEnsureToolInstalled:
+    """
+    Tests for `ensure_tool_installed`.
+    """
+
+    def test_installed_tool(self) -> None:
+        """
+        Ensuring that an extant tool is installed doesn't raise an error.
+        """
+        ensure_tool_installed("python")
+
+    def test_missing_tool(self) -> None:
+        """
+        Ensuring that a non-existent tool is installed raises an error.
+        """
+        with pytest.raises(SystemExit, match="missing required tool"):
+            ensure_tool_installed("does_not_exist")