Aggiunge replay YouTube temporaneo, pull registrazioni dai CPX e snapshot ingest in admin.
Così overflow Hetzner e VOD YouTube restano in archivio dopo lo spegnimento del nodo, e la colonna ingest non si svuota. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
+9
-5
@@ -43,7 +43,11 @@ class E2ECoverUploadTest {
|
||||
openMatchWizardViaQuickStart()
|
||||
|
||||
waitForText(s(R.string.wizard_step_title_match), timeoutMs = 45_000)
|
||||
scrollUntilVisible(s(R.string.wizard_match_cover_title))
|
||||
scrollUntilVisible(
|
||||
s(R.string.wizard_match_cover_title),
|
||||
"Copertina in pausa",
|
||||
"Pause cover",
|
||||
)
|
||||
|
||||
tapClickableText(s(R.string.wizard_match_cover_change))
|
||||
pickFirstPhotoFromPicker()
|
||||
@@ -185,12 +189,12 @@ class E2ECoverUploadTest {
|
||||
}
|
||||
}
|
||||
|
||||
private fun scrollUntilVisible(text: String) {
|
||||
repeat(8) {
|
||||
if (device.hasObject(By.text(text))) return
|
||||
private fun scrollUntilVisible(vararg texts: String) {
|
||||
repeat(20) {
|
||||
if (texts.any { device.hasObject(By.text(it)) }) return
|
||||
scrollDown(1)
|
||||
}
|
||||
waitForText(text, timeoutMs = 10_000)
|
||||
waitForAnyText(*texts, timeoutMs = 10_000)
|
||||
}
|
||||
|
||||
private fun grantRuntimePermissions() {
|
||||
|
||||
+4
-1
@@ -27,7 +27,10 @@ data class ChangePasswordRequest(
|
||||
|
||||
data class MessageResponse(val message: String)
|
||||
|
||||
data class ApiErrorResponse(val error: String? = null)
|
||||
data class ApiErrorResponse(
|
||||
val error: String? = null,
|
||||
@Json(name = "error_code") val errorCode: String? = null,
|
||||
)
|
||||
|
||||
data class LoginResponse(
|
||||
val user: UserDto,
|
||||
|
||||
+41
-9
@@ -2,31 +2,63 @@ package com.matchlivetv.match_live_tv.data.repository
|
||||
|
||||
import android.content.Context
|
||||
import com.matchlivetv.match_live_tv.core.DeviceTelemetry
|
||||
import com.matchlivetv.match_live_tv.data.api.ApiErrorResponse
|
||||
import com.matchlivetv.match_live_tv.data.api.CreateSessionRequest
|
||||
import com.matchlivetv.match_live_tv.data.api.MatchLiveApi
|
||||
import com.matchlivetv.match_live_tv.data.api.MinQualityRequest
|
||||
import com.matchlivetv.match_live_tv.data.api.NetworkTestRequest
|
||||
import com.matchlivetv.match_live_tv.data.api.NetworkTestResponse
|
||||
import com.matchlivetv.match_live_tv.domain.StreamSession
|
||||
import com.squareup.moshi.Moshi
|
||||
import com.squareup.moshi.kotlin.reflect.KotlinJsonAdapterFactory
|
||||
import kotlinx.coroutines.delay
|
||||
import retrofit2.HttpException
|
||||
|
||||
class SessionRepository(
|
||||
private val api: MatchLiveApi,
|
||||
private val appContext: Context,
|
||||
) {
|
||||
private val errorAdapter by lazy {
|
||||
Moshi.Builder()
|
||||
.add(KotlinJsonAdapterFactory())
|
||||
.build()
|
||||
.adapter(ApiErrorResponse::class.java)
|
||||
}
|
||||
|
||||
suspend fun createSession(
|
||||
matchId: String,
|
||||
platform: String = "matchlivetv",
|
||||
privacyStatus: String = "public",
|
||||
youtubeChannel: String? = null,
|
||||
): StreamSession = api.createSession(
|
||||
matchId,
|
||||
CreateSessionRequest(
|
||||
platform = platform,
|
||||
privacyStatus = privacyStatus,
|
||||
youtubeChannel = youtubeChannel,
|
||||
client = DeviceTelemetry.clientInfo(appContext),
|
||||
),
|
||||
).toDomain()
|
||||
scalingRetries: Int = 8,
|
||||
scalingRetryDelayMs: Long = 15_000L,
|
||||
): StreamSession {
|
||||
var attempt = 0
|
||||
while (true) {
|
||||
try {
|
||||
return api.createSession(
|
||||
matchId,
|
||||
CreateSessionRequest(
|
||||
platform = platform,
|
||||
privacyStatus = privacyStatus,
|
||||
youtubeChannel = youtubeChannel,
|
||||
client = DeviceTelemetry.clientInfo(appContext),
|
||||
),
|
||||
).toDomain()
|
||||
} catch (e: HttpException) {
|
||||
val code = parseErrorCode(e)
|
||||
if (code != "stream_capacity_scaling" || attempt >= scalingRetries) throw e
|
||||
attempt += 1
|
||||
delay(scalingRetryDelayMs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseErrorCode(error: HttpException): String? {
|
||||
val body = error.response()?.errorBody()?.string().orEmpty()
|
||||
if (body.isBlank()) return null
|
||||
return runCatching { errorAdapter.fromJson(body)?.errorCode }.getOrNull()
|
||||
}
|
||||
|
||||
suspend fun fetchSession(sessionId: String): StreamSession =
|
||||
api.session(sessionId).toDomain()
|
||||
|
||||
Reference in New Issue
Block a user