Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
365 commits
Select commit Hold shift + click to select a range
c322fc5
fix: target sabr websocket pump fetches
Priveetee Jul 6, 2026
91aa0cb
fix: warm sabr playable intersection
Priveetee Jul 6, 2026
de27763
fix: warm sabr startup window
Priveetee Jul 6, 2026
057f727
fix: restore sabr startup preflight
Priveetee Jul 6, 2026
27bc9b7
fix: expose sabr hls and dash manifests
Priveetee Jul 6, 2026
957cd83
fix: use relative sabr manifest paths
Priveetee Jul 6, 2026
0d908b9
fix: preflight sabr av manifests
Priveetee Jul 6, 2026
9dc3fc2
fix: reuse warm sabr manifest sessions
Priveetee Jul 6, 2026
e0ba76b
chore: deploy server beta after docker build
Priveetee Jul 6, 2026
af30444
fix: normalize sabr manifest urls
Priveetee Jul 6, 2026
c874131
fix: remove sabr websocket transport
Priveetee Jul 6, 2026
9a87d4b
fix: complete takeout imports asynchronously
Priveetee Jul 6, 2026
9e77287
docs: document redis cache fallback
Priveetee Jul 6, 2026
d5b7d83
fix: stabilize sabr dash audio probing
Priveetee Jul 6, 2026
fbd697d
fix: fallback sabr probes to mweb
Priveetee Jul 6, 2026
bf80184
fix: frame sabr media responses
Priveetee Jul 6, 2026
d5670b7
fix: emit api sabr manifest urls
Priveetee Jul 6, 2026
fb1c5fe
fix: serve sabr seek segments
Priveetee Jul 6, 2026
0cb7837
fix: window sabr seek manifests
Priveetee Jul 6, 2026
d9037d4
fix: retry stale sabr preflight
Priveetee Jul 6, 2026
bc6813d
fix: refresh sabr preflight retries
Priveetee Jul 6, 2026
66a30bc
fix: add sabr playback sessions
Priveetee Jul 7, 2026
5e8e370
fix: manage sabr playback pump state
Priveetee Jul 7, 2026
c78aaba
chore: log sabr probe failures
Priveetee Jul 7, 2026
6c2835c
fix: scope sabr playback seeks
Priveetee Jul 7, 2026
0b2f5c5
fix: make sabr playback manifest retryable
Priveetee Jul 7, 2026
2dd8bfa
refactor: centralize sabr playback sessions
Priveetee Jul 7, 2026
5ce4801
test: cover sabr playback services
Priveetee Jul 7, 2026
12da672
chore: support arm compose override
Priveetee Jul 7, 2026
cef4ef4
fix: keep dragonfly for arm override
Priveetee Jul 7, 2026
7ddff50
fix: scope sabr playback generations
Priveetee Jul 7, 2026
f79ae37
fix: guard sabr init generations
Priveetee Jul 7, 2026
d86728d
fix: advance sabr seek readers
Priveetee Jul 7, 2026
e9dcd80
fix: wait for sabr seek buffer
Priveetee Jul 7, 2026
8d108f9
fix: unblock sabr mse seeks
Priveetee Jul 7, 2026
076813a
fix: publish sabr seek windows
Priveetee Jul 7, 2026
bac91e4
fix: use sabr reader readiness
Priveetee Jul 7, 2026
75787b2
fix: fetch sabr seek edge segments
Priveetee Jul 7, 2026
0e34845
fix: align sabr seek reposition
Priveetee Jul 7, 2026
65e9ea3
fix: gate sabr seek manifests
Priveetee Jul 7, 2026
4ec7398
fix: consume sabr seek requests
Priveetee Jul 8, 2026
d0b0131
fix: serve cached sabr media
Priveetee Jul 8, 2026
d2c4042
fix: publish prepared sabr media
Priveetee Jul 8, 2026
6be04cf
fix: refresh sabr visitor token
Priveetee Jul 8, 2026
62e2f99
chore: add beta deploy workflow
Priveetee Jul 8, 2026
2067990
fix: try mobile sabr probes
Priveetee Jul 8, 2026
5a9f9e6
fix: keep sabr probes web only
Priveetee Jul 8, 2026
c8c9382
fix: reuse extracted sabr info
Priveetee Jul 8, 2026
e371e24
fix: update sabr extractor dependency
Priveetee Jul 8, 2026
aa637ee
fix: use token youtube decoder
Priveetee Jul 8, 2026
6d43b29
fix: use streaming sabr pump
Priveetee Jul 8, 2026
0bc888a
fix: select web youtube client
Priveetee Jul 8, 2026
3a8284f
chore: log sabr pump failures
Priveetee Jul 8, 2026
3a43bfb
fix: gate sabr manifest on buffered edge
Priveetee Jul 8, 2026
d6c7752
fix: use upstream sabr segment fetch
Priveetee Jul 8, 2026
77c88a0
fix: prefer mweb sabr client
Priveetee Jul 8, 2026
f146a29
fix: refresh sabr video token only
Priveetee Jul 8, 2026
a02fafd
fix: align sabr seek target
Priveetee Jul 8, 2026
bbf414d
feat: add sabr playback window
Priveetee Jul 8, 2026
a097225
fix: serialize sabr window response
Priveetee Jul 8, 2026
14c6aa5
fix: surface sabr protected terminal
Priveetee Jul 8, 2026
b6d3a16
feat: suggest sabr video fallback
Priveetee Jul 8, 2026
10c1410
fix: reject empty stream responses
Priveetee Jul 8, 2026
109ba4f
feat: split sabr playback window
Priveetee Jul 8, 2026
312a497
fix: prefetch sabr window gaps
Priveetee Jul 8, 2026
f3e39ac
perf: make sabr windows progressive
Priveetee Jul 9, 2026
b18deca
fix: warm sabr seek timing
Priveetee Jul 9, 2026
8ff1daa
fix: expose sabr vp9 formats
Priveetee Jul 9, 2026
a6cf5ff
fix: enrich sabr stream formats
Priveetee Jul 9, 2026
494a3a4
fix: align sabr web playback profile
Priveetee Jul 9, 2026
3de09fd
fix: align sabr nonzero start seeks
Priveetee Jul 9, 2026
fc0b6b2
fix: avoid direct sabr init warmup
Priveetee Jul 9, 2026
7da8115
fix: prioritize current sabr blockers
Priveetee Jul 9, 2026
3efff03
fix: preload sabr initialization timing
Priveetee Jul 9, 2026
a795285
fix: align sabr initial seek target
Priveetee Jul 9, 2026
0169232
fix: route sabr segments through pump
Priveetee Jul 9, 2026
678232f
fix: unblock sabr seek pump
Priveetee Jul 9, 2026
963d5fe
chore: instrument sabr pump rounds
Priveetee Jul 9, 2026
9211cb9
chore: expose sabr diagnostic trace
Priveetee Jul 9, 2026
c678c53
chore: run beta deploy on self-hosted
Priveetee Jul 9, 2026
9b2f254
fix: refresh sabr potoken session
Priveetee Jul 9, 2026
39513d5
fix: preroll sabr video seek segments
Priveetee Jul 9, 2026
adc14e0
fix: honor sabr seeks before initial pump
Priveetee Jul 9, 2026
d91b35d
fix: prime sabr seek before init preload
Priveetee Jul 9, 2026
bac4623
fix: isolate sabr cold seek init
Priveetee Jul 9, 2026
e34b366
fix: wait for cold sabr preload
Priveetee Jul 9, 2026
e584c61
fix: use exact sabr seek sequences
Priveetee Jul 9, 2026
f2d1da4
feat: expose build version endpoint
Priveetee Jul 9, 2026
90c857a
fix: pass build revision to docker
Priveetee Jul 9, 2026
d59f8b1
fix: anchor cold sabr seeks on audio
Priveetee Jul 9, 2026
cbcc664
fix: match cold sabr seek shape
Priveetee Jul 9, 2026
9397ba9
fix: refresh sabr video pot on protection
Priveetee Jul 9, 2026
15b34f2
fix: target sabr pump demands
Priveetee Jul 9, 2026
f9bf885
fix: preserve cold sabr seek target
Priveetee Jul 9, 2026
775425c
fix: match targeted sabr abr mode
Priveetee Jul 9, 2026
228bdb3
fix: keep sabr companion range
Priveetee Jul 9, 2026
218e6a3
fix: target exact sabr buffered range
Priveetee Jul 9, 2026
9113e81
fix: refresh sabr pot and previous range
Priveetee Jul 9, 2026
f83c3e2
fix: keep sabr target range contiguous
Priveetee Jul 9, 2026
a866d07
fix: send visitor pot for sabr
Priveetee Jul 9, 2026
50bc29a
fix: prioritize audio sabr cold seek
Priveetee Jul 9, 2026
42dc3e0
chore: skip dev test workflows
Priveetee Jul 9, 2026
455854c
fix: target sabr player time
Priveetee Jul 9, 2026
bad1a7f
fix: target single sabr track
Priveetee Jul 9, 2026
fdb05af
fix: discard sabr companion track
Priveetee Jul 9, 2026
48aba51
fix: keep sabr companion contiguous
Priveetee Jul 9, 2026
9da5cda
fix: keep sabr discard formats selected
Priveetee Jul 9, 2026
2bbb430
fix: preserve initial sabr cold seek
Priveetee Jul 9, 2026
d442b81
fix: bootstrap sabr cold seek
Priveetee Jul 9, 2026
9679da0
fix: keep cold seek sabr uninitialized
Priveetee Jul 9, 2026
d42fec0
fix: target sabr companion range
Priveetee Jul 9, 2026
37deccf
fix: localize sabr seek ranges
Priveetee Jul 9, 2026
275dcf4
fix: select sabr discard companion
Priveetee Jul 9, 2026
24b3ca8
fix: request sabr seek segment after range
Priveetee Jul 9, 2026
b1cb6af
fix: send sabr contiguous target range
Priveetee Jul 9, 2026
81cb43b
fix: avoid destructive sabr seek range
Priveetee Jul 9, 2026
db79e27
fix: target sabr seek by player time
Priveetee Jul 9, 2026
4a39e38
fix: restore sabr seek range guard
Priveetee Jul 9, 2026
813e339
fix: fallback sabr player po token
Priveetee Jul 9, 2026
2ae3660
fix: use observed sabr seek range
Priveetee Jul 9, 2026
4b5a242
fix: target sabr range before segment
Priveetee Jul 9, 2026
80a2563
fix: map sabr cold seek from init
Priveetee Jul 9, 2026
b8b4c15
fix: report contiguous sabr target range
Priveetee Jul 9, 2026
faa3c52
fix: initialize sabr cold seek index
Priveetee Jul 9, 2026
c66aeb3
fix: align sabr companion seek range
Priveetee Jul 9, 2026
25311e6
fix: target sabr with both tracks
Priveetee Jul 9, 2026
a1db383
fix: clear sabr cookie before target
Priveetee Jul 9, 2026
c967857
fix: keep sabr target track scoped
Priveetee Jul 9, 2026
cad2a83
fix: start sabr cold seek at target
Priveetee Jul 9, 2026
419a700
fix: bind sabr streaming token to video
Priveetee Jul 9, 2026
1acc955
fix: restore sabr visitor streaming token
Priveetee Jul 9, 2026
d5da660
chore: update PipePipeExtractor
Priveetee Jul 9, 2026
b601dec
perf: align sabr cold seek with PipePipe
Priveetee Jul 9, 2026
268002d
test: support direct sabr network probe
Priveetee Jul 9, 2026
0e2d609
fix: bind sabr player token to visitor
Priveetee Jul 9, 2026
e910026
perf: fetch sabr init before session fallback
Priveetee Jul 9, 2026
6dbc0e3
perf: share extracted sabr session metadata
Priveetee Jul 9, 2026
b91f1ea
fix: keep sabr metadata bound to visitor
Priveetee Jul 9, 2026
e815e0d
chore: rotate stream cache for sabr metadata
Priveetee Jul 9, 2026
cb28c73
fix: preroll sabr video seeks by one segment
Priveetee Jul 9, 2026
ae8aa9c
fix: preroll sabr audio seeks by one segment
Priveetee Jul 9, 2026
5c7d8fb
fix: align sabr preroll with actual segment timing
Priveetee Jul 9, 2026
c2fd954
perf: overlap sabr initialization with media startup
Priveetee Jul 9, 2026
13b905b
perf: reuse sabr init cache across signed urls
Priveetee Jul 10, 2026
4d2be84
fix: refresh sabr token once after upstream 403
Priveetee Jul 10, 2026
3d9e1bf
fix: align sabr audio with video keyframe
Priveetee Jul 10, 2026
a2b9f99
fix: require sabr seek buffer coverage
Priveetee Jul 10, 2026
9b376ac
fix: recreate failed sabr sessions
Priveetee Jul 10, 2026
6687525
test: align sabr coverage with current behavior
Priveetee Jul 10, 2026
11805c1
ci: run full tests on dev pushes
Priveetee Jul 10, 2026
cce301f
chore: update server dependencies
Priveetee Jul 10, 2026
318a18d
ci: avoid duplicate server compilation
Priveetee Jul 10, 2026
00f120c
ci: limit gradle worker contention
Priveetee Jul 10, 2026
bc29463
fix: accept prior sabr buffer formats
Priveetee Jul 10, 2026
bb3fbe9
perf: avoid duplicate sabr warmups
Priveetee Jul 10, 2026
4be73ec
fix: restore sabr playback recovery
Priveetee Jul 10, 2026
669357a
fix: align youtube hls proxy identity
Priveetee Jul 10, 2026
18a22bb
fix: remove ineffective hls identity change
Priveetee Jul 10, 2026
0ae87c9
fix: use attested youtube live manifests
Priveetee Jul 10, 2026
22a1fce
chore: establish server semantic version
Priveetee Jul 10, 2026
cade12f
fix: rebase sabr windows from media timing
Priveetee Jul 10, 2026
954b88c
fix: preserve authoritative sabr segment timing
Priveetee Jul 10, 2026
ea6e90e
fix: align sabr buffered edge after rebase
Priveetee Jul 10, 2026
a118b02
fix: reject stale sabr window anchors
Priveetee Jul 10, 2026
d228829
fix: require durable sabr playback windows
Priveetee Jul 10, 2026
cab9bcb
perf: restore progressive sabr window readiness
Priveetee Jul 10, 2026
2f53d82
perf: keep sabr media segments in memory
Priveetee Jul 10, 2026
34c13b4
fix: skip absent sabr media sequences
Priveetee Jul 10, 2026
0cf53f9
perf: extend sabr windows after client buffer
Priveetee Jul 10, 2026
b9debb7
fix: signal sabr stream completion
Priveetee Jul 10, 2026
ffe17b7
feat: add custom avatar storage
Priveetee Jul 10, 2026
5ea0a54
feat: add safe account identity updates
Priveetee Jul 10, 2026
772fdaa
feat: add cached dearrow metadata
Priveetee Jul 10, 2026
b207b03
feat: expose profile and dearrow features
Priveetee Jul 10, 2026
fd48d8f
fix: reset verification after email change
Priveetee Jul 10, 2026
e18328e
fix: make sabr manifest media paths relative
Priveetee Jul 11, 2026
036a989
fix: retry beta health check
Priveetee Jul 11, 2026
924336a
feat: expose server build version
Priveetee Jul 11, 2026
12dcd78
fix: stabilize sabr segment recovery
Priveetee Jul 11, 2026
e17c8ab
fix: replace stale sabr segment demand
Priveetee Jul 11, 2026
11840b4
fix: unblock sabr downloads
Priveetee Jul 11, 2026
4d9e260
fix: await pumped sabr segments
Priveetee Jul 11, 2026
026d339
perf: align sabr demand timing with PipePipe
Priveetee Jul 11, 2026
ce8585c
perf: return sabr playback sessions immediately
Priveetee Jul 11, 2026
1b289e2
perf: start sabr pumping on reader demand
Priveetee Jul 11, 2026
0ece183
perf: remove competing sabr warmup
Priveetee Jul 11, 2026
6522838
fix: serve dearrow thumbnails with correct media type
Priveetee Jul 11, 2026
09043f4
fix: isolate sabr workloads
Priveetee Jul 11, 2026
a5f0880
feat: expose read-only DeArrow options
Priveetee Jul 11, 2026
8895d20
fix: warm sabr before manifest preflight
Priveetee Jul 11, 2026
5c71721
fix: isolate dearrow request limits
Priveetee Jul 11, 2026
2465a1e
fix: compress recommendation cursors
Priveetee Jul 11, 2026
79d7c98
fix: restore admin bootstrap without an admin
Priveetee Jul 11, 2026
3477e33
fix: assign valid usernames during registration
Priveetee Jul 11, 2026
f13741c
fix: preserve YouTube thumbnail fallbacks
Priveetee Jul 11, 2026
145c73e
fix: retain exact sabr download demands
Priveetee Jul 11, 2026
252356b
Revert "fix: retain exact sabr download demands"
Priveetee Jul 11, 2026
0cfcdf1
fix: isolate sabr seek sessions
Priveetee Jul 11, 2026
a2bd719
perf: resolve takeout metadata concurrently
Priveetee Jul 11, 2026
f828b1f
fix: isolate audio-only sabr sessions
Priveetee Jul 11, 2026
e78211d
feat: support audio-only sabr windows
Priveetee Jul 12, 2026
87e8ec6
fix: isolate audio only sabr sessions
Priveetee Jul 12, 2026
e202c8e
perf: reuse sabr sessions for seeks
Priveetee Jul 12, 2026
ead8344
perf: skip video initialization for audio only
Priveetee Jul 12, 2026
7cf9375
fix: recover sabr with fresh token sessions
Priveetee Jul 12, 2026
20854d1
fix: serve token sabr formats when extraction is empty
Priveetee Jul 12, 2026
1127a6d
fix: decode raw sabr urls exactly once
Priveetee Jul 12, 2026
a5d70e6
fix: recover youtube streams through token sabr
Priveetee Jul 12, 2026
6e315aa
fix: recognize signed HLS playlist URLs
Priveetee Jul 12, 2026
16043fa
perf: streamline external audio playback
Priveetee Jul 12, 2026
8b8c2d0
perf: align SABR demand scheduling with PipePipe
Priveetee Jul 12, 2026
28b3893
perf: preserve cached SABR seek targets
Priveetee Jul 12, 2026
9a6e41c
perf: stream complete audio without range
Priveetee Jul 12, 2026
c29b542
perf: complete small audio range requests
Priveetee Jul 12, 2026
0038c7e
perf: probe missing audio content lengths
Priveetee Jul 12, 2026
bd0635e
perf: normalize audio-only content type
Priveetee Jul 12, 2026
84e8923
perf: query favorite status by video
Priveetee Jul 13, 2026
1689ee7
fix: preserve fallback channel avatars
Priveetee Jul 13, 2026
5093935
fix: invalidate stale stream avatars
Priveetee Jul 13, 2026
ffd1bbb
perf: reduce SABR extraction latency
Priveetee Jul 13, 2026
fbc039e
feat: isolate stream delivery endpoints
Priveetee Jul 13, 2026
1af7bd8
test: cover isolated stream delivery modes
Priveetee Jul 13, 2026
18498d7
fix: isolate classic YouTube extraction
Priveetee Jul 13, 2026
84af113
fix: restore classic YouTube fallback
Priveetee Jul 13, 2026
3d77219
fix: add classic TV extraction fallback
Priveetee Jul 13, 2026
a8dabf3
fix: preserve classic adaptive streams
Priveetee Jul 13, 2026
ef2297a
perf: cancel interruptible extraction work
Priveetee Jul 13, 2026
931d01d
perf: bootstrap SABR playback metadata
Priveetee Jul 13, 2026
78189e9
perf: recover stalled sabr streams
Priveetee Jul 13, 2026
89d8b74
fix: recover stalled sabr segment demand
Priveetee Jul 13, 2026
0881a44
fix: preserve classic streams contract
Priveetee Jul 13, 2026
487b412
fix: preserve backend sabr buffer progress
Priveetee Jul 13, 2026
cf2f90b
fix: recover failed sabr playback pumps
Priveetee Jul 13, 2026
0610632
fix: bound stalled sabr segment demands
Priveetee Jul 13, 2026
a1969e0
fix: align sabr streaming timeout with PipePipe
Priveetee Jul 13, 2026
913c878
fix: refresh stalled sabr playback metadata
Priveetee Jul 13, 2026
053dc20
fix: keep sabr token sessions atomic
Priveetee Jul 13, 2026
8b4b89d
fix: keep SABR fallback formats strictly lower
Priveetee Jul 14, 2026
a968c8a
fix: refresh only the stalled video token
Priveetee Jul 14, 2026
4cd7408
fix: keep refreshed SABR tokens session-bound
Priveetee Jul 14, 2026
0c80707
fix: retry SABR demand after network timeout
Priveetee Jul 14, 2026
c7a5684
fix: bound SABR recovery by network responses
Priveetee Jul 14, 2026
a02659b
fix: expire stalled SABR demands
Priveetee Jul 14, 2026
70d37e2
test: cover stalled SABR demand deadline
Priveetee Jul 14, 2026
49122dc
fix: stabilize stalled SABR demand recovery
Priveetee Jul 14, 2026
26269ab
test: cover stable SABR demand recovery
Priveetee Jul 14, 2026
1da10f5
fix: expire exact SABR demands safely
Priveetee Jul 14, 2026
30cf083
test: cover exact SABR demand lifecycle
Priveetee Jul 14, 2026
b47c0fd
fix: preload SABR timing before resume
Priveetee Jul 14, 2026
64e8953
fix: isolate SABR playback sessions
Priveetee Jul 14, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
66 changes: 1 addition & 65 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -23,68 +23,4 @@ jobs:
- uses: gradle/actions/setup-gradle@v6

- name: Build
run: ./gradlew build -x test

test:
needs: build
runs-on: [self-hosted, Linux, X64, arko, android]
strategy:
fail-fast: false
matrix:
group:
- name: extraction
tests: >-
--tests dev.typetype.server.ExtractionTest
--tests dev.typetype.server.StreamRoutesTest
--tests dev.typetype.server.ProxyRoutesTest
--tests dev.typetype.server.ManifestRoutesTest
--tests dev.typetype.server.ManifestServiceTest
--tests dev.typetype.server.HlsRewritingTest
--tests dev.typetype.server.UrlStrippingTest
--tests dev.typetype.server.UrlValidatorTest
--tests dev.typetype.server.NativeManifestUtilsTest
--tests dev.typetype.server.ExtractionResilienceTest
--tests dev.typetype.server.StreamInfoMappersCoreTest
--tests dev.typetype.server.NativeManifestBuilderCoreTest
--tests dev.typetype.server.OkHttpDownloaderCoreTest
--tests dev.typetype.server.StreamExtractionErrorMapperTest
--tests dev.typetype.server.ShortCanonicalUrlTest
--tests dev.typetype.server.ShortDedupKeyTest
- name: routes-media
tests: >-
--tests dev.typetype.server.SearchRoutesTest
--tests dev.typetype.server.TrendingRoutesTest
--tests dev.typetype.server.CommentRoutesTest
--tests dev.typetype.server.ChannelRoutesTest
--tests dev.typetype.server.SuggestionRoutesTest
- name: routes-user
tests: >-
--tests dev.typetype.server.SearchHistoryRoutesTest
--tests dev.typetype.server.ProgressRoutesTest
--tests dev.typetype.server.HistoryRoutesTest
--tests dev.typetype.server.FavoritesRoutesTest
--tests dev.typetype.server.WatchLaterRoutesTest
--tests dev.typetype.server.SubscriptionsRoutesTest
--tests dev.typetype.server.SettingsRoutesTest
--tests dev.typetype.server.BlockedRoutesTest
--tests dev.typetype.server.PlaylistRoutesTest
--tests dev.typetype.server.PlaylistServiceTest
--tests dev.typetype.server.SubscriptionFeedRoutesTest
--tests dev.typetype.server.SubscriptionShortsFeedRoutesTest
--tests dev.typetype.server.SubscriptionShortsFeedDiversityTest
--tests dev.typetype.server.AuthServiceCoreTest
--tests dev.typetype.server.PasswordResetServiceCoreTest
--tests dev.typetype.server.YoutubeTakeoutIssueServiceTest
--tests dev.typetype.server.ManifestRoutesTest
steps:
- uses: actions/checkout@v6

- uses: actions/setup-java@v5
with:
java-version: "25"
distribution: temurin

- uses: gradle/actions/setup-gradle@v6

- name: Test (${{ matrix.group.name }})
run: ./gradlew test ${{ matrix.group.tests }}
run: ./gradlew build --max-workers=8
2 changes: 0 additions & 2 deletions .github/workflows/coverage.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
name: Coverage

on:
push:
branches: ["dev"]
pull_request:
branches: ["dev", "main"]

Expand Down
35 changes: 35 additions & 0 deletions .github/workflows/deploy-beta.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
name: Deploy Beta

on:
workflow_dispatch:

env:
FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true

jobs:
deploy-beta:
runs-on: [self-hosted, Linux, X64, arko, android]
permissions:
contents: read

steps:
- name: Configure SSH key
run: |
mkdir -p ~/.ssh
printf '%s\n' "$TYPE_TYPE_DEPLOY_SSH_KEY" > ~/.ssh/typetype_deploy
chmod 600 ~/.ssh/typetype_deploy
env:
TYPE_TYPE_DEPLOY_SSH_KEY: ${{ secrets.TYPE_TYPE_DEPLOY_SSH_KEY }}

- name: Update beta stack
run: |
ssh -i ~/.ssh/typetype_deploy \
-p "$TYPE_TYPE_DEPLOY_PORT" \
-o BatchMode=yes \
-o StrictHostKeyChecking=accept-new \
"$TYPE_TYPE_DEPLOY_USER@$TYPE_TYPE_DEPLOY_HOST" \
/usr/local/sbin/typetype-beta-update
env:
TYPE_TYPE_DEPLOY_HOST: ${{ secrets.TYPE_TYPE_DEPLOY_HOST }}
TYPE_TYPE_DEPLOY_PORT: ${{ secrets.TYPE_TYPE_DEPLOY_PORT }}
TYPE_TYPE_DEPLOY_USER: ${{ secrets.TYPE_TYPE_DEPLOY_USER }}
60 changes: 60 additions & 0 deletions .github/workflows/docker.yml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,19 @@ jobs:
- name: Checkout
uses: actions/checkout@v6

- name: Resolve build metadata
id: build-info
run: |
base_version="$(sed -n 's/^appVersion=//p' gradle.properties)"
if [[ "$GITHUB_REF" == refs/tags/v* ]]; then
version="${GITHUB_REF_NAME#v}"
else
channel="${GITHUB_REF_NAME//[^0-9A-Za-z-]/-}"
version="$base_version-$channel.$GITHUB_RUN_NUMBER"
fi
echo "version=$version" >> "$GITHUB_OUTPUT"
echo "build-time=$(date -u +'%Y-%m-%dT%H:%M:%SZ')" >> "$GITHUB_OUTPUT"

- name: Log in to GitHub Container Registry
uses: docker/login-action@v4
with:
Expand Down Expand Up @@ -67,5 +80,52 @@ jobs:
push: true
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
build-args: |
APP_VERSION=${{ steps.build-info.outputs.version }}
GITHUB_SHA=${{ github.sha }}
BUILD_TIME=${{ steps.build-info.outputs.build-time }}
cache-from: type=gha
cache-to: type=gha,mode=max

deploy-beta:
needs: build-and-push
if: github.ref_name == 'dev'
runs-on: [self-hosted, Linux, X64, arko, android]
environment: beta
steps:
- name: Check deployment configuration
id: deploy-config
env:
TYPE_TYPE_DEPLOY_HOST: ${{ secrets.TYPE_TYPE_DEPLOY_HOST }}
TYPE_TYPE_DEPLOY_PORT: ${{ secrets.TYPE_TYPE_DEPLOY_PORT }}
TYPE_TYPE_DEPLOY_USER: ${{ secrets.TYPE_TYPE_DEPLOY_USER }}
TYPE_TYPE_DEPLOY_SSH_KEY: ${{ secrets.TYPE_TYPE_DEPLOY_SSH_KEY }}
run: |
if [ -z "$TYPE_TYPE_DEPLOY_HOST" ] || [ -z "$TYPE_TYPE_DEPLOY_PORT" ] || [ -z "$TYPE_TYPE_DEPLOY_USER" ] || [ -z "$TYPE_TYPE_DEPLOY_SSH_KEY" ]; then
echo "Deployment secrets are not configured; skipping deployment."
echo "configured=false" >> "$GITHUB_OUTPUT"
exit 0
fi
echo "configured=true" >> "$GITHUB_OUTPUT"

- name: Configure SSH
if: steps.deploy-config.outputs.configured == 'true'
env:
TYPE_TYPE_DEPLOY_HOST: ${{ secrets.TYPE_TYPE_DEPLOY_HOST }}
TYPE_TYPE_DEPLOY_PORT: ${{ secrets.TYPE_TYPE_DEPLOY_PORT }}
TYPE_TYPE_DEPLOY_SSH_KEY: ${{ secrets.TYPE_TYPE_DEPLOY_SSH_KEY }}
run: |
install -m 700 -d ~/.ssh
install -m 600 /dev/null ~/.ssh/typetype_deploy_key
printf '%s\n' "$TYPE_TYPE_DEPLOY_SSH_KEY" > ~/.ssh/typetype_deploy_key
ssh-keyscan -p "$TYPE_TYPE_DEPLOY_PORT" "$TYPE_TYPE_DEPLOY_HOST" >> ~/.ssh/known_hosts 2>/dev/null

- name: Deploy beta stack
if: steps.deploy-config.outputs.configured == 'true'
env:
TYPE_TYPE_DEPLOY_HOST: ${{ secrets.TYPE_TYPE_DEPLOY_HOST }}
TYPE_TYPE_DEPLOY_PORT: ${{ secrets.TYPE_TYPE_DEPLOY_PORT }}
TYPE_TYPE_DEPLOY_USER: ${{ secrets.TYPE_TYPE_DEPLOY_USER }}
run: |
ssh -i ~/.ssh/typetype_deploy_key -p "$TYPE_TYPE_DEPLOY_PORT" -o BatchMode=yes -o IdentitiesOnly=yes -o StrictHostKeyChecking=yes "$TYPE_TYPE_DEPLOY_USER@$TYPE_TYPE_DEPLOY_HOST" "/usr/local/sbin/typetype-beta-update"
curl --fail --retry 12 --retry-delay 2 --retry-all-errors --silent --show-error https://beta.typetype.video/api/health
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ local.properties
# AI agent instructions — local only, never committed
AGENTS.md
Vision.md
RESEARCH.MD

# Frontend integration guide — local only, shared manually
Backend.md
Expand Down
9 changes: 7 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,12 +1,17 @@
FROM --platform=$BUILDPLATFORM eclipse-temurin:25-jdk-alpine AS builder
ARG APP_VERSION=0.1.0
ARG GITHUB_SHA=unknown
ARG BUILD_TIME=unknown
ENV GITHUB_SHA=$GITHUB_SHA
ENV BUILD_TIME=$BUILD_TIME
WORKDIR /app
COPY gradlew ./
COPY gradle/ ./gradle/
RUN ./gradlew --version --no-daemon -q
COPY build.gradle.kts settings.gradle.kts* ./
COPY build.gradle.kts gradle.properties settings.gradle.kts* ./
RUN ./gradlew dependencies --no-daemon -q || true
COPY src/ ./src/
RUN ./gradlew shadowJar --no-daemon -q
RUN ./gradlew shadowJar --no-daemon -q -PappVersion="$APP_VERSION"

FROM eclipse-temurin:25-jre-alpine AS runner
RUN addgroup -S typetype && adduser -S typetype -G typetype
Expand Down
9 changes: 9 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,13 @@ docker compose -f docker-compose.dev-mirror.yml up -d
./scripts/bootstrap-garage.sh
```

On `arm64`/`aarch64` hosts, add the Dragonfly ARM override:

```bash
docker compose -f docker-compose.dev-mirror.yml -f docker-compose.arm64.yml up -d
COMPOSE_OVERRIDE_FILE="$PWD/docker-compose.arm64.yml" ./scripts/bootstrap-garage.sh
```

| Service | URL |
|---|---|
| Frontend | `http://localhost:28082` |
Expand All @@ -101,6 +108,8 @@ docker compose -f docker-compose.dev-mirror.yml up -d
| `DOWNLOADER_SERVICE_URL` | Base URL for TypeType-Downloader |
| `SUBTITLE_SERVICE_URL` | Base URL for TypeType-Token |

`DRAGONFLY_URL` is a Redis protocol URL consumed through Lettuce. The provided ARM Compose override keeps Dragonfly as the cache service, pins the `dragonfly` service to `linux/arm64`, and keeps the default URL as `redis://dragonfly:6379`.

## Checks

```bash
Expand Down
52 changes: 43 additions & 9 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
import java.time.Instant

plugins {
kotlin("jvm") version "2.4.0"
kotlin("plugin.serialization") version "2.4.0"
id("io.ktor.plugin") version "3.5.0"
id("io.ktor.plugin") version "3.5.1"
id("jacoco")
}

apply(from = "gradle/openapi-validation.gradle.kts")
group = "dev.typetype"
version = "0.0.1"
val applicationVersion = providers.gradleProperty("appVersion").get()
require(Regex("""(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?(?:\+[0-9A-Za-z-]+(?:\.[0-9A-Za-z-]+)*)?""").matches(applicationVersion)) {
"appVersion must be a valid semantic version"
}
version = applicationVersion
application {
mainClass.set("dev.typetype.server.ApplicationKt")
}
Expand All @@ -29,19 +35,20 @@ dependencies {
implementation("io.ktor:ktor-server-status-pages-jvm")
implementation("io.ktor:ktor-server-call-logging-jvm")
implementation("io.ktor:ktor-server-rate-limit-jvm")
implementation("ch.qos.logback:logback-classic:1.5.34")
implementation("com.github.InfinityLoop1308.PipePipeExtractor:extractor:e4b13eed86d83ae3ce309eb16e9e7460024a4d7b")
implementation("ch.qos.logback:logback-classic:1.5.38")
implementation("com.github.InfinityLoop1308.PipePipeExtractor:extractor:b974fde4a4586ae6111aa39c3132b9d1e331d90c")
compileOnly("com.github.TeamNewPipe:nanojson:1d9e1aea9049fc9f85e68b43ba39fe7be1c1f751")
implementation("org.json:json:20260522")
implementation("com.squareup.okhttp3:okhttp:5.4.0")
implementation("io.lettuce:lettuce-core:7.6.0.RELEASE")
implementation("org.jetbrains.exposed:exposed-core:1.3.0")
implementation("org.jetbrains.exposed:exposed-jdbc:1.3.0")
implementation("org.jetbrains.exposed:exposed-core:1.3.1")
implementation("org.jetbrains.exposed:exposed-jdbc:1.3.1")
implementation("com.zaxxer:HikariCP:7.1.0")
implementation("org.postgresql:postgresql:42.7.11")
implementation("org.postgresql:postgresql:42.7.13")
implementation("org.xerial:sqlite-jdbc:3.53.2.0")
implementation("com.password4j:password4j:1.8.4")
implementation("com.auth0:java-jwt:4.5.2")
testImplementation("org.junit.jupiter:junit-jupiter:6.1.0")
testImplementation("org.junit.jupiter:junit-jupiter:6.1.1")
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
testImplementation("io.mockk:mockk:1.14.11")
testImplementation("io.ktor:ktor-server-test-host-jvm")
Expand All @@ -52,9 +59,28 @@ dependencies {
testImplementation("org.testcontainers:testcontainers-junit-jupiter:2.0.5")
}
val buildInfoVersion = version.toString().trim().takeUnless { it.isBlank() || it == "unspecified" } ?: "0.0.0-dev"
fun gitRevisionOrUnknown(): String = runCatching {
providers.exec { commandLine("git", "rev-parse", "HEAD") }
.standardOutput
.asText
.get()
.trim()
.ifBlank { "unknown" }
}.getOrElse { "unknown" }

val buildInfoRevision = providers.environmentVariable("GITHUB_SHA")
.map { it.trim().ifBlank { "unknown" } }
.getOrElse(gitRevisionOrUnknown())
val buildInfoShortRevision = buildInfoRevision.takeIf { it != "unknown" }?.take(12) ?: "unknown"
val buildInfoBuildTime = providers.environmentVariable("BUILD_TIME")
.orElse(providers.provider { Instant.now().toString() })
.get()
val generatedBuildInfoDir = layout.buildDirectory.dir("generated/sources/buildInfo/main")
val generateBuildInfo = tasks.register("generateBuildInfo") {
inputs.property("version", buildInfoVersion)
inputs.property("revision", buildInfoRevision)
inputs.property("shortRevision", buildInfoShortRevision)
inputs.property("buildTime", buildInfoBuildTime)
outputs.dir(generatedBuildInfoDir)
doLast {
val output = generatedBuildInfoDir.get().file("dev/typetype/server/BuildInfo.kt").asFile
Expand All @@ -64,16 +90,24 @@ val generateBuildInfo = tasks.register("generateBuildInfo") {

object BuildInfo {
const val VERSION: String = "${buildInfoVersion.replace("\\", "\\\\").replace("\"", "\\\"")}"
const val REVISION: String = "${buildInfoRevision.replace("\\", "\\\\").replace("\"", "\\\"")}"
const val SHORT_REVISION: String = "${buildInfoShortRevision.replace("\\", "\\\\").replace("\"", "\\\"")}"
const val BUILD_TIME: String = "${buildInfoBuildTime.replace("\\", "\\\\").replace("\"", "\\\"")}"
}
""".trimIndent())
}
}

tasks.test {
useJUnitPlatform {
excludeTags("network")
// network-tagged tests are off by default. Flip on for the live SABR probe:
// ./gradlew test --tests SabrProbeTest -Dsabr.probe=true
if (System.getProperty("sabr.probe") != "true") excludeTags("network")
}
jvmArgs("-XX:+EnableDynamicAgentLoading", "-Xshare:off")
// Forward the gradle-level -Dsabr.probe=true to the test JVM so @EnabledIfSystemProperty can gate
// the live SABR probe (SabrProbeTest). Default "false" keeps the probe skipped in normal runs.
systemProperty("sabr.probe", System.getProperty("sabr.probe", "false"))
finalizedBy(tasks.jacocoTestReport)
}

Expand Down
4 changes: 4 additions & 0 deletions docker-compose.arm64.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
services:
dragonfly:
image: docker.dragonflydb.io/dragonflydb/dragonfly:latest
platform: linux/arm64
2 changes: 2 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ services:
ports:
- "8080:8080"
env_file: .env
environment:
DRAGONFLY_URL: ${DRAGONFLY_URL:-redis://dragonfly:6379}
depends_on:
- postgres
- dragonfly
Expand Down
1 change: 1 addition & 0 deletions gradle.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
org.gradle.jvmargs=-Xmx2g -XX:+UseG1GC
kotlin.code.style=official
appVersion=0.1.0
systemProp.sun.net.client.defaultReadTimeout=180000
systemProp.sun.net.client.defaultConnectTimeout=60000
4 changes: 2 additions & 2 deletions gradle/openapi-validation.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import java.net.URLClassLoader
import org.gradle.api.GradleException

val openApiValidator by configurations.creating
val openApiValidator = configurations.create("openApiValidator")

dependencies {
openApiValidator("io.swagger.parser.v3:swagger-parser-v3:2.1.44")
openApiValidator("io.swagger.parser.v3:swagger-parser-v3:2.1.45")
openApiValidator("org.slf4j:slf4j-nop:2.0.17")
}

Expand Down
Binary file modified gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
4 changes: 3 additions & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-9.5.1-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.6.1-bin.zip
networkTimeout=10000
retries=0
retryBackOffMs=500
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
2 changes: 1 addition & 1 deletion gradlew

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading