Save and display API limits

This commit is contained in:
Nicolas Pomepuy 2024-11-04 08:58:41 +01:00 committed by Duncan McNamara
parent c263543970
commit c49b081984
9 changed files with 160 additions and 30 deletions

View File

@ -1,7 +1,7 @@
package org.videolan.resources.opensubtitles package org.videolan.resources.opensubtitles
import com.squareup.moshi.Json import com.squareup.moshi.Json
import com.squareup.moshi.JsonClass import java.util.Date
data class OpenSubV1( data class OpenSubV1(
@field:Json(name = "data") @field:Json(name = "data")
@ -156,7 +156,7 @@ data class DownloadLink(
@field:Json(name = "reset_time") @field:Json(name = "reset_time")
val resetTime: String, val resetTime: String,
@field:Json(name = "reset_time_utc") @field:Json(name = "reset_time_utc")
val resetTimeUtc: String val resetTimeUtc: Date
) )
data class OpenSubtitleAccount( data class OpenSubtitleAccount(

View File

@ -3,6 +3,8 @@ package org.videolan.resources.opensubtitles
import android.util.Log import android.util.Log
import com.moczul.ok2curl.CurlInterceptor import com.moczul.ok2curl.CurlInterceptor
import com.moczul.ok2curl.logger.Logger import com.moczul.ok2curl.logger.Logger
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
import okhttp3.Interceptor import okhttp3.Interceptor
import okhttp3.OkHttpClient import okhttp3.OkHttpClient
import okhttp3.Request import okhttp3.Request
@ -13,6 +15,7 @@ import org.videolan.resources.BuildConfig
import org.videolan.resources.util.ConnectivityInterceptor import org.videolan.resources.util.ConnectivityInterceptor
import retrofit2.Retrofit import retrofit2.Retrofit
import retrofit2.converter.moshi.MoshiConverterFactory import retrofit2.converter.moshi.MoshiConverterFactory
import java.util.Date
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -35,7 +38,11 @@ private fun buildClient() = Retrofit.Builder()
.readTimeout(10, TimeUnit.SECONDS) .readTimeout(10, TimeUnit.SECONDS)
.connectTimeout(5, TimeUnit.SECONDS) .connectTimeout(5, TimeUnit.SECONDS)
.build()) .build())
.addConverterFactory(MoshiConverterFactory.create()) .addConverterFactory(MoshiConverterFactory.create(
Moshi.Builder()
.add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe())
.build()
))
.build() .build()
.create(IOpenSubtitleService::class.java) .create(IOpenSubtitleService::class.java)

View File

@ -0,0 +1,42 @@
/*
* ************************************************************************
* OpenSubtitlesLimit.kt
* *************************************************************************
* Copyright © 2024 VLC authors and VideoLAN
* Author: Nicolas POMEPUY
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* **************************************************************************
*
*
*/
package main.java.org.videolan.resources.opensubtitles
import java.util.Date
data class OpenSubtitlesLimit (
val requests: Int = 0,
val max: Int = 5,
val resetTime: Date? = null
) {
private fun getRemaining(): Int {
if (resetTime != null && Date().after(resetTime)) return max
return max - requests
}
fun getRemainingText(): String {
val remaining = getRemaining()
return "$remaining/$max"
}
}

View File

@ -39,26 +39,4 @@ data class OpenSubtitlesUser(
val errorMessage: String? = null val errorMessage: String? = null
) { ) {
fun isVip() = account?.user?.vip ?: false fun isVip() = account?.user?.vip ?: false
}
object OpenSubtitlesUserUtil {
fun get(settings: SharedPreferences): OpenSubtitlesUser {
settings.getString(KEY_OPEN_SUBTITLES_USER, "")?.let { userString ->
val moshi = Moshi.Builder().build()
val type = Types.newParameterizedType(OpenSubtitlesUser::class.java)
val jsonAdapter: JsonAdapter<OpenSubtitlesUser> = moshi.adapter(type)
return try {
jsonAdapter.fromJson(userString) ?: OpenSubtitlesUser()
} catch (e: Exception) {
OpenSubtitlesUser()
}
}
return OpenSubtitlesUser()
}
fun save(settings: SharedPreferences, user: OpenSubtitlesUser) {
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(OpenSubtitlesUser::class.java)
settings.putSingle(KEY_OPEN_SUBTITLES_USER, jsonAdapter.toJson(user))
}
} }

View File

@ -0,0 +1,83 @@
/*
* ************************************************************************
* OpenSubtitlesUtils.kt
* *************************************************************************
* Copyright © 2024 VLC authors and VideoLAN
* Author: Nicolas POMEPUY
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
* **************************************************************************
*
*
*/
package main.java.org.videolan.resources.opensubtitles
import android.content.SharedPreferences
import com.squareup.moshi.JsonAdapter
import com.squareup.moshi.Moshi
import com.squareup.moshi.adapters.Rfc3339DateJsonAdapter
import org.videolan.tools.KEY_OPEN_SUBTITLES_LIMIT
import org.videolan.tools.KEY_OPEN_SUBTITLES_USER
import org.videolan.tools.putSingle
import java.util.Date
object OpenSubtitlesUtils {
fun getUser(settings: SharedPreferences): OpenSubtitlesUser {
settings.getString(KEY_OPEN_SUBTITLES_USER, "")?.let { userString ->
val jsonAdapter = getUserAdapter()
return try {
jsonAdapter.fromJson(userString) ?: OpenSubtitlesUser()
} catch (e: Exception) {
OpenSubtitlesUser()
}
}
return OpenSubtitlesUser()
}
fun getLimit(settings: SharedPreferences): OpenSubtitlesLimit {
settings.getString(KEY_OPEN_SUBTITLES_LIMIT, "")?.let { limitString ->
val jsonAdapter = getLimitAdapter()
return try {
jsonAdapter.fromJson(limitString) ?: OpenSubtitlesLimit()
} catch (e: Exception) {
OpenSubtitlesLimit()
}
}
return OpenSubtitlesLimit()
}
fun saveUser(settings: SharedPreferences, user: OpenSubtitlesUser) {
val jsonAdapter = getUserAdapter()
settings.putSingle(KEY_OPEN_SUBTITLES_USER, jsonAdapter.toJson(user))
}
private fun getUserAdapter(): JsonAdapter<OpenSubtitlesUser> {
val moshi = Moshi.Builder().build()
val jsonAdapter = moshi.adapter(OpenSubtitlesUser::class.java)
return jsonAdapter
}
fun saveLimit(settings: SharedPreferences, limit: OpenSubtitlesLimit) {
val jsonAdapter = getLimitAdapter()
settings.putSingle(KEY_OPEN_SUBTITLES_LIMIT, jsonAdapter.toJson(limit))
}
private fun getLimitAdapter(): JsonAdapter<OpenSubtitlesLimit> {
val moshi =
Moshi.Builder().add(Date::class.java, Rfc3339DateJsonAdapter().nullSafe()).build()
val jsonAdapter = moshi.adapter(OpenSubtitlesLimit::class.java)
return jsonAdapter
}
}

View File

@ -248,6 +248,7 @@ const val WIDGETS_PREVIEW_PLAYING = "widgets_preview_playing"
//OpenSubtitles //OpenSubtitles
const val KEY_OPEN_SUBTITLES_USER = "open_subtitles_user" const val KEY_OPEN_SUBTITLES_USER = "open_subtitles_user"
const val KEY_OPEN_SUBTITLES_LIMIT = "open_subtitles_limit"
const val KEY_SAFE_MODE_PIN = "safe_mode_pin" const val KEY_SAFE_MODE_PIN = "safe_mode_pin"

View File

@ -49,6 +49,14 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
tools:text="Game of Thrones - S01e01" /> tools:text="Game of Thrones - S01e01" />
<TextView
android:id="@+id/limit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewmodel.observableLimit.get().getRemainingText()}"
app:layout_constraintStart_toStartOf="@+id/movieName"
app:layout_constraintTop_toBottomOf="@+id/movieName" />
<org.videolan.vlc.gui.view.LanguageSelector <org.videolan.vlc.gui.view.LanguageSelector
android:id="@+id/language_list_spinner" android:id="@+id/language_list_spinner"
android:layout_width="wrap_content" android:layout_width="wrap_content"

View File

@ -24,8 +24,9 @@ import kotlinx.coroutines.ObsoleteCoroutinesApi
import kotlinx.coroutines.channels.actor import kotlinx.coroutines.channels.actor
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesLimit
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUser import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUser
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUserUtil import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUtils
import org.videolan.resources.opensubtitles.OpenSubtitleRepository import org.videolan.resources.opensubtitles.OpenSubtitleRepository
import org.videolan.resources.util.parcelable import org.videolan.resources.util.parcelable
import org.videolan.tools.Settings import org.videolan.tools.Settings
@ -71,6 +72,13 @@ class SubtitleDownloaderDialogFragment : VLCBottomSheetDialogFragment() {
withContext(Dispatchers.IO) { withContext(Dispatchers.IO) {
val downloadLink = OpenSubtitleRepository.getInstance() val downloadLink = OpenSubtitleRepository.getInstance()
.getDownloadLink(subtitleEvent.item.fileId) .getDownloadLink(subtitleEvent.item.fileId)
val openSubtitlesLimit = OpenSubtitlesLimit(
downloadLink.requests,
downloadLink.requests + downloadLink.remaining,
downloadLink.resetTimeUtc
)
OpenSubtitlesUtils.saveLimit(settings, openSubtitlesLimit)
viewModel.observableLimit.set(openSubtitlesLimit)
subtitleEvent.item.zipDownloadLink = downloadLink.link subtitleEvent.item.zipDownloadLink = downloadLink.link
subtitleEvent.item.fileName = downloadLink.fileName subtitleEvent.item.fileName = downloadLink.fileName
} }
@ -126,7 +134,7 @@ class SubtitleDownloaderDialogFragment : VLCBottomSheetDialogFragment() {
binding.loginButton.setOnClickListener { binding.loginButton.setOnClickListener {
if (viewModel.observableUser.get()?.logged == true) { if (viewModel.observableUser.get()?.logged == true) {
val user = OpenSubtitlesUser() val user = OpenSubtitlesUser()
OpenSubtitlesUserUtil.save(settings, user) OpenSubtitlesUtils.saveUser(settings, user)
viewModel.observableUser.set(user) viewModel.observableUser.set(user)
}else { }else {
viewModel.login( viewModel.login(
@ -181,7 +189,8 @@ class SubtitleDownloaderDialogFragment : VLCBottomSheetDialogFragment() {
}) })
//todo //todo
viewModel.observableSearchHearingImpaired.set(false) viewModel.observableSearchHearingImpaired.set(false)
viewModel.observableUser.set(OpenSubtitlesUserUtil.get(settings)) viewModel.observableUser.set(OpenSubtitlesUtils.getUser(settings))
viewModel.observableLimit.set(OpenSubtitlesUtils.getLimit(settings))
binding.retryButton.setOnClickListener { binding.retryButton.setOnClickListener {
viewModel.onRefresh() viewModel.onRefresh()

View File

@ -21,8 +21,9 @@ import kotlinx.coroutines.Job
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext import kotlinx.coroutines.withContext
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesLimit
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUser import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUser
import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUserUtil import main.java.org.videolan.resources.opensubtitles.OpenSubtitlesUtils
import org.videolan.resources.opensubtitles.Data import org.videolan.resources.opensubtitles.Data
import org.videolan.resources.opensubtitles.OpenSubV1 import org.videolan.resources.opensubtitles.OpenSubV1
import org.videolan.resources.opensubtitles.OpenSubtitleRepository import org.videolan.resources.opensubtitles.OpenSubtitleRepository
@ -70,6 +71,7 @@ class SubtitlesModel(private val context: Context, private val mediaUri: Uri, pr
val observableSearchLanguage = ObservableField<List<String>>() val observableSearchLanguage = ObservableField<List<String>>()
val observableSearchHearingImpaired = ObservableField<Boolean>() val observableSearchHearingImpaired = ObservableField<Boolean>()
val observableUser = ObservableField<OpenSubtitlesUser>() val observableUser = ObservableField<OpenSubtitlesUser>()
val observableLimit = ObservableField<OpenSubtitlesLimit>()
private var previousSearchLanguage: List<String>? = null private var previousSearchLanguage: List<String>? = null
val manualSearchEnabled = ObservableBoolean(false) val manualSearchEnabled = ObservableBoolean(false)
@ -272,7 +274,7 @@ class SubtitlesModel(private val context: Context, private val mediaUri: Uri, pr
val userResult = call.body() val userResult = call.body()
if (userResult != null) { if (userResult != null) {
val openSubtitlesUser = OpenSubtitlesUser(true, userResult, username = username) val openSubtitlesUser = OpenSubtitlesUser(true, userResult, username = username)
OpenSubtitlesUserUtil.save(settings, openSubtitlesUser) OpenSubtitlesUtils.saveUser(settings, openSubtitlesUser)
observableUser.set(openSubtitlesUser) observableUser.set(openSubtitlesUser)
return@withContext return@withContext
} }