diff --git a/Xcinetop/build.gradle.kts b/Xcinetop/build.gradle.kts
new file mode 100644
index 00000000..cda2d4cb
--- /dev/null
+++ b/Xcinetop/build.gradle.kts
@@ -0,0 +1,26 @@
+// use an integer for version numbers
+version = 1
+
+
+cloudstream {
+ language = "de"
+ // All of these properties are optional, you can safely remove them
+
+ // description = "Lorem Ipsum"
+ authors = listOf("Hexated")
+
+ /**
+ * Status int as the following:
+ * 0: Down
+ * 1: Ok
+ * 2: Slow
+ * 3: Beta only
+ * */
+ status = 1 // will be 3 if unspecified
+ tvTypes = listOf(
+ "TvSeries",
+ "Movie",
+ )
+
+ iconUrl = "https://www.google.com/s2/favicons?domain=xcine.top&sz=%size%"
+}
\ No newline at end of file
diff --git a/Xcinetop/src/main/AndroidManifest.xml b/Xcinetop/src/main/AndroidManifest.xml
new file mode 100644
index 00000000..c98063f8
--- /dev/null
+++ b/Xcinetop/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/Xcinetop/src/main/kotlin/com/hexated/Xcinetop.kt b/Xcinetop/src/main/kotlin/com/hexated/Xcinetop.kt
new file mode 100644
index 00000000..d5da4d58
--- /dev/null
+++ b/Xcinetop/src/main/kotlin/com/hexated/Xcinetop.kt
@@ -0,0 +1,191 @@
+package com.hexated
+
+import com.fasterxml.jackson.annotation.JsonProperty
+import com.lagradost.cloudstream3.*
+import com.lagradost.cloudstream3.LoadResponse.Companion.addActors
+import com.lagradost.cloudstream3.LoadResponse.Companion.addTrailer
+import com.lagradost.cloudstream3.mvvm.safeApiCall
+import com.lagradost.cloudstream3.utils.*
+import com.lagradost.cloudstream3.utils.AppUtils.parseJson
+import com.lagradost.cloudstream3.utils.AppUtils.toJson
+import com.lagradost.cloudstream3.utils.AppUtils.tryParseJson
+import org.jsoup.nodes.Element
+
+class Xcinetop : MainAPI() {
+ override var mainUrl = "https://xcine.top"
+ override var name = "Xcine.top"
+ override val hasMainPage = true
+ override val hasDownloadSupport = true
+ override var lang = "de"
+ override val supportedTypes = setOf(TvType.TvSeries, TvType.Movie)
+
+ companion object {
+ private const val mainServer = "https://supervideo.tv"
+ }
+
+ override val mainPage = mainPageOf(
+ "$mainUrl/aktuelle-kinofilme-im-kino/page/" to "Kinofilme im kino",
+ "$mainUrl/serienstream-deutsch/page/" to "Serien",
+ "$mainUrl/animation/page/" to "Animation",
+ )
+
+ override suspend fun getMainPage(page: Int, request: MainPageRequest): HomePageResponse {
+ val document = app.get(request.data + page).document
+ val home = document.select("div#dle-content div.movie-item").mapNotNull {
+ it.toSearchResult()
+ }
+ return newHomePageResponse(request.name, home)
+ }
+
+ private fun Element.toSearchResult(): SearchResponse? {
+ val href = fixUrl(this.selectFirst("a")?.attr("href") ?: return null)
+ val title = this.selectFirst("div.movie-item__title")?.text()?.trim() ?: return null
+ val posterUrl = fixUrlNull(this.selectFirst("img")?.attr("src"))
+ val quantity = this.selectFirst("div.movie-item__label")?.text() ?: return null
+ val episode =
+ this.selectFirst("span.ep-num")?.text()?.filter { it.isDigit() }?.toIntOrNull()
+
+ return newAnimeSearchResponse(title, href, TvType.TvSeries) {
+ addQuality(quantity)
+ addDub(episode)
+ addPoster(posterUrl, headers = mapOf("Referer" to "$mainUrl/"))
+ }
+ }
+
+ override suspend fun search(query: String): List {
+ val document = app.post(
+ "$mainUrl/index.php?do=search", data = mapOf(
+ "do" to "search",
+ "subaction" to "search",
+ "search_start" to "0",
+ "full_search" to "0",
+ "result_from" to "1",
+ "story" to query
+ )
+ ).document
+ return document.select("div#dle-content div.movie-item").mapNotNull {
+ it.toSearchResult()
+ }
+ }
+
+ override suspend fun load(url: String): LoadResponse? {
+ val document = app.get(url).document
+
+ val title = document.selectFirst("h1.inner-page__title")?.text()?.trim() ?: return null
+ val poster = fixUrlNull(document.selectFirst("div.inner-page__img img")?.attr("src"))
+ val tags = document.select("ul.inner-page__list li:contains(Genre:) a").map { it.text() }
+ val year = document.selectFirst("ul.inner-page__list li:contains(Jahr:)")?.ownText()
+ ?.toIntOrNull()
+ val description = document.select("div.inner-page__text.text.clearfix").text()
+ val duration = document.selectFirst("ul.inner-page__list li:contains(Zeit:)")?.ownText()
+ ?.filter { it.isDigit() }?.toIntOrNull()
+ val actors = document.selectFirst("ul.inner-page__list li:contains(Darsteller:)")?.ownText()
+ ?.split(",")?.map { it.trim() }
+ val recommendations = document.select("div.section__content.section__items div.movie-item")
+ .mapNotNull { it.toSearchResult() }
+ val type = if (document.select("ul.series-select-menu.ep-menu")
+ .isNullOrEmpty()
+ ) TvType.Movie else TvType.TvSeries
+ val trailer = document.selectFirst("div.stretch-free-width.mirrors span:contains(Trailer)")
+ ?.attr("data-link") ?: document.selectFirst("div#trailer iframe")?.attr("src")
+
+ if (type == TvType.Movie) {
+ val link = document.select("div.stretch-free-width.mirrors span").map {
+ fixUrl(it.attr("data-link"))
+ }
+ return newMovieLoadResponse(title, url, TvType.Movie, Links(link).toJson()) {
+ addPoster(poster, headers = mapOf("Referer" to "$mainUrl/"))
+ this.year = year
+ plot = description
+ this.tags = tags
+ this.duration = duration
+ this.recommendations = recommendations
+ addActors(actors)
+ addTrailer(trailer)
+ }
+ } else {
+ val episodes = document.select("ul.series-select-menu.ep-menu li[id*=serie]").map {
+ val name = it.selectFirst("a")?.text()
+ val link = it.select("li").map { eps ->
+ fixUrl(eps.select("a").attr("data-link"))
+ }
+ Episode(
+ Links(link).toJson(),
+ name
+ )
+ }
+ return newTvSeriesLoadResponse(title, url, TvType.TvSeries, episodes = episodes) {
+ addPoster(poster, headers = mapOf("Referer" to "$mainUrl/"))
+ this.year = year
+ plot = description
+ this.tags = tags
+ this.duration = duration
+ this.recommendations = recommendations
+ addActors(actors)
+ addTrailer(trailer)
+ }
+ }
+ }
+
+ private suspend fun invokeLocalSource(
+ url: String,
+ callback: (ExtractorLink) -> Unit
+ ) {
+ val script = app.get(url, referer = "$mainUrl/").document.select("script")
+ .find { it.data().contains("eval(function(p,a,c,k,e,d)") }?.data()
+ val data = getAndUnpack(script ?: return).substringAfter("sources:[").substringBefore("],")
+ .replace("file", "\"file\"")
+ .replace("label", "\"label\"")
+
+ tryParseJson>("[$data]")?.map { link ->
+ val source = "Supervideo"
+ if (link.file?.contains(".m3u8") == true) {
+ M3u8Helper.generateM3u8(
+ "$source (Main)",
+ link.file,
+ "$mainServer/"
+ ).forEach(callback)
+ } else {
+ callback.invoke(
+ ExtractorLink(
+ "$source (Backup)",
+ "$source (Backup)",
+ link.file ?: return@map null,
+ "$mainServer/",
+ getQualityFromName(link.label)
+ )
+ )
+ }
+ }
+ }
+
+ override suspend fun loadLinks(
+ data: String,
+ isCasting: Boolean,
+ subtitleCallback: (SubtitleFile) -> Unit,
+ callback: (ExtractorLink) -> Unit
+ ): Boolean {
+
+ parseJson(data).url?.apmap { link ->
+ safeApiCall {
+ if (link.startsWith(mainServer)) {
+ invokeLocalSource(link, callback)
+ } else {
+ loadExtractor(link, "$mainUrl/", subtitleCallback, callback)
+ }
+ }
+ }
+
+ return true
+ }
+
+ private data class Links(
+ val url: List? = arrayListOf(),
+ )
+
+ private data class Sources(
+ @JsonProperty("file") val file: String? = null,
+ @JsonProperty("label") val label: String? = null
+ )
+
+}
\ No newline at end of file
diff --git a/Xcinetop/src/main/kotlin/com/hexated/XcinetopPlugin.kt b/Xcinetop/src/main/kotlin/com/hexated/XcinetopPlugin.kt
new file mode 100644
index 00000000..403357fe
--- /dev/null
+++ b/Xcinetop/src/main/kotlin/com/hexated/XcinetopPlugin.kt
@@ -0,0 +1,14 @@
+
+package com.hexated
+
+import com.lagradost.cloudstream3.plugins.CloudstreamPlugin
+import com.lagradost.cloudstream3.plugins.Plugin
+import android.content.Context
+
+@CloudstreamPlugin
+class XcinetopPlugin: Plugin() {
+ override fun load(context: Context) {
+ // All providers should be added in this manner. Please don't edit the providers list directly.
+ registerMainAPI(Xcinetop())
+ }
+}
\ No newline at end of file