diff --git a/library/build.gradle.kts b/library/build.gradle.kts index 1652970a617..4eeb9318343 100644 --- a/library/build.gradle.kts +++ b/library/build.gradle.kts @@ -20,6 +20,8 @@ val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) kotlin { version = "1.0.1" + applyDefaultHierarchyTemplate() + android { // If this is the same com.lagradost.cloudstream3.R stops working namespace = "com.lagradost.api" @@ -73,15 +75,15 @@ kotlin { implementation(libs.kotlin.test) } - // We will eventually add a new jvmCommonMain source set - // for things shared between Android and JVM. - androidMain.dependencies { - implementation(libs.newpipeextractor) + val jvmCommonMain by creating { + dependsOn(commonMain.get()) + dependencies { + implementation(libs.newpipeextractor) + } } - jvmMain.dependencies { - implementation(libs.newpipeextractor) - } + androidMain { dependsOn(jvmCommonMain) } + jvmMain { dependsOn(jvmCommonMain) } } } diff --git a/library/src/androidMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.android.kt b/library/src/jvmCommonMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.jvmCommon.kt similarity index 100% rename from library/src/androidMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.android.kt rename to library/src/jvmCommonMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.jvmCommon.kt diff --git a/library/src/jvmMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.jvm.kt b/library/src/jvmMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.jvm.kt deleted file mode 100644 index 345aa7185f0..00000000000 --- a/library/src/jvmMain/kotlin/com/lagradost/cloudstream3/extractors/YoutubeExtractor.jvm.kt +++ /dev/null @@ -1,105 +0,0 @@ -package com.lagradost.cloudstream3.extractors - -import com.lagradost.cloudstream3.SubtitleFile -import com.lagradost.cloudstream3.newAudioFile -import com.lagradost.cloudstream3.newSubtitleFile -import com.lagradost.cloudstream3.utils.ExtractorApi -import com.lagradost.cloudstream3.utils.ExtractorLink -import com.lagradost.cloudstream3.utils.ExtractorLinkType -import com.lagradost.cloudstream3.utils.newExtractorLink -import org.schabi.newpipe.extractor.stream.StreamInfo -import org.schabi.newpipe.extractor.stream.StreamType - -actual open class YoutubeExtractor actual constructor() : ExtractorApi() { - - actual override val mainUrl = "https://www.youtube.com" - actual override val name = "YouTube" - actual override val requiresReferer = false - - actual override suspend fun getUrl( - url: String, - referer: String?, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, - ) { - val videoId = extractYouTubeId(url) - val watchUrl = "$mainUrl/watch?v=$videoId" - - val info = StreamInfo.getInfo(watchUrl) - val isLive = info.streamType == StreamType.LIVE_STREAM - || info.streamType == StreamType.AUDIO_LIVE_STREAM - || info.streamType == StreamType.POST_LIVE_STREAM - || info.streamType == StreamType.POST_LIVE_AUDIO_STREAM - - if (isLive && info.hlsUrl != null) { - callback( - newExtractorLink( - source = name, - name = "YouTube Live", - url = info.hlsUrl - ) { - type = ExtractorLinkType.M3U8 - } - ) - } else { - processVideo(info, subtitleCallback, callback) - } - } - - private suspend fun processVideo( - info: StreamInfo, - subtitleCallback: (SubtitleFile) -> Unit, - callback: (ExtractorLink) -> Unit, - ): Boolean { - val videoStreams = info.videoOnlyStreams.orEmpty() - if (videoStreams.isEmpty()) return false - - val audioStreams = info.audioStreams.orEmpty() - videoStreams.forEach { video -> - callback( - newExtractorLink( - source = name, - name = "YouTube ${normalizeCodec(video.codec)}", - url = video.content - ) { - quality = video.height - audioTracks = audioStreams.map { newAudioFile(it.content) } - } - ) - } - - info.subtitles.forEach { subtitle -> - subtitleCallback( - newSubtitleFile( - lang = subtitle.displayLanguageName - ?: subtitle.languageTag - ?: "Unknown", - url = subtitle.content - ) - ) - } - - return true - } - - private fun extractYouTubeId(url: String): String { - val regex = Regex( - "(?:youtu\\.be/|youtube(?:-nocookie)?\\.com/(?:.*v=|v/|u/\\w/|embed/|shorts/|live/))([\\w-]{11})" - ) - - return regex.find(url)?.groupValues?.get(1) - ?: throw IllegalArgumentException("Invalid YouTube URL: $url") - } - - private fun normalizeCodec(codec: String?): String { - if (codec.isNullOrBlank()) return "" - val c = codec.lowercase() - return when { - c.startsWith("av01") -> "AV1" - c.startsWith("vp9") -> "VP9" - c.startsWith("avc1") || c.startsWith("h264") -> "H264" - c.startsWith("hev1") || c.startsWith("hvc1") || c.startsWith("hevc") -> "H265" - else -> codec.substringBefore('.').uppercase() - } - } -}