7 Commits

Author SHA1 Message Date
3f461792e5 release version v0.8.3 2025-02-01 18:59:36 -06:00
4738c317cc Fix play private videos 2025-02-01 18:53:20 -06:00
3997b38120 Fix session fetch 2025-02-01 17:41:34 -06:00
a1deaa844c Prepare release: fix media player and splashscreen bug 2025-01-24 17:41:32 -06:00
4de1408ba6 Fix player stucks on resume player 2024-08-09 15:13:09 -06:00
48eec0dc88 Fix to logout when token expires 2024-08-09 15:12:42 -06:00
4bbeb284da Fix release 2024-06-17 11:47:13 -06:00
12 changed files with 110 additions and 58 deletions

View File

@ -1,4 +1,3 @@
plugins { plugins {
id "com.android.application" id "com.android.application"
id "kotlin-android" id "kotlin-android"
@ -7,11 +6,11 @@ plugins {
android { android {
defaultConfig { defaultConfig {
applicationId "org.libre.agosto.p2play" applicationId "org.libre.agosto.p2play"
compileSdk 34 compileSdk 35
minSdkVersion 26 minSdkVersion 26
targetSdkVersion 32 targetSdkVersion 32
versionCode 10 versionCode 14
versionName "0.7.0" versionName "0.8.3"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
vectorDrawables.useSupportLibrary = true vectorDrawables.useSupportLibrary = true
} }
@ -25,14 +24,17 @@ android {
viewBinding = true viewBinding = true
} }
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_17 sourceCompatibility JavaVersion.VERSION_18
targetCompatibility JavaVersion.VERSION_17 targetCompatibility JavaVersion.VERSION_18
} }
namespace 'org.libre.agosto.p2play' namespace 'org.libre.agosto.p2play'
lint { lint {
abortOnError false abortOnError false
checkReleaseBuilds false checkReleaseBuilds false
} }
kotlinOptions {
jvmTarget = '18'
}
} }
dependencies { dependencies {

View File

@ -66,11 +66,6 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
binding.content.mini.miniPlayerAuthor.setOnClickListener { this.resumeVideo() } binding.content.mini.miniPlayerAuthor.setOnClickListener { this.resumeVideo() }
// binding.content.mini.setOnClickListener { this.resumeVideo() } // binding.content.mini.setOnClickListener { this.resumeVideo() }
binding.content.mini.miniPlayPause.setOnClickListener { this.playPausePlayer() } binding.content.mini.miniPlayPause.setOnClickListener { this.playPausePlayer() }
Handler().postDelayed({
// Title for nav_bar
binding.navView.getHeaderView(0).findViewById<TextView>(R.id.side_emailTxt).text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
}, 2000)
} }
// Generic function for set data to RecyclerView // Generic function for set data to RecyclerView
@ -374,10 +369,10 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
} }
private fun setSideData() { private fun setSideData() {
val headerView = binding.navView.getHeaderView(0)
if (ManagerSingleton.user.status == 1) { if (ManagerSingleton.user.status == 1) {
binding.navView.menu.findItem(R.id.ml).isVisible = true binding.navView.menu.findItem(R.id.ml).isVisible = true
val headerView = binding.navView.getHeaderView(0)
headerView.findViewById<TextView>(R.id.side_usernameTxt).text = ManagerSingleton.user.username headerView.findViewById<TextView>(R.id.side_usernameTxt).text = ManagerSingleton.user.username
headerView.findViewById<TextView>(R.id.side_emailTxt).text = ManagerSingleton.user.email headerView.findViewById<TextView>(R.id.side_emailTxt).text = ManagerSingleton.user.email
if (ManagerSingleton.user.avatar != "" && headerView.findViewById<ImageView>(R.id.side_imageView) != null) { if (ManagerSingleton.user.avatar != "" && headerView.findViewById<ImageView>(R.id.side_imageView) != null) {
@ -394,6 +389,7 @@ class MainActivity : AppCompatActivity(), NavigationView.OnNavigationItemSelecte
} }
} else { } else {
binding.navView.menu.findItem(R.id.ml).isVisible = false binding.navView.menu.findItem(R.id.ml).isVisible = false
headerView.findViewById<TextView>(R.id.side_emailTxt).text = getString(R.string.nav_header_subtitle) + " " + this.packageManager.getPackageInfo(this.packageName, 0).versionName
} }
} }

View File

@ -10,6 +10,7 @@ import android.net.Uri
import android.os.AsyncTask import android.os.AsyncTask
import android.os.Bundle import android.os.Bundle
import android.os.Looper import android.os.Looper
import android.util.Log
import android.view.View import android.view.View
import android.view.WindowManager import android.view.WindowManager
import android.webkit.WebChromeClient import android.webkit.WebChromeClient
@ -129,7 +130,7 @@ class ReproductorActivity : AppCompatActivity() {
binding.reportLayout.setOnClickListener { reportIntent() } binding.reportLayout.setOnClickListener { reportIntent() }
fullscreenButton.setOnClickListener { toggleFullscreen() } fullscreenButton.setOnClickListener { toggleFullscreen() }
fullscreenButton2.setOnClickListener { toggleFullscreen() } fullscreenButton2.setOnClickListener { toggleFullscreen() }
binding.downloadLayout!!.setOnClickListener { downloadVideo() } binding.downloadLayout.setOnClickListener { downloadVideo() }
binding.userImg.setOnClickListener { binding.userImg.setOnClickListener {
@ -139,7 +140,7 @@ class ReproductorActivity : AppCompatActivity() {
} }
AsyncTask.execute { AsyncTask.execute {
videoPlayback = this.clientVideo.getVideo(this.video.uuid) videoPlayback = this.clientVideo.getVideo(this.video.uuid, ManagerSingleton.token.token)
// TODO: Make this configurable // TODO: Make this configurable
// val bufferSize = 1024 * 1024 // 1mb // val bufferSize = 1024 * 1024 // 1mb
// val allocator = DefaultAllocator(true, bufferSize) // val allocator = DefaultAllocator(true, bufferSize)
@ -149,7 +150,7 @@ class ReproductorActivity : AppCompatActivity() {
runOnUiThread { runOnUiThread {
try { try {
if (PlaybackSingleton.player == null || !PlaybackSingleton.player!!.playWhenReady) { if (PlaybackSingleton.player == null || !PlaybackSingleton.player!!.isPlaying) {
PlaybackSingleton.player = ExoPlayer.Builder(this) PlaybackSingleton.player = ExoPlayer.Builder(this)
//.setSeekBackIncrementMs(10000) //.setSeekBackIncrementMs(10000)
//.setSeekForwardIncrementMs(10000) //.setSeekForwardIncrementMs(10000)
@ -160,7 +161,6 @@ class ReproductorActivity : AppCompatActivity() {
player = PlaybackSingleton.player!! player = PlaybackSingleton.player!!
binding.exoPlayer.player = player binding.exoPlayer.player = player
binding.exoPlayer
player.addListener( player.addListener(
object : Player.Listener { object : Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) { override fun onPlaybackStateChanged(playbackState: Int) {
@ -175,9 +175,6 @@ class ReproductorActivity : AppCompatActivity() {
} }
) )
println("----- video --------")
println(videoPlayback.streamingData?.playlistUrl)
if (!isResume) { if (!isResume) {
val mediaItem = MediaItem.Builder() val mediaItem = MediaItem.Builder()
.setUri(videoPlayback.streamingData?.playlistUrl!!) .setUri(videoPlayback.streamingData?.playlistUrl!!)
@ -192,7 +189,7 @@ class ReproductorActivity : AppCompatActivity() {
} }
// Start the playback. // Start the playback.
// TODO: Setting for autoplay // TODO: Setting for autoplay
// player.play() player.playWhenReady = true
} catch (err: Exception) { } catch (err: Exception) {
err.printStackTrace() err.printStackTrace()
} }
@ -359,6 +356,10 @@ class ReproductorActivity : AppCompatActivity() {
} else { } else {
binding.commentBox.commentaryLayout.visibility = View.GONE binding.commentBox.commentaryLayout.visibility = View.GONE
} }
if (::player.isInitialized && !player.isPlaying) {
binding.exoPlayer.onResume()
}
} }
private fun getDescription() { private fun getDescription() {

View File

@ -10,6 +10,8 @@ import android.util.Log
import androidx.appcompat.app.AppCompatActivity import androidx.appcompat.app.AppCompatActivity
import androidx.preference.PreferenceManager import androidx.preference.PreferenceManager
import org.libre.agosto.p2play.ajax.Auth import org.libre.agosto.p2play.ajax.Auth
import org.libre.agosto.p2play.helpers.TaskManager
import org.libre.agosto.p2play.models.TokenModel
import java.lang.Exception import java.lang.Exception
class SplashActivity : AppCompatActivity() { class SplashActivity : AppCompatActivity() {
@ -31,55 +33,50 @@ class SplashActivity : AppCompatActivity() {
val lastHost = settings.getString("last_host", "") val lastHost = settings.getString("last_host", "")
if (host != "") { if (host != "") {
if (lastHost != host) { if (lastHost != host) {
Handler().postDelayed({ Thread.sleep(2000)
startHostActivity() startHostActivity()
}, 2000)
} else { } else {
ManagerSingleton.url = host ManagerSingleton.url = host
checkUser() checkUser()
} }
} else { } else {
Handler().postDelayed({ Thread.sleep(2000)
startHostActivity() startHostActivity()
}, 2000)
} }
} }
private fun checkUser() { private fun checkUser() {
Log.d("was", "Checked")
try { try {
val token = db.getToken() val token = db.getToken()
val user = db.getUser() val user = db.getUser()
AsyncTask.execute {
if (Looper.myLooper() == null) {
Looper.prepare()
}
if (token.status == 1 && user.status == 1) { if (token.status == 1 && user.status == 1) {
val clientId = settings.getString("client_id", "")!! val clientId = settings.getString("client_id", "")!!
val clientSecret = settings.getString("client_secret", "")!! val clientSecret = settings.getString("client_secret", "")!!
val task = TaskManager<TokenModel>()
val newToken = client.refreshToken(token, clientId, clientSecret) task.runTask(
{
when (token.status.toString()) { client.refreshToken(token, clientId, clientSecret)
}, {
when (it.status.toString()) {
"1" -> { "1" -> {
db.newToken(newToken) db.newToken(it)
ManagerSingleton.token = newToken ManagerSingleton.token = it
ManagerSingleton.user = user ManagerSingleton.user = user
} }
else -> ManagerSingleton.logout() else -> ManagerSingleton.logout()
} }
startApp()
})
} else { } else {
ManagerSingleton.logout() ManagerSingleton.logout()
}
startApp() startApp()
} }
} catch (err: Exception) { } catch (err: Exception) {
err.printStackTrace() err.printStackTrace()
Handler().postDelayed({ Thread.sleep(2000)
startApp() startHostActivity()
}, 2000)
} }
} }

View File

@ -105,6 +105,7 @@ class Auth : Client() {
token.status = 1 token.status = 1
} else { } else {
Log.d("Status", con.responseMessage) Log.d("Status", con.responseMessage)
token.status = 0
} }
} catch (err: Exception) { } catch (err: Exception) {
err.printStackTrace() err.printStackTrace()

View File

@ -9,7 +9,7 @@ import java.net.HttpURLConnection
import java.net.URL import java.net.URL
open class Client { open class Client {
protected fun newCon(uri: String, method: String, token: String = ""): HttpURLConnection { protected fun newCon(uri: String, method: String, token: String? = null): HttpURLConnection {
val url = URL("https://${ManagerSingleton.url}/api/v1/$uri") val url = URL("https://${ManagerSingleton.url}/api/v1/$uri")
val con = url.openConnection() as HttpURLConnection val con = url.openConnection() as HttpURLConnection
@ -17,7 +17,7 @@ open class Client {
con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded") con.setRequestProperty("Content-Type", "application/x-www-form-urlencoded")
con.setRequestProperty("Accept", "*/*") con.setRequestProperty("Accept", "*/*")
if (token != "") { if (token !== null) {
con.setRequestProperty("Authorization", "Bearer $token") con.setRequestProperty("Authorization", "Bearer $token")
} }

View File

@ -201,8 +201,8 @@ class Videos : Client() {
return this.getVideos(start, "-likes") return this.getVideos(start, "-likes")
} }
fun getVideo(uuid: String): VideoModel { fun getVideo(uuid: String, token: String? = null): VideoModel {
val con = this.newCon("videos/$uuid", "GET") val con = this.newCon("videos/$uuid", "GET", token)
val video = VideoModel() val video = VideoModel()
try { try {
if (con.responseCode == 200) { if (con.responseCode == 200) {

View File

@ -0,0 +1,22 @@
package org.libre.agosto.p2play.helpers
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
class TaskManager<T> : ViewModel() {
val result = MutableLiveData<T>()
fun runTask(task: () -> T, callback: (T) -> Unit) {
viewModelScope.launch {
val data = withContext(Dispatchers.IO) {
task()
}
result.postValue(data)
callback(data)
}
}
}

View File

@ -2,6 +2,8 @@ package org.libre.agosto.p2play.services
import android.app.PendingIntent import android.app.PendingIntent
import android.content.Intent import android.content.Intent
import androidx.annotation.OptIn
import androidx.media3.common.util.UnstableApi
import androidx.media3.session.MediaSession import androidx.media3.session.MediaSession
import androidx.media3.session.MediaSessionService import androidx.media3.session.MediaSessionService
import org.libre.agosto.p2play.ReproductorActivity import org.libre.agosto.p2play.ReproductorActivity
@ -11,6 +13,7 @@ class PlaybackService : MediaSessionService() {
private var mediaSession: MediaSession? = null private var mediaSession: MediaSession? = null
// Create your Player and MediaSession in the onCreate lifecycle event // Create your Player and MediaSession in the onCreate lifecycle event
@OptIn(UnstableApi::class)
override fun onCreate() { override fun onCreate() {
super.onCreate() super.onCreate()
val player = PlaybackSingleton.player!! val player = PlaybackSingleton.player!!
@ -24,7 +27,8 @@ class PlaybackService : MediaSessionService() {
contentIntent, contentIntent,
PendingIntent.FLAG_MUTABLE, PendingIntent.FLAG_MUTABLE,
) )
mediaSession!!.setSessionActivity(pendingIntent)
mediaSession?.setSessionActivity(pendingIntent)
} }
// Remember to release the player and media session in onDestroy // Remember to release the player and media session in onDestroy

View File

@ -170,6 +170,35 @@
android:textAlignment="center" /> android:textAlignment="center" />
</LinearLayout> </LinearLayout>
<LinearLayout
android:id="@+id/downloadLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:orientation="vertical"
android:visibility="visible">
<ImageView
android:id="@+id/downloadImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:adjustViewBounds="false"
android:contentDescription="@string/reportBtn"
android:cropToPadding="false"
android:visibility="visible"
app:srcCompat="@drawable/ic_outline_cloud_download_24"
app:tint="#585858" />
<TextView
android:id="@+id/downloadText"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="1"
android:text="@string/downloadText"
android:textAlignment="center" />
</LinearLayout>
<LinearLayout <LinearLayout
android:id="@+id/reportLayout" android:id="@+id/reportLayout"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@ -7,7 +7,7 @@ buildscript {
mavenCentral() mavenCentral()
} }
dependencies { dependencies {
classpath 'com.android.tools.build:gradle:8.3.2' classpath 'com.android.tools.build:gradle:8.8.0'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong // NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files // in the individual module build.gradle files

View File

@ -1,6 +1,6 @@
#Mon Mar 18 13:17:32 CST 2024 #Fri Jan 24 15:00:50 CST 2025
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists zipStorePath=wrapper/dists