diff --git a/.gitignore b/.gitignore
index 20fb3088b..15fda4fd7 100644
--- a/.gitignore
+++ b/.gitignore
@@ -9,3 +9,4 @@ bin
!.yarn/sdks
!.yarn/versions
.build
+.wrangler
diff --git a/hack/latest-worker.js b/hack/latest-worker.js
new file mode 100644
index 000000000..dd52ee5cd
--- /dev/null
+++ b/hack/latest-worker.js
@@ -0,0 +1,83 @@
+/**aquareum
+ * Welcome to Cloudflare Workers! This is your first worker.
+ *
+ * - Run `npm run dev` in your terminal to start a development server
+ * - Open a browser tab at http://localhost:8787/ to see your worker in action
+ * - Run `npm run deploy` to publish your worker
+ *
+ * Learn more at https://developers.cloudflare.com/workers/
+ */
+
+const re = new RegExp(
+ `^aquareum-(v[0-9]\.[0-9]\.[0-9])-([0-9a-f]+)-([0-9a-z]+)-([0-9a-z]+)\.(.+)$`,
+);
+const inputRe = new RegExp(`^aquareum-([0-9a-z]+)-([0-9a-z]+)\.(.+)$`);
+
+const CI_API_V4_URL = "https://git.aquareum.tv/api/v4";
+const DOWNLOAD_BASE_URL =
+ "https://git.aquareum.tv/aquareum-tv/aquareum/-/package_files";
+const PROJECT_ID = "1";
+
+// Export a default object containing event handlers
+export default {
+ // The fetch handler is invoked when this worker receives a HTTP(S) request
+ // and should return a Response (optionally wrapped in a Promise)
+ async fetch(req, env, ctx) {
+ const { pathname } = new URL(req.url);
+ const [_, dl, branch, file] = pathname.split("/");
+ if (!branch || !file) {
+ return new Response("usage: /dl/latest/aquareum-linux-arm64.tar.gz", {
+ status: 400,
+ });
+ }
+ const inputPieces = inputRe.exec(file);
+ {
+ if (!inputPieces) {
+ return new Response(`could not parse filename ${file}`);
+ }
+ }
+ const [full, inputPlatform, inputArch, inputExt] = inputPieces;
+ const packageUrl = `${CI_API_V4_URL}/projects/${PROJECT_ID}/packages?order_by=created_at&sort=desc&package_name=${branch}`;
+ const packageReq = await fetch(packageUrl, {
+ headers: {
+ "user-agent": "aquareum-dl",
+ },
+ });
+ const packages = await packageReq.json();
+ const pkg = packages[0];
+ if (!pkg) {
+ return new Response(`package for branch ${branch} not found`, {
+ status: 404,
+ });
+ }
+ const fileUrl = `${CI_API_V4_URL}/projects/${PROJECT_ID}/packages/${pkg.id}/package_files`;
+ console.log(fileUrl);
+ const fileReq = await fetch(fileUrl);
+ const files = await fileReq.json();
+ let foundFile;
+ for (const f of files) {
+ const pieces = re.exec(f.file_name);
+ if (!pieces) {
+ console.error(`could not parse filename ${f.file_name}`);
+ continue;
+ }
+ const [full, ver, hash, platform, arch, ext] = pieces;
+ console.log({ full, ver, hash, platform, arch, ext });
+ if (
+ platform === inputPlatform &&
+ arch === inputArch &&
+ ext === inputExt
+ ) {
+ foundFile = f;
+ break;
+ }
+ }
+ if (!foundFile) {
+ throw new Error(
+ `could not find a file for platform=${inputPlatform} arch=${inputArch} ext=${inputExt})`,
+ );
+ }
+ const outUrl = `${DOWNLOAD_BASE_URL}/${foundFile.id}/download`;
+ return Response.redirect(outUrl, 302);
+ },
+};
diff --git a/js/app/app/(tabs)/index.tsx b/js/app/app/(tabs)/index.tsx
index 81e7c330b..6a46bce7e 100644
--- a/js/app/app/(tabs)/index.tsx
+++ b/js/app/app/(tabs)/index.tsx
@@ -46,6 +46,7 @@ import { Countdown } from "components";
import { ImageBackground } from "react-native";
import * as env from "constants/env";
import { useState } from "react";
+import GetApps from "components/get-apps";
const WebviewIframe = ({ src }) => {
if (isWeb) {
@@ -111,6 +112,9 @@ export default function TabOneScreen() {
Aquareum: The Video Layer for Everything
+
+
+
diff --git a/js/app/assets/images/appstore.svg b/js/app/assets/images/appstore.svg
new file mode 100644
index 000000000..4c06b31a9
--- /dev/null
+++ b/js/app/assets/images/appstore.svg
@@ -0,0 +1,41 @@
+
+
+
diff --git a/js/app/assets/images/playstore.svg b/js/app/assets/images/playstore.svg
new file mode 100644
index 000000000..f4758a39d
--- /dev/null
+++ b/js/app/assets/images/playstore.svg
@@ -0,0 +1,91 @@
+
+
+
diff --git a/js/app/components/get-apps.native.tsx b/js/app/components/get-apps.native.tsx
new file mode 100644
index 000000000..8e9254cd9
--- /dev/null
+++ b/js/app/components/get-apps.native.tsx
@@ -0,0 +1,5 @@
+import { View } from "tamagui";
+
+export default function GetApps() {
+ return ;
+}
diff --git a/js/app/components/get-apps.tsx b/js/app/components/get-apps.tsx
new file mode 100644
index 000000000..c57885b77
--- /dev/null
+++ b/js/app/components/get-apps.tsx
@@ -0,0 +1,31 @@
+import { XStack, Image, Anchor } from "tamagui";
+
+const RATIO = 3.39741547176;
+const WIDTH = 200;
+const HEIGHT = 200 / RATIO;
+
+export default function GetApps() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}