From e9ad0b4837fb08891c3aaccf01bb245201355738 Mon Sep 17 00:00:00 2001 From: David Ludwig Date: Tue, 22 Jun 2021 08:54:20 -0500 Subject: [PATCH] Added progress to webui --- .../src/app/components/MovieListItem.vue | 2 +- services/webui/src/app/index.ts | 7 ++- services/webui/src/app/livewire.ts | 55 +++++++++++++++++++ services/webui/src/app/util.ts | 7 +++ services/webui/src/app/websocket.ts | 12 +++- services/webui/tsconfig.json | 2 +- services/webui/tsconfig.server.json | 2 - 7 files changed, 81 insertions(+), 6 deletions(-) create mode 100644 services/webui/src/app/livewire.ts diff --git a/services/webui/src/app/components/MovieListItem.vue b/services/webui/src/app/components/MovieListItem.vue index 6792a36..859ffe4 100644 --- a/services/webui/src/app/components/MovieListItem.vue +++ b/services/webui/src/app/components/MovieListItem.vue @@ -13,7 +13,7 @@
-
+
diff --git a/services/webui/src/app/index.ts b/services/webui/src/app/index.ts index ac104bd..6e106e2 100644 --- a/services/webui/src/app/index.ts +++ b/services/webui/src/app/index.ts @@ -3,7 +3,7 @@ import router from "./routes"; import store from "./store"; import App from './App.vue' import "./styles/index.css"; -import "./websocket"; +import * as livewire from "./livewire"; /** * Create the Vue application @@ -13,6 +13,11 @@ app.use(router); app.use(store); app.mount("#app"); +/** + * Start livewire services + */ +livewire.updateMoviesInStore(); + /** * Dropdown menus */ diff --git a/services/webui/src/app/livewire.ts b/services/webui/src/app/livewire.ts new file mode 100644 index 0000000..a144ab7 --- /dev/null +++ b/services/webui/src/app/livewire.ts @@ -0,0 +1,55 @@ +import store from "./store"; +import { sleep } from "./util"; +import websocket from "./websocket"; + +/** + * Regularly update movies in the store + */ +export async function updateMoviesInStore() { + const THROTTLE = 500; + let lastUpdateTime = 0; + + // Cache movie ticket IDs + let ticketIds: number[] = []; + let updateCachedTicketIds = () => { + ticketIds = Object.keys(store.state.movieTickets).map(parseInt); + console.log("Ticket cache updated"); + }; + updateCachedTicketIds(); + + // Listen for movie list updates + let onMoviesUpdated: (() => void)|null = null; + store.watch(state => state.movieTickets, () => { + updateCachedTicketIds(); + if (onMoviesUpdated !== null) { + onMoviesUpdated(); + } + }, { deep: true }); + + while (true) { + // Throttle the udpates + await sleep(THROTTLE - (Date.now() - lastUpdateTime)); + lastUpdateTime = Date.now(); + + // Wait until there are movies in the list before updating + if (ticketIds.length == 0) { + await new Promise(resolve => onMoviesUpdated = resolve); + } + + // Get the progress of all movie tickets + console.log("Updating movies", ticketIds.length); + try { + let result = await websocket.movieProgress(ticketIds); + for (let ticketId of Object.keys(result)) { + let tmdbId = store.state.movieTickets[ticketId]; + if (tmdbId === undefined || store.state.movies[ticketId]) { + continue; + } + store.state.movies[tmdbId].movie.plexLink = result[ticketId].plexLink ?? null; + store.state.movies[tmdbId].movie.progress = result[ticketId].progress ?? null; + } + } catch(e) { + console.error("Failed to update movies!", e); + } + } +} diff --git a/services/webui/src/app/util.ts b/services/webui/src/app/util.ts index 5860e9f..c864a64 100644 --- a/services/webui/src/app/util.ts +++ b/services/webui/src/app/util.ts @@ -49,3 +49,10 @@ export function getAverageRgb(imgEl: HTMLImageElement) { return rgb; } + +/** + * Sleep for the provided number of milliseconds + */ +export function sleep(ms: number) { + return new Promise(resolve => setTimeout(resolve, ms)); +} diff --git a/services/webui/src/app/websocket.ts b/services/webui/src/app/websocket.ts index 4232a44..2386c4d 100644 --- a/services/webui/src/app/websocket.ts +++ b/services/webui/src/app/websocket.ts @@ -1,4 +1,5 @@ import { WebSocketClient as WSClient } from "@autoplex/websocket-client"; +import { IMovieProgressResponse, WebSocketMethod } from "@autoplex-api/request"; import store, { Action } from "./store"; class WebSocketClient extends WSClient @@ -23,6 +24,15 @@ class WebSocketClient extends WSClient protected forgetJwt() { store.dispatch(Action.AuthForget, undefined); } + + // Public Interface ---------------------------------------------------------------------------- + + /** + * Get the progress of the given movies + */ + public async movieProgress(ticketIds: number[]) { + return await this.request(WebSocketMethod.TicketProgress, ticketIds); + } } -export default new WebSocketClient("ws://localhost:3250/"); +export default new WebSocketClient(`ws://${document.domain}:3250/`); diff --git a/services/webui/tsconfig.json b/services/webui/tsconfig.json index 99aedf3..0667856 100644 --- a/services/webui/tsconfig.json +++ b/services/webui/tsconfig.json @@ -4,7 +4,7 @@ /* Basic Options */ // "incremental": true, /* Enable incremental compilation */ - "target": "es2015", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ + // "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ // "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ // "lib": [], /* Specify library files to be included in the compilation. */ // "allowJs": true, /* Allow javascript files to be compiled. */ diff --git a/services/webui/tsconfig.server.json b/services/webui/tsconfig.server.json index 7a537a4..cc23631 100644 --- a/services/webui/tsconfig.server.json +++ b/services/webui/tsconfig.server.json @@ -1,8 +1,6 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "target": "es5", /* Specify ECMAScript target version: 'ES3' (default), 'ES5', 'ES2015', 'ES2016', 'ES2017', 'ES2018', 'ES2019', 'ES2020', or 'ESNEXT'. */ - "module": "commonjs", /* Specify module code generation: 'none', 'commonjs', 'amd', 'system', 'umd', 'es2015', 'es2020', or 'ESNext'. */ "outDir": "dist/server", /* Redirect output structure to the directory. */ "sourceRoot": "src/server" /* Specify the location where debugger should locate TypeScript files instead of source locations. */ },