new app store assets ready for relese
@@ -0,0 +1,33 @@
|
||||
# Tarnax App Store release pack
|
||||
|
||||
Prepared for version 1.0, build 8. Support: mark.gregory@abbeysoftware.com.
|
||||
|
||||
Open `index.html` to browse the assets. This folder is a local preparation pack; nothing has been uploaded or published.
|
||||
|
||||
## Upload assets
|
||||
|
||||
- `screenshots/upload/iphone-6.9`: six finished portrait PNGs, 1320 × 2868.
|
||||
- `screenshots/upload/ipad-13`: six finished portrait PNGs, 2064 × 2752.
|
||||
- `screenshots/raw`: untouched underlying app captures with fictitious lawful sample data.
|
||||
- `icons/Tarnax-AppStore-1024.png`: opaque master icon. Smaller icons support website/press use; Xcode's existing asset catalog supplies the app icon.
|
||||
- `previews`: optional 24-second silent H.264 app previews and posters, iPhone 886 × 1920 and iPad 1200 × 1600. These present six static views from actual simulator footage; they do not demonstrate live gestures or a real server session. Preview them before choosing whether to upload.
|
||||
- `metadata/en-GB` and `en-US`: app name, subtitle, description, promotional text, keywords and first-release notes.
|
||||
- `marketing`: social artwork, press header, brand guide and contact sheets. These are not App Store screenshot uploads.
|
||||
|
||||
## Privacy, support and review
|
||||
|
||||
`website/` is a complete static support/marketing/privacy website. Publish only this directory on your chosen host. No hosting address has been invented. Add the resulting support and privacy URLs to `release-config.json` and App Store Connect.
|
||||
|
||||
`legal/` includes privacy policy, usage information and the privacy manifest also bundled in the app. `review/` contains reviewer instructions, the dedicated review-server checklist, proposed privacy-label assessment, age-rating worksheet and release checklist. Complete and confirm the assessments against your actual operating practices.
|
||||
|
||||
Supply an externally reachable, dedicated qBittorrent review server with disposable lawful content and credentials directly in App Store Connect. The screenshot fixture is isolated in Scratch, is not compiled into the production archive and does not replace reviewer access. Do not put passwords into this folder.
|
||||
|
||||
Outstanding owner decisions are recorded as nulls in `release-config.json`: website URLs, price, territories and reviewer contact phone. Naming rights, agreements, content rights, privacy and age-rating answers also require your confirmation. Earlier name searches do not establish trademark clearance.
|
||||
|
||||
## Build and reproduce
|
||||
|
||||
Run `scripts/test.sh --contracts-only` from the project. All 83 checks passed during preparation, and the Release archive built successfully. `appstore/tools/archive.sh` creates an App Store archive and attempts a local IPA export using existing signing assets. The optional `--allow-provisioning-updates` flag requires permission to update your developer account. A direct-install IPA is not an App Store upload binary.
|
||||
|
||||
Capture and rendering scripts in `tools/` use temporary files beneath `~/Developer/Scratch/Tarnax`. `capture.sh` builds an isolated fixture copy, `render_assets.py` uses Pillow, `make_previews.py` needs ffmpeg, and `build_website.py` regenerates the website. Run `validate.py` with a Python environment containing Pillow; add `--submission-ready` to require owner setup as well. `validation-report.json` records the latest result and `SHA256SUMS` records asset hashes.
|
||||
|
||||
Build archives under `build/` are private local release materials; do not publish them with the website. See `SOURCES.md` for Apple's requirements and `review/release-checklist.md` for final submission steps. No App Store acceptance or legal clearance is implied by local validation.
|
||||
@@ -0,0 +1,86 @@
|
||||
814301cd2ff741349e261e624d67809174caa6a08b2d94df3087f368f2f97e03 README.md
|
||||
0d1add7f9c86aaf802a9dd94b656c7b7bc5a5f28bc1f30e216ab41f82bfd4461 SOURCES.md
|
||||
c0e22e36f2c5f92802c6797c069cc58af6f68664e31a5d50bb774e33283dec75 asset-manifest.json
|
||||
18605382e1371769278f7d9cc30952886e87ce9c2192078480d8f449d68fffad icons/Tarnax-128.png
|
||||
8eccf035da8692920262e9f917b6f2971f9a9386a0125d773fb778a53367e0ed icons/Tarnax-180.png
|
||||
2aefc2583182234d263fb6bea8662a4bde0bd17030811cd50243d99bd544f402 icons/Tarnax-256.png
|
||||
283777a7ae895a7e6f0dc0b76c17597eec98d522ed8564eac48bc88aa466d1e3 icons/Tarnax-32.png
|
||||
adc9b33c96681be7a55ad93da090f07406653df48e1c1657f651c1fbaddf8329 icons/Tarnax-512.png
|
||||
2383de3a526e25413c992a6185230b71aa8c52bb23a33f369eb38bf173ee6bd5 icons/Tarnax-64.png
|
||||
0dd661c392e1704bdbf1b34db1a32ec5c1f063d5f8565f84d0df69b8383e0e19 icons/Tarnax-AppStore-1024.png
|
||||
362a665353a95c17045d7118bbd4b1aa3edc18d69bb906d9e65f00700aad9cb3 index.html
|
||||
a331d51864743ebe4e00dd22360b4a538b6b3ac26a6b3eb54094e60a36959a12 legal/PrivacyInfo.xcprivacy
|
||||
13f929aae013a42408dd4e95cc6d42947b344a01c36292a58c804c708b370619 legal/privacy-policy.md
|
||||
891b9cef0cc799c9dddf595afa763093ee0cfc46becba5d58ea1e9d206d367ed legal/terms-of-use.md
|
||||
07f2891f660a425b5e1136173133d1cd13443f9c46ef3b581b511f608a5f36b4 marketing/brand-guide.md
|
||||
d50904cccdcc439f340aff7253d561c350dcb88947389ac5abee14db7fa8c8b5 marketing/contact-sheet-ipad-13.jpg
|
||||
2300f54d1f697d329022cb942bb97e88c338d0c844e9d14bb2bf5eaea4db5aa8 marketing/contact-sheet-iphone-6.9.jpg
|
||||
34af26c9b1d9fa91ea5ff43fd264129df874583aaf961bea9ec38ea7ca1aa29b marketing/press-header.png
|
||||
9880f405de5b4ca628c0042d62b18b7388bc136fbc5e4541ab94237965fa3a20 marketing/social-landscape.png
|
||||
ddca648c4c88fbc726307241e05880b5c0d94329df22b728b6b45e1bd1ad081d marketing/social-square.png
|
||||
350c55e38678eaf972ff653007ddcf67eb17354b15aa56cb51383fa873b7d8fc metadata/en-GB/description.txt
|
||||
da3d8b42e6767a202975ab3acc35ab8840d4e13bcaa0a5901f94ff1a54dc72a0 metadata/en-GB/keywords.txt
|
||||
f8c26eae41d0601da204abe258342ee34400599b47f437e77168a6864f13e621 metadata/en-GB/name.txt
|
||||
32604bff19071ee403f69b81bad430af9069dbb60c4422305a648a6fda891825 metadata/en-GB/promotional_text.txt
|
||||
8a2dac92364607cbc829d397addc9f6725dfa939b0a1f39d032693a640114bb8 metadata/en-GB/release_notes.txt
|
||||
abb964f8c8c960cbfbdc12559cd5c1a9c015f1e370cbc9f80f74a6bb18609a98 metadata/en-GB/subtitle.txt
|
||||
350c55e38678eaf972ff653007ddcf67eb17354b15aa56cb51383fa873b7d8fc metadata/en-US/description.txt
|
||||
da3d8b42e6767a202975ab3acc35ab8840d4e13bcaa0a5901f94ff1a54dc72a0 metadata/en-US/keywords.txt
|
||||
f8c26eae41d0601da204abe258342ee34400599b47f437e77168a6864f13e621 metadata/en-US/name.txt
|
||||
32604bff19071ee403f69b81bad430af9069dbb60c4422305a648a6fda891825 metadata/en-US/promotional_text.txt
|
||||
8a2dac92364607cbc829d397addc9f6725dfa939b0a1f39d032693a640114bb8 metadata/en-US/release_notes.txt
|
||||
abb964f8c8c960cbfbdc12559cd5c1a9c015f1e370cbc9f80f74a6bb18609a98 metadata/en-US/subtitle.txt
|
||||
846ef7bd0c544289a9cc557570a90e40b546cbe08081c331098e94901c4080b4 previews/Tarnax-ipad-13-poster.png
|
||||
91d7857e4b1e278f40b179109e49c9e81d8b5bc77ac72095699f1385eba36d13 previews/Tarnax-ipad-13-preview.mp4
|
||||
3c912b3e563ffba5d684efc2850fbc2f3d93fc2e47cc0a2c38b49f68074c747b previews/Tarnax-iphone-6.9-poster.png
|
||||
bad1bed9c0d189a5e0083e790e225f644a7540a148a767e1f94b4106d958c08b previews/Tarnax-iphone-6.9-preview.mp4
|
||||
6e643c2736ed9fe2d10654c2a4238761b5c68a51125c4d4713ba6198c3276910 previews/preview-info.json
|
||||
050237c08cc0a9c9dcca3ff9c5acbff1c8e5ad0f2df0dd4743e13152ac101315 release-config.json
|
||||
f61ea210a854c21882064bb8d77ebf034635a4ccf927e8fd9961311245854d23 review/age-rating-and-compliance.md
|
||||
231309841c54f8bfdb69498b17e1e5d8a7e186dc7d1ac230615854ea2d17c9c2 review/privacy-label-assessment.md
|
||||
7bb449344015bed537e4d76f9d03a404c7e580ad8c39d5fe25d97d879a0abf67 review/release-checklist.md
|
||||
38960e34592cdce7c462e1257074ac5c052e36be1b48453d70513eb2216b0a2a review/review-notes.txt
|
||||
450dc35958ad9eabcf36a7bf5acf6b5878f986a74fc07678c28b59dff6dd9a67 review/reviewer-access-checklist.md
|
||||
595994544ddd1a03c5b238f5103dd9c10b427d4d19db53e98a3a861fb861b311 screenshots/raw/ipad-13/01-home.png
|
||||
bd427c6f416c37bb300d798774384bbcd3ecabe10fc0ede3837433f03eb2fb15 screenshots/raw/ipad-13/02-library.png
|
||||
7e9bb3deb1444024f6f145a2a4df70557655ccf3ac34bfaab76e5ed93bc25619 screenshots/raw/ipad-13/03-details.png
|
||||
33920fb8f42f18c5eaf737c810cf645ee3446ed6205d5a272c0368fcde0d2707 screenshots/raw/ipad-13/04-files.png
|
||||
40af107fa83aacc283508e30294a7ace6fec5a18e9f4c6ee82717f342b6b112e screenshots/raw/ipad-13/05-settings.png
|
||||
47d40a830c309dd82176dfb808ac502d5ec01f36ae9cd4c86d748b5678259cce screenshots/raw/ipad-13/06-add.png
|
||||
fcb7b8f98e1b5e11c9e1ce18c00532d6a4130c7d6e85c0b43139a9c3b06e444e screenshots/raw/iphone-6.9/01-home.png
|
||||
fefcc73bc2c2770215aa3ae103b3f301d8a38104923896d44500cd6efaa7e68f screenshots/raw/iphone-6.9/02-library.png
|
||||
8a716a7aeae5f9ec82cd952d4722219273f307c3658744196a024e7ecdfbeb23 screenshots/raw/iphone-6.9/03-details.png
|
||||
06ab8baccbe55e489444814a93ab92a5462bb664f8b571e0532b3433615a679c screenshots/raw/iphone-6.9/04-files.png
|
||||
5403182e93711055dd7144268cff0f961de29555c32f88d644027f2d9477e0b8 screenshots/raw/iphone-6.9/05-settings.png
|
||||
ac2a2568e6657e04b4e4a8f24f3eba223a9595fe8595bf94eeef195e471a992e screenshots/raw/iphone-6.9/06-add.png
|
||||
b2bc45c894c16c693f9f4b52b54d81df8d1eff804b189cb20a5db46699036198 screenshots/upload/ipad-13/01-home.png
|
||||
a51b20bba01b2965e131b74c874f8505aef9e40dfdfe322f6b0679bb70f3ae93 screenshots/upload/ipad-13/02-library.png
|
||||
3e9bd5c768daa4f2a10a350fa1d55e28774fd9f9b78611e14516b8ba54300113 screenshots/upload/ipad-13/03-details.png
|
||||
61c4782fb82161f050b6fa4d2171643d3dfb3be16248b0c36869a600fc1a89de screenshots/upload/ipad-13/04-files.png
|
||||
7de031bf40b4ac3d6243c8328b555c9c6dc44653410e9975b623d1586cd02a8d screenshots/upload/ipad-13/05-settings.png
|
||||
e0086af28c11c093e586203e5ba626feeee6435d16d9782777388b42d5041314 screenshots/upload/ipad-13/06-add.png
|
||||
ed387b7c406ab0b365c43a3d5784a3a52c3533673a283fe04ef22a7eebe44658 screenshots/upload/iphone-6.9/01-home.png
|
||||
00de403541a7b5412a5500703871253a94068c58a067c15e55871791757eb328 screenshots/upload/iphone-6.9/02-library.png
|
||||
304c9066091a7377616478f846c0f2e851e17669fd5975e15b42dab52c3a7c20 screenshots/upload/iphone-6.9/03-details.png
|
||||
48052e33ce3d520826c0266ec0264b5471d5b9294f56e98a7de0ce65a10909c3 screenshots/upload/iphone-6.9/04-files.png
|
||||
87f6036a9f87805c4ce13681d3d679e4769d0618d1ddbed544692d34cd9623ae screenshots/upload/iphone-6.9/05-settings.png
|
||||
ca06430586c526e8453835552d17c8a8ef17f9953c66ec122ca2da97156e4973 screenshots/upload/iphone-6.9/06-add.png
|
||||
9ed251947a2028763d621b0796537bf5011f7955546473318faa737adebfc17e tools/CaptureFixture.swift
|
||||
e86300304dc94bcee8076482fe603881057d128e8f73b3097477f0c67866911f tools/archive.sh
|
||||
970cc2141d288e56ae21bb912ad20f790978ef59a63edd9024d5117354dc6fca tools/build_website.py
|
||||
a879d89dbfedfc14cb4fa86234b0d7687326c26d80e37d1fed6756c8e5096bc7 tools/capture.sh
|
||||
abc9418074ad8374b0217c95028eb3711650efbf6e2e1b0c7ef86aa0b8226b63 tools/make_previews.py
|
||||
898a545d2ea544c59b039722358db146353820dec97017011ed1eeb5b8742da1 tools/prepare_capture.py
|
||||
c8a598609e773aaebe248a6c806ee9fbaf2eb02d350e7fac6cde7a84d6b73516 tools/render_assets.py
|
||||
d3d0e25991e5570c636f9fc33b511ad01f4a11496cf97cfaf0f0e1d7679d52a1 tools/validate.py
|
||||
ad7fef1fc3c6fd01cc605fb71df0e3def7a66bb1be010c6ed1e700d350224c86 validation-report.json
|
||||
51b1b1f9b03f020f9f9c18972e6340622a147e104cc1b2766516807d5243e604 validation-report.md
|
||||
8eccf035da8692920262e9f917b6f2971f9a9386a0125d773fb778a53367e0ed website/assets/apple-touch-icon.png
|
||||
283777a7ae895a7e6f0dc0b76c17597eec98d522ed8564eac48bc88aa466d1e3 website/assets/favicon.png
|
||||
0dd661c392e1704bdbf1b34db1a32ec5c1f063d5f8565f84d0df69b8383e0e19 website/assets/icon.png
|
||||
9880f405de5b4ca628c0042d62b18b7388bc136fbc5e4541ab94237965fa3a20 website/assets/social.png
|
||||
171ee36f6052e1651681bc383237959900c97250e3514f7ead2f16cb010ebe70 website/index.html
|
||||
41a9fb5fdc154cc5799b93bf5e65b2ef59e8ec2a0d4116b5cd9508a4fc8a41c5 website/privacy.html
|
||||
923d3cdc5124247f7d762f94b76264706555c2d37851b15440d1e91495ade839 website/style.css
|
||||
dc6cd7757303bc171cd38023c10a8e290817c12d4543ca994df818af38af9943 website/support.html
|
||||
e0e5f7b25d9e0239ac7d280f403b8a0ec2be9167edbe9e4280e1f7efd7dc0e34 website/terms.html
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>Tarnax release assets</title><style>body{margin:40px;background:#0b1020;color:#eef2ff;font:16px system-ui}a{color:#a5b4fc}main{max-width:1300px;margin:auto}.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:24px}figure{margin:0}img{width:100%;height:auto;border-radius:12px}nav{display:flex;gap:20px;flex-wrap:wrap;margin:30px 0}video{max-width:300px;max-height:600px}</style><main><h1>Tarnax</h1><p>App Store release assets · Version 1.0 (8)</p><p>Prepared locally. Website URLs, reviewer access and signing must be completed before submission.</p><nav><a href="README.md">Instructions</a><a href="validation-report.md">Validation</a><a href="website/index.html">Website</a><a href="review/release-checklist.md">Release checklist</a><a href="metadata/en-GB/description.txt">Store description</a></nav><h2>Screenshots</h2><div class="grid"><figure><a href="screenshots/upload/iphone-6.9/01-home.png"><img src="screenshots/upload/iphone-6.9/01-home.png" alt="01-home screenshot"></a><figcaption>iphone-6.9 · 01-home</figcaption></figure><figure><a href="screenshots/upload/iphone-6.9/02-library.png"><img src="screenshots/upload/iphone-6.9/02-library.png" alt="02-library screenshot"></a><figcaption>iphone-6.9 · 02-library</figcaption></figure><figure><a href="screenshots/upload/iphone-6.9/03-details.png"><img src="screenshots/upload/iphone-6.9/03-details.png" alt="03-details screenshot"></a><figcaption>iphone-6.9 · 03-details</figcaption></figure><figure><a href="screenshots/upload/iphone-6.9/04-files.png"><img src="screenshots/upload/iphone-6.9/04-files.png" alt="04-files screenshot"></a><figcaption>iphone-6.9 · 04-files</figcaption></figure><figure><a href="screenshots/upload/iphone-6.9/05-settings.png"><img src="screenshots/upload/iphone-6.9/05-settings.png" alt="05-settings screenshot"></a><figcaption>iphone-6.9 · 05-settings</figcaption></figure><figure><a href="screenshots/upload/iphone-6.9/06-add.png"><img src="screenshots/upload/iphone-6.9/06-add.png" alt="06-add screenshot"></a><figcaption>iphone-6.9 · 06-add</figcaption></figure><figure><a href="screenshots/upload/ipad-13/01-home.png"><img src="screenshots/upload/ipad-13/01-home.png" alt="01-home screenshot"></a><figcaption>ipad-13 · 01-home</figcaption></figure><figure><a href="screenshots/upload/ipad-13/02-library.png"><img src="screenshots/upload/ipad-13/02-library.png" alt="02-library screenshot"></a><figcaption>ipad-13 · 02-library</figcaption></figure><figure><a href="screenshots/upload/ipad-13/03-details.png"><img src="screenshots/upload/ipad-13/03-details.png" alt="03-details screenshot"></a><figcaption>ipad-13 · 03-details</figcaption></figure><figure><a href="screenshots/upload/ipad-13/04-files.png"><img src="screenshots/upload/ipad-13/04-files.png" alt="04-files screenshot"></a><figcaption>ipad-13 · 04-files</figcaption></figure><figure><a href="screenshots/upload/ipad-13/05-settings.png"><img src="screenshots/upload/ipad-13/05-settings.png" alt="05-settings screenshot"></a><figcaption>ipad-13 · 05-settings</figcaption></figure><figure><a href="screenshots/upload/ipad-13/06-add.png"><img src="screenshots/upload/ipad-13/06-add.png" alt="06-add screenshot"></a><figcaption>ipad-13 · 06-add</figcaption></figure></div><h2>Optional previews</h2><video controls preload="metadata" src="previews/Tarnax-iphone-6.9-preview.mp4"></video> <video controls preload="metadata" src="previews/Tarnax-ipad-13-preview.mp4"></video></main></html>
|
||||
|
Before Width: | Height: | Size: 146 KiB After Width: | Height: | Size: 159 KiB |
|
Before Width: | Height: | Size: 197 KiB After Width: | Height: | Size: 219 KiB |
|
Before Width: | Height: | Size: 221 KiB After Width: | Height: | Size: 370 KiB |
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 148 KiB |
|
After Width: | Height: | Size: 215 KiB |
|
After Width: | Height: | Size: 307 KiB |
@@ -0,0 +1,24 @@
|
||||
[
|
||||
{
|
||||
"file": "previews/Tarnax-iphone-6.9-preview.mp4",
|
||||
"width": 886,
|
||||
"height": 1920,
|
||||
"duration_seconds": 24,
|
||||
"fps": 30,
|
||||
"codec": "H.264 High Level 4.0",
|
||||
"audio": "AAC stereo 48kHz, silent",
|
||||
"poster_frame_seconds": 1,
|
||||
"footage": "Actual app UI captured in a simulator with fictitious sample data; no marketing artwork inserted."
|
||||
},
|
||||
{
|
||||
"file": "previews/Tarnax-ipad-13-preview.mp4",
|
||||
"width": 1200,
|
||||
"height": 1600,
|
||||
"duration_seconds": 24,
|
||||
"fps": 30,
|
||||
"codec": "H.264 High Level 4.0",
|
||||
"audio": "AAC stereo 48kHz, silent",
|
||||
"poster_frame_seconds": 1,
|
||||
"footage": "Actual app UI captured in a simulator with fictitious sample data; no marketing artwork inserted."
|
||||
}
|
||||
]
|
||||
|
Before Width: | Height: | Size: 145 KiB After Width: | Height: | Size: 481 KiB |
|
Before Width: | Height: | Size: 330 KiB After Width: | Height: | Size: 370 KiB |
|
Before Width: | Height: | Size: 357 KiB After Width: | Height: | Size: 357 KiB |
|
Before Width: | Height: | Size: 380 KiB After Width: | Height: | Size: 380 KiB |
|
Before Width: | Height: | Size: 430 KiB After Width: | Height: | Size: 449 KiB |
|
Before Width: | Height: | Size: 567 KiB After Width: | Height: | Size: 457 KiB |
|
Before Width: | Height: | Size: 102 KiB After Width: | Height: | Size: 509 KiB |
|
Before Width: | Height: | Size: 384 KiB After Width: | Height: | Size: 382 KiB |
|
Before Width: | Height: | Size: 327 KiB After Width: | Height: | Size: 325 KiB |
|
Before Width: | Height: | Size: 412 KiB After Width: | Height: | Size: 410 KiB |
|
Before Width: | Height: | Size: 428 KiB After Width: | Height: | Size: 421 KiB |
|
Before Width: | Height: | Size: 243 KiB After Width: | Height: | Size: 242 KiB |
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
set -euo pipefail
|
||||
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
||||
source "$ROOT/scripts/common.sh"
|
||||
PROVISIONING=()
|
||||
case "${1:-}" in
|
||||
--allow-provisioning-updates) PROVISIONING=(-allowProvisioningUpdates) ;;
|
||||
'') ;;
|
||||
-h|--help) echo 'Usage: appstore/tools/archive.sh [--allow-provisioning-updates]'; echo 'Creates an App Store archive and locally exports an IPA. Never uploads.'; exit 0 ;;
|
||||
*) echo "Unknown option: $1" >&2; exit 2 ;;
|
||||
esac
|
||||
[[ $# -le 1 ]] || { echo 'Too many arguments' >&2; exit 2; }
|
||||
OUTPUT="$(mktemp -d "$ROOT/appstore/build/$(date +%Y%m%d-%H%M%S).XXXXXX")"
|
||||
DERIVED="$(mktemp -d "$TARNAX_SCRATCH_ROOT/appstore-derived.XXXXXX")"
|
||||
echo "Output: $OUTPUT"
|
||||
xcodebuild -project "$ROOT/Tarnax.xcodeproj" -scheme Tarnax -configuration Release \
|
||||
-destination 'generic/platform=iOS' -derivedDataPath "$DERIVED" \
|
||||
-archivePath "$OUTPUT/Tarnax.xcarchive" \
|
||||
${PROVISIONING[@]+"${PROVISIONING[@]}"} archive 2>&1 | tee "$OUTPUT/archive.log"
|
||||
APP="$OUTPUT/Tarnax.xcarchive/Products/Applications/Tarnax.app"
|
||||
[[ -f "$APP/PrivacyInfo.xcprivacy" ]] || { echo 'Privacy manifest missing from archive' >&2; exit 1; }
|
||||
plutil -lint "$APP/PrivacyInfo.xcprivacy"
|
||||
xcrun nm -m "$APP/Tarnax" > "$DERIVED/symbols.txt"
|
||||
if grep -E 'weak external.*Foundation4DateV2(ge|le)oiy' "$DERIVED/symbols.txt"; then
|
||||
echo 'Incompatible Foundation Date comparison entry point detected' >&2; exit 1
|
||||
fi
|
||||
if grep -E 'StoreCapture|CaptureFixture' "$DERIVED/symbols.txt"; then
|
||||
echo 'Screenshot fixture leaked into production archive' >&2; exit 1
|
||||
fi
|
||||
xcodebuild -exportArchive -archivePath "$OUTPUT/Tarnax.xcarchive" \
|
||||
-exportPath "$OUTPUT/export" -exportOptionsPlist "$ROOT/appstore/build/ExportOptions-AppStore.plist" \
|
||||
${PROVISIONING[@]+"${PROVISIONING[@]}"} 2>&1 | tee "$OUTPUT/export.log"
|
||||
[[ -f "$OUTPUT/export/Tarnax.ipa" ]] || { echo 'IPA export missing' >&2; exit 1; }
|
||||
VERIFY="$(mktemp -d "$TARNAX_SCRATCH_ROOT/appstore-verify.XXXXXX")"
|
||||
trap 'rm -rf "$VERIFY"' EXIT
|
||||
unzip -q "$OUTPUT/export/Tarnax.ipa" -d "$VERIFY"
|
||||
codesign --verify --deep --strict "$VERIFY/Payload/Tarnax.app"
|
||||
security cms -D -i "$VERIFY/Payload/Tarnax.app/embedded.mobileprovision" > "$VERIFY/profile.plist"
|
||||
python3 - "$VERIFY" "$ROOT/appstore/build/latest.json" "$OUTPUT" <<'PY'
|
||||
from pathlib import Path
|
||||
import json,plistlib,sys,hashlib,datetime
|
||||
root=Path(sys.argv[1]);app=root/'Payload/Tarnax.app'
|
||||
with (app/'Info.plist').open('rb') as f:info=plistlib.load(f)
|
||||
with (root/'profile.plist').open('rb') as f:profile=plistlib.load(f)
|
||||
assert info['CFBundleIdentifier']=='net.absdev.Tarnax'
|
||||
assert not profile.get('ProvisionedDevices'), 'Device-limited profile is not App Store distribution'
|
||||
assert not profile.get('ProvisionsAllDevices'), 'Enterprise profile is not App Store distribution'
|
||||
assert not profile['Entitlements'].get('get-task-allow',False), 'Debugging enabled'
|
||||
assert profile['ExpirationDate']>datetime.datetime.now(datetime.timezone.utc).replace(tzinfo=None)
|
||||
output=Path(sys.argv[3]);ipa=output/'export/Tarnax.ipa'
|
||||
checksum=hashlib.sha256(ipa.read_bytes()).hexdigest()
|
||||
(output/'export/Tarnax.ipa.sha256').write_text(checksum+' Tarnax.ipa\n')
|
||||
Path(sys.argv[2]).write_text(json.dumps({'version':info['CFBundleShortVersionString'],'build':info['CFBundleVersion'],'archive':str(output/'Tarnax.xcarchive'),'ipa':str(ipa),'sha256':checksum,'distribution':'app-store-connect','uploaded':False},indent=2)+'\n')
|
||||
print('Verified App Store IPA:',ipa)
|
||||
PY
|
||||
@@ -0,0 +1,38 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Build static, tracker-free support and policy pages ready for HTTPS hosting."""
|
||||
from pathlib import Path
|
||||
import html,re
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
SITE=ROOT/'website'
|
||||
def markdown(text):
|
||||
blocks=[];inlist=False
|
||||
for line in text.splitlines():
|
||||
if not line.strip():
|
||||
if inlist:blocks.append('</ul>');inlist=False
|
||||
continue
|
||||
line=html.escape(line)
|
||||
line=re.sub(r'(https://[^\s<]+)',r'<a href="\1">\1</a>',line)
|
||||
if line.startswith('# '):blocks.append('<h1>'+line[2:]+'</h1>')
|
||||
elif line.startswith('## '):blocks.append('<h2>'+line[3:]+'</h2>')
|
||||
elif line.startswith('- '):
|
||||
if not inlist:blocks.append('<ul>');inlist=True
|
||||
blocks.append('<li>'+line[2:]+'</li>')
|
||||
else:blocks.append('<p>'+line+'</p>')
|
||||
if inlist:blocks.append('</ul>')
|
||||
return '\n'.join(blocks)
|
||||
|
||||
def page(title,content):
|
||||
return '''<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Tarnax — native remote control for your qBittorrent server. Support and privacy information."><title>'''+html.escape(title)+''' · Tarnax</title><link rel="icon" href="assets/favicon.png"><link rel="apple-touch-icon" href="assets/apple-touch-icon.png"><link rel="stylesheet" href="style.css"></head><body><header><a class="brand" href="index.html"><img src="assets/icon.png" alt="" width="44" height="44">Tarnax</a><nav aria-label="Main navigation"><a href="support.html">Support</a><a href="privacy.html">Privacy</a><a href="terms.html">Usage</a></nav></header><main>'''+content+'''</main><footer>© 2026 Mark Gregory · <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a><p>Independent software. Not affiliated with or endorsed by the qBittorrent project.</p></footer></body></html>'''
|
||||
|
||||
SITE.mkdir(exist_ok=True)
|
||||
SITE.joinpath('style.css').write_text('''*{box-sizing:border-box}html{color-scheme:dark}body{margin:0;background:#070b1b;color:#edf1fc;font:18px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}header,main,footer{max-width:1060px;margin:auto;padding:30px clamp(20px,5vw,64px)}header{display:flex;justify-content:space-between;align-items:center;gap:20px;border-bottom:1px solid #242e4a}.brand{display:flex;align-items:center;gap:14px;color:white;font-size:25px;font-weight:700;text-decoration:none}.brand img{border-radius:10px}nav{display:flex;gap:24px}a{color:#a9bdff;text-underline-offset:4px}a:hover{color:#fff}a:focus-visible{outline:3px solid #25c7ce;outline-offset:6px}h1{font-size:clamp(36px,6vw,64px);line-height:1.12;letter-spacing:-1.8px;margin:30px 0}h2{font-size:26px;line-height:1.3;margin-top:45px}p,li{max-width:76ch;color:#c8d2e8}.eyebrow{color:#67e3dd;font-size:14px;font-weight:700;letter-spacing:2px;text-transform:uppercase}.hero{padding:30px 0 50px}.hero img{width:140px;border-radius:32px}.hero strong{color:#c0c9ff}.button{display:inline-block;background:#7763ff;color:white;text-decoration:none;padding:12px 23px;border-radius:12px;font-weight:650}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px}.card{background:#111a31;border:1px solid #253253;border-radius:20px;padding:25px}.card h2{margin-top:0}.note{padding:20px 25px;border-left:3px solid #20bdc4;background:#101b2d}footer{font-size:14px;border-top:1px solid #242e4a;margin-top:40px}footer p{font-size:13px}details{border-bottom:1px solid #253253;padding:20px 0}summary{cursor:pointer;font-weight:650;color:white}@media(max-width:600px){header{align-items:flex-start;flex-direction:column}nav{font-size:16px}body{font-size:17px}}''')
|
||||
home='''<section class="hero"><img src="assets/icon.png" alt="Tarnax app icon"><p class="eyebrow">Remote for qBittorrent</p><h1>Your server.<br><strong>Your control.</strong></h1><p>A native iPhone and iPad remote for your own qBittorrent server. Follow live transfers, organise your library and manage the details from wherever you are.</p><a class="button" href="support.html">Get support</a></section><section class="cards"><article class="card"><h2>See the flow</h2><p>Colourful upload and download graphs, live speeds and the server space you need to know about.</p></article><article class="card"><h2>Manage the details</h2><p>Search and filter your transfers, control file priorities and edit your server’s preferences.</p></article><article class="card"><h2>Your connection</h2><p>Trusted HTTPS, device Keychain credentials and optional Face ID or device authentication.</p></article></section><p class="note">Requires your own qBittorrent server with its Web UI API enabled and a trusted HTTPS connection. Torrent contents stay on your server. Use only content you are authorised to access and share.</p>'''
|
||||
SITE.joinpath('index.html').write_text(page('Your server. Your control.',home))
|
||||
support='''<h1>How can we help?</h1><p>For Tarnax support, email <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a>. Please include the Tarnax version/build, iPhone or iPad model, iOS version, qBittorrent version, and what happened.</p><p class="note">Never send passwords, private magnet links or sensitive server contents. Redact identifying information from screenshots.</p><h2>Quick answers</h2>'''
|
||||
faqs=[('What do I need?','An existing qBittorrent server, Web UI API access, valid credentials and a trusted HTTPS endpoint. Tarnax does not provide the server, content catalogue or a VPN.'),('Why does my connection fail?','Check the HTTPS hostname, certificate chain and reverse-proxy subpath. HTTP 401 usually means proxy authentication; HTTP 403 may indicate session expiry, access rules or server protection. Use Disconnect/change server to reconnect after correcting the configuration.'),('Does Tarnax download to my phone?','No. It sends commands and selected .torrent files to your server. Torrent contents remain on that server.'),('Why does the graph start empty?','History records transfer samples while Tarnax is active and unlocked. It is session history, not a download-history database. Wait for a few updates; background pauses appear as gaps.'),('How do I retry Face ID?','Normal unlocking happens automatically. If authentication is cancelled or interrupted, tap Unlock to retry using Face ID or the device passcode fallback. Check that the app is allowed to use Face ID in iOS Settings.'),('How do I remove saved credentials?','Open Tarnax Settings and choose Forget saved credentials. iOS may retain Keychain data after deleting an app, so use this action before uninstalling if you want to remove the saved connection.'),('Can I edit every server option?','Tarnax exposes preferences returned by your server. Available settings and commands depend on qBittorrent’s version and configuration. Network, authentication and storage changes may interrupt access or move data.'),('Why don’t transfers update in the background?','This version refreshes while the app is active and unlocked. iOS background execution is not requested.'),('Where is the privacy policy?','Open Privacy in the navigation above, or Settings → Privacy policy inside Tarnax.')]
|
||||
for q,a in faqs:support+='<details><summary>'+html.escape(q)+'</summary><p>'+html.escape(a)+'</p></details>'
|
||||
SITE.joinpath('support.html').write_text(page('Support',support))
|
||||
privacy=markdown((ROOT/'legal/privacy-policy.md').read_text())+'<h2>This website</h2><p>These supplied pages contain no analytics scripts, advertising or cookies. The hosting provider you use may process technical request logs for operating and securing the site. Confirm the final hosting arrangement before publishing this policy.</p>'
|
||||
SITE.joinpath('privacy.html').write_text(page('Privacy',privacy))
|
||||
SITE.joinpath('terms.html').write_text(page('Usage',markdown((ROOT/'legal/terms-of-use.md').read_text())))
|
||||
print('Built four static support/marketing/policy pages; no publication performed.')
|
||||
@@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Create 24-second previews solely from actual simulator screen-recording footage."""
|
||||
from pathlib import Path
|
||||
import json,subprocess,os
|
||||
ROOT=Path(__file__).resolve().parents[1]
|
||||
SCRATCH=Path(os.environ.get('TARNAX_SCRATCH_ROOT',str(Path.home()/'Developer/Scratch/Tarnax')))
|
||||
SCENES=['01-home','02-library','03-details','04-files','05-settings','06-add']
|
||||
metadata=[]
|
||||
for device,size in [('iphone-6.9',(886,1920)),('ipad-13',(1200,1600))]:
|
||||
w,h=size
|
||||
work=SCRATCH/'appstore-video'/device
|
||||
encoded=[]
|
||||
for scene in SCENES:
|
||||
src=work/(scene+'.mov');out=work/(scene+'-encoded.mp4')
|
||||
vf=f'tpad=stop_mode=clone:stop_duration=4,scale={w}:{h}:force_original_aspect_ratio=decrease:force_divisible_by=2,pad={w}:{h}:(ow-iw)/2:(oh-ih)/2:color=black,fps=30,setsar=1,format=yuv420p'
|
||||
cmd=['ffmpeg','-y','-v','error','-ss','0','-i',str(src),'-f','lavfi','-i','anullsrc=r=48000:cl=stereo','-t','4','-vf',vf,'-c:v','libx264','-preset','fast','-profile:v','high','-level:v','4.0','-b:v','10M','-maxrate','12M','-bufsize','20M','-pix_fmt','yuv420p','-color_primaries','bt709','-color_trc','bt709','-colorspace','bt709','-c:a','aac','-b:a','256k','-ar','48000','-ac','2','-movflags','+faststart',str(out)]
|
||||
subprocess.run(cmd,check=True);encoded.append(out)
|
||||
playlist=work/'concat.txt';playlist.write_text(''.join("file '"+str(p).replace("'","'\\''")+"'\n" for p in encoded))
|
||||
dst=ROOT/f'previews/Tarnax-{device}-preview.mp4'
|
||||
subprocess.run(['ffmpeg','-y','-v','error','-f','concat','-safe','0','-i',str(playlist),'-c','copy','-movflags','+faststart',str(dst)],check=True)
|
||||
poster=ROOT/f'previews/Tarnax-{device}-poster.png'
|
||||
subprocess.run(['ffmpeg','-y','-v','error','-ss','1','-i',str(dst),'-frames:v','1',str(poster)],check=True)
|
||||
metadata.append({'file':str(dst.relative_to(ROOT)),'width':w,'height':h,'duration_seconds':24,'fps':30,'codec':'H.264 High Level 4.0','audio':'AAC stereo 48kHz, silent','poster_frame_seconds':1,'footage':'Actual app UI captured in a simulator with fictitious sample data; no marketing artwork inserted.'})
|
||||
(ROOT/'previews/preview-info.json').write_text(json.dumps(metadata,indent=2)+'\n')
|
||||
print('Created iPhone and iPad 24-second App Preview files.')
|
||||
@@ -0,0 +1,48 @@
|
||||
#!/usr/bin/env python3
|
||||
"""Validate local release assets; use --submission-ready to require owner setup too."""
|
||||
from pathlib import Path
|
||||
from PIL import Image,ImageStat
|
||||
import json,subprocess,plistlib,hashlib,sys
|
||||
R=Path(__file__).resolve().parents[1]
|
||||
errors=[];checks=[]
|
||||
def check(ok,label):
|
||||
(checks if ok else errors).append(label)
|
||||
for locale in ['en-GB','en-US']:
|
||||
for name,limit in [('name',30),('subtitle',30),('promotional_text',170),('description',4000),('keywords',100)]:
|
||||
value=(R/f'metadata/{locale}/{name}.txt').read_text().strip()
|
||||
check(bool(value) and (len(value.encode()) if name=='keywords' else len(value))<=limit,f'{locale}/{name}: length within {limit}')
|
||||
manifest=json.loads((R/'asset-manifest.json').read_text())
|
||||
check(len(manifest['screenshots'])==12,'12 upload screenshots')
|
||||
for item in manifest['screenshots']:
|
||||
for name in [item['file'],item['source']]:
|
||||
im=Image.open(R/name)
|
||||
check(im.size==(item['width'],item['height']) and (im.mode=='RGB' or ('A' in im.getbands() and im.getchannel('A').getextrema()==(255,255))),f'{name}: dimensions and opacity')
|
||||
check(max(ImageStat.Stat(im.resize((100,100))).stddev)>15,f'{name}: nonblank image')
|
||||
im=Image.open(R/'icons/Tarnax-AppStore-1024.png')
|
||||
check(im.size==(1024,1024) and im.mode=='RGB','App Store icon: opaque 1024 square')
|
||||
for device,size in [('iphone-6.9',(886,1920)),('ipad-13',(1200,1600))]:
|
||||
file=R/f'previews/Tarnax-{device}-preview.mp4'
|
||||
if not file.exists(): check(False,f'{device}: preview exists');continue
|
||||
data=json.loads(subprocess.check_output(['ffprobe','-v','error','-show_streams','-show_format','-of','json',str(file)]))
|
||||
video=next((s for s in data['streams'] if s['codec_type']=='video'),{})
|
||||
audio=next((s for s in data['streams'] if s['codec_type']=='audio'),{})
|
||||
check((video.get('width'),video.get('height'))==size and video.get('codec_name')=='h264' and video.get('level',999)<=40,f'{device}: video format')
|
||||
check(15<=float(data['format']['duration'])<=30 and file.stat().st_size<500_000_000,f'{device}: duration and size')
|
||||
check(audio.get('codec_name')=='aac' and audio.get('channels')==2 and audio.get('sample_rate')=='48000',f'{device}: audio format')
|
||||
a=plistlib.loads((R/'legal/PrivacyInfo.xcprivacy').read_bytes())
|
||||
check(a==plistlib.loads((R.parent/'Tarnax/PrivacyInfo.xcprivacy').read_bytes()),'Privacy manifest matches shipping source')
|
||||
for name in ['index.html','support.html','privacy.html','terms.html','style.css']:
|
||||
check((R/'website'/name).exists(),f'Website {name}')
|
||||
config=json.loads((R/'release-config.json').read_text())
|
||||
owner=[key for key in ['support_url','privacy_policy_url','price','territories'] if config[key] is None]
|
||||
if not config['review_contact']['phone']:owner.append('review contact phone')
|
||||
if not config['review_server']['https_url']:owner.append('dedicated reviewer server and credentials')
|
||||
if not (R/'build/latest.json').exists():owner.append('App Store signed IPA export')
|
||||
owner+=['Confirm naming rights, privacy answers, age rating, agreements and final physical-device QA']
|
||||
report={'asset_checks_passed':len(checks),'asset_errors':errors,'submission_ready':not(errors or owner),'owner_actions':owner}
|
||||
(R/'validation-report.json').write_text(json.dumps(report,indent=2)+'\n')
|
||||
(R/'validation-report.md').write_text('# Release asset validation\n\n'+f'{len(checks)} checks passed. {len(errors)} asset errors.\n\n'+ '\n'.join('- '+v for v in errors)+'\n\n## Owner actions before submission\n\n'+'\n'.join('- '+v for v in owner)+'\n')
|
||||
files=sorted(p for p in R.rglob('*') if p.is_file() and 'build' not in p.relative_to(R).parts and p.name not in ['SHA256SUMS'] and '__pycache__' not in p.parts)
|
||||
(R/'SHA256SUMS').write_text(''.join(hashlib.sha256(p.read_bytes()).hexdigest()+' '+str(p.relative_to(R))+'\n' for p in files))
|
||||
print(json.dumps(report,indent=2))
|
||||
sys.exit(1 if errors else 2 if '--submission-ready' in sys.argv and owner else 0)
|
||||
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"asset_checks_passed": 72,
|
||||
"asset_errors": [],
|
||||
"submission_ready": false,
|
||||
"owner_actions": [
|
||||
"support_url",
|
||||
"privacy_policy_url",
|
||||
"price",
|
||||
"territories",
|
||||
"review contact phone",
|
||||
"dedicated reviewer server and credentials",
|
||||
"App Store signed IPA export",
|
||||
"Confirm naming rights, privacy answers, age rating, agreements and final physical-device QA"
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
# Release asset validation
|
||||
|
||||
72 checks passed. 0 asset errors.
|
||||
|
||||
|
||||
|
||||
## Owner actions before submission
|
||||
|
||||
- support_url
|
||||
- privacy_policy_url
|
||||
- price
|
||||
- territories
|
||||
- review contact phone
|
||||
- dedicated reviewer server and credentials
|
||||
- App Store signed IPA export
|
||||
- Confirm naming rights, privacy answers, age rating, agreements and final physical-device QA
|
||||
|
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 148 KiB |
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Tarnax — native remote control for your qBittorrent server. Support and privacy information."><title>Your server. Your control. · Tarnax</title><link rel="icon" href="assets/favicon.png"><link rel="apple-touch-icon" href="assets/apple-touch-icon.png"><link rel="stylesheet" href="style.css"></head><body><header><a class="brand" href="index.html"><img src="assets/icon.png" alt="" width="44" height="44">Tarnax</a><nav aria-label="Main navigation"><a href="support.html">Support</a><a href="privacy.html">Privacy</a><a href="terms.html">Usage</a></nav></header><main><section class="hero"><img src="assets/icon.png" alt="Tarnax app icon"><p class="eyebrow">Remote for qBittorrent</p><h1>Your server.<br><strong>Your control.</strong></h1><p>A native iPhone and iPad remote for your own qBittorrent server. Follow live transfers, organise your library and manage the details from wherever you are.</p><a class="button" href="support.html">Get support</a></section><section class="cards"><article class="card"><h2>See the flow</h2><p>Colourful upload and download graphs, live speeds and the server space you need to know about.</p></article><article class="card"><h2>Manage the details</h2><p>Search and filter your transfers, control file priorities and edit your server’s preferences.</p></article><article class="card"><h2>Your connection</h2><p>Trusted HTTPS, device Keychain credentials and optional Face ID or device authentication.</p></article></section><p class="note">Requires your own qBittorrent server with its Web UI API enabled and a trusted HTTPS connection. Torrent contents stay on your server. Use only content you are authorised to access and share.</p></main><footer>© 2026 Mark Gregory · <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a><p>Independent software. Not affiliated with or endorsed by the qBittorrent project.</p></footer></body></html>
|
||||
@@ -0,0 +1,21 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Tarnax — native remote control for your qBittorrent server. Support and privacy information."><title>Privacy · Tarnax</title><link rel="icon" href="assets/favicon.png"><link rel="apple-touch-icon" href="assets/apple-touch-icon.png"><link rel="stylesheet" href="style.css"></head><body><header><a class="brand" href="index.html"><img src="assets/icon.png" alt="" width="44" height="44">Tarnax</a><nav aria-label="Main navigation"><a href="support.html">Support</a><a href="privacy.html">Privacy</a><a href="terms.html">Usage</a></nav></header><main><h1>Tarnax privacy policy</h1>
|
||||
<p>Effective date: 4 November 2026</p>
|
||||
<p>Tarnax is developed by Mark Gregory. Contact: mark.gregory@abbeysoftware.com.</p>
|
||||
<h2>Your connection</h2>
|
||||
<p>Tarnax is a remote control for a qBittorrent server that you configure. It sends your server address, authentication information, API requests, torrent links or files that you choose to add, and management commands directly to that server over HTTPS. Reverse-proxy credentials, if configured, are sent to the proxy serving that connection. The server and proxy operators may retain access logs, IP addresses, account information or transfer data under their own policies. You are responsible for choosing a server you trust and having permission to use it.</p>
|
||||
<p>Tarnax does not provide a hosted torrent service. It does not send your library or credentials to a developer-operated service unless you explicitly choose a server operated by the developer. The released app has no preset production server.</p>
|
||||
<h2>Information on your device</h2>
|
||||
<p>Saved connection credentials are kept in the device Keychain with device-only, when-unlocked protection. The app-lock preference and navigation state are stored locally. Session cookies use a private temporary network session and are discarded when the connection closes. Transfer-history samples are held in memory for the current session and are cleared when the server connection is replaced or disconnected.</p>
|
||||
<p>When you select a .torrent file, Tarnax reads it to upload it to your chosen server. Torrent contents remain on the server; Tarnax does not download those contents to your iPhone or iPad.</p>
|
||||
<h2>Authentication</h2>
|
||||
<p>Face ID, Touch ID where supported, and device passcode authentication are handled by Apple's LocalAuthentication services. Tarnax receives an authentication result. It does not receive or store biometric templates, facial images or your device passcode.</p>
|
||||
<h2>Tracking and analytics</h2>
|
||||
<p>Tarnax includes no advertising, tracking SDKs or third-party analytics services. It does not request advertising identifiers, contacts, photos, microphone, camera or location access. Apple may process App Store, payment or diagnostic information according to your Apple settings and Apple's policies. Information collected independently by your selected server is governed by that server operator.</p>
|
||||
<h2>Support correspondence</h2>
|
||||
<p>If you email support, we receive the information you choose to send and use it to respond, investigate the issue and maintain the support correspondence. Email providers process those messages as part of delivering the service. Do not send passwords, private torrent links or sensitive server data. Ask us to delete support correspondence by emailing the address above; we will consider the request subject to applicable retention obligations and legitimate record-keeping needs.</p>
|
||||
<h2>Your choices</h2>
|
||||
<p>Use Settings → Forget saved credentials to remove Tarnax's saved Keychain credentials and disconnect. Disconnecting also discards the session history. Deleting the app removes its local app data, but iOS may retain Keychain items; use the Forget action before deleting the app if you want to remove those credentials. Server-side accounts, files, logs and torrent data must be managed with your server operator.</p>
|
||||
<h2>Children and changes</h2>
|
||||
<p>Tarnax is a general-purpose server utility and is not designed specifically for children. We do not knowingly seek personal information from children. This policy may be updated if the app or its data practices change. The effective date above identifies the current version.</p>
|
||||
<h2>Contact</h2>
|
||||
<p>mark.gregory@abbeysoftware.com</p><h2>This website</h2><p>These supplied pages contain no analytics scripts, advertising or cookies. The hosting provider you use may process technical request logs for operating and securing the site. Confirm the final hosting arrangement before publishing this policy.</p></main><footer>© 2026 Mark Gregory · <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a><p>Independent software. Not affiliated with or endorsed by the qBittorrent project.</p></footer></body></html>
|
||||
@@ -0,0 +1 @@
|
||||
*{box-sizing:border-box}html{color-scheme:dark}body{margin:0;background:#070b1b;color:#edf1fc;font:18px/1.7 -apple-system,BlinkMacSystemFont,"Segoe UI",sans-serif}header,main,footer{max-width:1060px;margin:auto;padding:30px clamp(20px,5vw,64px)}header{display:flex;justify-content:space-between;align-items:center;gap:20px;border-bottom:1px solid #242e4a}.brand{display:flex;align-items:center;gap:14px;color:white;font-size:25px;font-weight:700;text-decoration:none}.brand img{border-radius:10px}nav{display:flex;gap:24px}a{color:#a9bdff;text-underline-offset:4px}a:hover{color:#fff}a:focus-visible{outline:3px solid #25c7ce;outline-offset:6px}h1{font-size:clamp(36px,6vw,64px);line-height:1.12;letter-spacing:-1.8px;margin:30px 0}h2{font-size:26px;line-height:1.3;margin-top:45px}p,li{max-width:76ch;color:#c8d2e8}.eyebrow{color:#67e3dd;font-size:14px;font-weight:700;letter-spacing:2px;text-transform:uppercase}.hero{padding:30px 0 50px}.hero img{width:140px;border-radius:32px}.hero strong{color:#c0c9ff}.button{display:inline-block;background:#7763ff;color:white;text-decoration:none;padding:12px 23px;border-radius:12px;font-weight:650}.cards{display:grid;grid-template-columns:repeat(auto-fit,minmax(240px,1fr));gap:20px}.card{background:#111a31;border:1px solid #253253;border-radius:20px;padding:25px}.card h2{margin-top:0}.note{padding:20px 25px;border-left:3px solid #20bdc4;background:#101b2d}footer{font-size:14px;border-top:1px solid #242e4a;margin-top:40px}footer p{font-size:13px}details{border-bottom:1px solid #253253;padding:20px 0}summary{cursor:pointer;font-weight:650;color:white}@media(max-width:600px){header{align-items:flex-start;flex-direction:column}nav{font-size:16px}body{font-size:17px}}
|
||||
@@ -0,0 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Tarnax — native remote control for your qBittorrent server. Support and privacy information."><title>Support · Tarnax</title><link rel="icon" href="assets/favicon.png"><link rel="apple-touch-icon" href="assets/apple-touch-icon.png"><link rel="stylesheet" href="style.css"></head><body><header><a class="brand" href="index.html"><img src="assets/icon.png" alt="" width="44" height="44">Tarnax</a><nav aria-label="Main navigation"><a href="support.html">Support</a><a href="privacy.html">Privacy</a><a href="terms.html">Usage</a></nav></header><main><h1>How can we help?</h1><p>For Tarnax support, email <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a>. Please include the Tarnax version/build, iPhone or iPad model, iOS version, qBittorrent version, and what happened.</p><p class="note">Never send passwords, private magnet links or sensitive server contents. Redact identifying information from screenshots.</p><h2>Quick answers</h2><details><summary>What do I need?</summary><p>An existing qBittorrent server, Web UI API access, valid credentials and a trusted HTTPS endpoint. Tarnax does not provide the server, content catalogue or a VPN.</p></details><details><summary>Why does my connection fail?</summary><p>Check the HTTPS hostname, certificate chain and reverse-proxy subpath. HTTP 401 usually means proxy authentication; HTTP 403 may indicate session expiry, access rules or server protection. Use Disconnect/change server to reconnect after correcting the configuration.</p></details><details><summary>Does Tarnax download to my phone?</summary><p>No. It sends commands and selected .torrent files to your server. Torrent contents remain on that server.</p></details><details><summary>Why does the graph start empty?</summary><p>History records transfer samples while Tarnax is active and unlocked. It is session history, not a download-history database. Wait for a few updates; background pauses appear as gaps.</p></details><details><summary>How do I retry Face ID?</summary><p>Normal unlocking happens automatically. If authentication is cancelled or interrupted, tap Unlock to retry using Face ID or the device passcode fallback. Check that the app is allowed to use Face ID in iOS Settings.</p></details><details><summary>How do I remove saved credentials?</summary><p>Open Tarnax Settings and choose Forget saved credentials. iOS may retain Keychain data after deleting an app, so use this action before uninstalling if you want to remove the saved connection.</p></details><details><summary>Can I edit every server option?</summary><p>Tarnax exposes preferences returned by your server. Available settings and commands depend on qBittorrent’s version and configuration. Network, authentication and storage changes may interrupt access or move data.</p></details><details><summary>Why don’t transfers update in the background?</summary><p>This version refreshes while the app is active and unlocked. iOS background execution is not requested.</p></details><details><summary>Where is the privacy policy?</summary><p>Open Privacy in the navigation above, or Settings → Privacy policy inside Tarnax.</p></details></main><footer>© 2026 Mark Gregory · <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a><p>Independent software. Not affiliated with or endorsed by the qBittorrent project.</p></footer></body></html>
|
||||
@@ -0,0 +1,7 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width, initial-scale=1"><meta name="description" content="Tarnax — native remote control for your qBittorrent server. Support and privacy information."><title>Usage · Tarnax</title><link rel="icon" href="assets/favicon.png"><link rel="apple-touch-icon" href="assets/apple-touch-icon.png"><link rel="stylesheet" href="style.css"></head><body><header><a class="brand" href="index.html"><img src="assets/icon.png" alt="" width="44" height="44">Tarnax</a><nav aria-label="Main navigation"><a href="support.html">Support</a><a href="privacy.html">Privacy</a><a href="terms.html">Usage</a></nav></header><main><h1>Tarnax usage information</h1>
|
||||
<p>Tarnax is an independent remote-control app for a user-configured qBittorrent server. It is not affiliated with or endorsed by the qBittorrent project, Marvel or any other software or entertainment brand.</p>
|
||||
<p>You need permission to access the server and to access, download or share any content you manage through it. Tarnax does not provide a content catalogue, search service, hosted download account, VPN or cloud storage. Do not use it to infringe intellectual-property rights or other applicable laws.</p>
|
||||
<p>Commands run on your server. Moving storage, changing server settings and deleting server files can have immediate effects. Keep backups and review destructive confirmations carefully. Feature availability depends on your server version and setup.</p>
|
||||
<p>If distributed through Apple's App Store without a custom licence, Apple's Standard Licensed Application End User License Agreement applies, together with any mandatory local consumer rights. This usage page does not replace that agreement or limit rights that cannot lawfully be excluded.</p>
|
||||
<p>Apple Standard EULA: <a href="https://www.apple.com/legal/internet-services/itunes/dev/stdeula/">https://www.apple.com/legal/internet-services/itunes/dev/stdeula/</a></p>
|
||||
<p>Support: mark.gregory@abbeysoftware.com</p></main><footer>© 2026 Mark Gregory · <a href="mailto:mark.gregory@abbeysoftware.com">mark.gregory@abbeysoftware.com</a><p>Independent software. Not affiliated with or endorsed by the qBittorrent project.</p></footer></body></html>
|
||||