Skip to content

Commit bccd97b

Browse files
author
Blatzar
committed
Added basic test
1 parent e59cbfb commit bccd97b

File tree

5 files changed

+197
-2
lines changed

5 files changed

+197
-2
lines changed

CloudstreamApi/build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ publishing {
1717
maven(MavenPublication) {
1818
groupId 'com.lagradost'
1919
artifactId 'cloudstream-api'
20-
version '0.1.0'
20+
version '0.1.1'
2121
from components.java
2222
}
2323
}

CloudstreamApi/src/main/java/com/lagradost/cloudstream3/MainApi.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ object APIHolder {
4040
private const val defProvider = 0
4141

4242
// ConcurrentModificationException is possible!!!
43-
val allProviders = listOf<MainAPI>()
43+
val allProviders = mutableListOf<MainAPI>()
4444

4545
fun initAll() {
4646
synchronized(allProviders) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
package com.lagradost.cloudstream3.plugins
2+
3+
@Suppress("unused")
4+
@Target(AnnotationTarget.CLASS)
5+
annotation class CloudstreamPlugin
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package com.lagradost.cloudstream3.plugins
2+
3+
import kotlin.Throws
4+
import com.lagradost.cloudstream3.MainAPI
5+
import com.lagradost.cloudstream3.APIHolder
6+
import com.lagradost.cloudstream3.utils.ExtractorApi
7+
import com.lagradost.cloudstream3.utils.extractorApis
8+
import android.util.Log
9+
import com.fasterxml.jackson.annotation.JsonProperty
10+
11+
const val PLUGIN_TAG = "PluginInstance"
12+
13+
abstract class Plugin {
14+
/**
15+
* Called when your Plugin is loaded
16+
* @param context Context
17+
*/
18+
@Throws(Throwable::class)
19+
open fun load(context: Any) {
20+
}
21+
22+
/**
23+
* Called when your Plugin is being unloaded
24+
*/
25+
@Throws(Throwable::class)
26+
open fun beforeUnload() {
27+
}
28+
29+
/**
30+
* Used to register providers instances of MainAPI
31+
* @param element MainAPI provider you want to register
32+
*/
33+
fun registerMainAPI(element: MainAPI) {
34+
Log.i(PLUGIN_TAG, "Adding ${element.name} (${element.mainUrl}) MainAPI")
35+
// Race condition causing which would case duplicates if not for distinctBy
36+
synchronized(APIHolder.allProviders) {
37+
APIHolder.allProviders.add(element)
38+
}
39+
APIHolder.addPluginMapping(element)
40+
}
41+
42+
/**
43+
* Used to register extractor instances of ExtractorApi
44+
* @param element ExtractorApi provider you want to register
45+
*/
46+
fun registerExtractorAPI(element: ExtractorApi) {
47+
Log.i(PLUGIN_TAG, "Adding ${element.name} (${element.mainUrl}) ExtractorApi")
48+
extractorApis.add(element)
49+
}
50+
51+
class Manifest {
52+
@JsonProperty("name")
53+
var name: String? = null
54+
@JsonProperty("pluginClassName")
55+
var pluginClassName: String? = null
56+
@JsonProperty("version")
57+
var version: Int? = null
58+
@JsonProperty("requiresResources")
59+
var requiresResources: Boolean = false
60+
}
61+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package com.lagradost.cloudstreamtest
2+
3+
import com.lagradost.cloudstream3.AnimeLoadResponse
4+
import com.lagradost.cloudstream3.HomePageResponse
5+
import com.lagradost.cloudstream3.LiveStreamLoadResponse
6+
import com.lagradost.cloudstream3.LoadResponse
7+
import com.lagradost.cloudstream3.MainAPI
8+
import com.lagradost.cloudstream3.MainPageRequest
9+
import com.lagradost.cloudstream3.MovieLoadResponse
10+
import com.lagradost.cloudstream3.SearchResponse
11+
import com.lagradost.cloudstream3.SubtitleFile
12+
import com.lagradost.cloudstream3.TvSeriesLoadResponse
13+
import com.lagradost.cloudstream3.utils.ExtractorLink
14+
import java.lang.RuntimeException
15+
16+
/**
17+
* Simple and easy testing class for providers.
18+
* Should really be expanded to be able to test all providers properly.
19+
* @see testAll
20+
*/
21+
open class ProviderTester(private val provider: MainAPI) {
22+
suspend fun testSearch(query: String, verbose: Boolean = false): List<SearchResponse> {
23+
val responses = provider.search(query) ?: emptyList()
24+
println("Response count: ${responses.size}, Query: $query")
25+
printSearchResponses(responses, verbose)
26+
return responses
27+
}
28+
29+
private fun printSearchResponses(responses: List<SearchResponse>, verbose: Boolean) {
30+
if (verbose) {
31+
println("Responses:\n${responses.joinToString("\n")}")
32+
} else {
33+
println("Responses:\n${responses.map { it.name to it.url }.joinToString("\n")}")
34+
}
35+
}
36+
37+
suspend fun testMainPage(verbose: Boolean = false): List<HomePageResponse> {
38+
if (!provider.hasMainPage) {
39+
throw RuntimeException("Provider does not have a main page!")
40+
}
41+
val responses = provider.mainPage.map { request ->
42+
provider.getMainPage(1, MainPageRequest(request.name, request.data, false))
43+
}.ifEmpty { listOf(provider.getMainPage(1, MainPageRequest("", "", false))) }
44+
.mapNotNull { it }
45+
46+
responses.map { it.items }.flatten().forEach {
47+
println("Main page: ${it.name}, Item count: ${it.list.size}")
48+
printSearchResponses(it.list, verbose)
49+
}
50+
return responses
51+
}
52+
53+
suspend fun testLoad(url: String): LoadResponse? {
54+
println("Loading response from: $url")
55+
val response = provider.load(url)
56+
println("Loaded response: $response")
57+
return response
58+
}
59+
60+
suspend fun testLoadLinks(data: String): Pair<List<ExtractorLink>, List<SubtitleFile>> {
61+
val subtitles = mutableListOf<SubtitleFile>()
62+
val links = mutableListOf<ExtractorLink>()
63+
provider.loadLinks(data, false, { file ->
64+
subtitles.add(file)
65+
}, { link ->
66+
links.add(link)
67+
})
68+
69+
println("Links count: ${links.size}, Subtitles count: ${subtitles.size}")
70+
println("Links: ${links.joinToString("\n")}")
71+
println("Subtitles: ${subtitles.joinToString("\n")}")
72+
73+
return links to subtitles
74+
}
75+
76+
suspend fun testAll(query: String? = null) {
77+
val response = if (provider.hasMainPage) {
78+
println("Testing Main Page: -------------------")
79+
val mainPage = testMainPage()
80+
val item = mainPage.first().items.first().list.first()
81+
println("\n\nTesting Search: -------------------")
82+
83+
val searchResponses = testSearch(item.name)
84+
assert(searchResponses.isNotEmpty())
85+
86+
item
87+
} else if (query != null) {
88+
println("Testing Search: -------------------")
89+
90+
testSearch(query).first()
91+
} else {
92+
throw RuntimeException("Cannot test everything without a query or a homepage")
93+
}
94+
println("\n\nTesting load: -------------------")
95+
96+
val loadResponse = testLoad(response.url)
97+
assert(loadResponse != null)
98+
if (loadResponse!!.url != response.url) {
99+
println("Testing bookmark functionality")
100+
val secondResponse = testLoad(loadResponse.url)
101+
assert(secondResponse != null)
102+
}
103+
104+
val data = when (loadResponse) {
105+
is AnimeLoadResponse -> {
106+
loadResponse.episodes.values.first().first().data
107+
}
108+
109+
is MovieLoadResponse -> {
110+
loadResponse.dataUrl
111+
}
112+
113+
is LiveStreamLoadResponse -> {
114+
loadResponse.dataUrl
115+
}
116+
117+
is TvSeriesLoadResponse -> {
118+
loadResponse.episodes.first().data
119+
}
120+
121+
else -> {
122+
throw RuntimeException("Unknown load response: ${loadResponse::class.simpleName}")
123+
}
124+
}
125+
126+
println("\n\nTesting LoadLinks: -------------------")
127+
val (links, subs) = testLoadLinks(data)
128+
}
129+
}

0 commit comments

Comments
 (0)