Skip to content
Two-PlayPublic

About

StashTube is a mobile client for Stash on iOS and Android, built with Flutter. It feels like the YouTube app

Topics

Resources

Contributing

Security policy

Stars

6 stars

Watchers

2 watching

Forks

Repository files navigation

StashTube app icon
StashTube

A YouTube-style mobile client for your own Stash server, for Android and iOS.

Latest release CI Downloads Platforms: Android and iOS Flutter 3.47 License: AGPL-3.0

Get it on Obtainium Join the beta on TestFlight Download on AltStore

StashTube feels like the YouTube app: a feed with large thumbnails, a miniplayer that keeps playing while you browse, performers and studios as "channels", and short portrait videos in a vertical Shorts feed. It talks to your own Stash server through its GraphQL API and plays the streams directly.

Note

StashTube connects only to the Stash server you enter. It has no account, no analytics and no other services. It is not affiliated with the Stash project.

It is in beta:

Important

Signed Android builds are on the releases page; there is no iOS download yet (see iOS).

Screenshots

Home feed with continue watching and shorts Player with controls, rating, chapters and details Shorts

A performer's channel page Markers in the library Choosing the theme after the first login

The screenshots show a demo library made from Blender's open movies Tears of Steel, Caminandes: Gran Dillama, Sintel and Big Buck Bunny (© Blender Foundation, blender.org, licensed under Creative Commons Attribution). tool/screenshots/ sets up that library and takes them again.

Contents

Features

Watching

  • Feed with sort chips, filters (tags, rating, length, resolution) and Stash's saved filters
  • Animated previews: the first fully shown video in a list plays its preview after a moment
  • Miniplayer that turns into the full player as you drag; swipe down to minimize
  • Controls:
    • seek bar with sprite thumbnails and chapter markers
    • double tap to skip 10 s, hold for 2× speed, plus a speed menu
    • quality and transcode choice (HD)
    • pinch to zoom
  • Fullscreen in the video's orientation; turning the phone to landscape enters it
  • Picture-in-picture, background playback, and optional lock screen controls
  • Resume position and play count are saved back to Stash
  • Chromecast, and AirPlay on iOS

Shorts

  • Vertical, looping feed of short portrait videos, with the next one preloaded
  • Your chosen tags show up more often, or exclusively
  • A performer's own shorts from their channel page
  • Four shorts on the home page, each with a queue of its own

Library

  • History, Watch later and groups, each played as a queue with autoplay
  • Markers: every marked moment, with a looping preview, played from the marker
  • Images and galleries, with a zoomable viewer
  • Performers (favorites), studios (with sub-studios) and tags
  • One search for scenes, images, galleries, performers and studios
  • Library and watch statistics

Editing

  • Edit scenes, performers, studios, tags and galleries, including images and URLs
  • Rate scenes, count O's and add markers right from the player

App

  • Several Stash servers to switch between, signed in with an API key or username and password
  • Configurable bottom bar, plus an "All" tab for everything else
  • Light and dark mode and accent colors
  • Layouts with several columns on tablets and in landscape
  • Haptic feedback (off, light, normal)
  • English and German

The backlog with every user story and its status is in docs/BACKLOG.md (German).

Installation

Android with Obtainium (recommended)

Obtainium installs apps straight from their GitHub releases and keeps them up to date.

  1. Install Obtainium.
  2. Tap the Get it on Obtainium badge above on your phone, or add the app in Obtainium by its URL: https://github.com/Two-Play/StashTube.
  3. While StashTube is in beta, turn on Include prereleases in the app's settings in Obtainium.
  4. Install. Obtainium picks the right APK for your phone and notifies you of updates.

Tip

Obtainium also shows the release notes of each update before you install it.

Android with an APK

  1. Open the latest release on your phone.

  2. Download the APK for your phone:

    File For
    stashtube-…-arm64-v8a.apk almost all phones of the last years
    stashtube-…-armeabi-v7a.apk older 32-bit phones
    stashtube-…-x86_64.apk emulators and x86 devices
    stashtube-…-universal.apk any device, but larger
    stashtube-…-foss.apk any device, without Google Cast (no Google Play Services needed)
  3. Open the file and allow your browser or file manager to install apps when Android asks.

  4. To update later, install the newer APK over the old one; your servers and settings stay.

Warning

Only install APKs from this repository's releases. Every release is signed with the same key, and Android refuses an update signed with another one, so nothing else can replace StashTube.

Checking a download

Every release has a SHA256SUMS file. Compare it with the APK you downloaded, for example on a computer:

sha256sum -c SHA256SUMS --ignore-missing

The signing certificate's SHA-256 fingerprint starts with F0:19:71:FF:8A:13:80:A8.

iOS

StashTube isn't in the App Store. There are two ways to get it:

TestFlight (easiest): open the public TestFlight link on your iPhone, install Apple's TestFlight app when asked and tap Accept and Install. TestFlight updates StashTube for you; each beta build runs for 90 days. The number of testers is limited, so the link may be full.

AltStore or SideStore, which sign the app with your own Apple ID:

  1. Install AltStore (with AltServer on a computer) or SideStore.
  2. In Browse → Sources (AltStore) or Sources (SideStore), add the source https://two-play.github.io/StashTube/altstore.json.
  3. Install StashTube from it. Updates show up in the app's My Apps tab.

You can also download the .ipa from the releases and open it in AltStore or SideStore, or build StashTube yourself and install it with Xcode (see Building from source).

Note

With a free Apple ID, sideloaded apps have to be refreshed every 7 days (AltStore and SideStore do it in the background), and only three can be installed at a time.

First start

  1. Enter your server's address, for example 192.168.1.10. Stash listens on port 9999 by default: without a port, StashTube tries that one as well, so you only need to add a port if yours is different. StashTube finds the GraphQL API (/graphql) itself.
  2. If your Stash has a password, either enter an API key (create one in Stash under Settings → Security) or sign in with your username and password.
  3. Pick a theme and an accent color. You can change them, and everything else, in the settings (the gear at the top).

Tip

Plain http:// works on your home network: Android allows cleartext traffic, and iOS has an exception for local servers and media.

Away from home:

Warning

Making your Stash server reachable from the internet is not recommended. To use StashTube on the go, connect your phone to your home network through a VPN (for example WireGuard, or a mesh VPN like Tailscale) and keep using the server's local address. That way Stash stays invisible to the internet.

If you expose it anyway:

Caution

Use https://, a strong password or API key, and keep Stash up to date. Over http:// your API key or password travels unencrypted. Casting always puts the API key into the stream URL, because cast devices can't send headers.

Privacy and discretion

StashTube has a few settings for keeping things private, under Settings → Privacy & security:

  • App lock with a PIN and optionally Face ID or fingerprint, right away or after 1, 5 or 15 minutes in the background
  • Hide in app switcher: covers the app in the recent apps view (always on with the app lock; on Android it also blocks screenshots)
  • Disguised app icon: Notes or Calculator instead of the StashTube icon
  • Lock screen controls (under Playback) are off by default, so titles and thumbnails don't show on the lock screen

Note

The PIN is stored only as a salted hash. It, API keys and passwords are kept in the system's secure storage (Keychain on iOS, Keystore on Android).

Found a security problem? Please report it privately, as described in SECURITY.md.

Building from source

You need:

  • Flutter 3.47 or newer (Dart 3.12)
  • for Android: a current JDK and the Android SDK (compile SDK 37)
  • for iOS: a Mac with Xcode and CocoaPods
  • a Stash server reachable from the device; a recent Stash release is recommended (features whose GraphQL fields an older server lacks are hidden)
git clone https://github.com/Two-Play/StashTube.git
cd StashTube
flutter pub get
flutter run            # on a connected phone or a simulator

To install on an iPhone, open ios/Runner.xcworkspace in Xcode, choose your Apple ID as the team under Signing & Capabilities, and run it on your phone.

Note

Without android/key.properties, which only the maintainers have, Android release builds are signed with the debug key. They install fine, but can't update the official releases, and the other way round.

A build without Google Cast, and so without any Google Play Services, as F-Droid needs it, is described in tool/fdroid/README.md.

Development

dart analyze      # flutter_lints + riverpod_lint (flutter analyze doesn't run analyzer plugins)
flutter test      # unit and widget tests
flutter gen-l10n  # after changing lib/l10n/*.arb
flutter pub run build_runner build --delete-conflicting-outputs   # after changing a .graphql file
  • State: Riverpod 3 with hand-written providers; there is no code generation for providers.
  • Data: StashRepository (lib/data/repositories/) is the only place that talks GraphQL. The documents are in lib/core/api/documents/*.graphql, checked against Stash's schema (lib/core/api/stash_schema.graphql) and generated into typed Dart classes.
  • Video: playback uses media_kit (mpv).
  • Texts: live in lib/l10n/app_en.arb and app_de.arb, never as string literals in the code.
  • Dependencies: pubspec.lock and ios/Podfile.lock are committed; CI runs flutter pub get --enforce-lockfile.
  • Branches: work comes together in develop through pull requests; main only changes with a release.
  • Releases: a pull request from develop to main with the new version, then a tag vX.Y.Z on main that matches version: in pubspec.yaml, which builds signed APKs and an AAB and publishes a GitHub release (.github/workflows/release.yml). Tags with a - become pre-releases.

CLAUDE.md describes the architecture in detail: the server config and data flow, paginated lists, the shell and navigation, the player, Shorts, casting, privacy, theming and localization.

lib/
  core/       API documents, server config, theme, haptics, pagination
  data/       models, StashRepository, list and detail providers
  features/   screens: home, player, shorts, library, performers, studios, tags,
              search, edit, settings, cast, pip, security
  widgets/    shared UI: scene cards, feeds, previews, images, app logo
  l10n/       ARB files and generated localizations

Contributing

Bug reports, ideas and pull requests are welcome. CONTRIBUTING.md explains how to set up, the code conventions and what a pull request needs.

License

StashTube is free software under the GNU Affero General Public License v3.0. The licenses of everything it uses are in the app under Settings → About → Open source licenses: the Flutter and Dart packages, and the native libraries of the video player (mpv, FFmpeg and their dependencies, under LGPL and permissive licenses).

Note

StashTube is an independent project. It is not affiliated with, endorsed by or connected to the Stash project or its developers; "Stash" only names the server software StashTube connects to.

About

StashTube is a mobile client for Stash on iOS and Android, built with Flutter. It feels like the YouTube app

Topics

Resources

Contributing

Security policy

Stars

6 stars

Watchers

2 watching

Forks

Releases

Sponsor this project

Packages

Used by

Contributors

Languages