Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ YOUTUBE_REMOTE_LOGIN_ENABLED=false
YOUTUBE_OUTBOUND_PROXY_URL=
YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN=SET_ME_YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN
YOUTUBE_SESSION_ENCRYPTION_KEY=SET_ME_YOUTUBE_SESSION_ENCRYPTION_KEY
BILIBILI_SESSION_ENCRYPTION_KEY=SET_ME_BILIBILI_SESSION_ENCRYPTION_KEY
YOUTUBE_REMOTE_LOGIN_CALLBACK_ORIGIN=http://typetype-server:8080
YOUTUBE_REMOTE_LOGIN_TTL_MS=480000
YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS=2
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ env:
jobs:
validate-pr:
if: github.event_name == 'pull_request'
runs-on: ubuntu-24.04
runs-on: [self-hosted, Linux, X64, ci-stack]
steps:
- uses: actions/checkout@v7.0.1
with:
Expand Down
62 changes: 62 additions & 0 deletions AI_TRANSPARENCY.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# AI Transparency

TypeType is built by humans. AI is a development tool, not an author, maintainer or decision-maker.

I use AI regularly. Depending on the task, I may use open-weight models in zero-data-retention setups, such as GLM, Qwen or DeepSeek, or hosted models such as GPT-5.6 Luna.

AI can help with debugging, refactoring, tests, docs, translations, infrastructure and even complete implementations. That is fine. But AI does not own the result.

## Human responsibility

For every merged change, a human must be able to answer:

- what does it do?
- why is it correct?
- how was it tested?
- what could break?
- can it be maintained?

AI can write 10%, 50% or 100% of the code. That is not the issue. The issue is whether a human reviewed it, validated it and takes responsibility for it.

## Testing still matters

AI can produce bugs. Humans can too.

Every meaningful change needs review, tests and real validation. The amount of AI used does not lower the quality bar.

Security changes, breaking changes, migration work and user-facing behavior require extra care.

## Contributor rules

You may use AI freely, including for complete implementations.

Your pull request should still explain:

- what the change does;
- why it is needed;
- how it was tested;
- known risks or limitations.

Low-effort AI spam is rejected. Mass-generated PRs, untested fixes, fake reports and unreviewed translations are not welcome.

## Commits and attribution

I do not want AI systems in commit history.

Do not add AI tools as author, committer or co-author. Do not add trailers like `Co-authored-by: SomeAI` or `Generated-with: SomeAI`.

The human who validates the change signs the work.

If you think an exception makes sense, explain it in the PR or contact me. I am open to discussion, but hidden AI attribution in commit history is not accepted by default.

## Private data

Do not send credentials, cookies, tokens, API keys, private keys, account data, third-party personal data or private logs to AI tools.

If real data is needed to reproduce an issue, reduce it, anonymize it and never publish it.

## Criticism is welcome

This document is my current position, not dogma.

If you think something here is wrong, open an issue, start a discussion or contact me. Explain your case. I prefer honest criticism over silent compliance.
2 changes: 1 addition & 1 deletion Docs-TypeType
Submodule Docs-TypeType updated 48 files
+1 −1 .github/workflows/deploy.yml
+2 −2 .github/workflows/typos.yml
+2 −0 README.md
+42 −3 docs/.vitepress/config.mts
+274 −0 docs/.vitepress/theme/LangSwitcher.vue
+12 −1 docs/.vitepress/theme/index.ts
+7 −0 docs/.vitepress/theme/style.css
+43 −0 docs/es/guide/accounts.md
+58 −0 docs/es/guide/discord-rich-presence.md
+93 −0 docs/es/guide/embedding.md
+43 −0 docs/es/guide/finding-content.md
+41 −0 docs/es/guide/index.md
+56 −0 docs/es/guide/library.md
+29 −0 docs/es/guide/privacy.md
+71 −0 docs/es/guide/settings.md
+92 −0 docs/es/guide/watching.md
+0 −3 docs/es/self-hosting/prerequisites.md
+43 −0 docs/fr/guide/accounts.md
+58 −0 docs/fr/guide/discord-rich-presence.md
+94 −0 docs/fr/guide/embedding.md
+43 −0 docs/fr/guide/finding-content.md
+41 −0 docs/fr/guide/index.md
+58 −0 docs/fr/guide/library.md
+29 −0 docs/fr/guide/privacy.md
+69 −0 docs/fr/guide/settings.md
+92 −0 docs/fr/guide/watching.md
+0 −3 docs/fr/self-hosting/prerequisites.md
+52 −0 docs/guide/discord-rich-presence.md
+17 −0 docs/project/community.md
+1 −0 docs/project/index.md
+30 −0 docs/project/repositories.md
+ − docs/public/screenshot-history.png
+ − docs/public/screenshot-home.png
+ − docs/public/screenshot-playlists.png
+ − docs/public/screenshot-presence-access.png
+ − docs/public/screenshot-presence-key-created.png
+ − docs/public/screenshot-rpc-discord-status.png
+ − docs/public/screenshot-rpc-settings.png
+ − docs/public/screenshot-search.png
+ − docs/public/screenshot-settings.png
+ − docs/public/screenshot-subscriptions.png
+ − docs/public/screenshot-watch.png
+3 −3 docs/self-hosting/authentication.md
+104 −12 docs/self-hosting/docker-compose.md
+8 −0 docs/self-hosting/importing-data.md
+12 −12 docs/self-hosting/introduction.md
+0 −3 docs/self-hosting/prerequisites.md
+2 −2 docs/self-hosting/reverse-proxy.md
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
<img src="assets/banner.svg" alt="TypeType" width="100%">
</p>

You want to know the current position of TypeType about AI ? Go check [this](https://github.com/TypeType-Video/TypeType/blob/dev/AI_TRANSPARENCY.md).

[Roadmap](https://roadmap.typetype.video) · [Git mirror](https://git.typetype.video/TypeType-Video)

# TypeType

TypeType is a self-hosted video platform for YouTube, NicoNico, and BiliBili.
Expand Down
59 changes: 59 additions & 0 deletions RELEASE_NOTES.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,62 @@
# TypeType 1.9.0

This is a big one. More than two weeks of work went into making playback more reliable, bringing subscription groups to desktop, improving Takeout and self-hosting, and making TypeType’s approach to AI easier to find. Many of these improvements started with community reports and PRs. We’re grateful to everyone who helped make this release happen.

## AI Transparency

We've added a public [AI Transparency document](https://github.com/TypeType-Video/TypeType/blob/main/AI_TRANSPARENCY.md) explaining our approach to AI in TypeType development.

## Playback and Providers

- Make YouTube web playback SABR-only, while keeping BiliBili and NicoNico playback unchanged. [#168](https://github.com/TypeType-Video/TypeType/issues/168)
- Requeue recoverable live requests in the active playback session instead of leaving playback stuck.
- Improve quality selection and stop showing the unavailable-audio warning on single-language streams. [Frontend #34](https://github.com/TypeType-Video/TypeType-Frontend/pull/34), [Frontend #33](https://github.com/TypeType-Video/TypeType-Frontend/pull/33)
- Decode extractor responses using their declared charset. [Server #87](https://github.com/TypeType-Video/TypeType-Server/pull/87)
- Fix YouTube comments displaying raw HTML. [#266](https://github.com/TypeType-Video/TypeType/issues/266)

Live playback passed three 30-minute beta runs with no session loss; 16 recoverable requests were requeued in place.

## Subscriptions and Watch Experience

- Add desktop management for subscription groups and paginate group members. [Frontend #32](https://github.com/TypeType-Video/TypeType-Frontend/pull/32), [Server #86](https://github.com/TypeType-Video/TypeType-Server/pull/86)
- Show a skeleton while channel avatars load and retry failed image requests without requiring a page refresh.
- Remove the duplicate NicoNico entry from the service picker.
- Fix Shorts not appearing on the initial home screen. [#275](https://github.com/TypeType-Video/TypeType/issues/275)

## Takeout and Self-Hosting

- Improve Takeout imports for localized fields, including Spanish, and larger archives.
- Add `BILIBILI_SESSION_ENCRYPTION_KEY` to the Compose and environment templates. [#291](https://github.com/TypeType-Video/TypeType/pull/291)
- Improve self-hosting documentation, including Dockge and Traefik guidance.
- Split the Server into focused Gradle modules and keep tests close to the code they cover.

## Issues Fixed in This Dev Line

- [#267](https://github.com/TypeType-Video/TypeType/issues/267): Account registration and login could fail.
- [#271](https://github.com/TypeType-Video/TypeType/issues/271), [#273](https://github.com/TypeType-Video/TypeType/issues/273), [#274](https://github.com/TypeType-Video/TypeType/issues/274): Fix YouTube Remote Login persistence and configuration issues, plus a readiness check.
- [#272](https://github.com/TypeType-Video/TypeType/issues/272): Document reverse-proxy WebSocket headers.
- [#275](https://github.com/TypeType-Video/TypeType/issues/275): Shorts could be missing from the initial home screen.
- [#266](https://github.com/TypeType-Video/TypeType/issues/266): YouTube comments could display raw HTML.

## Thx

More than two weeks of work went into this release, and many improvements began with someone taking the time to report a problem, send a PR, test a fix, or help with translations. We truly appreciate the time and care you put into TypeType.

- @Aquarius-Situla for the playback fixes in [Frontend #33](https://github.com/TypeType-Video/TypeType-Frontend/pull/33) and [#34](https://github.com/TypeType-Video/TypeType-Frontend/pull/34), and the BiliBili session configuration in [#291](https://github.com/TypeType-Video/TypeType/pull/291).
- @kapdon for desktop subscription-group management in [Frontend #32](https://github.com/TypeType-Video/TypeType-Frontend/pull/32) and pagination in [Server #86](https://github.com/TypeType-Video/TypeType-Server/pull/86).
- @tam1m for the charset fix in [Server #87](https://github.com/TypeType-Video/TypeType-Server/pull/87).
- @drJeckyll for reporting the YouTube comments issue in [#266](https://github.com/TypeType-Video/TypeType/issues/266).
- @hsjlyj for the detailed reports in [#271](https://github.com/TypeType-Video/TypeType/issues/271), [#272](https://github.com/TypeType-Video/TypeType/issues/272), [#273](https://github.com/TypeType-Video/TypeType/issues/273), and [#274](https://github.com/TypeType-Video/TypeType/issues/274).
- @therealresonix for reporting the login issue in [#267](https://github.com/TypeType-Video/TypeType/issues/267).
- @uniextra for the Shorts report and Takeout import feedback in [#275](https://github.com/TypeType-Video/TypeType/issues/275) and [#276](https://github.com/TypeType-Video/TypeType/issues/276).
- @Toastienergy for the German translation and beta testing.

## Updating

Follow the [update guide](https://typetype-video.github.io/Docs-TypeType/self-hosting/maintenance).

If necessary, follow the [rollback guide](https://typetype-video.github.io/Docs-TypeType/self-hosting/rollback).

# TypeType 1.8.1

TypeType 1.8.1 focuses on making playback more dependable across YouTube, BiliBili and NicoNico, improving mobile controls, strengthening profiles and notifications, making recommendations service-aware, and simplifying self-hosting.
Expand Down
2 changes: 1 addition & 1 deletion TypeType-Frontend
Submodule TypeType-Frontend updated 235 files
2 changes: 1 addition & 1 deletion TypeType-Server
Submodule TypeType-Server updated 1403 files
10 changes: 10 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,15 @@ services:
image: ${TYPETYPE_SERVER_BETA_IMAGE:-ghcr.io/typetype-video/typetype-server-beta:latest}
ports:
- "${HOST_BIND_SERVER_BETA:-127.0.0.1}:${HOST_PORT_SERVER_BETA:-18080}:8080"
mem_limit: 6g
mem_reservation: 4g
entrypoint:
- java
- -XX:+UseContainerSupport
- -XX:MaxRAMPercentage=50.0
- -XX:+ExitOnOutOfMemoryError
- -jar
- app.jar
env_file: .env
environment:
AUTH_SESSION_TTL_DAYS: ${AUTH_SESSION_TTL_DAYS:-30}
Expand All @@ -42,6 +51,7 @@ services:
YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE: /run/typetype-secrets/youtube_remote_login_internal_token
YOUTUBE_SESSION_ENCRYPTION_KEY: ""
YOUTUBE_SESSION_ENCRYPTION_KEY_FILE: /run/typetype-secrets/youtube_session_encryption_key
BILIBILI_SESSION_ENCRYPTION_KEY: ${BILIBILI_SESSION_ENCRYPTION_KEY:-}
YOUTUBE_REMOTE_LOGIN_TTL_MS: ${YOUTUBE_REMOTE_LOGIN_TTL_MS:-480000}
YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS: ${YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS:-2}
YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES: ${YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES:-524288}
Expand Down
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ services:
YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL: ${YOUTUBE_REMOTE_LOGIN_CALLBACK_BASE_URL:-http://typetype-server:8080}
YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN_FILE: /run/typetype-secrets/youtube_remote_login_internal_token
YOUTUBE_SESSION_ENCRYPTION_KEY_FILE: /run/typetype-secrets/youtube_session_encryption_key
BILIBILI_SESSION_ENCRYPTION_KEY: ${BILIBILI_SESSION_ENCRYPTION_KEY:-}
YOUTUBE_REMOTE_LOGIN_TTL_MS: ${YOUTUBE_REMOTE_LOGIN_TTL_MS:-480000}
YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS: ${YOUTUBE_REMOTE_LOGIN_MAX_SESSIONS:-2}
YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES: ${YOUTUBE_REMOTE_LOGIN_MAX_FRAME_BYTES:-524288}
Expand Down
2 changes: 2 additions & 0 deletions scripts/bootstrap-env.sh
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ ENV_FILE="${ENV_FILE:-${ROOT_DIR}/.env}"
REMOTE_LOGIN_PLACEHOLDER="SET_ME_YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN"
REMOTE_LOGIN_LEGACY_PLACEHOLDER="SET_ME_SHARED_SECRET"
SESSION_KEY_PLACEHOLDER="SET_ME_YOUTUBE_SESSION_ENCRYPTION_KEY"
BILIBILI_SESSION_KEY_PLACEHOLDER="SET_ME_BILIBILI_SESSION_ENCRYPTION_KEY"
GARAGE_RPC_PLACEHOLDER="SET_ME_GARAGE_RPC_SECRET"
GARAGE_RPC_STATIC_DEFAULT="f4db2c1d5aef1dce278d4315b80425e98831714a48c059e22c2a39001b15ca89"

Expand Down Expand Up @@ -86,4 +87,5 @@ ensure_hex_secret() {
ensure_env_file
ensure_secret "YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN" "${REMOTE_LOGIN_PLACEHOLDER}"
ensure_secret "YOUTUBE_SESSION_ENCRYPTION_KEY" "${SESSION_KEY_PLACEHOLDER}"
ensure_secret "BILIBILI_SESSION_ENCRYPTION_KEY" "${BILIBILI_SESSION_KEY_PLACEHOLDER}"
ensure_hex_secret "GARAGE_RPC_SECRET" "${GARAGE_RPC_PLACEHOLDER}"
2 changes: 1 addition & 1 deletion scripts/deploy-beta.sh
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ stage=locate-stack
trap 'printf "beta deployment failed during %s\n" "$stage" >&2' ERR
project=
anchor=
for candidate in typetype-beta typetype-beta-stack; do
for candidate in typetype-beta-stack typetype-beta; do
anchor=$(docker ps -a -q \
--filter "label=com.docker.compose.project=${candidate}" | head -n 1)
if [[ -n "$anchor" ]]; then
Expand Down
2 changes: 0 additions & 2 deletions scripts/deploy-stable.sh
Original file line number Diff line number Diff line change
Expand Up @@ -98,8 +98,6 @@ finish() {
if [[ "$succeeded" == true ]]; then
printf 'succeeded\n' > "$backup/status"
ln -sfn "$(basename "$backup")" "$rollback_root/last-successful"
find "$rollback_root" -mindepth 1 -maxdepth 1 -type d -printf '%T@ %p\n' \
| sort -nr | tail -n +6 | cut -d' ' -f2- | xargs -r rm -rf
exit "$status"
fi

Expand Down
90 changes: 90 additions & 0 deletions scripts/deploy-stable.test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env bash
set -euo pipefail

repository="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
temporary="$(mktemp -d)"
trap 'rm -rf "$temporary"' EXIT

source_root="$temporary/source"
stack="$temporary/stack"
fake_bin="$temporary/bin"
mkdir -p "$source_root/scripts" "$stack/scripts" "$fake_bin"

for file in \
.env.example \
docker-compose.yml \
docker-compose.arm64.yml \
scripts/bootstrap-env.sh \
scripts/bootstrap-garage.sh \
scripts/initialize-stack.sh \
scripts/run-stack-init.sh \
scripts/deploy-stable.sh; do
mkdir -p "$source_root/$(dirname "$file")" "$stack/$(dirname "$file")"
cp "$repository/$file" "$source_root/$file"
cp "$repository/$file" "$stack/$file"
done
printf 'POSTGRES_PASSWORD=test\n' > "$stack/.env"
for script in bootstrap-env.sh bootstrap-garage.sh initialize-stack.sh run-stack-init.sh; do
printf '#!/usr/bin/env bash\nexit 0\n' > "$source_root/scripts/$script"
done

rollback_root="$stack/.deploy-rollbacks"
mkdir -p "$rollback_root"
for index in {1..6}; do
mkdir -p "$rollback_root/old-$index"
printf 'existing snapshot\n' > "$rollback_root/old-$index/status"
done

cat > "$fake_bin/docker" <<'EOF'
#!/usr/bin/env bash
set -euo pipefail
case "$1" in
ps)
if [[ " $* " == *" -q "* ]]; then
echo server-container
fi
;;
inspect)
if [[ "$2" == server-container ]]; then
echo "$FAKE_STACK_ROOT"
else
echo sha256:old
fi
;;
compose)
case " $* " in
*" config --services "*)
printf '%s\n' typetype typetype-server postgres dragonfly garage
;;
*" ps -a -q "*)
printf 'container-%s\n' "${*: -1}"
;;
*" exec -T postgres sh -ec "*)
command="${*: -1}"
if [[ "$command" == *"SELECT 1 FROM pg_database"* ]]; then
printf '0\n'
elif [[ "$command" == *"pg_dump "* ]]; then
printf 'fake database dump\n'
fi
;;
esac
;;
esac
EOF
chmod +x "$fake_bin/docker"

PATH="$fake_bin:$PATH" \
FAKE_STACK_ROOT="$stack" \
"$repository/scripts/deploy-stable.sh" "$source_root"

for index in {1..6}; do
if [[ ! -d "$rollback_root/old-$index" ]]; then
echo "successful deployment removed existing rollback snapshot old-$index" >&2
exit 1
fi
done
snapshot_count="$(find "$rollback_root" -mindepth 1 -maxdepth 1 -type d | wc -l)"
if [[ "$snapshot_count" -ne 7 ]]; then
echo "expected six existing snapshots and one new snapshot, got $snapshot_count" >&2
exit 1
fi
2 changes: 2 additions & 0 deletions scripts/install-stack.test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -58,9 +58,11 @@ test ! -e "$python_log"
downloader_access_key="$(grep '^DOWNLOADER_S3_ACCESS_KEY=' "${install_dir}/.env" | cut -d= -f2-)"
downloader_secret_key="$(grep '^DOWNLOADER_S3_SECRET_KEY=' "${install_dir}/.env" | cut -d= -f2-)"
remote_login_token="$(grep '^YOUTUBE_REMOTE_LOGIN_INTERNAL_TOKEN=' "${install_dir}/.env" | cut -d= -f2-)"
bilibili_session_key="$(grep '^BILIBILI_SESSION_ENCRYPTION_KEY=' "${install_dir}/.env" | cut -d= -f2-)"
[[ "$downloader_access_key" =~ ^GK[0-9a-f]{24}$ ]]
[[ "$downloader_secret_key" =~ ^[0-9a-f]{64}$ ]]
[[ "$remote_login_token" =~ ^[A-Za-z0-9_-]{64}$ ]]
[[ "$bilibili_session_key" =~ ^[A-Za-z0-9_-]{64}$ ]]

beta_install_dir="${temporary}/beta-stack"
PATH="${fake_bin}:${PATH}" \
Expand Down
1 change: 1 addition & 0 deletions scripts/validate-stack.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ for script in scripts/*.sh; do
done
./scripts/install-stack.test.sh
./scripts/deploy-beta.test.sh
./scripts/deploy-stable.test.sh
./scripts/run-stack-init.test.sh

docker compose --env-file .env.example -f docker-compose.yml config -q
Expand Down