From aef1c584e534956b0d541a37c5526a2ad107844c Mon Sep 17 00:00:00 2001 From: Kelvin Date: Tue, 3 Sep 2024 22:32:50 +0200 Subject: [PATCH] Article spec structures --- app/src/main/assets/scripts/source.js | 41 ++++- .../platforms/js/models/IJSContentDetails.kt | 1 + .../media/platforms/js/models/JSArticle.kt | 78 --------- .../platforms/js/models/JSArticleDetails.kt | 162 ++++++++++++++++++ 4 files changed, 202 insertions(+), 80 deletions(-) delete mode 100644 app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticle.kt create mode 100644 app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticleDetails.kt diff --git a/app/src/main/assets/scripts/source.js b/app/src/main/assets/scripts/source.js index f65aa87b..fba714fc 100644 --- a/app/src/main/assets/scripts/source.js +++ b/app/src/main/assets/scripts/source.js @@ -201,7 +201,7 @@ class PlatformContent { obj = obj ?? {}; this.id = obj.id ?? PlatformID(); //PlatformID this.name = obj.name ?? ""; //string - this.thumbnails = obj.thumbnails; //Thumbnail[] + this.thumbnails = obj.thumbnails ?? new Thumbnails([]); //Thumbnail[] this.author = obj.author; //PlatformAuthorLink this.datetime = obj.datetime ?? obj.uploadDate ?? 0; //OffsetDateTime (Long) this.url = obj.url ?? ""; //String @@ -278,12 +278,49 @@ class PlatformPostDetails extends PlatformPost { super(obj); obj = obj ?? {}; this.plugin_type = "PlatformPostDetails"; - this.rating = obj.rating ?? RatingLikes(-1); + this.rating = obj.rating ?? new RatingLikes(-1); this.textType = obj.textType ?? 0; this.content = obj.content ?? ""; } } +class PlatformArticleDetails extends PlatformContent { + constructor(obj) { + super(obj, 3); + obj = obj ?? {}; + this.plugin_type = "PlatformArticleDetails"; + this.rating = obj.rating ?? new RatingLikes(-1); + this.summary = obj.summary ?? ""; + this.segments = obj.segments ?? []; + this.thumbnails = obj.thumbnails ?? new Thumbnails([]); + } +} +class ArticleSegment { + constructor(type) { + this.type = type; + } +} +class ArticleTextSegment extends ArticleSegment { + constructor(content, textType) { + super(1); + this.textType = textType; + this.content = content; + } +} +class ArticleImagesSegment extends ArticleSegment { + constructor(images) { + super(2); + this.images = images; + } +} +class ArticleNestedSegment extends ArticleSegment { + constructor(nested) { + super(9); + this.nested = nested; + } +} + + //Sources class VideoSourceDescriptor { constructor(obj) { diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/IJSContentDetails.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/IJSContentDetails.kt index 6ec2fd98..04382057 100644 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/IJSContentDetails.kt +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/IJSContentDetails.kt @@ -16,6 +16,7 @@ interface IJSContentDetails: IPlatformContent { return when(ContentType.fromInt(type)) { ContentType.MEDIA -> JSVideoDetails(plugin, obj); ContentType.POST -> JSPostDetails(plugin.config, obj); + ContentType.ARTICLE -> JSArticleDetails(plugin, obj); else -> throw NotImplementedError("Unknown content type ${type}"); } } diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticle.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticle.kt deleted file mode 100644 index 2d0e8a65..00000000 --- a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticle.kt +++ /dev/null @@ -1,78 +0,0 @@ -package com.futo.platformplayer.api.media.platforms.js.models - -import com.caoccao.javet.values.reference.V8ValueObject -import com.futo.platformplayer.api.media.IPluginSourced -import com.futo.platformplayer.api.media.models.Thumbnails -import com.futo.platformplayer.api.media.models.contents.ContentType -import com.futo.platformplayer.api.media.models.post.TextType -import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig -import com.futo.platformplayer.getOrDefault -import com.futo.platformplayer.getOrThrow -import com.futo.platformplayer.getOrThrowNullableList -import kotlin.streams.toList - -open class JSArticle : JSContent, IPluginSourced { - final override val contentType: ContentType get() = ContentType.POST; - - val summary: String; - val thumbnails: Thumbnails?; - val segments: List; - - constructor(config: SourcePluginConfig, obj: V8ValueObject): super(config, obj) { - val contextName = "PlatformPost"; - - summary = _content.getOrThrow(config, "summary", contextName); - if(_content.has("thumbnails")) - thumbnails = Thumbnails.fromV8(config, _content.getOrThrow(config, "thumbnails", contextName)); - else - thumbnails = null; - - - segments = (obj.getOrThrowNullableList(config, "segments", contextName) - ?.map { fromV8Segment(config, it) } - ?.filterNotNull() ?: listOf()); - } - - - companion object { - fun fromV8Segment(config: SourcePluginConfig, obj: V8ValueObject): IJSArticleSegment? { - if(!obj.has("type")) - throw IllegalArgumentException("Object missing type field"); - return when(obj.getOrThrow(config, "type", "JSArticle.Segment")) { - SegmentType.TEXT -> JSTextSegment(config, obj); - SegmentType.IMAGES -> JSImagesSegment(config, obj); - else -> null; - } - } - } -} - -enum class SegmentType(i: Int) { - UNKNOWN(0), - TEXT(1), - IMAGES(2) -} - -interface IJSArticleSegment { - val type: SegmentType; -} -class JSTextSegment: IJSArticleSegment { - override val type = SegmentType.TEXT; - val textType: TextType; - val content: String; - - constructor(config: SourcePluginConfig, obj: V8ValueObject) { - val contextName = "JSTextSegment"; - textType = TextType.fromInt((obj.getOrDefault(config, "textType", contextName, null) ?: 0)); - content = obj.getOrDefault(config, "content", contextName, "") ?: ""; - } -} -class JSImagesSegment: IJSArticleSegment { - override val type = SegmentType.IMAGES; - val images: List; - - constructor(config: SourcePluginConfig, obj: V8ValueObject) { - val contextName = "JSTextSegment"; - images = obj.getOrThrowNullableList(config, "images", contextName) ?: listOf(); - } -} \ No newline at end of file diff --git a/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticleDetails.kt b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticleDetails.kt new file mode 100644 index 00000000..453c59d8 --- /dev/null +++ b/app/src/main/java/com/futo/platformplayer/api/media/platforms/js/models/JSArticleDetails.kt @@ -0,0 +1,162 @@ +package com.futo.platformplayer.api.media.platforms.js.models + +import com.caoccao.javet.values.reference.V8ValueObject +import com.futo.platformplayer.api.media.IPlatformClient +import com.futo.platformplayer.api.media.IPluginSourced +import com.futo.platformplayer.api.media.models.Thumbnails +import com.futo.platformplayer.api.media.models.comments.IPlatformComment +import com.futo.platformplayer.api.media.models.contents.ContentType +import com.futo.platformplayer.api.media.models.contents.IPlatformContent +import com.futo.platformplayer.api.media.models.contents.IPlatformContentDetails +import com.futo.platformplayer.api.media.models.playback.IPlaybackTracker +import com.futo.platformplayer.api.media.models.post.TextType +import com.futo.platformplayer.api.media.models.ratings.IRating +import com.futo.platformplayer.api.media.models.ratings.RatingLikes +import com.futo.platformplayer.api.media.platforms.js.DevJSClient +import com.futo.platformplayer.api.media.platforms.js.JSClient +import com.futo.platformplayer.api.media.platforms.js.SourcePluginConfig +import com.futo.platformplayer.api.media.structures.IPager +import com.futo.platformplayer.getOrDefault +import com.futo.platformplayer.getOrThrow +import com.futo.platformplayer.getOrThrowNullableList +import com.futo.platformplayer.states.StateDeveloper + +open class JSArticleDetails : JSContent, IPluginSourced, IPlatformContentDetails { + final override val contentType: ContentType get() = ContentType.ARTICLE; + + private val _hasGetComments: Boolean; + private val _hasGetContentRecommendations: Boolean; + + val rating: IRating; + + val summary: String; + val thumbnails: Thumbnails?; + val segments: List; + + constructor(client: JSClient, obj: V8ValueObject): super(client.config, obj) { + val contextName = "PlatformPost"; + + rating = obj.getOrDefault(client.config, "rating", contextName, null)?.let { IRating.fromV8(client.config, it, contextName) } ?: RatingLikes(0); + summary = _content.getOrThrow(client.config, "summary", contextName); + if(_content.has("thumbnails")) + thumbnails = Thumbnails.fromV8(client.config, _content.getOrThrow(client.config, "thumbnails", contextName)); + else + thumbnails = null; + + + segments = (obj.getOrThrowNullableList(client.config, "segments", contextName) + ?.map { fromV8Segment(client, it) } + ?.filterNotNull() ?: listOf()); + + _hasGetComments = _content.has("getComments"); + _hasGetContentRecommendations = _content.has("getContentRecommendations"); + } + + override fun getComments(client: IPlatformClient): IPager? { + if(!_hasGetComments || _content.isClosed) + return null; + + if(client is DevJSClient) + return StateDeveloper.instance.handleDevCall(client.devID, "videoDetail.getComments()") { + return@handleDevCall getCommentsJS(client); + } + else if(client is JSClient) + return getCommentsJS(client); + + return null; + } + + override fun getPlaybackTracker(): IPlaybackTracker? = null; + + override fun getContentRecommendations(client: IPlatformClient): IPager? { + if(!_hasGetContentRecommendations || _content.isClosed) + return null; + + if(client is DevJSClient) + return StateDeveloper.instance.handleDevCall(client.devID, "postDetail.getContentRecommendations()") { + return@handleDevCall getContentRecommendationsJS(client); + } + else if(client is JSClient) + return getContentRecommendationsJS(client); + + return null; + } + + private fun getContentRecommendationsJS(client: JSClient): JSContentPager { + val contentPager = _content.invoke("getContentRecommendations", arrayOf()); + return JSContentPager(_pluginConfig, client, contentPager); + } + + private fun getCommentsJS(client: JSClient): JSCommentPager { + val commentPager = _content.invoke("getComments", arrayOf()); + return JSCommentPager(_pluginConfig, client, commentPager); + } + + companion object { + fun fromV8Segment(client: JSClient, obj: V8ValueObject): IJSArticleSegment? { + if(!obj.has("type")) + throw IllegalArgumentException("Object missing type field"); + return when(SegmentType.fromInt(obj.getOrThrow(client.config, "type", "JSArticle.Segment"))) { + SegmentType.TEXT -> JSTextSegment(client, obj); + SegmentType.IMAGES -> JSImagesSegment(client, obj); + SegmentType.NESTED -> JSNestedSegment(client, obj); + else -> null; + } + } + } +} + +enum class SegmentType(val value: Int) { + UNKNOWN(0), + TEXT(1), + IMAGES(2), + + NESTED(9); + + + companion object { + fun fromInt(value: Int): SegmentType + { + val result = SegmentType.entries.firstOrNull { it.value == value }; + if(result == null) + throw IllegalArgumentException("Unknown Texttype: $value"); + return result; + } + } +} + +interface IJSArticleSegment { + val type: SegmentType; +} +class JSTextSegment: IJSArticleSegment { + override val type = SegmentType.TEXT; + val textType: TextType; + val content: String; + + constructor(client: JSClient, obj: V8ValueObject) { + val contextName = "JSTextSegment"; + textType = TextType.fromInt((obj.getOrDefault(client.config, "textType", contextName, null) ?: 0)); + content = obj.getOrDefault(client.config, "content", contextName, "") ?: ""; + } +} +class JSImagesSegment: IJSArticleSegment { + override val type = SegmentType.IMAGES; + val images: List; + val caption: String; + + constructor(client: JSClient, obj: V8ValueObject) { + val contextName = "JSTextSegment"; + images = obj.getOrThrowNullableList(client.config, "images", contextName) ?: listOf(); + caption = obj.getOrDefault(client.config, "caption", contextName, "") ?: ""; + } +} +class JSNestedSegment: IJSArticleSegment { + override val type = SegmentType.NESTED; + val nested: IPlatformContent; + + constructor(client: JSClient, obj: V8ValueObject) { + val contextName = "JSNestedSegment"; + val nestedObj = obj.getOrThrow(client.config, "nested", contextName, false); + nested = IJSContent.fromV8(client, nestedObj); + } +} \ No newline at end of file