Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
33 changes: 29 additions & 4 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,15 +31,29 @@ jobs:
- name: Check out flatpak manifest
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Check out OpenTubeX screenshot automation
- name: Resolve latest stable metadata tag
id: stable-metadata
env:
GH_TOKEN: ${{ github.token }}
run: |
set -euo pipefail
tag="$(gh api repos/OpenTubeX/OpenTubeX/releases/latest --jq .tag_name)"
if [[ ! "$tag" =~ ^v[0-9]+\.[0-9]+\.[0-9]+-beta$ ]]; then
echo "Expected the latest stable release to be a beta tag, got: $tag" >&2
exit 1
fi
echo "tag=${tag}" >> "$GITHUB_OUTPUT"

- name: Check out OpenTubeX metadata assets
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
repository: OpenTubeX/OpenTubeX
ref: development
ref: ${{ steps.stable-metadata.outputs.tag }}
path: opentubex
persist-credentials: false
sparse-checkout: |
_scripts
_icons/icon.svg
docs/screenshots

- name: Resolve OpenTubeX release
Expand Down Expand Up @@ -101,17 +115,21 @@ jobs:
env:
TAG: ${{ steps.release.outputs.tag }}
ASSET_VERSION: ${{ steps.release.outputs.asset_version }}
STABLE_METADATA_TAG: ${{ steps.stable-metadata.outputs.tag }}
run: |
set -euo pipefail

sha256_x64="$(sha256sum "opentubex-${ASSET_VERSION}-linux-x64-portable.zip" | awk '{print $1}')"
sha256_arm64="$(sha256sum "opentubex-${ASSET_VERSION}-linux-arm64-portable.zip" | awk '{print $1}')"
icon_sha256="$(sha256sum opentubex/_icons/icon.svg | awk '{print $1}')"

yq -i "
.modules[0].sources[0].url = \"https://github.com/OpenTubeX/OpenTubeX/releases/download/${TAG}/opentubex-${ASSET_VERSION}-linux-x64-portable.zip\" |
.modules[0].sources[0].sha256 = \"${sha256_x64}\" |
.modules[0].sources[1].url = \"https://github.com/OpenTubeX/OpenTubeX/releases/download/${TAG}/opentubex-${ASSET_VERSION}-linux-arm64-portable.zip\" |
.modules[0].sources[1].sha256 = \"${sha256_arm64}\"
.modules[0].sources[1].sha256 = \"${sha256_arm64}\" |
.modules[0].sources[2].url = \"https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/${STABLE_METADATA_TAG}/_icons/icon.svg\" |
.modules[0].sources[2].sha256 = \"${icon_sha256}\"
" org.opentubex.OpenTubeX.yml

- name: Remove downloaded archives
Expand Down Expand Up @@ -155,7 +173,7 @@ jobs:
set -euo pipefail
node opentubex/_scripts/syncAppStreamScreenshots.mjs \
org.opentubex.OpenTubeX.metainfo.xml \
development
${{ steps.stable-metadata.outputs.tag }}

- name: Commit manifest updates
if: steps.release.outputs.channel == 'stable'
Expand Down Expand Up @@ -210,6 +228,13 @@ jobs:
name: manifest
path: .

- name: Validate Flatpak metadata
run: |
set -euo pipefail
flatpak-builder-lint manifest org.opentubex.OpenTubeX.yml
flatpak-builder-lint appstream org.opentubex.OpenTubeX.metainfo.xml
desktop-file-validate org.opentubex.OpenTubeX.desktop

- name: Build Flatpak bundle
uses: flatpak/flatpak-github-actions/flatpak-builder@79327416609af08178ad73b352877e51450790b3 # v6.8
with:
Expand Down
30 changes: 30 additions & 0 deletions .github/workflows/validate.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Validate Flatpak metadata

on:
pull_request:
push:
branches:
- main

permissions:
contents: read

jobs:
validate:
name: Validate metadata
runs-on: ubuntu-latest
container:
image: ghcr.io/flathub-infra/flatpak-github-actions:freedesktop-25.08

steps:
- name: Check out repository
uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1

- name: Validate manifest
run: flatpak-builder-lint manifest org.opentubex.OpenTubeX.yml

- name: Validate AppStream metadata
run: flatpak-builder-lint appstream org.opentubex.OpenTubeX.metainfo.xml

- name: Validate desktop entry
run: desktop-file-validate org.opentubex.OpenTubeX.desktop
9 changes: 5 additions & 4 deletions org.opentubex.OpenTubeX.desktop
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
[Desktop Entry]
Name=OpenTubeX
Comment=A private YouTube client
Comment[de]=Ein privater YouTube-Client
GenericName=OpenTubeX
Comment=Privacy-focused YouTube client
Comment[de]=Datenschutzorientierter YouTube-Client
GenericName=YouTube Client
Exec=/app/bin/run.sh %u
Icon=org.opentubex.OpenTubeX
Type=Application
StartupNotify=true
StartupWMClass=opentubex
Categories=GNOME;GTK;AudioVideo;Network;Utility;
Categories=AudioVideo;Video;Network;
Keywords=YouTube;video;privacy;subscriptions;playlists;SponsorBlock;
MimeType=x-scheme-handler/opentubex;
70 changes: 51 additions & 19 deletions org.opentubex.OpenTubeX.metainfo.xml
Original file line number Diff line number Diff line change
@@ -1,65 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Copyright 2026 OpenTubeX contributors -->
<component type="desktop-application">
<id>org.opentubex.OpenTubeX</id>
<metadata_license>CC0-1.0</metadata_license>
<name>OpenTubeX</name>
<summary>A private YouTube client</summary>
<summary>Privacy-focused YouTube client</summary>
<description>
<p>OpenTubeX is an open source desktop YouTube player built with privacy in
mind. Use YouTube without advertisements and prevent Google from tracking
you with their cookies and JavaScript. Available for Windows, Mac &amp;
Linux thanks to Electron.</p>
<p>Please note that OpenTubeX is currently in Beta. While it should work well
for most users, there are still bugs and missing features that need to be
addressed.</p>
<p>OpenTubeX is an open-source, highly customizable, privacy-focused YouTube
client. Watch videos without ads or a Google account, with subscriptions,
playlists and history stored on your device by default.</p>
<p>Organize subscriptions into profiles, save playback preferences per
channel, customize keyboard shortcuts, skip SponsorBlock segments, use
DeArrow, open videos in tabs, build a queue and keep watching in the
mini-player. Optional recommendations rank unwatched videos locally using
your viewing activity and feedback.</p>
<p>OpenTubeX uses a built-in extractor to request data and videos directly
from YouTube, or you can use an Invidious API instead. It does not load the
standard YouTube website or its page JavaScript; network services can still
observe request metadata unless you use a proxy.</p>
</description>
<launchable type="desktop-id">org.opentubex.OpenTubeX.desktop</launchable>
<categories>
<category>AudioVideo</category>
<category>Video</category>
<category>Network</category>
</categories>
<keywords>
<keyword>YouTube</keyword>
<keyword>video</keyword>
<keyword>privacy</keyword>
<keyword>subscriptions</keyword>
<keyword>playlists</keyword>
<keyword>SponsorBlock</keyword>
</keywords>
<url type="homepage">https://opentubex.org/</url>
<url type="bugtracker">https://github.com/OpenTubeX/OpenTubeX/issues</url>
<url type="vcs-browser">https://github.com/OpenTubeX/OpenTubeX</url>
<url type="translate">https://weblate.d3sox.me/engage/opentubex/</url>
<url type="translate">https://weblate.opentubex.org/engage/opentubex/</url>
<url type="donation">https://github.com/sponsors/D3SOX</url>
<project_license>AGPL-3.0-or-later</project_license>
<developer_name>OpenTubeX contributors</developer_name>
<developer id="org.opentubex">
<name>OpenTubeX contributors</name>
</developer>
<branding>
<color type="primary" scheme_preference="light">#147a70</color>
<color type="primary" scheme_preference="dark">#2ec4b6</color>
</branding>
<screenshots>
<screenshot type="default">
<caption>The main OpenTubeX window (dark theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX1-dark.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX1-dark.png</image>
</screenshot>
<screenshot>
<caption>The main OpenTubeX window (light theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX1-light.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX1-light.png</image>
</screenshot>
<screenshot>
<caption>Watching a video (dark theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX2-dark.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX2-dark.png</image>
</screenshot>
<screenshot>
<caption>Watching a video (light theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX2-light.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX2-light.png</image>
</screenshot>
<screenshot>
<caption>Settings (dark theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX3-dark.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX3-dark.png</image>
</screenshot>
<screenshot>
<caption>Settings (light theme)</caption>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/docs/screenshots/OpenTubeX3-light.png</image>
<image type="source" width="1710" height="1026">https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/docs/screenshots/OpenTubeX3-light.png</image>
</screenshot>
</screenshots>
<content_rating type="oars-1.0">
<content_rating type="oars-1.1">
<content_attribute id="violence-cartoon">moderate</content_attribute>
<content_attribute id="violence-fantasy">moderate</content_attribute>
<content_attribute id="violence-realistic">moderate</content_attribute>
<content_attribute id="violence-bloodshed">moderate</content_attribute>
<content_attribute id="drugs-alcohol">moderate</content_attribute>
<content_attribute id="drugs-narcotics">moderate</content_attribute>
<content_attribute id="drugs-tobacco">moderate</content_attribute>
<content_attribute id="language-profanity">moderate</content_attribute>
<content_attribute id="language-humor">moderate</content_attribute>
<content_attribute id="language-discrimination">moderate</content_attribute>
<content_attribute id="social-chat">moderate</content_attribute>
<content_attribute id="social-audio">moderate</content_attribute>
<content_attribute id="social-contacts">intense</content_attribute>
<content_attribute id="social-info">mild</content_attribute>
<content_attribute id="money-advertising">moderate</content_attribute>
</content_rating>
<supports>
<control>keyboard</control>
<control>pointing</control>
<control>touch</control>
<control>gamepad</control>
</supports>
<requires>
<display_length compare="ge">360</display_length>
Expand Down
21 changes: 11 additions & 10 deletions org.opentubex.OpenTubeX.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,9 @@ base-version: '25.08'
command: run.sh
separate-locales: false
finish-args:
- --require-version=1.16.0
- --device=dri
- --device=input
- --share=ipc
- --socket=wayland
- --socket=fallback-x11
Expand All @@ -31,26 +33,25 @@ modules:
x-checker-data:
is-main-source: true
type: json
url: https://api.github.com/repos/OpenTubeX/OpenTubeX/releases?per_page=1
version-query: .[0].tag_name
url-query: .[0].assets[] | select(.name | endswith("-linux-x64-portable.zip")) | .browser_download_url
timestamp-query: .[0].published_at
url: https://api.github.com/repos/OpenTubeX/OpenTubeX/releases?per_page=100
version-query: map(select(.prerelease == false and .draft == false))[0].tag_name
url-query: map(select(.prerelease == false and .draft == false))[0].assets[] | select(.name | endswith("-linux-x64-portable.zip")) | .browser_download_url
timestamp-query: map(select(.prerelease == false and .draft == false))[0].published_at
release-url-template: https://github.com/OpenTubeX/OpenTubeX/releases/tag/$version
- type: file
only-arches:
- aarch64
url: https://github.com/OpenTubeX/OpenTubeX/releases/download/v0.34.1-beta/opentubex-0.34.1-beta-linux-arm64-portable.zip
sha256: 5629307286b7b1d2e635c4c70cdb997c7da1eb6dc8114d9cfa8c6b0ec3ad017a
x-checker-data:
is-main-source: true
type: json
url: https://api.github.com/repos/OpenTubeX/OpenTubeX/releases?per_page=1
version-query: .[0].tag_name
url-query: .[0].assets[] | select(.name | endswith("-linux-arm64-portable.zip")) | .browser_download_url
timestamp-query: .[0].published_at
url: https://api.github.com/repos/OpenTubeX/OpenTubeX/releases?per_page=100
version-query: map(select(.prerelease == false and .draft == false))[0].tag_name
url-query: map(select(.prerelease == false and .draft == false))[0].assets[] | select(.name | endswith("-linux-arm64-portable.zip")) | .browser_download_url
timestamp-query: map(select(.prerelease == false and .draft == false))[0].published_at
release-url-template: https://github.com/OpenTubeX/OpenTubeX/releases/tag/$version
- type: file
url: https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/development/_icons/icon.svg
url: https://raw.githubusercontent.com/OpenTubeX/OpenTubeX/v0.34.1-beta/_icons/icon.svg
sha256: e1b049358231e105b2b04458ffbc08613674284d7be86a4b00b88cfe46384cb7
- type: file
path: run.sh
Expand Down
Loading