From dc4c6731f622e2bb7e27024a7b6c40b41b11b31d Mon Sep 17 00:00:00 2001 From: Cloudburst <18114966+C10udburst@users.noreply.github.com> Date: Sun, 18 Sep 2022 12:07:07 +0200 Subject: [PATCH] add adb functionality --- package-lock.json | 160 ++++++++++++++++++++++++++++++++++ package.json | 3 + src/components/adbconnect.jsx | 83 ++++++++++++++++++ src/components/cards/repo.jsx | 16 ++-- src/components/compatbtn.jsx | 21 +++-- src/pages/repos.js | 2 + 6 files changed, 271 insertions(+), 14 deletions(-) create mode 100644 src/components/adbconnect.jsx diff --git a/package-lock.json b/package-lock.json index b2a6c10..793aae8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,6 +9,9 @@ "version": "1.0.0", "dependencies": { "@noriginmedia/norigin-spatial-navigation": "^1.0.5", + "@yume-chan/adb": "^0.0.16", + "@yume-chan/adb-backend-webusb": "^0.0.16", + "@yume-chan/adb-credential-web": "^0.0.16", "daisyui": "^2.24.0", "gatsby": "^4.21.1", "gatsby-plugin-canonical-urls": "^4.22.0", @@ -4173,6 +4176,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" }, + "node_modules/@types/w3c-web-usb": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", + "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==" + }, "node_modules/@types/websocket": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.2.tgz", @@ -4543,6 +4551,73 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, + "node_modules/@yume-chan/adb": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb/-/adb-0.0.16.tgz", + "integrity": "sha512-+5q4d3q+rP8rbtv8pqfMX0Ln749TjHmJ75a/yZiEdlNdYIV7Oi+ZeEs43hd70dJs3wHnlwM/uLUaz93wdz4eSA==", + "dependencies": { + "@yume-chan/async": "^2.1.4", + "@yume-chan/dataview-bigint-polyfill": "^0.0.16", + "@yume-chan/event": "^0.0.16", + "@yume-chan/struct": "^0.0.16", + "tslib": "^2.3.1", + "web-streams-polyfill": "^4.0.0-beta.3" + } + }, + "node_modules/@yume-chan/adb-backend-webusb": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-backend-webusb/-/adb-backend-webusb-0.0.16.tgz", + "integrity": "sha512-BJ9gUKXaYrXG9rxW3kbI8yBFVSnQuIkUgPUs4GDvXRxtiEn0Snidqw1HhJBF78LPvqZSAcxfiU8mfB61s2ERWw==", + "dependencies": { + "@types/w3c-web-usb": "^1.0.4", + "@yume-chan/adb": "^0.0.16", + "@yume-chan/struct": "^0.0.16", + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/adb-credential-web": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-credential-web/-/adb-credential-web-0.0.16.tgz", + "integrity": "sha512-W2Gfq/KoUhlHQc8joIWcEfGu/AGKTlZ+EW+AwVCB9tK7u3iMjJEwYsFdNwciAzwGpJAjUiiCSFs6H5+Sa/4ODQ==", + "dependencies": { + "@yume-chan/adb": "^0.0.16", + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/async": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz", + "integrity": "sha512-jatCtX1/3DsR9Vt3EB8CGFy0MNrXP5f+eNiRGHLH+LkYz7MPLzpqL/DnvXSip+Z0EKBCDnzuNuELjsKEEzcdQA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/dataview-bigint-polyfill": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/dataview-bigint-polyfill/-/dataview-bigint-polyfill-0.0.16.tgz", + "integrity": "sha512-fvo4fclUgoPwO8dkRCEjce6efV5mnyJBNjiq3VYCUkXcuzb2anvbedIihuFpajhlDQ31GAKTnkQYFHpSOhzHqA==", + "dependencies": { + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/event": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/event/-/event-0.0.16.tgz", + "integrity": "sha512-bZ8B1oM2s4nKRtG2O2rQIRbiLBSl6HMeJnFqKdZ1in6tDNq3t9NJopOwzR/DUUvadCaa8KjEHIcyC2E2XnEEpQ==", + "dependencies": { + "@yume-chan/async": "^2.1.4", + "tslib": "^2.3.1" + } + }, + "node_modules/@yume-chan/struct": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/struct/-/struct-0.0.16.tgz", + "integrity": "sha512-RNEn3KPk6i0NkkoQE1xAPUYDp6Afqes1VYkmJIW6fGCmZqWTHUy0tH8qa6qMmfYaTK5sdcH77M0EyvifDxmzUA==", + "dependencies": { + "@yume-chan/dataview-bigint-polyfill": "^0.0.16", + "tslib": "^2.3.1" + } + }, "node_modules/abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -21399,6 +21474,14 @@ "url": "https://github.com/sponsors/wooorm" } }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", @@ -24870,6 +24953,11 @@ "resolved": "https://registry.npmjs.org/@types/unist/-/unist-2.0.6.tgz", "integrity": "sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==" }, + "@types/w3c-web-usb": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/w3c-web-usb/-/w3c-web-usb-1.0.6.tgz", + "integrity": "sha512-cSjhgrr8g4KbPnnijAr/KJDNKa/bBa+ixYkywFRvrhvi9n1WEl7yYbtRyzE6jqNQiSxxJxoAW3STaOQwJHndaw==" + }, "@types/websocket": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.2.tgz", @@ -25148,6 +25236,73 @@ "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" }, + "@yume-chan/adb": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb/-/adb-0.0.16.tgz", + "integrity": "sha512-+5q4d3q+rP8rbtv8pqfMX0Ln749TjHmJ75a/yZiEdlNdYIV7Oi+ZeEs43hd70dJs3wHnlwM/uLUaz93wdz4eSA==", + "requires": { + "@yume-chan/async": "^2.1.4", + "@yume-chan/dataview-bigint-polyfill": "^0.0.16", + "@yume-chan/event": "^0.0.16", + "@yume-chan/struct": "^0.0.16", + "tslib": "^2.3.1", + "web-streams-polyfill": "^4.0.0-beta.3" + } + }, + "@yume-chan/adb-backend-webusb": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-backend-webusb/-/adb-backend-webusb-0.0.16.tgz", + "integrity": "sha512-BJ9gUKXaYrXG9rxW3kbI8yBFVSnQuIkUgPUs4GDvXRxtiEn0Snidqw1HhJBF78LPvqZSAcxfiU8mfB61s2ERWw==", + "requires": { + "@types/w3c-web-usb": "^1.0.4", + "@yume-chan/adb": "^0.0.16", + "@yume-chan/struct": "^0.0.16", + "tslib": "^2.3.1" + } + }, + "@yume-chan/adb-credential-web": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/adb-credential-web/-/adb-credential-web-0.0.16.tgz", + "integrity": "sha512-W2Gfq/KoUhlHQc8joIWcEfGu/AGKTlZ+EW+AwVCB9tK7u3iMjJEwYsFdNwciAzwGpJAjUiiCSFs6H5+Sa/4ODQ==", + "requires": { + "@yume-chan/adb": "^0.0.16", + "tslib": "^2.3.1" + } + }, + "@yume-chan/async": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@yume-chan/async/-/async-2.2.0.tgz", + "integrity": "sha512-jatCtX1/3DsR9Vt3EB8CGFy0MNrXP5f+eNiRGHLH+LkYz7MPLzpqL/DnvXSip+Z0EKBCDnzuNuELjsKEEzcdQA==", + "requires": { + "tslib": "^2.3.1" + } + }, + "@yume-chan/dataview-bigint-polyfill": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/dataview-bigint-polyfill/-/dataview-bigint-polyfill-0.0.16.tgz", + "integrity": "sha512-fvo4fclUgoPwO8dkRCEjce6efV5mnyJBNjiq3VYCUkXcuzb2anvbedIihuFpajhlDQ31GAKTnkQYFHpSOhzHqA==", + "requires": { + "tslib": "^2.3.1" + } + }, + "@yume-chan/event": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/event/-/event-0.0.16.tgz", + "integrity": "sha512-bZ8B1oM2s4nKRtG2O2rQIRbiLBSl6HMeJnFqKdZ1in6tDNq3t9NJopOwzR/DUUvadCaa8KjEHIcyC2E2XnEEpQ==", + "requires": { + "@yume-chan/async": "^2.1.4", + "tslib": "^2.3.1" + } + }, + "@yume-chan/struct": { + "version": "0.0.16", + "resolved": "https://registry.npmjs.org/@yume-chan/struct/-/struct-0.0.16.tgz", + "integrity": "sha512-RNEn3KPk6i0NkkoQE1xAPUYDp6Afqes1VYkmJIW6fGCmZqWTHUy0tH8qa6qMmfYaTK5sdcH77M0EyvifDxmzUA==", + "requires": { + "@yume-chan/dataview-bigint-polyfill": "^0.0.16", + "tslib": "^2.3.1" + } + }, "abort-controller": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", @@ -37249,6 +37404,11 @@ "resolved": "https://registry.npmjs.org/web-namespaces/-/web-namespaces-1.1.4.tgz", "integrity": "sha512-wYxSGajtmoP4WxfejAPIr4l0fVh+jeMXZb08wNc0tMg6xsfZXj3cECqIK0G7ZAqUq0PP8WlMDtaOGVBTAWztNw==" }, + "web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==" + }, "webidl-conversions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", diff --git a/package.json b/package.json index b12ae42..b5f967a 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,9 @@ }, "dependencies": { "@noriginmedia/norigin-spatial-navigation": "^1.0.5", + "@yume-chan/adb": "^0.0.16", + "@yume-chan/adb-backend-webusb": "^0.0.16", + "@yume-chan/adb-credential-web": "^0.0.16", "daisyui": "^2.24.0", "gatsby": "^4.21.1", "gatsby-plugin-canonical-urls": "^4.22.0", diff --git a/src/components/adbconnect.jsx b/src/components/adbconnect.jsx new file mode 100644 index 0000000..c41b489 --- /dev/null +++ b/src/components/adbconnect.jsx @@ -0,0 +1,83 @@ +import React, { useState, useEffect } from "react"; +import { Adb } from '@yume-chan/adb'; +import AdbWebCredentialStore from '@yume-chan/adb-credential-web'; +import AdbWebUsbBackend from '@yume-chan/adb-backend-webusb'; + +import CompatBtn from "./compatbtn"; + +import {MdAdb} from "react-icons/md" + +const isBrowser = typeof window !== "undefined" + +const CredentialStore = new AdbWebCredentialStore(); + +const AdbConnect = () => { + const [status, setStatus] = useState("disconnected") + const [supported, setSupported] = useState(true); + + useEffect(() => { + if (!isBrowser) return; + setSupported(AdbWebUsbBackend.isSupported()) + }, []) + + function connect() { + if (!isBrowser) return; + AdbWebUsbBackend.requestDevice() + .then(req => { + setStatus(`loading/Connecting to ${req.name}`) + req.connect() + .then(conn => { + setStatus(`loading/Authenticating ${req.serial}`) + Adb.authenticate(conn, CredentialStore, undefined) + .then(dev => { + setStatus(`connected/${dev.device}`) + window.AdbConnection = dev + }) + .catch(err => { + setStatus(`error/${err}`) + }) + }) + }) + } + + if (!supported) return <> + + let color + if (status.startsWith("connected")) { + color = "alert-success" + } else if (status.startsWith("error")) { + color = "alert-error" + } else if (status.startsWith("loading")) { + color = "alert-info" + } else { + color = "" + } + + return
+
+ +
+

Connect to the device via ADB (via USB)

+ {!status.startsWith("error") && +
Useful if you do not have a web browser on your device.
+ } + {status.startsWith("error") && +
Failed to connect. ${status.split("/").at(1)}
+ } +
+
+
+ {status === "disconnected" && + Connect + } + {status.startsWith("loading") && + + } + {status.startsWith("connected") && + + } +
+
+} + +export default AdbConnect \ No newline at end of file diff --git a/src/components/cards/repo.jsx b/src/components/cards/repo.jsx index 9bd0c4e..9714edb 100644 --- a/src/components/cards/repo.jsx +++ b/src/components/cards/repo.jsx @@ -3,6 +3,16 @@ import React, { useState, useEffect } from "react"; import CompatBtn from "../compatbtn"; import { GoVerified } from "react-icons/go"; +function installRepo(url) { + if (window.AdbConnection !== undefined) { + window.AdbConnection.subprocess.shell(`am start -a android.intent.action.VIEW -d "cloudstreamrepo://${url.replace(/^https?:\/\//, "")}"`) + } else if (window.RepoApi !== undefined) { + window.RepoApi.installRepo(url) + } else { + window.open(`cloudstreamrepo://${url.replace(/^https?:\/\//, "")}`) + } +} + const RepoCard = ({ repoData, isFirst }) => { const [data, setData] = useState(null) @@ -41,11 +51,7 @@ const RepoCard = ({ repoData, isFirst }) => { group={true} className="btn-primary" onClick={() => { - if (window.RepoApi !== undefined) { - window.RepoApi.installRepo(url) - } else { - window.open(`cloudstreamrepo://${url.replace(/^https?:\/\//, "")}`) - } + installRepo(url) }} >Install { - if (!focused) return; - if (document.activeElement !== ref.current) return; - if (ev.key === "Enter" || ev.key === " ") { - ref.current?.click() - } - }) - } + useEffect(() => { + if (isBrowser) { + window.addEventListener("keyup", (ev) => { + if (!focused) return; + if (document.activeElement !== ref.current) return; + if (ev.key === "Enter" || ev.key === " ") { + ref.current?.click() + } + }) + } + }, []) + if (target !== "_blank" && !group && !onClick) { return {children} diff --git a/src/pages/repos.js b/src/pages/repos.js index c28d92a..2611a79 100644 --- a/src/pages/repos.js +++ b/src/pages/repos.js @@ -2,6 +2,7 @@ import React, {useEffect, useState} from "react" import Layout from "../components/layout" import RepoCard from "../components/cards/repo" +import AdbConnect from "../components/adbconnect" import bgImage from "../media/phones.png" import { TiWarning } from "react-icons/ti"; @@ -28,6 +29,7 @@ const IndexPage = () => { + {repos && repos.map((it, index) => ) }