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
Binary file removed .github/assets/screenshot-1.jpg
Binary file not shown.
Binary file added .github/assets/screenshot-1.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file removed .github/assets/screenshot-2.jpg
Binary file not shown.
Binary file added .github/assets/screenshot-2.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
108 changes: 56 additions & 52 deletions .github/workflows/build.yaml
Original file line number Diff line number Diff line change
@@ -1,72 +1,76 @@
name: "build"
name: build

on:
push:
branches: [main]
pull_request:
branches: [main]
branches:
- electron
paths:
- "**.ts"
- "**.js"
- "**.mjs"
- "**.json"
- "**.svelte"
- ".github/workflows/build.yaml"
workflow_dispatch:

jobs:
build:
runs-on: ubuntu-latest
release:
strategy:
fail-fast: false
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]

runs-on: ${{ matrix.os }}

steps:
- uses: actions/checkout@v4

- name: Install Ubuntu dependencies
run: |
sudo apt-get update
sudo apt-get install -y libwebkit2gtk-4.1-dev libasound2-dev libappindicator3-dev librsvg2-dev patchelf nsis lld llvm ninja-build nasm

- name: Setup node
- name: Install Node.js
uses: actions/setup-node@v4
with:
cache: "npm"
node-version: lts/*
node-version: 22
cache: npm
cache-dependency-path: "**/package-lock.json"

- name: Install npm dependencies
- name: Install dependencies
run: npm ci

- name: Run frontend lint
run: npm run lint && npm run check

- name: Install Rust
uses: dtolnay/rust-toolchain@stable
with:
targets: x86_64-pc-windows-msvc

- name: Cache cargo-xwin
uses: actions/cache@v4
with:
path: ~/.xwin
key: xwin-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
xwin-

- uses: Swatinem/rust-cache@v2
with:
workspaces: "./src-tauri -> target"

- name: Install cargo-xwin
run: cargo install --locked cargo-xwin

- name: Run clippy
working-directory: src-tauri
run: cargo clippy
- name: Run lint and typecheck
if: matrix.os == 'ubuntu-latest'
run: npm run lint && npm run typecheck

- name: Build for Linux
run: npm run tauri build
if: matrix.os == 'ubuntu-latest'
run: npm run build:linux

- name: Build for macOS
if: matrix.os == 'macos-latest'
run: npm run build:mac

- name: Build for Windows
run: npm run tauri build -- --runner cargo-xwin --target x86_64-pc-windows-msvc -- --xwin-cache-dir ~/.xwin
if: matrix.os == 'windows-latest'
run: npm run build:win

- name: Create bundles folder and move artifacts
run: |
mkdir -p bundles
mv src-tauri/target/x86_64-pc-windows-msvc/release/bundle/nsis/*.exe bundles
mv src-tauri/target/release/bundle/rpm/*.rpm bundles
mv src-tauri/target/release/bundle/deb/*.deb bundles
- name: Upload Linux installer
if: matrix.os == 'ubuntu-latest'
uses: actions/upload-artifact@v4
with:
name: linux
path: ./dist/rt-*-linux.deb
compression-level: 0

- name: Upload macOS installer
if: matrix.os == 'macos-latest'
uses: actions/upload-artifact@v4
with:
name: mac
path: ./dist/rt-*-mac.dmg
compression-level: 0

- uses: actions/upload-artifact@v4
- name: Upload Windows installer
if: matrix.os == 'windows-latest'
uses: actions/upload-artifact@v4
with:
name: bundles
path: bundles
name: windows
path: ./dist/rt-*-win.exe
compression-level: 0
13 changes: 6 additions & 7 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
.vscode

node_modules
.svelte-kit
build

src-tauri/target
src-tauri/gen/schemas
dist
out
.DS_Store
.eslintcache
electron.vite.config.*.mjs
*.log*
10 changes: 6 additions & 4 deletions .prettierignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package-lock.json
src-tauri
.svelte-kit
build
node_modules
.github
README.md
out
dist
README.md
LICENSE.md
tsconfig.json
tsconfig.*.json
1 change: 1 addition & 0 deletions .prettierrc
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"useTabs": true,
"singleQuote": true,
"semi": false,
"trailingComma": "none",
"printWidth": 100,
"endOfLine": "lf",
Expand Down
39 changes: 39 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
{
"version": "0.2.0",
"configurations": [
{
"name": "Debug Main Process",
"type": "node",
"request": "launch",
"cwd": "${workspaceRoot}",
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite",
"windows": {
"runtimeExecutable": "${workspaceRoot}/node_modules/.bin/electron-vite.cmd"
},
"runtimeArgs": ["--sourcemap"],
"env": {
"REMOTE_DEBUGGING_PORT": "9222"
}
},
{
"name": "Debug Renderer Process",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}/src/renderer",
"timeout": 60000,
"presentation": {
"hidden": true
}
}
],
"compounds": [
{
"name": "Debug All",
"configurations": ["Debug Main Process", "Debug Renderer Process"],
"presentation": {
"order": 1
}
}
]
}
3 changes: 3 additions & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"html.customData": ["./node_modules/vidstack/vscode.html-data.json"]
}
82 changes: 38 additions & 44 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,31 @@
# RT (name pending)

> [!NOTE]
> I am currently working on a port to Electron, I will go into more details about it once it reaches parity with the current version.
> [!WARNING]
> WIP! YouTube videos will run into 403 after some time, embedded videos are used by default for now.

A Twitch and YouTube frontend written in Rust using Tauri and SvelteKit.
A Twitch and YouTube frontend using Svelte and Electron.

<table>
<tr>
<td align="center">
<img alt="zfg1 playing OOT Randomizer" src=".github/assets/screenshot-1.jpg" width="500">
<img alt="vinesauce playing Yoshi's Island" src=".github/assets/screenshot-1.webp" width="500">
<em>
<div>
<a href="https://www.twitch.tv/zfg1">zfg1</a> playing OOT. Chat on Copium for Prime 4.
<a href="https://www.twitch.tv/vinesauce">vinesauce</a> playing Yoshi's Island.
</div>
</em>
</td>
<td align="center">
<img alt="paganmars playing Monster Hunter Wilds" src=".github/assets/screenshot-2.jpg" width="500">
<img alt="YouTube feed" src=".github/assets/screenshot-2.webp" width="500">
<em>
<div>
<a href="https://www.twitch.tv/paganmars">paganmars</a> playing Monster Hunter Wilds. An excelent use of screen space with PiP.
YouTube feed with videos and streams.
</div>
</em>
</td>
</tr>
</table>

> Very old screenshots.

## Features

- Import YouTube subscriptions. (Accepts a `csv` file separated by Channel ID, URL, Title)
Expand All @@ -36,18 +34,21 @@ A Twitch and YouTube frontend written in Rust using Tauri and SvelteKit.
- View Twitch chat with 7tv and BetterTTV emotes.
- Block ads.
- Open videos or streams directly in the app using `rt:://` URLs.
- Picture-in-picture (except for embedded videos).

## Download
## About

> All installers (`exe`, `deb`, `rpm`) are provided in a small zip file.
Tested on Windows and Ubuntu. Not tested on macOS.

[Quick download.](https://nightly.link/Kyagara/rt/workflows/build.yaml/main/bundles.zip) (does not require GitHub account).
### Download

Github Actions builds are available [here](https://github.com/Kyagara/rt/actions).
> These are files from the latest successful build, they do not require a GitHub account to download.

## About
- [Windows](https://nightly.link/Kyagara/rt/workflows/build.yaml/electron/windows.zip)
- [Linux](https://nightly.link/Kyagara/rt/workflows/build.yaml/electron/linux.zip)
- [macOS](https://nightly.link/Kyagara/rt/workflows/build.yaml/electron/mac.zip)

Tested on Windows and Ubuntu. Not tested on macOS as I don't have access to a macOS machine, if you manage to build and test it, please let me know and I will work on fixing issues and adding it to the build bundles.
Github Actions artifacts are available [here](https://github.com/Kyagara/rt/actions).

### Redirects

Expand All @@ -57,22 +58,22 @@ If the app is not running, it will be started with the URL as an argument, if it

`YouTube`:

- `rt://yt/dQw4w9WgXcQ`
- `rt://youtube/dQw4w9WgXcQ`
- `rt://www.youtube.com/watch?v=dQw4w9WgXcQ`
- `rt://youtu.be/dQw4w9WgXcQ`
- `rt://yt/{VIDEO_ID}`
- `rt://youtube/{VIDEO_ID}`
- `rt://www.youtube.com/watch?v={VIDEO_ID}`
- `rt://youtu.be/{VIDEO_ID}`

`Twitch`:

- `rt://tw/zfg1`
- `rt://twitch/zfg1`
- `rt://www.twitch.tv/zfg1`
- `rt://tw/{CHANNEL_NAME}`
- `rt://twitch/{CHANNEL_NAME}`
- `rt://www.twitch.tv/{CHANNEL_NAME}`

If you are using extensions like [LibRedirect](https://github.com/libredirect/browser_extension), you can set a frontend for YouTube like Invidious and set the instance URL to `rt://`. The same can be done for Twitch, you can set the frontend to SafeTwitch and set the instance URL to `rt://`.

### Paths

To store users, feeds and emotes, SQLite is used with [sqlx](https://crates.io/crates/sqlx).
To store users, feeds and emotes, SQLite is used with [better-sqlite3](https://github.com/WiseLibs/better-sqlite3).

Data (databases, window state, etc):

Expand All @@ -88,36 +89,29 @@ Logs:

`YouTube`:

The feed uses YouTube's rss feed to retrieve videos to avoid rate limits, this sadly does not contain video duration.

Using the excellent [RustyPipe](https://crates.io/crates/rustypipe) library to interact with YouTube, its recommended to install [rustypipe-botguard](https://crates.io/crates/rustypipe-botguard) to use a YouTube player instead of the embedded one.

```bash
cargo install rustypipe-botguard
```

The watch page will try to use RustyPipe to retrieve a YouTube player, if it fails, it will use Vidstack's YouTube [provider](https://vidstack.io/docs/player/api/providers/youtube/) to play videos via embeds, this fallback has the drawbacks of not being able to play videos that disallows embedding and not being able to select a video quality. You have the option to switch between them in the Watch page.
The feed uses YouTube's rss feed to retrieve videos to avoid rate limits, this sadly does not contain video duration or if the content is a livestream.

The player currently doesn't show the quality selection correctly, as there are multiple codecs for the same quality, which will show duplicates.
The watch page will try to retrieve a YouTube player using [YouTube.js](https://github.com/LuanRT/YouTube.js), if it fails, it will use Vidstack's YouTube [provider](https://vidstack.io/docs/player/api/providers/youtube/) to play videos via embeds, this fallback has the drawbacks of not being able to play videos that disallows embedding and not being able to select a video quality. You have the option to switch between them.

`Twitch`:

The player uses a custom [hls.js](https://github.com/video-dev/hls.js/) loader that communicates with the backend to retrieve and modify the m3u8 manifests, this is what allows for ad blocking as the backend can detect ads and switch to a backup stream until ads are over, this was inspired by [TwitchAdSolutions](https://github.com/pixeltris/TwitchAdSolutions) method of switching streams.
The player uses a custom [hls.js](https://github.com/video-dev/hls.js/) loader that fetches and reads the playlists, this is what allows for ad blocking as the loader can detect ads and switch to a backup stream until ads are over, this was inspired by [TwitchAdSolutions](https://github.com/pixeltris/TwitchAdSolutions) method of switching streams.

The backend uses GQL queries from the internal Twitch API to retrieve user data and stream playback.
Uses GQL queries from the internal Twitch API to retrieve user data and stream playback.

## TODO

- Update screenshots.
- Add information about the content somewhere in the watch page.
- Maybe make a custom player layout using tailwind.
- Tweak tsconfig and maybe add some more linting.
- Themes.
- Error handling.
- Logging.
- Maybe move to using classes.
- Maybe build just flatpak for Linux.
- Copy watch page content URL.
- YouTube:
- Fix URLs in descriptions, they currently open the URL in the app instead of the default browser, the links are also not formatted properly.
- Add YouTube channel page with video search.
- Allow downloading videos and thumbnails.
- Allow downloading videos (maybe using `yt-dlp`) and thumbnails.
- Search for videos in the feed.
- Properly handle links in the description.
- Fix mute/volume not working in the `player-settings` local storage.
- Twitch:
- It seems there are issues with the `avif` format in emotes in Linux, maybe use `webp` or `png` instead.
- Put the seek bar at the end when joining a stream, currently it is some seconds behind when first joining.
- Add global Twitch emotes.
- Button for adding/removing user from the watch page.
12 changes: 12 additions & 0 deletions build/entitlements.mac.plist
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.security.cs.allow-jit</key>
<true/>
<key>com.apple.security.cs.allow-unsigned-executable-memory</key>
<true/>
<key>com.apple.security.cs.allow-dyld-environment-variables</key>
<true/>
</dict>
</plist>
Binary file added build/icon.icns
Binary file not shown.
Binary file added build/icon.ico
Binary file not shown.
Binary file added build/icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading