@krx3d/tizentube2 1.16.30 → 1.30.0
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.
- package/.github/FUNDING.yml +2 -1
- package/.github/assets/profiles.xml +18 -0
- package/.github/scripts/build-release-notes.sh +113 -0
- package/.github/workflows/build-publish-cleanup.yml +674 -0
- package/.github/workflows/build-standalone-release.yaml +305 -0
- package/.github/workflows/claude.yml +58 -0
- package/.github/workflows/codeql.yml +44 -0
- package/.github/workflows/upstream-sync.yml +165 -0
- package/AGENTS.md +898 -0
- package/README.md +202 -12
- package/dist/service.js +15267 -15966
- package/dist/userScript.js +3 -13
- package/package.json +4 -5
- package/scripts/log-receiver/receiver.ps1 +116 -0
- package/scripts/tampermonkey/tizentube-loader.user.js +18 -0
- package/scripts/tampermonkey/tizentube-log-button.user.js +54 -0
- package/standalone/config.xml +41 -0
- package/standalone/icon.png +0 -0
- package/standalone/icon_16b9.png +0 -0
- package/standalone/index.html +240 -0
|
@@ -0,0 +1,305 @@
|
|
|
1
|
+
# -----------------------------------------------------------------------------
|
|
2
|
+
# Build and release the TizenTube Standalone app (standalone/)
|
|
3
|
+
#
|
|
4
|
+
# WHAT THIS DOES
|
|
5
|
+
# ---------------
|
|
6
|
+
# Builds the userscript + regular DIAL service (needed by the standalone
|
|
7
|
+
# service), then the standalone service itself, then packages and signs
|
|
8
|
+
# standalone/ into a .wgt using Samsung's own Tizen Studio CLI, and publishes
|
|
9
|
+
# it as a GitHub Release.
|
|
10
|
+
#
|
|
11
|
+
# Signing note: this used to sign via tizenjs (an unofficial community
|
|
12
|
+
# packaging tool), which produced a .wgt that installed fine as an *update*
|
|
13
|
+
# to an already-trusted app but was rejected with "invalid certificate
|
|
14
|
+
# chain" on a brand-new app id's *first* install. Comparing against three
|
|
15
|
+
# sibling projects (TizenBrew, TizenBrewInstaller, TizenYouTube) that all
|
|
16
|
+
# install fine as fresh apps: the one thing they share and this build didn't
|
|
17
|
+
# is that they're all packaged with Samsung's own official Tizen Studio CLI
|
|
18
|
+
# (`tizen build-web` + `tizen package`), not tizenjs. TizenYouTube in
|
|
19
|
+
# particular proved this isn't about certificate freshness — it uses the
|
|
20
|
+
# exact same (long-expired) Samsung public sample distributor certificate
|
|
21
|
+
# tizenjs was also falling back to, and still installs fine, because it's
|
|
22
|
+
# packaged with the official tool. So this workflow now matches that same
|
|
23
|
+
# working recipe: install Tizen Studio, configure a certificate profile
|
|
24
|
+
# (author cert from secrets + Samsung's public sample distributor cert,
|
|
25
|
+
# same as TizenYouTube/TizenBrew use), and package with `tizen package`
|
|
26
|
+
# instead of tizenjs.
|
|
27
|
+
#
|
|
28
|
+
# This is entirely separate from build-publish-cleanup.yml (which builds and
|
|
29
|
+
# npm-publishes the regular mod on push to main) — different trigger, no
|
|
30
|
+
# shared state, so it doesn't affect that workflow.
|
|
31
|
+
#
|
|
32
|
+
# WHEN IT RUNS
|
|
33
|
+
# ------------
|
|
34
|
+
# - Automatically, right after "Build, publish and cleanup old npm versions"
|
|
35
|
+
# (build-publish-cleanup.yml) finishes successfully on main — i.e. once the
|
|
36
|
+
# userscript's new version has actually been bumped and published to npm.
|
|
37
|
+
# This keeps the standalone app's version in lockstep with the userscript:
|
|
38
|
+
# it reads the version build-publish-cleanup.yml just bumped in package.json
|
|
39
|
+
# and writes that same number into standalone/config.xml before packaging,
|
|
40
|
+
# rather than tracking its own separate version.
|
|
41
|
+
# - On pushing a tag matching v*.*.* (e.g. v1.0.0)
|
|
42
|
+
# - Manually via "Run workflow" (workflow_dispatch)
|
|
43
|
+
#
|
|
44
|
+
# PREREQUISITES (REQUIRED) — Tizen author certificate
|
|
45
|
+
# -----------------------------------------------------
|
|
46
|
+
# The build needs a Tizen author certificate to sign the .wgt.
|
|
47
|
+
#
|
|
48
|
+
# 1) Install Tizen Studio (or just the Certificate Manager) from
|
|
49
|
+
# https://developer.tizen.org/development/tizen-studio/download
|
|
50
|
+
#
|
|
51
|
+
# 2) Open Certificate Manager (Tizen Studio → Tools → Certificate Manager,
|
|
52
|
+
# or run `certificate-manager` directly from the Tizen Studio tools dir).
|
|
53
|
+
#
|
|
54
|
+
# 3) Author tab → "+" → "Create a new author certificate". Fill in a name,
|
|
55
|
+
# organization/email, and a password — remember this password. This
|
|
56
|
+
# produces an author.p12 file (Certificate Manager will tell you where
|
|
57
|
+
# it saved it).
|
|
58
|
+
#
|
|
59
|
+
# 4) Base64-encode the .p12 with NO line wrapping:
|
|
60
|
+
# Linux/macOS: base64 -w0 author.p12
|
|
61
|
+
# Windows (PowerShell):
|
|
62
|
+
# [Convert]::ToBase64String([IO.File]::ReadAllBytes("author.p12"))
|
|
63
|
+
#
|
|
64
|
+
# 5) Add two repository secrets (GitHub repo → Settings → Secrets and
|
|
65
|
+
# variables → Actions → New repository secret):
|
|
66
|
+
# TIZEN_AUTHOR_KEY = the base64 string from step 4
|
|
67
|
+
# TIZEN_AUTHOR_KEY_PW = the certificate password from step 3
|
|
68
|
+
#
|
|
69
|
+
# (The distributor certificate needs no setup — it's Samsung's own public
|
|
70
|
+
# sample certificate, bundled with Tizen Studio and installed automatically
|
|
71
|
+
# by this workflow, same as TizenBrew/TizenYouTube use.)
|
|
72
|
+
#
|
|
73
|
+
# HOW TO TRIGGER A BUILD
|
|
74
|
+
# -----------------------
|
|
75
|
+
# git tag v1.0.0 && git push origin v1.0.0
|
|
76
|
+
# (or use "Run workflow" in the Actions tab for an ad-hoc build)
|
|
77
|
+
# -----------------------------------------------------------------------------
|
|
78
|
+
|
|
79
|
+
name: Build TizenTube Standalone and Release
|
|
80
|
+
|
|
81
|
+
on:
|
|
82
|
+
workflow_run:
|
|
83
|
+
workflows: ['Build, publish and cleanup old npm versions']
|
|
84
|
+
types: [completed]
|
|
85
|
+
push:
|
|
86
|
+
tags:
|
|
87
|
+
- 'v*.*.*'
|
|
88
|
+
workflow_dispatch:
|
|
89
|
+
inputs:
|
|
90
|
+
release_version:
|
|
91
|
+
description: 'Release version/tag name (e.g. v1.0.0)'
|
|
92
|
+
required: false
|
|
93
|
+
|
|
94
|
+
env:
|
|
95
|
+
TIZEN_STUDIO_VER: 5.6
|
|
96
|
+
|
|
97
|
+
jobs:
|
|
98
|
+
build:
|
|
99
|
+
runs-on: ubuntu-latest
|
|
100
|
+
# Only proceed on a successful npm-publish run that was itself triggered by
|
|
101
|
+
# a push to main (build-publish-cleanup.yml's job is skipped entirely for
|
|
102
|
+
# pull_request runs, which can still report an overall "success" — checking
|
|
103
|
+
# .workflow_run.event too avoids firing off of those). Tag pushes and
|
|
104
|
+
# manual dispatch always proceed.
|
|
105
|
+
if: >
|
|
106
|
+
github.event_name != 'workflow_run' ||
|
|
107
|
+
(github.event.workflow_run.conclusion == 'success' && github.event.workflow_run.event == 'push')
|
|
108
|
+
permissions:
|
|
109
|
+
contents: write
|
|
110
|
+
steps:
|
|
111
|
+
# No explicit ref: default checkout behavior is already correct for every
|
|
112
|
+
# trigger — workflow_run checks out the default branch's current tip,
|
|
113
|
+
# push (tag) checks out the tag, workflow_dispatch checks out the branch
|
|
114
|
+
# it was run from. Pinning to github.event.workflow_run.head_sha (as an
|
|
115
|
+
# earlier version of this workflow did) is wrong: that's the commit that
|
|
116
|
+
# *triggered* build-publish-cleanup.yml, not the version-bump commit it
|
|
117
|
+
# produces partway through its own run — checking that out meant this
|
|
118
|
+
# workflow read package.json *before* the bump, one version behind.
|
|
119
|
+
- name: Clone repo with full history and tags
|
|
120
|
+
uses: actions/checkout@v5
|
|
121
|
+
with:
|
|
122
|
+
fetch-depth: 0
|
|
123
|
+
fetch-tags: true
|
|
124
|
+
|
|
125
|
+
- name: Record the commit this build is actually based on
|
|
126
|
+
run: echo "RELEASE_SHA=$(git rev-parse HEAD)" >> $GITHUB_ENV
|
|
127
|
+
|
|
128
|
+
- name: Setup Node.js
|
|
129
|
+
uses: actions/setup-node@v6
|
|
130
|
+
with:
|
|
131
|
+
node-version: '24'
|
|
132
|
+
|
|
133
|
+
- name: Determine release version (sync with userscript's package.json)
|
|
134
|
+
run: |
|
|
135
|
+
set -euo pipefail
|
|
136
|
+
if [ "${{ github.event_name }}" = "workflow_dispatch" ] && [ -n "${{ github.event.inputs.release_version }}" ]; then
|
|
137
|
+
RELEASE_VERSION="${{ github.event.inputs.release_version }}"
|
|
138
|
+
elif [[ "${GITHUB_REF}" == refs/tags/* ]]; then
|
|
139
|
+
RELEASE_VERSION="${GITHUB_REF#refs/tags/}"
|
|
140
|
+
elif [ -f package.json ]; then
|
|
141
|
+
PKG_VER=$(node -p "require('./package.json').version")
|
|
142
|
+
RELEASE_VERSION="${PKG_VER:+v$PKG_VER}"
|
|
143
|
+
fi
|
|
144
|
+
|
|
145
|
+
if [ -z "${RELEASE_VERSION:-}" ]; then
|
|
146
|
+
CFG_VER=$(sed -n 's/.*<widget[^>]*version="\([^"]*\)".*/\1/p' standalone/config.xml | head -n1)
|
|
147
|
+
RELEASE_VERSION="${CFG_VER:+v$CFG_VER}"
|
|
148
|
+
RELEASE_VERSION="${RELEASE_VERSION:-v0.0.0-${GITHUB_SHA:0:7}}"
|
|
149
|
+
fi
|
|
150
|
+
echo "RELEASE_VERSION=$RELEASE_VERSION" >> $GITHUB_ENV
|
|
151
|
+
|
|
152
|
+
- name: Sync standalone/config.xml version with the userscript's version
|
|
153
|
+
run: |
|
|
154
|
+
set -euo pipefail
|
|
155
|
+
NEW_VER="${RELEASE_VERSION#v}"
|
|
156
|
+
CUR_VER=$(sed -n 's/.*<widget[^>]*version="\([^"]*\)".*/\1/p' standalone/config.xml | head -n1)
|
|
157
|
+
if [ -n "$NEW_VER" ] && [ "$NEW_VER" != "$CUR_VER" ]; then
|
|
158
|
+
sed -i "0,/<widget /s/version=\"${CUR_VER}\"/version=\"${NEW_VER}\"/" standalone/config.xml
|
|
159
|
+
echo "standalone/config.xml version: ${CUR_VER} -> ${NEW_VER}"
|
|
160
|
+
else
|
|
161
|
+
echo "standalone/config.xml version already ${CUR_VER}, nothing to sync"
|
|
162
|
+
fi
|
|
163
|
+
|
|
164
|
+
- name: Determine app metadata for release notes
|
|
165
|
+
run: |
|
|
166
|
+
set -euo pipefail
|
|
167
|
+
APP_ID=$(sed -n 's/.*<tizen:application[^>]*id="\([^"]*\)".*/\1/p' standalone/config.xml | head -n1)
|
|
168
|
+
APP_NAME=$(echo "$APP_ID" | sed -n 's/^[^.]*\.\(.*\)$/\1/p')
|
|
169
|
+
echo "APP_ID=${APP_ID:-unknown}" >> $GITHUB_ENV
|
|
170
|
+
echo "APP_NAME=${APP_NAME:-unknown}" >> $GITHUB_ENV
|
|
171
|
+
|
|
172
|
+
# ----------------------------
|
|
173
|
+
# Build the regular mod + DIAL service — the standalone service wraps
|
|
174
|
+
# dist/service.js, so it must exist before the standalone service builds.
|
|
175
|
+
# ----------------------------
|
|
176
|
+
- name: Build mods (userScript.js)
|
|
177
|
+
working-directory: mods
|
|
178
|
+
run: |
|
|
179
|
+
set -euo pipefail
|
|
180
|
+
npm ci
|
|
181
|
+
npx rollup -c
|
|
182
|
+
|
|
183
|
+
- name: Build service (service.js)
|
|
184
|
+
working-directory: service
|
|
185
|
+
run: |
|
|
186
|
+
set -euo pipefail
|
|
187
|
+
npm ci
|
|
188
|
+
npx rollup -c
|
|
189
|
+
|
|
190
|
+
# ----------------------------
|
|
191
|
+
# Build the standalone service
|
|
192
|
+
# ----------------------------
|
|
193
|
+
- name: Build standalone service
|
|
194
|
+
working-directory: standalone/service
|
|
195
|
+
run: |
|
|
196
|
+
set -euo pipefail
|
|
197
|
+
npm install
|
|
198
|
+
npm install -g @vercel/ncc
|
|
199
|
+
npm run build
|
|
200
|
+
rm -rf node_modules transpiled
|
|
201
|
+
|
|
202
|
+
# ----------------------------
|
|
203
|
+
# Sign and package the standalone app with Tizen Studio
|
|
204
|
+
# ----------------------------
|
|
205
|
+
- name: Download Tizen Studio CLI
|
|
206
|
+
run: |
|
|
207
|
+
set -euo pipefail
|
|
208
|
+
curl -fL -o tizen-installer "https://download.tizen.org/sdk/Installer/tizen-studio_${TIZEN_STUDIO_VER}/web-cli_Tizen_Studio_${TIZEN_STUDIO_VER}_ubuntu-64.bin"
|
|
209
|
+
chmod +x tizen-installer
|
|
210
|
+
|
|
211
|
+
- name: Install Tizen Studio CLI
|
|
212
|
+
run: |
|
|
213
|
+
set -euo pipefail
|
|
214
|
+
./tizen-installer --accept-license "${GITHUB_WORKSPACE}/tizen-studio"
|
|
215
|
+
rm ./tizen-installer
|
|
216
|
+
echo "${GITHUB_WORKSPACE}/tizen-studio/tools/ide/bin" >> $GITHUB_PATH
|
|
217
|
+
|
|
218
|
+
- name: Configure certificate profile
|
|
219
|
+
env:
|
|
220
|
+
AUTHOR_P12_B64: ${{ secrets.TIZEN_AUTHOR_KEY }}
|
|
221
|
+
AUTHOR_P12_PASSWORD: ${{ secrets.TIZEN_AUTHOR_KEY_PW }}
|
|
222
|
+
run: |
|
|
223
|
+
set -euo pipefail
|
|
224
|
+
mkdir -p "${GITHUB_WORKSPACE}/tizen-data/keystore/author"
|
|
225
|
+
mkdir -p "${GITHUB_WORKSPACE}/tizen-data/profile"
|
|
226
|
+
echo "$AUTHOR_P12_B64" | base64 -d > "${GITHUB_WORKSPACE}/tizen-data/keystore/author/author.p12"
|
|
227
|
+
|
|
228
|
+
echo "Author cert encryption before conversion:"
|
|
229
|
+
openssl pkcs12 -info -in "${GITHUB_WORKSPACE}/tizen-data/keystore/author/author.p12" -passin env:AUTHOR_P12_PASSWORD -noout 2>&1 | grep -i "pbe\|cipher\|mac" || true
|
|
230
|
+
|
|
231
|
+
# Tizen Studio's bundled Java signing tool is old and can fail to read a
|
|
232
|
+
# PKCS#12 file encrypted with the modern AES-256 cipher OpenSSL 3.x (the
|
|
233
|
+
# default everywhere since ~2021) uses by default — throwing a generic,
|
|
234
|
+
# misleading "Invalid password" even when the password is correct. Both
|
|
235
|
+
# node-forge (what tizenjs used) and modern OpenSSL read AES-256 p12s
|
|
236
|
+
# fine, so this wouldn't have surfaced until switching to Tizen Studio's
|
|
237
|
+
# own tooling. Re-encrypt with the older, broadly-compatible cipher
|
|
238
|
+
# in-place — same password, same cert/key contents, just an older wrapper.
|
|
239
|
+
openssl pkcs12 -legacy -in "${GITHUB_WORKSPACE}/tizen-data/keystore/author/author.p12" -out /tmp/author-intermediate.pem -nodes -passin env:AUTHOR_P12_PASSWORD
|
|
240
|
+
openssl pkcs12 -export -legacy -in /tmp/author-intermediate.pem -passout env:AUTHOR_P12_PASSWORD -out "${GITHUB_WORKSPACE}/tizen-data/keystore/author/author.p12" -certpbe PBE-SHA1-3DES -keypbe PBE-SHA1-3DES -macalg sha1
|
|
241
|
+
rm -f /tmp/author-intermediate.pem
|
|
242
|
+
|
|
243
|
+
echo "Author cert encryption after conversion:"
|
|
244
|
+
openssl pkcs12 -info -in "${GITHUB_WORKSPACE}/tizen-data/keystore/author/author.p12" -passin env:AUTHOR_P12_PASSWORD -noout 2>&1 | grep -i "pbe\|cipher\|mac" || true
|
|
245
|
+
|
|
246
|
+
cp .github/assets/profiles.xml "${GITHUB_WORKSPACE}/tizen-data/profile/profiles.xml"
|
|
247
|
+
python3 -c "from pathlib import Path; import os; from xml.sax.saxutils import escape; p=Path(os.environ['GITHUB_WORKSPACE'])/'tizen-data/profile/profiles.xml'; t=p.read_text(); t=t.replace('\$GITHUB_WORKSPACE', os.environ['GITHUB_WORKSPACE']).replace('\$KEY_PW', escape(os.environ['AUTHOR_P12_PASSWORD'], {'\"':'"'})); p.write_text(t)"
|
|
248
|
+
|
|
249
|
+
tizen cli-config "profiles.path=${GITHUB_WORKSPACE}/tizen-data/profile/profiles.xml"
|
|
250
|
+
|
|
251
|
+
- name: Build web app
|
|
252
|
+
working-directory: standalone
|
|
253
|
+
run: >
|
|
254
|
+
tizen build-web
|
|
255
|
+
-e "service/index.js"
|
|
256
|
+
-e "service/injector.js"
|
|
257
|
+
-e "service/bootstrap.js"
|
|
258
|
+
-e "service/build-service.js"
|
|
259
|
+
-e "service/package.json"
|
|
260
|
+
-e "service/package-lock.json"
|
|
261
|
+
-e "service/node_modules"
|
|
262
|
+
-e "release"
|
|
263
|
+
|
|
264
|
+
- name: Package WGT
|
|
265
|
+
working-directory: standalone
|
|
266
|
+
run: |
|
|
267
|
+
set -euo pipefail
|
|
268
|
+
tizen package -t wgt -s TizenTubeStandalone -- ./
|
|
269
|
+
mkdir -p release
|
|
270
|
+
cp *.wgt release/TizenTube.wgt
|
|
271
|
+
|
|
272
|
+
- name: Show Tizen CLI log on failure
|
|
273
|
+
if: failure()
|
|
274
|
+
run: |
|
|
275
|
+
LOG_PATH="${GITHUB_WORKSPACE}/tizen-studio-data/cli/logs/cli.log"
|
|
276
|
+
if [ -f "$LOG_PATH" ]; then
|
|
277
|
+
echo "--- tizen cli.log ---"
|
|
278
|
+
cat "$LOG_PATH"
|
|
279
|
+
else
|
|
280
|
+
echo "No cli.log found at $LOG_PATH"
|
|
281
|
+
fi
|
|
282
|
+
|
|
283
|
+
- name: Upload TizenTube Standalone artifact
|
|
284
|
+
uses: actions/upload-artifact@v6
|
|
285
|
+
with:
|
|
286
|
+
name: TizenTube-Standalone-${{ env.RELEASE_SHA }}.wgt
|
|
287
|
+
path: standalone/release/TizenTube.wgt
|
|
288
|
+
|
|
289
|
+
# Changelog is built from the PRs merged since the previous published
|
|
290
|
+
# release; the build/TBI_METADATA header stays first so the TizenBrew
|
|
291
|
+
# Installer still finds it.
|
|
292
|
+
- name: Build release notes
|
|
293
|
+
env:
|
|
294
|
+
GH_TOKEN: ${{ github.token }}
|
|
295
|
+
run: |
|
|
296
|
+
bash .github/scripts/build-release-notes.sh "${{ env.RELEASE_SHA }}" "${{ env.RELEASE_VERSION }}" "${{ env.APP_ID }}" "${{ env.APP_NAME }}" "$RUNNER_TEMP/release-notes.md"
|
|
297
|
+
|
|
298
|
+
- name: Release TizenTube Standalone
|
|
299
|
+
uses: softprops/action-gh-release@v1
|
|
300
|
+
with:
|
|
301
|
+
tag_name: ${{ env.RELEASE_VERSION }}
|
|
302
|
+
target_commitish: ${{ env.RELEASE_SHA }}
|
|
303
|
+
body_path: ${{ runner.temp }}/release-notes.md
|
|
304
|
+
files: |
|
|
305
|
+
standalone/release/*
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
name: Claude Code
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
issue_comment:
|
|
5
|
+
types: [created]
|
|
6
|
+
pull_request_review_comment:
|
|
7
|
+
types: [created]
|
|
8
|
+
issues:
|
|
9
|
+
types: [opened, assigned]
|
|
10
|
+
pull_request_review:
|
|
11
|
+
types: [submitted]
|
|
12
|
+
|
|
13
|
+
jobs:
|
|
14
|
+
claude:
|
|
15
|
+
if: |
|
|
16
|
+
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
17
|
+
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude')) ||
|
|
18
|
+
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude')) ||
|
|
19
|
+
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
|
20
|
+
runs-on: ubuntu-latest
|
|
21
|
+
permissions:
|
|
22
|
+
contents: write
|
|
23
|
+
pull-requests: write
|
|
24
|
+
issues: write
|
|
25
|
+
id-token: write
|
|
26
|
+
actions: read # Required for Claude to read CI results on PRs
|
|
27
|
+
steps:
|
|
28
|
+
- name: Checkout repository
|
|
29
|
+
uses: actions/checkout@v6
|
|
30
|
+
with:
|
|
31
|
+
fetch-depth: 1
|
|
32
|
+
|
|
33
|
+
- name: Run Claude Code
|
|
34
|
+
id: claude
|
|
35
|
+
uses: anthropics/claude-code-action@v1
|
|
36
|
+
with:
|
|
37
|
+
anthropic_api_key: ${{ secrets.ANTHROPIC_API_KEY }}
|
|
38
|
+
|
|
39
|
+
# Optional: Customize the trigger phrase (default: @claude)
|
|
40
|
+
# trigger_phrase: "/claude"
|
|
41
|
+
|
|
42
|
+
# Optional: Trigger when specific user is assigned to an issue
|
|
43
|
+
# assignee_trigger: "claude-bot"
|
|
44
|
+
|
|
45
|
+
# Optional: Configure Claude's behavior with CLI arguments
|
|
46
|
+
# claude_args: |
|
|
47
|
+
# --model claude-opus-4-1-20250805
|
|
48
|
+
# --max-turns 10
|
|
49
|
+
# --allowedTools "Bash(npm install),Bash(npm run build),Bash(npm run test:*),Bash(npm run lint:*)"
|
|
50
|
+
# --system-prompt "Follow our coding standards. Ensure all new code has tests. Use TypeScript for new files."
|
|
51
|
+
|
|
52
|
+
# Optional: Advanced settings configuration
|
|
53
|
+
# settings: |
|
|
54
|
+
# {
|
|
55
|
+
# "env": {
|
|
56
|
+
# "NODE_ENV": "test"
|
|
57
|
+
# }
|
|
58
|
+
# }
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
name: "CodeQL"
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: ["main"]
|
|
6
|
+
pull_request:
|
|
7
|
+
branches: ["main"]
|
|
8
|
+
schedule:
|
|
9
|
+
- cron: '23 3 * * 1'
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
analyze:
|
|
13
|
+
name: Analyze (${{ matrix.language }})
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
permissions:
|
|
16
|
+
actions: read
|
|
17
|
+
contents: read
|
|
18
|
+
security-events: write
|
|
19
|
+
|
|
20
|
+
strategy:
|
|
21
|
+
fail-fast: false
|
|
22
|
+
matrix:
|
|
23
|
+
language: ["javascript-typescript"]
|
|
24
|
+
|
|
25
|
+
steps:
|
|
26
|
+
- name: Checkout repository
|
|
27
|
+
uses: actions/checkout@v6
|
|
28
|
+
|
|
29
|
+
- name: Initialize CodeQL
|
|
30
|
+
uses: github/codeql-action/init@v4
|
|
31
|
+
with:
|
|
32
|
+
languages: ${{ matrix.language }}
|
|
33
|
+
queries: security-extended,security-and-quality
|
|
34
|
+
config: |
|
|
35
|
+
paths-ignore:
|
|
36
|
+
- dist/**
|
|
37
|
+
|
|
38
|
+
- name: Autobuild
|
|
39
|
+
uses: github/codeql-action/autobuild@v4
|
|
40
|
+
|
|
41
|
+
- name: Perform CodeQL Analysis
|
|
42
|
+
uses: github/codeql-action/analyze@v4
|
|
43
|
+
with:
|
|
44
|
+
category: "/language:${{matrix.language}}"
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
# Watch reisxd/TizenTube for new commits and open a PR that carries them.
|
|
2
|
+
#
|
|
3
|
+
# This fork has rewritten large parts of mods/ (adblock.js, hideWatched.js,
|
|
4
|
+
# settings.js in particular), so most upstream commits touching those files
|
|
5
|
+
# WILL conflict. The workflow does not pretend otherwise: it always produces a
|
|
6
|
+
# branch that merges cleanly into main, and when a file conflicted it keeps the
|
|
7
|
+
# fork's version and says so in the PR body, so the upstream change can be
|
|
8
|
+
# hand-ported afterwards.
|
|
9
|
+
name: Upstream sync
|
|
10
|
+
|
|
11
|
+
on:
|
|
12
|
+
schedule:
|
|
13
|
+
# 04:20 UTC daily — outside the usual release window.
|
|
14
|
+
- cron: '20 4 * * *'
|
|
15
|
+
workflow_dispatch:
|
|
16
|
+
|
|
17
|
+
concurrency:
|
|
18
|
+
group: upstream-sync
|
|
19
|
+
cancel-in-progress: false
|
|
20
|
+
|
|
21
|
+
env:
|
|
22
|
+
UPSTREAM_REPO: https://github.com/reisxd/TizenTube.git
|
|
23
|
+
UPSTREAM_BRANCH: main
|
|
24
|
+
UPSTREAM_BRANCH_REF: upstream/main
|
|
25
|
+
SYNC_BRANCH: sync/upstream
|
|
26
|
+
|
|
27
|
+
jobs:
|
|
28
|
+
sync:
|
|
29
|
+
runs-on: ubuntu-latest
|
|
30
|
+
permissions:
|
|
31
|
+
contents: write
|
|
32
|
+
pull-requests: write
|
|
33
|
+
steps:
|
|
34
|
+
- name: Clone repo with full history
|
|
35
|
+
uses: actions/checkout@v5
|
|
36
|
+
with:
|
|
37
|
+
fetch-depth: 0
|
|
38
|
+
|
|
39
|
+
- name: Configure git identity
|
|
40
|
+
run: |
|
|
41
|
+
git config user.name 'github-actions[bot]'
|
|
42
|
+
git config user.email 'github-actions[bot]@users.noreply.github.com'
|
|
43
|
+
|
|
44
|
+
- name: Fetch upstream
|
|
45
|
+
run: |
|
|
46
|
+
set -euo pipefail
|
|
47
|
+
git remote add upstream "$UPSTREAM_REPO" 2>/dev/null || git remote set-url upstream "$UPSTREAM_REPO"
|
|
48
|
+
git fetch upstream "$UPSTREAM_BRANCH" --no-tags
|
|
49
|
+
|
|
50
|
+
- name: Check for new upstream commits
|
|
51
|
+
id: check
|
|
52
|
+
run: |
|
|
53
|
+
set -euo pipefail
|
|
54
|
+
COUNT=$(git rev-list --count "origin/main..upstream/${UPSTREAM_BRANCH}")
|
|
55
|
+
echo "count=$COUNT" >> "$GITHUB_OUTPUT"
|
|
56
|
+
echo "Upstream commits not in main: $COUNT"
|
|
57
|
+
|
|
58
|
+
- name: Merge upstream, keeping the fork's side of any conflict
|
|
59
|
+
id: merge
|
|
60
|
+
if: steps.check.outputs.count != '0'
|
|
61
|
+
run: |
|
|
62
|
+
set -euo pipefail
|
|
63
|
+
BASE_SHA=$(git rev-parse origin/main)
|
|
64
|
+
git checkout -B "$SYNC_BRANCH" origin/main
|
|
65
|
+
|
|
66
|
+
# --no-commit so the CI-exclusion below lands in the same commit
|
|
67
|
+
# whether or not the merge conflicted, rather than needing a second.
|
|
68
|
+
CONFLICTS=""
|
|
69
|
+
git merge --no-commit --no-ff "$UPSTREAM_BRANCH_REF" || true
|
|
70
|
+
|
|
71
|
+
CONFLICTS=$(git diff --name-only --diff-filter=U || true)
|
|
72
|
+
if [ -n "$CONFLICTS" ]; then
|
|
73
|
+
# Keep this fork's version of every conflicted file. The point of
|
|
74
|
+
# the PR is to surface the change for review, not to guess at a
|
|
75
|
+
# resolution — committing conflict markers would only produce a
|
|
76
|
+
# branch that cannot build.
|
|
77
|
+
echo "Conflicted files kept at fork version:"
|
|
78
|
+
echo "$CONFLICTS"
|
|
79
|
+
while IFS= read -r f; do
|
|
80
|
+
[ -z "$f" ] && continue
|
|
81
|
+
git checkout --ours -- "$f" 2>/dev/null || git rm -q -- "$f"
|
|
82
|
+
git add -- "$f" 2>/dev/null || true
|
|
83
|
+
done <<< "$CONFLICTS"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# CI is never synced from upstream, for two reasons. This fork runs
|
|
87
|
+
# its own workflows (npm publish, standalone .wgt build, this sync)
|
|
88
|
+
# which have no upstream counterpart, so importing theirs would be
|
|
89
|
+
# actively wrong. And GITHUB_TOKEN *cannot* push changes under
|
|
90
|
+
# .github/workflows at all — there is no "workflows" permission in
|
|
91
|
+
# the permissions: block, that scope exists only for PATs and GitHub
|
|
92
|
+
# Apps, so a push carrying one is rejected outright:
|
|
93
|
+
# refusing to allow a GitHub App to create or update workflow
|
|
94
|
+
# `.github/workflows/...` without `workflows` permission
|
|
95
|
+
# Restoring the directory to exactly origin/main covers both the
|
|
96
|
+
# modified and the newly-added case.
|
|
97
|
+
if git rev-parse --verify -q "${BASE_SHA}:.github/workflows" >/dev/null; then
|
|
98
|
+
git rm -rf --quiet --ignore-unmatch .github/workflows >/dev/null 2>&1 || true
|
|
99
|
+
git checkout "$BASE_SHA" -- .github/workflows
|
|
100
|
+
git add -A .github/workflows
|
|
101
|
+
echo "Restored .github/workflows to the fork's version"
|
|
102
|
+
fi
|
|
103
|
+
|
|
104
|
+
# A clean merge leaves everything staged but uncommitted because of
|
|
105
|
+
# --no-commit; a conflicted one is staged by the loop above.
|
|
106
|
+
git commit --no-edit || echo "Nothing to commit"
|
|
107
|
+
|
|
108
|
+
{
|
|
109
|
+
echo 'conflicts<<TT_EOF'
|
|
110
|
+
echo "$CONFLICTS"
|
|
111
|
+
echo 'TT_EOF'
|
|
112
|
+
} >> "$GITHUB_OUTPUT"
|
|
113
|
+
|
|
114
|
+
if git diff --quiet origin/main -- .; then
|
|
115
|
+
echo "changed=false" >> "$GITHUB_OUTPUT"
|
|
116
|
+
else
|
|
117
|
+
echo "changed=true" >> "$GITHUB_OUTPUT"
|
|
118
|
+
git push --force-with-lease origin "$SYNC_BRANCH"
|
|
119
|
+
fi
|
|
120
|
+
|
|
121
|
+
- name: Open or update the sync PR
|
|
122
|
+
if: steps.check.outputs.count != '0' && steps.merge.outputs.changed == 'true'
|
|
123
|
+
env:
|
|
124
|
+
GH_TOKEN: ${{ github.token }}
|
|
125
|
+
CONFLICTS: ${{ steps.merge.outputs.conflicts }}
|
|
126
|
+
NEW_COMMITS: ${{ steps.check.outputs.count }}
|
|
127
|
+
run: |
|
|
128
|
+
set -euo pipefail
|
|
129
|
+
|
|
130
|
+
{
|
|
131
|
+
echo "Automated sync with [reisxd/TizenTube](https://github.com/reisxd/TizenTube) — **${NEW_COMMITS}** new upstream commit(s)."
|
|
132
|
+
echo
|
|
133
|
+
|
|
134
|
+
if [ -n "${CONFLICTS//[[:space:]]/}" ]; then
|
|
135
|
+
echo "## :warning: Needs hand-porting"
|
|
136
|
+
echo
|
|
137
|
+
echo "These files conflicted and were **kept at this fork's version**, so the upstream changes to them are *not* in this PR. Merging as-is is safe but incomplete — port them by hand before or after merging:"
|
|
138
|
+
echo
|
|
139
|
+
while IFS= read -r f; do
|
|
140
|
+
[ -z "$f" ] && continue
|
|
141
|
+
echo "- \`$f\`"
|
|
142
|
+
done <<< "$CONFLICTS"
|
|
143
|
+
echo
|
|
144
|
+
else
|
|
145
|
+
echo "Merged cleanly — no conflicts."
|
|
146
|
+
echo
|
|
147
|
+
fi
|
|
148
|
+
|
|
149
|
+
echo "## Upstream commits"
|
|
150
|
+
echo
|
|
151
|
+
git log --reverse --no-merges --pretty=format:'- [`%h`](https://github.com/reisxd/TizenTube/commit/%H) %s' "origin/main..upstream/${UPSTREAM_BRANCH}"
|
|
152
|
+
echo
|
|
153
|
+
echo
|
|
154
|
+
echo "_Opened automatically by \`.github/workflows/upstream-sync.yml\`._"
|
|
155
|
+
} > /tmp/pr-body.md
|
|
156
|
+
|
|
157
|
+
EXISTING=$(gh pr list --head "$SYNC_BRANCH" --state open --json number --jq '.[0].number // empty')
|
|
158
|
+
TITLE="Sync with upstream (${NEW_COMMITS} new commit(s))"
|
|
159
|
+
|
|
160
|
+
if [ -n "$EXISTING" ]; then
|
|
161
|
+
gh pr edit "$EXISTING" --title "$TITLE" --body-file /tmp/pr-body.md
|
|
162
|
+
echo "Updated PR #$EXISTING"
|
|
163
|
+
else
|
|
164
|
+
gh pr create --base main --head "$SYNC_BRANCH" --title "$TITLE" --body-file /tmp/pr-body.md
|
|
165
|
+
fi
|