Skip to content
This repository has been archived by the owner on Nov 27, 2024. It is now read-only.

Commit

Permalink
Merge branch 'master' into fix/lateinit_player
Browse files Browse the repository at this point in the history
  • Loading branch information
kuylar authored Jan 6, 2024
2 parents b269bb9 + d840866 commit 739d0bf
Show file tree
Hide file tree
Showing 10 changed files with 329 additions and 31 deletions.
51 changes: 50 additions & 1 deletion app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -30,12 +30,61 @@
<activity
android:name=".ui.activity.MainActivity"
android:configChanges="orientation|screenSize"
android:exported="true">
android:exported="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />

<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="youtube.com" />
<data android:host="m.youtube.com" />
<data android:host="www.youtube.com" />
<!-- Videos -->
<data android:pathPrefix="/v/" />
<data android:pathPrefix="/embed/" />
<data android:pathPrefix="/watch" />
<data android:pathPrefix="/attribution_link" />
<data android:pathPrefix="/shorts/" />
<data android:pathPrefix="/live/" />
<!-- Channels -->
<data android:pathPrefix="/channel/" />
<data android:pathPrefix="/user/" />
<data android:pathPrefix="/c/" />
<data android:pathPrefix="/@" />
<!-- Playlists -->
<data android:pathPrefix="/playlist" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="youtu.be" />
<data android:pathPrefix="/" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />

<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />

<data android:scheme="http" />
<data android:scheme="https" />
<data android:host="www.youtube-nocookie.com" />
<data android:pathPrefix="/embed/" />
</intent-filter>
</activity>
</application>

Expand Down
16 changes: 16 additions & 0 deletions app/src/main/java/dev/kuylar/lighttube/Utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -435,5 +435,21 @@ class Utils {
}
.show()
}

fun parseQueryString(query: String): HashMap<String, String> {
val queryString = query.trimStart('?')
val dict = HashMap<String, String>()
queryString.split('&').forEach {
val parts = it.split('=')
val name = parts.firstOrNull() ?: ""
val value = parts.drop(1).joinToString("=")
dict[name] = value
}
return dict
}

fun unwrapAttributionUrl(query: String): String {
return parseQueryString(query)["u"] ?: ""
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,12 +13,13 @@ class LightTubeVideo(
val likeCount: String,
val channel: Channel,
val commentsContinuation: String,
val commentCount: String,
val commentCount: String?,
val recommended: ArrayList<JsonObject>,
val playlist: Any? = null,
val chapters: ArrayList<VideoChapter>
) {
var showCommentsButton: Boolean = false
var firstComment: Triple<String, String, Int>? = null
fun getAsRenderer() : JsonObject {
val gson = Gson()
val asJson = gson.fromJson(gson.toJson(this), JsonObject::class.java)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -376,7 +376,13 @@ class VideoPlayerManager(private val activity: MainActivity) : Player.Listener,

fun showCommentsButton() {
try {
(fragmentManager.findFragmentById(R.id.player_video_info) as VideoInfoFragment).showCommentsButton()
(fragmentManager.findFragmentById(R.id.player_video_info) as VideoInfoFragment).showCommentsButton(null)
} catch (_: Exception) { }
}

fun showCommentsButton(firstCommentAvatar: String, firstCommentText: String, commentCount: Int) {
try {
(fragmentManager.findFragmentById(R.id.player_video_info) as VideoInfoFragment).showCommentsButton(Triple(firstCommentAvatar, firstCommentText, commentCount))
} catch (_: Exception) { }
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package dev.kuylar.lighttube.ui.activity
import android.annotation.SuppressLint
import android.content.Intent
import android.content.pm.ActivityInfo
import android.net.Uri
import android.os.Bundle
import android.os.Handler
import android.util.Log
Expand All @@ -11,12 +12,14 @@ import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView.OnItemClickListener
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.activity.addCallback
import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.SearchView.SearchAutoComplete
import androidx.constraintlayout.motion.widget.MotionLayout
import androidx.core.content.res.ResourcesCompat
import androidx.core.os.bundleOf
import androidx.core.view.WindowCompat
import androidx.core.view.WindowInsetsCompat
import androidx.core.view.WindowInsetsControllerCompat
Expand Down Expand Up @@ -169,6 +172,82 @@ class MainActivity : AppCompatActivity() {
handler.postDelayed(sponsorblockRunnable, 100)
}
handler.postDelayed(sponsorblockRunnable, 100)

if (intent != null)
handleDeepLinks(intent.action, intent.data)
}

private fun handleDeepLinks(action: String?, data: Uri?): Boolean {
if (action == null || data == null) return false
val path = if (data.path == "/attribution_link") Utils.unwrapAttributionUrl(
data.query ?: ""
) else ((data.path ?: "/") + "?" + (data.query ?: "")).trimEnd('?')
val query =
if (path.contains('?')) Utils.parseQueryString(path.split("?")[1]) else HashMap()

fun video(id: String, time: String?, playlist: String?) {
player.playVideo(id) //todo: time, playlist
miniplayerScene.progress = 1f
binding.navView.visibility = View.GONE
}

fun channel(id: String, tab: String?) {
val realTab = if (tab == "featured" || tab == null) "home" else tab
findNavController(R.id.nav_host_fragment_activity_main)
.navigate(R.id.navigation_channel, bundleOf(Pair("id", id), Pair("tab", realTab)))
}

fun playlist(id: String) {
findNavController(R.id.nav_host_fragment_activity_main)
.navigate(R.id.navigation_playlist, bundleOf(Pair("id", id)))
}

return try {
if (path.startsWith("/watch")) {
video(query["v"]!!, query["t"], query["list"])
} else if (path.startsWith("/v/")) {
video(path.split('/')[2].split('?')[0], query["t"], query["list"])
} else if (path.startsWith("/embed/") || path.startsWith("/shorts/") || path.startsWith(
"/live/"
)
) {
video(path.split('/')[2].split('?')[0], query["t"] ?: query["start"], query["list"])
} else if (path.startsWith("/channel/") || path.startsWith("/user/") || path.startsWith(
"/c/"
)
) {
val parts = path.split('/')
channel(
parts[2].split('?')[0],
if (parts.size > 3) parts[3].split('?')[0] else null
)
} else if (path.startsWith("/@")) {
val parts = path.split('/')
channel(
parts[1].split('?')[0],
if (parts.size > 2) parts[2].split('?')[0] else null
)
} else if (path.startsWith("/playlist")) {
playlist(query["list"]!!)
} else if (data.host == "youtu.be") {
video(path.trimStart('/').split('?')[0], query["t"], query["list"])
} else {
throw IllegalArgumentException()
}
true
} catch (e: Exception) {
Toast.makeText(this, R.string.error_intent_filter, Toast.LENGTH_LONG).show()
false
}
}

override fun onNewIntent(intent: Intent?) {
var success = false
if (intent != null)
success = handleDeepLinks(intent.action, intent.data)

if (!success)
super.onNewIntent(intent)
}

private fun goBack(closeApp: Boolean): Boolean {
Expand Down Expand Up @@ -344,7 +423,8 @@ class MainActivity : AppCompatActivity() {
}

fun updateVideoAspectRatio(aspectRatio: Float) {
val clampedAspectRatio = if (aspectRatio.isNaN()) 16f / 9f else aspectRatio.coerceIn(1f, 2f)
val clampedAspectRatio =
if (aspectRatio.isNaN()) 16f / 9f else aspectRatio.coerceIn(1f, 2f)
Log.i(
"VideoPlayer",
"Updating player aspect ratio to $clampedAspectRatio (original: $aspectRatio)"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,17 @@ class VideoCommentsFragment : Fragment() {
(activity as MainActivity).setLoading(true)
thread {
try {
val comments = if (initial) api.getComments(id, SortOrder.TopComments) else api.continueComments(commentsContinuation!!)
if (initial) player.showCommentsButton()
val comments = if (initial) api.getComments(
id,
SortOrder.TopComments
) else api.continueComments(commentsContinuation!!)
if (initial) with(comments.data!!.contents[0].asJsonObject) {
player.showCommentsButton(
this.getAsJsonObject("owner").getAsJsonPrimitive("avatar").asString,
this.getAsJsonPrimitive("content").asString,
comments.data.contents.size
)
}
val start = items.size
items.addAll(comments.data!!.contents)
commentsContinuation = comments.data.continuation
Expand All @@ -87,6 +96,7 @@ class VideoCommentsFragment : Fragment() {
} catch (e: IOException) {
if (activity == null) return@thread
activity?.runOnUiThread {
player.showCommentsButton()
loading = false
(activity as MainActivity).setLoading(false)
val sb = Snackbar.make(
Expand All @@ -103,6 +113,7 @@ class VideoCommentsFragment : Fragment() {
} catch (e: LightTubeException) {
if (activity == null) return@thread
activity?.runOnUiThread {
player.showCommentsButton()
loading = false
(activity as MainActivity).setLoading(false)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -130,9 +130,10 @@ class VideoInfoFragment : Fragment() {
commentsSheet.state = if (comments) BottomSheetBehavior.STATE_EXPANDED else BottomSheetBehavior.STATE_HIDDEN
}

fun showCommentsButton() {
fun showCommentsButton(firstComment: Triple<String, String, Int>?) {
val video = Gson().fromJson(items[0], LightTubeVideo::class.java)
video.showCommentsButton = true
video.firstComment = firstComment
items[0] = video.getAsRenderer()
adapter.notifyItemChanged(0)
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package dev.kuylar.lighttube.ui.viewholder

import android.content.Intent
import android.text.Html
import android.view.View
import androidx.core.os.bundleOf
import androidx.navigation.findNavController
Expand Down Expand Up @@ -30,20 +31,37 @@ open class SlimVideoInfoRenderer(private val binding: RendererSlimVideoInfoBindi
)
binding.videoTitle.text = video.title
binding.channelTitle.text = video.channel.title
binding.channelSubscribers.text = video.channel.subscribers
binding.videoViews.text = video.viewCount
binding.videoUploaded.text = video.dateText
binding.buttonLike.text = video.likeCount
if (video.showCommentsButton)
binding.buttonComments.visibility = View.VISIBLE
if (video.showCommentsButton) {
if (video.firstComment != null) {
binding.commentsLoading.visibility = View.GONE
binding.commentsFirst.visibility = View.VISIBLE

Glide.with(binding.root)
.load(video.firstComment!!.first)
.into(binding.commentAvatar)
binding.commentText.text =
Html.fromHtml(video.firstComment!!.second, Html.FROM_HTML_MODE_LEGACY)
binding.commentsCountBullet.visibility = View.VISIBLE
binding.commentsCount.text = video.commentCount?.takeIf { it.isNotEmpty() }
?: "${video.firstComment!!.third}+"
binding.cardComments.setOnClickListener {
activity.player.setSheets(details = false, comments = true)
}
} else {
binding.spinnerComments.visibility = View.GONE
binding.textCommentsLoading.setText(R.string.comments_loading_fail)
}
}

Glide
.with(activity)
.load(video.channel.avatar)
.into(binding.channelAvatar)

binding.buttonComments.setOnClickListener {
activity.getPlayer().setSheets(details = false, comments = true)
}
binding.videoDetails.setOnClickListener {
activity.getPlayer().setSheets(details = true, comments = false)
}
Expand Down
Loading

0 comments on commit 739d0bf

Please sign in to comment.