import com.android.build.gradle.internal.cxx.configure.gradleLocalProperties import org.jetbrains.dokka.gradle.engine.parameters.KotlinPlatform import org.jetbrains.dokka.gradle.engine.parameters.VisibilityModifier import org.jetbrains.kotlin.gradle.dsl.JvmDefaultMode import org.jetbrains.kotlin.gradle.dsl.JvmTarget import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile plugins { alias(libs.plugins.android.application) alias(libs.plugins.dokka) alias(libs.plugins.kotlin.serialization) } val javaTarget = JvmTarget.fromTarget(libs.versions.jvmTarget.get()) abstract class GenerateGitHashTask : DefaultTask() { @get:InputFile @get:PathSensitive(PathSensitivity.RELATIVE) abstract val headFile: RegularFileProperty @get:InputDirectory @get:PathSensitive(PathSensitivity.RELATIVE) abstract val headsDir: DirectoryProperty @get:OutputDirectory abstract val outputDir: DirectoryProperty @TaskAction fun generate() { val head = headFile.get().asFile val hash = try { if (head.exists()) { // Read the commit hash from .git/HEAD val headContent = head.readText().trim() if (headContent.startsWith("ref:")) { val refPath = headContent.substring(5) // e.g., refs/heads/main val commitFile = File(head.parentFile, refPath) if (commitFile.exists()) commitFile.readText().trim() else "" } else headContent // If it's a detached HEAD (commit hash directly) } else "" // If .git/HEAD doesn't exist } catch (_: Throwable) { "" // Just set to an empty string if any exception occurs }.take(7) // Get the short commit hash val outFile = outputDir.file("git-hash.txt").get().asFile outFile.parentFile.mkdirs() outFile.writeText(hash) } } val generateGitHash = tasks.register("generateGitHash") { val gitDir = layout.projectDirectory.dir("../.git") headFile.set(gitDir.file("HEAD")) headsDir.set(gitDir.dir("refs/heads")) outputDir.set(layout.buildDirectory.dir("generated/git")) } android { @Suppress("UnstableApiUsage") testOptions { unitTests.isReturnDefaultValues = true } // Looks like google likes to add metadata only they can read https://gitlab.com/IzzyOnDroid/repo/-/work_items/491 dependenciesInfo { // Disables dependency metadata when building APKs. includeInApk = false // Disables dependency metadata when building Android App Bundles. includeInBundle = false } androidComponents { onVariants { variant -> variant.sources.assets?.addGeneratedSourceDirectory( generateGitHash, GenerateGitHashTask::outputDir ) } } signingConfigs { // We just use SIGNING_KEY_ALIAS here since it won't change // so won't kill the configuration cache. if (System.getenv("SIGNING_KEY_ALIAS") != null) { create("prerelease") { val tmpFilePath = System.getProperty("user.home") + "/work/_temp/keystore/" val prereleaseStoreFile: File? = File(tmpFilePath).listFiles()?.first() storeFile = prereleaseStoreFile?.let { file(it) } storePassword = System.getenv("SIGNING_STORE_PASSWORD") keyAlias = System.getenv("SIGNING_KEY_ALIAS") keyPassword = System.getenv("SIGNING_KEY_PASSWORD") } } } compileSdk = libs.versions.compileSdk.get().toInt() defaultConfig { applicationId = "com.lagradost.cloudstream3" minSdk = libs.versions.minSdk.get().toInt() targetSdk = libs.versions.targetSdk.get().toInt() versionCode = libs.versions.versionCode.get().toInt() versionName = libs.versions.versionName.get() manifestPlaceholders["target_sdk_version"] = libs.versions.targetSdk.get() // Reads local.properties val localProperties = gradleLocalProperties(rootDir, project.providers) buildConfigField( "long", "BUILD_DATE", "${System.currentTimeMillis()}" ) buildConfigField( "String", "SIMKL_CLIENT_ID", "\"" + (System.getenv("SIMKL_CLIENT_ID") ?: localProperties["simkl.id"]) + "\"" ) buildConfigField( "String", "SIMKL_CLIENT_SECRET", "\"" + (System.getenv("SIMKL_CLIENT_SECRET") ?: localProperties["simkl.secret"]) + "\"" ) testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } buildTypes { release { isDebuggable = false isMinifyEnabled = false isShrinkResources = false proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } debug { isDebuggable = true applicationIdSuffix = ".debug" proguardFiles( getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro" ) } } flavorDimensions.add("state") productFlavors { create("stable") { dimension = "state" } create("prerelease") { dimension = "state" applicationIdSuffix = ".prerelease" if (signingConfigs.names.contains("prerelease")) { signingConfig = signingConfigs.getByName("prerelease") } else { logger.warn("No prerelease signing config!") } versionNameSuffix = "-PRE" versionCode = (System.currentTimeMillis() / 60000).toInt() } } compileOptions { isCoreLibraryDesugaringEnabled = true sourceCompatibility = JavaVersion.toVersion(javaTarget.target) targetCompatibility = JavaVersion.toVersion(javaTarget.target) } java { // Use Java 17 toolchain even if a higher JDK runs the build. // We still use Java 8 for now which higher JDKs have deprecated. toolchain { languageVersion.set(JavaLanguageVersion.of(libs.versions.jdkToolchain.get())) } } lint { checkReleaseBuilds = false } buildFeatures { buildConfig = true viewBinding = true } packaging { jniLibs { // Enables legacy JNI packaging to reduce APK size (similar to builds before minSdk 23). // Note: This may increase app startup time slightly. useLegacyPackaging = true } } namespace = "com.lagradost.cloudstream3" } dependencies { // Testing testImplementation(libs.junit) testImplementation(libs.json) androidTestImplementation(libs.core) androidTestImplementation(libs.classgraph) androidTestImplementation(libs.espresso.core) androidTestImplementation(libs.ext.junit) androidTestImplementation(libs.instancio.core) androidTestImplementation(libs.junit.ktx) androidTestImplementation(libs.kotlin.test) // Android Core & Lifecycle implementation(libs.core.ktx) implementation(libs.activity.ktx) implementation(libs.annotation) implementation(libs.appcompat) implementation(libs.fragment.ktx) implementation(libs.bundles.lifecycle) implementation(libs.bundles.navigation) implementation(libs.kotlinx.collections.immutable) implementation(libs.kotlinx.serialization.json) // JSON Parser // Design & UI implementation(libs.preference.ktx) implementation(libs.material) implementation(libs.constraintlayout) // Coil Image Loading implementation(libs.bundles.coil) // Media 3 (ExoPlayer) implementation(libs.bundles.media3) implementation(libs.video) // FFmpeg Decoding implementation(libs.bundles.nextlib) // Anime-db for filler implementation(libs.anime.db) // PlayBack implementation(libs.colorpicker) // Subtitle Color Picker implementation(libs.newpipeextractor) // For Trailers implementation(libs.juniversalchardet) // Subtitle Decoding // UI Stuff implementation(libs.shimmer) // Shimmering Effect (Loading Skeleton) implementation(libs.palette.ktx) // Palette for Images -> Colors implementation(libs.tvprovider) implementation(libs.overlappingpanels) // Gestures implementation(libs.biometric) // Fingerprint Authentication implementation(libs.previewseekbar.media3) // SeekBar Preview implementation(libs.qrcode.kotlin) // QR Code for PIN Auth on TV // Extensions & Other Libs implementation(libs.jsoup) // HTML Parser implementation(libs.rhino) // Run JavaScript implementation(libs.safefile) // To Prevent the URI File Fu*kery coreLibraryDesugaring(libs.desugar.jdk.libs.nio) // NIO Flavor Needed for NewPipeExtractor implementation(libs.conscrypt.android) // To Fix SSL Fu*kery on Android 9 implementation(libs.jackson.module.kotlin) // JSON Parser implementation(libs.zipline) // Deprecated; will be removed once extensions have time to migrate from using it implementation("me.xdrop:fuzzywuzzy:1.4.0") // Torrent Support implementation(libs.torrentserver) // Downloading & Networking implementation(libs.work.runtime.ktx) implementation(libs.nicehttp) // HTTP Lib implementation(project(":library")) } tasks.register("androidSourcesJar") { archiveClassifier.set("sources") from(android.sourceSets.getByName("main").java.directories) // Full Sources } tasks.register("copyJar") { dependsOn("build", ":library:jvmJar") from( "build/intermediates/compile_app_classes_jar/prereleaseDebug/bundlePrereleaseDebugClassesToCompileJar", "../library/build/libs" ) into("build/app-classes") include("classes.jar", "library-jvm*.jar") // Remove the version rename("library-jvm.*.jar", "library-jvm.jar") } // Merge the app classes and the library classes into classes.jar tasks.register("makeJar") { // Duplicates cause hard to catch errors, better to fail at compile time. duplicatesStrategy = DuplicatesStrategy.FAIL dependsOn(tasks.getByName("copyJar")) from( zipTree("build/app-classes/classes.jar"), zipTree("build/app-classes/library-jvm.jar") ) destinationDirectory.set(layout.buildDirectory) archiveBaseName = "classes" } tasks.withType { compilerOptions { jvmTarget.set(javaTarget) jvmDefault.set(JvmDefaultMode.ENABLE) freeCompilerArgs.add("-Xannotation-default-target=param-property") optIn.addAll( "com.lagradost.cloudstream3.InternalAPI", "com.lagradost.cloudstream3.Prerelease", "kotlin.uuid.ExperimentalUuidApi", ) } } dokka { moduleName = "App" dokkaSourceSets { configureEach { suppress = name != "prereleaseDebug" analysisPlatform = KotlinPlatform.JVM displayName = "JVM" documentedVisibilities( VisibilityModifier.Public, VisibilityModifier.Protected ) sourceLink { localDirectory = file("..") remoteUrl("https://github.com/recloudstream/cloudstream/tree/master") remoteLineSuffix = "#L" } } } }