diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index f54f4b6..b432b55 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -42,6 +42,8 @@ jobs: context: . platforms: linux/amd64,linux/arm64 push: true + build-args: | + VERSION=${{ steps.date.outputs.date }} tags: | ${{ secrets.DOCKERHUB_REPOSITORY }}:latest ${{ secrets.DOCKERHUB_REPOSITORY }}:${{ steps.date.outputs.date }} diff --git a/Dockerfile b/Dockerfile index 93456f1..10ad50d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -37,4 +37,9 @@ ENV STATE_DIR /downloads/.metube ENV TEMP_DIR /downloads VOLUME /downloads EXPOSE 8081 + +# Add build-time argument for version +ARG VERSION=dev +ENV METUBE_VERSION=$VERSION + ENTRYPOINT ["/sbin/tini", "-g", "--", "./docker-entrypoint.sh"] diff --git a/app/main.py b/app/main.py index 3fe2ca2..0e9959c 100644 --- a/app/main.py +++ b/app/main.py @@ -258,7 +258,10 @@ def robots(request): @routes.get(config.URL_PREFIX + 'version') def version(request): - return web.json_response({"version": yt_dlp_version}) + return web.json_response({ + "yt-dlp": yt_dlp_version, + "version": os.getenv("METUBE_VERSION", "dev") + }) if config.URL_PREFIX != '/': @routes.get('/') diff --git a/ui/package-lock.json b/ui/package-lock.json index 233bc3b..6c4d86b 100644 --- a/ui/package-lock.json +++ b/ui/package-lock.json @@ -20,6 +20,7 @@ "@angular/service-worker": "^19.2.14", "@fortawesome/angular-fontawesome": "~1.0.0", "@fortawesome/fontawesome-svg-core": "^6.7.0", + "@fortawesome/free-brands-svg-icons": "^6.7.2", "@fortawesome/free-regular-svg-icons": "^6.7.0", "@fortawesome/free-solid-svg-icons": "^6.7.0", "@ng-bootstrap/ng-bootstrap": "^18.0.0", @@ -2986,6 +2987,18 @@ "node": ">=6" } }, + "node_modules/@fortawesome/free-brands-svg-icons": { + "version": "6.7.2", + "resolved": "https://registry.npmjs.org/@fortawesome/free-brands-svg-icons/-/free-brands-svg-icons-6.7.2.tgz", + "integrity": "sha512-zu0evbcRTgjKfrr77/2XX+bU+kuGfjm0LbajJHVIgBWNIDzrhpRxiCPNT8DW5AdmSsq7Mcf9D1bH0aSeSUSM+Q==", + "license": "(CC-BY-4.0 AND MIT)", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.7.2" + }, + "engines": { + "node": ">=6" + } + }, "node_modules/@fortawesome/free-regular-svg-icons": { "version": "6.7.2", "resolved": "https://registry.npmjs.org/@fortawesome/free-regular-svg-icons/-/free-regular-svg-icons-6.7.2.tgz", diff --git a/ui/package.json b/ui/package.json index d731953..80a2d63 100644 --- a/ui/package.json +++ b/ui/package.json @@ -23,6 +23,7 @@ "@angular/service-worker": "^19.2.14", "@fortawesome/angular-fontawesome": "~1.0.0", "@fortawesome/fontawesome-svg-core": "^6.7.0", + "@fortawesome/free-brands-svg-icons": "^6.7.2", "@fortawesome/free-regular-svg-icons": "^6.7.0", "@fortawesome/free-solid-svg-icons": "^6.7.0", "@ng-bootstrap/ng-bootstrap": "^18.0.0", diff --git a/ui/src/app/app.component.html b/ui/src/app/app.component.html index 3414d23..9d81805 100644 --- a/ui/src/app/app.component.html +++ b/ui/src/app/app.component.html @@ -355,6 +355,21 @@ diff --git a/ui/src/app/app.component.sass b/ui/src/app/app.component.sass index eafd3b4..65fd740 100644 --- a/ui/src/app/app.component.sass +++ b/ui/src/app/app.component.sass @@ -126,3 +126,59 @@ td white-space: nowrap overflow: visible text-overflow: ellipsis + +.footer + width: 100% + padding: 10px 0 + background: linear-gradient(to bottom, rgba(0,0,0,0.2), rgba(0,0,0,0.1)) + + .footer-content + display: flex + justify-content: center + align-items: center + gap: 20px + color: #fff + font-size: 0.9rem + + .version-item + display: flex + align-items: center + gap: 8px + + .version-label + font-size: 0.75rem + text-transform: uppercase + letter-spacing: 0.5px + opacity: 0.7 + + .version-value + font-family: monospace + font-size: 0.85rem + padding: 2px 6px + background: rgba(255,255,255,0.1) + border-radius: 4px + + .version-separator + width: 1px + height: 16px + background: rgba(255,255,255,0.2) + margin: 0 4px + + .github-link + display: flex + align-items: center + gap: 6px + color: #fff + text-decoration: none + font-size: 0.85rem + padding: 2px 8px + border-radius: 4px + transition: background-color 0.2s ease + + &:hover + background: rgba(255,255,255,0.1) + color: #fff + text-decoration: none + + i + font-size: 1rem diff --git a/ui/src/app/app.component.ts b/ui/src/app/app.component.ts index 887f498..84cdf83 100644 --- a/ui/src/app/app.component.ts +++ b/ui/src/app/app.component.ts @@ -2,6 +2,7 @@ import { Component, ViewChild, ElementRef, AfterViewInit } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { faTrashAlt, faCheckCircle, faTimesCircle, IconDefinition } from '@fortawesome/free-regular-svg-icons'; import { faRedoAlt, faSun, faMoon, faCircleHalfStroke, faCheck, faExternalLinkAlt, faDownload, faFileImport, faFileExport, faCopy } from '@fortawesome/free-solid-svg-icons'; +import { faGithub } from '@fortawesome/free-brands-svg-icons'; import { CookieService } from 'ngx-cookie-service'; import { map, Observable, of, distinctUntilChanged } from 'rxjs'; @@ -38,7 +39,8 @@ export class AppComponent implements AfterViewInit { batchImportStatus = ''; importInProgress = false; cancelImportFlag = false; - versionInfo: string | null = null; + ytDlpVersion: string | null = null; + metubeVersion: string | null = null; isAdvancedOpen = false; @ViewChild('queueMasterCheckbox') queueMasterCheckbox: MasterCheckboxComponent; @@ -64,6 +66,7 @@ export class AppComponent implements AfterViewInit { faFileImport = faFileImport; faFileExport = faFileExport; faCopy = faCopy; + faGithub = faGithub; constructor(public downloads: DownloadsService, private cookieService: CookieService, private http: HttpClient) { this.format = cookieService.get('metube_format') || 'any'; @@ -449,13 +452,15 @@ export class AppComponent implements AfterViewInit { fetchVersionInfo(): void { const baseUrl = `${window.location.origin}${window.location.pathname.replace(/\/[^\/]*$/, '/')}`; const versionUrl = `${baseUrl}version`; - this.http.get<{ version: string}>(versionUrl) + this.http.get<{ 'yt-dlp': string, version: string }>(versionUrl) .subscribe({ next: (data) => { - this.versionInfo = `yt-dlp version: ${data.version}`; + this.ytDlpVersion = data['yt-dlp']; + this.metubeVersion = data.version; }, error: () => { - this.versionInfo = ''; + this.ytDlpVersion = null; + this.metubeVersion = null; } }); }