diff --git a/bazarr/api.py b/bazarr/api.py index 08d81cf51..97ea20c4a 100644 --- a/bazarr/api.py +++ b/bazarr/api.py @@ -23,6 +23,7 @@ from bs4 import BeautifulSoup as bso from get_args import args from config import settings, base_url, save_settings, get_settings from logger import empty_log +from init import startTime from init import * import logging @@ -606,6 +607,7 @@ class SystemStatus(Resource): system_status.update({'python_version': platform.python_version()}) system_status.update({'bazarr_directory': os.path.dirname(os.path.dirname(__file__))}) system_status.update({'bazarr_config_directory': args.config_dir}) + system_status.update({'start_time': startTime}) return jsonify(data=system_status) diff --git a/bazarr/init.py b/bazarr/init.py index f90c9947e..78e86942c 100644 --- a/bazarr/init.py +++ b/bazarr/init.py @@ -14,6 +14,11 @@ from helper import path_mappings from dogpile.cache.region import register_backend as register_cache_backend import subliminal import datetime +import time + +# set start time global variable as epoch +global startTime +startTime = time.time() # set subliminal_patch user agent os.environ["SZ_USER_AGENT"] = "Bazarr/{}".format(os.environ["BAZARR_VERSION"]) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index a2c91355d..39975ce57 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -19,6 +19,7 @@ "axios": "^0.23", "bootstrap": "^4", "lodash": "^4", + "moment": "^2.29.1", "rc-slider": "^9.7", "react": "^17", "react-bootstrap": "^1", @@ -13780,6 +13781,14 @@ "mkdirp": "bin/cmd.js" } }, + "node_modules/moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==", + "engines": { + "node": "*" + } + }, "node_modules/move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", @@ -32711,6 +32720,11 @@ "minimist": "^1.2.5" } }, + "moment": { + "version": "2.29.1", + "resolved": "https://registry.npmjs.org/moment/-/moment-2.29.1.tgz", + "integrity": "sha512-kHmoybcPV8Sqy59DwNDY3Jefr64lK/by/da0ViFcuA4DH0vQg5Q6Ze5VimxkfQNSC+Mls/Kx53s7TjP1RhFEDQ==" + }, "move-concurrently": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", diff --git a/frontend/package.json b/frontend/package.json index a8310e898..860700269 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -38,7 +38,8 @@ "rooks": "^5.7.1", "sass": "^1", "socket.io-client": "^4", - "typescript": "^4" + "typescript": "^4", + "moment": "^2.29.1" }, "devDependencies": { "@types/bootstrap": "^5", diff --git a/frontend/src/@types/system.d.ts b/frontend/src/@types/system.d.ts index 154bb5b98..737bd63d7 100644 --- a/frontend/src/@types/system.d.ts +++ b/frontend/src/@types/system.d.ts @@ -16,6 +16,7 @@ declare namespace System { python_version: string; radarr_version: string; sonarr_version: string; + start_time: number; } interface Health { diff --git a/frontend/src/System/Status/index.tsx b/frontend/src/System/Status/index.tsx index 44573f6ef..c937995eb 100644 --- a/frontend/src/System/Status/index.tsx +++ b/frontend/src/System/Status/index.tsx @@ -6,7 +6,8 @@ import { } from "@fortawesome/free-brands-svg-icons"; import { faPaperPlane } from "@fortawesome/free-solid-svg-icons"; import { FontAwesomeIcon } from "@fortawesome/react-fontawesome"; -import React, { FunctionComponent } from "react"; +import moment from "moment"; +import React, { FunctionComponent, useEffect, useState } from "react"; import { Col, Container, Row } from "react-bootstrap"; import { Helmet } from "react-helmet"; import { useSystemHealth, useSystemStatus } from "../../@redux/hooks"; @@ -69,6 +70,25 @@ const SystemStatusView: FunctionComponent = () => { const health = useSystemHealth(); const status = useSystemStatus(); + const [uptime, setState] = useState(); + + useEffect(() => { + const interval = setInterval(() => { + if (status) { + let duration = moment.duration( + moment().utc().unix() - status.start_time, + "seconds" + ), + days = duration.days(), + hours = duration.hours().toString().padStart(2, "0"), + minutes = duration.minutes().toString().padStart(2, "0"), + seconds = duration.seconds().toString().padStart(2, "0"); + setState(days + "d " + hours + ":" + minutes + ":" + seconds); + } + }, 1000); + return () => clearInterval(interval); + }, [status]); + return ( @@ -106,6 +126,9 @@ const SystemStatusView: FunctionComponent = () => { {status?.bazarr_config_directory} + + {uptime} +