Commit graph

12167 commits

Author SHA1 Message Date
7ff5ac79e5 v0.1.0-U (vc=8): Phase U-1 + U-2 — Rust core + rustypipe search
NewPipeExtractor (Java) → strawcore (Rust) migration begins. Phase U:
- U-1: Rust toolchain + UniFFI smoke test
- U-2: rustypipe search via uniffi suspend fun, SearchViewModel swapped

What landed:
- rust/strawcore — UniFFI-exported Rust crate using proc-macros.
  Builds for arm64-v8a + armeabi-v7a + x86 + x86_64 via cargo-ndk.
  Tokio multi-thread runtime singleton drives rustypipe's async API.
- strawApp/build.gradle.kts — cargoBuildHost + cargoBuild + uniffiBindgen
  Gradle Exec tasks chained into the Android build. Generated Kotlin
  bindings land in src/main/java/uniffi/strawcore/ (gitignored).
- SearchViewModel.kt — calls uniffi.strawcore.search(query) directly.
  NewPipeExtractor still in deps for VideoDetail/Player/Channel paths;
  those move to Rust in U-3 / U-4.
- Build chain quirks beat:
  * cargo absolute path in Exec tasks (PATH wasn't propagating)
  * uniffi-bindgen needs UNSTRIPPED host .so — separate cargoBuildHost
    builds a debug-profile host lib to read metadata from
  * rustypipe rustls-tls-webpki-roots avoids the openssl-sys
    cross-compile tarpit
  * rquickjs-sys 'bindgen' feature opted in (no prebuilt Android
    bindings ship; crafting-table has libclang 14)
- crafting-table runtime install (until Dockerfile catches up):
  rustup + 4 Android targets + cargo-ndk + NDK r27c. Persists in
  /caches/cargo + /caches/android-sdk via the volume mount.

APK size: 22MB (U-1) → 37MB (U-2). libstrawcore.so 3-5MB per ABI carries
rustypipe + reqwest + tokio + rustls + rquickjs. NewPipeExtractor still
in for now (still drives detail + player + channel + feed), so the
Java half is doubled up. U-5 removes it.
2026-05-24 08:36:50 -07:00
9550b207ab v0.1.0-T (vc=7): bug fixes + Opus audit pass #2 + home redesign
User-visible:
- BUG: 'clicking a second item went back to the first video' — VideoDetailViewModel
  guard was short-circuiting on Activity-scoped ViewModel reuse. Now tracks
  loadedUrl and only skips when the requested URL matches.
- BUG: PiP / window mode now auto-enters on Home gesture (Android 12+ via
  setAutoEnterEnabled). Manual PiP button reports failure cause via Toast.
- HOME REDESIGN: replaced 3-tab bottom nav with hamburger ModalNavigationDrawer.
  Default view = sub feed. Drawer items = Subscriptions / History / Search /
  Settings. Top-left hamburger like normal Android apps.

Audit pass #2 (Opus max-effort) — CRIT + HIGH fixes shipped:
- CRIT-1: PlaybackService now calls startForeground() inside onStartCommand
  with a media-playback notification + channel. Pre-fix could throw
  ForegroundServiceDidNotStartInTimeException on Android 12+ and crash-kill.
- CRIT-2: AndroidManifest service exported=false. Previously any installed
  app could craft an Intent and drive playback from attacker URLs.
- HIGH-1: 🎧 background handoff stops the activity player before starting
  the service so we don't dual-host two ExoPlayers + MediaSessions.
- HIGH-2: onStartCommand returns START_NOT_STICKY and tears down on null
  intent; no more crash-restart-crash loop after OS kills.
- HIGH-3: stop service on STATE_ENDED / STATE_IDLE via Player.Listener.
  onTaskRemoved checks playbackState properly so we don't hold WAKE_LOCK
  forever after a video ends in background.
- HIGH-4: Downloader validates scheme=https + googlevideo/youtube host
  before handing the URL to DownloadManager.
- HIGH-5: filename sanitization extended to ASCII control chars, DEL,
  Unicode bidi-override block, leading-dot, trailing whitespace.
- HIGH-6: SubscriptionFeedViewModel cancels prior in-flight refresh,
  caps parallelism at 8 via Semaphore, applies 15s per-channel timeout.
- HIGH-7: sub feed error banner now shows above cached items when refresh
  fails (previously hidden, looked indistinguishable from success).
- HIGH-8: PlayerViewModel falls back to lowest-available stream when no
  stream is under the max-resolution ceiling (was: silent black screen).
- HIGH-9: network_security_config explicit cleartextTrafficPermitted='false'
  on the RYD domain-config block (doesn't inherit from base-config).
- MED-1: PlaybackService.onDestroy nulls field before releasing session to
  close a race with onGetSession during teardown.
- MED-6: Downloader catches enqueue exceptions, returns -1L, caller toasts
  'download refused (bad URL)' instead of crashing.

Deferred (audit said 'can wait'): MED-2..5, MED-7..11, HIGH-10 UX consistency.
2026-05-24 07:49:35 -07:00
Kayos
081f238355 Straw phases P/Q/R/S — bottom nav, sub feed, downloads, background audio
Phase P — bottom navigation:
- StrawHome restructured as a Scaffold with Material3 NavigationBar.
- Three tabs: Home (search + last 10 watches), Library (full watch
  history with count), Subs (channel chips + aggregated feed).

Phase Q — subscription feed:
- New SubscriptionFeedViewModel fans out per-channel ChannelInfo +
  ChannelTabs.VIDEOS fetches in parallel via async/awaitAll.
- Each channel contributes top 5; merged across all subs, capped at
  200, sorted by view count as a soft-recency proxy (extractor doesn't
  reliably surface upload timestamps).
- 10-minute cache TTL avoids hammering YT on tab re-entry.
- Subs tab renders the feed below the avatar row with a Refresh button.

Phase R — download:
- Download button on VideoDetail (next to Play / Share). Pops a tiny
  dialog: Audio (best audioStream) or Video (best videoStream/
  videoOnly fallback).
- Uses Android's DownloadManager — saves into app-private external
  files dir (Android/data/com.sulkta.straw.debug/files/Movies/<kind>/).
  Notification + progress for free. No WRITE_EXTERNAL_STORAGE needed.
- Filenames sanitized (no /:*?\"<>| chars), capped at 120 chars.

Phase S — background audio:
- New "Background" overlay button (🎧) on the player. Tap to pause the
  activity player and start PlaybackService with the audio URL.
- PlaybackService is a Media3 MediaSessionService with its own ExoPlayer
  configured with our custom DataSource.Factory (User-Agent set, cross-
  protocol redirects). Foreground service + media notification.
- Audio survives activity death — swipe the app out of recents, audio
  keeps playing. Stop via notification or open-the-app-and-tap-stop.
- onTaskRemoved keeps the service alive iff something is playing.

Versions shipped: P+Q as vc=4, R as vc=5, S as vc=6. Each landed in the
F-Droid repo for the day-by-day refresh path.

Day-N+ ideas: real MediaController unification (single Player for both
foreground + background paths), MergingMediaSource on the service side
for high-res YT videos, real upload-timestamp sort for feed once the
extractor exposes it consistently, queue/playlist.
2026-05-24 04:30:06 -07:00
Kayos
fa97b698fe Straw phase O: related videos + max-resolution picker (v0.1.0-O / vc=3)
VideoDetail screen:
- New "Related" section at the bottom — pulls
  StreamInfo.relatedItems, filters to StreamInfoItem, renders as
  inline thumbnail rows. Tap → push another VideoDetail. Up to 20
  items shown. Each row uses bestThumbnail() for hi-res.

Settings screen + PlayerViewModel:
- New "Playback" section with a Max-Resolution picker:
  Auto / 1080p / 720p / 480p / 360p / 144p. Persisted to
  SharedPreferences (KEY_MAX_RES) via SettingsStore.maxResolution
  StateFlow.
- PlayerViewModel.resolve filters videoStreams + videoOnlyStreams by
  the ceiling before picking the max-bitrate one. Auto (Int.MAX_VALUE)
  is unchanged behavior. Choosing 720p caps the renderer so 1080p/4K
  streams are skipped — saves bandwidth on mobile + helps low-end
  decoders.

Phase P next ideas: bottom navigation tabs (Home / Subs feed /
Library), Download (audio + video), the MediaSessionService refactor
for true background audio after activity death.
2026-05-24 03:44:54 -07:00
Kayos
253c5e268b Straw phase N: share + playback speed + audio-only toggle (v0.1.0-N / vc=2)
Player overlay (top-right) now hosts four buttons in a row:
- Speed: 1× by default; tap opens a dialog of 0.25× / 0.5× / 0.75× / 1× /
  1.25× / 1.5× / 1.75× / 2×. Applies via exoPlayer.playbackParameters.
- Audio-only toggle (📻/📺): toggles Player.TRACK_TYPE_VIDEO via
  TrackSelectionParameters. Saves bandwidth + battery for screen-off
  listening. Toast confirms state.
- Share (↗): Intent.ACTION_SEND with text/plain containing the YouTube
  URL + the video title as EXTRA_SUBJECT. Hands off to Android share
  sheet.
- PiP (⊟): same as M-1 but now part of the row instead of its own
  floating square.

VideoDetail screen: Play button now lives in a Row with an OutlinedButton
"Share" that fires the same ACTION_SEND chooser. Same UX surface for
users who land on detail without going to player.

Version: STRAW_VERSION_CODE 1 → 2, STRAW_VERSION_NAME "0.1.0-day1" →
"0.1.0-N" so the F-Droid client sees this as an upgrade.

Phase O next (per Cobb's "where are all the features"): quality picker,
related videos on detail, download (audio + video).
2026-05-23 21:20:15 -07:00
Kayos
7894fe5a4d Straw phase M-2: MediaSession + audio focus + service skeleton
Wraps the existing Activity-owned ExoPlayer in a Media3 MediaSession. Side
effects:
- Lock-screen media controls (play/pause)
- System media notification with play/pause buttons
- Audio focus + ducking (other audio dims when straw plays)
- Bluetooth + headset hardware-button routing
- Plays nicely alongside other media apps' notifications

The ExoPlayer is also configured with AudioAttributes (USAGE_MEDIA +
CONTENT_TYPE_MOVIE) and handleAudioFocus=true so other apps can request
focus correctly (e.g., a phone call ducks/pauses straw).

Also scaffolded but NOT yet wired:
- PlaybackService extending MediaSessionService — the foundation for
  true background-after-Activity-kill audio. Manifest entry + deps
  added (media3-session 1.4.1, concurrent-futures-ktx 1.2.0). The
  Activity-to-Service migration via MediaController is M-3 work.
- POST_NOTIFICATIONS, FOREGROUND_SERVICE,
  FOREGROUND_SERVICE_MEDIA_PLAYBACK, WAKE_LOCK permissions in manifest.

For the user right now: lock the phone while a video plays — media
controls appear on the lock screen. Open another app — notification with
play/pause sits in the shade. Press a headset's play/pause — straw
responds. Pull the home screen — PiP keeps the video floating + audio
continues. Full screen-off-background-audio after killing the activity
arrives in M-3.
2026-05-23 20:46:47 -07:00
Kayos
1578de5dbb Straw phase M-1: tap-thumbnail-to-play + hi-res thumbs + Picture-in-Picture
Cobb's real-use feedback: "playing a video is a button under a very
pixelated thumbnail, no playing in window mode, ... where are all the
features." This is the visible-UX pass.

Thumbnails:
- New util/Thumbnails.kt#bestThumbnail picks the highest-res image from
  NewPipeExtractor's List<Image> by w*h pixel area. Was firstOrNull()
  which is the smallest in the sorted list. Applied across Search,
  Channel video rows, Channel avatar + banner, VideoDetail.

Tap-to-play:
- VideoDetail thumbnail is now wrapped in a clickable Box that fires
  onPlay(). Centered semi-transparent black circle with a white play
  triangle overlay so the affordance is obvious. The standalone "Play"
  button below stays for accessibility (tap target consistency).

Picture-in-Picture:
- Manifest: android:supportsPictureInPicture="true" on StrawActivity +
  added screenLayout|smallestScreenSize|screenSize to configChanges so
  rotation into PiP doesn't recreate.
- PlayerScreen: top-right floating button enters PiP with 16:9 aspect.
- Lifecycle ON_STOP observer now checks isInPictureInPictureMode and
  skips pausing when we're in PiP (was killing playback on PiP entry).

Phase M-2 next: MediaSession + background audio + foreground service
(the "play with screen off / lock screen controls" feature).
2026-05-23 20:40:53 -07:00
Kayos
2fd439cac8 Straw audit-fix sprint: CRIT-1 + HIGH-9 + targeted MED
Phase L. Triages findings from the Opus max-effort audit
(memory/2026-05-23-night3-straw later; agent report inline).

CRIT-1: ACTION_SEND URL extracted from arbitrary text/plain share now
  re-validated via URI host check before reaching NewPipeExtractor.
  Manifest scheme also validated for VIEW. Regex broadened to accept
  music.youtube.com + youtube-nocookie. Host set expanded.

HIGH: usesCleartextTraffic="true" removed from manifest (was redundant
  with network_security_config + misleading to reviewers).

HIGH: NewPipeDownloader hardens header copy — runCatching around addHeader
  to survive poisoned response headers with \r/\n. Explicit UA added AFTER
  upstream header copy so it wins. Switched to OkHttp 5 extension form
  for toRequestBody.

HIGH: Bounded response bodies via new util `cappedString(maxBytes)`. Caps
  at 8MiB (NewPipeExtractor), 1MiB (SponsorBlock), 256KiB (RYD). Defends
  against OOM via gigabyte response. Partial defense — chunked transfers
  without Content-Length still streamed up to cap.

HIGH: HistoryStore / SettingsStore / SubscriptionsStore moved from
  non-atomic `_flow.value = next` to `_flow.updateAndGet { ... }`. Closes
  the read-modify-write race that could drop concurrent writes.

HIGH: VideoDetailViewModel.load had a dead-code `if (...)` block with no
  body — falls through every call. Replaced with a real early-return on
  detail-already-loaded.

HIGH: ChannelViewModel picked `info.tabs.firstOrNull()` which is YouTube's
  curated "Home" tab. Switched to `firstOrNull { ChannelTabs.VIDEOS in
  contentFilters }` with fallback. Channel screen now shows actual videos.

HIGH: PlayerScreen SponsorBlock skip loop hardened:
  - dedup skipped UUIDs so re-listen doesn't fight the user
  - poll 250ms → 150ms reduces sponsor leak through buffering
  - `isPlaying` → `playbackState != IDLE/ENDED` so buffering doesn't miss
  - clamp seek away from duration boundary (prevents past-end jank)
  - filter POI-style point segments (start ≈ end)

MED: ExoPlayer pause on app background via Lifecycle.Event.ON_STOP
  observer. Was silently playing audio with no MediaSession when app
  was backgrounded.

MED: Log.d/Log.w gated behind BuildConfig.DEBUG via new strawLogD/strawLogW
  inline helpers in util/Log.kt. Lambda body skipped in release too.
  Log.i remains unguarded for user-quotable events. RydClient +
  SponsorBlockClient + PlayerScreen updated.

MED: Hardcoded version "v0.1.0" in StrawHome replaced with
  BuildConfig.VERSION_NAME. Now reads "v0.1.0-day1" matching ProjectConfig.

MED: Triplicated formatCount/formatViews/formatDuration extracted to
  util/Formatting.kt. Search/Channel/VideoDetail import the shared
  functions.

MED: SponsorBlockClient.buildJsonArray uses kotlinx-serialization Json
  encoder instead of hand-rolled string concat — defends against future
  user-typed category names breaking the URL.

MED: Description regex passes capped to 20k input chars before stripHtml
  on detail screen — defends against ANR on multi-MB descriptions.

Deferred to phase M (not in this sprint):
  - R8 + ProGuard rules for release builds (isMinifyEnabled=true)
  - ExoPlayer hoisting into PlayerViewModel (AndroidViewModel)
  - DI / Koin to replace `error("not initialized")` singleton accessors
  - String resources / i18n
  - rememberSaveable nav stack for process-death restore
  - onNewIntent override for in-running YouTube URL shares
  - certificate pinning on RYD endpoint
2026-05-23 20:23:34 -07:00
Kayos
01496c647a Straw phase K: subscriptions store + Subscribe button + Home section
New SubscriptionsStore (SharedPrefs-lite, same pattern as History/Settings).
Holds Set<ChannelRef> { url, name, avatar }.

ChannelScreen header now has a "Subscribe / Subscribed" button on the
right. Button toggles membership; UI updates immediately via StateFlow.

StrawHome: new "Subscriptions" section above "Recently watched", a
LazyRow of subscribed channels (avatar + name, 80dp chips). Tap a
subscription chip → opens that channel.

StrawApp.onCreate: Subscriptions.init(this).

Day-4 ideas: auto-aggregate latest videos from subs on Home (no more
"hit search to see videos"), sub-feed-only screen, channel notifications.
2026-05-23 20:02:52 -07:00
Kayos
06e6ec64e3 Straw phase J: tappable uploader → channel browse
New Screen.Channel(channelUrl, name). ChannelViewModel calls
NewPipeExtractor's ChannelInfo.getInfo() + first ChannelTab (Videos) for
the list of streams. ChannelScreen renders banner + circular avatar +
subscriber count + LazyColumn of recent videos.

Wiring:
- SearchViewModel.StreamItem now carries uploaderUrl from
  StreamInfoItem.uploaderUrl.
- VideoDetailViewModel.VideoDetail likewise.
- VideoDetailScreen: uploader name is now a clickable Text in primary
  color when uploaderUrl is non-null. Tap → Screen.Channel.
- StrawActivity routes Screen.Channel to ChannelScreen.

Smoke test: tapping "jawed" on the Me-at-the-zoo detail screen opens the
jawed channel — banner, avatar, 6.1M subscribers, the one video he ever
uploaded (this still cracks me up).

Day-4: tappable uploader in search row, channel tabs (Playlists, Shorts),
subscription toggle wired to a Subscriptions store.
2026-05-23 19:58:37 -07:00
Kayos
6f5e1ed199 Straw phase I: SB segment count chip + clear-history buttons
Detail screen: VideoDetailViewModel now also fetches SponsorBlock segment
count for the user's currently-enabled categories alongside RYD. When >0,
detail screen shows a "⏭ N skip(s)" AssistChip next to the like/dislike
chips. Lets the user see at-a-glance whether SB is going to do anything
on this video before tapping Play.

Settings screen: "History" section at the bottom with two OutlinedButtons —
"Clear watch history" and "Clear searches". Each calls the corresponding
HistoryStore.clear* method. List updates immediately via the StateFlow.

Empty-category set on SB now means "skip the API call" (was already
checking this in PlayerViewModel.resolve, now also in VideoDetailViewModel).
2026-05-23 19:54:37 -07:00
Kayos
ce3ba9afa2 Straw phase H: Settings screen + SponsorBlock category toggles
New: SettingsStore (SharedPreferences-lite, same pattern as HistoryStore)
exposes a Set<SbCategory> StateFlow.

7 SponsorBlock categories surfaced as toggle rows in a new Settings screen:
sponsor (on by default), selfpromo, intro, outro, interaction (reminders),
music_offtopic (talking in music videos), filler.

Wiring:
- StrawApp.onCreate: Settings.init(this)
- StrawHome: new Settings gear icon next to "straw v0.1.0" header. Tap
  routes to Screen.Settings.
- PlayerViewModel.resolve: reads Settings.get().sbCategories on resolve.
  Empty set = SponsorBlock skip disabled (no API call).

Material-icons-core dep added (1.7.5) for the Icons.Filled.Settings glyph.

Day-4 ideas: theme override, default audio-only playback, preferred quality,
clear history buttons.
2026-05-23 19:51:43 -07:00
Kayos
b3a0972909 Straw phase G: recent watches + search history (SharedPreferences-lite)
New: HistoryStore — JSON-encoded SharedPreferences for two lists. Watches
keyed by videoId (max 50, FIFO), searches deduped case-insensitively (max
20). Surfaced as StateFlow so screens recompose live.

Wiring:
- StrawApp.onCreate: History.init(this)
- VideoDetailViewModel.load: recordWatch after StreamInfo resolves
- SearchViewModel.submit: recordSearch on each query

UI:
- StrawHome: redesigned. Tight inline header, full-width Search button,
  "Recently watched" LazyColumn below. Tap a recent row → VideoDetail.
- SearchScreen: when query is blank, show recent searches as
  AssistChip row. Tap a chip → onQueryChange + submit (instant search).

Day-4 graduates to Room when there's a real query pattern that SP can't
serve (date ranges, full-text search). For now the JSON-blob approach
ships in 30 minutes vs an hour of Room+KSP plumbing.
2026-05-23 19:47:29 -07:00
Kayos
f3b78b4530 Straw phase F: visible polish — RYD, HTML, intent filter, network sec
Four polish items, all visible:
1. Fixed RYD URL: was returnyoutubedislike.com (the website, 404s on /votes)
   → returnyoutubedislikeapi.com (the actual API).
2. Bundled Sectigo "Public Server Authentication CA DV R36" intermediate
   as an additional trust anchor (network_security_config.xml) for the
   .com web host — the API uses Google Trust Services already so this
   is defensive, in case we ever fetch the landing page.
3. Added intent-filter for YouTube URLs (VIEW + SEND) on StrawActivity.
   Single-task launchMode; pickYouTubeUrl() routes the initial Intent
   to Screen.VideoDetail(url) instead of Home.
4. stripHtml() utility removes <br>, </p>, and other tags from
   NewPipeExtractor's description. Chapter timestamps now render
   readably; raw HTML gone.

Also added Log.d to SponsorBlockClient and RydClient for visible
verification (StrawSb / StrawRyd tags). PlayerScreen now shows a
"SB: N segments" overlay chip in the top-left so the user can see
that SponsorBlock is armed.

Verified on Android 14 emulator with "Me at the zoo" intent:
- RYD: 👍 18.9M / 👎 424.2K renders
- Intent: direct URL → VideoDetail (no Home pass-through)
- HTML: chapter timestamps render clean
2026-05-23 19:40:08 -07:00
Kayos
496ed30bda Sulkta day-2: search → detail → player → SponsorBlock + RYD
Phase A: NewPipeExtractor + OkHttp Downloader wired in. Search bar +
LazyColumn results. Tap = navigate to detail.

Phase B: VideoDetail screen — StreamInfo metadata + Return YouTube
Dislike chips + description.

Phase C: Media3 ExoPlayer in Compose. Resolves StreamInfo to best
playable: DASH MPD → HLS → combined progressive → merged
videoOnly+audio.

Phase D: SponsorBlock SHA-256 prefix lookup. 250ms position-poll loop
inside PlayerScreen — exoPlayer.seekTo(segment.end) when entering
a sponsor segment. Toast on skip.

Phase E: Verified live on Android 14 emulator. linus tech tips search
returns real results with thumbnails; tapped result opens detail;
hit Play → video plays through ExoPlayer.

Architecture: everything in :strawApp for now (not pushed into :shared
yet — KMP refactor is day-3). Pure-state nav (sealed Screen + stack,
no nav library).

Known polish gaps (day-3): RYD chips render empty on some videos,
description has raw HTML (markdown render needed), no Koin DI yet,
no persistence.

GPL-3.0-or-later per upstream NewPipe.
2026-05-23 19:22:52 -07:00
Kayos
ff4dc6f121 Sulkta day-1: straw — KMP/Compose YouTube client fork
Initial Sulkta fork of NewPipe with a new :strawApp module that ships a
clean Compose-based Android APK at applicationId com.sulkta.straw.

What's here:
- :strawApp — thin Android application shell, MaterialTheme + StrawHome
  Composable. Lives alongside legacy :app so we don't break upstream.
- buildSrc — STRAW_APPLICATION_ID/VERSION constants alongside the existing
  NEWPIPE_APPLICATION_ID_OLD/NEW.
- docs/sulkta — RECON.md (NewPipe codebase breakdown) + DECISIONS.md
  (stack + scope decisions).

NewPipe's :shared KMP scaffold is at 892 LOC and renders nothing; this
fork picks up there and races ahead. Day-1 ships a hello APK; day-2 wires
NewPipeExtractor + Media3 player + SponsorBlock + Return YouTube Dislike.

GPL-3.0-or-later per upstream.
2026-05-23 17:37:55 -07:00
Hosted Weblate
94005cfe9c
Translated using Weblate (Dutch)
Currently translated at 55.4% (51 of 92 strings)

Translated using Weblate (Latvian)

Currently translated at 97.8% (759 of 776 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Latvian)

Currently translated at 97.8% (759 of 776 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 66.3% (61 of 92 strings)

Translated using Weblate (Belarusian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 65.2% (60 of 92 strings)

Translated using Weblate (Slovak)

Currently translated at 77.1% (71 of 92 strings)

Translated using Weblate (Croatian)

Currently translated at 99.8% (775 of 776 strings)

Translated using Weblate (Serbian)

Currently translated at 99.2% (770 of 776 strings)

Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Milan <mobrcian@hotmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nero <guihsalmeida0210@hotmail.com>
Co-authored-by: Peter Dave Hello <hsu@peterdavehello.org>
Co-authored-by: Yauhen <bugomol@users.noreply.hosted.weblate.org>
Co-authored-by: ojppe <ojppe@users.noreply.hosted.weblate.org>
Co-authored-by: Саша Петровић <salepetronije@gmail.com>
Co-authored-by: ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) <coool@mail.lv>
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/nl/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/pt_BR/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/sk/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/zh_Hant/
Translation: NewPipe/Metadata
2026-05-23 20:15:02 +00:00
tobigr
d3d6b0283f Merge branch 'master' into dev 2026-05-23 20:18:19 +02:00
tobigr
45af64a518 Release NewPipe 0.28.7 (1012) 2026-05-23 19:34:09 +02:00
tobigr
28654471d5 Add changelog for NewPipe 0.28.7 (1012) 2026-05-23 19:34:09 +02:00
tobigr
82e3e71849 Update NewPipe Extractor to v0.26.2 2026-05-23 19:29:38 +02:00
Ida Delphine
d4698f9d8e
Merge pull request #13525 from theimpulson/cmp
shared: Add top app bar composable to reflect different active services
2026-05-23 09:22:51 +01:00
Aayush Gupta
01e3742521 shared: Add missing settings implementation
This seems to have gotten missed during moving settings to different modules

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-23 16:14:52 +08:00
Aayush Gupta
0f2bbf11ff shared: Add top app bar composable to reflect different active services
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-23 16:14:48 +08:00
Tobi
aa48a76486
Merge pull request #13524 from TeamNewPipe/proguard
proguard-rules: Keep resource classes for prettytime
2026-05-23 00:37:33 +02:00
Aayush Gupta
abf97404a0 proguard-rules: Keep resource classes for prettytime
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-22 20:21:55 +08:00
Aayush Gupta
dfc3f4b9f3
Merge pull request #13507 from theimpulson/cmp
Introduce compose multiplatform
2026-05-21 16:06:44 +08:00
Aayush Gupta
d1bc8c23cf Better share version information between modules
Move important version properties to buildSrc directory to access between modules
as needed.

Also add a simple task to generate a simple BuildConfig class to access version name.
This is better than adding dependency on a third-party library/plugin.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-20 18:27:08 +08:00
Aayush Gupta
53f36154aa Switch to new syntax for declaring SDK versions
Current ones are planned to be deprecated in AGP 10.x

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-19 12:27:42 +08:00
Aayush Gupta
89d55ede72 Initial setup for navigation display with nav3
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-19 12:27:29 +08:00
Aayush Gupta
909bd347a7 Setup multiplatform settings with KMP and theme
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-19 12:24:35 +08:00
Aayush Gupta
cc74ac8ce8 Initial support for compose multiplatform
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-19 12:22:31 +08:00
TobiGr
ef85e567fb Update NewPIpe Extractor to the latest version 2026-05-16 09:20:30 +02:00
Hosted Weblate
238124c7be
Translated using Weblate (Russian)
Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Croatian)

Currently translated at 99.7% (774 of 776 strings)

Translated using Weblate (Spanish)

Currently translated at 72.8% (67 of 92 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Romanian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Portuguese (Portugal))

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Azerbaijani)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Portuguese)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Slovak)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Italian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Latvian)

Currently translated at 97.1% (754 of 776 strings)

Translated using Weblate (Korean)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Greek)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (Czech)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (French)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Portuguese (Brazil))

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (French)

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (Estonian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Persian)

Currently translated at 98.8% (767 of 776 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (German)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Hungarian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Chinese (Simplified Han script))

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (German)

Currently translated at 100.0% (92 of 92 strings)

Translated using Weblate (Bulgarian)

Currently translated at 100.0% (776 of 776 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 63.7% (58 of 91 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 83.5% (76 of 91 strings)

Translated using Weblate (Spanish)

Currently translated at 72.5% (66 of 91 strings)

Translated using Weblate (English (United Kingdom))

Currently translated at 100.0% (773 of 773 strings)

Translated using Weblate (Polish)

Currently translated at 100.0% (773 of 773 strings)

Translated using Weblate (Chinese (Traditional Han script))

Currently translated at 100.0% (773 of 773 strings)

Co-authored-by: 439JBYL80IGQTF25UXNR0X1BG <439jbyl80igqtf25uxnr0x1bg@users.noreply.hosted.weblate.org>
Co-authored-by: Agnieszka C <aga_04@o2.pl>
Co-authored-by: Danial Behzadi <dani.behzi@ubuntu.com>
Co-authored-by: Edward <edwardchirita@mailbox.org>
Co-authored-by: Emin Tufan Çetin <etcetin@gmail.com>
Co-authored-by: Femini <nizamismidov4@gmail.com>
Co-authored-by: Fjuro <fjuro@users.noreply.hosted.weblate.org>
Co-authored-by: Ghost of Sparta <makesocialfoss32@keemail.me>
Co-authored-by: Hosted Weblate <hosted@weblate.org>
Co-authored-by: Michalis <michalisntovas@yahoo.gr>
Co-authored-by: Mickaël Binos <mickaelbinos@outlook.com>
Co-authored-by: Milan <mobrcian@hotmail.com>
Co-authored-by: Milo Ivir <mail@milotype.de>
Co-authored-by: Nicolás Pérez <nicoperez241@proton.me>
Co-authored-by: Olly <pifahif961@cadinr.com>
Co-authored-by: Philip Goto <philip.goto@gmail.com>
Co-authored-by: Priit Jõerüüt <jrthwlate@users.noreply.hosted.weblate.org>
Co-authored-by: Random <random-r@users.noreply.hosted.weblate.org>
Co-authored-by: Trunars <trunars@abv.bg>
Co-authored-by: UDP <udp@users.noreply.hosted.weblate.org>
Co-authored-by: VfBFan <vfbfan@users.noreply.hosted.weblate.org>
Co-authored-by: delvani <del.cidrak@users.noreply.hosted.weblate.org>
Co-authored-by: justcontributor <kty5663@gmail.com>
Co-authored-by: ssantos <ssantos@web.de>
Co-authored-by: ℂ𝕠𝕠𝕠𝕝 (𝕘𝕚𝕥𝕙𝕦𝕓.𝕔𝕠𝕞/ℂ𝕠𝕠𝕠𝕝) <coool@mail.lv>
Co-authored-by: 大王叫我来巡山 <hamburger2048@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/cs/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/de/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/en_GB/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/es/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/fr/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/zh_Hans/
Translate-URL: https://hosted.weblate.org/projects/newpipe/metadata/zh_Hant/
Translation: NewPipe/Metadata
2026-05-16 06:41:13 +00:00
Tobi
6f3f4219dc
Merge pull request #13504 from laiosg/repeatmode-ui-fix
Fix repeat mode UI out-of-sync when switching videos
2026-05-16 08:41:01 +02:00
TobiGr
9dd0f1984f Replace if-else with switch 2026-05-16 08:35:29 +02:00
Tobi
b6a2167516
Merge pull request #13505 from theimpulson/depUpdate
Update dependencies and plugins to latest releases
2026-05-16 08:22:05 +02:00
Aayush Gupta
c2ead904fe Update libs to latest stable releases
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-16 12:36:21 +08:00
Aayush Gupta
6419b6bac7 Update Gradle and wrapper to 9.5.1
Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-16 12:34:57 +08:00
Aayush Gupta
6cd63dc0c5 Upgrade AGP to 9.2.0
Building release builds is still broken on encrypted linux file systems but that's seems
to be not a priority for Google to fix. Upgrade so that developers can avoid suffering from
bugs such as preview rendering failure.

Signed-off-by: Aayush Gupta <aayushgupta219@gmail.com>
2026-05-16 12:25:24 +08:00
George Laios
18d54b6225 Fix repeat mode UI out-of-sync when switching videos 2026-05-16 05:46:36 +03:00
Tobi
cd171dab54
Merge pull request #13454 from TeamNewPipe/depUpdate
Update dependencies and build with JDK 21
2026-05-03 09:09:39 +02:00
tobigr
07b4fa7b35 Merge branch 'master' into dev 2026-05-01 23:59:24 +02:00
Stypox
6c65949f5b
Merge pull request #13462 from Stypox/release-0.28.6 2026-05-01 16:07:45 +02:00
Stypox
d4941c4424
Release v0.28.6 (1011) 2026-05-01 14:34:35 +02:00
Stypox
9373a6c40d
Add changelog for v0.28.6 (1011) 2026-05-01 14:33:51 +02:00
Stypox
6e3b858f42
Merge pull request #13458 from Stypox/minsdk-23-popup 2026-05-01 14:29:44 +02:00
Stypox
6d52522523
Add popup for NewPipe dropping support for Android 5 2026-05-01 12:05:04 +02:00
Stypox
9360d2f61c
Cleanup KeepAndroidOpen dialog code 2026-04-29 14:49:31 +02:00
Tobi
56982455f6
Merge pull request #13455 from TeamNewPipe/weblate
Translation updates via weblate
2026-04-26 11:20:02 +02:00