6.5.2 commit
This commit is contained in:
parent
0299b53c8c
commit
c29eb0bf1b
|
@ -31,8 +31,8 @@ android {
|
|||
testApplicationId "ac.mdiq.podcini.tests"
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
versionCode 3020235
|
||||
versionName "6.5.1"
|
||||
versionCode 3020236
|
||||
versionName "6.5.2"
|
||||
|
||||
applicationId "ac.mdiq.podcini.R"
|
||||
def commit = ""
|
||||
|
@ -90,8 +90,8 @@ android {
|
|||
compose true
|
||||
}
|
||||
|
||||
splits {
|
||||
abi {
|
||||
splits {
|
||||
abi {
|
||||
enable true
|
||||
reset()
|
||||
include "arm64-v8a" // Specify the ABI you want to split.
|
||||
|
@ -142,11 +142,11 @@ android {
|
|||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
|
||||
resValue "string", "app_name", "Podcini.R"
|
||||
resValue "string", "provider_authority", "ac.mdiq.podcini.R.provider"
|
||||
// debuggable false
|
||||
vcsInfo.include false
|
||||
minifyEnabled true
|
||||
shrinkResources true
|
||||
signingConfig signingConfigs.releaseConfig
|
||||
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard.cfg"
|
||||
}
|
||||
debug {
|
||||
resValue "string", "app_name", "Podcini.R Debug"
|
||||
|
@ -161,8 +161,8 @@ android {
|
|||
def buildType = variant.buildType.name
|
||||
def versionName = variant.versionName
|
||||
def flavorName = variant.flavorName ?: ""
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI) ?: "universal"
|
||||
outputFileName = "${applicationName}_${flavorName}_${buildType}_${versionName}_${abiName}.apk"
|
||||
def abiName = output.getFilter(com.android.build.OutputFile.ABI) ?: ""
|
||||
outputFileName = "${applicationName}_${buildType}_${flavorName}_${versionName}_${abiName}.apk"
|
||||
}
|
||||
}
|
||||
androidResources {
|
||||
|
|
|
@ -1,17 +1,21 @@
|
|||
-dontobfuscate
|
||||
-renamesourcefileattribute SourceFile
|
||||
-keepattributes SourceFile,LineNumberTable
|
||||
|
||||
#-renamesourcefileattribute SourceFile
|
||||
-keepattributes Exceptions, SourceFile,LineNumberTable
|
||||
-optimizations !code/allocation/variable
|
||||
-optimizationpasses 5
|
||||
|
||||
## Rules for VistaGuide
|
||||
# -keepclassmembers class ac.mdiq.vista** {*;}
|
||||
-keep class ac.mdiq.vista.extractor.timeago.patterns.** { *; }
|
||||
-keep class org.mozilla.javascript.** { *; }
|
||||
-keep class org.mozilla.classfile.ClassFileWriter
|
||||
-keep class java.beans.**
|
||||
-dontwarn org.mozilla.javascript.tools.**
|
||||
-keep class java.beans.**
|
||||
-dontwarn java.beans.**
|
||||
|
||||
-keep class ac.mdiq.vista.settings.notifications.** { *; }
|
||||
|
||||
-allowaccessmodification
|
||||
-dontskipnonpubliclibraryclassmembers
|
||||
|
||||
|
@ -19,8 +23,6 @@
|
|||
# Without this, methods only used in tests are removed and break tests.
|
||||
-keep class ac.mdiq.podcini**
|
||||
-keepclassmembers class ac.mdiq.podcini** {*;}
|
||||
# -keep class de.test.podcini**
|
||||
# -keepclassmembers class de.test.podcini** {*;}
|
||||
|
||||
# Keep methods used in tests.
|
||||
# This is only needed when running tests with proguard enabled.
|
||||
|
@ -40,9 +42,6 @@
|
|||
-dontwarn okhttp3.**
|
||||
-dontwarn okio.**
|
||||
|
||||
# android-iconify
|
||||
#-keep class com.joanzapata.** { *; }
|
||||
|
||||
#### Proguard rules for fyyd client
|
||||
# Retrofit 2.0
|
||||
-dontwarn retrofit2.**
|
||||
|
@ -62,10 +61,10 @@
|
|||
####
|
||||
|
||||
# awaitility
|
||||
-dontwarn java.beans.BeanInfo
|
||||
-dontwarn java.beans.Introspector
|
||||
-dontwarn java.beans.IntrospectionException
|
||||
-dontwarn java.beans.PropertyDescriptor
|
||||
# -dontwarn java.beans.BeanInfo
|
||||
# -dontwarn java.beans.Introspector
|
||||
# -dontwarn java.beans.IntrospectionException
|
||||
# -dontwarn java.beans.PropertyDescriptor
|
||||
-dontwarn java.lang.management.ManagementFactory
|
||||
-dontwarn java.lang.management.ThreadInfo
|
||||
-dontwarn java.lang.management.ThreadMXBean
|
||||
|
|
|
@ -45,8 +45,8 @@
|
|||
android:supportsRtl="true"
|
||||
android:logo="@mipmap/ic_launcher"
|
||||
android:resizeableActivity="true"
|
||||
android:allowAudioPlaybackCapture="true"
|
||||
android:networkSecurityConfig="@xml/network_security_config">
|
||||
android:allowAudioPlaybackCapture="true">
|
||||
<!-- android:networkSecurityConfig="@xml/network_security_config">-->
|
||||
|
||||
<service android:name=".playback.service.PlaybackService"
|
||||
android:foregroundServiceType="mediaPlayback"
|
||||
|
|
|
@ -8,10 +8,12 @@ import ac.mdiq.vista.extractor.downloader.Response
|
|||
import ac.mdiq.vista.extractor.exceptions.ReCaptchaException
|
||||
import android.content.Context
|
||||
import androidx.preference.PreferenceManager
|
||||
import okhttp3.Cache
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request.Builder
|
||||
import okhttp3.RequestBody
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import java.util.concurrent.TimeUnit
|
||||
|
@ -22,7 +24,7 @@ class VistaDownloaderImpl private constructor(builder: OkHttpClient.Builder) : D
|
|||
private val mCookies: MutableMap<String, String> = HashMap()
|
||||
private val client: OkHttpClient = builder
|
||||
.readTimeout(30, TimeUnit.SECONDS)
|
||||
// .cache(new Cache(new File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
|
||||
// .cache(Cache(File(context.getExternalCacheDir(), "okhttp"), 16 * 1024 * 1024))
|
||||
.build()
|
||||
|
||||
private fun getCookies(url: String): String {
|
||||
|
@ -107,17 +109,22 @@ class VistaDownloaderImpl private constructor(builder: OkHttpClient.Builder) : D
|
|||
}
|
||||
}
|
||||
|
||||
val response = client.newCall(requestBuilder.build()).execute()
|
||||
if (response.code == 429) {
|
||||
response.close()
|
||||
throw ReCaptchaException("reCaptcha Challenge requested", url)
|
||||
try {
|
||||
val response = client.newCall(requestBuilder.build()).execute()
|
||||
if (response.code == 429) {
|
||||
response.close()
|
||||
throw ReCaptchaException("reCaptcha Challenge requested", url)
|
||||
}
|
||||
|
||||
val body = response.body
|
||||
val responseBodyToReturn: String? = body?.string()
|
||||
|
||||
val latestUrl = response.request.url.toString()
|
||||
return Response(response.code, response.message, response.headers.toMultimap(), responseBodyToReturn, latestUrl)
|
||||
} catch (e: Throwable) {
|
||||
e.printStackTrace()
|
||||
throw IOException("Something is wrong ${e.message}")
|
||||
}
|
||||
|
||||
val body = response.body
|
||||
val responseBodyToReturn: String? = body?.string()
|
||||
|
||||
val latestUrl = response.request.url.toString()
|
||||
return Response(response.code, response.message, response.headers.toMultimap(), responseBodyToReturn, latestUrl)
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -101,9 +101,7 @@ object PodciniHttpClient {
|
|||
if (!proxyConfig!!.username.isNullOrEmpty() && proxyConfig!!.password != null) {
|
||||
builder.proxyAuthenticator { _: Route?, response: Response ->
|
||||
val credentials = basic(proxyConfig!!.username!!, proxyConfig!!.password!!)
|
||||
response.request.newBuilder()
|
||||
.header("Proxy-Authorization", credentials)
|
||||
.build()
|
||||
response.request.newBuilder().header("Proxy-Authorization", credentials).build()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -126,9 +124,7 @@ object PodciniHttpClient {
|
|||
@Throws(IOException::class)
|
||||
override fun intercept(chain: Chain): Response {
|
||||
TrafficStats.setThreadStatsTag(Thread.currentThread().id.toInt())
|
||||
return chain.proceed(chain.request().newBuilder()
|
||||
.header("User-Agent", ClientConfig.USER_AGENT?:"")
|
||||
.build())
|
||||
return chain.proceed(chain.request().newBuilder().header("User-Agent", ClientConfig.USER_AGENT?:"").build())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
package ac.mdiq.podcini.net.feed.discovery
|
||||
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import android.util.Log
|
||||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.async
|
||||
|
@ -21,13 +22,9 @@ class CombinedSearcher : PodcastSearcher {
|
|||
try {
|
||||
val results = searcher.search(query)
|
||||
searchResults[index] = results
|
||||
} catch (e: Throwable) {
|
||||
Log.d(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
} catch (e: Throwable) { Logd(TAG, Log.getStackTraceString(e)) }
|
||||
}
|
||||
} else {
|
||||
null
|
||||
}
|
||||
} else null
|
||||
}.filterNotNull() // Remove null jobs
|
||||
// Wait for all search jobs to complete
|
||||
searchJobs.awaitAll()
|
||||
|
|
|
@ -391,11 +391,7 @@ class GpodnetService(private val httpClient: OkHttpClient, baseHosturl: String?,
|
|||
throw GpodnetServiceAuthenticationException("Wrong username or password")
|
||||
} else {
|
||||
if (BuildConfig.DEBUG) {
|
||||
try {
|
||||
Logd(TAG, response.body!!.string())
|
||||
} catch (e: IOException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
try { Logd(TAG, response.body!!.string()) } catch (e: IOException) { e.printStackTrace() }
|
||||
}
|
||||
if (responseCode >= 500) {
|
||||
throw GpodnetServiceBadStatusCodeException("Gpodder.net is currently unavailable (code " + responseCode + ")", responseCode)
|
||||
|
|
|
@ -39,7 +39,9 @@ object UrlChecker {
|
|||
// prepareUrl(removedWebsite)
|
||||
// }
|
||||
// }
|
||||
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "http://$url"
|
||||
// TODO: test
|
||||
// !(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "http://$url"
|
||||
!(lowerCaseUrl.startsWith("http://") || lowerCaseUrl.startsWith("https://")) -> "https://$url"
|
||||
else -> url
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
package ac.mdiq.podcini.playback.service
|
||||
|
||||
import ac.mdiq.podcini.BuildConfig
|
||||
import ac.mdiq.podcini.R
|
||||
import ac.mdiq.podcini.net.download.service.HttpCredentialEncoder
|
||||
import ac.mdiq.podcini.net.download.service.PodciniHttpClient
|
||||
|
@ -20,11 +19,11 @@ import ac.mdiq.podcini.storage.model.Feed
|
|||
import ac.mdiq.podcini.storage.model.MediaType
|
||||
import ac.mdiq.podcini.storage.model.Playable
|
||||
import ac.mdiq.podcini.storage.utils.EpisodeUtil
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.config.ClientConfig
|
||||
import ac.mdiq.podcini.util.EventFlow
|
||||
import ac.mdiq.podcini.util.FlowEvent
|
||||
import ac.mdiq.podcini.util.FlowEvent.PlayEvent.Action
|
||||
import ac.mdiq.podcini.util.Logd
|
||||
import ac.mdiq.podcini.util.config.ClientConfig
|
||||
import ac.mdiq.vista.extractor.MediaFormat
|
||||
import ac.mdiq.vista.extractor.Vista
|
||||
import ac.mdiq.vista.extractor.stream.*
|
||||
|
@ -56,7 +55,6 @@ import androidx.media3.exoplayer.source.ProgressiveMediaSource
|
|||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector
|
||||
import androidx.media3.exoplayer.trackselection.DefaultTrackSelector.SelectionOverride
|
||||
import androidx.media3.exoplayer.trackselection.ExoTrackSelection
|
||||
import androidx.media3.exoplayer.util.EventLogger
|
||||
import androidx.media3.extractor.DefaultExtractorsFactory
|
||||
import androidx.media3.extractor.mp3.Mp3Extractor
|
||||
import androidx.media3.ui.DefaultTrackNameProvider
|
||||
|
@ -67,8 +65,6 @@ import java.lang.Runnable
|
|||
import java.util.*
|
||||
import java.util.concurrent.CountDownLatch
|
||||
import java.util.concurrent.TimeUnit
|
||||
import kotlin.collections.ArrayList
|
||||
import kotlin.collections.HashMap
|
||||
import kotlin.concurrent.Volatile
|
||||
|
||||
/**
|
||||
|
@ -186,28 +182,29 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
@Throws(IllegalArgumentException::class, IllegalStateException::class)
|
||||
private fun setDataSource(metadata: MediaMetadata, media: EpisodeMedia) {
|
||||
val url = media.getStreamUrl() ?: return
|
||||
Logd(TAG, "setDataSource1: $url")
|
||||
val preferences = media.episodeOrFetch()?.feed?.preferences
|
||||
val user = preferences?.username
|
||||
val password = preferences?.password
|
||||
if (media.episode?.feed?.type == Feed.FeedType.YOUTUBE.name) {
|
||||
Logd(TAG, "setDataSource setting for YouTube source")
|
||||
Logd(TAG, "setDataSource1 setting for YouTube source")
|
||||
try {
|
||||
val streamInfo = StreamInfo.getInfo(Vista.getService(0), url)
|
||||
val vService = Vista.getService(0)
|
||||
val streamInfo = StreamInfo.getInfo(vService, url)
|
||||
val audioStreamsList = getFilteredAudioStreams(streamInfo.audioStreams)
|
||||
Logd(TAG, "setDataSource1 got ${audioStreamsList.size}")
|
||||
val audioIndex = if (isNetworkRestricted) 0 else audioStreamsList.size - 1
|
||||
val audioStream = audioStreamsList[audioIndex]
|
||||
Logd(TAG, "setDataSource1 use audio quality: ${audioStream.bitrate}")
|
||||
val aSource = DefaultMediaSourceFactory(context).createMediaSource(MediaItem.Builder().setTag(metadata).setUri(Uri.parse(audioStream.content)).build())
|
||||
Logd(TAG, "setDataSource use audio quality: ${audioStream.bitrate}")
|
||||
if (media.episode?.feed?.preferences?.playAudioOnly != true) {
|
||||
Logd(TAG, "setDataSource result: $streamInfo")
|
||||
Logd(TAG, "setDataSource videoStreams: ${streamInfo.videoStreams.size} videoOnlyStreams: ${streamInfo.videoOnlyStreams.size} audioStreams: ${streamInfo.audioStreams.size}")
|
||||
Logd(TAG, "setDataSource1 result: $streamInfo")
|
||||
Logd(TAG, "setDataSource1 videoStreams: ${streamInfo.videoStreams.size} videoOnlyStreams: ${streamInfo.videoOnlyStreams.size} audioStreams: ${streamInfo.audioStreams.size}")
|
||||
val videoStreamsList = getSortedStreamVideosList(streamInfo.videoStreams, streamInfo.videoOnlyStreams, true, true)
|
||||
val videoIndex = 0
|
||||
val videoStream = videoStreamsList[videoIndex]
|
||||
Logd(TAG, "setDataSource use video quality: ${videoStream.resolution}")
|
||||
Logd(TAG, "setDataSource1 use video quality: ${videoStream.resolution}")
|
||||
val vSource = DefaultMediaSourceFactory(context).createMediaSource(MediaItem.Builder().setTag(metadata).setUri(Uri.parse(videoStream.content)).build())
|
||||
val mediaSources: MutableList<MediaSource> = java.util.ArrayList()
|
||||
val mediaSources: MutableList<MediaSource> = ArrayList()
|
||||
mediaSources.add(vSource)
|
||||
mediaSources.add(aSource)
|
||||
mediaSource = MergingMediaSource(true, *mediaSources.toTypedArray<MediaSource>())
|
||||
|
@ -215,9 +212,9 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
} else mediaSource = aSource
|
||||
mediaItem = mediaSource?.mediaItem
|
||||
setSourceCredentials(user, password)
|
||||
} catch (throwable: Throwable) { Logd(TAG, "setDataSource error: ${throwable.message}") }
|
||||
} catch (throwable: Throwable) { Log.e(TAG, "setDataSource1 error: ${throwable.message}") }
|
||||
} else {
|
||||
Logd(TAG, "setDataSource setting for Podcast source")
|
||||
Logd(TAG, "setDataSource1 setting for Podcast source")
|
||||
setDataSource(metadata, url,user, password)
|
||||
}
|
||||
}
|
||||
|
@ -255,15 +252,15 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
* streams and normal video streams are available
|
||||
* @return the sorted list
|
||||
*/
|
||||
fun getSortedStreamVideosList(videoStreams: List<VideoStream>?, videoOnlyStreams: List<VideoStream>?, ascendingOrder: Boolean,
|
||||
private fun getSortedStreamVideosList(videoStreams: List<VideoStream>?, videoOnlyStreams: List<VideoStream>?, ascendingOrder: Boolean,
|
||||
preferVideoOnlyStreams: Boolean): List<VideoStream> {
|
||||
val videoStreamsOrdered = if (preferVideoOnlyStreams) listOf(videoStreams, videoOnlyStreams) else listOf(videoOnlyStreams, videoStreams)
|
||||
val allInitialStreams = videoStreamsOrdered.filterNotNull().flatMap { it }.toList()
|
||||
val allInitialStreams = videoStreamsOrdered.filterNotNull().flatten().toList()
|
||||
val comparator = compareBy<VideoStream> { it.resolution.toResolutionValue() }
|
||||
return if (ascendingOrder) allInitialStreams.sortedWith(comparator) else { allInitialStreams.sortedWith(comparator.reversed()) }
|
||||
}
|
||||
|
||||
fun String.toResolutionValue(): Int {
|
||||
private fun String.toResolutionValue(): Int {
|
||||
val match = Regex("(\\d+)p|(\\d+)k").find(this)
|
||||
return when {
|
||||
match?.groupValues?.get(1) != null -> match.groupValues[1].toInt()
|
||||
|
@ -272,7 +269,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
}
|
||||
}
|
||||
|
||||
fun getFilteredAudioStreams(audioStreams: List<AudioStream>?): List<AudioStream> {
|
||||
private fun getFilteredAudioStreams(audioStreams: List<AudioStream>?): List<AudioStream> {
|
||||
if (audioStreams == null) return listOf()
|
||||
val collectedStreams = mutableSetOf<AudioStream>()
|
||||
for (stream in audioStreams) {
|
||||
|
@ -281,7 +278,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
continue
|
||||
collectedStreams.add(stream)
|
||||
}
|
||||
return collectedStreams.toList().sortedWith(compareBy<AudioStream> { it.bitrate })
|
||||
return collectedStreams.toList().sortedWith(compareBy { it.bitrate })
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -355,7 +352,8 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
if (streamurl != null) {
|
||||
val media = curMedia
|
||||
if (media is EpisodeMedia) {
|
||||
setDataSource(metadata, media)
|
||||
val deferred = CoroutineScope(Dispatchers.IO).async { setDataSource(metadata, media) }
|
||||
runBlocking { deferred.await() }
|
||||
// val preferences = media.episodeOrFetch()?.feed?.preferences
|
||||
// setDataSource(metadata, streamurl, preferences?.username, preferences?.password)
|
||||
} else setDataSource(metadata, streamurl, null, null)
|
||||
|
@ -381,13 +379,12 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
e.printStackTrace()
|
||||
setPlayerStatus(PlayerStatus.ERROR, null)
|
||||
EventFlow.postStickyEvent(FlowEvent.PlayerErrorEvent(e.localizedMessage ?: ""))
|
||||
} finally {
|
||||
}
|
||||
} finally { }
|
||||
}
|
||||
|
||||
override fun resume() {
|
||||
if (status == PlayerStatus.PAUSED || status == PlayerStatus.PREPARED) {
|
||||
Log.d(TAG, "Resuming/Starting playback")
|
||||
Logd(TAG, "Resuming/Starting playback")
|
||||
acquireWifiLockIfNecessary()
|
||||
setPlaybackParams(getCurrentPlaybackSpeed(curMedia), UserPreferences.isSkipSilence)
|
||||
setVolume(1.0f, 1.0f)
|
||||
|
@ -441,9 +438,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
releaseWifiLockIfNecessary()
|
||||
when {
|
||||
curMedia != null -> playMediaObject(curMedia!!, isStreaming, startWhenPrepared.get(), prepareImmediately = false, true)
|
||||
else -> {
|
||||
Logd(TAG, "Call to reinit: media and mediaPlayer were null, ignored")
|
||||
}
|
||||
else -> Logd(TAG, "Call to reinit: media and mediaPlayer were null, ignored")
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -466,11 +461,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
PlayerStatus.PLAYING, PlayerStatus.PAUSED, PlayerStatus.PREPARED -> {
|
||||
Logd(TAG, "seekTo() called $t")
|
||||
if (seekLatch != null && seekLatch!!.count > 0) {
|
||||
try {
|
||||
seekLatch!!.await(3, TimeUnit.SECONDS)
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
try { seekLatch!!.await(3, TimeUnit.SECONDS) } catch (e: InterruptedException) { Log.e(TAG, Log.getStackTraceString(e)) }
|
||||
}
|
||||
seekLatch = CountDownLatch(1)
|
||||
statusBeforeSeeking = status
|
||||
|
@ -479,11 +470,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
if (curMedia != null) EventFlow.postEvent(FlowEvent.PlaybackPositionEvent(curMedia, t, curMedia!!.getDuration()))
|
||||
audioSeekCompleteListener?.run()
|
||||
if (statusBeforeSeeking == PlayerStatus.PREPARED) curMedia?.setPosition(t)
|
||||
try {
|
||||
seekLatch!!.await(3, TimeUnit.SECONDS)
|
||||
} catch (e: InterruptedException) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
try { seekLatch!!.await(3, TimeUnit.SECONDS) } catch (e: InterruptedException) { Log.e(TAG, Log.getStackTraceString(e)) }
|
||||
}
|
||||
PlayerStatus.INITIALIZED -> {
|
||||
curMedia?.setPosition(t)
|
||||
|
@ -729,7 +716,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
override fun onIsPlayingChanged(isPlaying: Boolean) {
|
||||
val stat = if (isPlaying) PlayerStatus.PLAYING else PlayerStatus.PAUSED
|
||||
setPlayerStatus(stat, curMedia)
|
||||
Log.d(TAG, "onIsPlayingChanged $isPlaying")
|
||||
Logd(TAG, "onIsPlayingChanged $isPlaying")
|
||||
}
|
||||
override fun onPlayerError(error: PlaybackException) {
|
||||
Logd(TAG, "onPlayerError ${error.message}")
|
||||
|
@ -808,7 +795,7 @@ class LocalMediaPlayer(context: Context, callback: MediaPlayerCallback) : MediaP
|
|||
.setAudioOffloadPreferences(audioOffloadPreferences)
|
||||
.build()
|
||||
|
||||
if (BuildConfig.DEBUG) exoPlayer!!.addAnalyticsListener(EventLogger())
|
||||
// if (BuildConfig.DEBUG) exoPlayer!!.addAnalyticsListener(EventLogger())
|
||||
|
||||
if (exoplayerListener != null) {
|
||||
exoPlayer?.removeListener(exoplayerListener!!)
|
||||
|
|
|
@ -19,7 +19,6 @@ import android.util.Log
|
|||
class PowerConnectionReceiver : BroadcastReceiver() {
|
||||
@UnstableApi override fun onReceive(context: Context, intent: Intent) {
|
||||
val action = intent.action
|
||||
|
||||
Log.d(TAG, "onReceive charging intent: $action")
|
||||
|
||||
ClientConfigurator.initialize(context)
|
||||
|
|
|
@ -152,11 +152,11 @@ object Feeds {
|
|||
}
|
||||
|
||||
fun getFeed(feedId: Long, copy: Boolean = false): Feed? {
|
||||
if (BuildConfig.DEBUG) {
|
||||
val stackTrace = Thread.currentThread().stackTrace
|
||||
val caller = if (stackTrace.size > 3) stackTrace[3] else null
|
||||
Logd(TAG, "${caller?.className}.${caller?.methodName} getFeed called")
|
||||
}
|
||||
// if (BuildConfig.DEBUG) {
|
||||
// val stackTrace = Thread.currentThread().stackTrace
|
||||
// val caller = if (stackTrace.size > 3) stackTrace[3] else null
|
||||
// Logd(TAG, "${caller?.className}.${caller?.methodName} getFeed called")
|
||||
// }
|
||||
val f = realm.query(Feed::class, "id == $feedId").first().find()
|
||||
return if (f != null) {
|
||||
if (copy) realm.copyFromRealm(f)
|
||||
|
|
|
@ -689,9 +689,7 @@ import java.util.concurrent.Semaphore
|
|||
runOnIOScope {
|
||||
val feed_ = realm.query(Feed::class, "id == ${feed.id}").first().find()
|
||||
if (feed_ != null) {
|
||||
upsert(feed_) {
|
||||
it.sortOrder = sortOrder
|
||||
}
|
||||
upsert(feed_) { it.sortOrder = sortOrder }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -737,6 +735,10 @@ import java.util.concurrent.Semaphore
|
|||
private const val ARGUMENT_FEED_ID = "argument.ac.mdiq.podcini.feed_id"
|
||||
private const val KEY_UP_ARROW = "up_arrow"
|
||||
|
||||
var tts: TextToSpeech? = null
|
||||
var ttsReady = false
|
||||
var ttsWorking = false
|
||||
|
||||
fun newInstance(feedId: Long): FeedEpisodesFragment {
|
||||
val i = FeedEpisodesFragment()
|
||||
val b = Bundle()
|
||||
|
@ -744,9 +746,5 @@ import java.util.concurrent.Semaphore
|
|||
i.arguments = b
|
||||
return i
|
||||
}
|
||||
|
||||
var tts: TextToSpeech? = null
|
||||
var ttsReady = false
|
||||
var ttsWorking = false
|
||||
}
|
||||
}
|
||||
|
|
|
@ -268,6 +268,7 @@ class OnlineFeedViewFragment : Fragment() {
|
|||
val channelTabInfo = ChannelTabInfo.getInfo(service, channelInfo.tabs.first())
|
||||
Logd(TAG, "startFeedBuilding result1: $channelTabInfo ${channelTabInfo.relatedItems.size}")
|
||||
selectedDownloadUrl = prepareUrl(url)
|
||||
// selectedDownloadUrl = url
|
||||
val feed_ = Feed(selectedDownloadUrl, null)
|
||||
feed_.id = 1234567889L
|
||||
feed_.type = Feed.FeedType.YOUTUBE.name
|
||||
|
|
|
@ -403,7 +403,7 @@ import java.util.*
|
|||
}
|
||||
|
||||
private fun onFeedPrefsChanged(event: FlowEvent.FeedPrefsChangeEvent) {
|
||||
Log.d(TAG,"speedPresetChanged called")
|
||||
Logd(TAG,"speedPresetChanged called")
|
||||
for (item in queueItems) {
|
||||
if (item.feed?.id == event.feed.id) item.feed = null
|
||||
}
|
||||
|
|
|
@ -31,18 +31,12 @@ object RatingDialog {
|
|||
mPreferences = context.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
|
||||
|
||||
val firstDate: Long = mPreferences.getLong(KEY_FIRST_START_DATE, 0)
|
||||
if (firstDate == 0L) {
|
||||
resetStartDate()
|
||||
}
|
||||
if (firstDate == 0L) resetStartDate()
|
||||
}
|
||||
|
||||
fun check() {
|
||||
if (shouldShow()) {
|
||||
try {
|
||||
showInAppReview()
|
||||
} catch (e: Exception) {
|
||||
Log.e(TAG, Log.getStackTraceString(e))
|
||||
}
|
||||
try { showInAppReview() } catch (e: Exception) { Log.e(TAG, Log.getStackTraceString(e)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,9 +52,8 @@ object RatingDialog {
|
|||
val flow: Task<Void?> = manager.launchReviewFlow(context as Activity, reviewInfo)
|
||||
flow.addOnCompleteListener { task1: Task<Void?>? ->
|
||||
val previousAttempts: Int = mPreferences.getInt(KEY_NUMBER_OF_REVIEWS, 0)
|
||||
if (previousAttempts >= 3) {
|
||||
saveRated()
|
||||
} else {
|
||||
if (previousAttempts >= 3) saveRated()
|
||||
else {
|
||||
resetStartDate()
|
||||
mPreferences
|
||||
.edit()
|
||||
|
@ -69,14 +62,10 @@ object RatingDialog {
|
|||
}
|
||||
Logd("ReviewDialog", "Successfully finished in-app review")
|
||||
}
|
||||
.addOnFailureListener { error: Exception? ->
|
||||
Logd("ReviewDialog", "failed in reviewing process")
|
||||
}
|
||||
.addOnFailureListener { error: Exception? -> Logd("ReviewDialog", "failed in reviewing process") }
|
||||
}
|
||||
}
|
||||
.addOnFailureListener { error: Exception? ->
|
||||
Logd("ReviewDialog", "failed to get in-app review request")
|
||||
}
|
||||
.addOnFailureListener { error: Exception? -> Logd("ReviewDialog", "failed to get in-app review request") }
|
||||
}
|
||||
|
||||
private fun rated(): Boolean {
|
||||
|
@ -99,9 +88,7 @@ object RatingDialog {
|
|||
}
|
||||
|
||||
private fun shouldShow(): Boolean {
|
||||
if (rated() || BuildConfig.DEBUG) {
|
||||
return false
|
||||
}
|
||||
if (rated() || BuildConfig.DEBUG) return false
|
||||
|
||||
val now = System.currentTimeMillis()
|
||||
val firstDate: Long = mPreferences.getLong(KEY_FIRST_START_DATE, now)
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
# 6.5.2
|
||||
|
||||
* replace all url of http to https
|
||||
* resolved the nasty issue of Youtube media not properly played in release app
|
||||
|
||||
# 6.5.1
|
||||
|
||||
* further improved behavior in video player, seamless switch among audio-only, window and fullscreen modes, and automatical switch to audio when exit
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Version 6.5.2 brings several changes:
|
||||
|
||||
* replace all url of http to https
|
||||
* resolved the nasty issue of Youtube media not properly played in release app
|
Loading…
Reference in New Issue