From 48657c1c12df3dae7ee88d2d99ab25fe96ae9c40 Mon Sep 17 00:00:00 2001 From: Philipp Hutterer Date: Sat, 30 Dec 2023 04:15:44 +0100 Subject: [PATCH] feat: integrated Web Share Target API for PWA --- ui/angular.json | 12 ++++-- ui/ngsw-config.json | 30 ++++++++++++++ ui/package-lock.json | 19 +++++++++ ui/package.json | 1 + ui/src/app/app.module.ts | 11 ++++- ui/src/app/metube-socket.ts | 8 ++-- .../assets/icons/android-chrome-192x192.png | Bin 0 -> 3912 bytes .../assets/icons/android-chrome-384x384.png | Bin 0 -> 7967 bytes ui/src/custom-service-worker.js | 38 ++++++++++++++++++ ui/src/index.html | 5 ++- ui/src/manifest.webmanifest | 28 +++++++++++++ 11 files changed, 142 insertions(+), 10 deletions(-) create mode 100644 ui/ngsw-config.json create mode 100644 ui/src/assets/icons/android-chrome-192x192.png create mode 100644 ui/src/assets/icons/android-chrome-384x384.png create mode 100644 ui/src/custom-service-worker.js create mode 100644 ui/src/manifest.webmanifest diff --git a/ui/angular.json b/ui/angular.json index 65b1d1e..801cf09 100644 --- a/ui/angular.json +++ b/ui/angular.json @@ -25,14 +25,18 @@ "aot": true, "assets": [ "src/favicon.ico", - "src/assets" + "src/assets", + "src/manifest.webmanifest", + "src/custom-service-worker.js" ], "styles": [ "src/styles.sass" ], "scripts": [ "node_modules/bootstrap/dist/js/bootstrap.bundle.min.js", - ] + ], + "serviceWorker": true, + "ngswConfigPath": "ngsw-config.json" }, "configurations": { "production": { @@ -90,7 +94,9 @@ "karmaConfig": "karma.conf.js", "assets": [ "src/favicon.ico", - "src/assets" + "src/assets", + "src/manifest.webmanifest", + "src/custom-service-worker.js" ], "styles": [ "src/styles.sass" diff --git a/ui/ngsw-config.json b/ui/ngsw-config.json new file mode 100644 index 0000000..f8bf210 --- /dev/null +++ b/ui/ngsw-config.json @@ -0,0 +1,30 @@ +{ + "$schema": "./node_modules/@angular/service-worker/config/schema.json", + "index": "/index.html", + "assetGroups": [ + { + "name": "app", + "installMode": "prefetch", + "resources": { + "files": [ + "/favicon.ico", + "/index.html", + "/manifest.webmanifest", + "/*.css", + "/*.js" + ] + } + }, + { + "name": "assets", + "installMode": "lazy", + "updateMode": "prefetch", + "resources": { + "files": [ + "/assets/**", + "/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)" + ] + } + } + ] +} diff --git a/ui/package-lock.json b/ui/package-lock.json index f0f62aa..16335a9 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -17,6 +17,7 @@ "@angular/platform-browser": "^15.0.0", "@angular/platform-browser-dynamic": "^15.0.0", "@angular/router": "^15.0.0", + "@angular/service-worker": "^15.0.0", "@fortawesome/angular-fontawesome": "~0.12.0", "@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0", @@ -642,6 +643,24 @@ "rxjs": "^6.5.3 || ^7.4.0" } }, + "node_modules/@angular/service-worker": { + "version": "15.2.10", + "resolved": "https://registry.npmjs.org/@angular/service-worker/-/service-worker-15.2.10.tgz", + "integrity": "sha512-dTLLt02OwYVZ7U2sat8v/1jxtBNYnps+AZyRVXxpTPvgkljLHphhWuSPv6V8IRxxKF0SU7e6RVrcAMLIPUSVeg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "bin": { + "ngsw-config": "ngsw-config.js" + }, + "engines": { + "node": "^14.20.0 || ^16.13.0 || >=18.10.0" + }, + "peerDependencies": { + "@angular/common": "15.2.10", + "@angular/core": "15.2.10" + } + }, "node_modules/@assemblyscript/loader": { "version": "0.10.1", "resolved": "https://registry.npmjs.org/@assemblyscript/loader/-/loader-0.10.1.tgz", diff --git a/ui/package.json b/ui/package.json index 76ea0f0..fffb2fd 100644 --- a/ui/package.json +++ b/ui/package.json @@ -20,6 +20,7 @@ "@angular/platform-browser": "^15.0.0", "@angular/platform-browser-dynamic": "^15.0.0", "@angular/router": "^15.0.0", + "@angular/service-worker": "^15.0.0", "@fortawesome/angular-fontawesome": "~0.12.0", "@fortawesome/fontawesome-svg-core": "^6.4.0", "@fortawesome/free-regular-svg-icons": "^6.4.0", diff --git a/ui/src/app/app.module.ts b/ui/src/app/app.module.ts index 8eddbca..35e0621 100644 --- a/ui/src/app/app.module.ts +++ b/ui/src/app/app.module.ts @@ -1,5 +1,5 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; +import { NgModule, isDevMode } from '@angular/core'; import { FormsModule } from '@angular/forms'; import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { HttpClientModule } from '@angular/common/http'; @@ -11,6 +11,7 @@ import { EtaPipe, SpeedPipe, EncodeURIComponent } from './downloads.pipe'; import { MasterCheckboxComponent, SlaveCheckboxComponent } from './master-checkbox.component'; import { MeTubeSocket } from './metube-socket'; import { NgSelectModule } from '@ng-select/ng-select'; +import { ServiceWorkerModule } from '@angular/service-worker'; @NgModule({ declarations: [ @@ -27,7 +28,13 @@ import { NgSelectModule } from '@ng-select/ng-select'; NgbModule, HttpClientModule, FontAwesomeModule, - NgSelectModule + NgSelectModule, + ServiceWorkerModule.register('custom-service-worker.js', { + enabled: !isDevMode(), + // Register the ServiceWorker as soon as the application is stable + // or after 30 seconds (whichever comes first). + registrationStrategy: 'registerWhenStable:30000' + }) ], providers: [CookieService, MeTubeSocket], bootstrap: [AppComponent] diff --git a/ui/src/app/metube-socket.ts b/ui/src/app/metube-socket.ts index cfc8fea..65629ae 100644 --- a/ui/src/app/metube-socket.ts +++ b/ui/src/app/metube-socket.ts @@ -3,7 +3,9 @@ import { Socket } from 'ngx-socket-io'; @Injectable() export class MeTubeSocket extends Socket { - constructor() { - super({ url: '', options: {path: document.location.pathname + 'socket.io'} }); - } + constructor() { + const path = + document.location.pathname.replace(/share-target/, '') + 'socket.io'; + super({ url: '', options: { path } }); + } } diff --git a/ui/src/assets/icons/android-chrome-192x192.png b/ui/src/assets/icons/android-chrome-192x192.png new file mode 100644 index 0000000000000000000000000000000000000000..bc22269bcede5f01b1505319b38ab468eed6a9e9 GIT binary patch literal 3912 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 literal 0 HcmV?d00001 diff --git a/ui/src/assets/icons/android-chrome-384x384.png b/ui/src/assets/icons/android-chrome-384x384.png new file mode 100644 index 0000000000000000000000000000000000000000..abd6b9d79ae342f41241be6f1d40cf6b956559b2 GIT binary patch literal 7967 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 literal 0 HcmV?d00001 diff --git a/ui/src/custom-service-worker.js b/ui/src/custom-service-worker.js new file mode 100644 index 0000000..5ff616f --- /dev/null +++ b/ui/src/custom-service-worker.js @@ -0,0 +1,38 @@ +const URL_PATTERN = + /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._\+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_\+.~#?&//=]*)/gi; + +self.addEventListener("fetch", (event) => { + if (event.request.method === "GET") { + const url = new URL(event.request.url); + + if (url.pathname.endsWith("/share-target")) { + const urlRegExp = new RegExp(URL_PATTERN); + const sharedText = url.searchParams.get("text"); + const matches = [...sharedText.matchAll(urlRegExp)].map((m) => m[0]); + + event.respondWith( + (async () => { + await Promise.all( + matches.map((url) => { + return fetch("/add", { + method: "POST", + headers: { + "Content-Type": "application/json", + }, + body: JSON.stringify({ + url, + quality: "best", + format: "any", + auto_start: true, + }), + }); + }) + ); + return Response.redirect("/", 303); + })() + ); + } + } +}); + +importScripts("./ngsw-worker.js"); diff --git a/ui/src/index.html b/ui/src/index.html index d57a30b..f620859 100644 --- a/ui/src/index.html +++ b/ui/src/index.html @@ -7,14 +7,15 @@ - - + + + diff --git a/ui/src/manifest.webmanifest b/ui/src/manifest.webmanifest new file mode 100644 index 0000000..88183ee --- /dev/null +++ b/ui/src/manifest.webmanifest @@ -0,0 +1,28 @@ +{ + "name": "MeTube", + "short_name": "MeTube", + "theme_color": "#212529", + "background_color": "#fafafa", + "display": "standalone", + "scope": "./", + "start_url": "/?utm_source=homescreen", + "icons": [ + { + "src": "assets/icons/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "assets/icons/android-chrome-384x384.png", + "sizes": "384x384", + "type": "image/png" + } + ], + "share_target": { + "action": "/share-target", + "method": "GET", + "params": { + "text": "text" + } + } +}