mirror of
https://github.com/TeamNewPipe/NewPipe
synced 2026-02-05 09:40:17 +00:00
Compare commits
8 Commits
refactor
...
frankenpip
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6c3f31a721 | ||
|
|
10163e1082 | ||
|
|
0911d1ce7d | ||
|
|
df3b56ed63 | ||
|
|
cf351c28b0 | ||
|
|
4409a990de | ||
|
|
16b372dece | ||
|
|
c02fb89359 |
@@ -42,7 +42,7 @@ android {
|
|||||||
|
|
||||||
// suffix the app id and the app name with git branch name
|
// suffix the app id and the app name with git branch name
|
||||||
def workingBranch = getGitWorkingBranch()
|
def workingBranch = getGitWorkingBranch()
|
||||||
def normalizedWorkingBranch = workingBranch.replaceFirst("^[^A-Za-z]+", "").replaceAll("[^0-9A-Za-z]+", "")
|
def normalizedWorkingBranch = ""
|
||||||
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
|
if (normalizedWorkingBranch.isEmpty() || workingBranch == "master" || workingBranch == "dev") {
|
||||||
// default values when branch name could not be determined or is master or dev
|
// default values when branch name could not be determined or is master or dev
|
||||||
applicationIdSuffix ".debug"
|
applicationIdSuffix ".debug"
|
||||||
@@ -88,6 +88,11 @@ android {
|
|||||||
|
|
||||||
kotlinOptions {
|
kotlinOptions {
|
||||||
jvmTarget = JavaVersion.VERSION_17
|
jvmTarget = JavaVersion.VERSION_17
|
||||||
|
freeCompilerArgs += [
|
||||||
|
// Generate default method implementations for interfaces
|
||||||
|
// https://kotlinlang.org/docs/java-to-kotlin-interop.html#default-methods-in-interfaces
|
||||||
|
'-Xjvm-default=all'
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
sourceSets {
|
sourceSets {
|
||||||
@@ -168,7 +173,8 @@ afterEvaluate {
|
|||||||
if (!System.properties.containsKey('skipFormatKtlint')) {
|
if (!System.properties.containsKey('skipFormatKtlint')) {
|
||||||
preDebugBuild.dependsOn formatKtlint
|
preDebugBuild.dependsOn formatKtlint
|
||||||
}
|
}
|
||||||
preDebugBuild.dependsOn runCheckstyle, runKtlint, checkDependenciesOrder
|
// preDebugBuild.dependsOn runCheckstyle,
|
||||||
|
preDebugBuild.dependsOn runKtlint, checkDependenciesOrder
|
||||||
}
|
}
|
||||||
|
|
||||||
sonar {
|
sonar {
|
||||||
@@ -199,6 +205,8 @@ dependencies {
|
|||||||
implementation libs.teamnewpipe.newpipe.extractor
|
implementation libs.teamnewpipe.newpipe.extractor
|
||||||
implementation libs.teamnewpipe.nononsense.filepicker
|
implementation libs.teamnewpipe.nononsense.filepicker
|
||||||
|
|
||||||
|
implementation 'com.github.TeamNewPipe:NewPlayer'
|
||||||
|
|
||||||
/** Checkstyle **/
|
/** Checkstyle **/
|
||||||
checkstyle libs.tools.checkstyle
|
checkstyle libs.tools.checkstyle
|
||||||
ktlint libs.tools.ktlint
|
ktlint libs.tools.ktlint
|
||||||
@@ -226,6 +234,9 @@ dependencies {
|
|||||||
implementation libs.androidx.work.runtime
|
implementation libs.androidx.work.runtime
|
||||||
implementation libs.androidx.work.rxjava3
|
implementation libs.androidx.work.rxjava3
|
||||||
implementation libs.androidx.material
|
implementation libs.androidx.material
|
||||||
|
implementation libs.androidx.media3.common
|
||||||
|
implementation libs.androidx.media3.exoplayer
|
||||||
|
implementation libs.androidx.media3.ui
|
||||||
|
|
||||||
/** Third-party libraries **/
|
/** Third-party libraries **/
|
||||||
// Instance state boilerplate elimination
|
// Instance state boilerplate elimination
|
||||||
|
|||||||
@@ -94,6 +94,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
import dagger.hilt.android.AndroidEntryPoint;
|
||||||
|
|
||||||
|
@AndroidEntryPoint
|
||||||
public class MainActivity extends AppCompatActivity {
|
public class MainActivity extends AppCompatActivity {
|
||||||
private static final String TAG = "MainActivity";
|
private static final String TAG = "MainActivity";
|
||||||
@SuppressWarnings("ConstantConditions")
|
@SuppressWarnings("ConstantConditions")
|
||||||
|
|||||||
268
app/src/main/java/org/schabi/newpipe/NewPlayerComponent.kt
Normal file
268
app/src/main/java/org/schabi/newpipe/NewPlayerComponent.kt
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
/* NewPlayer
|
||||||
|
*
|
||||||
|
* @author Christian Schabesberger
|
||||||
|
*
|
||||||
|
* Copyright (C) NewPipe e.V. 2024 <code(at)newpipe-ev.de>
|
||||||
|
*
|
||||||
|
* NewPlayer 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 3 of the License, or
|
||||||
|
* (at your option) any later version.
|
||||||
|
*
|
||||||
|
* NewPlayer 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 NewPlayer. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package net.newpipe.newplayer.testapp
|
||||||
|
|
||||||
|
import android.app.Application
|
||||||
|
import android.graphics.Bitmap
|
||||||
|
import android.graphics.BitmapFactory
|
||||||
|
import android.net.Uri
|
||||||
|
import android.util.Log
|
||||||
|
import androidx.annotation.OptIn
|
||||||
|
import androidx.core.graphics.drawable.IconCompat
|
||||||
|
import androidx.media3.common.MediaMetadata
|
||||||
|
import androidx.media3.common.util.UnstableApi
|
||||||
|
import dagger.Module
|
||||||
|
import dagger.Provides
|
||||||
|
import dagger.hilt.InstallIn
|
||||||
|
import dagger.hilt.components.SingletonComponent
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
import kotlinx.coroutines.withContext
|
||||||
|
import net.newpipe.newplayer.NewPlayer
|
||||||
|
import net.newpipe.newplayer.NewPlayerImpl
|
||||||
|
import net.newpipe.newplayer.data.AudioStreamTrack
|
||||||
|
import net.newpipe.newplayer.data.Chapter
|
||||||
|
import net.newpipe.newplayer.data.Stream
|
||||||
|
import net.newpipe.newplayer.data.Subtitle
|
||||||
|
import net.newpipe.newplayer.data.VideoStreamTrack
|
||||||
|
import net.newpipe.newplayer.repository.CachingRepository
|
||||||
|
import net.newpipe.newplayer.repository.MediaRepository
|
||||||
|
import net.newpipe.newplayer.repository.PrefetchingRepository
|
||||||
|
import okhttp3.OkHttpClient
|
||||||
|
import okhttp3.Request
|
||||||
|
import org.schabi.newpipe.App
|
||||||
|
import org.schabi.newpipe.MainActivity
|
||||||
|
import org.schabi.newpipe.extractor.ServiceList
|
||||||
|
import org.schabi.newpipe.extractor.services.media_ccc.extractors.MediaCCCStreamExtractor
|
||||||
|
import org.schabi.newpipe.extractor.services.media_ccc.extractors.data.MediaCCCRecording
|
||||||
|
import javax.inject.Singleton
|
||||||
|
|
||||||
|
@Module
|
||||||
|
@InstallIn(SingletonComponent::class)
|
||||||
|
object NewPlayerComponent {
|
||||||
|
@Provides
|
||||||
|
@Singleton
|
||||||
|
fun provideNewPlayer(app: Application): NewPlayer {
|
||||||
|
val player = NewPlayerImpl(
|
||||||
|
app = app,
|
||||||
|
repository = PrefetchingRepository(CachingRepository(MediaCCCTestRepository())),
|
||||||
|
notificationIcon = IconCompat.createWithResource(app, net.newpipe.newplayer.R.drawable.new_player_tiny_icon),
|
||||||
|
playerActivityClass = MainActivity::class.java,
|
||||||
|
// rescueStreamFault = …
|
||||||
|
)
|
||||||
|
if (app is App) {
|
||||||
|
CoroutineScope(Dispatchers.IO).launch {
|
||||||
|
while (true) {
|
||||||
|
player.errorFlow.collect { e ->
|
||||||
|
Log.e("NewPlayerException", e.stackTraceToString())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return player
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class TestMediaRepository() : MediaRepository {
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
|
override fun getRepoInfo() =
|
||||||
|
MediaRepository.RepoMetaInfo(canHandleTimestampedLinks = true, pullsDataFromNetwork = true)
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
override suspend fun getMetaInfo(item: String): MediaMetadata =
|
||||||
|
MediaMetadata.Builder()
|
||||||
|
.setTitle("BGP and the rule of bla")
|
||||||
|
.setArtist("mr BGP")
|
||||||
|
.setArtworkUri(Uri.parse("https://static.media.ccc.de/media/congress/2017/9072-hd.jpg"))
|
||||||
|
.setDurationMs(
|
||||||
|
1871L * 1000L
|
||||||
|
)
|
||||||
|
.build()
|
||||||
|
|
||||||
|
override suspend fun getStreams(item: String): List<Stream> {
|
||||||
|
return listOf(
|
||||||
|
Stream(
|
||||||
|
item = "bgp",
|
||||||
|
streamUri = Uri.parse("https://cdn.media.ccc.de/congress/2017/h264-hd/34c3-9072-eng-BGP_and_the_Rule_of_Custom.mp4"),
|
||||||
|
mimeType = null,
|
||||||
|
streamTracks = listOf(
|
||||||
|
AudioStreamTrack(
|
||||||
|
bitrate = 480000,
|
||||||
|
fileFormat = "MPEG4",
|
||||||
|
language = "en"
|
||||||
|
),
|
||||||
|
VideoStreamTrack(
|
||||||
|
width = 1920,
|
||||||
|
height = 1080,
|
||||||
|
frameRate = 25,
|
||||||
|
fileFormat = "MPEG4"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSubtitles(item: String) =
|
||||||
|
emptyList<Subtitle>()
|
||||||
|
|
||||||
|
override suspend fun getPreviewThumbnail(item: String, timestampInMs: Long): Bitmap? {
|
||||||
|
|
||||||
|
val templateUrl = "https://static.media.ccc.de/media/congress/2017/9072-hd.jpg"
|
||||||
|
|
||||||
|
val thumbnailId = (timestampInMs / (10 * 1000)) + 1
|
||||||
|
|
||||||
|
if (getPreviewThumbnailsInfo(item).count < thumbnailId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val thumbUrl = String.format(templateUrl, thumbnailId)
|
||||||
|
|
||||||
|
val bitmap = withContext(Dispatchers.IO) {
|
||||||
|
val request = Request.Builder().url(thumbUrl).build()
|
||||||
|
val response = client.newCall(request).execute()
|
||||||
|
try {
|
||||||
|
val responseBody = response.body
|
||||||
|
val bitmap = BitmapFactory.decodeStream(responseBody?.byteStream())
|
||||||
|
return@withContext bitmap
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getPreviewThumbnailsInfo(item: String) =
|
||||||
|
MediaRepository.PreviewThumbnailsInfo(0, 0)
|
||||||
|
|
||||||
|
override suspend fun getChapters(item: String) =
|
||||||
|
listOf<Chapter>()
|
||||||
|
|
||||||
|
override suspend fun getTimestampLink(item: String, timestampInSeconds: Long) =
|
||||||
|
""
|
||||||
|
}
|
||||||
|
|
||||||
|
class MediaCCCTestRepository() : MediaRepository {
|
||||||
|
private val client = OkHttpClient()
|
||||||
|
|
||||||
|
private val service = ServiceList.MediaCCC
|
||||||
|
|
||||||
|
suspend fun fetchPage(item: String): MediaCCCStreamExtractor {
|
||||||
|
return withContext(Dispatchers.IO) {
|
||||||
|
// TODO: handle MediaCCCLiveStreamExtractor as well
|
||||||
|
val extractor = service.getStreamExtractor(item) as MediaCCCStreamExtractor
|
||||||
|
extractor.fetchPage()
|
||||||
|
extractor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getRepoInfo() =
|
||||||
|
MediaRepository.RepoMetaInfo(canHandleTimestampedLinks = true, pullsDataFromNetwork = true)
|
||||||
|
|
||||||
|
@OptIn(UnstableApi::class)
|
||||||
|
override suspend fun getMetaInfo(item: String): MediaMetadata {
|
||||||
|
val extractor = fetchPage(item)
|
||||||
|
return MediaMetadata.Builder().apply {
|
||||||
|
setTitle(extractor.name)
|
||||||
|
setArtist(extractor.subChannelName)
|
||||||
|
setDurationMs(
|
||||||
|
extractor.length * 1000L
|
||||||
|
)
|
||||||
|
extractor.thumbnails.firstOrNull()?.url?.let {
|
||||||
|
setArtworkUri(Uri.parse(it))
|
||||||
|
}
|
||||||
|
}.build()
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getStreams(item: String): List<Stream> {
|
||||||
|
val extractor = fetchPage(item)
|
||||||
|
return extractor.recordings.filterIsInstance<MediaCCCRecording.Video>()
|
||||||
|
.filter { it.recordingType == MediaCCCRecording.VideoType.MAIN }
|
||||||
|
.map { track ->
|
||||||
|
Stream(
|
||||||
|
item = item,
|
||||||
|
streamUri = Uri.parse(track.url),
|
||||||
|
streamTracks =
|
||||||
|
listOf(
|
||||||
|
VideoStreamTrack(
|
||||||
|
width = track.width,
|
||||||
|
height = track.height,
|
||||||
|
fileFormat = track.mimeType
|
||||||
|
),
|
||||||
|
) +
|
||||||
|
// one audio track per language
|
||||||
|
// (TODO: probably don’t need to attach the audio track here?)
|
||||||
|
track.languages.map { language ->
|
||||||
|
AudioStreamTrack(
|
||||||
|
// TODO: should we pass the Locale instead??
|
||||||
|
language = language.language,
|
||||||
|
fileFormat = track.mimeType,
|
||||||
|
// TODO: that’s something ExoPlayer should determine for us,
|
||||||
|
// we don’t know that from the metadata
|
||||||
|
bitrate = 44100,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getSubtitles(item: String) =
|
||||||
|
emptyList<Subtitle>()
|
||||||
|
|
||||||
|
override suspend fun getPreviewThumbnail(item: String, timestampInMs: Long): Bitmap? {
|
||||||
|
val extractor = fetchPage(item)
|
||||||
|
|
||||||
|
val templateUrl = extractor.thumbnails.firstOrNull()?.url ?: return null
|
||||||
|
|
||||||
|
val thumbnailId = (timestampInMs / (10 * 1000)) + 1
|
||||||
|
|
||||||
|
if (getPreviewThumbnailsInfo(item).count < thumbnailId) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
val thumbUrl = String.format(templateUrl, thumbnailId)
|
||||||
|
|
||||||
|
val bitmap = withContext(Dispatchers.IO) {
|
||||||
|
val request = Request.Builder().url(thumbUrl).build()
|
||||||
|
val response = client.newCall(request).execute()
|
||||||
|
try {
|
||||||
|
val responseBody = response.body
|
||||||
|
val bitmap = BitmapFactory.decodeStream(responseBody?.byteStream())
|
||||||
|
return@withContext bitmap
|
||||||
|
} catch (e: Exception) {
|
||||||
|
return@withContext null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return bitmap
|
||||||
|
}
|
||||||
|
|
||||||
|
override suspend fun getPreviewThumbnailsInfo(item: String) =
|
||||||
|
MediaRepository.PreviewThumbnailsInfo(1, 0)
|
||||||
|
|
||||||
|
override suspend fun getChapters(item: String) =
|
||||||
|
listOf<Chapter>()
|
||||||
|
|
||||||
|
override suspend fun getTimestampLink(item: String, timestampInSeconds: Long) =
|
||||||
|
""
|
||||||
|
}
|
||||||
File diff suppressed because it is too large
Load Diff
36
app/src/main/java/org/schabi/newpipe/util/JavaFlow.kt
Normal file
36
app/src/main/java/org/schabi/newpipe/util/JavaFlow.kt
Normal file
@@ -0,0 +1,36 @@
|
|||||||
|
package org.schabi.newpipe.util
|
||||||
|
|
||||||
|
import kotlinx.coroutines.CoroutineScope
|
||||||
|
import kotlinx.coroutines.Dispatchers
|
||||||
|
import kotlinx.coroutines.cancel
|
||||||
|
import kotlinx.coroutines.flow.Flow
|
||||||
|
import kotlinx.coroutines.flow.onCompletion
|
||||||
|
import kotlinx.coroutines.flow.onStart
|
||||||
|
import kotlinx.coroutines.launch
|
||||||
|
|
||||||
|
class JavaFlow<T>(
|
||||||
|
private val coroutineScope: CoroutineScope = CoroutineScope(Dispatchers.Default)
|
||||||
|
) {
|
||||||
|
|
||||||
|
interface OperatorCallback <T> {
|
||||||
|
fun onStart() = Unit
|
||||||
|
fun onCompletion(thr: Throwable?) = Unit
|
||||||
|
fun onResult(result: T)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun collect(
|
||||||
|
flow: Flow<T>,
|
||||||
|
operatorCallback: OperatorCallback<T>,
|
||||||
|
) {
|
||||||
|
coroutineScope.launch {
|
||||||
|
flow
|
||||||
|
.onStart { operatorCallback.onStart() }
|
||||||
|
.onCompletion { operatorCallback.onCompletion(it) }
|
||||||
|
.collect { operatorCallback.onResult(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun close() {
|
||||||
|
coroutineScope.cancel()
|
||||||
|
}
|
||||||
|
}
|
||||||
7
app/src/main/res/layout/fragment_newplayer_view.xml
Normal file
7
app/src/main/res/layout/fragment_newplayer_view.xml
Normal file
@@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<net.newpipe.newplayer.ui.NewPlayerView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:id="@+id/embedded_player_newplayer"
|
||||||
|
android:name="net.newpipe.newplayer.VideoPlayerFragment"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:minHeight="50dp" />
|
||||||
@@ -598,110 +598,110 @@
|
|||||||
|
|
||||||
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
</androidx.coordinatorlayout.widget.CoordinatorLayout>
|
||||||
|
|
||||||
<RelativeLayout
|
<!-- <RelativeLayout-->
|
||||||
android:id="@+id/overlay_layout"
|
<!-- android:id="@+id/overlay_layout"-->
|
||||||
android:layout_width="match_parent"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="match_parent"
|
<!-- android:layout_height="match_parent"-->
|
||||||
android:alpha="0.9"
|
<!-- android:alpha="0.9"-->
|
||||||
android:background="?attr/windowBackground">
|
<!-- android:background="?attr/windowBackground">-->
|
||||||
|
|
||||||
<ImageButton
|
<!-- <ImageButton-->
|
||||||
android:id="@+id/overlay_thumbnail"
|
<!-- android:id="@+id/overlay_thumbnail"-->
|
||||||
android:layout_width="62dp"
|
<!-- android:layout_width="62dp"-->
|
||||||
android:layout_height="60dp"
|
<!-- android:layout_height="60dp"-->
|
||||||
android:layout_alignParentStart="true"
|
<!-- android:layout_alignParentStart="true"-->
|
||||||
android:background="@color/transparent_background_color"
|
<!-- android:background="@color/transparent_background_color"-->
|
||||||
android:gravity="center_vertical"
|
<!-- android:gravity="center_vertical"-->
|
||||||
android:paddingLeft="@dimen/video_item_search_padding"
|
<!-- android:paddingLeft="@dimen/video_item_search_padding"-->
|
||||||
android:paddingRight="@dimen/video_item_search_padding"
|
<!-- android:paddingRight="@dimen/video_item_search_padding"-->
|
||||||
android:scaleType="fitCenter"
|
<!-- android:scaleType="fitCenter"-->
|
||||||
tools:ignore="ContentDescription" />
|
<!-- tools:ignore="ContentDescription" />-->
|
||||||
|
|
||||||
<LinearLayout
|
<!-- <LinearLayout-->
|
||||||
android:id="@+id/overlay_metadata_layout"
|
<!-- android:id="@+id/overlay_metadata_layout"-->
|
||||||
android:layout_width="match_parent"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="60dp"
|
<!-- android:layout_height="60dp"-->
|
||||||
android:layout_toStartOf="@+id/overlay_buttons_layout"
|
<!-- android:layout_toStartOf="@+id/overlay_buttons_layout"-->
|
||||||
android:layout_toEndOf="@+id/overlay_thumbnail"
|
<!-- android:layout_toEndOf="@+id/overlay_thumbnail"-->
|
||||||
android:clickable="true"
|
<!-- android:clickable="true"-->
|
||||||
android:focusable="true"
|
<!-- android:focusable="true"-->
|
||||||
android:gravity="center_vertical"
|
<!-- android:gravity="center_vertical"-->
|
||||||
android:orientation="vertical"
|
<!-- android:orientation="vertical"-->
|
||||||
android:theme="@style/ContrastTintTheme"
|
<!-- android:theme="@style/ContrastTintTheme"-->
|
||||||
tools:ignore="RtlHardcoded">
|
<!-- tools:ignore="RtlHardcoded">-->
|
||||||
|
|
||||||
<org.schabi.newpipe.views.NewPipeTextView
|
<!-- <org.schabi.newpipe.views.NewPipeTextView-->
|
||||||
android:id="@+id/overlay_title_text_view"
|
<!-- android:id="@+id/overlay_title_text_view"-->
|
||||||
android:layout_width="match_parent"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="wrap_content"
|
<!-- android:layout_height="wrap_content"-->
|
||||||
android:ellipsize="marquee"
|
<!-- android:ellipsize="marquee"-->
|
||||||
android:fadingEdge="horizontal"
|
<!-- android:fadingEdge="horizontal"-->
|
||||||
android:marqueeRepeatLimit="marquee_forever"
|
<!-- android:marqueeRepeatLimit="marquee_forever"-->
|
||||||
android:scrollHorizontally="true"
|
<!-- android:scrollHorizontally="true"-->
|
||||||
android:singleLine="true"
|
<!-- android:singleLine="true"-->
|
||||||
android:textAppearance="?android:attr/textAppearanceLarge"
|
<!-- android:textAppearance="?android:attr/textAppearanceLarge"-->
|
||||||
android:textSize="@dimen/video_item_search_title_text_size"
|
<!-- android:textSize="@dimen/video_item_search_title_text_size"-->
|
||||||
tools:ignore="RtlHardcoded"
|
<!-- tools:ignore="RtlHardcoded"-->
|
||||||
tools:text="The Video Title LONG very LONVideo Title LONG very LONG" />
|
<!-- tools:text="The Video Title LONG very LONVideo Title LONG very LONG" />-->
|
||||||
|
|
||||||
<org.schabi.newpipe.views.NewPipeTextView
|
<!-- <org.schabi.newpipe.views.NewPipeTextView-->
|
||||||
android:id="@+id/overlay_channel_text_view"
|
<!-- android:id="@+id/overlay_channel_text_view"-->
|
||||||
android:layout_width="match_parent"
|
<!-- android:layout_width="match_parent"-->
|
||||||
android:layout_height="wrap_content"
|
<!-- android:layout_height="wrap_content"-->
|
||||||
android:ellipsize="marquee"
|
<!-- android:ellipsize="marquee"-->
|
||||||
android:fadingEdge="horizontal"
|
<!-- android:fadingEdge="horizontal"-->
|
||||||
android:marqueeRepeatLimit="marquee_forever"
|
<!-- android:marqueeRepeatLimit="marquee_forever"-->
|
||||||
android:scrollHorizontally="true"
|
<!-- android:scrollHorizontally="true"-->
|
||||||
android:singleLine="true"
|
<!-- android:singleLine="true"-->
|
||||||
android:textAppearance="?android:attr/textAppearanceSmall"
|
<!-- android:textAppearance="?android:attr/textAppearanceSmall"-->
|
||||||
android:textSize="@dimen/video_item_search_uploader_text_size"
|
<!-- android:textSize="@dimen/video_item_search_uploader_text_size"-->
|
||||||
tools:text="The Video Artist LONG very LONG very Long" />
|
<!-- tools:text="The Video Artist LONG very LONG very Long" />-->
|
||||||
|
|
||||||
</LinearLayout>
|
<!-- </LinearLayout>-->
|
||||||
|
|
||||||
<LinearLayout
|
<!-- <LinearLayout-->
|
||||||
android:id="@+id/overlay_buttons_layout"
|
<!-- android:id="@+id/overlay_buttons_layout"-->
|
||||||
android:layout_width="wrap_content"
|
<!-- android:layout_width="wrap_content"-->
|
||||||
android:layout_height="60dp"
|
<!-- android:layout_height="60dp"-->
|
||||||
android:layout_alignParentEnd="true"
|
<!-- android:layout_alignParentEnd="true"-->
|
||||||
android:gravity="center_vertical"
|
<!-- android:gravity="center_vertical"-->
|
||||||
android:theme="@style/ContrastTintTheme"
|
<!-- android:theme="@style/ContrastTintTheme"-->
|
||||||
tools:ignore="RtlHardcoded">
|
<!-- tools:ignore="RtlHardcoded">-->
|
||||||
|
|
||||||
<ImageButton
|
<!-- <ImageButton-->
|
||||||
android:id="@+id/overlay_play_queue_button"
|
<!-- android:id="@+id/overlay_play_queue_button"-->
|
||||||
android:layout_width="40dp"
|
<!-- android:layout_width="40dp"-->
|
||||||
android:layout_height="match_parent"
|
<!-- android:layout_height="match_parent"-->
|
||||||
android:background="?attr/selectableItemBackground"
|
<!-- android:background="?attr/selectableItemBackground"-->
|
||||||
android:contentDescription="@string/title_activity_play_queue"
|
<!-- android:contentDescription="@string/title_activity_play_queue"-->
|
||||||
android:scaleType="center"
|
<!-- android:scaleType="center"-->
|
||||||
android:src="@drawable/ic_list"
|
<!-- android:src="@drawable/ic_list"-->
|
||||||
tools:ignore="RtlHardcoded" />
|
<!-- tools:ignore="RtlHardcoded" />-->
|
||||||
|
|
||||||
<ImageButton
|
<!-- <ImageButton-->
|
||||||
android:id="@+id/overlay_play_pause_button"
|
<!-- android:id="@+id/overlay_play_pause_button"-->
|
||||||
android:layout_width="40dp"
|
<!-- android:layout_width="40dp"-->
|
||||||
android:layout_height="match_parent"
|
<!-- android:layout_height="match_parent"-->
|
||||||
android:background="?attr/selectableItemBackground"
|
<!-- android:background="?attr/selectableItemBackground"-->
|
||||||
android:contentDescription="@string/pause"
|
<!-- android:contentDescription="@string/pause"-->
|
||||||
android:focusable="true"
|
<!-- android:focusable="true"-->
|
||||||
android:focusedByDefault="true"
|
<!-- android:focusedByDefault="true"-->
|
||||||
android:scaleType="center"
|
<!-- android:scaleType="center"-->
|
||||||
android:src="@drawable/ic_play_arrow" />
|
<!-- android:src="@drawable/ic_play_arrow" />-->
|
||||||
|
|
||||||
<ImageButton
|
<!-- <ImageButton-->
|
||||||
android:id="@+id/overlay_close_button"
|
<!-- android:id="@+id/overlay_close_button"-->
|
||||||
android:layout_width="48dp"
|
<!-- android:layout_width="48dp"-->
|
||||||
android:layout_height="match_parent"
|
<!-- android:layout_height="match_parent"-->
|
||||||
android:background="?attr/selectableItemBackground"
|
<!-- android:background="?attr/selectableItemBackground"-->
|
||||||
android:contentDescription="@string/close"
|
<!-- android:contentDescription="@string/close"-->
|
||||||
android:paddingRight="8dp"
|
<!-- android:paddingRight="8dp"-->
|
||||||
android:scaleType="center"
|
<!-- android:scaleType="center"-->
|
||||||
android:src="@drawable/ic_close"
|
<!-- android:src="@drawable/ic_close"-->
|
||||||
tools:ignore="RtlSymmetry" />
|
<!-- tools:ignore="RtlSymmetry" />-->
|
||||||
|
|
||||||
</LinearLayout>
|
<!-- </LinearLayout>-->
|
||||||
|
|
||||||
</RelativeLayout>
|
<!-- </RelativeLayout>-->
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
||||||
|
|||||||
@@ -17,6 +17,10 @@ buildscript {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
id 'com.google.dagger.hilt.android' version '2.52' apply false
|
||||||
|
}
|
||||||
|
|
||||||
allprojects {
|
allprojects {
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ localbroadcastmanager = "1.1.0"
|
|||||||
markwon = "4.6.2"
|
markwon = "4.6.2"
|
||||||
material = "1.11.0"
|
material = "1.11.0"
|
||||||
media = "1.7.0"
|
media = "1.7.0"
|
||||||
|
media3 = "1.3.1"
|
||||||
mockitoCore = "5.6.0"
|
mockitoCore = "5.6.0"
|
||||||
navigationCompose = "2.8.3"
|
navigationCompose = "2.8.3"
|
||||||
okhttp = "4.12.0"
|
okhttp = "4.12.0"
|
||||||
@@ -96,6 +97,9 @@ androidx-lifecycle-viewmodel-compose = { group = "androidx.lifecycle", name = "l
|
|||||||
androidx-localbroadcastmanager = { group = "androidx.localbroadcastmanager", name = "localbroadcastmanager", version.ref = "localbroadcastmanager" }
|
androidx-localbroadcastmanager = { group = "androidx.localbroadcastmanager", name = "localbroadcastmanager", version.ref = "localbroadcastmanager" }
|
||||||
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
androidx-material = { group = "com.google.android.material", name = "material", version.ref = "material" }
|
||||||
androidx-media = { group = "androidx.media", name = "media", version.ref = "media" }
|
androidx-media = { group = "androidx.media", name = "media", version.ref = "media" }
|
||||||
|
androidx-media3-common = { group = "androidx.media3", name = "media3-common", version.ref = "media3" }
|
||||||
|
androidx-media3-exoplayer = { group = "androidx.media3", name = "media3-exoplayer", version.ref = "media3" }
|
||||||
|
androidx-media3-ui = { group = "androidx.media3", name = "media3-ui", version.ref = "media3" }
|
||||||
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
androidx-navigation-compose = { group = "androidx.navigation", name = "navigation-compose", version.ref = "navigationCompose" }
|
||||||
androidx-paging-compose = { group = "androidx.paging", name = "paging-compose", version.ref = "pagingCompose" }
|
androidx-paging-compose = { group = "androidx.paging", name = "paging-compose", version.ref = "pagingCompose" }
|
||||||
androidx-preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
|
androidx-preference = { group = "androidx.preference", name = "preference", version.ref = "preference" }
|
||||||
|
|||||||
@@ -4,8 +4,15 @@ include ':app'
|
|||||||
// We assume, that NewPipe and NewPipe Extractor have the same parent directory.
|
// We assume, that NewPipe and NewPipe Extractor have the same parent directory.
|
||||||
// If this is not the case, please change the path in includeBuild().
|
// If this is not the case, please change the path in includeBuild().
|
||||||
|
|
||||||
//includeBuild('../NewPipeExtractor') {
|
includeBuild('../NewPipeExtractor') {
|
||||||
// dependencySubstitution {
|
dependencySubstitution {
|
||||||
// substitute module('com.github.TeamNewPipe:NewPipeExtractor') using project(':extractor')
|
substitute module('com.github.TeamNewPipe:NewPipeExtractor') using project(':extractor')
|
||||||
// }
|
}
|
||||||
//}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
includeBuild('../NewPlayer') {
|
||||||
|
dependencySubstitution {
|
||||||
|
substitute module('com.github.TeamNewPipe:NewPlayer') using project(':new-player')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user