From 810518579576087e864bc5a9222b2dddac7bf43d Mon Sep 17 00:00:00 2001 From: silentbil Date: Fri, 12 Jun 2026 22:06:15 +0300 Subject: [PATCH 1/3] Fix verify build workflow to run on all PRs including forks --- .github/workflows/build-check.yml | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index d4e3ea46f..9148031f1 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -1,12 +1,13 @@ name: Build Check on: - pull_request: + pull_request_target: branches: - main + types: [opened, synchronize, reopened] concurrency: - group: build-check-${{ github.ref }} + group: build-check-${{ github.event.pull_request.number }} cancel-in-progress: true jobs: @@ -15,8 +16,10 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout + - name: Checkout PR code uses: actions/checkout@v4 + with: + ref: ${{ github.event.pull_request.head.sha }} - name: Set up Java uses: actions/setup-java@v4 From 00af4b4363e2c9c7b18f98cba5410c6399c2ec81 Mon Sep 17 00:00:00 2001 From: silentbil Date: Sat, 13 Jun 2026 21:07:55 +0300 Subject: [PATCH 2/3] better search for telegram based on user lang --- .../tv/data/telegram/TelegramSearchMatcher.kt | 64 ++++++++++++------- .../data/telegram/TelegramSourceResolver.kt | 37 +++++++---- 2 files changed, 67 insertions(+), 34 deletions(-) diff --git a/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSearchMatcher.kt b/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSearchMatcher.kt index 0aec67910..5867358c8 100644 --- a/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSearchMatcher.kt +++ b/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSearchMatcher.kt @@ -27,7 +27,7 @@ class TelegramSearchMatcher @Inject constructor() { fileName: String, caption: String, title: String, - hebrewTitle: String? = null, + localizedTitle: String? = null, englishTitle: String? = null, year: Int?, season: Int?, @@ -36,15 +36,15 @@ class TelegramSearchMatcher @Inject constructor() { val combined = "$fileName $caption" val normalizedCombined = normalize(combined) val normalizedTitle = normalize(title) - val normalizedHebrew = hebrewTitle?.let { normalize(it) } + val normalizedLocalized = localizedTitle?.let { normalize(it) } val normalizedEnglish = englishTitle?.let { normalize(it) } - // Primary match: TMDB English title, TMDB Hebrew title, or app title (in that priority) + // Primary match: TMDB English title, TMDB localized title, or app title (in that priority) val engMatch = normalizedEnglish != null && normalizedEnglish.isNotBlank() && normalizedCombined.contains(normalizedEnglish) - val hebMatch = normalizedHebrew != null && normalizedHebrew.isNotBlank() && normalizedCombined.contains(normalizedHebrew) + val locMatch = normalizedLocalized != null && normalizedLocalized.isNotBlank() && normalizedCombined.contains(normalizedLocalized) val appMatch = normalizedCombined.contains(normalizedTitle) - if (!engMatch && !hebMatch && !appMatch) return 0 + if (!engMatch && !locMatch && !appMatch) return 0 var score = 60 @@ -101,25 +101,31 @@ class TelegramSearchMatcher @Inject constructor() { return m.groupValues[1].toIntOrNull() } - fun buildMovieQueries(title: String, year: Int?, hebrewTitle: String? = null, englishTitle: String? = null): List { + fun buildMovieQueries(title: String, year: Int?, localizedTitle: String? = null, englishTitle: String? = null): List { // Prefer TMDB English title as primary; fall back to app title val primary = englishTitle?.let { cleanTitle(it) } ?: cleanTitle(title) - val hebrew = hebrewTitle?.let { cleanTitle(it) } + val localized = localizedTitle?.let { cleanTitle(it) } val queries = mutableListOf() if (year != null) queries.add("$primary $year") queries.add(primary) - if (hebrew != null && !hebrew.equals(primary, ignoreCase = true)) { - if (year != null) queries.add("$hebrew $year") - queries.add(hebrew) + if (localized != null && !localized.equals(primary, ignoreCase = true)) { + if (year != null) queries.add("$localized $year") + queries.add(localized) } return queries.distinct() } - fun buildSeriesQueries(title: String, season: Int, episode: Int, hebrewTitle: String? = null, englishTitle: String? = null): List { - // Prefer TMDB English as primary for English patterns; TMDB Hebrew for Hebrew patterns + fun buildSeriesQueries( + title: String, + season: Int, + episode: Int, + localizedTitle: String? = null, + englishTitle: String? = null, + languageCode: String = "en" + ): List { val engBase = englishTitle?.let { cleanTitle(it) } ?: cleanTitle(title) - val hebBase = hebrewTitle?.let { cleanTitle(it) } - val titlesAreSame = hebBase == null || hebBase.equals(engBase, ignoreCase = true) + val locBase = localizedTitle?.let { cleanTitle(it) } + val titlesAreSame = locBase == null || locBase.equals(engBase, ignoreCase = true) val s = season.toString() val e = episode.toString() val s2 = season.toString().padStart(2, '0') @@ -127,16 +133,28 @@ class TelegramSearchMatcher @Inject constructor() { val queries = mutableListOf() - // Hebrew patterns with Hebrew title (or engBase if same) - val hebTitle = if (titlesAreSame) engBase else hebBase!! - queries += listOf( - "$hebTitle ע$s פ$e", - "$hebTitle ע${s}פ${e}", - "$hebTitle עונה $s פרק $e", - ) - if (season == 1) queries += listOf("$hebTitle פ$e", "$hebTitle פרק $e") + // Hebrew-specific episode markers — only for Hebrew users + if (languageCode == "he") { + val hebTitle = if (titlesAreSame) engBase else locBase ?: engBase + queries += listOf( + "$hebTitle ע$s פ$e", + "$hebTitle ע${s}פ${e}", + "$hebTitle עונה $s פרק $e", + ) + if (season == 1) queries += listOf("$hebTitle פ$e", "$hebTitle פרק $e") + } + + // Localized title with English S/E patterns (any non-English language) + if (!titlesAreSame) { + queries += listOf( + "$locBase s${s}e${e}", + "$locBase s${s2}e${e2}", + "$locBase s$s e$e", + "$locBase s$s2 e$e2", + ) + } - // English patterns with English title + // English patterns queries += listOf( "$engBase s${s}e${e}", "$engBase s${s2}e${e2}", diff --git a/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSourceResolver.kt b/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSourceResolver.kt index 95e4658f0..c05e1902e 100644 --- a/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSourceResolver.kt +++ b/app/src/main/kotlin/com/arflix/tv/data/telegram/TelegramSourceResolver.kt @@ -92,12 +92,17 @@ class TelegramSourceResolver @Inject constructor( isMovie: Boolean ): List { val excludedIds = repository.getExcludedChatIds().first() - val (englishTitle, hebrewTitle) = fetchTitles(imdbId, isMovie) + // Read content language from SharedPreferences (same store SettingsViewModel writes to). + // Avoids a DI cycle: StreamRepository → TelegramSourceResolver → MediaRepository → StreamRepository. + val rawLang = context.getSharedPreferences("app_locale", android.content.Context.MODE_PRIVATE) + .getString("locale_tag", "en-US") ?: "en-US" + val langCode = rawLang.replace("iw", "he").substringBefore("-") + val (englishTitle, localizedTitle) = fetchTitles(imdbId, isMovie, langCode) val queries = if (season != null && episode != null) - matcher.buildSeriesQueries(title, season, episode, hebrewTitle, englishTitle) + matcher.buildSeriesQueries(title, season, episode, localizedTitle, englishTitle, langCode) else - matcher.buildMovieQueries(title, year, hebrewTitle, englishTitle) + matcher.buildMovieQueries(title, year, localizedTitle, englishTitle) val seen = mutableSetOf>() val allMessages = mutableListOf() @@ -128,7 +133,7 @@ class TelegramSourceResolver @Inject constructor( fileName = msg.fileName, caption = msg.caption, title = title, - hebrewTitle = hebrewTitle, + localizedTitle = localizedTitle, englishTitle = englishTitle, year = year, season = season, @@ -163,7 +168,7 @@ class TelegramSourceResolver @Inject constructor( ) } .sortedWith( - compareByDescending { matcher.isHebrew(it.source) } + compareByDescending { langCode == "he" && matcher.isHebrew(it.source) } .thenByDescending { qualityTier(it.quality) } .thenByDescending { it.sizeBytes ?: 0L } ) @@ -195,21 +200,31 @@ class TelegramSourceResolver @Inject constructor( else -> 0 } - private suspend fun fetchTitles(imdbId: String, isMovie: Boolean): Pair { + private suspend fun fetchTitles(imdbId: String, isMovie: Boolean, langCode: String): Pair { if (imdbId.isBlank()) return null to null return try { val findResult = tmdbApi.findByExternalId(imdbId, Constants.TMDB_API_KEY) val findItem = if (isMovie) findResult.movieResults.firstOrNull() else findResult.tvResults.firstOrNull() val tmdbId = findItem?.id ?: return null to null - val englishTitle = (if (isMovie) findItem.title else findItem.name).takeIf { it.isNotBlank() } - val hebrewTitle = if (isMovie) - tmdbApi.getMovieDetails(tmdbId, Constants.TMDB_API_KEY, language = "he").title + // Always fetch English explicitly — the HTTP interceptor may inject the user's + // content language into all TMDB calls, so findItem.title isn't always English. + val englishTitle = if (isMovie) + tmdbApi.getMovieDetails(tmdbId, Constants.TMDB_API_KEY, language = "en").title .takeIf { it.isNotBlank() } else - tmdbApi.getTvDetails(tmdbId, Constants.TMDB_API_KEY, language = "he").name + tmdbApi.getTvDetails(tmdbId, Constants.TMDB_API_KEY, language = "en").name .takeIf { it.isNotBlank() } - englishTitle to hebrewTitle + // Fetch localized title only when the user's language is not English + val localizedTitle = if (langCode != "en") { + if (isMovie) + tmdbApi.getMovieDetails(tmdbId, Constants.TMDB_API_KEY, language = langCode).title + .takeIf { it.isNotBlank() } + else + tmdbApi.getTvDetails(tmdbId, Constants.TMDB_API_KEY, language = langCode).name + .takeIf { it.isNotBlank() } + } else null + englishTitle to localizedTitle } catch (e: Exception) { Log.w(TAG, "Failed to fetch titles for $imdbId: ${e.message}") null to null From 2621478915adaca58474659ecd6e741ac140bb58 Mon Sep 17 00:00:00 2001 From: silentbil Date: Sat, 13 Jun 2026 21:11:13 +0300 Subject: [PATCH 3/3] better search for telegram based on user lang --- .github/workflows/build-check.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-check.yml b/.github/workflows/build-check.yml index 9148031f1..d4e3ea46f 100644 --- a/.github/workflows/build-check.yml +++ b/.github/workflows/build-check.yml @@ -1,13 +1,12 @@ name: Build Check on: - pull_request_target: + pull_request: branches: - main - types: [opened, synchronize, reopened] concurrency: - group: build-check-${{ github.event.pull_request.number }} + group: build-check-${{ github.ref }} cancel-in-progress: true jobs: @@ -16,10 +15,8 @@ jobs: runs-on: ubuntu-latest steps: - - name: Checkout PR code + - name: Checkout uses: actions/checkout@v4 - with: - ref: ${{ github.event.pull_request.head.sha }} - name: Set up Java uses: actions/setup-java@v4