From 7fcbbed2df3dcd7bb35c94bf1e491ff96ec195aa Mon Sep 17 00:00:00 2001 From: "stainless-app[bot]" <142633134+stainless-app[bot]@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:58:01 +0000 Subject: [PATCH] feat(api): align reply extraction contracts Regenerate every SDK from the exact production OpenAPI contract. --- .stats.yml | 4 +- .../api/models/ContentDisclosure.kt | 43 +- .../api/models/EmbeddedTweet.kt | 3319 ++++++++++- .../api/models/PaginatedTweets.kt | 7 +- .../api/models/SearchTweet.kt | 3202 +++++++++- .../api/models/TweetMedia.kt | 1276 +++- .../api/models/UserProfile.kt | 1571 ++++- .../support/tickets/TicketListResponse.kt | 288 +- .../support/tickets/TicketRetrieveResponse.kt | 478 +- .../support/tickets/TicketUpdateResponse.kt | 203 +- .../api/models/trends/TrendListResponse.kt | 148 +- .../api/models/x/XGetArticleResponse.kt | 36 +- .../api/models/x/XGetTrendsResponse.kt | 148 +- ...ccountConnectionAttemptRetrieveResponse.kt | 766 +-- ...ccountConnectionChallengeSubmitResponse.kt | 52 +- .../x/accounts/AccountCreateResponse.kt | 1492 ++++- .../x/accounts/AccountReauthResponse.kt | 52 +- .../CommunityRetrieveInfoResponse.kt | 78 +- .../CommunityRetrieveSearchParams.kt | 12 +- .../tweets/TweetListByCommunityParams.kt | 12 +- .../x/communities/tweets/TweetListParams.kt | 12 +- .../x/lists/ListRetrieveTweetsParams.kt | 12 +- .../api/models/x/tweets/TweetAuthor.kt | 771 ++- .../api/models/x/tweets/TweetDetail.kt | 3202 +++++++++- .../models/x/tweets/TweetGetQuotesParams.kt | 12 +- .../models/x/tweets/TweetGetRepliesParams.kt | 208 +- .../x/tweets/TweetGetRepliesResponse.kt | 2654 +++++++++ .../models/x/tweets/TweetGetThreadParams.kt | 12 +- .../models/x/users/UserRetrieveLikesParams.kt | 12 +- .../models/x/users/UserRetrieveMediaParams.kt | 12 +- .../x/users/UserRetrieveMentionsParams.kt | 12 +- .../x/users/UserRetrieveRepliesParams.kt | 12 +- .../x/users/UserRetrieveTweetsParams.kt | 12 +- .../api/services/async/x/TweetServiceAsync.kt | 36 +- .../services/async/x/TweetServiceAsyncImpl.kt | 9 +- .../api/services/blocking/x/TweetService.kt | 34 +- .../services/blocking/x/TweetServiceImpl.kt | 9 +- .../api/models/ContentDisclosureTest.kt | 3 - .../api/models/EmbeddedTweetTest.kt | 476 +- .../api/models/GeneratedModelContractTest.kt | 25 +- .../api/models/PaginatedTweetsTest.kt | 1523 ++++- .../api/models/PaginatedUsersTest.kt | 114 +- .../api/models/SearchTweetTest.kt | 1438 ++++- .../api/models/TweetMediaTest.kt | 94 + .../api/models/UserProfileTest.kt | 117 +- .../support/tickets/TicketListResponseTest.kt | 9 +- .../tickets/TicketRetrieveResponseTest.kt | 23 +- .../tickets/TicketUpdateResponseTest.kt | 8 +- .../models/trends/TrendListResponseTest.kt | 9 + .../api/models/x/XGetArticleResponseTest.kt | 3 - .../api/models/x/XGetTrendsResponseTest.kt | 9 + ...ntConnectionAttemptRetrieveResponseTest.kt | 126 +- ...ntConnectionChallengeSubmitResponseTest.kt | 3 - .../x/accounts/AccountCreateResponseTest.kt | 135 +- .../x/accounts/AccountReauthResponseTest.kt | 3 - .../CommunityRetrieveInfoResponseTest.kt | 6 - .../api/models/x/tweets/TweetAuthorTest.kt | 117 +- .../api/models/x/tweets/TweetDetailTest.kt | 1438 ++++- .../x/tweets/TweetGetRepliesParamsTest.kt | 6 + .../x/tweets/TweetGetRepliesResponseTest.kt | 5132 +++++++++++++++++ .../x/tweets/TweetRetrieveResponseTest.kt | 1637 +++++- .../x/users/UserRetrieveBatchResponseTest.kt | 114 +- .../services/async/x/TweetServiceAsyncTest.kt | 8 +- .../services/blocking/x/TweetServiceTest.kt | 6 +- 64 files changed, 31019 insertions(+), 1781 deletions(-) create mode 100644 x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponse.kt create mode 100644 x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponseTest.kt diff --git a/.stats.yml b/.stats.yml index 722a8b3..ec9dedf 100644 --- a/.stats.yml +++ b/.stats.yml @@ -1,4 +1,4 @@ configured_endpoints: 123 -openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-323137ebb1ee9824cd9cfb63a325c0839deb81f17244e42e8154d6567e7af954.yml -openapi_spec_hash: 48da9c2747c1e7c474dd514d39c28c49 +openapi_spec_url: https://storage.googleapis.com/stainless-sdk-openapi-specs/xquik/x-twitter-scraper-5f26f3694399b4ac5a4431c66f7d27c4024f9d0dcd899702de5fde1150e28330.yml +openapi_spec_hash: 362e24e622f9a74ded8b38018e50460c config_hash: dab26921eb273c16e5570c0485c9ac2c diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/ContentDisclosure.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/ContentDisclosure.kt index 7c211d8..ea16825 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/ContentDisclosure.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/ContentDisclosure.kt @@ -359,7 +359,6 @@ private constructor( class AiGenerated @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - private val canEdit: JsonField, private val detectionSource: JsonField, private val hasAiGeneratedMedia: JsonField, private val additionalProperties: MutableMap, @@ -367,22 +366,13 @@ private constructor( @JsonCreator private constructor( - @JsonProperty("canEdit") @ExcludeMissing canEdit: JsonField = JsonMissing.of(), @JsonProperty("detectionSource") @ExcludeMissing detectionSource: JsonField = JsonMissing.of(), @JsonProperty("hasAiGeneratedMedia") @ExcludeMissing hasAiGeneratedMedia: JsonField = JsonMissing.of(), - ) : this(canEdit, detectionSource, hasAiGeneratedMedia, mutableMapOf()) - - /** - * Whether the disclosure can be edited on X. - * - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun canEdit(): Optional = canEdit.getOptional("canEdit") + ) : this(detectionSource, hasAiGeneratedMedia, mutableMapOf()) /** * Source of the AI-generated media disclosure. @@ -401,13 +391,6 @@ private constructor( fun hasAiGeneratedMedia(): Optional = hasAiGeneratedMedia.getOptional("hasAiGeneratedMedia") - /** - * Returns the raw JSON value of [canEdit]. - * - * Unlike [canEdit], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("canEdit") @ExcludeMissing fun _canEdit(): JsonField = canEdit - /** * Returns the raw JSON value of [detectionSource]. * @@ -449,31 +432,17 @@ private constructor( /** A builder for [AiGenerated]. */ class Builder internal constructor() { - private var canEdit: JsonField = JsonMissing.of() private var detectionSource: JsonField = JsonMissing.of() private var hasAiGeneratedMedia: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(aiGenerated: AiGenerated) = apply { - canEdit = aiGenerated.canEdit detectionSource = aiGenerated.detectionSource hasAiGeneratedMedia = aiGenerated.hasAiGeneratedMedia additionalProperties = aiGenerated.additionalProperties.toMutableMap() } - /** Whether the disclosure can be edited on X. */ - fun canEdit(canEdit: Boolean) = canEdit(JsonField.of(canEdit)) - - /** - * Sets [Builder.canEdit] to an arbitrary JSON value. - * - * You should usually call [Builder.canEdit] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun canEdit(canEdit: JsonField) = apply { this.canEdit = canEdit } - /** Source of the AI-generated media disclosure. */ fun detectionSource(detectionSource: String) = detectionSource(JsonField.of(detectionSource)) @@ -530,7 +499,6 @@ private constructor( */ fun build(): AiGenerated = AiGenerated( - canEdit, detectionSource, hasAiGeneratedMedia, additionalProperties.toMutableMap(), @@ -553,7 +521,6 @@ private constructor( return@apply } - canEdit() detectionSource() hasAiGeneratedMedia() validated = true @@ -575,8 +542,7 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (canEdit.asKnown().isPresent) 1 else 0) + - (if (detectionSource.asKnown().isPresent) 1 else 0) + + (if (detectionSource.asKnown().isPresent) 1 else 0) + (if (hasAiGeneratedMedia.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { @@ -585,20 +551,19 @@ private constructor( } return other is AiGenerated && - canEdit == other.canEdit && detectionSource == other.detectionSource && hasAiGeneratedMedia == other.hasAiGeneratedMedia && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(canEdit, detectionSource, hasAiGeneratedMedia, additionalProperties) + Objects.hash(detectionSource, hasAiGeneratedMedia, additionalProperties) } override fun hashCode(): Int = hashCode override fun toString() = - "AiGenerated{canEdit=$canEdit, detectionSource=$detectionSource, hasAiGeneratedMedia=$hasAiGeneratedMedia, additionalProperties=$additionalProperties}" + "AiGenerated{detectionSource=$detectionSource, hasAiGeneratedMedia=$hasAiGeneratedMedia, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweet.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweet.kt index 478c879..a0ccb5e 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweet.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweet.kt @@ -39,11 +39,15 @@ private constructor( private val retweetCount: JsonField, private val text: JsonField, private val viewCount: JsonField, + private val article: JsonField
, private val author: JsonField, + private val card: JsonField, + private val communityNote: JsonField, private val contentDisclosure: JsonField, private val conversationId: JsonField, private val createdAt: JsonField, private val displayTextRange: JsonField>, + private val edit: JsonField, private val entities: JsonField, private val inReplyToId: JsonField, private val inReplyToUserId: JsonField, @@ -52,11 +56,19 @@ private constructor( private val isNoteTweet: JsonField, private val isQuoteStatus: JsonField, private val isReply: JsonField, + private val isTranslatable: JsonField, private val lang: JsonField, private val media: JsonField>, + private val noteTweet: JsonField, + private val place: JsonField, + private val possiblySensitive: JsonField, + private val previousCounts: JsonField, + private val quotedTweet: JsonField, + private val retweetedTweet: JsonField, private val source: JsonField, private val type: JsonField, private val url: JsonField, + private val viewState: JsonField, private val additionalProperties: MutableMap, ) { @@ -74,7 +86,12 @@ private constructor( retweetCount: JsonField = JsonMissing.of(), @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), @JsonProperty("viewCount") @ExcludeMissing viewCount: JsonField = JsonMissing.of(), + @JsonProperty("article") @ExcludeMissing article: JsonField
= JsonMissing.of(), @JsonProperty("author") @ExcludeMissing author: JsonField = JsonMissing.of(), + @JsonProperty("card") @ExcludeMissing card: JsonField = JsonMissing.of(), + @JsonProperty("communityNote") + @ExcludeMissing + communityNote: JsonField = JsonMissing.of(), @JsonProperty("contentDisclosure") @ExcludeMissing contentDisclosure: JsonField = JsonMissing.of(), @@ -85,6 +102,7 @@ private constructor( @JsonProperty("displayTextRange") @ExcludeMissing displayTextRange: JsonField> = JsonMissing.of(), + @JsonProperty("edit") @ExcludeMissing edit: JsonField = JsonMissing.of(), @JsonProperty("entities") @ExcludeMissing entities: JsonField = JsonMissing.of(), @JsonProperty("inReplyToId") @ExcludeMissing @@ -105,13 +123,33 @@ private constructor( @ExcludeMissing isQuoteStatus: JsonField = JsonMissing.of(), @JsonProperty("isReply") @ExcludeMissing isReply: JsonField = JsonMissing.of(), + @JsonProperty("isTranslatable") + @ExcludeMissing + isTranslatable: JsonField = JsonMissing.of(), @JsonProperty("lang") @ExcludeMissing lang: JsonField = JsonMissing.of(), @JsonProperty("media") @ExcludeMissing media: JsonField> = JsonMissing.of(), + @JsonProperty("noteTweet") + @ExcludeMissing + noteTweet: JsonField = JsonMissing.of(), + @JsonProperty("place") @ExcludeMissing place: JsonField = JsonMissing.of(), + @JsonProperty("possiblySensitive") + @ExcludeMissing + possiblySensitive: JsonField = JsonMissing.of(), + @JsonProperty("previousCounts") + @ExcludeMissing + previousCounts: JsonField = JsonMissing.of(), + @JsonProperty("quoted_tweet") + @ExcludeMissing + quotedTweet: JsonField = JsonMissing.of(), + @JsonProperty("retweeted_tweet") + @ExcludeMissing + retweetedTweet: JsonField = JsonMissing.of(), @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("viewState") @ExcludeMissing viewState: JsonField = JsonMissing.of(), ) : this( id, bookmarkCount, @@ -121,11 +159,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -134,11 +176,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, + quotedTweet, + retweetedTweet, source, type, url, + viewState, mutableMapOf(), ) @@ -190,6 +240,14 @@ private constructor( */ fun viewCount(): Long = viewCount.getRequired("viewCount") + /** + * Article metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun article(): Optional
= article.getOptional("article") + /** * X user profile with bio, follower counts, and verification status. * @@ -198,6 +256,22 @@ private constructor( */ fun author(): Optional = author.getOptional("author") + /** + * Public card metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun card(): Optional = card.getOptional("card") + + /** + * Community Note presentation metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun communityNote(): Optional = communityNote.getOptional("communityNote") + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership content or * AI-generated media. @@ -226,6 +300,14 @@ private constructor( */ fun displayTextRange(): Optional> = displayTextRange.getOptional("displayTextRange") + /** + * Edit history metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun edit(): Optional = edit.getOptional("edit") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -274,6 +356,12 @@ private constructor( */ fun isReply(): Optional = isReply.getOptional("isReply") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isTranslatable(): Optional = isTranslatable.getOptional("isTranslatable") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -286,6 +374,56 @@ private constructor( */ fun media(): Optional> = media.getOptional("media") + /** + * Complete Note Tweet content and rich-text metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun noteTweet(): Optional = noteTweet.getOptional("noteTweet") + + /** + * Public place metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun place(): Optional = place.getOptional("place") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun possiblySensitive(): Optional = possiblySensitive.getOptional("possiblySensitive") + + /** + * Engagement counts retained from a prior tweet edit. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun previousCounts(): Optional = previousCounts.getOptional("previousCounts") + + /** + * Quoted or retweeted tweet context. Every object includes id, text, and engagement metrics. A + * zero metric can mean X did not report the count. Author, media, and conversation fields + * appear when available. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun quotedTweet(): Optional = quotedTweet.getOptional("quoted_tweet") + + /** + * Quoted or retweeted tweet context. Every object includes id, text, and engagement metrics. A + * zero metric can mean X did not report the count. Author, media, and conversation fields + * appear when available. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun retweetedTweet(): Optional = retweetedTweet.getOptional("retweeted_tweet") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -304,6 +442,12 @@ private constructor( */ fun url(): Optional = url.getOptional("url") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewState(): Optional = viewState.getOptional("viewState") + /** * Returns the raw JSON value of [id]. * @@ -364,6 +508,13 @@ private constructor( */ @JsonProperty("viewCount") @ExcludeMissing fun _viewCount(): JsonField = viewCount + /** + * Returns the raw JSON value of [article]. + * + * Unlike [article], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("article") @ExcludeMissing fun _article(): JsonField
= article + /** * Returns the raw JSON value of [author]. * @@ -371,6 +522,22 @@ private constructor( */ @JsonProperty("author") @ExcludeMissing fun _author(): JsonField = author + /** + * Returns the raw JSON value of [card]. + * + * Unlike [card], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("card") @ExcludeMissing fun _card(): JsonField = card + + /** + * Returns the raw JSON value of [communityNote]. + * + * Unlike [communityNote], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("communityNote") + @ExcludeMissing + fun _communityNote(): JsonField = communityNote + /** * Returns the raw JSON value of [contentDisclosure]. * @@ -407,6 +574,13 @@ private constructor( @ExcludeMissing fun _displayTextRange(): JsonField> = displayTextRange + /** + * Returns the raw JSON value of [edit]. + * + * Unlike [edit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("edit") @ExcludeMissing fun _edit(): JsonField = edit + /** * Returns the raw JSON value of [entities]. * @@ -474,6 +648,15 @@ private constructor( */ @JsonProperty("isReply") @ExcludeMissing fun _isReply(): JsonField = isReply + /** + * Returns the raw JSON value of [isTranslatable]. + * + * Unlike [isTranslatable], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("isTranslatable") + @ExcludeMissing + fun _isTranslatable(): JsonField = isTranslatable + /** * Returns the raw JSON value of [lang]. * @@ -488,6 +671,57 @@ private constructor( */ @JsonProperty("media") @ExcludeMissing fun _media(): JsonField> = media + /** + * Returns the raw JSON value of [noteTweet]. + * + * Unlike [noteTweet], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("noteTweet") @ExcludeMissing fun _noteTweet(): JsonField = noteTweet + + /** + * Returns the raw JSON value of [place]. + * + * Unlike [place], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("place") @ExcludeMissing fun _place(): JsonField = place + + /** + * Returns the raw JSON value of [possiblySensitive]. + * + * Unlike [possiblySensitive], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("possiblySensitive") + @ExcludeMissing + fun _possiblySensitive(): JsonField = possiblySensitive + + /** + * Returns the raw JSON value of [previousCounts]. + * + * Unlike [previousCounts], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previousCounts") + @ExcludeMissing + fun _previousCounts(): JsonField = previousCounts + + /** + * Returns the raw JSON value of [quotedTweet]. + * + * Unlike [quotedTweet], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("quoted_tweet") + @ExcludeMissing + fun _quotedTweet(): JsonField = quotedTweet + + /** + * Returns the raw JSON value of [retweetedTweet]. + * + * Unlike [retweetedTweet], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("retweeted_tweet") + @ExcludeMissing + fun _retweetedTweet(): JsonField = retweetedTweet + /** * Returns the raw JSON value of [source]. * @@ -509,6 +743,13 @@ private constructor( */ @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + /** + * Returns the raw JSON value of [viewState]. + * + * Unlike [viewState], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("viewState") @ExcludeMissing fun _viewState(): JsonField = viewState + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -552,11 +793,15 @@ private constructor( private var retweetCount: JsonField? = null private var text: JsonField? = null private var viewCount: JsonField? = null + private var article: JsonField
= JsonMissing.of() private var author: JsonField = JsonMissing.of() + private var card: JsonField = JsonMissing.of() + private var communityNote: JsonField = JsonMissing.of() private var contentDisclosure: JsonField = JsonMissing.of() private var conversationId: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() private var displayTextRange: JsonField>? = null + private var edit: JsonField = JsonMissing.of() private var entities: JsonField = JsonMissing.of() private var inReplyToId: JsonField = JsonMissing.of() private var inReplyToUserId: JsonField = JsonMissing.of() @@ -565,11 +810,19 @@ private constructor( private var isNoteTweet: JsonField = JsonMissing.of() private var isQuoteStatus: JsonField = JsonMissing.of() private var isReply: JsonField = JsonMissing.of() + private var isTranslatable: JsonField = JsonMissing.of() private var lang: JsonField = JsonMissing.of() private var media: JsonField>? = null + private var noteTweet: JsonField = JsonMissing.of() + private var place: JsonField = JsonMissing.of() + private var possiblySensitive: JsonField = JsonMissing.of() + private var previousCounts: JsonField = JsonMissing.of() + private var quotedTweet: JsonField = JsonMissing.of() + private var retweetedTweet: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() private var type: JsonField = JsonMissing.of() private var url: JsonField = JsonMissing.of() + private var viewState: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -582,11 +835,15 @@ private constructor( retweetCount = embeddedTweet.retweetCount text = embeddedTweet.text viewCount = embeddedTweet.viewCount + article = embeddedTweet.article author = embeddedTweet.author + card = embeddedTweet.card + communityNote = embeddedTweet.communityNote contentDisclosure = embeddedTweet.contentDisclosure conversationId = embeddedTweet.conversationId createdAt = embeddedTweet.createdAt displayTextRange = embeddedTweet.displayTextRange.map { it.toMutableList() } + edit = embeddedTweet.edit entities = embeddedTweet.entities inReplyToId = embeddedTweet.inReplyToId inReplyToUserId = embeddedTweet.inReplyToUserId @@ -595,11 +852,19 @@ private constructor( isNoteTweet = embeddedTweet.isNoteTweet isQuoteStatus = embeddedTweet.isQuoteStatus isReply = embeddedTweet.isReply + isTranslatable = embeddedTweet.isTranslatable lang = embeddedTweet.lang media = embeddedTweet.media.map { it.toMutableList() } + noteTweet = embeddedTweet.noteTweet + place = embeddedTweet.place + possiblySensitive = embeddedTweet.possiblySensitive + previousCounts = embeddedTweet.previousCounts + quotedTweet = embeddedTweet.quotedTweet + retweetedTweet = embeddedTweet.retweetedTweet source = embeddedTweet.source type = embeddedTweet.type url = embeddedTweet.url + viewState = embeddedTweet.viewState additionalProperties = embeddedTweet.additionalProperties.toMutableMap() } @@ -687,6 +952,17 @@ private constructor( */ fun viewCount(viewCount: JsonField) = apply { this.viewCount = viewCount } + /** Article metadata attached to a tweet. */ + fun article(article: Article) = article(JsonField.of(article)) + + /** + * Sets [Builder.article] to an arbitrary JSON value. + * + * You should usually call [Builder.article] with a well-typed [Article] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun article(article: JsonField
) = apply { this.article = article } + /** X user profile with bio, follower counts, and verification status. */ fun author(author: UserProfile) = author(JsonField.of(author)) @@ -699,6 +975,31 @@ private constructor( */ fun author(author: JsonField) = apply { this.author = author } + /** Public card metadata attached to a tweet. */ + fun card(card: Card) = card(JsonField.of(card)) + + /** + * Sets [Builder.card] to an arbitrary JSON value. + * + * You should usually call [Builder.card] with a well-typed [Card] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun card(card: JsonField) = apply { this.card = card } + + /** Community Note presentation metadata returned by X. */ + fun communityNote(communityNote: CommunityNote) = communityNote(JsonField.of(communityNote)) + + /** + * Sets [Builder.communityNote] to an arbitrary JSON value. + * + * You should usually call [Builder.communityNote] with a well-typed [CommunityNote] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun communityNote(communityNote: JsonField) = apply { + this.communityNote = communityNote + } + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership * content or AI-generated media. @@ -767,6 +1068,17 @@ private constructor( } } + /** Edit history metadata returned by X. */ + fun edit(edit: Edit) = edit(JsonField.of(edit)) + + /** + * Sets [Builder.edit] to an arbitrary JSON value. + * + * You should usually call [Builder.edit] with a well-typed [Edit] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun edit(edit: JsonField) = apply { this.edit = edit } + fun entities(entities: Entities) = entities(JsonField.of(entities)) /** @@ -864,6 +1176,19 @@ private constructor( */ fun isReply(isReply: JsonField) = apply { this.isReply = isReply } + fun isTranslatable(isTranslatable: Boolean) = isTranslatable(JsonField.of(isTranslatable)) + + /** + * Sets [Builder.isTranslatable] to an arbitrary JSON value. + * + * You should usually call [Builder.isTranslatable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isTranslatable(isTranslatable: JsonField) = apply { + this.isTranslatable = isTranslatable + } + fun lang(lang: String) = lang(JsonField.of(lang)) /** @@ -899,6 +1224,95 @@ private constructor( } } + /** Complete Note Tweet content and rich-text metadata. */ + fun noteTweet(noteTweet: NoteTweet) = noteTweet(JsonField.of(noteTweet)) + + /** + * Sets [Builder.noteTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.noteTweet] with a well-typed [NoteTweet] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun noteTweet(noteTweet: JsonField) = apply { this.noteTweet = noteTweet } + + /** Public place metadata attached to a tweet. */ + fun place(place: Place) = place(JsonField.of(place)) + + /** + * Sets [Builder.place] to an arbitrary JSON value. + * + * You should usually call [Builder.place] with a well-typed [Place] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun place(place: JsonField) = apply { this.place = place } + + fun possiblySensitive(possiblySensitive: Boolean) = + possiblySensitive(JsonField.of(possiblySensitive)) + + /** + * Sets [Builder.possiblySensitive] to an arbitrary JSON value. + * + * You should usually call [Builder.possiblySensitive] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun possiblySensitive(possiblySensitive: JsonField) = apply { + this.possiblySensitive = possiblySensitive + } + + /** Engagement counts retained from a prior tweet edit. */ + fun previousCounts(previousCounts: PreviousCounts) = + previousCounts(JsonField.of(previousCounts)) + + /** + * Sets [Builder.previousCounts] to an arbitrary JSON value. + * + * You should usually call [Builder.previousCounts] with a well-typed [PreviousCounts] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previousCounts(previousCounts: JsonField) = apply { + this.previousCounts = previousCounts + } + + /** + * Quoted or retweeted tweet context. Every object includes id, text, and engagement + * metrics. A zero metric can mean X did not report the count. Author, media, and + * conversation fields appear when available. + */ + fun quotedTweet(quotedTweet: EmbeddedTweet) = quotedTweet(JsonField.of(quotedTweet)) + + /** + * Sets [Builder.quotedTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.quotedTweet] with a well-typed [EmbeddedTweet] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun quotedTweet(quotedTweet: JsonField) = apply { + this.quotedTweet = quotedTweet + } + + /** + * Quoted or retweeted tweet context. Every object includes id, text, and engagement + * metrics. A zero metric can mean X did not report the count. Author, media, and + * conversation fields appear when available. + */ + fun retweetedTweet(retweetedTweet: EmbeddedTweet) = + retweetedTweet(JsonField.of(retweetedTweet)) + + /** + * Sets [Builder.retweetedTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.retweetedTweet] with a well-typed [EmbeddedTweet] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun retweetedTweet(retweetedTweet: JsonField) = apply { + this.retweetedTweet = retweetedTweet + } + fun source(source: String) = source(JsonField.of(source)) /** @@ -929,6 +1343,17 @@ private constructor( */ fun url(url: JsonField) = apply { this.url = url } + fun viewState(viewState: String) = viewState(JsonField.of(viewState)) + + /** + * Sets [Builder.viewState] to an arbitrary JSON value. + * + * You should usually call [Builder.viewState] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewState(viewState: JsonField) = apply { this.viewState = viewState } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -977,11 +1402,15 @@ private constructor( checkRequired("retweetCount", retweetCount), checkRequired("text", text), checkRequired("viewCount", viewCount), + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, (displayTextRange ?: JsonMissing.of()).map { it.toImmutable() }, + edit, entities, inReplyToId, inReplyToUserId, @@ -990,11 +1419,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, (media ?: JsonMissing.of()).map { it.toImmutable() }, + noteTweet, + place, + possiblySensitive, + previousCounts, + quotedTweet, + retweetedTweet, source, type, url, + viewState, additionalProperties.toMutableMap(), ) } @@ -1022,11 +1459,15 @@ private constructor( retweetCount() text() viewCount() + article().ifPresent { it.validate() } author().ifPresent { it.validate() } + card().ifPresent { it.validate() } + communityNote().ifPresent { it.validate() } contentDisclosure().ifPresent { it.validate() } conversationId() createdAt() displayTextRange() + edit().ifPresent { it.validate() } entities().ifPresent { it.validate() } inReplyToId() inReplyToUserId() @@ -1035,11 +1476,19 @@ private constructor( isNoteTweet() isQuoteStatus() isReply() + isTranslatable() lang() media().ifPresent { it.forEach { it.validate() } } + noteTweet().ifPresent { it.validate() } + place().ifPresent { it.validate() } + possiblySensitive() + previousCounts().ifPresent { it.validate() } + quotedTweet().ifPresent { it.validate() } + retweetedTweet().ifPresent { it.validate() } source() type() url() + viewState() validated = true } @@ -1066,11 +1515,15 @@ private constructor( (if (retweetCount.asKnown().isPresent) 1 else 0) + (if (text.asKnown().isPresent) 1 else 0) + (if (viewCount.asKnown().isPresent) 1 else 0) + + (article.asKnown().getOrNull()?.validity() ?: 0) + (author.asKnown().getOrNull()?.validity() ?: 0) + + (card.asKnown().getOrNull()?.validity() ?: 0) + + (communityNote.asKnown().getOrNull()?.validity() ?: 0) + (contentDisclosure.asKnown().getOrNull()?.validity() ?: 0) + (if (conversationId.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (displayTextRange.asKnown().getOrNull()?.size ?: 0) + + (edit.asKnown().getOrNull()?.validity() ?: 0) + (entities.asKnown().getOrNull()?.validity() ?: 0) + (if (inReplyToId.asKnown().isPresent) 1 else 0) + (if (inReplyToUserId.asKnown().isPresent) 1 else 0) + @@ -1079,42 +1532,2353 @@ private constructor( (if (isNoteTweet.asKnown().isPresent) 1 else 0) + (if (isQuoteStatus.asKnown().isPresent) 1 else 0) + (if (isReply.asKnown().isPresent) 1 else 0) + + (if (isTranslatable.asKnown().isPresent) 1 else 0) + (if (lang.asKnown().isPresent) 1 else 0) + (media.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (noteTweet.asKnown().getOrNull()?.validity() ?: 0) + + (place.asKnown().getOrNull()?.validity() ?: 0) + + (if (possiblySensitive.asKnown().isPresent) 1 else 0) + + (previousCounts.asKnown().getOrNull()?.validity() ?: 0) + + (quotedTweet.asKnown().getOrNull()?.validity() ?: 0) + + (retweetedTweet.asKnown().getOrNull()?.validity() ?: 0) + (if (source.asKnown().isPresent) 1 else 0) + (if (type.asKnown().isPresent) 1 else 0) + - (if (url.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + + (if (viewState.asKnown().isPresent) 1 else 0) - class Entities - @JsonCreator + /** Article metadata attached to a tweet. */ + class Article + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map + private val id: JsonField, + private val coverMediaUrl: JsonField, + private val previewText: JsonField, + private val title: JsonField, + private val additionalProperties: MutableMap, ) { - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("coverMediaUrl") + @ExcludeMissing + coverMediaUrl: JsonField = JsonMissing.of(), + @JsonProperty("previewText") + @ExcludeMissing + previewText: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + ) : this(id, coverMediaUrl, previewText, title, mutableMapOf()) - fun toBuilder() = Builder().from(this) + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") - companion object { + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun coverMediaUrl(): Optional = coverMediaUrl.getOptional("coverMediaUrl") - /** Returns a mutable builder for constructing an instance of [Entities]. */ - @JvmStatic fun builder() = Builder() - } + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun previewText(): Optional = previewText.getOptional("previewText") - /** A builder for [Entities]. */ - class Builder internal constructor() { + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") - private var additionalProperties: MutableMap = mutableMapOf() + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id - @JvmSynthetic - internal fun from(entities: Entities) = apply { - additionalProperties = entities.additionalProperties.toMutableMap() - } + /** + * Returns the raw JSON value of [coverMediaUrl]. + * + * Unlike [coverMediaUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("coverMediaUrl") + @ExcludeMissing + fun _coverMediaUrl(): JsonField = coverMediaUrl - fun additionalProperties(additionalProperties: Map) = apply { + /** + * Returns the raw JSON value of [previewText]. + * + * Unlike [previewText], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previewText") + @ExcludeMissing + fun _previewText(): JsonField = previewText + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Article]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Article]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var coverMediaUrl: JsonField = JsonMissing.of() + private var previewText: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(article: Article) = apply { + id = article.id + coverMediaUrl = article.coverMediaUrl + previewText = article.previewText + title = article.title + additionalProperties = article.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun coverMediaUrl(coverMediaUrl: String) = coverMediaUrl(JsonField.of(coverMediaUrl)) + + /** + * Sets [Builder.coverMediaUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.coverMediaUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun coverMediaUrl(coverMediaUrl: JsonField) = apply { + this.coverMediaUrl = coverMediaUrl + } + + fun previewText(previewText: String) = previewText(JsonField.of(previewText)) + + /** + * Sets [Builder.previewText] to an arbitrary JSON value. + * + * You should usually call [Builder.previewText] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previewText(previewText: JsonField) = apply { + this.previewText = previewText + } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Article]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Article = + Article(id, coverMediaUrl, previewText, title, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Article = apply { + if (validated) { + return@apply + } + + id() + coverMediaUrl() + previewText() + title() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (coverMediaUrl.asKnown().isPresent) 1 else 0) + + (if (previewText.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Article && + id == other.id && + coverMediaUrl == other.coverMediaUrl && + previewText == other.previewText && + title == other.title && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, coverMediaUrl, previewText, title, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Article{id=$id, coverMediaUrl=$coverMediaUrl, previewText=$previewText, title=$title, additionalProperties=$additionalProperties}" + } + + /** Public card metadata attached to a tweet. */ + class Card + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val bindingValues: JsonField, + private val name: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("bindingValues") + @ExcludeMissing + bindingValues: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(id, bindingValues, name, url, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bindingValues(): Optional = bindingValues.getOptional("bindingValues") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [bindingValues]. + * + * Unlike [bindingValues], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bindingValues") + @ExcludeMissing + fun _bindingValues(): JsonField = bindingValues + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Card]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Card]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var bindingValues: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(card: Card) = apply { + id = card.id + bindingValues = card.bindingValues + name = card.name + url = card.url + additionalProperties = card.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun bindingValues(bindingValues: BindingValues) = + bindingValues(JsonField.of(bindingValues)) + + /** + * Sets [Builder.bindingValues] to an arbitrary JSON value. + * + * You should usually call [Builder.bindingValues] with a well-typed [BindingValues] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun bindingValues(bindingValues: JsonField) = apply { + this.bindingValues = bindingValues + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Card]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Card = + Card(id, bindingValues, name, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Card = apply { + if (validated) { + return@apply + } + + id() + bindingValues().ifPresent { it.validate() } + name() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (bindingValues.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BindingValues + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BindingValues]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BindingValues]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(bindingValues: BindingValues) = apply { + additionalProperties = bindingValues.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BindingValues]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BindingValues = BindingValues(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BindingValues = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BindingValues && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BindingValues{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Card && + id == other.id && + bindingValues == other.bindingValues && + name == other.name && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, bindingValues, name, url, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Card{id=$id, bindingValues=$bindingValues, name=$name, url=$url, additionalProperties=$additionalProperties}" + } + + /** Community Note presentation metadata returned by X. */ + class CommunityNote + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val destinationUrl: JsonField, + private val footer: JsonField, + private val shortTitle: JsonField, + private val subtitle: JsonField, + private val title: JsonField, + private val visualStyle: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("destinationUrl") + @ExcludeMissing + destinationUrl: JsonField = JsonMissing.of(), + @JsonProperty("footer") @ExcludeMissing footer: JsonField = JsonMissing.of(), + @JsonProperty("shortTitle") + @ExcludeMissing + shortTitle: JsonField = JsonMissing.of(), + @JsonProperty("subtitle") + @ExcludeMissing + subtitle: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + @JsonProperty("visualStyle") + @ExcludeMissing + visualStyle: JsonField = JsonMissing.of(), + ) : this( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun destinationUrl(): Optional = destinationUrl.getOptional("destinationUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun footer(): Optional = footer.getOptional("footer") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun shortTitle(): Optional = shortTitle.getOptional("shortTitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun subtitle(): Optional = subtitle.getOptional("subtitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun visualStyle(): Optional = visualStyle.getOptional("visualStyle") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [destinationUrl]. + * + * Unlike [destinationUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("destinationUrl") + @ExcludeMissing + fun _destinationUrl(): JsonField = destinationUrl + + /** + * Returns the raw JSON value of [footer]. + * + * Unlike [footer], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("footer") @ExcludeMissing fun _footer(): JsonField = footer + + /** + * Returns the raw JSON value of [shortTitle]. + * + * Unlike [shortTitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("shortTitle") + @ExcludeMissing + fun _shortTitle(): JsonField = shortTitle + + /** + * Returns the raw JSON value of [subtitle]. + * + * Unlike [subtitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("subtitle") @ExcludeMissing fun _subtitle(): JsonField = subtitle + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + /** + * Returns the raw JSON value of [visualStyle]. + * + * Unlike [visualStyle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("visualStyle") + @ExcludeMissing + fun _visualStyle(): JsonField = visualStyle + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [CommunityNote]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CommunityNote]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var destinationUrl: JsonField = JsonMissing.of() + private var footer: JsonField = JsonMissing.of() + private var shortTitle: JsonField = JsonMissing.of() + private var subtitle: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var visualStyle: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(communityNote: CommunityNote) = apply { + id = communityNote.id + destinationUrl = communityNote.destinationUrl + footer = communityNote.footer + shortTitle = communityNote.shortTitle + subtitle = communityNote.subtitle + title = communityNote.title + visualStyle = communityNote.visualStyle + additionalProperties = communityNote.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun destinationUrl(destinationUrl: String) = + destinationUrl(JsonField.of(destinationUrl)) + + /** + * Sets [Builder.destinationUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.destinationUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun destinationUrl(destinationUrl: JsonField) = apply { + this.destinationUrl = destinationUrl + } + + fun footer(footer: String) = footer(JsonField.of(footer)) + + /** + * Sets [Builder.footer] to an arbitrary JSON value. + * + * You should usually call [Builder.footer] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun footer(footer: JsonField) = apply { this.footer = footer } + + fun shortTitle(shortTitle: String) = shortTitle(JsonField.of(shortTitle)) + + /** + * Sets [Builder.shortTitle] to an arbitrary JSON value. + * + * You should usually call [Builder.shortTitle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun shortTitle(shortTitle: JsonField) = apply { this.shortTitle = shortTitle } + + fun subtitle(subtitle: String) = subtitle(JsonField.of(subtitle)) + + /** + * Sets [Builder.subtitle] to an arbitrary JSON value. + * + * You should usually call [Builder.subtitle] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun subtitle(subtitle: JsonField) = apply { this.subtitle = subtitle } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + fun visualStyle(visualStyle: String) = visualStyle(JsonField.of(visualStyle)) + + /** + * Sets [Builder.visualStyle] to an arbitrary JSON value. + * + * You should usually call [Builder.visualStyle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun visualStyle(visualStyle: JsonField) = apply { + this.visualStyle = visualStyle + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CommunityNote]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): CommunityNote = + CommunityNote( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): CommunityNote = apply { + if (validated) { + return@apply + } + + id() + destinationUrl() + footer() + shortTitle() + subtitle() + title() + visualStyle() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (destinationUrl.asKnown().isPresent) 1 else 0) + + (if (footer.asKnown().isPresent) 1 else 0) + + (if (shortTitle.asKnown().isPresent) 1 else 0) + + (if (subtitle.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) + + (if (visualStyle.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CommunityNote && + id == other.id && + destinationUrl == other.destinationUrl && + footer == other.footer && + shortTitle == other.shortTitle && + subtitle == other.subtitle && + title == other.title && + visualStyle == other.visualStyle && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CommunityNote{id=$id, destinationUrl=$destinationUrl, footer=$footer, shortTitle=$shortTitle, subtitle=$subtitle, title=$title, visualStyle=$visualStyle, additionalProperties=$additionalProperties}" + } + + /** Edit history metadata returned by X. */ + class Edit + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val editableUntilMsecs: JsonField, + private val editTweetIds: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + editableUntilMsecs: JsonField = JsonMissing.of(), + @JsonProperty("editTweetIds") + @ExcludeMissing + editTweetIds: JsonField> = JsonMissing.of(), + ) : this(editableUntilMsecs, editTweetIds, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editableUntilMsecs(): Optional = + editableUntilMsecs.getOptional("editableUntilMsecs") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editTweetIds(): Optional> = editTweetIds.getOptional("editTweetIds") + + /** + * Returns the raw JSON value of [editableUntilMsecs]. + * + * Unlike [editableUntilMsecs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + fun _editableUntilMsecs(): JsonField = editableUntilMsecs + + /** + * Returns the raw JSON value of [editTweetIds]. + * + * Unlike [editTweetIds], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("editTweetIds") + @ExcludeMissing + fun _editTweetIds(): JsonField> = editTweetIds + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Edit]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Edit]. */ + class Builder internal constructor() { + + private var editableUntilMsecs: JsonField = JsonMissing.of() + private var editTweetIds: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(edit: Edit) = apply { + editableUntilMsecs = edit.editableUntilMsecs + editTweetIds = edit.editTweetIds.map { it.toMutableList() } + additionalProperties = edit.additionalProperties.toMutableMap() + } + + fun editableUntilMsecs(editableUntilMsecs: String) = + editableUntilMsecs(JsonField.of(editableUntilMsecs)) + + /** + * Sets [Builder.editableUntilMsecs] to an arbitrary JSON value. + * + * You should usually call [Builder.editableUntilMsecs] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editableUntilMsecs(editableUntilMsecs: JsonField) = apply { + this.editableUntilMsecs = editableUntilMsecs + } + + fun editTweetIds(editTweetIds: List) = editTweetIds(JsonField.of(editTweetIds)) + + /** + * Sets [Builder.editTweetIds] to an arbitrary JSON value. + * + * You should usually call [Builder.editTweetIds] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editTweetIds(editTweetIds: JsonField>) = apply { + this.editTweetIds = editTweetIds.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [editTweetIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEditTweetId(editTweetId: String) = apply { + editTweetIds = + (editTweetIds ?: JsonField.of(mutableListOf())).also { + checkKnown("editTweetIds", it).add(editTweetId) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Edit]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Edit = + Edit( + editableUntilMsecs, + (editTweetIds ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Edit = apply { + if (validated) { + return@apply + } + + editableUntilMsecs() + editTweetIds() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (editableUntilMsecs.asKnown().isPresent) 1 else 0) + + (editTweetIds.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Edit && + editableUntilMsecs == other.editableUntilMsecs && + editTweetIds == other.editTweetIds && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(editableUntilMsecs, editTweetIds, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Edit{editableUntilMsecs=$editableUntilMsecs, editTweetIds=$editTweetIds, additionalProperties=$additionalProperties}" + } + + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + /** Complete Note Tweet content and rich-text metadata. */ + class NoteTweet + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val text: JsonField, + private val id: JsonField, + private val entities: JsonField, + private val isExpandable: JsonField, + private val richtextTags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("entities") + @ExcludeMissing + entities: JsonField = JsonMissing.of(), + @JsonProperty("isExpandable") + @ExcludeMissing + isExpandable: JsonField = JsonMissing.of(), + @JsonProperty("richtextTags") + @ExcludeMissing + richtextTags: JsonField> = JsonMissing.of(), + ) : this(text, id, entities, isExpandable, richtextTags, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun text(): String = text.getRequired("text") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun entities(): Optional = entities.getOptional("entities") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isExpandable(): Optional = isExpandable.getOptional("isExpandable") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun richtextTags(): Optional> = richtextTags.getOptional("richtextTags") + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [entities]. + * + * Unlike [entities], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("entities") @ExcludeMissing fun _entities(): JsonField = entities + + /** + * Returns the raw JSON value of [isExpandable]. + * + * Unlike [isExpandable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isExpandable") + @ExcludeMissing + fun _isExpandable(): JsonField = isExpandable + + /** + * Returns the raw JSON value of [richtextTags]. + * + * Unlike [richtextTags], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("richtextTags") + @ExcludeMissing + fun _richtextTags(): JsonField> = richtextTags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [NoteTweet]. + * + * The following fields are required: + * ```java + * .text() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [NoteTweet]. */ + class Builder internal constructor() { + + private var text: JsonField? = null + private var id: JsonField = JsonMissing.of() + private var entities: JsonField = JsonMissing.of() + private var isExpandable: JsonField = JsonMissing.of() + private var richtextTags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(noteTweet: NoteTweet) = apply { + text = noteTweet.text + id = noteTweet.id + entities = noteTweet.entities + isExpandable = noteTweet.isExpandable + richtextTags = noteTweet.richtextTags.map { it.toMutableList() } + additionalProperties = noteTweet.additionalProperties.toMutableMap() + } + + fun text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun entities(entities: Entities) = entities(JsonField.of(entities)) + + /** + * Sets [Builder.entities] to an arbitrary JSON value. + * + * You should usually call [Builder.entities] with a well-typed [Entities] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun entities(entities: JsonField) = apply { this.entities = entities } + + fun isExpandable(isExpandable: Boolean) = isExpandable(JsonField.of(isExpandable)) + + /** + * Sets [Builder.isExpandable] to an arbitrary JSON value. + * + * You should usually call [Builder.isExpandable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isExpandable(isExpandable: JsonField) = apply { + this.isExpandable = isExpandable + } + + fun richtextTags(richtextTags: List) = + richtextTags(JsonField.of(richtextTags)) + + /** + * Sets [Builder.richtextTags] to an arbitrary JSON value. + * + * You should usually call [Builder.richtextTags] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun richtextTags(richtextTags: JsonField>) = apply { + this.richtextTags = richtextTags.map { it.toMutableList() } + } + + /** + * Adds a single [RichtextTag] to [richtextTags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRichtextTag(richtextTag: RichtextTag) = apply { + richtextTags = + (richtextTags ?: JsonField.of(mutableListOf())).also { + checkKnown("richtextTags", it).add(richtextTag) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [NoteTweet]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .text() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): NoteTweet = + NoteTweet( + checkRequired("text", text), + id, + entities, + isExpandable, + (richtextTags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): NoteTweet = apply { + if (validated) { + return@apply + } + + text() + id() + entities().ifPresent { it.validate() } + isExpandable() + richtextTags().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (text.asKnown().isPresent) 1 else 0) + + (if (id.asKnown().isPresent) 1 else 0) + + (entities.asKnown().getOrNull()?.validity() ?: 0) + + (if (isExpandable.asKnown().isPresent) 1 else 0) + + (richtextTags.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + class RichtextTag + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val fromIndex: JsonField, + private val toIndex: JsonField, + private val types: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("fromIndex") + @ExcludeMissing + fromIndex: JsonField = JsonMissing.of(), + @JsonProperty("toIndex") + @ExcludeMissing + toIndex: JsonField = JsonMissing.of(), + @JsonProperty("types") + @ExcludeMissing + types: JsonField> = JsonMissing.of(), + ) : this(fromIndex, toIndex, types, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun fromIndex(): Long = fromIndex.getRequired("fromIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun toIndex(): Long = toIndex.getRequired("toIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun types(): List = types.getRequired("types") + + /** + * Returns the raw JSON value of [fromIndex]. + * + * Unlike [fromIndex], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("fromIndex") @ExcludeMissing fun _fromIndex(): JsonField = fromIndex + + /** + * Returns the raw JSON value of [toIndex]. + * + * Unlike [toIndex], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("toIndex") @ExcludeMissing fun _toIndex(): JsonField = toIndex + + /** + * Returns the raw JSON value of [types]. + * + * Unlike [types], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("types") @ExcludeMissing fun _types(): JsonField> = types + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RichtextTag]. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RichtextTag]. */ + class Builder internal constructor() { + + private var fromIndex: JsonField? = null + private var toIndex: JsonField? = null + private var types: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(richtextTag: RichtextTag) = apply { + fromIndex = richtextTag.fromIndex + toIndex = richtextTag.toIndex + types = richtextTag.types.map { it.toMutableList() } + additionalProperties = richtextTag.additionalProperties.toMutableMap() + } + + fun fromIndex(fromIndex: Long) = fromIndex(JsonField.of(fromIndex)) + + /** + * Sets [Builder.fromIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.fromIndex] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun fromIndex(fromIndex: JsonField) = apply { this.fromIndex = fromIndex } + + fun toIndex(toIndex: Long) = toIndex(JsonField.of(toIndex)) + + /** + * Sets [Builder.toIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.toIndex] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun toIndex(toIndex: JsonField) = apply { this.toIndex = toIndex } + + fun types(types: List) = types(JsonField.of(types)) + + /** + * Sets [Builder.types] to an arbitrary JSON value. + * + * You should usually call [Builder.types] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun types(types: JsonField>) = apply { + this.types = types.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [types]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addType(type: String) = apply { + types = + (types ?: JsonField.of(mutableListOf())).also { + checkKnown("types", it).add(type) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [RichtextTag]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RichtextTag = + RichtextTag( + checkRequired("fromIndex", fromIndex), + checkRequired("toIndex", toIndex), + checkRequired("types", types).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): RichtextTag = apply { + if (validated) { + return@apply + } + + fromIndex() + toIndex() + types() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (fromIndex.asKnown().isPresent) 1 else 0) + + (if (toIndex.asKnown().isPresent) 1 else 0) + + (types.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RichtextTag && + fromIndex == other.fromIndex && + toIndex == other.toIndex && + types == other.types && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(fromIndex, toIndex, types, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RichtextTag{fromIndex=$fromIndex, toIndex=$toIndex, types=$types, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is NoteTweet && + text == other.text && + id == other.id && + entities == other.entities && + isExpandable == other.isExpandable && + richtextTags == other.richtextTags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(text, id, entities, isExpandable, richtextTags, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "NoteTweet{text=$text, id=$id, entities=$entities, isExpandable=$isExpandable, richtextTags=$richtextTags, additionalProperties=$additionalProperties}" + } + + /** Public place metadata attached to a tweet. */ + class Place + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val boundingBox: JsonField, + private val country: JsonField, + private val countryCode: JsonField, + private val fullName: JsonField, + private val name: JsonField, + private val placeType: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("boundingBox") + @ExcludeMissing + boundingBox: JsonField = JsonMissing.of(), + @JsonProperty("country") @ExcludeMissing country: JsonField = JsonMissing.of(), + @JsonProperty("countryCode") + @ExcludeMissing + countryCode: JsonField = JsonMissing.of(), + @JsonProperty("fullName") + @ExcludeMissing + fullName: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("placeType") + @ExcludeMissing + placeType: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun boundingBox(): Optional = boundingBox.getOptional("boundingBox") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun country(): Optional = country.getOptional("country") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun countryCode(): Optional = countryCode.getOptional("countryCode") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun fullName(): Optional = fullName.getOptional("fullName") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun placeType(): Optional = placeType.getOptional("placeType") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [boundingBox]. + * + * Unlike [boundingBox], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("boundingBox") + @ExcludeMissing + fun _boundingBox(): JsonField = boundingBox + + /** + * Returns the raw JSON value of [country]. + * + * Unlike [country], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("country") @ExcludeMissing fun _country(): JsonField = country + + /** + * Returns the raw JSON value of [countryCode]. + * + * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("countryCode") + @ExcludeMissing + fun _countryCode(): JsonField = countryCode + + /** + * Returns the raw JSON value of [fullName]. + * + * Unlike [fullName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("fullName") @ExcludeMissing fun _fullName(): JsonField = fullName + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [placeType]. + * + * Unlike [placeType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("placeType") @ExcludeMissing fun _placeType(): JsonField = placeType + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Place]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Place]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var boundingBox: JsonField = JsonMissing.of() + private var country: JsonField = JsonMissing.of() + private var countryCode: JsonField = JsonMissing.of() + private var fullName: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var placeType: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(place: Place) = apply { + id = place.id + boundingBox = place.boundingBox + country = place.country + countryCode = place.countryCode + fullName = place.fullName + name = place.name + placeType = place.placeType + url = place.url + additionalProperties = place.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun boundingBox(boundingBox: BoundingBox) = boundingBox(JsonField.of(boundingBox)) + + /** + * Sets [Builder.boundingBox] to an arbitrary JSON value. + * + * You should usually call [Builder.boundingBox] with a well-typed [BoundingBox] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun boundingBox(boundingBox: JsonField) = apply { + this.boundingBox = boundingBox + } + + fun country(country: String) = country(JsonField.of(country)) + + /** + * Sets [Builder.country] to an arbitrary JSON value. + * + * You should usually call [Builder.country] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun country(country: JsonField) = apply { this.country = country } + + fun countryCode(countryCode: String) = countryCode(JsonField.of(countryCode)) + + /** + * Sets [Builder.countryCode] to an arbitrary JSON value. + * + * You should usually call [Builder.countryCode] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun countryCode(countryCode: JsonField) = apply { + this.countryCode = countryCode + } + + fun fullName(fullName: String) = fullName(JsonField.of(fullName)) + + /** + * Sets [Builder.fullName] to an arbitrary JSON value. + * + * You should usually call [Builder.fullName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fullName(fullName: JsonField) = apply { this.fullName = fullName } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun placeType(placeType: String) = placeType(JsonField.of(placeType)) + + /** + * Sets [Builder.placeType] to an arbitrary JSON value. + * + * You should usually call [Builder.placeType] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun placeType(placeType: JsonField) = apply { this.placeType = placeType } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) } @@ -1134,11 +3898,22 @@ private constructor( } /** - * Returns an immutable instance of [Entities]. + * Returns an immutable instance of [Place]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Entities = Entities(additionalProperties.toImmutable()) + fun build(): Place = + Place( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -1152,11 +3927,19 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): Entities = apply { + fun validate(): Place = apply { if (validated) { return@apply } + id() + boundingBox().ifPresent { it.validate() } + country() + countryCode() + fullName() + name() + placeType() + url() validated = true } @@ -1175,8 +3958,127 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (boundingBox.asKnown().getOrNull()?.validity() ?: 0) + + (if (country.asKnown().isPresent) 1 else 0) + + (if (countryCode.asKnown().isPresent) 1 else 0) + + (if (fullName.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (placeType.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BoundingBox + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BoundingBox]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BoundingBox]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(boundingBox: BoundingBox) = apply { + additionalProperties = boundingBox.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BoundingBox]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BoundingBox = BoundingBox(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BoundingBox = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BoundingBox && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BoundingBox{additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1184,14 +4086,347 @@ private constructor( return true } - return other is Entities && additionalProperties == other.additionalProperties + return other is Place && + id == other.id && + boundingBox == other.boundingBox && + country == other.country && + countryCode == other.countryCode && + fullName == other.fullName && + name == other.name && + placeType == other.placeType && + url == other.url && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties, + ) + } override fun hashCode(): Int = hashCode - override fun toString() = "Entities{additionalProperties=$additionalProperties}" + override fun toString() = + "Place{id=$id, boundingBox=$boundingBox, country=$country, countryCode=$countryCode, fullName=$fullName, name=$name, placeType=$placeType, url=$url, additionalProperties=$additionalProperties}" + } + + /** Engagement counts retained from a prior tweet edit. */ + class PreviousCounts + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val bookmarkCount: JsonField, + private val likeCount: JsonField, + private val quoteCount: JsonField, + private val replyCount: JsonField, + private val retweetCount: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("bookmarkCount") + @ExcludeMissing + bookmarkCount: JsonField = JsonMissing.of(), + @JsonProperty("likeCount") + @ExcludeMissing + likeCount: JsonField = JsonMissing.of(), + @JsonProperty("quoteCount") + @ExcludeMissing + quoteCount: JsonField = JsonMissing.of(), + @JsonProperty("replyCount") + @ExcludeMissing + replyCount: JsonField = JsonMissing.of(), + @JsonProperty("retweetCount") + @ExcludeMissing + retweetCount: JsonField = JsonMissing.of(), + ) : this(bookmarkCount, likeCount, quoteCount, replyCount, retweetCount, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bookmarkCount(): Optional = bookmarkCount.getOptional("bookmarkCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun likeCount(): Optional = likeCount.getOptional("likeCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun quoteCount(): Optional = quoteCount.getOptional("quoteCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun replyCount(): Optional = replyCount.getOptional("replyCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun retweetCount(): Optional = retweetCount.getOptional("retweetCount") + + /** + * Returns the raw JSON value of [bookmarkCount]. + * + * Unlike [bookmarkCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bookmarkCount") + @ExcludeMissing + fun _bookmarkCount(): JsonField = bookmarkCount + + /** + * Returns the raw JSON value of [likeCount]. + * + * Unlike [likeCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("likeCount") @ExcludeMissing fun _likeCount(): JsonField = likeCount + + /** + * Returns the raw JSON value of [quoteCount]. + * + * Unlike [quoteCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("quoteCount") @ExcludeMissing fun _quoteCount(): JsonField = quoteCount + + /** + * Returns the raw JSON value of [replyCount]. + * + * Unlike [replyCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("replyCount") @ExcludeMissing fun _replyCount(): JsonField = replyCount + + /** + * Returns the raw JSON value of [retweetCount]. + * + * Unlike [retweetCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("retweetCount") + @ExcludeMissing + fun _retweetCount(): JsonField = retweetCount + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [PreviousCounts]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreviousCounts]. */ + class Builder internal constructor() { + + private var bookmarkCount: JsonField = JsonMissing.of() + private var likeCount: JsonField = JsonMissing.of() + private var quoteCount: JsonField = JsonMissing.of() + private var replyCount: JsonField = JsonMissing.of() + private var retweetCount: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(previousCounts: PreviousCounts) = apply { + bookmarkCount = previousCounts.bookmarkCount + likeCount = previousCounts.likeCount + quoteCount = previousCounts.quoteCount + replyCount = previousCounts.replyCount + retweetCount = previousCounts.retweetCount + additionalProperties = previousCounts.additionalProperties.toMutableMap() + } + + fun bookmarkCount(bookmarkCount: Long) = bookmarkCount(JsonField.of(bookmarkCount)) + + /** + * Sets [Builder.bookmarkCount] to an arbitrary JSON value. + * + * You should usually call [Builder.bookmarkCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun bookmarkCount(bookmarkCount: JsonField) = apply { + this.bookmarkCount = bookmarkCount + } + + fun likeCount(likeCount: Long) = likeCount(JsonField.of(likeCount)) + + /** + * Sets [Builder.likeCount] to an arbitrary JSON value. + * + * You should usually call [Builder.likeCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun likeCount(likeCount: JsonField) = apply { this.likeCount = likeCount } + + fun quoteCount(quoteCount: Long) = quoteCount(JsonField.of(quoteCount)) + + /** + * Sets [Builder.quoteCount] to an arbitrary JSON value. + * + * You should usually call [Builder.quoteCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun quoteCount(quoteCount: JsonField) = apply { this.quoteCount = quoteCount } + + fun replyCount(replyCount: Long) = replyCount(JsonField.of(replyCount)) + + /** + * Sets [Builder.replyCount] to an arbitrary JSON value. + * + * You should usually call [Builder.replyCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun replyCount(replyCount: JsonField) = apply { this.replyCount = replyCount } + + fun retweetCount(retweetCount: Long) = retweetCount(JsonField.of(retweetCount)) + + /** + * Sets [Builder.retweetCount] to an arbitrary JSON value. + * + * You should usually call [Builder.retweetCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun retweetCount(retweetCount: JsonField) = apply { + this.retweetCount = retweetCount + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreviousCounts]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreviousCounts = + PreviousCounts( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): PreviousCounts = apply { + if (validated) { + return@apply + } + + bookmarkCount() + likeCount() + quoteCount() + replyCount() + retweetCount() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (bookmarkCount.asKnown().isPresent) 1 else 0) + + (if (likeCount.asKnown().isPresent) 1 else 0) + + (if (quoteCount.asKnown().isPresent) 1 else 0) + + (if (replyCount.asKnown().isPresent) 1 else 0) + + (if (retweetCount.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PreviousCounts && + bookmarkCount == other.bookmarkCount && + likeCount == other.likeCount && + quoteCount == other.quoteCount && + replyCount == other.replyCount && + retweetCount == other.retweetCount && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreviousCounts{bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1208,11 +4443,15 @@ private constructor( retweetCount == other.retweetCount && text == other.text && viewCount == other.viewCount && + article == other.article && author == other.author && + card == other.card && + communityNote == other.communityNote && contentDisclosure == other.contentDisclosure && conversationId == other.conversationId && createdAt == other.createdAt && displayTextRange == other.displayTextRange && + edit == other.edit && entities == other.entities && inReplyToId == other.inReplyToId && inReplyToUserId == other.inReplyToUserId && @@ -1221,11 +4460,19 @@ private constructor( isNoteTweet == other.isNoteTweet && isQuoteStatus == other.isQuoteStatus && isReply == other.isReply && + isTranslatable == other.isTranslatable && lang == other.lang && media == other.media && + noteTweet == other.noteTweet && + place == other.place && + possiblySensitive == other.possiblySensitive && + previousCounts == other.previousCounts && + quotedTweet == other.quotedTweet && + retweetedTweet == other.retweetedTweet && source == other.source && type == other.type && url == other.url && + viewState == other.viewState && additionalProperties == other.additionalProperties } @@ -1239,11 +4486,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -1252,11 +4503,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, + quotedTweet, + retweetedTweet, source, type, url, + viewState, additionalProperties, ) } @@ -1264,5 +4523,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "EmbeddedTweet{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, author=$author, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, lang=$lang, media=$media, source=$source, type=$type, url=$url, additionalProperties=$additionalProperties}" + "EmbeddedTweet{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, article=$article, author=$author, card=$card, communityNote=$communityNote, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, edit=$edit, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, isTranslatable=$isTranslatable, lang=$lang, media=$media, noteTweet=$noteTweet, place=$place, possiblySensitive=$possiblySensitive, previousCounts=$previousCounts, quotedTweet=$quotedTweet, retweetedTweet=$retweetedTweet, source=$source, type=$type, url=$url, viewState=$viewState, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/PaginatedTweets.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/PaginatedTweets.kt index 8c23502..5c33381 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/PaginatedTweets.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/PaginatedTweets.kt @@ -23,10 +23,9 @@ import java.util.Objects import kotlin.jvm.optionals.getOrNull /** - * Paginated tweet results. The item count can be lower than pageSize when the source returns fewer - * tweets, filters remove tweets, or remaining credits cover fewer results. Follow next_cursor while - * has_next_page is true. An empty page can still have has_next_page true after filtering. Zero - * affordable results returns 402 insufficient_credits. + * Paginated tweets. Source visibility, filters, or remaining credits can reduce results. An empty + * filtered page can still have has_next_page true. Follow next_cursor while has_next_page is true. + * Zero affordable results returns 402 insufficient_credits. */ class PaginatedTweets @JsonCreator(mode = JsonCreator.Mode.DISABLED) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/SearchTweet.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/SearchTweet.kt index b63d822..7395120 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/SearchTweet.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/SearchTweet.kt @@ -38,11 +38,15 @@ private constructor( private val retweetCount: JsonField, private val text: JsonField, private val viewCount: JsonField, + private val article: JsonField
, private val author: JsonField, + private val card: JsonField, + private val communityNote: JsonField, private val contentDisclosure: JsonField, private val conversationId: JsonField, private val createdAt: JsonField, private val displayTextRange: JsonField>, + private val edit: JsonField, private val entities: JsonField, private val inReplyToId: JsonField, private val inReplyToUserId: JsonField, @@ -51,13 +55,19 @@ private constructor( private val isNoteTweet: JsonField, private val isQuoteStatus: JsonField, private val isReply: JsonField, + private val isTranslatable: JsonField, private val lang: JsonField, private val media: JsonField>, + private val noteTweet: JsonField, + private val place: JsonField, + private val possiblySensitive: JsonField, + private val previousCounts: JsonField, private val quotedTweet: JsonField, private val retweetedTweet: JsonField, private val source: JsonField, private val type: JsonField, private val url: JsonField, + private val viewState: JsonField, private val additionalProperties: MutableMap, ) { @@ -75,7 +85,12 @@ private constructor( retweetCount: JsonField = JsonMissing.of(), @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), @JsonProperty("viewCount") @ExcludeMissing viewCount: JsonField = JsonMissing.of(), + @JsonProperty("article") @ExcludeMissing article: JsonField
= JsonMissing.of(), @JsonProperty("author") @ExcludeMissing author: JsonField = JsonMissing.of(), + @JsonProperty("card") @ExcludeMissing card: JsonField = JsonMissing.of(), + @JsonProperty("communityNote") + @ExcludeMissing + communityNote: JsonField = JsonMissing.of(), @JsonProperty("contentDisclosure") @ExcludeMissing contentDisclosure: JsonField = JsonMissing.of(), @@ -86,6 +101,7 @@ private constructor( @JsonProperty("displayTextRange") @ExcludeMissing displayTextRange: JsonField> = JsonMissing.of(), + @JsonProperty("edit") @ExcludeMissing edit: JsonField = JsonMissing.of(), @JsonProperty("entities") @ExcludeMissing entities: JsonField = JsonMissing.of(), @JsonProperty("inReplyToId") @ExcludeMissing @@ -106,10 +122,23 @@ private constructor( @ExcludeMissing isQuoteStatus: JsonField = JsonMissing.of(), @JsonProperty("isReply") @ExcludeMissing isReply: JsonField = JsonMissing.of(), + @JsonProperty("isTranslatable") + @ExcludeMissing + isTranslatable: JsonField = JsonMissing.of(), @JsonProperty("lang") @ExcludeMissing lang: JsonField = JsonMissing.of(), @JsonProperty("media") @ExcludeMissing media: JsonField> = JsonMissing.of(), + @JsonProperty("noteTweet") + @ExcludeMissing + noteTweet: JsonField = JsonMissing.of(), + @JsonProperty("place") @ExcludeMissing place: JsonField = JsonMissing.of(), + @JsonProperty("possiblySensitive") + @ExcludeMissing + possiblySensitive: JsonField = JsonMissing.of(), + @JsonProperty("previousCounts") + @ExcludeMissing + previousCounts: JsonField = JsonMissing.of(), @JsonProperty("quoted_tweet") @ExcludeMissing quotedTweet: JsonField = JsonMissing.of(), @@ -119,6 +148,7 @@ private constructor( @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("viewState") @ExcludeMissing viewState: JsonField = JsonMissing.of(), ) : this( id, bookmarkCount, @@ -128,11 +158,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -141,13 +175,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, mutableMapOf(), ) @@ -199,6 +239,14 @@ private constructor( */ fun viewCount(): Long = viewCount.getRequired("viewCount") + /** + * Article metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun article(): Optional
= article.getOptional("article") + /** * X user profile with bio, follower counts, and verification status. * @@ -207,6 +255,22 @@ private constructor( */ fun author(): Optional = author.getOptional("author") + /** + * Public card metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun card(): Optional = card.getOptional("card") + + /** + * Community Note presentation metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun communityNote(): Optional = communityNote.getOptional("communityNote") + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership content or * AI-generated media. @@ -239,6 +303,14 @@ private constructor( */ fun displayTextRange(): Optional> = displayTextRange.getOptional("displayTextRange") + /** + * Edit history metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun edit(): Optional = edit.getOptional("edit") + /** * Parsed search-result entities including URLs, mentions, hashtags, and media markers * @@ -303,6 +375,12 @@ private constructor( */ fun isReply(): Optional = isReply.getOptional("isReply") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isTranslatable(): Optional = isTranslatable.getOptional("isTranslatable") + /** * Search result language code. * @@ -319,6 +397,36 @@ private constructor( */ fun media(): Optional> = media.getOptional("media") + /** + * Complete Note Tweet content and rich-text metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun noteTweet(): Optional = noteTweet.getOptional("noteTweet") + + /** + * Public place metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun place(): Optional = place.getOptional("place") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun possiblySensitive(): Optional = possiblySensitive.getOptional("possiblySensitive") + + /** + * Engagement counts retained from a prior tweet edit. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun previousCounts(): Optional = previousCounts.getOptional("previousCounts") + /** * Quoted or retweeted tweet context. Every object includes id, text, and engagement metrics. A * zero metric can mean X did not report the count. Author, media, and conversation fields @@ -361,6 +469,12 @@ private constructor( */ fun url(): Optional = url.getOptional("url") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewState(): Optional = viewState.getOptional("viewState") + /** * Returns the raw JSON value of [id]. * @@ -421,6 +535,13 @@ private constructor( */ @JsonProperty("viewCount") @ExcludeMissing fun _viewCount(): JsonField = viewCount + /** + * Returns the raw JSON value of [article]. + * + * Unlike [article], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("article") @ExcludeMissing fun _article(): JsonField
= article + /** * Returns the raw JSON value of [author]. * @@ -428,6 +549,22 @@ private constructor( */ @JsonProperty("author") @ExcludeMissing fun _author(): JsonField = author + /** + * Returns the raw JSON value of [card]. + * + * Unlike [card], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("card") @ExcludeMissing fun _card(): JsonField = card + + /** + * Returns the raw JSON value of [communityNote]. + * + * Unlike [communityNote], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("communityNote") + @ExcludeMissing + fun _communityNote(): JsonField = communityNote + /** * Returns the raw JSON value of [contentDisclosure]. * @@ -464,6 +601,13 @@ private constructor( @ExcludeMissing fun _displayTextRange(): JsonField> = displayTextRange + /** + * Returns the raw JSON value of [edit]. + * + * Unlike [edit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("edit") @ExcludeMissing fun _edit(): JsonField = edit + /** * Returns the raw JSON value of [entities]. * @@ -531,6 +675,15 @@ private constructor( */ @JsonProperty("isReply") @ExcludeMissing fun _isReply(): JsonField = isReply + /** + * Returns the raw JSON value of [isTranslatable]. + * + * Unlike [isTranslatable], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("isTranslatable") + @ExcludeMissing + fun _isTranslatable(): JsonField = isTranslatable + /** * Returns the raw JSON value of [lang]. * @@ -545,6 +698,39 @@ private constructor( */ @JsonProperty("media") @ExcludeMissing fun _media(): JsonField> = media + /** + * Returns the raw JSON value of [noteTweet]. + * + * Unlike [noteTweet], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("noteTweet") @ExcludeMissing fun _noteTweet(): JsonField = noteTweet + + /** + * Returns the raw JSON value of [place]. + * + * Unlike [place], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("place") @ExcludeMissing fun _place(): JsonField = place + + /** + * Returns the raw JSON value of [possiblySensitive]. + * + * Unlike [possiblySensitive], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("possiblySensitive") + @ExcludeMissing + fun _possiblySensitive(): JsonField = possiblySensitive + + /** + * Returns the raw JSON value of [previousCounts]. + * + * Unlike [previousCounts], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previousCounts") + @ExcludeMissing + fun _previousCounts(): JsonField = previousCounts + /** * Returns the raw JSON value of [quotedTweet]. * @@ -584,6 +770,13 @@ private constructor( */ @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + /** + * Returns the raw JSON value of [viewState]. + * + * Unlike [viewState], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("viewState") @ExcludeMissing fun _viewState(): JsonField = viewState + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -627,11 +820,15 @@ private constructor( private var retweetCount: JsonField? = null private var text: JsonField? = null private var viewCount: JsonField? = null + private var article: JsonField
= JsonMissing.of() private var author: JsonField = JsonMissing.of() + private var card: JsonField = JsonMissing.of() + private var communityNote: JsonField = JsonMissing.of() private var contentDisclosure: JsonField = JsonMissing.of() private var conversationId: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() private var displayTextRange: JsonField>? = null + private var edit: JsonField = JsonMissing.of() private var entities: JsonField = JsonMissing.of() private var inReplyToId: JsonField = JsonMissing.of() private var inReplyToUserId: JsonField = JsonMissing.of() @@ -640,13 +837,19 @@ private constructor( private var isNoteTweet: JsonField = JsonMissing.of() private var isQuoteStatus: JsonField = JsonMissing.of() private var isReply: JsonField = JsonMissing.of() + private var isTranslatable: JsonField = JsonMissing.of() private var lang: JsonField = JsonMissing.of() private var media: JsonField>? = null + private var noteTweet: JsonField = JsonMissing.of() + private var place: JsonField = JsonMissing.of() + private var possiblySensitive: JsonField = JsonMissing.of() + private var previousCounts: JsonField = JsonMissing.of() private var quotedTweet: JsonField = JsonMissing.of() private var retweetedTweet: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() private var type: JsonField = JsonMissing.of() private var url: JsonField = JsonMissing.of() + private var viewState: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -659,11 +862,15 @@ private constructor( retweetCount = searchTweet.retweetCount text = searchTweet.text viewCount = searchTweet.viewCount + article = searchTweet.article author = searchTweet.author + card = searchTweet.card + communityNote = searchTweet.communityNote contentDisclosure = searchTweet.contentDisclosure conversationId = searchTweet.conversationId createdAt = searchTweet.createdAt displayTextRange = searchTweet.displayTextRange.map { it.toMutableList() } + edit = searchTweet.edit entities = searchTweet.entities inReplyToId = searchTweet.inReplyToId inReplyToUserId = searchTweet.inReplyToUserId @@ -672,13 +879,19 @@ private constructor( isNoteTweet = searchTweet.isNoteTweet isQuoteStatus = searchTweet.isQuoteStatus isReply = searchTweet.isReply + isTranslatable = searchTweet.isTranslatable lang = searchTweet.lang media = searchTweet.media.map { it.toMutableList() } + noteTweet = searchTweet.noteTweet + place = searchTweet.place + possiblySensitive = searchTweet.possiblySensitive + previousCounts = searchTweet.previousCounts quotedTweet = searchTweet.quotedTweet retweetedTweet = searchTweet.retweetedTweet source = searchTweet.source type = searchTweet.type url = searchTweet.url + viewState = searchTweet.viewState additionalProperties = searchTweet.additionalProperties.toMutableMap() } @@ -766,6 +979,17 @@ private constructor( */ fun viewCount(viewCount: JsonField) = apply { this.viewCount = viewCount } + /** Article metadata attached to a tweet. */ + fun article(article: Article) = article(JsonField.of(article)) + + /** + * Sets [Builder.article] to an arbitrary JSON value. + * + * You should usually call [Builder.article] with a well-typed [Article] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun article(article: JsonField
) = apply { this.article = article } + /** X user profile with bio, follower counts, and verification status. */ fun author(author: UserProfile) = author(JsonField.of(author)) @@ -778,6 +1002,31 @@ private constructor( */ fun author(author: JsonField) = apply { this.author = author } + /** Public card metadata attached to a tweet. */ + fun card(card: Card) = card(JsonField.of(card)) + + /** + * Sets [Builder.card] to an arbitrary JSON value. + * + * You should usually call [Builder.card] with a well-typed [Card] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun card(card: JsonField) = apply { this.card = card } + + /** Community Note presentation metadata returned by X. */ + fun communityNote(communityNote: CommunityNote) = communityNote(JsonField.of(communityNote)) + + /** + * Sets [Builder.communityNote] to an arbitrary JSON value. + * + * You should usually call [Builder.communityNote] with a well-typed [CommunityNote] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun communityNote(communityNote: JsonField) = apply { + this.communityNote = communityNote + } + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership * content or AI-generated media. @@ -848,6 +1097,17 @@ private constructor( } } + /** Edit history metadata returned by X. */ + fun edit(edit: Edit) = edit(JsonField.of(edit)) + + /** + * Sets [Builder.edit] to an arbitrary JSON value. + * + * You should usually call [Builder.edit] with a well-typed [Edit] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun edit(edit: JsonField) = apply { this.edit = edit } + /** Parsed search-result entities including URLs, mentions, hashtags, and media markers */ fun entities(entities: Entities) = entities(JsonField.of(entities)) @@ -953,6 +1213,19 @@ private constructor( */ fun isReply(isReply: JsonField) = apply { this.isReply = isReply } + fun isTranslatable(isTranslatable: Boolean) = isTranslatable(JsonField.of(isTranslatable)) + + /** + * Sets [Builder.isTranslatable] to an arbitrary JSON value. + * + * You should usually call [Builder.isTranslatable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isTranslatable(isTranslatable: JsonField) = apply { + this.isTranslatable = isTranslatable + } + /** Search result language code. */ fun lang(lang: String) = lang(JsonField.of(lang)) @@ -990,6 +1263,58 @@ private constructor( } } + /** Complete Note Tweet content and rich-text metadata. */ + fun noteTweet(noteTweet: NoteTweet) = noteTweet(JsonField.of(noteTweet)) + + /** + * Sets [Builder.noteTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.noteTweet] with a well-typed [NoteTweet] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun noteTweet(noteTweet: JsonField) = apply { this.noteTweet = noteTweet } + + /** Public place metadata attached to a tweet. */ + fun place(place: Place) = place(JsonField.of(place)) + + /** + * Sets [Builder.place] to an arbitrary JSON value. + * + * You should usually call [Builder.place] with a well-typed [Place] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun place(place: JsonField) = apply { this.place = place } + + fun possiblySensitive(possiblySensitive: Boolean) = + possiblySensitive(JsonField.of(possiblySensitive)) + + /** + * Sets [Builder.possiblySensitive] to an arbitrary JSON value. + * + * You should usually call [Builder.possiblySensitive] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun possiblySensitive(possiblySensitive: JsonField) = apply { + this.possiblySensitive = possiblySensitive + } + + /** Engagement counts retained from a prior tweet edit. */ + fun previousCounts(previousCounts: PreviousCounts) = + previousCounts(JsonField.of(previousCounts)) + + /** + * Sets [Builder.previousCounts] to an arbitrary JSON value. + * + * You should usually call [Builder.previousCounts] with a well-typed [PreviousCounts] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previousCounts(previousCounts: JsonField) = apply { + this.previousCounts = previousCounts + } + /** * Quoted or retweeted tweet context. Every object includes id, text, and engagement * metrics. A zero metric can mean X did not report the count. Author, media, and @@ -1059,6 +1384,17 @@ private constructor( */ fun url(url: JsonField) = apply { this.url = url } + fun viewState(viewState: String) = viewState(JsonField.of(viewState)) + + /** + * Sets [Builder.viewState] to an arbitrary JSON value. + * + * You should usually call [Builder.viewState] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewState(viewState: JsonField) = apply { this.viewState = viewState } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1107,11 +1443,15 @@ private constructor( checkRequired("retweetCount", retweetCount), checkRequired("text", text), checkRequired("viewCount", viewCount), + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, (displayTextRange ?: JsonMissing.of()).map { it.toImmutable() }, + edit, entities, inReplyToId, inReplyToUserId, @@ -1120,13 +1460,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, (media ?: JsonMissing.of()).map { it.toImmutable() }, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, additionalProperties.toMutableMap(), ) } @@ -1154,11 +1500,15 @@ private constructor( retweetCount() text() viewCount() + article().ifPresent { it.validate() } author().ifPresent { it.validate() } + card().ifPresent { it.validate() } + communityNote().ifPresent { it.validate() } contentDisclosure().ifPresent { it.validate() } conversationId() createdAt() displayTextRange() + edit().ifPresent { it.validate() } entities().ifPresent { it.validate() } inReplyToId() inReplyToUserId() @@ -1167,13 +1517,19 @@ private constructor( isNoteTweet() isQuoteStatus() isReply() + isTranslatable() lang() media().ifPresent { it.forEach { it.validate() } } + noteTweet().ifPresent { it.validate() } + place().ifPresent { it.validate() } + possiblySensitive() + previousCounts().ifPresent { it.validate() } quotedTweet().ifPresent { it.validate() } retweetedTweet().ifPresent { it.validate() } source() type() url() + viewState() validated = true } @@ -1200,11 +1556,15 @@ private constructor( (if (retweetCount.asKnown().isPresent) 1 else 0) + (if (text.asKnown().isPresent) 1 else 0) + (if (viewCount.asKnown().isPresent) 1 else 0) + + (article.asKnown().getOrNull()?.validity() ?: 0) + (author.asKnown().getOrNull()?.validity() ?: 0) + + (card.asKnown().getOrNull()?.validity() ?: 0) + + (communityNote.asKnown().getOrNull()?.validity() ?: 0) + (contentDisclosure.asKnown().getOrNull()?.validity() ?: 0) + (if (conversationId.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (displayTextRange.asKnown().getOrNull()?.size ?: 0) + + (edit.asKnown().getOrNull()?.validity() ?: 0) + (entities.asKnown().getOrNull()?.validity() ?: 0) + (if (inReplyToId.asKnown().isPresent) 1 else 0) + (if (inReplyToUserId.asKnown().isPresent) 1 else 0) + @@ -1213,44 +1573,184 @@ private constructor( (if (isNoteTweet.asKnown().isPresent) 1 else 0) + (if (isQuoteStatus.asKnown().isPresent) 1 else 0) + (if (isReply.asKnown().isPresent) 1 else 0) + + (if (isTranslatable.asKnown().isPresent) 1 else 0) + (if (lang.asKnown().isPresent) 1 else 0) + (media.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (noteTweet.asKnown().getOrNull()?.validity() ?: 0) + + (place.asKnown().getOrNull()?.validity() ?: 0) + + (if (possiblySensitive.asKnown().isPresent) 1 else 0) + + (previousCounts.asKnown().getOrNull()?.validity() ?: 0) + (quotedTweet.asKnown().getOrNull()?.validity() ?: 0) + (retweetedTweet.asKnown().getOrNull()?.validity() ?: 0) + (if (source.asKnown().isPresent) 1 else 0) + (if (type.asKnown().isPresent) 1 else 0) + - (if (url.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + + (if (viewState.asKnown().isPresent) 1 else 0) - /** Parsed search-result entities including URLs, mentions, hashtags, and media markers */ - class Entities - @JsonCreator + /** Article metadata attached to a tweet. */ + class Article + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map + private val id: JsonField, + private val coverMediaUrl: JsonField, + private val previewText: JsonField, + private val title: JsonField, + private val additionalProperties: MutableMap, ) { + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("coverMediaUrl") + @ExcludeMissing + coverMediaUrl: JsonField = JsonMissing.of(), + @JsonProperty("previewText") + @ExcludeMissing + previewText: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + ) : this(id, coverMediaUrl, previewText, title, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun coverMediaUrl(): Optional = coverMediaUrl.getOptional("coverMediaUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun previewText(): Optional = previewText.getOptional("previewText") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [coverMediaUrl]. + * + * Unlike [coverMediaUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("coverMediaUrl") + @ExcludeMissing + fun _coverMediaUrl(): JsonField = coverMediaUrl + + /** + * Returns the raw JSON value of [previewText]. + * + * Unlike [previewText], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previewText") + @ExcludeMissing + fun _previewText(): JsonField = previewText + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) companion object { - /** Returns a mutable builder for constructing an instance of [Entities]. */ + /** Returns a mutable builder for constructing an instance of [Article]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [Entities]. */ + /** A builder for [Article]. */ class Builder internal constructor() { + private var id: JsonField = JsonMissing.of() + private var coverMediaUrl: JsonField = JsonMissing.of() + private var previewText: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(entities: Entities) = apply { - additionalProperties = entities.additionalProperties.toMutableMap() + internal fun from(article: Article) = apply { + id = article.id + coverMediaUrl = article.coverMediaUrl + previewText = article.previewText + title = article.title + additionalProperties = article.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun coverMediaUrl(coverMediaUrl: String) = coverMediaUrl(JsonField.of(coverMediaUrl)) + + /** + * Sets [Builder.coverMediaUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.coverMediaUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun coverMediaUrl(coverMediaUrl: JsonField) = apply { + this.coverMediaUrl = coverMediaUrl } + fun previewText(previewText: String) = previewText(JsonField.of(previewText)) + + /** + * Sets [Builder.previewText] to an arbitrary JSON value. + * + * You should usually call [Builder.previewText] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previewText(previewText: JsonField) = apply { + this.previewText = previewText + } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1271,11 +1771,12 @@ private constructor( } /** - * Returns an immutable instance of [Entities]. + * Returns an immutable instance of [Article]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Entities = Entities(additionalProperties.toImmutable()) + fun build(): Article = + Article(id, coverMediaUrl, previewText, title, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -1289,11 +1790,15 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): Entities = apply { + fun validate(): Article = apply { if (validated) { return@apply } + id() + coverMediaUrl() + previewText() + title() validated = true } @@ -1312,23 +1817,2658 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (coverMediaUrl.asKnown().isPresent) 1 else 0) + + (if (previewText.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Entities && additionalProperties == other.additionalProperties + return other is Article && + id == other.id && + coverMediaUrl == other.coverMediaUrl && + previewText == other.previewText && + title == other.title && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(id, coverMediaUrl, previewText, title, additionalProperties) + } override fun hashCode(): Int = hashCode - override fun toString() = "Entities{additionalProperties=$additionalProperties}" + override fun toString() = + "Article{id=$id, coverMediaUrl=$coverMediaUrl, previewText=$previewText, title=$title, additionalProperties=$additionalProperties}" + } + + /** Public card metadata attached to a tweet. */ + class Card + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val bindingValues: JsonField, + private val name: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("bindingValues") + @ExcludeMissing + bindingValues: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(id, bindingValues, name, url, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bindingValues(): Optional = bindingValues.getOptional("bindingValues") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [bindingValues]. + * + * Unlike [bindingValues], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bindingValues") + @ExcludeMissing + fun _bindingValues(): JsonField = bindingValues + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Card]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Card]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var bindingValues: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(card: Card) = apply { + id = card.id + bindingValues = card.bindingValues + name = card.name + url = card.url + additionalProperties = card.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun bindingValues(bindingValues: BindingValues) = + bindingValues(JsonField.of(bindingValues)) + + /** + * Sets [Builder.bindingValues] to an arbitrary JSON value. + * + * You should usually call [Builder.bindingValues] with a well-typed [BindingValues] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun bindingValues(bindingValues: JsonField) = apply { + this.bindingValues = bindingValues + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Card]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Card = + Card(id, bindingValues, name, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Card = apply { + if (validated) { + return@apply + } + + id() + bindingValues().ifPresent { it.validate() } + name() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (bindingValues.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BindingValues + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BindingValues]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BindingValues]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(bindingValues: BindingValues) = apply { + additionalProperties = bindingValues.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BindingValues]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BindingValues = BindingValues(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BindingValues = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BindingValues && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BindingValues{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Card && + id == other.id && + bindingValues == other.bindingValues && + name == other.name && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, bindingValues, name, url, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Card{id=$id, bindingValues=$bindingValues, name=$name, url=$url, additionalProperties=$additionalProperties}" + } + + /** Community Note presentation metadata returned by X. */ + class CommunityNote + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val destinationUrl: JsonField, + private val footer: JsonField, + private val shortTitle: JsonField, + private val subtitle: JsonField, + private val title: JsonField, + private val visualStyle: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("destinationUrl") + @ExcludeMissing + destinationUrl: JsonField = JsonMissing.of(), + @JsonProperty("footer") @ExcludeMissing footer: JsonField = JsonMissing.of(), + @JsonProperty("shortTitle") + @ExcludeMissing + shortTitle: JsonField = JsonMissing.of(), + @JsonProperty("subtitle") + @ExcludeMissing + subtitle: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + @JsonProperty("visualStyle") + @ExcludeMissing + visualStyle: JsonField = JsonMissing.of(), + ) : this( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun destinationUrl(): Optional = destinationUrl.getOptional("destinationUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun footer(): Optional = footer.getOptional("footer") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun shortTitle(): Optional = shortTitle.getOptional("shortTitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun subtitle(): Optional = subtitle.getOptional("subtitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun visualStyle(): Optional = visualStyle.getOptional("visualStyle") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [destinationUrl]. + * + * Unlike [destinationUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("destinationUrl") + @ExcludeMissing + fun _destinationUrl(): JsonField = destinationUrl + + /** + * Returns the raw JSON value of [footer]. + * + * Unlike [footer], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("footer") @ExcludeMissing fun _footer(): JsonField = footer + + /** + * Returns the raw JSON value of [shortTitle]. + * + * Unlike [shortTitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("shortTitle") + @ExcludeMissing + fun _shortTitle(): JsonField = shortTitle + + /** + * Returns the raw JSON value of [subtitle]. + * + * Unlike [subtitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("subtitle") @ExcludeMissing fun _subtitle(): JsonField = subtitle + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + /** + * Returns the raw JSON value of [visualStyle]. + * + * Unlike [visualStyle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("visualStyle") + @ExcludeMissing + fun _visualStyle(): JsonField = visualStyle + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [CommunityNote]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CommunityNote]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var destinationUrl: JsonField = JsonMissing.of() + private var footer: JsonField = JsonMissing.of() + private var shortTitle: JsonField = JsonMissing.of() + private var subtitle: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var visualStyle: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(communityNote: CommunityNote) = apply { + id = communityNote.id + destinationUrl = communityNote.destinationUrl + footer = communityNote.footer + shortTitle = communityNote.shortTitle + subtitle = communityNote.subtitle + title = communityNote.title + visualStyle = communityNote.visualStyle + additionalProperties = communityNote.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun destinationUrl(destinationUrl: String) = + destinationUrl(JsonField.of(destinationUrl)) + + /** + * Sets [Builder.destinationUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.destinationUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun destinationUrl(destinationUrl: JsonField) = apply { + this.destinationUrl = destinationUrl + } + + fun footer(footer: String) = footer(JsonField.of(footer)) + + /** + * Sets [Builder.footer] to an arbitrary JSON value. + * + * You should usually call [Builder.footer] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun footer(footer: JsonField) = apply { this.footer = footer } + + fun shortTitle(shortTitle: String) = shortTitle(JsonField.of(shortTitle)) + + /** + * Sets [Builder.shortTitle] to an arbitrary JSON value. + * + * You should usually call [Builder.shortTitle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun shortTitle(shortTitle: JsonField) = apply { this.shortTitle = shortTitle } + + fun subtitle(subtitle: String) = subtitle(JsonField.of(subtitle)) + + /** + * Sets [Builder.subtitle] to an arbitrary JSON value. + * + * You should usually call [Builder.subtitle] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun subtitle(subtitle: JsonField) = apply { this.subtitle = subtitle } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + fun visualStyle(visualStyle: String) = visualStyle(JsonField.of(visualStyle)) + + /** + * Sets [Builder.visualStyle] to an arbitrary JSON value. + * + * You should usually call [Builder.visualStyle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun visualStyle(visualStyle: JsonField) = apply { + this.visualStyle = visualStyle + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CommunityNote]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): CommunityNote = + CommunityNote( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): CommunityNote = apply { + if (validated) { + return@apply + } + + id() + destinationUrl() + footer() + shortTitle() + subtitle() + title() + visualStyle() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (destinationUrl.asKnown().isPresent) 1 else 0) + + (if (footer.asKnown().isPresent) 1 else 0) + + (if (shortTitle.asKnown().isPresent) 1 else 0) + + (if (subtitle.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) + + (if (visualStyle.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CommunityNote && + id == other.id && + destinationUrl == other.destinationUrl && + footer == other.footer && + shortTitle == other.shortTitle && + subtitle == other.subtitle && + title == other.title && + visualStyle == other.visualStyle && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CommunityNote{id=$id, destinationUrl=$destinationUrl, footer=$footer, shortTitle=$shortTitle, subtitle=$subtitle, title=$title, visualStyle=$visualStyle, additionalProperties=$additionalProperties}" + } + + /** Edit history metadata returned by X. */ + class Edit + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val editableUntilMsecs: JsonField, + private val editTweetIds: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + editableUntilMsecs: JsonField = JsonMissing.of(), + @JsonProperty("editTweetIds") + @ExcludeMissing + editTweetIds: JsonField> = JsonMissing.of(), + ) : this(editableUntilMsecs, editTweetIds, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editableUntilMsecs(): Optional = + editableUntilMsecs.getOptional("editableUntilMsecs") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editTweetIds(): Optional> = editTweetIds.getOptional("editTweetIds") + + /** + * Returns the raw JSON value of [editableUntilMsecs]. + * + * Unlike [editableUntilMsecs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + fun _editableUntilMsecs(): JsonField = editableUntilMsecs + + /** + * Returns the raw JSON value of [editTweetIds]. + * + * Unlike [editTweetIds], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("editTweetIds") + @ExcludeMissing + fun _editTweetIds(): JsonField> = editTweetIds + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Edit]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Edit]. */ + class Builder internal constructor() { + + private var editableUntilMsecs: JsonField = JsonMissing.of() + private var editTweetIds: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(edit: Edit) = apply { + editableUntilMsecs = edit.editableUntilMsecs + editTweetIds = edit.editTweetIds.map { it.toMutableList() } + additionalProperties = edit.additionalProperties.toMutableMap() + } + + fun editableUntilMsecs(editableUntilMsecs: String) = + editableUntilMsecs(JsonField.of(editableUntilMsecs)) + + /** + * Sets [Builder.editableUntilMsecs] to an arbitrary JSON value. + * + * You should usually call [Builder.editableUntilMsecs] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editableUntilMsecs(editableUntilMsecs: JsonField) = apply { + this.editableUntilMsecs = editableUntilMsecs + } + + fun editTweetIds(editTweetIds: List) = editTweetIds(JsonField.of(editTweetIds)) + + /** + * Sets [Builder.editTweetIds] to an arbitrary JSON value. + * + * You should usually call [Builder.editTweetIds] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editTweetIds(editTweetIds: JsonField>) = apply { + this.editTweetIds = editTweetIds.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [editTweetIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEditTweetId(editTweetId: String) = apply { + editTweetIds = + (editTweetIds ?: JsonField.of(mutableListOf())).also { + checkKnown("editTweetIds", it).add(editTweetId) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Edit]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Edit = + Edit( + editableUntilMsecs, + (editTweetIds ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Edit = apply { + if (validated) { + return@apply + } + + editableUntilMsecs() + editTweetIds() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (editableUntilMsecs.asKnown().isPresent) 1 else 0) + + (editTweetIds.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Edit && + editableUntilMsecs == other.editableUntilMsecs && + editTweetIds == other.editTweetIds && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(editableUntilMsecs, editTweetIds, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Edit{editableUntilMsecs=$editableUntilMsecs, editTweetIds=$editTweetIds, additionalProperties=$additionalProperties}" + } + + /** Parsed search-result entities including URLs, mentions, hashtags, and media markers */ + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + /** Complete Note Tweet content and rich-text metadata. */ + class NoteTweet + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val text: JsonField, + private val id: JsonField, + private val entities: JsonField, + private val isExpandable: JsonField, + private val richtextTags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("entities") + @ExcludeMissing + entities: JsonField = JsonMissing.of(), + @JsonProperty("isExpandable") + @ExcludeMissing + isExpandable: JsonField = JsonMissing.of(), + @JsonProperty("richtextTags") + @ExcludeMissing + richtextTags: JsonField> = JsonMissing.of(), + ) : this(text, id, entities, isExpandable, richtextTags, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun text(): String = text.getRequired("text") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun entities(): Optional = entities.getOptional("entities") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isExpandable(): Optional = isExpandable.getOptional("isExpandable") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun richtextTags(): Optional> = richtextTags.getOptional("richtextTags") + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [entities]. + * + * Unlike [entities], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("entities") @ExcludeMissing fun _entities(): JsonField = entities + + /** + * Returns the raw JSON value of [isExpandable]. + * + * Unlike [isExpandable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isExpandable") + @ExcludeMissing + fun _isExpandable(): JsonField = isExpandable + + /** + * Returns the raw JSON value of [richtextTags]. + * + * Unlike [richtextTags], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("richtextTags") + @ExcludeMissing + fun _richtextTags(): JsonField> = richtextTags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [NoteTweet]. + * + * The following fields are required: + * ```java + * .text() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [NoteTweet]. */ + class Builder internal constructor() { + + private var text: JsonField? = null + private var id: JsonField = JsonMissing.of() + private var entities: JsonField = JsonMissing.of() + private var isExpandable: JsonField = JsonMissing.of() + private var richtextTags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(noteTweet: NoteTweet) = apply { + text = noteTweet.text + id = noteTweet.id + entities = noteTweet.entities + isExpandable = noteTweet.isExpandable + richtextTags = noteTweet.richtextTags.map { it.toMutableList() } + additionalProperties = noteTweet.additionalProperties.toMutableMap() + } + + fun text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun entities(entities: Entities) = entities(JsonField.of(entities)) + + /** + * Sets [Builder.entities] to an arbitrary JSON value. + * + * You should usually call [Builder.entities] with a well-typed [Entities] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun entities(entities: JsonField) = apply { this.entities = entities } + + fun isExpandable(isExpandable: Boolean) = isExpandable(JsonField.of(isExpandable)) + + /** + * Sets [Builder.isExpandable] to an arbitrary JSON value. + * + * You should usually call [Builder.isExpandable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isExpandable(isExpandable: JsonField) = apply { + this.isExpandable = isExpandable + } + + fun richtextTags(richtextTags: List) = + richtextTags(JsonField.of(richtextTags)) + + /** + * Sets [Builder.richtextTags] to an arbitrary JSON value. + * + * You should usually call [Builder.richtextTags] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun richtextTags(richtextTags: JsonField>) = apply { + this.richtextTags = richtextTags.map { it.toMutableList() } + } + + /** + * Adds a single [RichtextTag] to [richtextTags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRichtextTag(richtextTag: RichtextTag) = apply { + richtextTags = + (richtextTags ?: JsonField.of(mutableListOf())).also { + checkKnown("richtextTags", it).add(richtextTag) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [NoteTweet]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .text() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): NoteTweet = + NoteTweet( + checkRequired("text", text), + id, + entities, + isExpandable, + (richtextTags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): NoteTweet = apply { + if (validated) { + return@apply + } + + text() + id() + entities().ifPresent { it.validate() } + isExpandable() + richtextTags().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (text.asKnown().isPresent) 1 else 0) + + (if (id.asKnown().isPresent) 1 else 0) + + (entities.asKnown().getOrNull()?.validity() ?: 0) + + (if (isExpandable.asKnown().isPresent) 1 else 0) + + (richtextTags.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + class RichtextTag + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val fromIndex: JsonField, + private val toIndex: JsonField, + private val types: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("fromIndex") + @ExcludeMissing + fromIndex: JsonField = JsonMissing.of(), + @JsonProperty("toIndex") + @ExcludeMissing + toIndex: JsonField = JsonMissing.of(), + @JsonProperty("types") + @ExcludeMissing + types: JsonField> = JsonMissing.of(), + ) : this(fromIndex, toIndex, types, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun fromIndex(): Long = fromIndex.getRequired("fromIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun toIndex(): Long = toIndex.getRequired("toIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun types(): List = types.getRequired("types") + + /** + * Returns the raw JSON value of [fromIndex]. + * + * Unlike [fromIndex], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("fromIndex") @ExcludeMissing fun _fromIndex(): JsonField = fromIndex + + /** + * Returns the raw JSON value of [toIndex]. + * + * Unlike [toIndex], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("toIndex") @ExcludeMissing fun _toIndex(): JsonField = toIndex + + /** + * Returns the raw JSON value of [types]. + * + * Unlike [types], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("types") @ExcludeMissing fun _types(): JsonField> = types + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RichtextTag]. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RichtextTag]. */ + class Builder internal constructor() { + + private var fromIndex: JsonField? = null + private var toIndex: JsonField? = null + private var types: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(richtextTag: RichtextTag) = apply { + fromIndex = richtextTag.fromIndex + toIndex = richtextTag.toIndex + types = richtextTag.types.map { it.toMutableList() } + additionalProperties = richtextTag.additionalProperties.toMutableMap() + } + + fun fromIndex(fromIndex: Long) = fromIndex(JsonField.of(fromIndex)) + + /** + * Sets [Builder.fromIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.fromIndex] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun fromIndex(fromIndex: JsonField) = apply { this.fromIndex = fromIndex } + + fun toIndex(toIndex: Long) = toIndex(JsonField.of(toIndex)) + + /** + * Sets [Builder.toIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.toIndex] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun toIndex(toIndex: JsonField) = apply { this.toIndex = toIndex } + + fun types(types: List) = types(JsonField.of(types)) + + /** + * Sets [Builder.types] to an arbitrary JSON value. + * + * You should usually call [Builder.types] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun types(types: JsonField>) = apply { + this.types = types.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [types]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addType(type: String) = apply { + types = + (types ?: JsonField.of(mutableListOf())).also { + checkKnown("types", it).add(type) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [RichtextTag]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RichtextTag = + RichtextTag( + checkRequired("fromIndex", fromIndex), + checkRequired("toIndex", toIndex), + checkRequired("types", types).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): RichtextTag = apply { + if (validated) { + return@apply + } + + fromIndex() + toIndex() + types() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (fromIndex.asKnown().isPresent) 1 else 0) + + (if (toIndex.asKnown().isPresent) 1 else 0) + + (types.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RichtextTag && + fromIndex == other.fromIndex && + toIndex == other.toIndex && + types == other.types && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(fromIndex, toIndex, types, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RichtextTag{fromIndex=$fromIndex, toIndex=$toIndex, types=$types, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is NoteTweet && + text == other.text && + id == other.id && + entities == other.entities && + isExpandable == other.isExpandable && + richtextTags == other.richtextTags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(text, id, entities, isExpandable, richtextTags, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "NoteTweet{text=$text, id=$id, entities=$entities, isExpandable=$isExpandable, richtextTags=$richtextTags, additionalProperties=$additionalProperties}" + } + + /** Public place metadata attached to a tweet. */ + class Place + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val boundingBox: JsonField, + private val country: JsonField, + private val countryCode: JsonField, + private val fullName: JsonField, + private val name: JsonField, + private val placeType: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("boundingBox") + @ExcludeMissing + boundingBox: JsonField = JsonMissing.of(), + @JsonProperty("country") @ExcludeMissing country: JsonField = JsonMissing.of(), + @JsonProperty("countryCode") + @ExcludeMissing + countryCode: JsonField = JsonMissing.of(), + @JsonProperty("fullName") + @ExcludeMissing + fullName: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("placeType") + @ExcludeMissing + placeType: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun boundingBox(): Optional = boundingBox.getOptional("boundingBox") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun country(): Optional = country.getOptional("country") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun countryCode(): Optional = countryCode.getOptional("countryCode") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun fullName(): Optional = fullName.getOptional("fullName") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun placeType(): Optional = placeType.getOptional("placeType") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [boundingBox]. + * + * Unlike [boundingBox], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("boundingBox") + @ExcludeMissing + fun _boundingBox(): JsonField = boundingBox + + /** + * Returns the raw JSON value of [country]. + * + * Unlike [country], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("country") @ExcludeMissing fun _country(): JsonField = country + + /** + * Returns the raw JSON value of [countryCode]. + * + * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("countryCode") + @ExcludeMissing + fun _countryCode(): JsonField = countryCode + + /** + * Returns the raw JSON value of [fullName]. + * + * Unlike [fullName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("fullName") @ExcludeMissing fun _fullName(): JsonField = fullName + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [placeType]. + * + * Unlike [placeType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("placeType") @ExcludeMissing fun _placeType(): JsonField = placeType + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Place]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Place]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var boundingBox: JsonField = JsonMissing.of() + private var country: JsonField = JsonMissing.of() + private var countryCode: JsonField = JsonMissing.of() + private var fullName: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var placeType: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(place: Place) = apply { + id = place.id + boundingBox = place.boundingBox + country = place.country + countryCode = place.countryCode + fullName = place.fullName + name = place.name + placeType = place.placeType + url = place.url + additionalProperties = place.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun boundingBox(boundingBox: BoundingBox) = boundingBox(JsonField.of(boundingBox)) + + /** + * Sets [Builder.boundingBox] to an arbitrary JSON value. + * + * You should usually call [Builder.boundingBox] with a well-typed [BoundingBox] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun boundingBox(boundingBox: JsonField) = apply { + this.boundingBox = boundingBox + } + + fun country(country: String) = country(JsonField.of(country)) + + /** + * Sets [Builder.country] to an arbitrary JSON value. + * + * You should usually call [Builder.country] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun country(country: JsonField) = apply { this.country = country } + + fun countryCode(countryCode: String) = countryCode(JsonField.of(countryCode)) + + /** + * Sets [Builder.countryCode] to an arbitrary JSON value. + * + * You should usually call [Builder.countryCode] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun countryCode(countryCode: JsonField) = apply { + this.countryCode = countryCode + } + + fun fullName(fullName: String) = fullName(JsonField.of(fullName)) + + /** + * Sets [Builder.fullName] to an arbitrary JSON value. + * + * You should usually call [Builder.fullName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fullName(fullName: JsonField) = apply { this.fullName = fullName } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun placeType(placeType: String) = placeType(JsonField.of(placeType)) + + /** + * Sets [Builder.placeType] to an arbitrary JSON value. + * + * You should usually call [Builder.placeType] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun placeType(placeType: JsonField) = apply { this.placeType = placeType } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Place]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Place = + Place( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Place = apply { + if (validated) { + return@apply + } + + id() + boundingBox().ifPresent { it.validate() } + country() + countryCode() + fullName() + name() + placeType() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (boundingBox.asKnown().getOrNull()?.validity() ?: 0) + + (if (country.asKnown().isPresent) 1 else 0) + + (if (countryCode.asKnown().isPresent) 1 else 0) + + (if (fullName.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (placeType.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BoundingBox + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BoundingBox]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BoundingBox]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(boundingBox: BoundingBox) = apply { + additionalProperties = boundingBox.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BoundingBox]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BoundingBox = BoundingBox(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BoundingBox = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BoundingBox && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BoundingBox{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Place && + id == other.id && + boundingBox == other.boundingBox && + country == other.country && + countryCode == other.countryCode && + fullName == other.fullName && + name == other.name && + placeType == other.placeType && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Place{id=$id, boundingBox=$boundingBox, country=$country, countryCode=$countryCode, fullName=$fullName, name=$name, placeType=$placeType, url=$url, additionalProperties=$additionalProperties}" + } + + /** Engagement counts retained from a prior tweet edit. */ + class PreviousCounts + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val bookmarkCount: JsonField, + private val likeCount: JsonField, + private val quoteCount: JsonField, + private val replyCount: JsonField, + private val retweetCount: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("bookmarkCount") + @ExcludeMissing + bookmarkCount: JsonField = JsonMissing.of(), + @JsonProperty("likeCount") + @ExcludeMissing + likeCount: JsonField = JsonMissing.of(), + @JsonProperty("quoteCount") + @ExcludeMissing + quoteCount: JsonField = JsonMissing.of(), + @JsonProperty("replyCount") + @ExcludeMissing + replyCount: JsonField = JsonMissing.of(), + @JsonProperty("retweetCount") + @ExcludeMissing + retweetCount: JsonField = JsonMissing.of(), + ) : this(bookmarkCount, likeCount, quoteCount, replyCount, retweetCount, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bookmarkCount(): Optional = bookmarkCount.getOptional("bookmarkCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun likeCount(): Optional = likeCount.getOptional("likeCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun quoteCount(): Optional = quoteCount.getOptional("quoteCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun replyCount(): Optional = replyCount.getOptional("replyCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun retweetCount(): Optional = retweetCount.getOptional("retweetCount") + + /** + * Returns the raw JSON value of [bookmarkCount]. + * + * Unlike [bookmarkCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bookmarkCount") + @ExcludeMissing + fun _bookmarkCount(): JsonField = bookmarkCount + + /** + * Returns the raw JSON value of [likeCount]. + * + * Unlike [likeCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("likeCount") @ExcludeMissing fun _likeCount(): JsonField = likeCount + + /** + * Returns the raw JSON value of [quoteCount]. + * + * Unlike [quoteCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("quoteCount") @ExcludeMissing fun _quoteCount(): JsonField = quoteCount + + /** + * Returns the raw JSON value of [replyCount]. + * + * Unlike [replyCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("replyCount") @ExcludeMissing fun _replyCount(): JsonField = replyCount + + /** + * Returns the raw JSON value of [retweetCount]. + * + * Unlike [retweetCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("retweetCount") + @ExcludeMissing + fun _retweetCount(): JsonField = retweetCount + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [PreviousCounts]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreviousCounts]. */ + class Builder internal constructor() { + + private var bookmarkCount: JsonField = JsonMissing.of() + private var likeCount: JsonField = JsonMissing.of() + private var quoteCount: JsonField = JsonMissing.of() + private var replyCount: JsonField = JsonMissing.of() + private var retweetCount: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(previousCounts: PreviousCounts) = apply { + bookmarkCount = previousCounts.bookmarkCount + likeCount = previousCounts.likeCount + quoteCount = previousCounts.quoteCount + replyCount = previousCounts.replyCount + retweetCount = previousCounts.retweetCount + additionalProperties = previousCounts.additionalProperties.toMutableMap() + } + + fun bookmarkCount(bookmarkCount: Long) = bookmarkCount(JsonField.of(bookmarkCount)) + + /** + * Sets [Builder.bookmarkCount] to an arbitrary JSON value. + * + * You should usually call [Builder.bookmarkCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun bookmarkCount(bookmarkCount: JsonField) = apply { + this.bookmarkCount = bookmarkCount + } + + fun likeCount(likeCount: Long) = likeCount(JsonField.of(likeCount)) + + /** + * Sets [Builder.likeCount] to an arbitrary JSON value. + * + * You should usually call [Builder.likeCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun likeCount(likeCount: JsonField) = apply { this.likeCount = likeCount } + + fun quoteCount(quoteCount: Long) = quoteCount(JsonField.of(quoteCount)) + + /** + * Sets [Builder.quoteCount] to an arbitrary JSON value. + * + * You should usually call [Builder.quoteCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun quoteCount(quoteCount: JsonField) = apply { this.quoteCount = quoteCount } + + fun replyCount(replyCount: Long) = replyCount(JsonField.of(replyCount)) + + /** + * Sets [Builder.replyCount] to an arbitrary JSON value. + * + * You should usually call [Builder.replyCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun replyCount(replyCount: JsonField) = apply { this.replyCount = replyCount } + + fun retweetCount(retweetCount: Long) = retweetCount(JsonField.of(retweetCount)) + + /** + * Sets [Builder.retweetCount] to an arbitrary JSON value. + * + * You should usually call [Builder.retweetCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun retweetCount(retweetCount: JsonField) = apply { + this.retweetCount = retweetCount + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreviousCounts]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreviousCounts = + PreviousCounts( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): PreviousCounts = apply { + if (validated) { + return@apply + } + + bookmarkCount() + likeCount() + quoteCount() + replyCount() + retweetCount() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (bookmarkCount.asKnown().isPresent) 1 else 0) + + (if (likeCount.asKnown().isPresent) 1 else 0) + + (if (quoteCount.asKnown().isPresent) 1 else 0) + + (if (replyCount.asKnown().isPresent) 1 else 0) + + (if (retweetCount.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PreviousCounts && + bookmarkCount == other.bookmarkCount && + likeCount == other.likeCount && + quoteCount == other.quoteCount && + replyCount == other.replyCount && + retweetCount == other.retweetCount && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreviousCounts{bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1345,11 +4485,15 @@ private constructor( retweetCount == other.retweetCount && text == other.text && viewCount == other.viewCount && + article == other.article && author == other.author && + card == other.card && + communityNote == other.communityNote && contentDisclosure == other.contentDisclosure && conversationId == other.conversationId && createdAt == other.createdAt && displayTextRange == other.displayTextRange && + edit == other.edit && entities == other.entities && inReplyToId == other.inReplyToId && inReplyToUserId == other.inReplyToUserId && @@ -1358,13 +4502,19 @@ private constructor( isNoteTweet == other.isNoteTweet && isQuoteStatus == other.isQuoteStatus && isReply == other.isReply && + isTranslatable == other.isTranslatable && lang == other.lang && media == other.media && + noteTweet == other.noteTweet && + place == other.place && + possiblySensitive == other.possiblySensitive && + previousCounts == other.previousCounts && quotedTweet == other.quotedTweet && retweetedTweet == other.retweetedTweet && source == other.source && type == other.type && url == other.url && + viewState == other.viewState && additionalProperties == other.additionalProperties } @@ -1378,11 +4528,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -1391,13 +4545,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, additionalProperties, ) } @@ -1405,5 +4565,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "SearchTweet{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, author=$author, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, lang=$lang, media=$media, quotedTweet=$quotedTweet, retweetedTweet=$retweetedTweet, source=$source, type=$type, url=$url, additionalProperties=$additionalProperties}" + "SearchTweet{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, article=$article, author=$author, card=$card, communityNote=$communityNote, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, edit=$edit, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, isTranslatable=$isTranslatable, lang=$lang, media=$media, noteTweet=$noteTweet, place=$place, possiblySensitive=$possiblySensitive, previousCounts=$previousCounts, quotedTweet=$quotedTweet, retweetedTweet=$retweetedTweet, source=$source, type=$type, url=$url, viewState=$viewState, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/TweetMedia.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/TweetMedia.kt index aceb4e1..2c1a08e 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/TweetMedia.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/TweetMedia.kt @@ -31,7 +31,23 @@ private constructor( private val mediaUrl: JsonField, private val type: JsonField, private val url: JsonField, + private val id: JsonField, + private val allowDownload: JsonField, + private val altText: JsonField, + private val aspectRatio: JsonField>, + private val availabilityStatus: JsonField, + private val displayUrl: JsonField, + private val durationMillis: JsonField, + private val expandedUrl: JsonField, + private val faceRects: JsonField, + private val focusRects: JsonField>, + private val height: JsonField, + private val indices: JsonField>, + private val mediaKey: JsonField, + private val monetizable: JsonField, + private val sizes: JsonField, private val videoVariants: JsonField>, + private val width: JsonField, private val additionalProperties: MutableMap, ) { @@ -40,10 +56,66 @@ private constructor( @JsonProperty("mediaUrl") @ExcludeMissing mediaUrl: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("allowDownload") + @ExcludeMissing + allowDownload: JsonField = JsonMissing.of(), + @JsonProperty("altText") @ExcludeMissing altText: JsonField = JsonMissing.of(), + @JsonProperty("aspectRatio") + @ExcludeMissing + aspectRatio: JsonField> = JsonMissing.of(), + @JsonProperty("availabilityStatus") + @ExcludeMissing + availabilityStatus: JsonField = JsonMissing.of(), + @JsonProperty("displayUrl") + @ExcludeMissing + displayUrl: JsonField = JsonMissing.of(), + @JsonProperty("durationMillis") + @ExcludeMissing + durationMillis: JsonField = JsonMissing.of(), + @JsonProperty("expandedUrl") + @ExcludeMissing + expandedUrl: JsonField = JsonMissing.of(), + @JsonProperty("faceRects") + @ExcludeMissing + faceRects: JsonField = JsonMissing.of(), + @JsonProperty("focusRects") + @ExcludeMissing + focusRects: JsonField> = JsonMissing.of(), + @JsonProperty("height") @ExcludeMissing height: JsonField = JsonMissing.of(), + @JsonProperty("indices") @ExcludeMissing indices: JsonField> = JsonMissing.of(), + @JsonProperty("mediaKey") @ExcludeMissing mediaKey: JsonField = JsonMissing.of(), + @JsonProperty("monetizable") + @ExcludeMissing + monetizable: JsonField = JsonMissing.of(), + @JsonProperty("sizes") @ExcludeMissing sizes: JsonField = JsonMissing.of(), @JsonProperty("videoVariants") @ExcludeMissing videoVariants: JsonField> = JsonMissing.of(), - ) : this(mediaUrl, type, url, videoVariants, mutableMapOf()) + @JsonProperty("width") @ExcludeMissing width: JsonField = JsonMissing.of(), + ) : this( + mediaUrl, + type, + url, + id, + allowDownload, + altText, + aspectRatio, + availabilityStatus, + displayUrl, + durationMillis, + expandedUrl, + faceRects, + focusRects, + height, + indices, + mediaKey, + monetizable, + sizes, + videoVariants, + width, + mutableMapOf(), + ) /** * Media preview URL @@ -67,6 +139,127 @@ private constructor( */ fun url(): String = url.getRequired("url") + /** + * X media entity ID. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * Whether X permits direct media download. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun allowDownload(): Optional = allowDownload.getOptional("allowDownload") + + /** + * Accessibility text supplied for the media. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun altText(): Optional = altText.getOptional("altText") + + /** + * Video aspect ratio as width and height. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun aspectRatio(): Optional> = aspectRatio.getOptional("aspectRatio") + + /** + * Media availability state reported by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun availabilityStatus(): Optional = + availabilityStatus.getOptional("availabilityStatus") + + /** + * Display-friendly media URL reported by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun displayUrl(): Optional = displayUrl.getOptional("displayUrl") + + /** + * Video duration in milliseconds. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun durationMillis(): Optional = durationMillis.getOptional("durationMillis") + + /** + * Expanded X media URL. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun expandedUrl(): Optional = expandedUrl.getOptional("expandedUrl") + + /** + * Face-aware crop rectangles grouped by media size. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun faceRects(): Optional = faceRects.getOptional("faceRects") + + /** + * Suggested image crops reported by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun focusRects(): Optional> = focusRects.getOptional("focusRects") + + /** + * Original media height. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun height(): Optional = height.getOptional("height") + + /** + * Media entity offsets in the tweet text. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun indices(): Optional> = indices.getOptional("indices") + + /** + * Stable X media key. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun mediaKey(): Optional = mediaKey.getOptional("mediaKey") + + /** + * Whether X reports the media as monetizable. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun monetizable(): Optional = monetizable.getOptional("monetizable") + + /** + * Named media renditions and resize modes. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun sizes(): Optional = sizes.getOptional("sizes") + /** * Available video encodings, ordered as returned * @@ -75,6 +268,14 @@ private constructor( */ fun videoVariants(): Optional> = videoVariants.getOptional("videoVariants") + /** + * Original media width. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun width(): Optional = width.getOptional("width") + /** * Returns the raw JSON value of [mediaUrl]. * @@ -96,6 +297,124 @@ private constructor( */ @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [allowDownload]. + * + * Unlike [allowDownload], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("allowDownload") + @ExcludeMissing + fun _allowDownload(): JsonField = allowDownload + + /** + * Returns the raw JSON value of [altText]. + * + * Unlike [altText], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("altText") @ExcludeMissing fun _altText(): JsonField = altText + + /** + * Returns the raw JSON value of [aspectRatio]. + * + * Unlike [aspectRatio], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("aspectRatio") + @ExcludeMissing + fun _aspectRatio(): JsonField> = aspectRatio + + /** + * Returns the raw JSON value of [availabilityStatus]. + * + * Unlike [availabilityStatus], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("availabilityStatus") + @ExcludeMissing + fun _availabilityStatus(): JsonField = availabilityStatus + + /** + * Returns the raw JSON value of [displayUrl]. + * + * Unlike [displayUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("displayUrl") @ExcludeMissing fun _displayUrl(): JsonField = displayUrl + + /** + * Returns the raw JSON value of [durationMillis]. + * + * Unlike [durationMillis], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("durationMillis") + @ExcludeMissing + fun _durationMillis(): JsonField = durationMillis + + /** + * Returns the raw JSON value of [expandedUrl]. + * + * Unlike [expandedUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("expandedUrl") @ExcludeMissing fun _expandedUrl(): JsonField = expandedUrl + + /** + * Returns the raw JSON value of [faceRects]. + * + * Unlike [faceRects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("faceRects") @ExcludeMissing fun _faceRects(): JsonField = faceRects + + /** + * Returns the raw JSON value of [focusRects]. + * + * Unlike [focusRects], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("focusRects") + @ExcludeMissing + fun _focusRects(): JsonField> = focusRects + + /** + * Returns the raw JSON value of [height]. + * + * Unlike [height], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("height") @ExcludeMissing fun _height(): JsonField = height + + /** + * Returns the raw JSON value of [indices]. + * + * Unlike [indices], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("indices") @ExcludeMissing fun _indices(): JsonField> = indices + + /** + * Returns the raw JSON value of [mediaKey]. + * + * Unlike [mediaKey], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("mediaKey") @ExcludeMissing fun _mediaKey(): JsonField = mediaKey + + /** + * Returns the raw JSON value of [monetizable]. + * + * Unlike [monetizable], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("monetizable") + @ExcludeMissing + fun _monetizable(): JsonField = monetizable + + /** + * Returns the raw JSON value of [sizes]. + * + * Unlike [sizes], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("sizes") @ExcludeMissing fun _sizes(): JsonField = sizes + /** * Returns the raw JSON value of [videoVariants]. * @@ -105,6 +424,13 @@ private constructor( @ExcludeMissing fun _videoVariants(): JsonField> = videoVariants + /** + * Returns the raw JSON value of [width]. + * + * Unlike [width], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("width") @ExcludeMissing fun _width(): JsonField = width + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -138,7 +464,23 @@ private constructor( private var mediaUrl: JsonField? = null private var type: JsonField? = null private var url: JsonField? = null + private var id: JsonField = JsonMissing.of() + private var allowDownload: JsonField = JsonMissing.of() + private var altText: JsonField = JsonMissing.of() + private var aspectRatio: JsonField>? = null + private var availabilityStatus: JsonField = JsonMissing.of() + private var displayUrl: JsonField = JsonMissing.of() + private var durationMillis: JsonField = JsonMissing.of() + private var expandedUrl: JsonField = JsonMissing.of() + private var faceRects: JsonField = JsonMissing.of() + private var focusRects: JsonField>? = null + private var height: JsonField = JsonMissing.of() + private var indices: JsonField>? = null + private var mediaKey: JsonField = JsonMissing.of() + private var monetizable: JsonField = JsonMissing.of() + private var sizes: JsonField = JsonMissing.of() private var videoVariants: JsonField>? = null + private var width: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -146,7 +488,23 @@ private constructor( mediaUrl = tweetMedia.mediaUrl type = tweetMedia.type url = tweetMedia.url + id = tweetMedia.id + allowDownload = tweetMedia.allowDownload + altText = tweetMedia.altText + aspectRatio = tweetMedia.aspectRatio.map { it.toMutableList() } + availabilityStatus = tweetMedia.availabilityStatus + displayUrl = tweetMedia.displayUrl + durationMillis = tweetMedia.durationMillis + expandedUrl = tweetMedia.expandedUrl + faceRects = tweetMedia.faceRects + focusRects = tweetMedia.focusRects.map { it.toMutableList() } + height = tweetMedia.height + indices = tweetMedia.indices.map { it.toMutableList() } + mediaKey = tweetMedia.mediaKey + monetizable = tweetMedia.monetizable + sizes = tweetMedia.sizes videoVariants = tweetMedia.videoVariants.map { it.toMutableList() } + width = tweetMedia.width additionalProperties = tweetMedia.additionalProperties.toMutableMap() } @@ -182,80 +540,331 @@ private constructor( */ fun url(url: JsonField) = apply { this.url = url } - /** Available video encodings, ordered as returned */ - fun videoVariants(videoVariants: List) = - videoVariants(JsonField.of(videoVariants)) + /** X media entity ID. */ + fun id(id: String) = id(JsonField.of(id)) /** - * Sets [Builder.videoVariants] to an arbitrary JSON value. + * Sets [Builder.id] to an arbitrary JSON value. * - * You should usually call [Builder.videoVariants] with a well-typed `List` - * value instead. This method is primarily for setting the field to an undocumented or not - * yet supported value. + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun videoVariants(videoVariants: JsonField>) = apply { - this.videoVariants = videoVariants.map { it.toMutableList() } + fun id(id: JsonField) = apply { this.id = id } + + /** Whether X permits direct media download. */ + fun allowDownload(allowDownload: Boolean) = allowDownload(JsonField.of(allowDownload)) + + /** + * Sets [Builder.allowDownload] to an arbitrary JSON value. + * + * You should usually call [Builder.allowDownload] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun allowDownload(allowDownload: JsonField) = apply { + this.allowDownload = allowDownload } + /** Accessibility text supplied for the media. */ + fun altText(altText: String) = altText(JsonField.of(altText)) + /** - * Adds a single [VideoVariant] to [videoVariants]. + * Sets [Builder.altText] to an arbitrary JSON value. + * + * You should usually call [Builder.altText] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun altText(altText: JsonField) = apply { this.altText = altText } + + /** Video aspect ratio as width and height. */ + fun aspectRatio(aspectRatio: List) = aspectRatio(JsonField.of(aspectRatio)) + + /** + * Sets [Builder.aspectRatio] to an arbitrary JSON value. + * + * You should usually call [Builder.aspectRatio] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun aspectRatio(aspectRatio: JsonField>) = apply { + this.aspectRatio = aspectRatio.map { it.toMutableList() } + } + + /** + * Adds a single [Long] to [Builder.aspectRatio]. * * @throws IllegalStateException if the field was previously set to a non-list. */ - fun addVideoVariant(videoVariant: VideoVariant) = apply { - videoVariants = - (videoVariants ?: JsonField.of(mutableListOf())).also { - checkKnown("videoVariants", it).add(videoVariant) + fun addAspectRatio(aspectRatio: Long) = apply { + this.aspectRatio = + (this.aspectRatio ?: JsonField.of(mutableListOf())).also { + checkKnown("aspectRatio", it).add(aspectRatio) } } - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** Media availability state reported by X. */ + fun availabilityStatus(availabilityStatus: String) = + availabilityStatus(JsonField.of(availabilityStatus)) - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) + /** + * Sets [Builder.availabilityStatus] to an arbitrary JSON value. + * + * You should usually call [Builder.availabilityStatus] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun availabilityStatus(availabilityStatus: JsonField) = apply { + this.availabilityStatus = availabilityStatus } - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + /** Display-friendly media URL reported by X. */ + fun displayUrl(displayUrl: String) = displayUrl(JsonField.of(displayUrl)) - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + /** + * Sets [Builder.displayUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.displayUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun displayUrl(displayUrl: JsonField) = apply { this.displayUrl = displayUrl } - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) - } + /** Video duration in milliseconds. */ + fun durationMillis(durationMillis: Long) = durationMillis(JsonField.of(durationMillis)) /** - * Returns an immutable instance of [TweetMedia]. + * Sets [Builder.durationMillis] to an arbitrary JSON value. * - * Further updates to this [Builder] will not mutate the returned instance. + * You should usually call [Builder.durationMillis] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun durationMillis(durationMillis: JsonField) = apply { + this.durationMillis = durationMillis + } + + /** Expanded X media URL. */ + fun expandedUrl(expandedUrl: String) = expandedUrl(JsonField.of(expandedUrl)) + + /** + * Sets [Builder.expandedUrl] to an arbitrary JSON value. * - * The following fields are required: - * ```java - * .mediaUrl() - * .type() - * .url() - * ``` + * You should usually call [Builder.expandedUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun expandedUrl(expandedUrl: JsonField) = apply { this.expandedUrl = expandedUrl } + + /** Face-aware crop rectangles grouped by media size. */ + fun faceRects(faceRects: FaceRects) = faceRects(JsonField.of(faceRects)) + + /** + * Sets [Builder.faceRects] to an arbitrary JSON value. * - * @throws IllegalStateException if any required field is unset. + * You should usually call [Builder.faceRects] with a well-typed [FaceRects] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun build(): TweetMedia = - TweetMedia( - checkRequired("mediaUrl", mediaUrl), - checkRequired("type", type), - checkRequired("url", url), - (videoVariants ?: JsonMissing.of()).map { it.toImmutable() }, - additionalProperties.toMutableMap(), - ) - } + fun faceRects(faceRects: JsonField) = apply { this.faceRects = faceRects } - private var validated: Boolean = false + /** Suggested image crops reported by X. */ + fun focusRects(focusRects: List) = focusRects(JsonField.of(focusRects)) - /** - * Validates that the types of all values in this object match their expected types recursively. + /** + * Sets [Builder.focusRects] to an arbitrary JSON value. + * + * You should usually call [Builder.focusRects] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun focusRects(focusRects: JsonField>) = apply { + this.focusRects = focusRects.map { it.toMutableList() } + } + + /** + * Adds a single [FocusRect] to [focusRects]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addFocusRect(focusRect: FocusRect) = apply { + focusRects = + (focusRects ?: JsonField.of(mutableListOf())).also { + checkKnown("focusRects", it).add(focusRect) + } + } + + /** Original media height. */ + fun height(height: Long) = height(JsonField.of(height)) + + /** + * Sets [Builder.height] to an arbitrary JSON value. + * + * You should usually call [Builder.height] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun height(height: JsonField) = apply { this.height = height } + + /** Media entity offsets in the tweet text. */ + fun indices(indices: List) = indices(JsonField.of(indices)) + + /** + * Sets [Builder.indices] to an arbitrary JSON value. + * + * You should usually call [Builder.indices] with a well-typed `List` value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun indices(indices: JsonField>) = apply { + this.indices = indices.map { it.toMutableList() } + } + + /** + * Adds a single [Long] to [indices]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addIndex(index: Long) = apply { + indices = + (indices ?: JsonField.of(mutableListOf())).also { + checkKnown("indices", it).add(index) + } + } + + /** Stable X media key. */ + fun mediaKey(mediaKey: String) = mediaKey(JsonField.of(mediaKey)) + + /** + * Sets [Builder.mediaKey] to an arbitrary JSON value. + * + * You should usually call [Builder.mediaKey] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun mediaKey(mediaKey: JsonField) = apply { this.mediaKey = mediaKey } + + /** Whether X reports the media as monetizable. */ + fun monetizable(monetizable: Boolean) = monetizable(JsonField.of(monetizable)) + + /** + * Sets [Builder.monetizable] to an arbitrary JSON value. + * + * You should usually call [Builder.monetizable] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun monetizable(monetizable: JsonField) = apply { this.monetizable = monetizable } + + /** Named media renditions and resize modes. */ + fun sizes(sizes: Sizes) = sizes(JsonField.of(sizes)) + + /** + * Sets [Builder.sizes] to an arbitrary JSON value. + * + * You should usually call [Builder.sizes] with a well-typed [Sizes] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun sizes(sizes: JsonField) = apply { this.sizes = sizes } + + /** Available video encodings, ordered as returned */ + fun videoVariants(videoVariants: List) = + videoVariants(JsonField.of(videoVariants)) + + /** + * Sets [Builder.videoVariants] to an arbitrary JSON value. + * + * You should usually call [Builder.videoVariants] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun videoVariants(videoVariants: JsonField>) = apply { + this.videoVariants = videoVariants.map { it.toMutableList() } + } + + /** + * Adds a single [VideoVariant] to [videoVariants]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addVideoVariant(videoVariant: VideoVariant) = apply { + videoVariants = + (videoVariants ?: JsonField.of(mutableListOf())).also { + checkKnown("videoVariants", it).add(videoVariant) + } + } + + /** Original media width. */ + fun width(width: Long) = width(JsonField.of(width)) + + /** + * Sets [Builder.width] to an arbitrary JSON value. + * + * You should usually call [Builder.width] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun width(width: JsonField) = apply { this.width = width } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [TweetMedia]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .mediaUrl() + * .type() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): TweetMedia = + TweetMedia( + checkRequired("mediaUrl", mediaUrl), + checkRequired("type", type), + checkRequired("url", url), + id, + allowDownload, + altText, + (aspectRatio ?: JsonMissing.of()).map { it.toImmutable() }, + availabilityStatus, + displayUrl, + durationMillis, + expandedUrl, + faceRects, + (focusRects ?: JsonMissing.of()).map { it.toImmutable() }, + height, + (indices ?: JsonMissing.of()).map { it.toImmutable() }, + mediaKey, + monetizable, + sizes, + (videoVariants ?: JsonMissing.of()).map { it.toImmutable() }, + width, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types recursively. * * This method is _not_ forwards compatible with new types from the API for existing fields. * @@ -270,7 +879,23 @@ private constructor( mediaUrl() type().validate() url() + id() + allowDownload() + altText() + aspectRatio() + availabilityStatus() + displayUrl() + durationMillis() + expandedUrl() + faceRects().ifPresent { it.validate() } + focusRects().ifPresent { it.forEach { it.validate() } } + height() + indices() + mediaKey() + monetizable() + sizes().ifPresent { it.validate() } videoVariants().ifPresent { it.forEach { it.validate() } } + width() validated = true } @@ -292,7 +917,23 @@ private constructor( (if (mediaUrl.asKnown().isPresent) 1 else 0) + (type.asKnown().getOrNull()?.validity() ?: 0) + (if (url.asKnown().isPresent) 1 else 0) + - (videoVariants.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + (if (id.asKnown().isPresent) 1 else 0) + + (if (allowDownload.asKnown().isPresent) 1 else 0) + + (if (altText.asKnown().isPresent) 1 else 0) + + (aspectRatio.asKnown().getOrNull()?.size ?: 0) + + (if (availabilityStatus.asKnown().isPresent) 1 else 0) + + (if (displayUrl.asKnown().isPresent) 1 else 0) + + (if (durationMillis.asKnown().isPresent) 1 else 0) + + (if (expandedUrl.asKnown().isPresent) 1 else 0) + + (faceRects.asKnown().getOrNull()?.validity() ?: 0) + + (focusRects.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (if (height.asKnown().isPresent) 1 else 0) + + (indices.asKnown().getOrNull()?.size ?: 0) + + (if (mediaKey.asKnown().isPresent) 1 else 0) + + (if (monetizable.asKnown().isPresent) 1 else 0) + + (sizes.asKnown().getOrNull()?.validity() ?: 0) + + (videoVariants.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (if (width.asKnown().isPresent) 1 else 0) class Type @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -436,6 +1077,499 @@ private constructor( override fun toString() = value.toString() } + /** Face-aware crop rectangles grouped by media size. */ + class FaceRects + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [FaceRects]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [FaceRects]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(faceRects: FaceRects) = apply { + additionalProperties = faceRects.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [FaceRects]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): FaceRects = FaceRects(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): FaceRects = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FaceRects && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "FaceRects{additionalProperties=$additionalProperties}" + } + + class FocusRect + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val h: JsonField, + private val w: JsonField, + private val x: JsonField, + private val y: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("h") @ExcludeMissing h: JsonField = JsonMissing.of(), + @JsonProperty("w") @ExcludeMissing w: JsonField = JsonMissing.of(), + @JsonProperty("x") @ExcludeMissing x: JsonField = JsonMissing.of(), + @JsonProperty("y") @ExcludeMissing y: JsonField = JsonMissing.of(), + ) : this(h, w, x, y, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun h(): Long = h.getRequired("h") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun w(): Long = w.getRequired("w") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun x(): Long = x.getRequired("x") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun y(): Long = y.getRequired("y") + + /** + * Returns the raw JSON value of [h]. + * + * Unlike [h], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("h") @ExcludeMissing fun _h(): JsonField = h + + /** + * Returns the raw JSON value of [w]. + * + * Unlike [w], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("w") @ExcludeMissing fun _w(): JsonField = w + + /** + * Returns the raw JSON value of [x]. + * + * Unlike [x], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("x") @ExcludeMissing fun _x(): JsonField = x + + /** + * Returns the raw JSON value of [y]. + * + * Unlike [y], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("y") @ExcludeMissing fun _y(): JsonField = y + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [FocusRect]. + * + * The following fields are required: + * ```java + * .h() + * .w() + * .x() + * .y() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [FocusRect]. */ + class Builder internal constructor() { + + private var h: JsonField? = null + private var w: JsonField? = null + private var x: JsonField? = null + private var y: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(focusRect: FocusRect) = apply { + h = focusRect.h + w = focusRect.w + x = focusRect.x + y = focusRect.y + additionalProperties = focusRect.additionalProperties.toMutableMap() + } + + fun h(h: Long) = h(JsonField.of(h)) + + /** + * Sets [Builder.h] to an arbitrary JSON value. + * + * You should usually call [Builder.h] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun h(h: JsonField) = apply { this.h = h } + + fun w(w: Long) = w(JsonField.of(w)) + + /** + * Sets [Builder.w] to an arbitrary JSON value. + * + * You should usually call [Builder.w] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun w(w: JsonField) = apply { this.w = w } + + fun x(x: Long) = x(JsonField.of(x)) + + /** + * Sets [Builder.x] to an arbitrary JSON value. + * + * You should usually call [Builder.x] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun x(x: JsonField) = apply { this.x = x } + + fun y(y: Long) = y(JsonField.of(y)) + + /** + * Sets [Builder.y] to an arbitrary JSON value. + * + * You should usually call [Builder.y] with a well-typed [Long] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun y(y: JsonField) = apply { this.y = y } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [FocusRect]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .h() + * .w() + * .x() + * .y() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): FocusRect = + FocusRect( + checkRequired("h", h), + checkRequired("w", w), + checkRequired("x", x), + checkRequired("y", y), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): FocusRect = apply { + if (validated) { + return@apply + } + + h() + w() + x() + y() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (h.asKnown().isPresent) 1 else 0) + + (if (w.asKnown().isPresent) 1 else 0) + + (if (x.asKnown().isPresent) 1 else 0) + + (if (y.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is FocusRect && + h == other.h && + w == other.w && + x == other.x && + y == other.y && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(h, w, x, y, additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "FocusRect{h=$h, w=$w, x=$x, y=$y, additionalProperties=$additionalProperties}" + } + + /** Named media renditions and resize modes. */ + class Sizes + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Sizes]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Sizes]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sizes: Sizes) = apply { + additionalProperties = sizes.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Sizes]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Sizes = Sizes(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Sizes = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Sizes && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Sizes{additionalProperties=$additionalProperties}" + } + class VideoVariant @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( @@ -688,16 +1822,54 @@ private constructor( mediaUrl == other.mediaUrl && type == other.type && url == other.url && + id == other.id && + allowDownload == other.allowDownload && + altText == other.altText && + aspectRatio == other.aspectRatio && + availabilityStatus == other.availabilityStatus && + displayUrl == other.displayUrl && + durationMillis == other.durationMillis && + expandedUrl == other.expandedUrl && + faceRects == other.faceRects && + focusRects == other.focusRects && + height == other.height && + indices == other.indices && + mediaKey == other.mediaKey && + monetizable == other.monetizable && + sizes == other.sizes && videoVariants == other.videoVariants && + width == other.width && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(mediaUrl, type, url, videoVariants, additionalProperties) + Objects.hash( + mediaUrl, + type, + url, + id, + allowDownload, + altText, + aspectRatio, + availabilityStatus, + displayUrl, + durationMillis, + expandedUrl, + faceRects, + focusRects, + height, + indices, + mediaKey, + monetizable, + sizes, + videoVariants, + width, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "TweetMedia{mediaUrl=$mediaUrl, type=$type, url=$url, videoVariants=$videoVariants, additionalProperties=$additionalProperties}" + "TweetMedia{mediaUrl=$mediaUrl, type=$type, url=$url, id=$id, allowDownload=$allowDownload, altText=$altText, aspectRatio=$aspectRatio, availabilityStatus=$availabilityStatus, displayUrl=$displayUrl, durationMillis=$durationMillis, expandedUrl=$expandedUrl, faceRects=$faceRects, focusRects=$focusRects, height=$height, indices=$indices, mediaKey=$mediaKey, monetizable=$monetizable, sizes=$sizes, videoVariants=$videoVariants, width=$width, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/UserProfile.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/UserProfile.kt index 90abbe6..54c596f 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/UserProfile.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/UserProfile.kt @@ -30,36 +30,48 @@ private constructor( private val id: JsonField, private val name: JsonField, private val username: JsonField, + private val affiliatesHighlightedLabel: JsonField, private val automatedBy: JsonField, - private val canDm: JsonField, + private val businessAccountAffiliatesCount: JsonField, private val communityRole: JsonField, private val coverPicture: JsonField, private val createdAt: JsonField, + private val creatorSubscriptionsCount: JsonField, private val description: JsonField, private val favouritesCount: JsonField, private val followers: JsonField, private val following: JsonField, private val hasCustomTimelines: JsonField, + private val hasGraduatedAccess: JsonField, + private val hasHiddenSubscriptionsOnProfile: JsonField, + private val highlightsInfo: JsonField, + private val identityVerification: JsonField, private val isAutomated: JsonField, private val isBlueVerified: JsonField, + private val isProfileTranslatable: JsonField, private val isTranslator: JsonField, private val isVerified: JsonField, private val location: JsonField, private val mediaCount: JsonField, + private val parodyCommentaryFanLabel: JsonField, private val pinnedTweetIds: JsonField>, private val possiblySensitive: JsonField, private val profileBio: JsonField, private val profileBannerUrl: JsonField, + private val profileDescriptionLanguage: JsonField, + private val profileImageShape: JsonField, + private val profileInterstitialType: JsonField, private val profilePicture: JsonField, + private val profileSortEnabled: JsonField, + private val profileTranslatorType: JsonField, private val protected_: JsonField, private val statusesCount: JsonField, + private val superFollowEligible: JsonField, private val unavailable: JsonField, private val unavailableReason: JsonField, private val url: JsonField, private val verified: JsonField, private val verifiedType: JsonField, - private val viewerFollowedBy: JsonField, - private val viewerFollowing: JsonField, private val withheldInCountries: JsonField>, private val additionalProperties: MutableMap, ) { @@ -69,10 +81,15 @@ private constructor( @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), @JsonProperty("username") @ExcludeMissing username: JsonField = JsonMissing.of(), + @JsonProperty("affiliatesHighlightedLabel") + @ExcludeMissing + affiliatesHighlightedLabel: JsonField = JsonMissing.of(), @JsonProperty("automatedBy") @ExcludeMissing automatedBy: JsonField = JsonMissing.of(), - @JsonProperty("canDm") @ExcludeMissing canDm: JsonField = JsonMissing.of(), + @JsonProperty("businessAccountAffiliatesCount") + @ExcludeMissing + businessAccountAffiliatesCount: JsonField = JsonMissing.of(), @JsonProperty("communityRole") @ExcludeMissing communityRole: JsonField = JsonMissing.of(), @@ -80,6 +97,9 @@ private constructor( @ExcludeMissing coverPicture: JsonField = JsonMissing.of(), @JsonProperty("createdAt") @ExcludeMissing createdAt: JsonField = JsonMissing.of(), + @JsonProperty("creatorSubscriptionsCount") + @ExcludeMissing + creatorSubscriptionsCount: JsonField = JsonMissing.of(), @JsonProperty("description") @ExcludeMissing description: JsonField = JsonMissing.of(), @@ -91,12 +111,27 @@ private constructor( @JsonProperty("hasCustomTimelines") @ExcludeMissing hasCustomTimelines: JsonField = JsonMissing.of(), + @JsonProperty("hasGraduatedAccess") + @ExcludeMissing + hasGraduatedAccess: JsonField = JsonMissing.of(), + @JsonProperty("hasHiddenSubscriptionsOnProfile") + @ExcludeMissing + hasHiddenSubscriptionsOnProfile: JsonField = JsonMissing.of(), + @JsonProperty("highlightsInfo") + @ExcludeMissing + highlightsInfo: JsonField = JsonMissing.of(), + @JsonProperty("identityVerification") + @ExcludeMissing + identityVerification: JsonField = JsonMissing.of(), @JsonProperty("isAutomated") @ExcludeMissing isAutomated: JsonField = JsonMissing.of(), @JsonProperty("isBlueVerified") @ExcludeMissing isBlueVerified: JsonField = JsonMissing.of(), + @JsonProperty("isProfileTranslatable") + @ExcludeMissing + isProfileTranslatable: JsonField = JsonMissing.of(), @JsonProperty("isTranslator") @ExcludeMissing isTranslator: JsonField = JsonMissing.of(), @@ -105,6 +140,9 @@ private constructor( isVerified: JsonField = JsonMissing.of(), @JsonProperty("location") @ExcludeMissing location: JsonField = JsonMissing.of(), @JsonProperty("mediaCount") @ExcludeMissing mediaCount: JsonField = JsonMissing.of(), + @JsonProperty("parodyCommentaryFanLabel") + @ExcludeMissing + parodyCommentaryFanLabel: JsonField = JsonMissing.of(), @JsonProperty("pinnedTweetIds") @ExcludeMissing pinnedTweetIds: JsonField> = JsonMissing.of(), @@ -117,15 +155,33 @@ private constructor( @JsonProperty("profileBannerUrl") @ExcludeMissing profileBannerUrl: JsonField = JsonMissing.of(), + @JsonProperty("profileDescriptionLanguage") + @ExcludeMissing + profileDescriptionLanguage: JsonField = JsonMissing.of(), + @JsonProperty("profileImageShape") + @ExcludeMissing + profileImageShape: JsonField = JsonMissing.of(), + @JsonProperty("profileInterstitialType") + @ExcludeMissing + profileInterstitialType: JsonField = JsonMissing.of(), @JsonProperty("profilePicture") @ExcludeMissing profilePicture: JsonField = JsonMissing.of(), + @JsonProperty("profileSortEnabled") + @ExcludeMissing + profileSortEnabled: JsonField = JsonMissing.of(), + @JsonProperty("profileTranslatorType") + @ExcludeMissing + profileTranslatorType: JsonField = JsonMissing.of(), @JsonProperty("protected") @ExcludeMissing protected_: JsonField = JsonMissing.of(), @JsonProperty("statusesCount") @ExcludeMissing statusesCount: JsonField = JsonMissing.of(), + @JsonProperty("superFollowEligible") + @ExcludeMissing + superFollowEligible: JsonField = JsonMissing.of(), @JsonProperty("unavailable") @ExcludeMissing unavailable: JsonField = JsonMissing.of(), @@ -137,12 +193,6 @@ private constructor( @JsonProperty("verifiedType") @ExcludeMissing verifiedType: JsonField = JsonMissing.of(), - @JsonProperty("viewerFollowedBy") - @ExcludeMissing - viewerFollowedBy: JsonField = JsonMissing.of(), - @JsonProperty("viewerFollowing") - @ExcludeMissing - viewerFollowing: JsonField = JsonMissing.of(), @JsonProperty("withheldInCountries") @ExcludeMissing withheldInCountries: JsonField> = JsonMissing.of(), @@ -150,36 +200,48 @@ private constructor( id, name, username, + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, pinnedTweetIds, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, withheldInCountries, mutableMapOf(), ) @@ -202,6 +264,15 @@ private constructor( */ fun username(): String = username.getRequired("username") + /** + * Organization affiliation label shown on an X profile. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun affiliatesHighlightedLabel(): Optional = + affiliatesHighlightedLabel.getOptional("affiliatesHighlightedLabel") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -212,7 +283,8 @@ private constructor( * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun canDm(): Optional = canDm.getOptional("canDm") + fun businessAccountAffiliatesCount(): Optional = + businessAccountAffiliatesCount.getOptional("businessAccountAffiliatesCount") /** * Community role when returned by community member reads @@ -234,6 +306,13 @@ private constructor( */ fun createdAt(): Optional = createdAt.getOptional("createdAt") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun creatorSubscriptionsCount(): Optional = + creatorSubscriptionsCount.getOptional("creatorSubscriptionsCount") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -265,6 +344,37 @@ private constructor( fun hasCustomTimelines(): Optional = hasCustomTimelines.getOptional("hasCustomTimelines") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun hasGraduatedAccess(): Optional = + hasGraduatedAccess.getOptional("hasGraduatedAccess") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun hasHiddenSubscriptionsOnProfile(): Optional = + hasHiddenSubscriptionsOnProfile.getOptional("hasHiddenSubscriptionsOnProfile") + + /** + * Profile highlight availability and count metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun highlightsInfo(): Optional = highlightsInfo.getOptional("highlightsInfo") + + /** + * Identity verification metadata displayed by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun identityVerification(): Optional = + identityVerification.getOptional("identityVerification") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -279,6 +389,13 @@ private constructor( */ fun isBlueVerified(): Optional = isBlueVerified.getOptional("isBlueVerified") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isProfileTranslatable(): Optional = + isProfileTranslatable.getOptional("isProfileTranslatable") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -305,6 +422,13 @@ private constructor( */ fun mediaCount(): Optional = mediaCount.getOptional("mediaCount") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun parodyCommentaryFanLabel(): Optional = + parodyCommentaryFanLabel.getOptional("parodyCommentaryFanLabel") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -333,6 +457,26 @@ private constructor( */ fun profileBannerUrl(): Optional = profileBannerUrl.getOptional("profileBannerUrl") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileDescriptionLanguage(): Optional = + profileDescriptionLanguage.getOptional("profileDescriptionLanguage") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileImageShape(): Optional = profileImageShape.getOptional("profileImageShape") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileInterstitialType(): Optional = + profileInterstitialType.getOptional("profileInterstitialType") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -340,64 +484,69 @@ private constructor( fun profilePicture(): Optional = profilePicture.getOptional("profilePicture") /** - * Whether the profile protects its posts - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun protected_(): Optional = protected_.getOptional("protected") + fun profileSortEnabled(): Optional = + profileSortEnabled.getOptional("profileSortEnabled") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun statusesCount(): Optional = statusesCount.getOptional("statusesCount") + fun profileTranslatorType(): Optional = + profileTranslatorType.getOptional("profileTranslatorType") /** + * Whether the profile protects its posts + * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun unavailable(): Optional = unavailable.getOptional("unavailable") + fun protected_(): Optional = protected_.getOptional("protected") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun unavailableReason(): Optional = unavailableReason.getOptional("unavailableReason") + fun statusesCount(): Optional = statusesCount.getOptional("statusesCount") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun url(): Optional = url.getOptional("url") + fun superFollowEligible(): Optional = + superFollowEligible.getOptional("superFollowEligible") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verified(): Optional = verified.getOptional("verified") + fun unavailable(): Optional = unavailable.getOptional("unavailable") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verifiedType(): Optional = verifiedType.getOptional("verifiedType") + fun unavailableReason(): Optional = unavailableReason.getOptional("unavailableReason") /** - * Whether this profile follows the authenticated viewer - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun viewerFollowedBy(): Optional = viewerFollowedBy.getOptional("viewerFollowedBy") + fun url(): Optional = url.getOptional("url") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun verified(): Optional = verified.getOptional("verified") /** - * Whether the authenticated viewer follows this profile - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun viewerFollowing(): Optional = viewerFollowing.getOptional("viewerFollowing") + fun verifiedType(): Optional = verifiedType.getOptional("verifiedType") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if @@ -427,6 +576,17 @@ private constructor( */ @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username + /** + * Returns the raw JSON value of [affiliatesHighlightedLabel]. + * + * Unlike [affiliatesHighlightedLabel], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("affiliatesHighlightedLabel") + @ExcludeMissing + fun _affiliatesHighlightedLabel(): JsonField = + affiliatesHighlightedLabel + /** * Returns the raw JSON value of [automatedBy]. * @@ -435,11 +595,14 @@ private constructor( @JsonProperty("automatedBy") @ExcludeMissing fun _automatedBy(): JsonField = automatedBy /** - * Returns the raw JSON value of [canDm]. + * Returns the raw JSON value of [businessAccountAffiliatesCount]. * - * Unlike [canDm], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [businessAccountAffiliatesCount], this method doesn't throw if the JSON field has an + * unexpected type. */ - @JsonProperty("canDm") @ExcludeMissing fun _canDm(): JsonField = canDm + @JsonProperty("businessAccountAffiliatesCount") + @ExcludeMissing + fun _businessAccountAffiliatesCount(): JsonField = businessAccountAffiliatesCount /** * Returns the raw JSON value of [communityRole]. @@ -466,6 +629,16 @@ private constructor( */ @JsonProperty("createdAt") @ExcludeMissing fun _createdAt(): JsonField = createdAt + /** + * Returns the raw JSON value of [creatorSubscriptionsCount]. + * + * Unlike [creatorSubscriptionsCount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("creatorSubscriptionsCount") + @ExcludeMissing + fun _creatorSubscriptionsCount(): JsonField = creatorSubscriptionsCount + /** * Returns the raw JSON value of [description]. * @@ -506,6 +679,45 @@ private constructor( @ExcludeMissing fun _hasCustomTimelines(): JsonField = hasCustomTimelines + /** + * Returns the raw JSON value of [hasGraduatedAccess]. + * + * Unlike [hasGraduatedAccess], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("hasGraduatedAccess") + @ExcludeMissing + fun _hasGraduatedAccess(): JsonField = hasGraduatedAccess + + /** + * Returns the raw JSON value of [hasHiddenSubscriptionsOnProfile]. + * + * Unlike [hasHiddenSubscriptionsOnProfile], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("hasHiddenSubscriptionsOnProfile") + @ExcludeMissing + fun _hasHiddenSubscriptionsOnProfile(): JsonField = hasHiddenSubscriptionsOnProfile + + /** + * Returns the raw JSON value of [highlightsInfo]. + * + * Unlike [highlightsInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("highlightsInfo") + @ExcludeMissing + fun _highlightsInfo(): JsonField = highlightsInfo + + /** + * Returns the raw JSON value of [identityVerification]. + * + * Unlike [identityVerification], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("identityVerification") + @ExcludeMissing + fun _identityVerification(): JsonField = identityVerification + /** * Returns the raw JSON value of [isAutomated]. * @@ -524,6 +736,16 @@ private constructor( @ExcludeMissing fun _isBlueVerified(): JsonField = isBlueVerified + /** + * Returns the raw JSON value of [isProfileTranslatable]. + * + * Unlike [isProfileTranslatable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isProfileTranslatable") + @ExcludeMissing + fun _isProfileTranslatable(): JsonField = isProfileTranslatable + /** * Returns the raw JSON value of [isTranslator]. * @@ -554,6 +776,16 @@ private constructor( */ @JsonProperty("mediaCount") @ExcludeMissing fun _mediaCount(): JsonField = mediaCount + /** + * Returns the raw JSON value of [parodyCommentaryFanLabel]. + * + * Unlike [parodyCommentaryFanLabel], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("parodyCommentaryFanLabel") + @ExcludeMissing + fun _parodyCommentaryFanLabel(): JsonField = parodyCommentaryFanLabel + /** * Returns the raw JSON value of [pinnedTweetIds]. * @@ -592,6 +824,36 @@ private constructor( @ExcludeMissing fun _profileBannerUrl(): JsonField = profileBannerUrl + /** + * Returns the raw JSON value of [profileDescriptionLanguage]. + * + * Unlike [profileDescriptionLanguage], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("profileDescriptionLanguage") + @ExcludeMissing + fun _profileDescriptionLanguage(): JsonField = profileDescriptionLanguage + + /** + * Returns the raw JSON value of [profileImageShape]. + * + * Unlike [profileImageShape], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileImageShape") + @ExcludeMissing + fun _profileImageShape(): JsonField = profileImageShape + + /** + * Returns the raw JSON value of [profileInterstitialType]. + * + * Unlike [profileInterstitialType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("profileInterstitialType") + @ExcludeMissing + fun _profileInterstitialType(): JsonField = profileInterstitialType + /** * Returns the raw JSON value of [profilePicture]. * @@ -601,6 +863,26 @@ private constructor( @ExcludeMissing fun _profilePicture(): JsonField = profilePicture + /** + * Returns the raw JSON value of [profileSortEnabled]. + * + * Unlike [profileSortEnabled], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileSortEnabled") + @ExcludeMissing + fun _profileSortEnabled(): JsonField = profileSortEnabled + + /** + * Returns the raw JSON value of [profileTranslatorType]. + * + * Unlike [profileTranslatorType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileTranslatorType") + @ExcludeMissing + fun _profileTranslatorType(): JsonField = profileTranslatorType + /** * Returns the raw JSON value of [protected_]. * @@ -617,6 +899,16 @@ private constructor( @ExcludeMissing fun _statusesCount(): JsonField = statusesCount + /** + * Returns the raw JSON value of [superFollowEligible]. + * + * Unlike [superFollowEligible], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("superFollowEligible") + @ExcludeMissing + fun _superFollowEligible(): JsonField = superFollowEligible + /** * Returns the raw JSON value of [unavailable]. * @@ -659,25 +951,6 @@ private constructor( @ExcludeMissing fun _verifiedType(): JsonField = verifiedType - /** - * Returns the raw JSON value of [viewerFollowedBy]. - * - * Unlike [viewerFollowedBy], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("viewerFollowedBy") - @ExcludeMissing - fun _viewerFollowedBy(): JsonField = viewerFollowedBy - - /** - * Returns the raw JSON value of [viewerFollowing]. - * - * Unlike [viewerFollowing], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("viewerFollowing") - @ExcludeMissing - fun _viewerFollowing(): JsonField = viewerFollowing - /** * Returns the raw JSON value of [withheldInCountries]. * @@ -721,36 +994,49 @@ private constructor( private var id: JsonField? = null private var name: JsonField? = null private var username: JsonField? = null + private var affiliatesHighlightedLabel: JsonField = + JsonMissing.of() private var automatedBy: JsonField = JsonMissing.of() - private var canDm: JsonField = JsonMissing.of() + private var businessAccountAffiliatesCount: JsonField = JsonMissing.of() private var communityRole: JsonField = JsonMissing.of() private var coverPicture: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() + private var creatorSubscriptionsCount: JsonField = JsonMissing.of() private var description: JsonField = JsonMissing.of() private var favouritesCount: JsonField = JsonMissing.of() private var followers: JsonField = JsonMissing.of() private var following: JsonField = JsonMissing.of() private var hasCustomTimelines: JsonField = JsonMissing.of() + private var hasGraduatedAccess: JsonField = JsonMissing.of() + private var hasHiddenSubscriptionsOnProfile: JsonField = JsonMissing.of() + private var highlightsInfo: JsonField = JsonMissing.of() + private var identityVerification: JsonField = JsonMissing.of() private var isAutomated: JsonField = JsonMissing.of() private var isBlueVerified: JsonField = JsonMissing.of() + private var isProfileTranslatable: JsonField = JsonMissing.of() private var isTranslator: JsonField = JsonMissing.of() private var isVerified: JsonField = JsonMissing.of() private var location: JsonField = JsonMissing.of() private var mediaCount: JsonField = JsonMissing.of() + private var parodyCommentaryFanLabel: JsonField = JsonMissing.of() private var pinnedTweetIds: JsonField>? = null private var possiblySensitive: JsonField = JsonMissing.of() private var profileBio: JsonField = JsonMissing.of() private var profileBannerUrl: JsonField = JsonMissing.of() + private var profileDescriptionLanguage: JsonField = JsonMissing.of() + private var profileImageShape: JsonField = JsonMissing.of() + private var profileInterstitialType: JsonField = JsonMissing.of() private var profilePicture: JsonField = JsonMissing.of() + private var profileSortEnabled: JsonField = JsonMissing.of() + private var profileTranslatorType: JsonField = JsonMissing.of() private var protected_: JsonField = JsonMissing.of() private var statusesCount: JsonField = JsonMissing.of() + private var superFollowEligible: JsonField = JsonMissing.of() private var unavailable: JsonField = JsonMissing.of() private var unavailableReason: JsonField = JsonMissing.of() private var url: JsonField = JsonMissing.of() private var verified: JsonField = JsonMissing.of() private var verifiedType: JsonField = JsonMissing.of() - private var viewerFollowedBy: JsonField = JsonMissing.of() - private var viewerFollowing: JsonField = JsonMissing.of() private var withheldInCountries: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -759,36 +1045,48 @@ private constructor( id = userProfile.id name = userProfile.name username = userProfile.username + affiliatesHighlightedLabel = userProfile.affiliatesHighlightedLabel automatedBy = userProfile.automatedBy - canDm = userProfile.canDm + businessAccountAffiliatesCount = userProfile.businessAccountAffiliatesCount communityRole = userProfile.communityRole coverPicture = userProfile.coverPicture createdAt = userProfile.createdAt + creatorSubscriptionsCount = userProfile.creatorSubscriptionsCount description = userProfile.description favouritesCount = userProfile.favouritesCount followers = userProfile.followers following = userProfile.following hasCustomTimelines = userProfile.hasCustomTimelines + hasGraduatedAccess = userProfile.hasGraduatedAccess + hasHiddenSubscriptionsOnProfile = userProfile.hasHiddenSubscriptionsOnProfile + highlightsInfo = userProfile.highlightsInfo + identityVerification = userProfile.identityVerification isAutomated = userProfile.isAutomated isBlueVerified = userProfile.isBlueVerified + isProfileTranslatable = userProfile.isProfileTranslatable isTranslator = userProfile.isTranslator isVerified = userProfile.isVerified location = userProfile.location mediaCount = userProfile.mediaCount + parodyCommentaryFanLabel = userProfile.parodyCommentaryFanLabel pinnedTweetIds = userProfile.pinnedTweetIds.map { it.toMutableList() } possiblySensitive = userProfile.possiblySensitive profileBio = userProfile.profileBio profileBannerUrl = userProfile.profileBannerUrl + profileDescriptionLanguage = userProfile.profileDescriptionLanguage + profileImageShape = userProfile.profileImageShape + profileInterstitialType = userProfile.profileInterstitialType profilePicture = userProfile.profilePicture + profileSortEnabled = userProfile.profileSortEnabled + profileTranslatorType = userProfile.profileTranslatorType protected_ = userProfile.protected_ statusesCount = userProfile.statusesCount + superFollowEligible = userProfile.superFollowEligible unavailable = userProfile.unavailable unavailableReason = userProfile.unavailableReason url = userProfile.url verified = userProfile.verified verifiedType = userProfile.verifiedType - viewerFollowedBy = userProfile.viewerFollowedBy - viewerFollowing = userProfile.viewerFollowing withheldInCountries = userProfile.withheldInCountries.map { it.toMutableList() } additionalProperties = userProfile.additionalProperties.toMutableMap() } @@ -823,6 +1121,21 @@ private constructor( */ fun username(username: JsonField) = apply { this.username = username } + /** Organization affiliation label shown on an X profile. */ + fun affiliatesHighlightedLabel(affiliatesHighlightedLabel: AffiliatesHighlightedLabel) = + affiliatesHighlightedLabel(JsonField.of(affiliatesHighlightedLabel)) + + /** + * Sets [Builder.affiliatesHighlightedLabel] to an arbitrary JSON value. + * + * You should usually call [Builder.affiliatesHighlightedLabel] with a well-typed + * [AffiliatesHighlightedLabel] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun affiliatesHighlightedLabel( + affiliatesHighlightedLabel: JsonField + ) = apply { this.affiliatesHighlightedLabel = affiliatesHighlightedLabel } + fun automatedBy(automatedBy: String) = automatedBy(JsonField.of(automatedBy)) /** @@ -834,15 +1147,20 @@ private constructor( */ fun automatedBy(automatedBy: JsonField) = apply { this.automatedBy = automatedBy } - fun canDm(canDm: Boolean) = canDm(JsonField.of(canDm)) + fun businessAccountAffiliatesCount(businessAccountAffiliatesCount: Long) = + businessAccountAffiliatesCount(JsonField.of(businessAccountAffiliatesCount)) /** - * Sets [Builder.canDm] to an arbitrary JSON value. + * Sets [Builder.businessAccountAffiliatesCount] to an arbitrary JSON value. * - * You should usually call [Builder.canDm] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.businessAccountAffiliatesCount] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. */ - fun canDm(canDm: JsonField) = apply { this.canDm = canDm } + fun businessAccountAffiliatesCount(businessAccountAffiliatesCount: JsonField) = + apply { + this.businessAccountAffiliatesCount = businessAccountAffiliatesCount + } /** Community role when returned by community member reads */ fun communityRole(communityRole: String) = communityRole(JsonField.of(communityRole)) @@ -882,6 +1200,20 @@ private constructor( */ fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } + fun creatorSubscriptionsCount(creatorSubscriptionsCount: Long) = + creatorSubscriptionsCount(JsonField.of(creatorSubscriptionsCount)) + + /** + * Sets [Builder.creatorSubscriptionsCount] to an arbitrary JSON value. + * + * You should usually call [Builder.creatorSubscriptionsCount] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun creatorSubscriptionsCount(creatorSubscriptionsCount: JsonField) = apply { + this.creatorSubscriptionsCount = creatorSubscriptionsCount + } + fun description(description: String) = description(JsonField.of(description)) /** @@ -940,6 +1272,65 @@ private constructor( this.hasCustomTimelines = hasCustomTimelines } + fun hasGraduatedAccess(hasGraduatedAccess: Boolean) = + hasGraduatedAccess(JsonField.of(hasGraduatedAccess)) + + /** + * Sets [Builder.hasGraduatedAccess] to an arbitrary JSON value. + * + * You should usually call [Builder.hasGraduatedAccess] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun hasGraduatedAccess(hasGraduatedAccess: JsonField) = apply { + this.hasGraduatedAccess = hasGraduatedAccess + } + + fun hasHiddenSubscriptionsOnProfile(hasHiddenSubscriptionsOnProfile: Boolean) = + hasHiddenSubscriptionsOnProfile(JsonField.of(hasHiddenSubscriptionsOnProfile)) + + /** + * Sets [Builder.hasHiddenSubscriptionsOnProfile] to an arbitrary JSON value. + * + * You should usually call [Builder.hasHiddenSubscriptionsOnProfile] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun hasHiddenSubscriptionsOnProfile(hasHiddenSubscriptionsOnProfile: JsonField) = + apply { + this.hasHiddenSubscriptionsOnProfile = hasHiddenSubscriptionsOnProfile + } + + /** Profile highlight availability and count metadata. */ + fun highlightsInfo(highlightsInfo: HighlightsInfo) = + highlightsInfo(JsonField.of(highlightsInfo)) + + /** + * Sets [Builder.highlightsInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.highlightsInfo] with a well-typed [HighlightsInfo] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun highlightsInfo(highlightsInfo: JsonField) = apply { + this.highlightsInfo = highlightsInfo + } + + /** Identity verification metadata displayed by X. */ + fun identityVerification(identityVerification: IdentityVerification) = + identityVerification(JsonField.of(identityVerification)) + + /** + * Sets [Builder.identityVerification] to an arbitrary JSON value. + * + * You should usually call [Builder.identityVerification] with a well-typed + * [IdentityVerification] value instead. This method is primarily for setting the field to + * an undocumented or not yet supported value. + */ + fun identityVerification(identityVerification: JsonField) = apply { + this.identityVerification = identityVerification + } + fun isAutomated(isAutomated: Boolean) = isAutomated(JsonField.of(isAutomated)) /** @@ -965,6 +1356,20 @@ private constructor( this.isBlueVerified = isBlueVerified } + fun isProfileTranslatable(isProfileTranslatable: Boolean) = + isProfileTranslatable(JsonField.of(isProfileTranslatable)) + + /** + * Sets [Builder.isProfileTranslatable] to an arbitrary JSON value. + * + * You should usually call [Builder.isProfileTranslatable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isProfileTranslatable(isProfileTranslatable: JsonField) = apply { + this.isProfileTranslatable = isProfileTranslatable + } + fun isTranslator(isTranslator: Boolean) = isTranslator(JsonField.of(isTranslator)) /** @@ -1010,6 +1415,20 @@ private constructor( */ fun mediaCount(mediaCount: JsonField) = apply { this.mediaCount = mediaCount } + fun parodyCommentaryFanLabel(parodyCommentaryFanLabel: String) = + parodyCommentaryFanLabel(JsonField.of(parodyCommentaryFanLabel)) + + /** + * Sets [Builder.parodyCommentaryFanLabel] to an arbitrary JSON value. + * + * You should usually call [Builder.parodyCommentaryFanLabel] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun parodyCommentaryFanLabel(parodyCommentaryFanLabel: JsonField) = apply { + this.parodyCommentaryFanLabel = parodyCommentaryFanLabel + } + fun pinnedTweetIds(pinnedTweetIds: List) = pinnedTweetIds(JsonField.of(pinnedTweetIds)) @@ -1077,19 +1496,89 @@ private constructor( this.profileBannerUrl = profileBannerUrl } - fun profilePicture(profilePicture: String) = profilePicture(JsonField.of(profilePicture)) + fun profileDescriptionLanguage(profileDescriptionLanguage: String) = + profileDescriptionLanguage(JsonField.of(profileDescriptionLanguage)) /** - * Sets [Builder.profilePicture] to an arbitrary JSON value. + * Sets [Builder.profileDescriptionLanguage] to an arbitrary JSON value. * - * You should usually call [Builder.profilePicture] with a well-typed [String] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ + * You should usually call [Builder.profileDescriptionLanguage] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun profileDescriptionLanguage(profileDescriptionLanguage: JsonField) = apply { + this.profileDescriptionLanguage = profileDescriptionLanguage + } + + fun profileImageShape(profileImageShape: String) = + profileImageShape(JsonField.of(profileImageShape)) + + /** + * Sets [Builder.profileImageShape] to an arbitrary JSON value. + * + * You should usually call [Builder.profileImageShape] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileImageShape(profileImageShape: JsonField) = apply { + this.profileImageShape = profileImageShape + } + + fun profileInterstitialType(profileInterstitialType: String) = + profileInterstitialType(JsonField.of(profileInterstitialType)) + + /** + * Sets [Builder.profileInterstitialType] to an arbitrary JSON value. + * + * You should usually call [Builder.profileInterstitialType] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun profileInterstitialType(profileInterstitialType: JsonField) = apply { + this.profileInterstitialType = profileInterstitialType + } + + fun profilePicture(profilePicture: String) = profilePicture(JsonField.of(profilePicture)) + + /** + * Sets [Builder.profilePicture] to an arbitrary JSON value. + * + * You should usually call [Builder.profilePicture] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ fun profilePicture(profilePicture: JsonField) = apply { this.profilePicture = profilePicture } + fun profileSortEnabled(profileSortEnabled: Boolean) = + profileSortEnabled(JsonField.of(profileSortEnabled)) + + /** + * Sets [Builder.profileSortEnabled] to an arbitrary JSON value. + * + * You should usually call [Builder.profileSortEnabled] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileSortEnabled(profileSortEnabled: JsonField) = apply { + this.profileSortEnabled = profileSortEnabled + } + + fun profileTranslatorType(profileTranslatorType: String) = + profileTranslatorType(JsonField.of(profileTranslatorType)) + + /** + * Sets [Builder.profileTranslatorType] to an arbitrary JSON value. + * + * You should usually call [Builder.profileTranslatorType] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileTranslatorType(profileTranslatorType: JsonField) = apply { + this.profileTranslatorType = profileTranslatorType + } + /** Whether the profile protects its posts */ fun protected_(protected_: Boolean) = protected_(JsonField.of(protected_)) @@ -1115,6 +1604,20 @@ private constructor( this.statusesCount = statusesCount } + fun superFollowEligible(superFollowEligible: Boolean) = + superFollowEligible(JsonField.of(superFollowEligible)) + + /** + * Sets [Builder.superFollowEligible] to an arbitrary JSON value. + * + * You should usually call [Builder.superFollowEligible] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun superFollowEligible(superFollowEligible: JsonField) = apply { + this.superFollowEligible = superFollowEligible + } + fun unavailable(unavailable: Boolean) = unavailable(JsonField.of(unavailable)) /** @@ -1174,36 +1677,6 @@ private constructor( this.verifiedType = verifiedType } - /** Whether this profile follows the authenticated viewer */ - fun viewerFollowedBy(viewerFollowedBy: Boolean) = - viewerFollowedBy(JsonField.of(viewerFollowedBy)) - - /** - * Sets [Builder.viewerFollowedBy] to an arbitrary JSON value. - * - * You should usually call [Builder.viewerFollowedBy] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun viewerFollowedBy(viewerFollowedBy: JsonField) = apply { - this.viewerFollowedBy = viewerFollowedBy - } - - /** Whether the authenticated viewer follows this profile */ - fun viewerFollowing(viewerFollowing: Boolean) = - viewerFollowing(JsonField.of(viewerFollowing)) - - /** - * Sets [Builder.viewerFollowing] to an arbitrary JSON value. - * - * You should usually call [Builder.viewerFollowing] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun viewerFollowing(viewerFollowing: JsonField) = apply { - this.viewerFollowing = viewerFollowing - } - fun withheldInCountries(withheldInCountries: List) = withheldInCountries(JsonField.of(withheldInCountries)) @@ -1268,36 +1741,48 @@ private constructor( checkRequired("id", id), checkRequired("name", name), checkRequired("username", username), + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, (pinnedTweetIds ?: JsonMissing.of()).map { it.toImmutable() }, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, (withheldInCountries ?: JsonMissing.of()).map { it.toImmutable() }, additionalProperties.toMutableMap(), ) @@ -1321,36 +1806,48 @@ private constructor( id() name() username() + affiliatesHighlightedLabel().ifPresent { it.validate() } automatedBy() - canDm() + businessAccountAffiliatesCount() communityRole() coverPicture() createdAt() + creatorSubscriptionsCount() description() favouritesCount() followers() following() hasCustomTimelines() + hasGraduatedAccess() + hasHiddenSubscriptionsOnProfile() + highlightsInfo().ifPresent { it.validate() } + identityVerification().ifPresent { it.validate() } isAutomated() isBlueVerified() + isProfileTranslatable() isTranslator() isVerified() location() mediaCount() + parodyCommentaryFanLabel() pinnedTweetIds() possiblySensitive() profileBio().ifPresent { it.validate() } profileBannerUrl() + profileDescriptionLanguage() + profileImageShape() + profileInterstitialType() profilePicture() + profileSortEnabled() + profileTranslatorType() protected_() statusesCount() + superFollowEligible() unavailable() unavailableReason() url() verified() verifiedType() - viewerFollowedBy() - viewerFollowing() withheldInCountries() validated = true } @@ -1373,38 +1870,860 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + (if (username.asKnown().isPresent) 1 else 0) + + (affiliatesHighlightedLabel.asKnown().getOrNull()?.validity() ?: 0) + (if (automatedBy.asKnown().isPresent) 1 else 0) + - (if (canDm.asKnown().isPresent) 1 else 0) + + (if (businessAccountAffiliatesCount.asKnown().isPresent) 1 else 0) + (if (communityRole.asKnown().isPresent) 1 else 0) + (if (coverPicture.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + + (if (creatorSubscriptionsCount.asKnown().isPresent) 1 else 0) + (if (description.asKnown().isPresent) 1 else 0) + (if (favouritesCount.asKnown().isPresent) 1 else 0) + (if (followers.asKnown().isPresent) 1 else 0) + (if (following.asKnown().isPresent) 1 else 0) + (if (hasCustomTimelines.asKnown().isPresent) 1 else 0) + + (if (hasGraduatedAccess.asKnown().isPresent) 1 else 0) + + (if (hasHiddenSubscriptionsOnProfile.asKnown().isPresent) 1 else 0) + + (highlightsInfo.asKnown().getOrNull()?.validity() ?: 0) + + (identityVerification.asKnown().getOrNull()?.validity() ?: 0) + (if (isAutomated.asKnown().isPresent) 1 else 0) + (if (isBlueVerified.asKnown().isPresent) 1 else 0) + + (if (isProfileTranslatable.asKnown().isPresent) 1 else 0) + (if (isTranslator.asKnown().isPresent) 1 else 0) + (if (isVerified.asKnown().isPresent) 1 else 0) + (if (location.asKnown().isPresent) 1 else 0) + (if (mediaCount.asKnown().isPresent) 1 else 0) + + (if (parodyCommentaryFanLabel.asKnown().isPresent) 1 else 0) + (pinnedTweetIds.asKnown().getOrNull()?.size ?: 0) + (if (possiblySensitive.asKnown().isPresent) 1 else 0) + (profileBio.asKnown().getOrNull()?.validity() ?: 0) + (if (profileBannerUrl.asKnown().isPresent) 1 else 0) + + (if (profileDescriptionLanguage.asKnown().isPresent) 1 else 0) + + (if (profileImageShape.asKnown().isPresent) 1 else 0) + + (if (profileInterstitialType.asKnown().isPresent) 1 else 0) + (if (profilePicture.asKnown().isPresent) 1 else 0) + + (if (profileSortEnabled.asKnown().isPresent) 1 else 0) + + (if (profileTranslatorType.asKnown().isPresent) 1 else 0) + (if (protected_.asKnown().isPresent) 1 else 0) + (if (statusesCount.asKnown().isPresent) 1 else 0) + + (if (superFollowEligible.asKnown().isPresent) 1 else 0) + (if (unavailable.asKnown().isPresent) 1 else 0) + (if (unavailableReason.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + (if (verified.asKnown().isPresent) 1 else 0) + (if (verifiedType.asKnown().isPresent) 1 else 0) + - (if (viewerFollowedBy.asKnown().isPresent) 1 else 0) + - (if (viewerFollowing.asKnown().isPresent) 1 else 0) + (withheldInCountries.asKnown().getOrNull()?.size ?: 0) + /** Organization affiliation label shown on an X profile. */ + class AffiliatesHighlightedLabel + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val badgeUrl: JsonField, + private val description: JsonField, + private val url: JsonField, + private val urlType: JsonField, + private val userLabelDisplayType: JsonField, + private val userLabelType: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("badgeUrl") + @ExcludeMissing + badgeUrl: JsonField = JsonMissing.of(), + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("urlType") @ExcludeMissing urlType: JsonField = JsonMissing.of(), + @JsonProperty("userLabelDisplayType") + @ExcludeMissing + userLabelDisplayType: JsonField = JsonMissing.of(), + @JsonProperty("userLabelType") + @ExcludeMissing + userLabelType: JsonField = JsonMissing.of(), + ) : this( + badgeUrl, + description, + url, + urlType, + userLabelDisplayType, + userLabelType, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun badgeUrl(): Optional = badgeUrl.getOptional("badgeUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun urlType(): Optional = urlType.getOptional("urlType") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun userLabelDisplayType(): Optional = + userLabelDisplayType.getOptional("userLabelDisplayType") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun userLabelType(): Optional = userLabelType.getOptional("userLabelType") + + /** + * Returns the raw JSON value of [badgeUrl]. + * + * Unlike [badgeUrl], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("badgeUrl") @ExcludeMissing fun _badgeUrl(): JsonField = badgeUrl + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + /** + * Returns the raw JSON value of [urlType]. + * + * Unlike [urlType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("urlType") @ExcludeMissing fun _urlType(): JsonField = urlType + + /** + * Returns the raw JSON value of [userLabelDisplayType]. + * + * Unlike [userLabelDisplayType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("userLabelDisplayType") + @ExcludeMissing + fun _userLabelDisplayType(): JsonField = userLabelDisplayType + + /** + * Returns the raw JSON value of [userLabelType]. + * + * Unlike [userLabelType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("userLabelType") + @ExcludeMissing + fun _userLabelType(): JsonField = userLabelType + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [AffiliatesHighlightedLabel]. + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [AffiliatesHighlightedLabel]. */ + class Builder internal constructor() { + + private var badgeUrl: JsonField = JsonMissing.of() + private var description: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var urlType: JsonField = JsonMissing.of() + private var userLabelDisplayType: JsonField = JsonMissing.of() + private var userLabelType: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(affiliatesHighlightedLabel: AffiliatesHighlightedLabel) = apply { + badgeUrl = affiliatesHighlightedLabel.badgeUrl + description = affiliatesHighlightedLabel.description + url = affiliatesHighlightedLabel.url + urlType = affiliatesHighlightedLabel.urlType + userLabelDisplayType = affiliatesHighlightedLabel.userLabelDisplayType + userLabelType = affiliatesHighlightedLabel.userLabelType + additionalProperties = + affiliatesHighlightedLabel.additionalProperties.toMutableMap() + } + + fun badgeUrl(badgeUrl: String) = badgeUrl(JsonField.of(badgeUrl)) + + /** + * Sets [Builder.badgeUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.badgeUrl] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun badgeUrl(badgeUrl: JsonField) = apply { this.badgeUrl = badgeUrl } + + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun urlType(urlType: String) = urlType(JsonField.of(urlType)) + + /** + * Sets [Builder.urlType] to an arbitrary JSON value. + * + * You should usually call [Builder.urlType] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun urlType(urlType: JsonField) = apply { this.urlType = urlType } + + fun userLabelDisplayType(userLabelDisplayType: String) = + userLabelDisplayType(JsonField.of(userLabelDisplayType)) + + /** + * Sets [Builder.userLabelDisplayType] to an arbitrary JSON value. + * + * You should usually call [Builder.userLabelDisplayType] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun userLabelDisplayType(userLabelDisplayType: JsonField) = apply { + this.userLabelDisplayType = userLabelDisplayType + } + + fun userLabelType(userLabelType: String) = userLabelType(JsonField.of(userLabelType)) + + /** + * Sets [Builder.userLabelType] to an arbitrary JSON value. + * + * You should usually call [Builder.userLabelType] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun userLabelType(userLabelType: JsonField) = apply { + this.userLabelType = userLabelType + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [AffiliatesHighlightedLabel]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): AffiliatesHighlightedLabel = + AffiliatesHighlightedLabel( + badgeUrl, + description, + url, + urlType, + userLabelDisplayType, + userLabelType, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): AffiliatesHighlightedLabel = apply { + if (validated) { + return@apply + } + + badgeUrl() + description() + url() + urlType() + userLabelDisplayType() + userLabelType() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (badgeUrl.asKnown().isPresent) 1 else 0) + + (if (description.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + (if (urlType.asKnown().isPresent) 1 else 0) + + (if (userLabelDisplayType.asKnown().isPresent) 1 else 0) + + (if (userLabelType.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is AffiliatesHighlightedLabel && + badgeUrl == other.badgeUrl && + description == other.description && + url == other.url && + urlType == other.urlType && + userLabelDisplayType == other.userLabelDisplayType && + userLabelType == other.userLabelType && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + badgeUrl, + description, + url, + urlType, + userLabelDisplayType, + userLabelType, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "AffiliatesHighlightedLabel{badgeUrl=$badgeUrl, description=$description, url=$url, urlType=$urlType, userLabelDisplayType=$userLabelDisplayType, userLabelType=$userLabelType, additionalProperties=$additionalProperties}" + } + + /** Profile highlight availability and count metadata. */ + class HighlightsInfo + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val canHighlightTweets: JsonField, + private val highlightedTweets: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("canHighlightTweets") + @ExcludeMissing + canHighlightTweets: JsonField = JsonMissing.of(), + @JsonProperty("highlightedTweets") + @ExcludeMissing + highlightedTweets: JsonField = JsonMissing.of(), + ) : this(canHighlightTweets, highlightedTweets, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun canHighlightTweets(): Optional = + canHighlightTweets.getOptional("canHighlightTweets") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun highlightedTweets(): Optional = + highlightedTweets.getOptional("highlightedTweets") + + /** + * Returns the raw JSON value of [canHighlightTweets]. + * + * Unlike [canHighlightTweets], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("canHighlightTweets") + @ExcludeMissing + fun _canHighlightTweets(): JsonField = canHighlightTweets + + /** + * Returns the raw JSON value of [highlightedTweets]. + * + * Unlike [highlightedTweets], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("highlightedTweets") + @ExcludeMissing + fun _highlightedTweets(): JsonField = highlightedTweets + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [HighlightsInfo]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [HighlightsInfo]. */ + class Builder internal constructor() { + + private var canHighlightTweets: JsonField = JsonMissing.of() + private var highlightedTweets: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(highlightsInfo: HighlightsInfo) = apply { + canHighlightTweets = highlightsInfo.canHighlightTweets + highlightedTweets = highlightsInfo.highlightedTweets + additionalProperties = highlightsInfo.additionalProperties.toMutableMap() + } + + fun canHighlightTweets(canHighlightTweets: Boolean) = + canHighlightTweets(JsonField.of(canHighlightTweets)) + + /** + * Sets [Builder.canHighlightTweets] to an arbitrary JSON value. + * + * You should usually call [Builder.canHighlightTweets] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun canHighlightTweets(canHighlightTweets: JsonField) = apply { + this.canHighlightTweets = canHighlightTweets + } + + fun highlightedTweets(highlightedTweets: String) = + highlightedTweets(JsonField.of(highlightedTweets)) + + /** + * Sets [Builder.highlightedTweets] to an arbitrary JSON value. + * + * You should usually call [Builder.highlightedTweets] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun highlightedTweets(highlightedTweets: JsonField) = apply { + this.highlightedTweets = highlightedTweets + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [HighlightsInfo]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): HighlightsInfo = + HighlightsInfo( + canHighlightTweets, + highlightedTweets, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): HighlightsInfo = apply { + if (validated) { + return@apply + } + + canHighlightTweets() + highlightedTweets() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (canHighlightTweets.asKnown().isPresent) 1 else 0) + + (if (highlightedTweets.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is HighlightsInfo && + canHighlightTweets == other.canHighlightTweets && + highlightedTweets == other.highlightedTweets && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(canHighlightTweets, highlightedTweets, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "HighlightsInfo{canHighlightTweets=$canHighlightTweets, highlightedTweets=$highlightedTweets, additionalProperties=$additionalProperties}" + } + + /** Identity verification metadata displayed by X. */ + class IdentityVerification + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val description: JsonField, + private val isIdentityVerified: JsonField, + private val verifiedSinceMsec: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("description") + @ExcludeMissing + description: JsonField = JsonMissing.of(), + @JsonProperty("isIdentityVerified") + @ExcludeMissing + isIdentityVerified: JsonField = JsonMissing.of(), + @JsonProperty("verifiedSinceMsec") + @ExcludeMissing + verifiedSinceMsec: JsonField = JsonMissing.of(), + ) : this(description, isIdentityVerified, verifiedSinceMsec, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun description(): Optional = description.getOptional("description") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isIdentityVerified(): Optional = + isIdentityVerified.getOptional("isIdentityVerified") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun verifiedSinceMsec(): Optional = + verifiedSinceMsec.getOptional("verifiedSinceMsec") + + /** + * Returns the raw JSON value of [description]. + * + * Unlike [description], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("description") + @ExcludeMissing + fun _description(): JsonField = description + + /** + * Returns the raw JSON value of [isIdentityVerified]. + * + * Unlike [isIdentityVerified], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("isIdentityVerified") + @ExcludeMissing + fun _isIdentityVerified(): JsonField = isIdentityVerified + + /** + * Returns the raw JSON value of [verifiedSinceMsec]. + * + * Unlike [verifiedSinceMsec], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("verifiedSinceMsec") + @ExcludeMissing + fun _verifiedSinceMsec(): JsonField = verifiedSinceMsec + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [IdentityVerification]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [IdentityVerification]. */ + class Builder internal constructor() { + + private var description: JsonField = JsonMissing.of() + private var isIdentityVerified: JsonField = JsonMissing.of() + private var verifiedSinceMsec: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(identityVerification: IdentityVerification) = apply { + description = identityVerification.description + isIdentityVerified = identityVerification.isIdentityVerified + verifiedSinceMsec = identityVerification.verifiedSinceMsec + additionalProperties = identityVerification.additionalProperties.toMutableMap() + } + + fun description(description: String) = description(JsonField.of(description)) + + /** + * Sets [Builder.description] to an arbitrary JSON value. + * + * You should usually call [Builder.description] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun description(description: JsonField) = apply { + this.description = description + } + + fun isIdentityVerified(isIdentityVerified: Boolean) = + isIdentityVerified(JsonField.of(isIdentityVerified)) + + /** + * Sets [Builder.isIdentityVerified] to an arbitrary JSON value. + * + * You should usually call [Builder.isIdentityVerified] with a well-typed [Boolean] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun isIdentityVerified(isIdentityVerified: JsonField) = apply { + this.isIdentityVerified = isIdentityVerified + } + + fun verifiedSinceMsec(verifiedSinceMsec: String) = + verifiedSinceMsec(JsonField.of(verifiedSinceMsec)) + + /** + * Sets [Builder.verifiedSinceMsec] to an arbitrary JSON value. + * + * You should usually call [Builder.verifiedSinceMsec] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun verifiedSinceMsec(verifiedSinceMsec: JsonField) = apply { + this.verifiedSinceMsec = verifiedSinceMsec + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [IdentityVerification]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): IdentityVerification = + IdentityVerification( + description, + isIdentityVerified, + verifiedSinceMsec, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): IdentityVerification = apply { + if (validated) { + return@apply + } + + description() + isIdentityVerified() + verifiedSinceMsec() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (description.asKnown().isPresent) 1 else 0) + + (if (isIdentityVerified.asKnown().isPresent) 1 else 0) + + (if (verifiedSinceMsec.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is IdentityVerification && + description == other.description && + isIdentityVerified == other.isIdentityVerified && + verifiedSinceMsec == other.verifiedSinceMsec && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(description, isIdentityVerified, verifiedSinceMsec, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "IdentityVerification{description=$description, isIdentityVerified=$isIdentityVerified, verifiedSinceMsec=$verifiedSinceMsec, additionalProperties=$additionalProperties}" + } + /** Structured profile bio with entity annotations */ class ProfileBio @JsonCreator @@ -1524,36 +2843,48 @@ private constructor( id == other.id && name == other.name && username == other.username && + affiliatesHighlightedLabel == other.affiliatesHighlightedLabel && automatedBy == other.automatedBy && - canDm == other.canDm && + businessAccountAffiliatesCount == other.businessAccountAffiliatesCount && communityRole == other.communityRole && coverPicture == other.coverPicture && createdAt == other.createdAt && + creatorSubscriptionsCount == other.creatorSubscriptionsCount && description == other.description && favouritesCount == other.favouritesCount && followers == other.followers && following == other.following && hasCustomTimelines == other.hasCustomTimelines && + hasGraduatedAccess == other.hasGraduatedAccess && + hasHiddenSubscriptionsOnProfile == other.hasHiddenSubscriptionsOnProfile && + highlightsInfo == other.highlightsInfo && + identityVerification == other.identityVerification && isAutomated == other.isAutomated && isBlueVerified == other.isBlueVerified && + isProfileTranslatable == other.isProfileTranslatable && isTranslator == other.isTranslator && isVerified == other.isVerified && location == other.location && mediaCount == other.mediaCount && + parodyCommentaryFanLabel == other.parodyCommentaryFanLabel && pinnedTweetIds == other.pinnedTweetIds && possiblySensitive == other.possiblySensitive && profileBio == other.profileBio && profileBannerUrl == other.profileBannerUrl && + profileDescriptionLanguage == other.profileDescriptionLanguage && + profileImageShape == other.profileImageShape && + profileInterstitialType == other.profileInterstitialType && profilePicture == other.profilePicture && + profileSortEnabled == other.profileSortEnabled && + profileTranslatorType == other.profileTranslatorType && protected_ == other.protected_ && statusesCount == other.statusesCount && + superFollowEligible == other.superFollowEligible && unavailable == other.unavailable && unavailableReason == other.unavailableReason && url == other.url && verified == other.verified && verifiedType == other.verifiedType && - viewerFollowedBy == other.viewerFollowedBy && - viewerFollowing == other.viewerFollowing && withheldInCountries == other.withheldInCountries && additionalProperties == other.additionalProperties } @@ -1563,36 +2894,48 @@ private constructor( id, name, username, + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, pinnedTweetIds, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, withheldInCountries, additionalProperties, ) @@ -1601,5 +2944,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "UserProfile{id=$id, name=$name, username=$username, automatedBy=$automatedBy, canDm=$canDm, communityRole=$communityRole, coverPicture=$coverPicture, createdAt=$createdAt, description=$description, favouritesCount=$favouritesCount, followers=$followers, following=$following, hasCustomTimelines=$hasCustomTimelines, isAutomated=$isAutomated, isBlueVerified=$isBlueVerified, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, pinnedTweetIds=$pinnedTweetIds, possiblySensitive=$possiblySensitive, profileBio=$profileBio, profileBannerUrl=$profileBannerUrl, profilePicture=$profilePicture, protected_=$protected_, statusesCount=$statusesCount, unavailable=$unavailable, unavailableReason=$unavailableReason, url=$url, verified=$verified, verifiedType=$verifiedType, viewerFollowedBy=$viewerFollowedBy, viewerFollowing=$viewerFollowing, withheldInCountries=$withheldInCountries, additionalProperties=$additionalProperties}" + "UserProfile{id=$id, name=$name, username=$username, affiliatesHighlightedLabel=$affiliatesHighlightedLabel, automatedBy=$automatedBy, businessAccountAffiliatesCount=$businessAccountAffiliatesCount, communityRole=$communityRole, coverPicture=$coverPicture, createdAt=$createdAt, creatorSubscriptionsCount=$creatorSubscriptionsCount, description=$description, favouritesCount=$favouritesCount, followers=$followers, following=$following, hasCustomTimelines=$hasCustomTimelines, hasGraduatedAccess=$hasGraduatedAccess, hasHiddenSubscriptionsOnProfile=$hasHiddenSubscriptionsOnProfile, highlightsInfo=$highlightsInfo, identityVerification=$identityVerification, isAutomated=$isAutomated, isBlueVerified=$isBlueVerified, isProfileTranslatable=$isProfileTranslatable, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, parodyCommentaryFanLabel=$parodyCommentaryFanLabel, pinnedTweetIds=$pinnedTweetIds, possiblySensitive=$possiblySensitive, profileBio=$profileBio, profileBannerUrl=$profileBannerUrl, profileDescriptionLanguage=$profileDescriptionLanguage, profileImageShape=$profileImageShape, profileInterstitialType=$profileInterstitialType, profilePicture=$profilePicture, profileSortEnabled=$profileSortEnabled, profileTranslatorType=$profileTranslatorType, protected_=$protected_, statusesCount=$statusesCount, superFollowEligible=$superFollowEligible, unavailable=$unavailable, unavailableReason=$unavailableReason, url=$url, verified=$verified, verifiedType=$verifiedType, withheldInCountries=$withheldInCountries, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponse.kt index 7c1a577..4d15ec6 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponse.kt @@ -10,17 +10,18 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing import com.x_twitter_scraper.api.core.JsonField import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.checkKnown +import com.x_twitter_scraper.api.core.checkRequired import com.x_twitter_scraper.api.core.toImmutable import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException import java.time.OffsetDateTime import java.util.Collections import java.util.Objects -import java.util.Optional import kotlin.jvm.optionals.getOrNull class TicketListResponse @@ -36,10 +37,10 @@ private constructor( ) : this(tickets, mutableMapOf()) /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun tickets(): Optional> = tickets.getOptional("tickets") + fun tickets(): List = tickets.getRequired("tickets") /** * Returns the raw JSON value of [tickets]. @@ -62,7 +63,14 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [TicketListResponse]. */ + /** + * Returns a mutable builder for constructing an instance of [TicketListResponse]. + * + * The following fields are required: + * ```java + * .tickets() + * ``` + */ @JvmStatic fun builder() = Builder() } @@ -126,10 +134,17 @@ private constructor( * Returns an immutable instance of [TicketListResponse]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .tickets() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): TicketListResponse = TicketListResponse( - (tickets ?: JsonMissing.of()).map { it.toImmutable() }, + checkRequired("tickets", tickets).map { it.toImmutable() }, additionalProperties.toMutableMap(), ) } @@ -149,7 +164,7 @@ private constructor( return@apply } - tickets().ifPresent { it.forEach { it.validate() } } + tickets().forEach { it.validate() } validated = true } @@ -175,7 +190,7 @@ private constructor( private val createdAt: JsonField, private val messageCount: JsonField, private val publicId: JsonField, - private val status: JsonField, + private val status: JsonField, private val subject: JsonField, private val updatedAt: JsonField, private val additionalProperties: MutableMap, @@ -192,7 +207,7 @@ private constructor( @JsonProperty("publicId") @ExcludeMissing publicId: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), @JsonProperty("subject") @ExcludeMissing subject: JsonField = JsonMissing.of(), @JsonProperty("updatedAt") @ExcludeMissing @@ -200,40 +215,46 @@ private constructor( ) : this(createdAt, messageCount, publicId, status, subject, updatedAt, mutableMapOf()) /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun createdAt(): Optional = createdAt.getOptional("createdAt") + fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun messageCount(): Optional = messageCount.getOptional("messageCount") + fun messageCount(): Long = messageCount.getRequired("messageCount") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun publicId(): Optional = publicId.getOptional("publicId") + fun publicId(): String = publicId.getRequired("publicId") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun status(): Optional = status.getOptional("status") + fun status(): Status = status.getRequired("status") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun subject(): Optional = subject.getOptional("subject") + fun subject(): String = subject.getRequired("subject") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun updatedAt(): Optional = updatedAt.getOptional("updatedAt") + fun updatedAt(): OffsetDateTime = updatedAt.getRequired("updatedAt") /** * Returns the raw JSON value of [createdAt]. @@ -266,7 +287,7 @@ private constructor( * * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status /** * Returns the raw JSON value of [subject]. @@ -298,19 +319,31 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Ticket]. */ + /** + * Returns a mutable builder for constructing an instance of [Ticket]. + * + * The following fields are required: + * ```java + * .createdAt() + * .messageCount() + * .publicId() + * .status() + * .subject() + * .updatedAt() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [Ticket]. */ class Builder internal constructor() { - private var createdAt: JsonField = JsonMissing.of() - private var messageCount: JsonField = JsonMissing.of() - private var publicId: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() - private var subject: JsonField = JsonMissing.of() - private var updatedAt: JsonField = JsonMissing.of() + private var createdAt: JsonField? = null + private var messageCount: JsonField? = null + private var publicId: JsonField? = null + private var status: JsonField? = null + private var subject: JsonField? = null + private var updatedAt: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -361,16 +394,16 @@ private constructor( */ fun publicId(publicId: JsonField) = apply { this.publicId = publicId } - fun status(status: String) = status(JsonField.of(status)) + fun status(status: Status) = status(JsonField.of(status)) /** * Sets [Builder.status] to an arbitrary JSON value. * - * You should usually call [Builder.status] with a well-typed [String] value instead. + * You should usually call [Builder.status] with a well-typed [Status] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonField) = apply { this.status = status } fun subject(subject: String) = subject(JsonField.of(subject)) @@ -419,15 +452,27 @@ private constructor( * Returns an immutable instance of [Ticket]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .createdAt() + * .messageCount() + * .publicId() + * .status() + * .subject() + * .updatedAt() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): Ticket = Ticket( - createdAt, - messageCount, - publicId, - status, - subject, - updatedAt, + checkRequired("createdAt", createdAt), + checkRequired("messageCount", messageCount), + checkRequired("publicId", publicId), + checkRequired("status", status), + checkRequired("subject", subject), + checkRequired("updatedAt", updatedAt), additionalProperties.toMutableMap(), ) } @@ -451,7 +496,7 @@ private constructor( createdAt() messageCount() publicId() - status() + status().validate() subject() updatedAt() validated = true @@ -476,10 +521,161 @@ private constructor( (if (createdAt.asKnown().isPresent) 1 else 0) + (if (messageCount.asKnown().isPresent) 1 else 0) + (if (publicId.asKnown().isPresent) 1 else 0) + - (if (status.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + (if (subject.asKnown().isPresent) 1 else 0) + (if (updatedAt.asKnown().isPresent) 1 else 0) + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPEN = of("open") + + @JvmField val IN_PROGRESS = of("in_progress") + + @JvmField val RESOLVED = of("resolved") + + @JvmField val CLOSED = of("closed") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + OPEN, + IN_PROGRESS, + RESOLVED, + CLOSED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPEN, + IN_PROGRESS, + RESOLVED, + CLOSED, + /** + * An enum member indicating that [Status] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPEN -> Value.OPEN + IN_PROGRESS -> Value.IN_PROGRESS + RESOLVED -> Value.RESOLVED + CLOSED -> Value.CLOSED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + OPEN -> Known.OPEN + IN_PROGRESS -> Known.IN_PROGRESS + RESOLVED -> Known.RESOLVED + CLOSED -> Known.CLOSED + else -> throw XTwitterScraperInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponse.kt index 0f3c720..2ba16ff 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponse.kt @@ -22,7 +22,6 @@ import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException import java.time.OffsetDateTime import java.util.Collections import java.util.Objects -import java.util.Optional import kotlin.jvm.optionals.getOrNull class TicketRetrieveResponse @@ -31,7 +30,7 @@ private constructor( private val createdAt: JsonField, private val messages: JsonField>, private val publicId: JsonField, - private val status: JsonField, + private val status: JsonField, private val subject: JsonField, private val updatedAt: JsonField, private val additionalProperties: MutableMap, @@ -46,7 +45,7 @@ private constructor( @ExcludeMissing messages: JsonField> = JsonMissing.of(), @JsonProperty("publicId") @ExcludeMissing publicId: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), @JsonProperty("subject") @ExcludeMissing subject: JsonField = JsonMissing.of(), @JsonProperty("updatedAt") @ExcludeMissing @@ -54,40 +53,40 @@ private constructor( ) : this(createdAt, messages, publicId, status, subject, updatedAt, mutableMapOf()) /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun createdAt(): Optional = createdAt.getOptional("createdAt") + fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun messages(): Optional> = messages.getOptional("messages") + fun messages(): List = messages.getRequired("messages") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun publicId(): Optional = publicId.getOptional("publicId") + fun publicId(): String = publicId.getRequired("publicId") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun status(): Optional = status.getOptional("status") + fun status(): Status = status.getRequired("status") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun subject(): Optional = subject.getOptional("subject") + fun subject(): String = subject.getRequired("subject") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun updatedAt(): Optional = updatedAt.getOptional("updatedAt") + fun updatedAt(): OffsetDateTime = updatedAt.getRequired("updatedAt") /** * Returns the raw JSON value of [createdAt]. @@ -117,7 +116,7 @@ private constructor( * * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status /** * Returns the raw JSON value of [subject]. @@ -149,19 +148,31 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [TicketRetrieveResponse]. */ + /** + * Returns a mutable builder for constructing an instance of [TicketRetrieveResponse]. + * + * The following fields are required: + * ```java + * .createdAt() + * .messages() + * .publicId() + * .status() + * .subject() + * .updatedAt() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [TicketRetrieveResponse]. */ class Builder internal constructor() { - private var createdAt: JsonField = JsonMissing.of() + private var createdAt: JsonField? = null private var messages: JsonField>? = null - private var publicId: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() - private var subject: JsonField = JsonMissing.of() - private var updatedAt: JsonField = JsonMissing.of() + private var publicId: JsonField? = null + private var status: JsonField? = null + private var subject: JsonField? = null + private var updatedAt: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -221,15 +232,15 @@ private constructor( */ fun publicId(publicId: JsonField) = apply { this.publicId = publicId } - fun status(status: String) = status(JsonField.of(status)) + fun status(status: Status) = status(JsonField.of(status)) /** * Sets [Builder.status] to an arbitrary JSON value. * - * You should usually call [Builder.status] with a well-typed [String] value instead. This + * You should usually call [Builder.status] with a well-typed [Status] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonField) = apply { this.status = status } fun subject(subject: String) = subject(JsonField.of(subject)) @@ -275,15 +286,27 @@ private constructor( * Returns an immutable instance of [TicketRetrieveResponse]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .createdAt() + * .messages() + * .publicId() + * .status() + * .subject() + * .updatedAt() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): TicketRetrieveResponse = TicketRetrieveResponse( - createdAt, - (messages ?: JsonMissing.of()).map { it.toImmutable() }, - publicId, - status, - subject, - updatedAt, + checkRequired("createdAt", createdAt), + checkRequired("messages", messages).map { it.toImmutable() }, + checkRequired("publicId", publicId), + checkRequired("status", status), + checkRequired("subject", subject), + checkRequired("updatedAt", updatedAt), additionalProperties.toMutableMap(), ) } @@ -304,9 +327,9 @@ private constructor( } createdAt() - messages().ifPresent { it.forEach { it.validate() } } + messages().forEach { it.validate() } publicId() - status() + status().validate() subject() updatedAt() validated = true @@ -330,7 +353,7 @@ private constructor( (if (createdAt.asKnown().isPresent) 1 else 0) + (messages.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + (if (publicId.asKnown().isPresent) 1 else 0) + - (if (status.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + (if (subject.asKnown().isPresent) 1 else 0) + (if (updatedAt.asKnown().isPresent) 1 else 0) @@ -340,7 +363,7 @@ private constructor( private val attachments: JsonField>, private val body: JsonField, private val createdAt: JsonField, - private val sender: JsonField, + private val sender: JsonField, private val additionalProperties: MutableMap, ) { @@ -353,32 +376,36 @@ private constructor( @JsonProperty("createdAt") @ExcludeMissing createdAt: JsonField = JsonMissing.of(), - @JsonProperty("sender") @ExcludeMissing sender: JsonField = JsonMissing.of(), + @JsonProperty("sender") @ExcludeMissing sender: JsonField = JsonMissing.of(), ) : this(attachments, body, createdAt, sender, mutableMapOf()) /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun attachments(): Optional> = attachments.getOptional("attachments") + fun attachments(): List = attachments.getRequired("attachments") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun body(): Optional = body.getOptional("body") + fun body(): String = body.getRequired("body") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun createdAt(): Optional = createdAt.getOptional("createdAt") + fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). */ - fun sender(): Optional = sender.getOptional("sender") + fun sender(): Sender = sender.getRequired("sender") /** * Returns the raw JSON value of [attachments]. @@ -410,7 +437,7 @@ private constructor( * * Unlike [sender], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("sender") @ExcludeMissing fun _sender(): JsonField = sender + @JsonProperty("sender") @ExcludeMissing fun _sender(): JsonField = sender @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -426,7 +453,17 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [Message]. */ + /** + * Returns a mutable builder for constructing an instance of [Message]. + * + * The following fields are required: + * ```java + * .attachments() + * .body() + * .createdAt() + * .sender() + * ``` + */ @JvmStatic fun builder() = Builder() } @@ -434,9 +471,9 @@ private constructor( class Builder internal constructor() { private var attachments: JsonField>? = null - private var body: JsonField = JsonMissing.of() - private var createdAt: JsonField = JsonMissing.of() - private var sender: JsonField = JsonMissing.of() + private var body: JsonField? = null + private var createdAt: JsonField? = null + private var sender: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -497,16 +534,16 @@ private constructor( this.createdAt = createdAt } - fun sender(sender: String) = sender(JsonField.of(sender)) + fun sender(sender: Sender) = sender(JsonField.of(sender)) /** * Sets [Builder.sender] to an arbitrary JSON value. * - * You should usually call [Builder.sender] with a well-typed [String] value instead. + * You should usually call [Builder.sender] with a well-typed [Sender] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun sender(sender: JsonField) = apply { this.sender = sender } + fun sender(sender: JsonField) = apply { this.sender = sender } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -531,13 +568,23 @@ private constructor( * Returns an immutable instance of [Message]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .attachments() + * .body() + * .createdAt() + * .sender() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): Message = Message( - (attachments ?: JsonMissing.of()).map { it.toImmutable() }, - body, - createdAt, - sender, + checkRequired("attachments", attachments).map { it.toImmutable() }, + checkRequired("body", body), + checkRequired("createdAt", createdAt), + checkRequired("sender", sender), additionalProperties.toMutableMap(), ) } @@ -558,10 +605,10 @@ private constructor( return@apply } - attachments().ifPresent { it.forEach { it.validate() } } + attachments().forEach { it.validate() } body() createdAt() - sender() + sender().validate() validated = true } @@ -584,7 +631,7 @@ private constructor( (attachments.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + (if (body.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + - (if (sender.asKnown().isPresent) 1 else 0) + (sender.asKnown().getOrNull()?.validity() ?: 0) /** Downloadable image or video attached to a support message. */ class Attachment @@ -1470,6 +1517,151 @@ private constructor( "Attachment{contentType=$contentType, filename=$filename, kind=$kind, publicId=$publicId, sizeBytes=$sizeBytes, status=$status, url=$url, additionalProperties=$additionalProperties}" } + class Sender @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val USER = of("user") + + @JvmField val SUPPORT = of("support") + + @JvmField val SYSTEM = of("system") + + @JvmStatic fun of(value: String) = Sender(JsonField.of(value)) + } + + /** An enum containing [Sender]'s known values. */ + enum class Known { + USER, + SUPPORT, + SYSTEM, + } + + /** + * An enum containing [Sender]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Sender] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + USER, + SUPPORT, + SYSTEM, + /** + * An enum member indicating that [Sender] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + USER -> Value.USER + SUPPORT -> Value.SUPPORT + SYSTEM -> Value.SYSTEM + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + USER -> Known.USER + SUPPORT -> Known.SUPPORT + SYSTEM -> Known.SYSTEM + else -> throw XTwitterScraperInvalidDataException("Unknown Sender: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Sender = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Sender && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true @@ -1493,6 +1685,154 @@ private constructor( "Message{attachments=$attachments, body=$body, createdAt=$createdAt, sender=$sender, additionalProperties=$additionalProperties}" } + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPEN = of("open") + + @JvmField val IN_PROGRESS = of("in_progress") + + @JvmField val RESOLVED = of("resolved") + + @JvmField val CLOSED = of("closed") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + OPEN, + IN_PROGRESS, + RESOLVED, + CLOSED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPEN, + IN_PROGRESS, + RESOLVED, + CLOSED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPEN -> Value.OPEN + IN_PROGRESS -> Value.IN_PROGRESS + RESOLVED -> Value.RESOLVED + CLOSED -> Value.CLOSED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + OPEN -> Known.OPEN + IN_PROGRESS -> Known.IN_PROGRESS + RESOLVED -> Known.RESOLVED + CLOSED -> Known.CLOSED + else -> throw XTwitterScraperInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + override fun equals(other: Any?): Boolean { if (this === other) { return true diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponse.kt index 979b89f..bc2f806 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponse.kt @@ -10,40 +10,42 @@ import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator import com.fasterxml.jackson.annotation.JsonProperty +import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing import com.x_twitter_scraper.api.core.JsonField import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.checkRequired import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException import java.util.Collections import java.util.Objects -import java.util.Optional +import kotlin.jvm.optionals.getOrNull class TicketUpdateResponse @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val publicId: JsonField, - private val status: JsonField, + private val status: JsonField, private val additionalProperties: MutableMap, ) { @JsonCreator private constructor( @JsonProperty("publicId") @ExcludeMissing publicId: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), ) : this(publicId, status, mutableMapOf()) /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun publicId(): Optional = publicId.getOptional("publicId") + fun publicId(): String = publicId.getRequired("publicId") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if - * the server responded with an unexpected value). + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). */ - fun status(): Optional = status.getOptional("status") + fun status(): Status = status.getRequired("status") /** * Returns the raw JSON value of [publicId]. @@ -57,7 +59,7 @@ private constructor( * * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status + @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { @@ -73,15 +75,23 @@ private constructor( companion object { - /** Returns a mutable builder for constructing an instance of [TicketUpdateResponse]. */ + /** + * Returns a mutable builder for constructing an instance of [TicketUpdateResponse]. + * + * The following fields are required: + * ```java + * .publicId() + * .status() + * ``` + */ @JvmStatic fun builder() = Builder() } /** A builder for [TicketUpdateResponse]. */ class Builder internal constructor() { - private var publicId: JsonField = JsonMissing.of() - private var status: JsonField = JsonMissing.of() + private var publicId: JsonField? = null + private var status: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -101,15 +111,15 @@ private constructor( */ fun publicId(publicId: JsonField) = apply { this.publicId = publicId } - fun status(status: String) = status(JsonField.of(status)) + fun status(status: Status) = status(JsonField.of(status)) /** * Sets [Builder.status] to an arbitrary JSON value. * - * You should usually call [Builder.status] with a well-typed [String] value instead. This + * You should usually call [Builder.status] with a well-typed [Status] value instead. This * method is primarily for setting the field to an undocumented or not yet supported value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonField) = apply { this.status = status } fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() @@ -134,9 +144,21 @@ private constructor( * Returns an immutable instance of [TicketUpdateResponse]. * * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .publicId() + * .status() + * ``` + * + * @throws IllegalStateException if any required field is unset. */ fun build(): TicketUpdateResponse = - TicketUpdateResponse(publicId, status, additionalProperties.toMutableMap()) + TicketUpdateResponse( + checkRequired("publicId", publicId), + checkRequired("status", status), + additionalProperties.toMutableMap(), + ) } private var validated: Boolean = false @@ -155,7 +177,7 @@ private constructor( } publicId() - status() + status().validate() validated = true } @@ -174,7 +196,150 @@ private constructor( */ @JvmSynthetic internal fun validity(): Int = - (if (publicId.asKnown().isPresent) 1 else 0) + (if (status.asKnown().isPresent) 1 else 0) + (if (publicId.asKnown().isPresent) 1 else 0) + + (status.asKnown().getOrNull()?.validity() ?: 0) + + class Status @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val OPEN = of("open") + + @JvmField val RESOLVED = of("resolved") + + @JvmField val CLOSED = of("closed") + + @JvmStatic fun of(value: String) = Status(JsonField.of(value)) + } + + /** An enum containing [Status]'s known values. */ + enum class Known { + OPEN, + RESOLVED, + CLOSED, + } + + /** + * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Status] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + OPEN, + RESOLVED, + CLOSED, + /** An enum member indicating that [Status] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + OPEN -> Value.OPEN + RESOLVED -> Value.RESOLVED + CLOSED -> Value.CLOSED + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + OPEN -> Known.OPEN + RESOLVED -> Known.RESOLVED + CLOSED -> Known.CLOSED + else -> throw XTwitterScraperInvalidDataException("Unknown Status: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Status = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Status && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } override fun equals(other: Any?): Boolean { if (this === other) { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponse.kt index 5ab77cb..f5d245b 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponse.kt @@ -253,8 +253,11 @@ private constructor( private constructor( private val name: JsonField, private val description: JsonField, + private val promotedContent: JsonField, private val query: JsonField, private val rank: JsonField, + private val tweetVolume: JsonField, + private val url: JsonField, private val additionalProperties: MutableMap, ) { @@ -264,9 +267,16 @@ private constructor( @JsonProperty("description") @ExcludeMissing description: JsonField = JsonMissing.of(), + @JsonProperty("promotedContent") + @ExcludeMissing + promotedContent: JsonField = JsonMissing.of(), @JsonProperty("query") @ExcludeMissing query: JsonField = JsonMissing.of(), @JsonProperty("rank") @ExcludeMissing rank: JsonField = JsonMissing.of(), - ) : this(name, description, query, rank, mutableMapOf()) + @JsonProperty("tweetVolume") + @ExcludeMissing + tweetVolume: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(name, description, promotedContent, query, rank, tweetVolume, url, mutableMapOf()) /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or @@ -281,6 +291,14 @@ private constructor( */ fun description(): Optional = description.getOptional("description") + /** + * Promotion identifier from X. Null for organic trends. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun promotedContent(): Optional = promotedContent.getOptional("promotedContent") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). @@ -293,6 +311,22 @@ private constructor( */ fun rank(): Optional = rank.getOptional("rank") + /** + * Approximate public post volume when X supplies it. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun tweetVolume(): Optional = tweetVolume.getOptional("tweetVolume") + + /** + * X search URL for the trend. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + /** * Returns the raw JSON value of [name]. * @@ -309,6 +343,16 @@ private constructor( @ExcludeMissing fun _description(): JsonField = description + /** + * Returns the raw JSON value of [promotedContent]. + * + * Unlike [promotedContent], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("promotedContent") + @ExcludeMissing + fun _promotedContent(): JsonField = promotedContent + /** * Returns the raw JSON value of [query]. * @@ -323,6 +367,22 @@ private constructor( */ @JsonProperty("rank") @ExcludeMissing fun _rank(): JsonField = rank + /** + * Returns the raw JSON value of [tweetVolume]. + * + * Unlike [tweetVolume], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tweetVolume") + @ExcludeMissing + fun _tweetVolume(): JsonField = tweetVolume + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -353,16 +413,22 @@ private constructor( private var name: JsonField? = null private var description: JsonField = JsonMissing.of() + private var promotedContent: JsonField = JsonMissing.of() private var query: JsonField = JsonMissing.of() private var rank: JsonField = JsonMissing.of() + private var tweetVolume: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(trend: Trend) = apply { name = trend.name description = trend.description + promotedContent = trend.promotedContent query = trend.query rank = trend.rank + tweetVolume = trend.tweetVolume + url = trend.url additionalProperties = trend.additionalProperties.toMutableMap() } @@ -390,6 +456,25 @@ private constructor( this.description = description } + /** Promotion identifier from X. Null for organic trends. */ + fun promotedContent(promotedContent: String?) = + promotedContent(JsonField.ofNullable(promotedContent)) + + /** Alias for calling [Builder.promotedContent] with `promotedContent.orElse(null)`. */ + fun promotedContent(promotedContent: Optional) = + promotedContent(promotedContent.getOrNull()) + + /** + * Sets [Builder.promotedContent] to an arbitrary JSON value. + * + * You should usually call [Builder.promotedContent] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promotedContent(promotedContent: JsonField) = apply { + this.promotedContent = promotedContent + } + fun query(query: String) = query(JsonField.of(query)) /** @@ -412,6 +497,40 @@ private constructor( */ fun rank(rank: JsonField) = apply { this.rank = rank } + /** Approximate public post volume when X supplies it. */ + fun tweetVolume(tweetVolume: Long?) = tweetVolume(JsonField.ofNullable(tweetVolume)) + + /** + * Alias for [Builder.tweetVolume]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tweetVolume(tweetVolume: Long) = tweetVolume(tweetVolume as Long?) + + /** Alias for calling [Builder.tweetVolume] with `tweetVolume.orElse(null)`. */ + fun tweetVolume(tweetVolume: Optional) = tweetVolume(tweetVolume.getOrNull()) + + /** + * Sets [Builder.tweetVolume] to an arbitrary JSON value. + * + * You should usually call [Builder.tweetVolume] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tweetVolume(tweetVolume: JsonField) = apply { this.tweetVolume = tweetVolume } + + /** X search URL for the trend. */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -447,8 +566,11 @@ private constructor( Trend( checkRequired("name", name), description, + promotedContent, query, rank, + tweetVolume, + url, additionalProperties.toMutableMap(), ) } @@ -471,8 +593,11 @@ private constructor( name() description() + promotedContent() query() rank() + tweetVolume() + url() validated = true } @@ -494,8 +619,11 @@ private constructor( internal fun validity(): Int = (if (name.asKnown().isPresent) 1 else 0) + (if (description.asKnown().isPresent) 1 else 0) + + (if (promotedContent.asKnown().isPresent) 1 else 0) + (if (query.asKnown().isPresent) 1 else 0) + - (if (rank.asKnown().isPresent) 1 else 0) + (if (rank.asKnown().isPresent) 1 else 0) + + (if (tweetVolume.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -505,19 +633,31 @@ private constructor( return other is Trend && name == other.name && description == other.description && + promotedContent == other.promotedContent && query == other.query && rank == other.rank && + tweetVolume == other.tweetVolume && + url == other.url && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(name, description, query, rank, additionalProperties) + Objects.hash( + name, + description, + promotedContent, + query, + rank, + tweetVolume, + url, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "Trend{name=$name, description=$description, query=$query, rank=$rank, additionalProperties=$additionalProperties}" + "Trend{name=$name, description=$description, promotedContent=$promotedContent, query=$query, rank=$rank, tweetVolume=$tweetVolume, url=$url, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponse.kt index 074b937..16e0b37 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponse.kt @@ -1358,7 +1358,6 @@ private constructor( private val id: JsonField, private val name: JsonField, private val username: JsonField, - private val canDm: JsonField, private val createdAt: JsonField, private val description: JsonField, private val favouritesCount: JsonField, @@ -1384,7 +1383,6 @@ private constructor( @JsonProperty("username") @ExcludeMissing username: JsonField = JsonMissing.of(), - @JsonProperty("canDm") @ExcludeMissing canDm: JsonField = JsonMissing.of(), @JsonProperty("createdAt") @ExcludeMissing createdAt: JsonField = JsonMissing.of(), @@ -1432,7 +1430,6 @@ private constructor( id, name, username, - canDm, createdAt, description, favouritesCount, @@ -1472,12 +1469,6 @@ private constructor( */ fun username(): String = username.getRequired("username") - /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun canDm(): Optional = canDm.getOptional("canDm") - /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). @@ -1589,13 +1580,6 @@ private constructor( */ @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username - /** - * Returns the raw JSON value of [canDm]. - * - * Unlike [canDm], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("canDm") @ExcludeMissing fun _canDm(): JsonField = canDm - /** * Returns the raw JSON value of [createdAt]. * @@ -1764,7 +1748,6 @@ private constructor( private var id: JsonField? = null private var name: JsonField? = null private var username: JsonField? = null - private var canDm: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() private var description: JsonField = JsonMissing.of() private var favouritesCount: JsonField = JsonMissing.of() @@ -1787,7 +1770,6 @@ private constructor( id = author.id name = author.name username = author.username - canDm = author.canDm createdAt = author.createdAt description = author.description favouritesCount = author.favouritesCount @@ -1839,17 +1821,6 @@ private constructor( */ fun username(username: JsonField) = apply { this.username = username } - fun canDm(canDm: Boolean) = canDm(JsonField.of(canDm)) - - /** - * Sets [Builder.canDm] to an arbitrary JSON value. - * - * You should usually call [Builder.canDm] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun canDm(canDm: JsonField) = apply { this.canDm = canDm } - fun createdAt(createdAt: String) = createdAt(JsonField.of(createdAt)) /** @@ -2075,7 +2046,6 @@ private constructor( checkRequired("id", id), checkRequired("name", name), checkRequired("username", username), - canDm, createdAt, description, favouritesCount, @@ -2114,7 +2084,6 @@ private constructor( id() name() username() - canDm() createdAt() description() favouritesCount() @@ -2152,7 +2121,6 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + (if (username.asKnown().isPresent) 1 else 0) + - (if (canDm.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (if (description.asKnown().isPresent) 1 else 0) + (if (favouritesCount.asKnown().isPresent) 1 else 0) + @@ -2178,7 +2146,6 @@ private constructor( id == other.id && name == other.name && username == other.username && - canDm == other.canDm && createdAt == other.createdAt && description == other.description && favouritesCount == other.favouritesCount && @@ -2202,7 +2169,6 @@ private constructor( id, name, username, - canDm, createdAt, description, favouritesCount, @@ -2225,7 +2191,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Author{id=$id, name=$name, username=$username, canDm=$canDm, createdAt=$createdAt, description=$description, favouritesCount=$favouritesCount, followersCount=$followersCount, followingCount=$followingCount, isBlueVerified=$isBlueVerified, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, profileBannerUrl=$profileBannerUrl, profilePicture=$profilePicture, protected_=$protected_, statusesCount=$statusesCount, url=$url, additionalProperties=$additionalProperties}" + "Author{id=$id, name=$name, username=$username, createdAt=$createdAt, description=$description, favouritesCount=$favouritesCount, followersCount=$followersCount, followingCount=$followingCount, isBlueVerified=$isBlueVerified, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, profileBannerUrl=$profileBannerUrl, profilePicture=$profilePicture, protected_=$protected_, statusesCount=$statusesCount, url=$url, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponse.kt index ebb2b8d..ca80516 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponse.kt @@ -253,8 +253,11 @@ private constructor( private constructor( private val name: JsonField, private val description: JsonField, + private val promotedContent: JsonField, private val query: JsonField, private val rank: JsonField, + private val tweetVolume: JsonField, + private val url: JsonField, private val additionalProperties: MutableMap, ) { @@ -264,9 +267,16 @@ private constructor( @JsonProperty("description") @ExcludeMissing description: JsonField = JsonMissing.of(), + @JsonProperty("promotedContent") + @ExcludeMissing + promotedContent: JsonField = JsonMissing.of(), @JsonProperty("query") @ExcludeMissing query: JsonField = JsonMissing.of(), @JsonProperty("rank") @ExcludeMissing rank: JsonField = JsonMissing.of(), - ) : this(name, description, query, rank, mutableMapOf()) + @JsonProperty("tweetVolume") + @ExcludeMissing + tweetVolume: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(name, description, promotedContent, query, rank, tweetVolume, url, mutableMapOf()) /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or @@ -281,6 +291,14 @@ private constructor( */ fun description(): Optional = description.getOptional("description") + /** + * Promotion identifier from X. Null for organic trends. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun promotedContent(): Optional = promotedContent.getOptional("promotedContent") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type * (e.g. if the server responded with an unexpected value). @@ -293,6 +311,22 @@ private constructor( */ fun rank(): Optional = rank.getOptional("rank") + /** + * Approximate public post volume when X supplies it. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun tweetVolume(): Optional = tweetVolume.getOptional("tweetVolume") + + /** + * X search URL for the trend. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + /** * Returns the raw JSON value of [name]. * @@ -309,6 +343,16 @@ private constructor( @ExcludeMissing fun _description(): JsonField = description + /** + * Returns the raw JSON value of [promotedContent]. + * + * Unlike [promotedContent], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("promotedContent") + @ExcludeMissing + fun _promotedContent(): JsonField = promotedContent + /** * Returns the raw JSON value of [query]. * @@ -323,6 +367,22 @@ private constructor( */ @JsonProperty("rank") @ExcludeMissing fun _rank(): JsonField = rank + /** + * Returns the raw JSON value of [tweetVolume]. + * + * Unlike [tweetVolume], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tweetVolume") + @ExcludeMissing + fun _tweetVolume(): JsonField = tweetVolume + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -353,16 +413,22 @@ private constructor( private var name: JsonField? = null private var description: JsonField = JsonMissing.of() + private var promotedContent: JsonField = JsonMissing.of() private var query: JsonField = JsonMissing.of() private var rank: JsonField = JsonMissing.of() + private var tweetVolume: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic internal fun from(trend: Trend) = apply { name = trend.name description = trend.description + promotedContent = trend.promotedContent query = trend.query rank = trend.rank + tweetVolume = trend.tweetVolume + url = trend.url additionalProperties = trend.additionalProperties.toMutableMap() } @@ -390,6 +456,25 @@ private constructor( this.description = description } + /** Promotion identifier from X. Null for organic trends. */ + fun promotedContent(promotedContent: String?) = + promotedContent(JsonField.ofNullable(promotedContent)) + + /** Alias for calling [Builder.promotedContent] with `promotedContent.orElse(null)`. */ + fun promotedContent(promotedContent: Optional) = + promotedContent(promotedContent.getOrNull()) + + /** + * Sets [Builder.promotedContent] to an arbitrary JSON value. + * + * You should usually call [Builder.promotedContent] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun promotedContent(promotedContent: JsonField) = apply { + this.promotedContent = promotedContent + } + fun query(query: String) = query(JsonField.of(query)) /** @@ -412,6 +497,40 @@ private constructor( */ fun rank(rank: JsonField) = apply { this.rank = rank } + /** Approximate public post volume when X supplies it. */ + fun tweetVolume(tweetVolume: Long?) = tweetVolume(JsonField.ofNullable(tweetVolume)) + + /** + * Alias for [Builder.tweetVolume]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun tweetVolume(tweetVolume: Long) = tweetVolume(tweetVolume as Long?) + + /** Alias for calling [Builder.tweetVolume] with `tweetVolume.orElse(null)`. */ + fun tweetVolume(tweetVolume: Optional) = tweetVolume(tweetVolume.getOrNull()) + + /** + * Sets [Builder.tweetVolume] to an arbitrary JSON value. + * + * You should usually call [Builder.tweetVolume] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tweetVolume(tweetVolume: JsonField) = apply { this.tweetVolume = tweetVolume } + + /** X search URL for the trend. */ + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -447,8 +566,11 @@ private constructor( Trend( checkRequired("name", name), description, + promotedContent, query, rank, + tweetVolume, + url, additionalProperties.toMutableMap(), ) } @@ -471,8 +593,11 @@ private constructor( name() description() + promotedContent() query() rank() + tweetVolume() + url() validated = true } @@ -494,8 +619,11 @@ private constructor( internal fun validity(): Int = (if (name.asKnown().isPresent) 1 else 0) + (if (description.asKnown().isPresent) 1 else 0) + + (if (promotedContent.asKnown().isPresent) 1 else 0) + (if (query.asKnown().isPresent) 1 else 0) + - (if (rank.asKnown().isPresent) 1 else 0) + (if (rank.asKnown().isPresent) 1 else 0) + + (if (tweetVolume.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { @@ -505,19 +633,31 @@ private constructor( return other is Trend && name == other.name && description == other.description && + promotedContent == other.promotedContent && query == other.query && rank == other.rank && + tweetVolume == other.tweetVolume && + url == other.url && additionalProperties == other.additionalProperties } private val hashCode: Int by lazy { - Objects.hash(name, description, query, rank, additionalProperties) + Objects.hash( + name, + description, + promotedContent, + query, + rank, + tweetVolume, + url, + additionalProperties, + ) } override fun hashCode(): Int = hashCode override fun toString() = - "Trend{name=$name, description=$description, query=$query, rank=$rank, additionalProperties=$additionalProperties}" + "Trend{name=$name, description=$description, promotedContent=$promotedContent, query=$query, rank=$rank, tweetVolume=$tweetVolume, url=$url, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt index f445ea9..dd102b2 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponse.kt @@ -15,12 +15,10 @@ import com.fasterxml.jackson.databind.annotation.JsonSerialize import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.x_twitter_scraper.api.core.BaseDeserializer import com.x_twitter_scraper.api.core.BaseSerializer -import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing import com.x_twitter_scraper.api.core.JsonField import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue -import com.x_twitter_scraper.api.core.allMaxBy import com.x_twitter_scraper.api.core.checkRequired import com.x_twitter_scraper.api.core.getOrThrow import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException @@ -35,58 +33,50 @@ import kotlin.jvm.optionals.getOrNull @JsonSerialize(using = AccountConnectionAttemptRetrieveResponse.Serializer::class) class AccountConnectionAttemptRetrieveResponse private constructor( - private val xAccountConnectionAttemptPending: XAccountConnectionAttemptPending? = null, - private val xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess? = null, - private val xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed? = null, - private val xAccountConnectionChallenge: XAccountConnectionChallenge? = null, + private val pending: Pending? = null, + private val success: Success? = null, + private val failed: Failed? = null, + private val requiresEmailCode: RequiresEmailCode? = null, private val _json: JsonValue? = null, ) { /** The connection is still in progress. */ - fun xAccountConnectionAttemptPending(): Optional = - Optional.ofNullable(xAccountConnectionAttemptPending) + fun pending(): Optional = Optional.ofNullable(pending) /** The account connected successfully. */ - fun xAccountConnectionAttemptSuccess(): Optional = - Optional.ofNullable(xAccountConnectionAttemptSuccess) + fun success(): Optional = Optional.ofNullable(success) /** The connection reached a final failure. */ - fun xAccountConnectionAttemptFailed(): Optional = - Optional.ofNullable(xAccountConnectionAttemptFailed) + fun failed(): Optional = Optional.ofNullable(failed) /** * Resumable account connection challenge. Submit the email code to finish the same connection * attempt. */ - fun xAccountConnectionChallenge(): Optional = - Optional.ofNullable(xAccountConnectionChallenge) + fun requiresEmailCode(): Optional = Optional.ofNullable(requiresEmailCode) - fun isXAccountConnectionAttemptPending(): Boolean = xAccountConnectionAttemptPending != null + fun isPending(): Boolean = pending != null - fun isXAccountConnectionAttemptSuccess(): Boolean = xAccountConnectionAttemptSuccess != null + fun isSuccess(): Boolean = success != null - fun isXAccountConnectionAttemptFailed(): Boolean = xAccountConnectionAttemptFailed != null + fun isFailed(): Boolean = failed != null - fun isXAccountConnectionChallenge(): Boolean = xAccountConnectionChallenge != null + fun isRequiresEmailCode(): Boolean = requiresEmailCode != null /** The connection is still in progress. */ - fun asXAccountConnectionAttemptPending(): XAccountConnectionAttemptPending = - xAccountConnectionAttemptPending.getOrThrow("xAccountConnectionAttemptPending") + fun asPending(): Pending = pending.getOrThrow("pending") /** The account connected successfully. */ - fun asXAccountConnectionAttemptSuccess(): XAccountConnectionAttemptSuccess = - xAccountConnectionAttemptSuccess.getOrThrow("xAccountConnectionAttemptSuccess") + fun asSuccess(): Success = success.getOrThrow("success") /** The connection reached a final failure. */ - fun asXAccountConnectionAttemptFailed(): XAccountConnectionAttemptFailed = - xAccountConnectionAttemptFailed.getOrThrow("xAccountConnectionAttemptFailed") + fun asFailed(): Failed = failed.getOrThrow("failed") /** * Resumable account connection challenge. Submit the email code to finish the same connection * attempt. */ - fun asXAccountConnectionChallenge(): XAccountConnectionChallenge = - xAccountConnectionChallenge.getOrThrow("xAccountConnectionChallenge") + fun asRequiresEmailCode(): RequiresEmailCode = requiresEmailCode.getOrThrow("requiresEmailCode") fun _json(): Optional = Optional.ofNullable(_json) @@ -102,8 +92,8 @@ private constructor( * * Optional result = accountConnectionAttemptRetrieveResponse.accept(new AccountConnectionAttemptRetrieveResponse.Visitor>() { * @Override - * public Optional visitXAccountConnectionAttemptPending(XAccountConnectionAttemptPending xAccountConnectionAttemptPending) { - * return Optional.of(xAccountConnectionAttemptPending.toString()); + * public Optional visitPending(Pending pending) { + * return Optional.of(pending.toString()); * } * * // ... @@ -121,14 +111,10 @@ private constructor( */ fun accept(visitor: Visitor): T = when { - xAccountConnectionAttemptPending != null -> - visitor.visitXAccountConnectionAttemptPending(xAccountConnectionAttemptPending) - xAccountConnectionAttemptSuccess != null -> - visitor.visitXAccountConnectionAttemptSuccess(xAccountConnectionAttemptSuccess) - xAccountConnectionAttemptFailed != null -> - visitor.visitXAccountConnectionAttemptFailed(xAccountConnectionAttemptFailed) - xAccountConnectionChallenge != null -> - visitor.visitXAccountConnectionChallenge(xAccountConnectionChallenge) + pending != null -> visitor.visitPending(pending) + success != null -> visitor.visitSuccess(success) + failed != null -> visitor.visitFailed(failed) + requiresEmailCode != null -> visitor.visitRequiresEmailCode(requiresEmailCode) else -> visitor.unknown(_json) } @@ -149,28 +135,20 @@ private constructor( accept( object : Visitor { - override fun visitXAccountConnectionAttemptPending( - xAccountConnectionAttemptPending: XAccountConnectionAttemptPending - ) { - xAccountConnectionAttemptPending.validate() + override fun visitPending(pending: Pending) { + pending.validate() } - override fun visitXAccountConnectionAttemptSuccess( - xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess - ) { - xAccountConnectionAttemptSuccess.validate() + override fun visitSuccess(success: Success) { + success.validate() } - override fun visitXAccountConnectionAttemptFailed( - xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed - ) { - xAccountConnectionAttemptFailed.validate() + override fun visitFailed(failed: Failed) { + failed.validate() } - override fun visitXAccountConnectionChallenge( - xAccountConnectionChallenge: XAccountConnectionChallenge - ) { - xAccountConnectionChallenge.validate() + override fun visitRequiresEmailCode(requiresEmailCode: RequiresEmailCode) { + requiresEmailCode.validate() } } ) @@ -194,21 +172,14 @@ private constructor( internal fun validity(): Int = accept( object : Visitor { - override fun visitXAccountConnectionAttemptPending( - xAccountConnectionAttemptPending: XAccountConnectionAttemptPending - ) = xAccountConnectionAttemptPending.validity() + override fun visitPending(pending: Pending) = pending.validity() - override fun visitXAccountConnectionAttemptSuccess( - xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess - ) = xAccountConnectionAttemptSuccess.validity() + override fun visitSuccess(success: Success) = success.validity() - override fun visitXAccountConnectionAttemptFailed( - xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed - ) = xAccountConnectionAttemptFailed.validity() + override fun visitFailed(failed: Failed) = failed.validity() - override fun visitXAccountConnectionChallenge( - xAccountConnectionChallenge: XAccountConnectionChallenge - ) = xAccountConnectionChallenge.validity() + override fun visitRequiresEmailCode(requiresEmailCode: RequiresEmailCode) = + requiresEmailCode.validity() override fun unknown(json: JsonValue?) = 0 } @@ -220,30 +191,21 @@ private constructor( } return other is AccountConnectionAttemptRetrieveResponse && - xAccountConnectionAttemptPending == other.xAccountConnectionAttemptPending && - xAccountConnectionAttemptSuccess == other.xAccountConnectionAttemptSuccess && - xAccountConnectionAttemptFailed == other.xAccountConnectionAttemptFailed && - xAccountConnectionChallenge == other.xAccountConnectionChallenge + pending == other.pending && + success == other.success && + failed == other.failed && + requiresEmailCode == other.requiresEmailCode } - override fun hashCode(): Int = - Objects.hash( - xAccountConnectionAttemptPending, - xAccountConnectionAttemptSuccess, - xAccountConnectionAttemptFailed, - xAccountConnectionChallenge, - ) + override fun hashCode(): Int = Objects.hash(pending, success, failed, requiresEmailCode) override fun toString(): String = when { - xAccountConnectionAttemptPending != null -> - "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptPending=$xAccountConnectionAttemptPending}" - xAccountConnectionAttemptSuccess != null -> - "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptSuccess=$xAccountConnectionAttemptSuccess}" - xAccountConnectionAttemptFailed != null -> - "AccountConnectionAttemptRetrieveResponse{xAccountConnectionAttemptFailed=$xAccountConnectionAttemptFailed}" - xAccountConnectionChallenge != null -> - "AccountConnectionAttemptRetrieveResponse{xAccountConnectionChallenge=$xAccountConnectionChallenge}" + pending != null -> "AccountConnectionAttemptRetrieveResponse{pending=$pending}" + success != null -> "AccountConnectionAttemptRetrieveResponse{success=$success}" + failed != null -> "AccountConnectionAttemptRetrieveResponse{failed=$failed}" + requiresEmailCode != null -> + "AccountConnectionAttemptRetrieveResponse{requiresEmailCode=$requiresEmailCode}" _json != null -> "AccountConnectionAttemptRetrieveResponse{_unknown=$_json}" else -> throw IllegalStateException("Invalid AccountConnectionAttemptRetrieveResponse") } @@ -252,42 +214,25 @@ private constructor( /** The connection is still in progress. */ @JvmStatic - fun ofXAccountConnectionAttemptPending( - xAccountConnectionAttemptPending: XAccountConnectionAttemptPending - ) = - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptPending = xAccountConnectionAttemptPending - ) + fun ofPending(pending: Pending) = + AccountConnectionAttemptRetrieveResponse(pending = pending) /** The account connected successfully. */ @JvmStatic - fun ofXAccountConnectionAttemptSuccess( - xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess - ) = - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptSuccess = xAccountConnectionAttemptSuccess - ) + fun ofSuccess(success: Success) = + AccountConnectionAttemptRetrieveResponse(success = success) /** The connection reached a final failure. */ @JvmStatic - fun ofXAccountConnectionAttemptFailed( - xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed - ) = - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptFailed = xAccountConnectionAttemptFailed - ) + fun ofFailed(failed: Failed) = AccountConnectionAttemptRetrieveResponse(failed = failed) /** * Resumable account connection challenge. Submit the email code to finish the same * connection attempt. */ @JvmStatic - fun ofXAccountConnectionChallenge( - xAccountConnectionChallenge: XAccountConnectionChallenge - ) = - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionChallenge = xAccountConnectionChallenge - ) + fun ofRequiresEmailCode(requiresEmailCode: RequiresEmailCode) = + AccountConnectionAttemptRetrieveResponse(requiresEmailCode = requiresEmailCode) } /** @@ -297,27 +242,19 @@ private constructor( interface Visitor { /** The connection is still in progress. */ - fun visitXAccountConnectionAttemptPending( - xAccountConnectionAttemptPending: XAccountConnectionAttemptPending - ): T + fun visitPending(pending: Pending): T /** The account connected successfully. */ - fun visitXAccountConnectionAttemptSuccess( - xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess - ): T + fun visitSuccess(success: Success): T /** The connection reached a final failure. */ - fun visitXAccountConnectionAttemptFailed( - xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed - ): T + fun visitFailed(failed: Failed): T /** * Resumable account connection challenge. Submit the email code to finish the same * connection attempt. */ - fun visitXAccountConnectionChallenge( - xAccountConnectionChallenge: XAccountConnectionChallenge - ): T + fun visitRequiresEmailCode(requiresEmailCode: RequiresEmailCode): T /** * Maps an unknown variant of [AccountConnectionAttemptRetrieveResponse] to a value of type @@ -346,49 +283,35 @@ private constructor( node: JsonNode ): AccountConnectionAttemptRetrieveResponse { val json = JsonValue.fromJsonNode(node) + val status = json.asObject().getOrNull()?.get("status")?.asString()?.getOrNull() - val bestMatches = - sequenceOf( - tryDeserialize(node, jacksonTypeRef()) - ?.let { - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptPending = it, - _json = json, - ) - }, - tryDeserialize(node, jacksonTypeRef()) - ?.let { - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptSuccess = it, - _json = json, - ) - }, - tryDeserialize(node, jacksonTypeRef()) - ?.let { - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionAttemptFailed = it, - _json = json, - ) - }, - tryDeserialize(node, jacksonTypeRef())?.let { - AccountConnectionAttemptRetrieveResponse( - xAccountConnectionChallenge = it, - _json = json, - ) - }, - ) - .filterNotNull() - .allMaxBy { it.validity() } - .toList() - return when (bestMatches.size) { - // This can happen if what we're deserializing is completely incompatible with all - // the possible variants (e.g. deserializing from boolean). - 0 -> AccountConnectionAttemptRetrieveResponse(_json = json) - 1 -> bestMatches.single() - // If there's more than one match with the highest validity, then use the first - // completely valid match, or simply the first match if none are completely valid. - else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + when (status) { + "pending" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + AccountConnectionAttemptRetrieveResponse(pending = it, _json = json) + } ?: AccountConnectionAttemptRetrieveResponse(_json = json) + } + "success" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + AccountConnectionAttemptRetrieveResponse(success = it, _json = json) + } ?: AccountConnectionAttemptRetrieveResponse(_json = json) + } + "failed" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + AccountConnectionAttemptRetrieveResponse(failed = it, _json = json) + } ?: AccountConnectionAttemptRetrieveResponse(_json = json) + } + "requires_email_code" -> { + return tryDeserialize(node, jacksonTypeRef())?.let { + AccountConnectionAttemptRetrieveResponse( + requiresEmailCode = it, + _json = json, + ) + } ?: AccountConnectionAttemptRetrieveResponse(_json = json) + } } + + return AccountConnectionAttemptRetrieveResponse(_json = json) } } @@ -403,14 +326,10 @@ private constructor( provider: SerializerProvider, ) { when { - value.xAccountConnectionAttemptPending != null -> - generator.writeObject(value.xAccountConnectionAttemptPending) - value.xAccountConnectionAttemptSuccess != null -> - generator.writeObject(value.xAccountConnectionAttemptSuccess) - value.xAccountConnectionAttemptFailed != null -> - generator.writeObject(value.xAccountConnectionAttemptFailed) - value.xAccountConnectionChallenge != null -> - generator.writeObject(value.xAccountConnectionChallenge) + value.pending != null -> generator.writeObject(value.pending) + value.success != null -> generator.writeObject(value.success) + value.failed != null -> generator.writeObject(value.failed) + value.requiresEmailCode != null -> generator.writeObject(value.requiresEmailCode) value._json != null -> generator.writeObject(value._json) else -> throw IllegalStateException("Invalid AccountConnectionAttemptRetrieveResponse") @@ -419,7 +338,7 @@ private constructor( } /** The connection is still in progress. */ - class XAccountConnectionAttemptPending + class Pending @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, @@ -506,8 +425,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [XAccountConnectionAttemptPending]. + * Returns a mutable builder for constructing an instance of [Pending]. * * The following fields are required: * ```java @@ -518,7 +436,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [XAccountConnectionAttemptPending]. */ + /** A builder for [Pending]. */ class Builder internal constructor() { private var id: JsonField? = null @@ -528,15 +446,13 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(xAccountConnectionAttemptPending: XAccountConnectionAttemptPending) = - apply { - id = xAccountConnectionAttemptPending.id - object_ = xAccountConnectionAttemptPending.object_ - pollAfterMs = xAccountConnectionAttemptPending.pollAfterMs - status = xAccountConnectionAttemptPending.status - additionalProperties = - xAccountConnectionAttemptPending.additionalProperties.toMutableMap() - } + internal fun from(pending: Pending) = apply { + id = pending.id + object_ = pending.object_ + pollAfterMs = pending.pollAfterMs + status = pending.status + additionalProperties = pending.additionalProperties.toMutableMap() + } fun id(id: String) = id(JsonField.of(id)) @@ -608,7 +524,7 @@ private constructor( } /** - * Returns an immutable instance of [XAccountConnectionAttemptPending]. + * Returns an immutable instance of [Pending]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -620,8 +536,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): XAccountConnectionAttemptPending = - XAccountConnectionAttemptPending( + fun build(): Pending = + Pending( checkRequired("id", id), object_, checkRequired("pollAfterMs", pollAfterMs), @@ -641,7 +557,7 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): XAccountConnectionAttemptPending = apply { + fun validate(): Pending = apply { if (validated) { return@apply } @@ -687,7 +603,7 @@ private constructor( return true } - return other is XAccountConnectionAttemptPending && + return other is Pending && id == other.id && object_ == other.object_ && pollAfterMs == other.pollAfterMs && @@ -702,11 +618,11 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "XAccountConnectionAttemptPending{id=$id, object_=$object_, pollAfterMs=$pollAfterMs, status=$status, additionalProperties=$additionalProperties}" + "Pending{id=$id, object_=$object_, pollAfterMs=$pollAfterMs, status=$status, additionalProperties=$additionalProperties}" } /** The account connected successfully. */ - class XAccountConnectionAttemptSuccess + class Success @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, @@ -773,8 +689,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [XAccountConnectionAttemptSuccess]. + * Returns a mutable builder for constructing an instance of [Success]. * * The following fields are required: * ```java @@ -784,7 +699,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [XAccountConnectionAttemptSuccess]. */ + /** A builder for [Success]. */ class Builder internal constructor() { private var id: JsonField? = null @@ -793,14 +708,12 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(xAccountConnectionAttemptSuccess: XAccountConnectionAttemptSuccess) = - apply { - id = xAccountConnectionAttemptSuccess.id - object_ = xAccountConnectionAttemptSuccess.object_ - status = xAccountConnectionAttemptSuccess.status - additionalProperties = - xAccountConnectionAttemptSuccess.additionalProperties.toMutableMap() - } + internal fun from(success: Success) = apply { + id = success.id + object_ = success.object_ + status = success.status + additionalProperties = success.additionalProperties.toMutableMap() + } fun id(id: String) = id(JsonField.of(id)) @@ -861,7 +774,7 @@ private constructor( } /** - * Returns an immutable instance of [XAccountConnectionAttemptSuccess]. + * Returns an immutable instance of [Success]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -872,8 +785,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): XAccountConnectionAttemptSuccess = - XAccountConnectionAttemptSuccess( + fun build(): Success = + Success( checkRequired("id", id), object_, status, @@ -892,7 +805,7 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): XAccountConnectionAttemptSuccess = apply { + fun validate(): Success = apply { if (validated) { return@apply } @@ -936,7 +849,7 @@ private constructor( return true } - return other is XAccountConnectionAttemptSuccess && + return other is Success && id == other.id && object_ == other.object_ && status == other.status && @@ -950,11 +863,11 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "XAccountConnectionAttemptSuccess{id=$id, object_=$object_, status=$status, additionalProperties=$additionalProperties}" + "Success{id=$id, object_=$object_, status=$status, additionalProperties=$additionalProperties}" } /** The connection reached a final failure. */ - class XAccountConnectionAttemptFailed + class Failed @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, @@ -1070,8 +983,7 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [XAccountConnectionAttemptFailed]. + * Returns a mutable builder for constructing an instance of [Failed]. * * The following fields are required: * ```java @@ -1083,7 +995,7 @@ private constructor( @JvmStatic fun builder() = Builder() } - /** A builder for [XAccountConnectionAttemptFailed]. */ + /** A builder for [Failed]. */ class Builder internal constructor() { private var id: JsonField? = null @@ -1095,17 +1007,15 @@ private constructor( private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(xAccountConnectionAttemptFailed: XAccountConnectionAttemptFailed) = - apply { - id = xAccountConnectionAttemptFailed.id - error = xAccountConnectionAttemptFailed.error - object_ = xAccountConnectionAttemptFailed.object_ - retryable = xAccountConnectionAttemptFailed.retryable - status = xAccountConnectionAttemptFailed.status - reason = xAccountConnectionAttemptFailed.reason - additionalProperties = - xAccountConnectionAttemptFailed.additionalProperties.toMutableMap() - } + internal fun from(failed: Failed) = apply { + id = failed.id + error = failed.error + object_ = failed.object_ + retryable = failed.retryable + status = failed.status + reason = failed.reason + additionalProperties = failed.additionalProperties.toMutableMap() + } fun id(id: String) = id(JsonField.of(id)) @@ -1199,7 +1109,7 @@ private constructor( } /** - * Returns an immutable instance of [XAccountConnectionAttemptFailed]. + * Returns an immutable instance of [Failed]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1212,8 +1122,8 @@ private constructor( * * @throws IllegalStateException if any required field is unset. */ - fun build(): XAccountConnectionAttemptFailed = - XAccountConnectionAttemptFailed( + fun build(): Failed = + Failed( checkRequired("id", id), checkRequired("error", error), object_, @@ -1235,7 +1145,7 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): XAccountConnectionAttemptFailed = apply { + fun validate(): Failed = apply { if (validated) { return@apply } @@ -1285,7 +1195,7 @@ private constructor( return true } - return other is XAccountConnectionAttemptFailed && + return other is Failed && id == other.id && error == other.error && object_ == other.object_ && @@ -1302,21 +1212,21 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "XAccountConnectionAttemptFailed{id=$id, error=$error, object_=$object_, retryable=$retryable, status=$status, reason=$reason, additionalProperties=$additionalProperties}" + "Failed{id=$id, error=$error, object_=$object_, retryable=$retryable, status=$status, reason=$reason, additionalProperties=$additionalProperties}" } /** * Resumable account connection challenge. Submit the email code to finish the same connection * attempt. */ - class XAccountConnectionChallenge + class RequiresEmailCode @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( private val id: JsonField, private val expiresAt: JsonField, private val message: JsonField, - private val object_: JsonField, - private val status: JsonField, + private val object_: JsonValue, + private val status: JsonValue, private val username: JsonField, private val additionalProperties: MutableMap, ) { @@ -1328,8 +1238,8 @@ private constructor( @ExcludeMissing expiresAt: JsonField = JsonMissing.of(), @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), - @JsonProperty("object") @ExcludeMissing object_: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), @JsonProperty("username") @ExcludeMissing username: JsonField = JsonMissing.of(), @@ -1357,18 +1267,26 @@ private constructor( fun message(): String = message.getRequired("message") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_challenge") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). */ - fun object_(): Object = object_.getRequired("object") + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or - * is unexpectedly missing or null (e.g. if the server responded with an unexpected - * value). + * Expected to always return the following: + * ```java + * JsonValue.from("requires_email_code") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). */ - fun status(): Status = status.getRequired("status") + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or @@ -1400,20 +1318,6 @@ private constructor( */ @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message - /** - * Returns the raw JSON value of [object_]. - * - * Unlike [object_], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("object") @ExcludeMissing fun _object_(): JsonField = object_ - - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - /** * Returns the raw JSON value of [username]. * @@ -1436,43 +1340,39 @@ private constructor( companion object { /** - * Returns a mutable builder for constructing an instance of - * [XAccountConnectionChallenge]. + * Returns a mutable builder for constructing an instance of [RequiresEmailCode]. * * The following fields are required: * ```java * .id() * .expiresAt() * .message() - * .object_() - * .status() * .username() * ``` */ @JvmStatic fun builder() = Builder() } - /** A builder for [XAccountConnectionChallenge]. */ + /** A builder for [RequiresEmailCode]. */ class Builder internal constructor() { private var id: JsonField? = null private var expiresAt: JsonField? = null private var message: JsonField? = null - private var object_: JsonField? = null - private var status: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_challenge") + private var status: JsonValue = JsonValue.from("requires_email_code") private var username: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(xAccountConnectionChallenge: XAccountConnectionChallenge) = apply { - id = xAccountConnectionChallenge.id - expiresAt = xAccountConnectionChallenge.expiresAt - message = xAccountConnectionChallenge.message - object_ = xAccountConnectionChallenge.object_ - status = xAccountConnectionChallenge.status - username = xAccountConnectionChallenge.username - additionalProperties = - xAccountConnectionChallenge.additionalProperties.toMutableMap() + internal fun from(requiresEmailCode: RequiresEmailCode) = apply { + id = requiresEmailCode.id + expiresAt = requiresEmailCode.expiresAt + message = requiresEmailCode.message + object_ = requiresEmailCode.object_ + status = requiresEmailCode.status + username = requiresEmailCode.username + additionalProperties = requiresEmailCode.additionalProperties.toMutableMap() } fun id(id: String) = id(JsonField.of(id)) @@ -1510,27 +1410,33 @@ private constructor( */ fun message(message: JsonField) = apply { this.message = message } - fun object_(object_: Object) = object_(JsonField.of(object_)) - /** - * Sets [Builder.object_] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_challenge") + * ``` * - * You should usually call [Builder.object_] with a well-typed [Object] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun object_(object_: JsonField) = apply { this.object_ = object_ } - - fun status(status: Status) = status(JsonField.of(status)) + fun object_(object_: JsonValue) = apply { this.object_ = object_ } /** - * Sets [Builder.status] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("requires_email_code") + * ``` * - * You should usually call [Builder.status] with a well-typed [Status] value instead. * This method is primarily for setting the field to an undocumented or not yet * supported value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonValue) = apply { this.status = status } fun username(username: String) = username(JsonField.of(username)) @@ -1563,7 +1469,7 @@ private constructor( } /** - * Returns an immutable instance of [XAccountConnectionChallenge]. + * Returns an immutable instance of [RequiresEmailCode]. * * Further updates to this [Builder] will not mutate the returned instance. * @@ -1572,20 +1478,18 @@ private constructor( * .id() * .expiresAt() * .message() - * .object_() - * .status() * .username() * ``` * * @throws IllegalStateException if any required field is unset. */ - fun build(): XAccountConnectionChallenge = - XAccountConnectionChallenge( + fun build(): RequiresEmailCode = + RequiresEmailCode( checkRequired("id", id), checkRequired("expiresAt", expiresAt), checkRequired("message", message), - checkRequired("object_", object_), - checkRequired("status", status), + object_, + status, checkRequired("username", username), additionalProperties.toMutableMap(), ) @@ -1602,7 +1506,7 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): XAccountConnectionChallenge = apply { + fun validate(): RequiresEmailCode = apply { if (validated) { return@apply } @@ -1610,8 +1514,16 @@ private constructor( id() expiresAt() message() - object_().validate() - status().validate() + _object_().let { + if (it != JsonValue.from("x_account_connection_challenge")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + _status().let { + if (it != JsonValue.from("requires_email_code")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } username() validated = true } @@ -1635,282 +1547,18 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (expiresAt.asKnown().isPresent) 1 else 0) + (if (message.asKnown().isPresent) 1 else 0) + - (object_.asKnown().getOrNull()?.validity() ?: 0) + - (status.asKnown().getOrNull()?.validity() ?: 0) + + object_.let { + if (it == JsonValue.from("x_account_connection_challenge")) 1 else 0 + } + + status.let { if (it == JsonValue.from("requires_email_code")) 1 else 0 } + (if (username.asKnown().isPresent) 1 else 0) - class Object @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val X_ACCOUNT_CONNECTION_CHALLENGE = of("x_account_connection_challenge") - - @JvmStatic fun of(value: String) = Object(JsonField.of(value)) - } - - /** An enum containing [Object]'s known values. */ - enum class Known { - X_ACCOUNT_CONNECTION_CHALLENGE - } - - /** - * An enum containing [Object]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Object] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if - * the SDK is on an older version than the API, then the API may respond with new - * members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - X_ACCOUNT_CONNECTION_CHALLENGE, - /** - * An enum member indicating that [Object] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - X_ACCOUNT_CONNECTION_CHALLENGE -> Value.X_ACCOUNT_CONNECTION_CHALLENGE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - X_ACCOUNT_CONNECTION_CHALLENGE -> Known.X_ACCOUNT_CONNECTION_CHALLENGE - else -> throw XTwitterScraperInvalidDataException("Unknown Object: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - XTwitterScraperInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - /** - * Validates that the types of all values in this object match their expected types - * recursively. - * - * This method is _not_ forwards compatible with new types from the API for existing - * fields. - * - * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't - * match its expected type. - */ - fun validate(): Object = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: XTwitterScraperInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Object && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - - class Status @JsonCreator private constructor(private val value: JsonField) : Enum { - - /** - * Returns this class instance's raw value. - * - * This is usually only useful if this instance was deserialized from data that doesn't - * match any known member, and you want to know that value. For example, if the SDK is - * on an older version than the API, then the API may respond with new members that the - * SDK is unaware of. - */ - @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value - - companion object { - - @JvmField val REQUIRES_EMAIL_CODE = of("requires_email_code") - - @JvmStatic fun of(value: String) = Status(JsonField.of(value)) - } - - /** An enum containing [Status]'s known values. */ - enum class Known { - REQUIRES_EMAIL_CODE - } - - /** - * An enum containing [Status]'s known values, as well as an [_UNKNOWN] member. - * - * An instance of [Status] can contain an unknown value in a couple of cases: - * - It was deserialized from data that doesn't match any known member. For example, if - * the SDK is on an older version than the API, then the API may respond with new - * members that the SDK is unaware of. - * - It was constructed with an arbitrary value using the [of] method. - */ - enum class Value { - REQUIRES_EMAIL_CODE, - /** - * An enum member indicating that [Status] was instantiated with an unknown value. - */ - _UNKNOWN, - } - - /** - * Returns an enum member corresponding to this class instance's value, or - * [Value._UNKNOWN] if the class was instantiated with an unknown value. - * - * Use the [known] method instead if you're certain the value is always known or if you - * want to throw for the unknown case. - */ - fun value(): Value = - when (this) { - REQUIRES_EMAIL_CODE -> Value.REQUIRES_EMAIL_CODE - else -> Value._UNKNOWN - } - - /** - * Returns an enum member corresponding to this class instance's value. - * - * Use the [value] method instead if you're uncertain the value is always known and - * don't want to throw for the unknown case. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a - * known member. - */ - fun known(): Known = - when (this) { - REQUIRES_EMAIL_CODE -> Known.REQUIRES_EMAIL_CODE - else -> throw XTwitterScraperInvalidDataException("Unknown Status: $value") - } - - /** - * Returns this class instance's primitive wire representation. - * - * This differs from the [toString] method because that method is primarily for - * debugging and generally doesn't throw. - * - * @throws XTwitterScraperInvalidDataException if this class instance's value does not - * have the expected primitive type. - */ - fun asString(): String = - _value().asString().orElseThrow { - XTwitterScraperInvalidDataException("Value is not a String") - } - - private var validated: Boolean = false - - /** - * Validates that the types of all values in this object match their expected types - * recursively. - * - * This method is _not_ forwards compatible with new types from the API for existing - * fields. - * - * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't - * match its expected type. - */ - fun validate(): Status = apply { - if (validated) { - return@apply - } - - known() - validated = true - } - - fun isValid(): Boolean = - try { - validate() - true - } catch (e: XTwitterScraperInvalidDataException) { - false - } - - /** - * Returns a score indicating how many valid values are contained in this object - * recursively. - * - * Used for best match union deserialization. - */ - @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 - - override fun equals(other: Any?): Boolean { - if (this === other) { - return true - } - - return other is Status && value == other.value - } - - override fun hashCode() = value.hashCode() - - override fun toString() = value.toString() - } - override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is XAccountConnectionChallenge && + return other is RequiresEmailCode && id == other.id && expiresAt == other.expiresAt && message == other.message && @@ -1927,6 +1575,6 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "XAccountConnectionChallenge{id=$id, expiresAt=$expiresAt, message=$message, object_=$object_, status=$status, username=$username, additionalProperties=$additionalProperties}" + "RequiresEmailCode{id=$id, expiresAt=$expiresAt, message=$message, object_=$object_, status=$status, username=$username, additionalProperties=$additionalProperties}" } } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponse.kt index ad6018b..2dba6ce 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponse.kt @@ -29,7 +29,7 @@ private constructor( private val id: JsonField, private val createdAt: JsonField, private val health: JsonField, - private val status: JsonField, + private val status: JsonValue, private val xUserId: JsonField, private val xUsername: JsonField, private val additionalProperties: MutableMap, @@ -42,7 +42,7 @@ private constructor( @ExcludeMissing createdAt: JsonField = JsonMissing.of(), @JsonProperty("health") @ExcludeMissing health: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), @JsonProperty("xUserId") @ExcludeMissing xUserId: JsonField = JsonMissing.of(), @JsonProperty("xUsername") @ExcludeMissing xUsername: JsonField = JsonMissing.of(), ) : this(id, createdAt, health, status, xUserId, xUsername, mutableMapOf()) @@ -66,10 +66,15 @@ private constructor( fun health(): Health = health.getRequired("health") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + * Expected to always return the following: + * ```java + * JsonValue.from("active") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). */ - fun status(): String = status.getRequired("status") + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is @@ -106,13 +111,6 @@ private constructor( */ @JsonProperty("health") @ExcludeMissing fun _health(): JsonField = health - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - /** * Returns the raw JSON value of [xUserId]. * @@ -150,7 +148,6 @@ private constructor( * .id() * .createdAt() * .health() - * .status() * .xUserId() * .xUsername() * ``` @@ -164,7 +161,7 @@ private constructor( private var id: JsonField? = null private var createdAt: JsonField? = null private var health: JsonField? = null - private var status: JsonField? = null + private var status: JsonValue = JsonValue.from("active") private var xUserId: JsonField? = null private var xUsername: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -214,15 +211,19 @@ private constructor( */ fun health(health: JsonField) = apply { this.health = health } - fun status(status: String) = status(JsonField.of(status)) - /** - * Sets [Builder.status] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("active") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonValue) = apply { this.status = status } fun xUserId(xUserId: String) = xUserId(JsonField.of(xUserId)) @@ -274,7 +275,6 @@ private constructor( * .id() * .createdAt() * .health() - * .status() * .xUserId() * .xUsername() * ``` @@ -286,7 +286,7 @@ private constructor( checkRequired("id", id), checkRequired("createdAt", createdAt), checkRequired("health", health), - checkRequired("status", status), + status, checkRequired("xUserId", xUserId), checkRequired("xUsername", xUsername), additionalProperties.toMutableMap(), @@ -311,7 +311,11 @@ private constructor( id() createdAt() health().validate() - status() + _status().let { + if (it != JsonValue.from("active")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } xUserId() xUsername() validated = true @@ -335,7 +339,7 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (health.asKnown().getOrNull()?.validity() ?: 0) + - (if (status.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("active")) 1 else 0 } + (if (xUserId.asKnown().isPresent) 1 else 0) + (if (xUsername.asKnown().isPresent) 1 else 0) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt index cf0b97b..ba70f64 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponse.kt @@ -9,74 +9,117 @@ package com.x_twitter_scraper.api.models.x.accounts import com.fasterxml.jackson.annotation.JsonAnyGetter import com.fasterxml.jackson.annotation.JsonAnySetter import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.fasterxml.jackson.core.JsonGenerator +import com.fasterxml.jackson.core.ObjectCodec +import com.fasterxml.jackson.databind.JsonNode +import com.fasterxml.jackson.databind.SerializerProvider +import com.fasterxml.jackson.databind.annotation.JsonDeserialize +import com.fasterxml.jackson.databind.annotation.JsonSerialize +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.BaseDeserializer +import com.x_twitter_scraper.api.core.BaseSerializer +import com.x_twitter_scraper.api.core.Enum import com.x_twitter_scraper.api.core.ExcludeMissing +import com.x_twitter_scraper.api.core.JsonField +import com.x_twitter_scraper.api.core.JsonMissing import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.allMaxBy +import com.x_twitter_scraper.api.core.checkRequired +import com.x_twitter_scraper.api.core.getOrThrow import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException +import java.time.OffsetDateTime import java.util.Collections import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull +/** Sanitized X account summary returned by connect and reauth. */ +@JsonDeserialize(using = AccountCreateResponse.Deserializer::class) +@JsonSerialize(using = AccountCreateResponse.Serializer::class) class AccountCreateResponse -@JsonCreator(mode = JsonCreator.Mode.DISABLED) -private constructor(private val additionalProperties: MutableMap) { +private constructor( + private val sanitizedXAccount: SanitizedXAccount? = null, + private val xAccountConnectionAttemptPending: XAccountConnectionAttemptPending? = null, + private val xAccountConnectionChallenge: XAccountConnectionChallenge? = null, + private val _json: JsonValue? = null, +) { - @JsonCreator private constructor() : this(mutableMapOf()) + /** Sanitized X account summary returned by connect and reauth. */ + fun sanitizedXAccount(): Optional = Optional.ofNullable(sanitizedXAccount) - @JsonAnySetter - private fun putAdditionalProperty(key: String, value: JsonValue) { - additionalProperties.put(key, value) - } - - @JsonAnyGetter - @ExcludeMissing - fun _additionalProperties(): Map = - Collections.unmodifiableMap(additionalProperties) - - fun toBuilder() = Builder().from(this) + /** The connection is still in progress. */ + fun xAccountConnectionAttemptPending(): Optional = + Optional.ofNullable(xAccountConnectionAttemptPending) - companion object { - - /** Returns a mutable builder for constructing an instance of [AccountCreateResponse]. */ - @JvmStatic fun builder() = Builder() - } + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + fun xAccountConnectionChallenge(): Optional = + Optional.ofNullable(xAccountConnectionChallenge) - /** A builder for [AccountCreateResponse]. */ - class Builder internal constructor() { + fun isSanitizedXAccount(): Boolean = sanitizedXAccount != null - private var additionalProperties: MutableMap = mutableMapOf() + fun isXAccountConnectionAttemptPending(): Boolean = xAccountConnectionAttemptPending != null - @JvmSynthetic - internal fun from(accountCreateResponse: AccountCreateResponse) = apply { - additionalProperties = accountCreateResponse.additionalProperties.toMutableMap() - } + fun isXAccountConnectionChallenge(): Boolean = xAccountConnectionChallenge != null - fun additionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.clear() - putAllAdditionalProperties(additionalProperties) - } + /** Sanitized X account summary returned by connect and reauth. */ + fun asSanitizedXAccount(): SanitizedXAccount = sanitizedXAccount.getOrThrow("sanitizedXAccount") - fun putAdditionalProperty(key: String, value: JsonValue) = apply { - additionalProperties.put(key, value) - } + /** The connection is still in progress. */ + fun asXAccountConnectionAttemptPending(): XAccountConnectionAttemptPending = + xAccountConnectionAttemptPending.getOrThrow("xAccountConnectionAttemptPending") - fun putAllAdditionalProperties(additionalProperties: Map) = apply { - this.additionalProperties.putAll(additionalProperties) - } + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + fun asXAccountConnectionChallenge(): XAccountConnectionChallenge = + xAccountConnectionChallenge.getOrThrow("xAccountConnectionChallenge") - fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + fun _json(): Optional = Optional.ofNullable(_json) - fun removeAllAdditionalProperties(keys: Set) = apply { - keys.forEach(::removeAdditionalProperty) + /** + * Maps this instance's current variant to a value of type [T] using the given [visitor]. + * + * Note that this method is _not_ forwards compatible with new variants from the API, unless + * [visitor] overrides [Visitor.unknown]. To handle variants not known to this version of the + * SDK gracefully, consider overriding [Visitor.unknown]: + * ```java + * import com.x_twitter_scraper.api.core.JsonValue; + * import java.util.Optional; + * + * Optional result = accountCreateResponse.accept(new AccountCreateResponse.Visitor>() { + * @Override + * public Optional visitSanitizedXAccount(SanitizedXAccount sanitizedXAccount) { + * return Optional.of(sanitizedXAccount.toString()); + * } + * + * // ... + * + * @Override + * public Optional unknown(JsonValue json) { + * // Or inspect the `json`. + * return Optional.empty(); + * } + * }); + * ``` + * + * @throws XTwitterScraperInvalidDataException if [Visitor.unknown] is not overridden in + * [visitor] and the current variant is unknown. + */ + fun accept(visitor: Visitor): T = + when { + sanitizedXAccount != null -> visitor.visitSanitizedXAccount(sanitizedXAccount) + xAccountConnectionAttemptPending != null -> + visitor.visitXAccountConnectionAttemptPending(xAccountConnectionAttemptPending) + xAccountConnectionChallenge != null -> + visitor.visitXAccountConnectionChallenge(xAccountConnectionChallenge) + else -> visitor.unknown(_json) } - /** - * Returns an immutable instance of [AccountCreateResponse]. - * - * Further updates to this [Builder] will not mutate the returned instance. - */ - fun build(): AccountCreateResponse = - AccountCreateResponse(additionalProperties.toMutableMap()) - } - private var validated: Boolean = false /** @@ -92,6 +135,25 @@ private constructor(private val additionalProperties: MutableMap { + override fun visitSanitizedXAccount(sanitizedXAccount: SanitizedXAccount) { + sanitizedXAccount.validate() + } + + override fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) { + xAccountConnectionAttemptPending.validate() + } + + override fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) { + xAccountConnectionChallenge.validate() + } + } + ) validated = true } @@ -108,19 +170,1343 @@ private constructor(private val additionalProperties: MutableMap { + override fun visitSanitizedXAccount(sanitizedXAccount: SanitizedXAccount) = + sanitizedXAccount.validity() + + override fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) = xAccountConnectionAttemptPending.validity() + + override fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) = xAccountConnectionChallenge.validity() + + override fun unknown(json: JsonValue?) = 0 + } + ) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is AccountCreateResponse && additionalProperties == other.additionalProperties + return other is AccountCreateResponse && + sanitizedXAccount == other.sanitizedXAccount && + xAccountConnectionAttemptPending == other.xAccountConnectionAttemptPending && + xAccountConnectionChallenge == other.xAccountConnectionChallenge + } + + override fun hashCode(): Int = + Objects.hash( + sanitizedXAccount, + xAccountConnectionAttemptPending, + xAccountConnectionChallenge, + ) + + override fun toString(): String = + when { + sanitizedXAccount != null -> + "AccountCreateResponse{sanitizedXAccount=$sanitizedXAccount}" + xAccountConnectionAttemptPending != null -> + "AccountCreateResponse{xAccountConnectionAttemptPending=$xAccountConnectionAttemptPending}" + xAccountConnectionChallenge != null -> + "AccountCreateResponse{xAccountConnectionChallenge=$xAccountConnectionChallenge}" + _json != null -> "AccountCreateResponse{_unknown=$_json}" + else -> throw IllegalStateException("Invalid AccountCreateResponse") + } + + companion object { + + /** Sanitized X account summary returned by connect and reauth. */ + @JvmStatic + fun ofSanitizedXAccount(sanitizedXAccount: SanitizedXAccount) = + AccountCreateResponse(sanitizedXAccount = sanitizedXAccount) + + /** The connection is still in progress. */ + @JvmStatic + fun ofXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ) = + AccountCreateResponse( + xAccountConnectionAttemptPending = xAccountConnectionAttemptPending + ) + + /** + * Resumable account connection challenge. Submit the email code to finish the same + * connection attempt. + */ + @JvmStatic + fun ofXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ) = AccountCreateResponse(xAccountConnectionChallenge = xAccountConnectionChallenge) + } + + /** + * An interface that defines how to map each variant of [AccountCreateResponse] to a value of + * type [T]. + */ + interface Visitor { + + /** Sanitized X account summary returned by connect and reauth. */ + fun visitSanitizedXAccount(sanitizedXAccount: SanitizedXAccount): T + + /** The connection is still in progress. */ + fun visitXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending: XAccountConnectionAttemptPending + ): T + + /** + * Resumable account connection challenge. Submit the email code to finish the same + * connection attempt. + */ + fun visitXAccountConnectionChallenge( + xAccountConnectionChallenge: XAccountConnectionChallenge + ): T + + /** + * Maps an unknown variant of [AccountCreateResponse] to a value of type [T]. + * + * An instance of [AccountCreateResponse] can contain an unknown variant if it was + * deserialized from data that doesn't match any known variant. For example, if the SDK is + * on an older version than the API, then the API may respond with new variants that the SDK + * is unaware of. + * + * @throws XTwitterScraperInvalidDataException in the default implementation. + */ + fun unknown(json: JsonValue?): T { + throw XTwitterScraperInvalidDataException("Unknown AccountCreateResponse: $json") + } + } + + internal class Deserializer : + BaseDeserializer(AccountCreateResponse::class) { + + override fun ObjectCodec.deserialize(node: JsonNode): AccountCreateResponse { + val json = JsonValue.fromJsonNode(node) + + val bestMatches = + sequenceOf( + tryDeserialize(node, jacksonTypeRef())?.let { + AccountCreateResponse(sanitizedXAccount = it, _json = json) + }, + tryDeserialize(node, jacksonTypeRef()) + ?.let { + AccountCreateResponse( + xAccountConnectionAttemptPending = it, + _json = json, + ) + }, + tryDeserialize(node, jacksonTypeRef())?.let { + AccountCreateResponse(xAccountConnectionChallenge = it, _json = json) + }, + ) + .filterNotNull() + .allMaxBy { it.validity() } + .toList() + return when (bestMatches.size) { + // This can happen if what we're deserializing is completely incompatible with all + // the possible variants (e.g. deserializing from boolean). + 0 -> AccountCreateResponse(_json = json) + 1 -> bestMatches.single() + // If there's more than one match with the highest validity, then use the first + // completely valid match, or simply the first match if none are completely valid. + else -> bestMatches.firstOrNull { it.isValid() } ?: bestMatches.first() + } + } + } + + internal class Serializer : + BaseSerializer(AccountCreateResponse::class) { + + override fun serialize( + value: AccountCreateResponse, + generator: JsonGenerator, + provider: SerializerProvider, + ) { + when { + value.sanitizedXAccount != null -> generator.writeObject(value.sanitizedXAccount) + value.xAccountConnectionAttemptPending != null -> + generator.writeObject(value.xAccountConnectionAttemptPending) + value.xAccountConnectionChallenge != null -> + generator.writeObject(value.xAccountConnectionChallenge) + value._json != null -> generator.writeObject(value._json) + else -> throw IllegalStateException("Invalid AccountCreateResponse") + } + } + } + + /** Sanitized X account summary returned by connect and reauth. */ + class SanitizedXAccount + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val createdAt: JsonField, + private val health: JsonField, + private val status: JsonValue, + private val xUserId: JsonField, + private val xUsername: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("createdAt") + @ExcludeMissing + createdAt: JsonField = JsonMissing.of(), + @JsonProperty("health") @ExcludeMissing health: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + @JsonProperty("xUserId") @ExcludeMissing xUserId: JsonField = JsonMissing.of(), + @JsonProperty("xUsername") + @ExcludeMissing + xUsername: JsonField = JsonMissing.of(), + ) : this(id, createdAt, health, status, xUserId, xUsername, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun createdAt(): OffsetDateTime = createdAt.getRequired("createdAt") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun health(): Health = health.getRequired("health") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("active") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun xUserId(): String = xUserId.getRequired("xUserId") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun xUsername(): String = xUsername.getRequired("xUsername") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [createdAt]. + * + * Unlike [createdAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("createdAt") + @ExcludeMissing + fun _createdAt(): JsonField = createdAt + + /** + * Returns the raw JSON value of [health]. + * + * Unlike [health], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("health") @ExcludeMissing fun _health(): JsonField = health + + /** + * Returns the raw JSON value of [xUserId]. + * + * Unlike [xUserId], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("xUserId") @ExcludeMissing fun _xUserId(): JsonField = xUserId + + /** + * Returns the raw JSON value of [xUsername]. + * + * Unlike [xUsername], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("xUsername") @ExcludeMissing fun _xUsername(): JsonField = xUsername + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [SanitizedXAccount]. + * + * The following fields are required: + * ```java + * .id() + * .createdAt() + * .health() + * .xUserId() + * .xUsername() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [SanitizedXAccount]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var createdAt: JsonField? = null + private var health: JsonField? = null + private var status: JsonValue = JsonValue.from("active") + private var xUserId: JsonField? = null + private var xUsername: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(sanitizedXAccount: SanitizedXAccount) = apply { + id = sanitizedXAccount.id + createdAt = sanitizedXAccount.createdAt + health = sanitizedXAccount.health + status = sanitizedXAccount.status + xUserId = sanitizedXAccount.xUserId + xUsername = sanitizedXAccount.xUsername + additionalProperties = sanitizedXAccount.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun createdAt(createdAt: OffsetDateTime) = createdAt(JsonField.of(createdAt)) + + /** + * Sets [Builder.createdAt] to an arbitrary JSON value. + * + * You should usually call [Builder.createdAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun createdAt(createdAt: JsonField) = apply { + this.createdAt = createdAt + } + + fun health(health: Health) = health(JsonField.of(health)) + + /** + * Sets [Builder.health] to an arbitrary JSON value. + * + * You should usually call [Builder.health] with a well-typed [Health] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun health(health: JsonField) = apply { this.health = health } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("active") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun xUserId(xUserId: String) = xUserId(JsonField.of(xUserId)) + + /** + * Sets [Builder.xUserId] to an arbitrary JSON value. + * + * You should usually call [Builder.xUserId] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun xUserId(xUserId: JsonField) = apply { this.xUserId = xUserId } + + fun xUsername(xUsername: String) = xUsername(JsonField.of(xUsername)) + + /** + * Sets [Builder.xUsername] to an arbitrary JSON value. + * + * You should usually call [Builder.xUsername] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun xUsername(xUsername: JsonField) = apply { this.xUsername = xUsername } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [SanitizedXAccount]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .createdAt() + * .health() + * .xUserId() + * .xUsername() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): SanitizedXAccount = + SanitizedXAccount( + checkRequired("id", id), + checkRequired("createdAt", createdAt), + checkRequired("health", health), + status, + checkRequired("xUserId", xUserId), + checkRequired("xUsername", xUsername), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): SanitizedXAccount = apply { + if (validated) { + return@apply + } + + id() + createdAt() + health().validate() + _status().let { + if (it != JsonValue.from("active")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + xUserId() + xUsername() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (createdAt.asKnown().isPresent) 1 else 0) + + (health.asKnown().getOrNull()?.validity() ?: 0) + + status.let { if (it == JsonValue.from("active")) 1 else 0 } + + (if (xUserId.asKnown().isPresent) 1 else 0) + + (if (xUsername.asKnown().isPresent) 1 else 0) + + class Health @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is + * on an older version than the API, then the API may respond with new members that the + * SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val HEALTHY = of("healthy") + + @JvmField val LOCKED = of("locked") + + @JvmField val NEEDS_REAUTH = of("needsReauth") + + @JvmField val RECOVERING = of("recovering") + + @JvmField val SUSPENDED = of("suspended") + + @JvmField val TEMPORARY_ISSUE = of("temporaryIssue") + + @JvmStatic fun of(value: String) = Health(JsonField.of(value)) + } + + /** An enum containing [Health]'s known values. */ + enum class Known { + HEALTHY, + LOCKED, + NEEDS_REAUTH, + RECOVERING, + SUSPENDED, + TEMPORARY_ISSUE, + } + + /** + * An enum containing [Health]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Health] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + HEALTHY, + LOCKED, + NEEDS_REAUTH, + RECOVERING, + SUSPENDED, + TEMPORARY_ISSUE, + /** + * An enum member indicating that [Health] was instantiated with an unknown value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you + * want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + HEALTHY -> Value.HEALTHY + LOCKED -> Value.LOCKED + NEEDS_REAUTH -> Value.NEEDS_REAUTH + RECOVERING -> Value.RECOVERING + SUSPENDED -> Value.SUSPENDED + TEMPORARY_ISSUE -> Value.TEMPORARY_ISSUE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + HEALTHY -> Known.HEALTHY + LOCKED -> Known.LOCKED + NEEDS_REAUTH -> Known.NEEDS_REAUTH + RECOVERING -> Known.RECOVERING + SUSPENDED -> Known.SUSPENDED + TEMPORARY_ISSUE -> Known.TEMPORARY_ISSUE + else -> throw XTwitterScraperInvalidDataException("Unknown Health: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not + * have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Health = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Health && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is SanitizedXAccount && + id == other.id && + createdAt == other.createdAt && + health == other.health && + status == other.status && + xUserId == other.xUserId && + xUsername == other.xUsername && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, createdAt, health, status, xUserId, xUsername, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "SanitizedXAccount{id=$id, createdAt=$createdAt, health=$health, status=$status, xUserId=$xUserId, xUsername=$xUsername, additionalProperties=$additionalProperties}" + } + + /** The connection is still in progress. */ + class XAccountConnectionAttemptPending + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val object_: JsonValue, + private val pollAfterMs: JsonField, + private val status: JsonValue, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("pollAfterMs") + @ExcludeMissing + pollAfterMs: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + ) : this(id, object_, pollAfterMs, status, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pollAfterMs(): Long = pollAfterMs.getRequired("pollAfterMs") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("pending") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [pollAfterMs]. + * + * Unlike [pollAfterMs], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("pollAfterMs") + @ExcludeMissing + fun _pollAfterMs(): JsonField = pollAfterMs + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionAttemptPending]. + * + * The following fields are required: + * ```java + * .id() + * .pollAfterMs() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionAttemptPending]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_attempt") + private var pollAfterMs: JsonField? = null + private var status: JsonValue = JsonValue.from("pending") + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionAttemptPending: XAccountConnectionAttemptPending) = + apply { + id = xAccountConnectionAttemptPending.id + object_ = xAccountConnectionAttemptPending.object_ + pollAfterMs = xAccountConnectionAttemptPending.pollAfterMs + status = xAccountConnectionAttemptPending.status + additionalProperties = + xAccountConnectionAttemptPending.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_attempt") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonValue) = apply { this.object_ = object_ } + + fun pollAfterMs(pollAfterMs: Long) = pollAfterMs(JsonField.of(pollAfterMs)) + + /** + * Sets [Builder.pollAfterMs] to an arbitrary JSON value. + * + * You should usually call [Builder.pollAfterMs] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pollAfterMs(pollAfterMs: JsonField) = apply { this.pollAfterMs = pollAfterMs } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("pending") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionAttemptPending]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .pollAfterMs() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionAttemptPending = + XAccountConnectionAttemptPending( + checkRequired("id", id), + object_, + checkRequired("pollAfterMs", pollAfterMs), + status, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionAttemptPending = apply { + if (validated) { + return@apply + } + + id() + _object_().let { + if (it != JsonValue.from("x_account_connection_attempt")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + pollAfterMs() + _status().let { + if (it != JsonValue.from("pending")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + object_.let { if (it == JsonValue.from("x_account_connection_attempt")) 1 else 0 } + + (if (pollAfterMs.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("pending")) 1 else 0 } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionAttemptPending && + id == other.id && + object_ == other.object_ && + pollAfterMs == other.pollAfterMs && + status == other.status && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, object_, pollAfterMs, status, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionAttemptPending{id=$id, object_=$object_, pollAfterMs=$pollAfterMs, status=$status, additionalProperties=$additionalProperties}" } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + /** + * Resumable account connection challenge. Submit the email code to finish the same connection + * attempt. + */ + class XAccountConnectionChallenge + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val expiresAt: JsonField, + private val message: JsonField, + private val object_: JsonValue, + private val status: JsonValue, + private val username: JsonField, + private val additionalProperties: MutableMap, + ) { - override fun hashCode(): Int = hashCode + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("expiresAt") + @ExcludeMissing + expiresAt: JsonField = JsonMissing.of(), + @JsonProperty("message") @ExcludeMissing message: JsonField = JsonMissing.of(), + @JsonProperty("object") @ExcludeMissing object_: JsonValue = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), + @JsonProperty("username") + @ExcludeMissing + username: JsonField = JsonMissing.of(), + ) : this(id, expiresAt, message, object_, status, username, mutableMapOf()) - override fun toString() = "AccountCreateResponse{additionalProperties=$additionalProperties}" + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun id(): String = id.getRequired("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun expiresAt(): OffsetDateTime = expiresAt.getRequired("expiresAt") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun message(): String = message.getRequired("message") + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("x_account_connection_challenge") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("object") @ExcludeMissing fun _object_(): JsonValue = object_ + + /** + * Expected to always return the following: + * ```java + * JsonValue.from("requires_email_code") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server + * responded with an unexpected value). + */ + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun username(): String = username.getRequired("username") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [expiresAt]. + * + * Unlike [expiresAt], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("expiresAt") + @ExcludeMissing + fun _expiresAt(): JsonField = expiresAt + + /** + * Returns the raw JSON value of [message]. + * + * Unlike [message], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("message") @ExcludeMissing fun _message(): JsonField = message + + /** + * Returns the raw JSON value of [username]. + * + * Unlike [username], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of + * [XAccountConnectionChallenge]. + * + * The following fields are required: + * ```java + * .id() + * .expiresAt() + * .message() + * .username() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [XAccountConnectionChallenge]. */ + class Builder internal constructor() { + + private var id: JsonField? = null + private var expiresAt: JsonField? = null + private var message: JsonField? = null + private var object_: JsonValue = JsonValue.from("x_account_connection_challenge") + private var status: JsonValue = JsonValue.from("requires_email_code") + private var username: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(xAccountConnectionChallenge: XAccountConnectionChallenge) = apply { + id = xAccountConnectionChallenge.id + expiresAt = xAccountConnectionChallenge.expiresAt + message = xAccountConnectionChallenge.message + object_ = xAccountConnectionChallenge.object_ + status = xAccountConnectionChallenge.status + username = xAccountConnectionChallenge.username + additionalProperties = + xAccountConnectionChallenge.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun expiresAt(expiresAt: OffsetDateTime) = expiresAt(JsonField.of(expiresAt)) + + /** + * Sets [Builder.expiresAt] to an arbitrary JSON value. + * + * You should usually call [Builder.expiresAt] with a well-typed [OffsetDateTime] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun expiresAt(expiresAt: JsonField) = apply { + this.expiresAt = expiresAt + } + + fun message(message: String) = message(JsonField.of(message)) + + /** + * Sets [Builder.message] to an arbitrary JSON value. + * + * You should usually call [Builder.message] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun message(message: JsonField) = apply { this.message = message } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("x_account_connection_challenge") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun object_(object_: JsonValue) = apply { this.object_ = object_ } + + /** + * Sets the field to an arbitrary JSON value. + * + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("requires_email_code") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun status(status: JsonValue) = apply { this.status = status } + + fun username(username: String) = username(JsonField.of(username)) + + /** + * Sets [Builder.username] to an arbitrary JSON value. + * + * You should usually call [Builder.username] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun username(username: JsonField) = apply { this.username = username } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [XAccountConnectionChallenge]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .id() + * .expiresAt() + * .message() + * .username() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): XAccountConnectionChallenge = + XAccountConnectionChallenge( + checkRequired("id", id), + checkRequired("expiresAt", expiresAt), + checkRequired("message", message), + object_, + status, + checkRequired("username", username), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): XAccountConnectionChallenge = apply { + if (validated) { + return@apply + } + + id() + expiresAt() + message() + _object_().let { + if (it != JsonValue.from("x_account_connection_challenge")) { + throw XTwitterScraperInvalidDataException("'object_' is invalid, received $it") + } + } + _status().let { + if (it != JsonValue.from("requires_email_code")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } + username() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (expiresAt.asKnown().isPresent) 1 else 0) + + (if (message.asKnown().isPresent) 1 else 0) + + object_.let { + if (it == JsonValue.from("x_account_connection_challenge")) 1 else 0 + } + + status.let { if (it == JsonValue.from("requires_email_code")) 1 else 0 } + + (if (username.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is XAccountConnectionChallenge && + id == other.id && + expiresAt == other.expiresAt && + message == other.message && + object_ == other.object_ && + status == other.status && + username == other.username && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, expiresAt, message, object_, status, username, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "XAccountConnectionChallenge{id=$id, expiresAt=$expiresAt, message=$message, object_=$object_, status=$status, username=$username, additionalProperties=$additionalProperties}" + } } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponse.kt index a6f0341..c2bf1c4 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponse.kt @@ -29,7 +29,7 @@ private constructor( private val id: JsonField, private val createdAt: JsonField, private val health: JsonField, - private val status: JsonField, + private val status: JsonValue, private val xUserId: JsonField, private val xUsername: JsonField, private val additionalProperties: MutableMap, @@ -42,7 +42,7 @@ private constructor( @ExcludeMissing createdAt: JsonField = JsonMissing.of(), @JsonProperty("health") @ExcludeMissing health: JsonField = JsonMissing.of(), - @JsonProperty("status") @ExcludeMissing status: JsonField = JsonMissing.of(), + @JsonProperty("status") @ExcludeMissing status: JsonValue = JsonMissing.of(), @JsonProperty("xUserId") @ExcludeMissing xUserId: JsonField = JsonMissing.of(), @JsonProperty("xUsername") @ExcludeMissing xUsername: JsonField = JsonMissing.of(), ) : this(id, createdAt, health, status, xUserId, xUsername, mutableMapOf()) @@ -66,10 +66,15 @@ private constructor( fun health(): Health = health.getRequired("health") /** - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is - * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + * Expected to always return the following: + * ```java + * JsonValue.from("active") + * ``` + * + * However, this method can be useful for debugging and logging (e.g. if the server responded + * with an unexpected value). */ - fun status(): String = status.getRequired("status") + @JsonProperty("status") @ExcludeMissing fun _status(): JsonValue = status /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is @@ -106,13 +111,6 @@ private constructor( */ @JsonProperty("health") @ExcludeMissing fun _health(): JsonField = health - /** - * Returns the raw JSON value of [status]. - * - * Unlike [status], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("status") @ExcludeMissing fun _status(): JsonField = status - /** * Returns the raw JSON value of [xUserId]. * @@ -149,7 +147,6 @@ private constructor( * .id() * .createdAt() * .health() - * .status() * .xUserId() * .xUsername() * ``` @@ -163,7 +160,7 @@ private constructor( private var id: JsonField? = null private var createdAt: JsonField? = null private var health: JsonField? = null - private var status: JsonField? = null + private var status: JsonValue = JsonValue.from("active") private var xUserId: JsonField? = null private var xUsername: JsonField? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -210,15 +207,19 @@ private constructor( */ fun health(health: JsonField) = apply { this.health = health } - fun status(status: String) = status(JsonField.of(status)) - /** - * Sets [Builder.status] to an arbitrary JSON value. + * Sets the field to an arbitrary JSON value. * - * You should usually call [Builder.status] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * It is usually unnecessary to call this method because the field defaults to the + * following: + * ```java + * JsonValue.from("active") + * ``` + * + * This method is primarily for setting the field to an undocumented or not yet supported + * value. */ - fun status(status: JsonField) = apply { this.status = status } + fun status(status: JsonValue) = apply { this.status = status } fun xUserId(xUserId: String) = xUserId(JsonField.of(xUserId)) @@ -270,7 +271,6 @@ private constructor( * .id() * .createdAt() * .health() - * .status() * .xUserId() * .xUsername() * ``` @@ -282,7 +282,7 @@ private constructor( checkRequired("id", id), checkRequired("createdAt", createdAt), checkRequired("health", health), - checkRequired("status", status), + status, checkRequired("xUserId", xUserId), checkRequired("xUsername", xUsername), additionalProperties.toMutableMap(), @@ -307,7 +307,11 @@ private constructor( id() createdAt() health().validate() - status() + _status().let { + if (it != JsonValue.from("active")) { + throw XTwitterScraperInvalidDataException("'status' is invalid, received $it") + } + } xUserId() xUsername() validated = true @@ -331,7 +335,7 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (health.asKnown().getOrNull()?.validity() ?: 0) + - (if (status.asKnown().isPresent) 1 else 0) + + status.let { if (it == JsonValue.from("active")) 1 else 0 } + (if (xUserId.asKnown().isPresent) 1 else 0) + (if (xUsername.asKnown().isPresent) 1 else 0) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponse.kt index f2fd30b..e7ab8d9 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponse.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponse.kt @@ -184,14 +184,12 @@ private constructor( private val creator: JsonField, private val description: JsonField, private val invitesPolicy: JsonField, - private val isMember: JsonField, private val isNsfw: JsonField, private val joinPolicy: JsonField, private val memberCount: JsonField, private val moderatorCount: JsonField, private val name: JsonField, private val primaryTopic: JsonField, - private val role: JsonField, private val rules: JsonField>, private val additionalProperties: MutableMap, ) { @@ -212,9 +210,6 @@ private constructor( @JsonProperty("invites_policy") @ExcludeMissing invitesPolicy: JsonField = JsonMissing.of(), - @JsonProperty("is_member") - @ExcludeMissing - isMember: JsonField = JsonMissing.of(), @JsonProperty("is_nsfw") @ExcludeMissing isNsfw: JsonField = JsonMissing.of(), @JsonProperty("join_policy") @ExcludeMissing @@ -229,7 +224,6 @@ private constructor( @JsonProperty("primary_topic") @ExcludeMissing primaryTopic: JsonField = JsonMissing.of(), - @JsonProperty("role") @ExcludeMissing role: JsonField = JsonMissing.of(), @JsonProperty("rules") @ExcludeMissing rules: JsonField> = JsonMissing.of(), ) : this( id, @@ -238,14 +232,12 @@ private constructor( creator, description, invitesPolicy, - isMember, isNsfw, joinPolicy, memberCount, moderatorCount, name, primaryTopic, - role, rules, mutableMapOf(), ) @@ -297,14 +289,6 @@ private constructor( */ fun invitesPolicy(): Optional = invitesPolicy.getOptional("invites_policy") - /** - * Whether the authenticated viewer is a member - * - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun isMember(): Optional = isMember.getOptional("is_member") - /** * Whether the community is marked sensitive * @@ -353,14 +337,6 @@ private constructor( */ fun primaryTopic(): Optional = primaryTopic.getOptional("primary_topic") - /** - * Authenticated viewer's community role - * - * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type - * (e.g. if the server responded with an unexpected value). - */ - fun role(): Optional = role.getOptional("role") - /** * Community rules * @@ -416,13 +392,6 @@ private constructor( @ExcludeMissing fun _invitesPolicy(): JsonField = invitesPolicy - /** - * Returns the raw JSON value of [isMember]. - * - * Unlike [isMember], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("is_member") @ExcludeMissing fun _isMember(): JsonField = isMember - /** * Returns the raw JSON value of [isNsfw]. * @@ -475,13 +444,6 @@ private constructor( @ExcludeMissing fun _primaryTopic(): JsonField = primaryTopic - /** - * Returns the raw JSON value of [role]. - * - * Unlike [role], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("role") @ExcludeMissing fun _role(): JsonField = role - /** * Returns the raw JSON value of [rules]. * @@ -523,14 +485,12 @@ private constructor( private var creator: JsonField = JsonMissing.of() private var description: JsonField = JsonMissing.of() private var invitesPolicy: JsonField = JsonMissing.of() - private var isMember: JsonField = JsonMissing.of() private var isNsfw: JsonField = JsonMissing.of() private var joinPolicy: JsonField = JsonMissing.of() private var memberCount: JsonField = JsonMissing.of() private var moderatorCount: JsonField = JsonMissing.of() private var name: JsonField = JsonMissing.of() private var primaryTopic: JsonField = JsonMissing.of() - private var role: JsonField = JsonMissing.of() private var rules: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -542,14 +502,12 @@ private constructor( creator = community.creator description = community.description invitesPolicy = community.invitesPolicy - isMember = community.isMember isNsfw = community.isNsfw joinPolicy = community.joinPolicy memberCount = community.memberCount moderatorCount = community.moderatorCount name = community.name primaryTopic = community.primaryTopic - role = community.role rules = community.rules.map { it.toMutableList() } additionalProperties = community.additionalProperties.toMutableMap() } @@ -629,18 +587,6 @@ private constructor( this.invitesPolicy = invitesPolicy } - /** Whether the authenticated viewer is a member */ - fun isMember(isMember: Boolean) = isMember(JsonField.of(isMember)) - - /** - * Sets [Builder.isMember] to an arbitrary JSON value. - * - * You should usually call [Builder.isMember] with a well-typed [Boolean] value instead. - * This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun isMember(isMember: JsonField) = apply { this.isMember = isMember } - /** Whether the community is marked sensitive */ fun isNsfw(isNsfw: Boolean) = isNsfw(JsonField.of(isNsfw)) @@ -717,18 +663,6 @@ private constructor( this.primaryTopic = primaryTopic } - /** Authenticated viewer's community role */ - fun role(role: String) = role(JsonField.of(role)) - - /** - * Sets [Builder.role] to an arbitrary JSON value. - * - * You should usually call [Builder.role] with a well-typed [String] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported - * value. - */ - fun role(role: JsonField) = apply { this.role = role } - /** Community rules */ fun rules(rules: List) = rules(JsonField.of(rules)) @@ -794,14 +728,12 @@ private constructor( creator, description, invitesPolicy, - isMember, isNsfw, joinPolicy, memberCount, moderatorCount, name, primaryTopic, - role, (rules ?: JsonMissing.of()).map { it.toImmutable() }, additionalProperties.toMutableMap(), ) @@ -829,14 +761,12 @@ private constructor( creator().ifPresent { it.validate() } description() invitesPolicy() - isMember() isNsfw() joinPolicy() memberCount() moderatorCount() name() primaryTopic().ifPresent { it.validate() } - role() rules().ifPresent { it.forEach { it.validate() } } validated = true } @@ -863,14 +793,12 @@ private constructor( (creator.asKnown().getOrNull()?.validity() ?: 0) + (if (description.asKnown().isPresent) 1 else 0) + (if (invitesPolicy.asKnown().isPresent) 1 else 0) + - (if (isMember.asKnown().isPresent) 1 else 0) + (if (isNsfw.asKnown().isPresent) 1 else 0) + (if (joinPolicy.asKnown().isPresent) 1 else 0) + (if (memberCount.asKnown().isPresent) 1 else 0) + (if (moderatorCount.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + (primaryTopic.asKnown().getOrNull()?.validity() ?: 0) + - (if (role.asKnown().isPresent) 1 else 0) + (rules.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) class Creator @@ -1576,14 +1504,12 @@ private constructor( creator == other.creator && description == other.description && invitesPolicy == other.invitesPolicy && - isMember == other.isMember && isNsfw == other.isNsfw && joinPolicy == other.joinPolicy && memberCount == other.memberCount && moderatorCount == other.moderatorCount && name == other.name && primaryTopic == other.primaryTopic && - role == other.role && rules == other.rules && additionalProperties == other.additionalProperties } @@ -1596,14 +1522,12 @@ private constructor( creator, description, invitesPolicy, - isMember, isNsfw, joinPolicy, memberCount, moderatorCount, name, primaryTopic, - role, rules, additionalProperties, ) @@ -1612,7 +1536,7 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "Community{id=$id, bannerUrl=$bannerUrl, createdAt=$createdAt, creator=$creator, description=$description, invitesPolicy=$invitesPolicy, isMember=$isMember, isNsfw=$isNsfw, joinPolicy=$joinPolicy, memberCount=$memberCount, moderatorCount=$moderatorCount, name=$name, primaryTopic=$primaryTopic, role=$role, rules=$rules, additionalProperties=$additionalProperties}" + "Community{id=$id, bannerUrl=$bannerUrl, createdAt=$createdAt, creator=$creator, description=$description, invitesPolicy=$invitesPolicy, isNsfw=$isNsfw, joinPolicy=$joinPolicy, memberCount=$memberCount, moderatorCount=$moderatorCount, name=$name, primaryTopic=$primaryTopic, rules=$rules, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveSearchParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveSearchParams.kt index ae91fa7..307093b 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveSearchParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveSearchParams.kt @@ -40,10 +40,8 @@ private constructor( fun cursor(): Optional = Optional.ofNullable(cursor) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -108,10 +106,8 @@ private constructor( fun cursor(cursor: Optional) = cursor(cursor.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListByCommunityParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListByCommunityParams.kt index b300ef7..d285fe1 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListByCommunityParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListByCommunityParams.kt @@ -29,10 +29,8 @@ private constructor( fun cursor(): Optional = Optional.ofNullable(cursor) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -84,10 +82,8 @@ private constructor( fun cursor(cursor: Optional) = cursor(cursor.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListParams.kt index 1b20609..3f82af8 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/communities/tweets/TweetListParams.kt @@ -40,10 +40,8 @@ private constructor( fun cursor(): Optional = Optional.ofNullable(cursor) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -107,10 +105,8 @@ private constructor( fun cursor(cursor: Optional) = cursor(cursor.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/lists/ListRetrieveTweetsParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/lists/ListRetrieveTweetsParams.kt index 4e6993a..27ffc5f 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/lists/ListRetrieveTweetsParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/lists/ListRetrieveTweetsParams.kt @@ -35,10 +35,8 @@ private constructor( fun includeReplies(): Optional = Optional.ofNullable(includeReplies) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -116,10 +114,8 @@ private constructor( includeReplies(includeReplies.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthor.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthor.kt index 10ceae9..87062ee 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthor.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthor.kt @@ -34,36 +34,48 @@ private constructor( private val id: JsonField, private val name: JsonField, private val username: JsonField, + private val affiliatesHighlightedLabel: JsonField, private val automatedBy: JsonField, - private val canDm: JsonField, + private val businessAccountAffiliatesCount: JsonField, private val communityRole: JsonField, private val coverPicture: JsonField, private val createdAt: JsonField, + private val creatorSubscriptionsCount: JsonField, private val description: JsonField, private val favouritesCount: JsonField, private val followers: JsonField, private val following: JsonField, private val hasCustomTimelines: JsonField, + private val hasGraduatedAccess: JsonField, + private val hasHiddenSubscriptionsOnProfile: JsonField, + private val highlightsInfo: JsonField, + private val identityVerification: JsonField, private val isAutomated: JsonField, private val isBlueVerified: JsonField, + private val isProfileTranslatable: JsonField, private val isTranslator: JsonField, private val isVerified: JsonField, private val location: JsonField, private val mediaCount: JsonField, + private val parodyCommentaryFanLabel: JsonField, private val pinnedTweetIds: JsonField>, private val possiblySensitive: JsonField, private val profileBio: JsonField, private val profileBannerUrl: JsonField, + private val profileDescriptionLanguage: JsonField, + private val profileImageShape: JsonField, + private val profileInterstitialType: JsonField, private val profilePicture: JsonField, + private val profileSortEnabled: JsonField, + private val profileTranslatorType: JsonField, private val protected_: JsonField, private val statusesCount: JsonField, + private val superFollowEligible: JsonField, private val unavailable: JsonField, private val unavailableReason: JsonField, private val url: JsonField, private val verified: JsonField, private val verifiedType: JsonField, - private val viewerFollowedBy: JsonField, - private val viewerFollowing: JsonField, private val withheldInCountries: JsonField>, private val additionalProperties: MutableMap, ) { @@ -73,10 +85,16 @@ private constructor( @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), @JsonProperty("username") @ExcludeMissing username: JsonField = JsonMissing.of(), + @JsonProperty("affiliatesHighlightedLabel") + @ExcludeMissing + affiliatesHighlightedLabel: JsonField = + JsonMissing.of(), @JsonProperty("automatedBy") @ExcludeMissing automatedBy: JsonField = JsonMissing.of(), - @JsonProperty("canDm") @ExcludeMissing canDm: JsonField = JsonMissing.of(), + @JsonProperty("businessAccountAffiliatesCount") + @ExcludeMissing + businessAccountAffiliatesCount: JsonField = JsonMissing.of(), @JsonProperty("communityRole") @ExcludeMissing communityRole: JsonField = JsonMissing.of(), @@ -84,6 +102,9 @@ private constructor( @ExcludeMissing coverPicture: JsonField = JsonMissing.of(), @JsonProperty("createdAt") @ExcludeMissing createdAt: JsonField = JsonMissing.of(), + @JsonProperty("creatorSubscriptionsCount") + @ExcludeMissing + creatorSubscriptionsCount: JsonField = JsonMissing.of(), @JsonProperty("description") @ExcludeMissing description: JsonField = JsonMissing.of(), @@ -95,12 +116,27 @@ private constructor( @JsonProperty("hasCustomTimelines") @ExcludeMissing hasCustomTimelines: JsonField = JsonMissing.of(), + @JsonProperty("hasGraduatedAccess") + @ExcludeMissing + hasGraduatedAccess: JsonField = JsonMissing.of(), + @JsonProperty("hasHiddenSubscriptionsOnProfile") + @ExcludeMissing + hasHiddenSubscriptionsOnProfile: JsonField = JsonMissing.of(), + @JsonProperty("highlightsInfo") + @ExcludeMissing + highlightsInfo: JsonField = JsonMissing.of(), + @JsonProperty("identityVerification") + @ExcludeMissing + identityVerification: JsonField = JsonMissing.of(), @JsonProperty("isAutomated") @ExcludeMissing isAutomated: JsonField = JsonMissing.of(), @JsonProperty("isBlueVerified") @ExcludeMissing isBlueVerified: JsonField = JsonMissing.of(), + @JsonProperty("isProfileTranslatable") + @ExcludeMissing + isProfileTranslatable: JsonField = JsonMissing.of(), @JsonProperty("isTranslator") @ExcludeMissing isTranslator: JsonField = JsonMissing.of(), @@ -109,6 +145,9 @@ private constructor( isVerified: JsonField = JsonMissing.of(), @JsonProperty("location") @ExcludeMissing location: JsonField = JsonMissing.of(), @JsonProperty("mediaCount") @ExcludeMissing mediaCount: JsonField = JsonMissing.of(), + @JsonProperty("parodyCommentaryFanLabel") + @ExcludeMissing + parodyCommentaryFanLabel: JsonField = JsonMissing.of(), @JsonProperty("pinnedTweetIds") @ExcludeMissing pinnedTweetIds: JsonField> = JsonMissing.of(), @@ -121,15 +160,33 @@ private constructor( @JsonProperty("profileBannerUrl") @ExcludeMissing profileBannerUrl: JsonField = JsonMissing.of(), + @JsonProperty("profileDescriptionLanguage") + @ExcludeMissing + profileDescriptionLanguage: JsonField = JsonMissing.of(), + @JsonProperty("profileImageShape") + @ExcludeMissing + profileImageShape: JsonField = JsonMissing.of(), + @JsonProperty("profileInterstitialType") + @ExcludeMissing + profileInterstitialType: JsonField = JsonMissing.of(), @JsonProperty("profilePicture") @ExcludeMissing profilePicture: JsonField = JsonMissing.of(), + @JsonProperty("profileSortEnabled") + @ExcludeMissing + profileSortEnabled: JsonField = JsonMissing.of(), + @JsonProperty("profileTranslatorType") + @ExcludeMissing + profileTranslatorType: JsonField = JsonMissing.of(), @JsonProperty("protected") @ExcludeMissing protected_: JsonField = JsonMissing.of(), @JsonProperty("statusesCount") @ExcludeMissing statusesCount: JsonField = JsonMissing.of(), + @JsonProperty("superFollowEligible") + @ExcludeMissing + superFollowEligible: JsonField = JsonMissing.of(), @JsonProperty("unavailable") @ExcludeMissing unavailable: JsonField = JsonMissing.of(), @@ -141,12 +198,6 @@ private constructor( @JsonProperty("verifiedType") @ExcludeMissing verifiedType: JsonField = JsonMissing.of(), - @JsonProperty("viewerFollowedBy") - @ExcludeMissing - viewerFollowedBy: JsonField = JsonMissing.of(), - @JsonProperty("viewerFollowing") - @ExcludeMissing - viewerFollowing: JsonField = JsonMissing.of(), @JsonProperty("withheldInCountries") @ExcludeMissing withheldInCountries: JsonField> = JsonMissing.of(), @@ -154,36 +205,48 @@ private constructor( id, name, username, + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, pinnedTweetIds, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, withheldInCountries, mutableMapOf(), ) @@ -193,36 +256,48 @@ private constructor( .id(id) .name(name) .username(username) + .affiliatesHighlightedLabel(affiliatesHighlightedLabel) .automatedBy(automatedBy) - .canDm(canDm) + .businessAccountAffiliatesCount(businessAccountAffiliatesCount) .communityRole(communityRole) .coverPicture(coverPicture) .createdAt(createdAt) + .creatorSubscriptionsCount(creatorSubscriptionsCount) .description(description) .favouritesCount(favouritesCount) .followers(followers) .following(following) .hasCustomTimelines(hasCustomTimelines) + .hasGraduatedAccess(hasGraduatedAccess) + .hasHiddenSubscriptionsOnProfile(hasHiddenSubscriptionsOnProfile) + .highlightsInfo(highlightsInfo) + .identityVerification(identityVerification) .isAutomated(isAutomated) .isBlueVerified(isBlueVerified) + .isProfileTranslatable(isProfileTranslatable) .isTranslator(isTranslator) .isVerified(isVerified) .location(location) .mediaCount(mediaCount) + .parodyCommentaryFanLabel(parodyCommentaryFanLabel) .pinnedTweetIds(pinnedTweetIds) .possiblySensitive(possiblySensitive) .profileBio(profileBio) .profileBannerUrl(profileBannerUrl) + .profileDescriptionLanguage(profileDescriptionLanguage) + .profileImageShape(profileImageShape) + .profileInterstitialType(profileInterstitialType) .profilePicture(profilePicture) + .profileSortEnabled(profileSortEnabled) + .profileTranslatorType(profileTranslatorType) .protected_(protected_) .statusesCount(statusesCount) + .superFollowEligible(superFollowEligible) .unavailable(unavailable) .unavailableReason(unavailableReason) .url(url) .verified(verified) .verifiedType(verifiedType) - .viewerFollowedBy(viewerFollowedBy) - .viewerFollowing(viewerFollowing) .withheldInCountries(withheldInCountries) .build() @@ -244,6 +319,15 @@ private constructor( */ fun username(): String = username.getRequired("username") + /** + * Organization affiliation label shown on an X profile. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun affiliatesHighlightedLabel(): Optional = + affiliatesHighlightedLabel.getOptional("affiliatesHighlightedLabel") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -254,7 +338,8 @@ private constructor( * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun canDm(): Optional = canDm.getOptional("canDm") + fun businessAccountAffiliatesCount(): Optional = + businessAccountAffiliatesCount.getOptional("businessAccountAffiliatesCount") /** * Community role when returned by community member reads @@ -276,6 +361,13 @@ private constructor( */ fun createdAt(): Optional = createdAt.getOptional("createdAt") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun creatorSubscriptionsCount(): Optional = + creatorSubscriptionsCount.getOptional("creatorSubscriptionsCount") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -307,6 +399,38 @@ private constructor( fun hasCustomTimelines(): Optional = hasCustomTimelines.getOptional("hasCustomTimelines") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun hasGraduatedAccess(): Optional = + hasGraduatedAccess.getOptional("hasGraduatedAccess") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun hasHiddenSubscriptionsOnProfile(): Optional = + hasHiddenSubscriptionsOnProfile.getOptional("hasHiddenSubscriptionsOnProfile") + + /** + * Profile highlight availability and count metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun highlightsInfo(): Optional = + highlightsInfo.getOptional("highlightsInfo") + + /** + * Identity verification metadata displayed by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun identityVerification(): Optional = + identityVerification.getOptional("identityVerification") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -321,6 +445,13 @@ private constructor( */ fun isBlueVerified(): Optional = isBlueVerified.getOptional("isBlueVerified") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isProfileTranslatable(): Optional = + isProfileTranslatable.getOptional("isProfileTranslatable") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -347,6 +478,13 @@ private constructor( */ fun mediaCount(): Optional = mediaCount.getOptional("mediaCount") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun parodyCommentaryFanLabel(): Optional = + parodyCommentaryFanLabel.getOptional("parodyCommentaryFanLabel") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -375,6 +513,26 @@ private constructor( */ fun profileBannerUrl(): Optional = profileBannerUrl.getOptional("profileBannerUrl") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileDescriptionLanguage(): Optional = + profileDescriptionLanguage.getOptional("profileDescriptionLanguage") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileImageShape(): Optional = profileImageShape.getOptional("profileImageShape") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun profileInterstitialType(): Optional = + profileInterstitialType.getOptional("profileInterstitialType") + /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). @@ -382,64 +540,69 @@ private constructor( fun profilePicture(): Optional = profilePicture.getOptional("profilePicture") /** - * Whether the profile protects its posts - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun protected_(): Optional = protected_.getOptional("protected") + fun profileSortEnabled(): Optional = + profileSortEnabled.getOptional("profileSortEnabled") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun statusesCount(): Optional = statusesCount.getOptional("statusesCount") + fun profileTranslatorType(): Optional = + profileTranslatorType.getOptional("profileTranslatorType") /** + * Whether the profile protects its posts + * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun unavailable(): Optional = unavailable.getOptional("unavailable") + fun protected_(): Optional = protected_.getOptional("protected") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun unavailableReason(): Optional = unavailableReason.getOptional("unavailableReason") + fun statusesCount(): Optional = statusesCount.getOptional("statusesCount") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun url(): Optional = url.getOptional("url") + fun superFollowEligible(): Optional = + superFollowEligible.getOptional("superFollowEligible") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verified(): Optional = verified.getOptional("verified") + fun unavailable(): Optional = unavailable.getOptional("unavailable") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun verifiedType(): Optional = verifiedType.getOptional("verifiedType") + fun unavailableReason(): Optional = unavailableReason.getOptional("unavailableReason") /** - * Whether this profile follows the authenticated viewer - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun viewerFollowedBy(): Optional = viewerFollowedBy.getOptional("viewerFollowedBy") + fun url(): Optional = url.getOptional("url") /** - * Whether the authenticated viewer follows this profile - * * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if * the server responded with an unexpected value). */ - fun viewerFollowing(): Optional = viewerFollowing.getOptional("viewerFollowing") + fun verified(): Optional = verified.getOptional("verified") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun verifiedType(): Optional = verifiedType.getOptional("verifiedType") /** * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if @@ -469,6 +632,17 @@ private constructor( */ @JsonProperty("username") @ExcludeMissing fun _username(): JsonField = username + /** + * Returns the raw JSON value of [affiliatesHighlightedLabel]. + * + * Unlike [affiliatesHighlightedLabel], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("affiliatesHighlightedLabel") + @ExcludeMissing + fun _affiliatesHighlightedLabel(): JsonField = + affiliatesHighlightedLabel + /** * Returns the raw JSON value of [automatedBy]. * @@ -477,11 +651,14 @@ private constructor( @JsonProperty("automatedBy") @ExcludeMissing fun _automatedBy(): JsonField = automatedBy /** - * Returns the raw JSON value of [canDm]. + * Returns the raw JSON value of [businessAccountAffiliatesCount]. * - * Unlike [canDm], this method doesn't throw if the JSON field has an unexpected type. + * Unlike [businessAccountAffiliatesCount], this method doesn't throw if the JSON field has an + * unexpected type. */ - @JsonProperty("canDm") @ExcludeMissing fun _canDm(): JsonField = canDm + @JsonProperty("businessAccountAffiliatesCount") + @ExcludeMissing + fun _businessAccountAffiliatesCount(): JsonField = businessAccountAffiliatesCount /** * Returns the raw JSON value of [communityRole]. @@ -508,6 +685,16 @@ private constructor( */ @JsonProperty("createdAt") @ExcludeMissing fun _createdAt(): JsonField = createdAt + /** + * Returns the raw JSON value of [creatorSubscriptionsCount]. + * + * Unlike [creatorSubscriptionsCount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("creatorSubscriptionsCount") + @ExcludeMissing + fun _creatorSubscriptionsCount(): JsonField = creatorSubscriptionsCount + /** * Returns the raw JSON value of [description]. * @@ -548,6 +735,45 @@ private constructor( @ExcludeMissing fun _hasCustomTimelines(): JsonField = hasCustomTimelines + /** + * Returns the raw JSON value of [hasGraduatedAccess]. + * + * Unlike [hasGraduatedAccess], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("hasGraduatedAccess") + @ExcludeMissing + fun _hasGraduatedAccess(): JsonField = hasGraduatedAccess + + /** + * Returns the raw JSON value of [hasHiddenSubscriptionsOnProfile]. + * + * Unlike [hasHiddenSubscriptionsOnProfile], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("hasHiddenSubscriptionsOnProfile") + @ExcludeMissing + fun _hasHiddenSubscriptionsOnProfile(): JsonField = hasHiddenSubscriptionsOnProfile + + /** + * Returns the raw JSON value of [highlightsInfo]. + * + * Unlike [highlightsInfo], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("highlightsInfo") + @ExcludeMissing + fun _highlightsInfo(): JsonField = highlightsInfo + + /** + * Returns the raw JSON value of [identityVerification]. + * + * Unlike [identityVerification], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("identityVerification") + @ExcludeMissing + fun _identityVerification(): JsonField = identityVerification + /** * Returns the raw JSON value of [isAutomated]. * @@ -566,6 +792,16 @@ private constructor( @ExcludeMissing fun _isBlueVerified(): JsonField = isBlueVerified + /** + * Returns the raw JSON value of [isProfileTranslatable]. + * + * Unlike [isProfileTranslatable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isProfileTranslatable") + @ExcludeMissing + fun _isProfileTranslatable(): JsonField = isProfileTranslatable + /** * Returns the raw JSON value of [isTranslator]. * @@ -596,6 +832,16 @@ private constructor( */ @JsonProperty("mediaCount") @ExcludeMissing fun _mediaCount(): JsonField = mediaCount + /** + * Returns the raw JSON value of [parodyCommentaryFanLabel]. + * + * Unlike [parodyCommentaryFanLabel], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("parodyCommentaryFanLabel") + @ExcludeMissing + fun _parodyCommentaryFanLabel(): JsonField = parodyCommentaryFanLabel + /** * Returns the raw JSON value of [pinnedTweetIds]. * @@ -634,6 +880,36 @@ private constructor( @ExcludeMissing fun _profileBannerUrl(): JsonField = profileBannerUrl + /** + * Returns the raw JSON value of [profileDescriptionLanguage]. + * + * Unlike [profileDescriptionLanguage], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("profileDescriptionLanguage") + @ExcludeMissing + fun _profileDescriptionLanguage(): JsonField = profileDescriptionLanguage + + /** + * Returns the raw JSON value of [profileImageShape]. + * + * Unlike [profileImageShape], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileImageShape") + @ExcludeMissing + fun _profileImageShape(): JsonField = profileImageShape + + /** + * Returns the raw JSON value of [profileInterstitialType]. + * + * Unlike [profileInterstitialType], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("profileInterstitialType") + @ExcludeMissing + fun _profileInterstitialType(): JsonField = profileInterstitialType + /** * Returns the raw JSON value of [profilePicture]. * @@ -643,6 +919,26 @@ private constructor( @ExcludeMissing fun _profilePicture(): JsonField = profilePicture + /** + * Returns the raw JSON value of [profileSortEnabled]. + * + * Unlike [profileSortEnabled], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileSortEnabled") + @ExcludeMissing + fun _profileSortEnabled(): JsonField = profileSortEnabled + + /** + * Returns the raw JSON value of [profileTranslatorType]. + * + * Unlike [profileTranslatorType], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("profileTranslatorType") + @ExcludeMissing + fun _profileTranslatorType(): JsonField = profileTranslatorType + /** * Returns the raw JSON value of [protected_]. * @@ -659,6 +955,16 @@ private constructor( @ExcludeMissing fun _statusesCount(): JsonField = statusesCount + /** + * Returns the raw JSON value of [superFollowEligible]. + * + * Unlike [superFollowEligible], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("superFollowEligible") + @ExcludeMissing + fun _superFollowEligible(): JsonField = superFollowEligible + /** * Returns the raw JSON value of [unavailable]. * @@ -701,25 +1007,6 @@ private constructor( @ExcludeMissing fun _verifiedType(): JsonField = verifiedType - /** - * Returns the raw JSON value of [viewerFollowedBy]. - * - * Unlike [viewerFollowedBy], this method doesn't throw if the JSON field has an unexpected - * type. - */ - @JsonProperty("viewerFollowedBy") - @ExcludeMissing - fun _viewerFollowedBy(): JsonField = viewerFollowedBy - - /** - * Returns the raw JSON value of [viewerFollowing]. - * - * Unlike [viewerFollowing], this method doesn't throw if the JSON field has an unexpected type. - */ - @JsonProperty("viewerFollowing") - @ExcludeMissing - fun _viewerFollowing(): JsonField = viewerFollowing - /** * Returns the raw JSON value of [withheldInCountries]. * @@ -763,36 +1050,50 @@ private constructor( private var id: JsonField? = null private var name: JsonField? = null private var username: JsonField? = null + private var affiliatesHighlightedLabel: JsonField = + JsonMissing.of() private var automatedBy: JsonField = JsonMissing.of() - private var canDm: JsonField = JsonMissing.of() + private var businessAccountAffiliatesCount: JsonField = JsonMissing.of() private var communityRole: JsonField = JsonMissing.of() private var coverPicture: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() + private var creatorSubscriptionsCount: JsonField = JsonMissing.of() private var description: JsonField = JsonMissing.of() private var favouritesCount: JsonField = JsonMissing.of() private var followers: JsonField = JsonMissing.of() private var following: JsonField = JsonMissing.of() private var hasCustomTimelines: JsonField = JsonMissing.of() + private var hasGraduatedAccess: JsonField = JsonMissing.of() + private var hasHiddenSubscriptionsOnProfile: JsonField = JsonMissing.of() + private var highlightsInfo: JsonField = JsonMissing.of() + private var identityVerification: JsonField = + JsonMissing.of() private var isAutomated: JsonField = JsonMissing.of() private var isBlueVerified: JsonField = JsonMissing.of() + private var isProfileTranslatable: JsonField = JsonMissing.of() private var isTranslator: JsonField = JsonMissing.of() private var isVerified: JsonField = JsonMissing.of() private var location: JsonField = JsonMissing.of() private var mediaCount: JsonField = JsonMissing.of() + private var parodyCommentaryFanLabel: JsonField = JsonMissing.of() private var pinnedTweetIds: JsonField>? = null private var possiblySensitive: JsonField = JsonMissing.of() private var profileBio: JsonField = JsonMissing.of() private var profileBannerUrl: JsonField = JsonMissing.of() + private var profileDescriptionLanguage: JsonField = JsonMissing.of() + private var profileImageShape: JsonField = JsonMissing.of() + private var profileInterstitialType: JsonField = JsonMissing.of() private var profilePicture: JsonField = JsonMissing.of() + private var profileSortEnabled: JsonField = JsonMissing.of() + private var profileTranslatorType: JsonField = JsonMissing.of() private var protected_: JsonField = JsonMissing.of() private var statusesCount: JsonField = JsonMissing.of() + private var superFollowEligible: JsonField = JsonMissing.of() private var unavailable: JsonField = JsonMissing.of() private var unavailableReason: JsonField = JsonMissing.of() private var url: JsonField = JsonMissing.of() private var verified: JsonField = JsonMissing.of() private var verifiedType: JsonField = JsonMissing.of() - private var viewerFollowedBy: JsonField = JsonMissing.of() - private var viewerFollowing: JsonField = JsonMissing.of() private var withheldInCountries: JsonField>? = null private var additionalProperties: MutableMap = mutableMapOf() @@ -801,36 +1102,48 @@ private constructor( id = tweetAuthor.id name = tweetAuthor.name username = tweetAuthor.username + affiliatesHighlightedLabel = tweetAuthor.affiliatesHighlightedLabel automatedBy = tweetAuthor.automatedBy - canDm = tweetAuthor.canDm + businessAccountAffiliatesCount = tweetAuthor.businessAccountAffiliatesCount communityRole = tweetAuthor.communityRole coverPicture = tweetAuthor.coverPicture createdAt = tweetAuthor.createdAt + creatorSubscriptionsCount = tweetAuthor.creatorSubscriptionsCount description = tweetAuthor.description favouritesCount = tweetAuthor.favouritesCount followers = tweetAuthor.followers following = tweetAuthor.following hasCustomTimelines = tweetAuthor.hasCustomTimelines + hasGraduatedAccess = tweetAuthor.hasGraduatedAccess + hasHiddenSubscriptionsOnProfile = tweetAuthor.hasHiddenSubscriptionsOnProfile + highlightsInfo = tweetAuthor.highlightsInfo + identityVerification = tweetAuthor.identityVerification isAutomated = tweetAuthor.isAutomated isBlueVerified = tweetAuthor.isBlueVerified + isProfileTranslatable = tweetAuthor.isProfileTranslatable isTranslator = tweetAuthor.isTranslator isVerified = tweetAuthor.isVerified location = tweetAuthor.location mediaCount = tweetAuthor.mediaCount + parodyCommentaryFanLabel = tweetAuthor.parodyCommentaryFanLabel pinnedTweetIds = tweetAuthor.pinnedTweetIds.map { it.toMutableList() } possiblySensitive = tweetAuthor.possiblySensitive profileBio = tweetAuthor.profileBio profileBannerUrl = tweetAuthor.profileBannerUrl + profileDescriptionLanguage = tweetAuthor.profileDescriptionLanguage + profileImageShape = tweetAuthor.profileImageShape + profileInterstitialType = tweetAuthor.profileInterstitialType profilePicture = tweetAuthor.profilePicture + profileSortEnabled = tweetAuthor.profileSortEnabled + profileTranslatorType = tweetAuthor.profileTranslatorType protected_ = tweetAuthor.protected_ statusesCount = tweetAuthor.statusesCount + superFollowEligible = tweetAuthor.superFollowEligible unavailable = tweetAuthor.unavailable unavailableReason = tweetAuthor.unavailableReason url = tweetAuthor.url verified = tweetAuthor.verified verifiedType = tweetAuthor.verifiedType - viewerFollowedBy = tweetAuthor.viewerFollowedBy - viewerFollowing = tweetAuthor.viewerFollowing withheldInCountries = tweetAuthor.withheldInCountries.map { it.toMutableList() } additionalProperties = tweetAuthor.additionalProperties.toMutableMap() } @@ -865,6 +1178,22 @@ private constructor( */ fun username(username: JsonField) = apply { this.username = username } + /** Organization affiliation label shown on an X profile. */ + fun affiliatesHighlightedLabel( + affiliatesHighlightedLabel: UserProfile.AffiliatesHighlightedLabel + ) = affiliatesHighlightedLabel(JsonField.of(affiliatesHighlightedLabel)) + + /** + * Sets [Builder.affiliatesHighlightedLabel] to an arbitrary JSON value. + * + * You should usually call [Builder.affiliatesHighlightedLabel] with a well-typed + * [UserProfile.AffiliatesHighlightedLabel] value instead. This method is primarily for + * setting the field to an undocumented or not yet supported value. + */ + fun affiliatesHighlightedLabel( + affiliatesHighlightedLabel: JsonField + ) = apply { this.affiliatesHighlightedLabel = affiliatesHighlightedLabel } + fun automatedBy(automatedBy: String) = automatedBy(JsonField.of(automatedBy)) /** @@ -876,15 +1205,20 @@ private constructor( */ fun automatedBy(automatedBy: JsonField) = apply { this.automatedBy = automatedBy } - fun canDm(canDm: Boolean) = canDm(JsonField.of(canDm)) + fun businessAccountAffiliatesCount(businessAccountAffiliatesCount: Long) = + businessAccountAffiliatesCount(JsonField.of(businessAccountAffiliatesCount)) /** - * Sets [Builder.canDm] to an arbitrary JSON value. + * Sets [Builder.businessAccountAffiliatesCount] to an arbitrary JSON value. * - * You should usually call [Builder.canDm] with a well-typed [Boolean] value instead. This - * method is primarily for setting the field to an undocumented or not yet supported value. + * You should usually call [Builder.businessAccountAffiliatesCount] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. */ - fun canDm(canDm: JsonField) = apply { this.canDm = canDm } + fun businessAccountAffiliatesCount(businessAccountAffiliatesCount: JsonField) = + apply { + this.businessAccountAffiliatesCount = businessAccountAffiliatesCount + } /** Community role when returned by community member reads */ fun communityRole(communityRole: String) = communityRole(JsonField.of(communityRole)) @@ -924,6 +1258,20 @@ private constructor( */ fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } + fun creatorSubscriptionsCount(creatorSubscriptionsCount: Long) = + creatorSubscriptionsCount(JsonField.of(creatorSubscriptionsCount)) + + /** + * Sets [Builder.creatorSubscriptionsCount] to an arbitrary JSON value. + * + * You should usually call [Builder.creatorSubscriptionsCount] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun creatorSubscriptionsCount(creatorSubscriptionsCount: JsonField) = apply { + this.creatorSubscriptionsCount = creatorSubscriptionsCount + } + fun description(description: String) = description(JsonField.of(description)) /** @@ -982,6 +1330,65 @@ private constructor( this.hasCustomTimelines = hasCustomTimelines } + fun hasGraduatedAccess(hasGraduatedAccess: Boolean) = + hasGraduatedAccess(JsonField.of(hasGraduatedAccess)) + + /** + * Sets [Builder.hasGraduatedAccess] to an arbitrary JSON value. + * + * You should usually call [Builder.hasGraduatedAccess] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun hasGraduatedAccess(hasGraduatedAccess: JsonField) = apply { + this.hasGraduatedAccess = hasGraduatedAccess + } + + fun hasHiddenSubscriptionsOnProfile(hasHiddenSubscriptionsOnProfile: Boolean) = + hasHiddenSubscriptionsOnProfile(JsonField.of(hasHiddenSubscriptionsOnProfile)) + + /** + * Sets [Builder.hasHiddenSubscriptionsOnProfile] to an arbitrary JSON value. + * + * You should usually call [Builder.hasHiddenSubscriptionsOnProfile] with a well-typed + * [Boolean] value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun hasHiddenSubscriptionsOnProfile(hasHiddenSubscriptionsOnProfile: JsonField) = + apply { + this.hasHiddenSubscriptionsOnProfile = hasHiddenSubscriptionsOnProfile + } + + /** Profile highlight availability and count metadata. */ + fun highlightsInfo(highlightsInfo: UserProfile.HighlightsInfo) = + highlightsInfo(JsonField.of(highlightsInfo)) + + /** + * Sets [Builder.highlightsInfo] to an arbitrary JSON value. + * + * You should usually call [Builder.highlightsInfo] with a well-typed + * [UserProfile.HighlightsInfo] value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun highlightsInfo(highlightsInfo: JsonField) = apply { + this.highlightsInfo = highlightsInfo + } + + /** Identity verification metadata displayed by X. */ + fun identityVerification(identityVerification: UserProfile.IdentityVerification) = + identityVerification(JsonField.of(identityVerification)) + + /** + * Sets [Builder.identityVerification] to an arbitrary JSON value. + * + * You should usually call [Builder.identityVerification] with a well-typed + * [UserProfile.IdentityVerification] value instead. This method is primarily for setting + * the field to an undocumented or not yet supported value. + */ + fun identityVerification( + identityVerification: JsonField + ) = apply { this.identityVerification = identityVerification } + fun isAutomated(isAutomated: Boolean) = isAutomated(JsonField.of(isAutomated)) /** @@ -1007,6 +1414,20 @@ private constructor( this.isBlueVerified = isBlueVerified } + fun isProfileTranslatable(isProfileTranslatable: Boolean) = + isProfileTranslatable(JsonField.of(isProfileTranslatable)) + + /** + * Sets [Builder.isProfileTranslatable] to an arbitrary JSON value. + * + * You should usually call [Builder.isProfileTranslatable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isProfileTranslatable(isProfileTranslatable: JsonField) = apply { + this.isProfileTranslatable = isProfileTranslatable + } + fun isTranslator(isTranslator: Boolean) = isTranslator(JsonField.of(isTranslator)) /** @@ -1052,6 +1473,20 @@ private constructor( */ fun mediaCount(mediaCount: JsonField) = apply { this.mediaCount = mediaCount } + fun parodyCommentaryFanLabel(parodyCommentaryFanLabel: String) = + parodyCommentaryFanLabel(JsonField.of(parodyCommentaryFanLabel)) + + /** + * Sets [Builder.parodyCommentaryFanLabel] to an arbitrary JSON value. + * + * You should usually call [Builder.parodyCommentaryFanLabel] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun parodyCommentaryFanLabel(parodyCommentaryFanLabel: JsonField) = apply { + this.parodyCommentaryFanLabel = parodyCommentaryFanLabel + } + fun pinnedTweetIds(pinnedTweetIds: List) = pinnedTweetIds(JsonField.of(pinnedTweetIds)) @@ -1121,6 +1556,48 @@ private constructor( this.profileBannerUrl = profileBannerUrl } + fun profileDescriptionLanguage(profileDescriptionLanguage: String) = + profileDescriptionLanguage(JsonField.of(profileDescriptionLanguage)) + + /** + * Sets [Builder.profileDescriptionLanguage] to an arbitrary JSON value. + * + * You should usually call [Builder.profileDescriptionLanguage] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun profileDescriptionLanguage(profileDescriptionLanguage: JsonField) = apply { + this.profileDescriptionLanguage = profileDescriptionLanguage + } + + fun profileImageShape(profileImageShape: String) = + profileImageShape(JsonField.of(profileImageShape)) + + /** + * Sets [Builder.profileImageShape] to an arbitrary JSON value. + * + * You should usually call [Builder.profileImageShape] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileImageShape(profileImageShape: JsonField) = apply { + this.profileImageShape = profileImageShape + } + + fun profileInterstitialType(profileInterstitialType: String) = + profileInterstitialType(JsonField.of(profileInterstitialType)) + + /** + * Sets [Builder.profileInterstitialType] to an arbitrary JSON value. + * + * You should usually call [Builder.profileInterstitialType] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun profileInterstitialType(profileInterstitialType: JsonField) = apply { + this.profileInterstitialType = profileInterstitialType + } + fun profilePicture(profilePicture: String) = profilePicture(JsonField.of(profilePicture)) /** @@ -1134,6 +1611,34 @@ private constructor( this.profilePicture = profilePicture } + fun profileSortEnabled(profileSortEnabled: Boolean) = + profileSortEnabled(JsonField.of(profileSortEnabled)) + + /** + * Sets [Builder.profileSortEnabled] to an arbitrary JSON value. + * + * You should usually call [Builder.profileSortEnabled] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileSortEnabled(profileSortEnabled: JsonField) = apply { + this.profileSortEnabled = profileSortEnabled + } + + fun profileTranslatorType(profileTranslatorType: String) = + profileTranslatorType(JsonField.of(profileTranslatorType)) + + /** + * Sets [Builder.profileTranslatorType] to an arbitrary JSON value. + * + * You should usually call [Builder.profileTranslatorType] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun profileTranslatorType(profileTranslatorType: JsonField) = apply { + this.profileTranslatorType = profileTranslatorType + } + /** Whether the profile protects its posts */ fun protected_(protected_: Boolean) = protected_(JsonField.of(protected_)) @@ -1159,6 +1664,20 @@ private constructor( this.statusesCount = statusesCount } + fun superFollowEligible(superFollowEligible: Boolean) = + superFollowEligible(JsonField.of(superFollowEligible)) + + /** + * Sets [Builder.superFollowEligible] to an arbitrary JSON value. + * + * You should usually call [Builder.superFollowEligible] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun superFollowEligible(superFollowEligible: JsonField) = apply { + this.superFollowEligible = superFollowEligible + } + fun unavailable(unavailable: Boolean) = unavailable(JsonField.of(unavailable)) /** @@ -1218,36 +1737,6 @@ private constructor( this.verifiedType = verifiedType } - /** Whether this profile follows the authenticated viewer */ - fun viewerFollowedBy(viewerFollowedBy: Boolean) = - viewerFollowedBy(JsonField.of(viewerFollowedBy)) - - /** - * Sets [Builder.viewerFollowedBy] to an arbitrary JSON value. - * - * You should usually call [Builder.viewerFollowedBy] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun viewerFollowedBy(viewerFollowedBy: JsonField) = apply { - this.viewerFollowedBy = viewerFollowedBy - } - - /** Whether the authenticated viewer follows this profile */ - fun viewerFollowing(viewerFollowing: Boolean) = - viewerFollowing(JsonField.of(viewerFollowing)) - - /** - * Sets [Builder.viewerFollowing] to an arbitrary JSON value. - * - * You should usually call [Builder.viewerFollowing] with a well-typed [Boolean] value - * instead. This method is primarily for setting the field to an undocumented or not yet - * supported value. - */ - fun viewerFollowing(viewerFollowing: JsonField) = apply { - this.viewerFollowing = viewerFollowing - } - fun withheldInCountries(withheldInCountries: List) = withheldInCountries(JsonField.of(withheldInCountries)) @@ -1312,36 +1801,48 @@ private constructor( checkRequired("id", id), checkRequired("name", name), checkRequired("username", username), + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, (pinnedTweetIds ?: JsonMissing.of()).map { it.toImmutable() }, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, (withheldInCountries ?: JsonMissing.of()).map { it.toImmutable() }, additionalProperties.toMutableMap(), ) @@ -1365,36 +1866,48 @@ private constructor( id() name() username() + affiliatesHighlightedLabel().ifPresent { it.validate() } automatedBy() - canDm() + businessAccountAffiliatesCount() communityRole() coverPicture() createdAt() + creatorSubscriptionsCount() description() favouritesCount() followers() following() hasCustomTimelines() + hasGraduatedAccess() + hasHiddenSubscriptionsOnProfile() + highlightsInfo().ifPresent { it.validate() } + identityVerification().ifPresent { it.validate() } isAutomated() isBlueVerified() + isProfileTranslatable() isTranslator() isVerified() location() mediaCount() + parodyCommentaryFanLabel() pinnedTweetIds() possiblySensitive() profileBio().ifPresent { it.validate() } profileBannerUrl() + profileDescriptionLanguage() + profileImageShape() + profileInterstitialType() profilePicture() + profileSortEnabled() + profileTranslatorType() protected_() statusesCount() + superFollowEligible() unavailable() unavailableReason() url() verified() verifiedType() - viewerFollowedBy() - viewerFollowing() withheldInCountries() validated = true } @@ -1417,36 +1930,48 @@ private constructor( (if (id.asKnown().isPresent) 1 else 0) + (if (name.asKnown().isPresent) 1 else 0) + (if (username.asKnown().isPresent) 1 else 0) + + (affiliatesHighlightedLabel.asKnown().getOrNull()?.validity() ?: 0) + (if (automatedBy.asKnown().isPresent) 1 else 0) + - (if (canDm.asKnown().isPresent) 1 else 0) + + (if (businessAccountAffiliatesCount.asKnown().isPresent) 1 else 0) + (if (communityRole.asKnown().isPresent) 1 else 0) + (if (coverPicture.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + + (if (creatorSubscriptionsCount.asKnown().isPresent) 1 else 0) + (if (description.asKnown().isPresent) 1 else 0) + (if (favouritesCount.asKnown().isPresent) 1 else 0) + (if (followers.asKnown().isPresent) 1 else 0) + (if (following.asKnown().isPresent) 1 else 0) + (if (hasCustomTimelines.asKnown().isPresent) 1 else 0) + + (if (hasGraduatedAccess.asKnown().isPresent) 1 else 0) + + (if (hasHiddenSubscriptionsOnProfile.asKnown().isPresent) 1 else 0) + + (highlightsInfo.asKnown().getOrNull()?.validity() ?: 0) + + (identityVerification.asKnown().getOrNull()?.validity() ?: 0) + (if (isAutomated.asKnown().isPresent) 1 else 0) + (if (isBlueVerified.asKnown().isPresent) 1 else 0) + + (if (isProfileTranslatable.asKnown().isPresent) 1 else 0) + (if (isTranslator.asKnown().isPresent) 1 else 0) + (if (isVerified.asKnown().isPresent) 1 else 0) + (if (location.asKnown().isPresent) 1 else 0) + (if (mediaCount.asKnown().isPresent) 1 else 0) + + (if (parodyCommentaryFanLabel.asKnown().isPresent) 1 else 0) + (pinnedTweetIds.asKnown().getOrNull()?.size ?: 0) + (if (possiblySensitive.asKnown().isPresent) 1 else 0) + (profileBio.asKnown().getOrNull()?.validity() ?: 0) + (if (profileBannerUrl.asKnown().isPresent) 1 else 0) + + (if (profileDescriptionLanguage.asKnown().isPresent) 1 else 0) + + (if (profileImageShape.asKnown().isPresent) 1 else 0) + + (if (profileInterstitialType.asKnown().isPresent) 1 else 0) + (if (profilePicture.asKnown().isPresent) 1 else 0) + + (if (profileSortEnabled.asKnown().isPresent) 1 else 0) + + (if (profileTranslatorType.asKnown().isPresent) 1 else 0) + (if (protected_.asKnown().isPresent) 1 else 0) + (if (statusesCount.asKnown().isPresent) 1 else 0) + + (if (superFollowEligible.asKnown().isPresent) 1 else 0) + (if (unavailable.asKnown().isPresent) 1 else 0) + (if (unavailableReason.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + (if (verified.asKnown().isPresent) 1 else 0) + (if (verifiedType.asKnown().isPresent) 1 else 0) + - (if (viewerFollowedBy.asKnown().isPresent) 1 else 0) + - (if (viewerFollowing.asKnown().isPresent) 1 else 0) + (withheldInCountries.asKnown().getOrNull()?.size ?: 0) override fun equals(other: Any?): Boolean { @@ -1458,36 +1983,48 @@ private constructor( id == other.id && name == other.name && username == other.username && + affiliatesHighlightedLabel == other.affiliatesHighlightedLabel && automatedBy == other.automatedBy && - canDm == other.canDm && + businessAccountAffiliatesCount == other.businessAccountAffiliatesCount && communityRole == other.communityRole && coverPicture == other.coverPicture && createdAt == other.createdAt && + creatorSubscriptionsCount == other.creatorSubscriptionsCount && description == other.description && favouritesCount == other.favouritesCount && followers == other.followers && following == other.following && hasCustomTimelines == other.hasCustomTimelines && + hasGraduatedAccess == other.hasGraduatedAccess && + hasHiddenSubscriptionsOnProfile == other.hasHiddenSubscriptionsOnProfile && + highlightsInfo == other.highlightsInfo && + identityVerification == other.identityVerification && isAutomated == other.isAutomated && isBlueVerified == other.isBlueVerified && + isProfileTranslatable == other.isProfileTranslatable && isTranslator == other.isTranslator && isVerified == other.isVerified && location == other.location && mediaCount == other.mediaCount && + parodyCommentaryFanLabel == other.parodyCommentaryFanLabel && pinnedTweetIds == other.pinnedTweetIds && possiblySensitive == other.possiblySensitive && profileBio == other.profileBio && profileBannerUrl == other.profileBannerUrl && + profileDescriptionLanguage == other.profileDescriptionLanguage && + profileImageShape == other.profileImageShape && + profileInterstitialType == other.profileInterstitialType && profilePicture == other.profilePicture && + profileSortEnabled == other.profileSortEnabled && + profileTranslatorType == other.profileTranslatorType && protected_ == other.protected_ && statusesCount == other.statusesCount && + superFollowEligible == other.superFollowEligible && unavailable == other.unavailable && unavailableReason == other.unavailableReason && url == other.url && verified == other.verified && verifiedType == other.verifiedType && - viewerFollowedBy == other.viewerFollowedBy && - viewerFollowing == other.viewerFollowing && withheldInCountries == other.withheldInCountries && additionalProperties == other.additionalProperties } @@ -1497,36 +2034,48 @@ private constructor( id, name, username, + affiliatesHighlightedLabel, automatedBy, - canDm, + businessAccountAffiliatesCount, communityRole, coverPicture, createdAt, + creatorSubscriptionsCount, description, favouritesCount, followers, following, hasCustomTimelines, + hasGraduatedAccess, + hasHiddenSubscriptionsOnProfile, + highlightsInfo, + identityVerification, isAutomated, isBlueVerified, + isProfileTranslatable, isTranslator, isVerified, location, mediaCount, + parodyCommentaryFanLabel, pinnedTweetIds, possiblySensitive, profileBio, profileBannerUrl, + profileDescriptionLanguage, + profileImageShape, + profileInterstitialType, profilePicture, + profileSortEnabled, + profileTranslatorType, protected_, statusesCount, + superFollowEligible, unavailable, unavailableReason, url, verified, verifiedType, - viewerFollowedBy, - viewerFollowing, withheldInCountries, additionalProperties, ) @@ -1535,5 +2084,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "TweetAuthor{id=$id, name=$name, username=$username, automatedBy=$automatedBy, canDm=$canDm, communityRole=$communityRole, coverPicture=$coverPicture, createdAt=$createdAt, description=$description, favouritesCount=$favouritesCount, followers=$followers, following=$following, hasCustomTimelines=$hasCustomTimelines, isAutomated=$isAutomated, isBlueVerified=$isBlueVerified, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, pinnedTweetIds=$pinnedTweetIds, possiblySensitive=$possiblySensitive, profileBio=$profileBio, profileBannerUrl=$profileBannerUrl, profilePicture=$profilePicture, protected_=$protected_, statusesCount=$statusesCount, unavailable=$unavailable, unavailableReason=$unavailableReason, url=$url, verified=$verified, verifiedType=$verifiedType, viewerFollowedBy=$viewerFollowedBy, viewerFollowing=$viewerFollowing, withheldInCountries=$withheldInCountries, additionalProperties=$additionalProperties}" + "TweetAuthor{id=$id, name=$name, username=$username, affiliatesHighlightedLabel=$affiliatesHighlightedLabel, automatedBy=$automatedBy, businessAccountAffiliatesCount=$businessAccountAffiliatesCount, communityRole=$communityRole, coverPicture=$coverPicture, createdAt=$createdAt, creatorSubscriptionsCount=$creatorSubscriptionsCount, description=$description, favouritesCount=$favouritesCount, followers=$followers, following=$following, hasCustomTimelines=$hasCustomTimelines, hasGraduatedAccess=$hasGraduatedAccess, hasHiddenSubscriptionsOnProfile=$hasHiddenSubscriptionsOnProfile, highlightsInfo=$highlightsInfo, identityVerification=$identityVerification, isAutomated=$isAutomated, isBlueVerified=$isBlueVerified, isProfileTranslatable=$isProfileTranslatable, isTranslator=$isTranslator, isVerified=$isVerified, location=$location, mediaCount=$mediaCount, parodyCommentaryFanLabel=$parodyCommentaryFanLabel, pinnedTweetIds=$pinnedTweetIds, possiblySensitive=$possiblySensitive, profileBio=$profileBio, profileBannerUrl=$profileBannerUrl, profileDescriptionLanguage=$profileDescriptionLanguage, profileImageShape=$profileImageShape, profileInterstitialType=$profileInterstitialType, profilePicture=$profilePicture, profileSortEnabled=$profileSortEnabled, profileTranslatorType=$profileTranslatorType, protected_=$protected_, statusesCount=$statusesCount, superFollowEligible=$superFollowEligible, unavailable=$unavailable, unavailableReason=$unavailableReason, url=$url, verified=$verified, verifiedType=$verifiedType, withheldInCountries=$withheldInCountries, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetail.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetail.kt index dea42e9..87e8f87 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetail.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetail.kt @@ -41,11 +41,15 @@ private constructor( private val retweetCount: JsonField, private val text: JsonField, private val viewCount: JsonField, + private val article: JsonField
, private val author: JsonField, + private val card: JsonField, + private val communityNote: JsonField, private val contentDisclosure: JsonField, private val conversationId: JsonField, private val createdAt: JsonField, private val displayTextRange: JsonField>, + private val edit: JsonField, private val entities: JsonField, private val inReplyToId: JsonField, private val inReplyToUserId: JsonField, @@ -54,13 +58,19 @@ private constructor( private val isNoteTweet: JsonField, private val isQuoteStatus: JsonField, private val isReply: JsonField, + private val isTranslatable: JsonField, private val lang: JsonField, private val media: JsonField>, + private val noteTweet: JsonField, + private val place: JsonField, + private val possiblySensitive: JsonField, + private val previousCounts: JsonField, private val quotedTweet: JsonField, private val retweetedTweet: JsonField, private val source: JsonField, private val type: JsonField, private val url: JsonField, + private val viewState: JsonField, private val additionalProperties: MutableMap, ) { @@ -78,7 +88,12 @@ private constructor( retweetCount: JsonField = JsonMissing.of(), @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), @JsonProperty("viewCount") @ExcludeMissing viewCount: JsonField = JsonMissing.of(), + @JsonProperty("article") @ExcludeMissing article: JsonField
= JsonMissing.of(), @JsonProperty("author") @ExcludeMissing author: JsonField = JsonMissing.of(), + @JsonProperty("card") @ExcludeMissing card: JsonField = JsonMissing.of(), + @JsonProperty("communityNote") + @ExcludeMissing + communityNote: JsonField = JsonMissing.of(), @JsonProperty("contentDisclosure") @ExcludeMissing contentDisclosure: JsonField = JsonMissing.of(), @@ -89,6 +104,7 @@ private constructor( @JsonProperty("displayTextRange") @ExcludeMissing displayTextRange: JsonField> = JsonMissing.of(), + @JsonProperty("edit") @ExcludeMissing edit: JsonField = JsonMissing.of(), @JsonProperty("entities") @ExcludeMissing entities: JsonField = JsonMissing.of(), @JsonProperty("inReplyToId") @ExcludeMissing @@ -109,10 +125,23 @@ private constructor( @ExcludeMissing isQuoteStatus: JsonField = JsonMissing.of(), @JsonProperty("isReply") @ExcludeMissing isReply: JsonField = JsonMissing.of(), + @JsonProperty("isTranslatable") + @ExcludeMissing + isTranslatable: JsonField = JsonMissing.of(), @JsonProperty("lang") @ExcludeMissing lang: JsonField = JsonMissing.of(), @JsonProperty("media") @ExcludeMissing media: JsonField> = JsonMissing.of(), + @JsonProperty("noteTweet") + @ExcludeMissing + noteTweet: JsonField = JsonMissing.of(), + @JsonProperty("place") @ExcludeMissing place: JsonField = JsonMissing.of(), + @JsonProperty("possiblySensitive") + @ExcludeMissing + possiblySensitive: JsonField = JsonMissing.of(), + @JsonProperty("previousCounts") + @ExcludeMissing + previousCounts: JsonField = JsonMissing.of(), @JsonProperty("quoted_tweet") @ExcludeMissing quotedTweet: JsonField = JsonMissing.of(), @@ -122,6 +151,7 @@ private constructor( @JsonProperty("source") @ExcludeMissing source: JsonField = JsonMissing.of(), @JsonProperty("type") @ExcludeMissing type: JsonField = JsonMissing.of(), @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + @JsonProperty("viewState") @ExcludeMissing viewState: JsonField = JsonMissing.of(), ) : this( id, bookmarkCount, @@ -131,11 +161,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -144,13 +178,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, mutableMapOf(), ) @@ -202,6 +242,14 @@ private constructor( */ fun viewCount(): Long = viewCount.getRequired("viewCount") + /** + * Article metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun article(): Optional
= article.getOptional("article") + /** * Tweet author profile. The lookup route always includes follower count and verification state. * Other profile fields appear when available. @@ -211,6 +259,22 @@ private constructor( */ fun author(): Optional = author.getOptional("author") + /** + * Public card metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun card(): Optional = card.getOptional("card") + + /** + * Community Note presentation metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun communityNote(): Optional = communityNote.getOptional("communityNote") + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership content or * AI-generated media. @@ -243,6 +307,14 @@ private constructor( */ fun displayTextRange(): Optional> = displayTextRange.getOptional("displayTextRange") + /** + * Edit history metadata returned by X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun edit(): Optional = edit.getOptional("edit") + /** * Parsed entities from the tweet text (URLs, mentions, hashtags, media) * @@ -307,6 +379,12 @@ private constructor( */ fun isReply(): Optional = isReply.getOptional("isReply") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun isTranslatable(): Optional = isTranslatable.getOptional("isTranslatable") + /** * Tweet language code * @@ -323,6 +401,36 @@ private constructor( */ fun media(): Optional> = media.getOptional("media") + /** + * Complete Note Tweet content and rich-text metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun noteTweet(): Optional = noteTweet.getOptional("noteTweet") + + /** + * Public place metadata attached to a tweet. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun place(): Optional = place.getOptional("place") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun possiblySensitive(): Optional = possiblySensitive.getOptional("possiblySensitive") + + /** + * Engagement counts retained from a prior tweet edit. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun previousCounts(): Optional = previousCounts.getOptional("previousCounts") + /** * Quoted or retweeted tweet context. Every object includes id, text, and engagement metrics. A * zero metric can mean X did not report the count. Author, media, and conversation fields @@ -367,6 +475,12 @@ private constructor( */ fun url(): Optional = url.getOptional("url") + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun viewState(): Optional = viewState.getOptional("viewState") + /** * Returns the raw JSON value of [id]. * @@ -427,6 +541,13 @@ private constructor( */ @JsonProperty("viewCount") @ExcludeMissing fun _viewCount(): JsonField = viewCount + /** + * Returns the raw JSON value of [article]. + * + * Unlike [article], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("article") @ExcludeMissing fun _article(): JsonField
= article + /** * Returns the raw JSON value of [author]. * @@ -434,6 +555,22 @@ private constructor( */ @JsonProperty("author") @ExcludeMissing fun _author(): JsonField = author + /** + * Returns the raw JSON value of [card]. + * + * Unlike [card], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("card") @ExcludeMissing fun _card(): JsonField = card + + /** + * Returns the raw JSON value of [communityNote]. + * + * Unlike [communityNote], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("communityNote") + @ExcludeMissing + fun _communityNote(): JsonField = communityNote + /** * Returns the raw JSON value of [contentDisclosure]. * @@ -470,6 +607,13 @@ private constructor( @ExcludeMissing fun _displayTextRange(): JsonField> = displayTextRange + /** + * Returns the raw JSON value of [edit]. + * + * Unlike [edit], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("edit") @ExcludeMissing fun _edit(): JsonField = edit + /** * Returns the raw JSON value of [entities]. * @@ -537,6 +681,15 @@ private constructor( */ @JsonProperty("isReply") @ExcludeMissing fun _isReply(): JsonField = isReply + /** + * Returns the raw JSON value of [isTranslatable]. + * + * Unlike [isTranslatable], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("isTranslatable") + @ExcludeMissing + fun _isTranslatable(): JsonField = isTranslatable + /** * Returns the raw JSON value of [lang]. * @@ -551,6 +704,39 @@ private constructor( */ @JsonProperty("media") @ExcludeMissing fun _media(): JsonField> = media + /** + * Returns the raw JSON value of [noteTweet]. + * + * Unlike [noteTweet], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("noteTweet") @ExcludeMissing fun _noteTweet(): JsonField = noteTweet + + /** + * Returns the raw JSON value of [place]. + * + * Unlike [place], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("place") @ExcludeMissing fun _place(): JsonField = place + + /** + * Returns the raw JSON value of [possiblySensitive]. + * + * Unlike [possiblySensitive], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("possiblySensitive") + @ExcludeMissing + fun _possiblySensitive(): JsonField = possiblySensitive + + /** + * Returns the raw JSON value of [previousCounts]. + * + * Unlike [previousCounts], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previousCounts") + @ExcludeMissing + fun _previousCounts(): JsonField = previousCounts + /** * Returns the raw JSON value of [quotedTweet]. * @@ -590,6 +776,13 @@ private constructor( */ @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + /** + * Returns the raw JSON value of [viewState]. + * + * Unlike [viewState], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("viewState") @ExcludeMissing fun _viewState(): JsonField = viewState + @JsonAnySetter private fun putAdditionalProperty(key: String, value: JsonValue) { additionalProperties.put(key, value) @@ -633,11 +826,15 @@ private constructor( private var retweetCount: JsonField? = null private var text: JsonField? = null private var viewCount: JsonField? = null + private var article: JsonField
= JsonMissing.of() private var author: JsonField = JsonMissing.of() + private var card: JsonField = JsonMissing.of() + private var communityNote: JsonField = JsonMissing.of() private var contentDisclosure: JsonField = JsonMissing.of() private var conversationId: JsonField = JsonMissing.of() private var createdAt: JsonField = JsonMissing.of() private var displayTextRange: JsonField>? = null + private var edit: JsonField = JsonMissing.of() private var entities: JsonField = JsonMissing.of() private var inReplyToId: JsonField = JsonMissing.of() private var inReplyToUserId: JsonField = JsonMissing.of() @@ -646,13 +843,19 @@ private constructor( private var isNoteTweet: JsonField = JsonMissing.of() private var isQuoteStatus: JsonField = JsonMissing.of() private var isReply: JsonField = JsonMissing.of() + private var isTranslatable: JsonField = JsonMissing.of() private var lang: JsonField = JsonMissing.of() private var media: JsonField>? = null + private var noteTweet: JsonField = JsonMissing.of() + private var place: JsonField = JsonMissing.of() + private var possiblySensitive: JsonField = JsonMissing.of() + private var previousCounts: JsonField = JsonMissing.of() private var quotedTweet: JsonField = JsonMissing.of() private var retweetedTweet: JsonField = JsonMissing.of() private var source: JsonField = JsonMissing.of() private var type: JsonField = JsonMissing.of() private var url: JsonField = JsonMissing.of() + private var viewState: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic @@ -665,11 +868,15 @@ private constructor( retweetCount = tweetDetail.retweetCount text = tweetDetail.text viewCount = tweetDetail.viewCount + article = tweetDetail.article author = tweetDetail.author + card = tweetDetail.card + communityNote = tweetDetail.communityNote contentDisclosure = tweetDetail.contentDisclosure conversationId = tweetDetail.conversationId createdAt = tweetDetail.createdAt displayTextRange = tweetDetail.displayTextRange.map { it.toMutableList() } + edit = tweetDetail.edit entities = tweetDetail.entities inReplyToId = tweetDetail.inReplyToId inReplyToUserId = tweetDetail.inReplyToUserId @@ -678,13 +885,19 @@ private constructor( isNoteTweet = tweetDetail.isNoteTweet isQuoteStatus = tweetDetail.isQuoteStatus isReply = tweetDetail.isReply + isTranslatable = tweetDetail.isTranslatable lang = tweetDetail.lang media = tweetDetail.media.map { it.toMutableList() } + noteTweet = tweetDetail.noteTweet + place = tweetDetail.place + possiblySensitive = tweetDetail.possiblySensitive + previousCounts = tweetDetail.previousCounts quotedTweet = tweetDetail.quotedTweet retweetedTweet = tweetDetail.retweetedTweet source = tweetDetail.source type = tweetDetail.type url = tweetDetail.url + viewState = tweetDetail.viewState additionalProperties = tweetDetail.additionalProperties.toMutableMap() } @@ -772,6 +985,17 @@ private constructor( */ fun viewCount(viewCount: JsonField) = apply { this.viewCount = viewCount } + /** Article metadata attached to a tweet. */ + fun article(article: Article) = article(JsonField.of(article)) + + /** + * Sets [Builder.article] to an arbitrary JSON value. + * + * You should usually call [Builder.article] with a well-typed [Article] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun article(article: JsonField
) = apply { this.article = article } + /** * Tweet author profile. The lookup route always includes follower count and verification * state. Other profile fields appear when available. @@ -787,6 +1011,31 @@ private constructor( */ fun author(author: JsonField) = apply { this.author = author } + /** Public card metadata attached to a tweet. */ + fun card(card: Card) = card(JsonField.of(card)) + + /** + * Sets [Builder.card] to an arbitrary JSON value. + * + * You should usually call [Builder.card] with a well-typed [Card] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun card(card: JsonField) = apply { this.card = card } + + /** Community Note presentation metadata returned by X. */ + fun communityNote(communityNote: CommunityNote) = communityNote(JsonField.of(communityNote)) + + /** + * Sets [Builder.communityNote] to an arbitrary JSON value. + * + * You should usually call [Builder.communityNote] with a well-typed [CommunityNote] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun communityNote(communityNote: JsonField) = apply { + this.communityNote = communityNote + } + /** * Content disclosure metadata shown by X when a tweet is labeled as paid partnership * content or AI-generated media. @@ -857,6 +1106,17 @@ private constructor( } } + /** Edit history metadata returned by X. */ + fun edit(edit: Edit) = edit(JsonField.of(edit)) + + /** + * Sets [Builder.edit] to an arbitrary JSON value. + * + * You should usually call [Builder.edit] with a well-typed [Edit] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun edit(edit: JsonField) = apply { this.edit = edit } + /** Parsed entities from the tweet text (URLs, mentions, hashtags, media) */ fun entities(entities: Entities) = entities(JsonField.of(entities)) @@ -962,6 +1222,19 @@ private constructor( */ fun isReply(isReply: JsonField) = apply { this.isReply = isReply } + fun isTranslatable(isTranslatable: Boolean) = isTranslatable(JsonField.of(isTranslatable)) + + /** + * Sets [Builder.isTranslatable] to an arbitrary JSON value. + * + * You should usually call [Builder.isTranslatable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isTranslatable(isTranslatable: JsonField) = apply { + this.isTranslatable = isTranslatable + } + /** Tweet language code */ fun lang(lang: String) = lang(JsonField.of(lang)) @@ -999,6 +1272,58 @@ private constructor( } } + /** Complete Note Tweet content and rich-text metadata. */ + fun noteTweet(noteTweet: NoteTweet) = noteTweet(JsonField.of(noteTweet)) + + /** + * Sets [Builder.noteTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.noteTweet] with a well-typed [NoteTweet] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun noteTweet(noteTweet: JsonField) = apply { this.noteTweet = noteTweet } + + /** Public place metadata attached to a tweet. */ + fun place(place: Place) = place(JsonField.of(place)) + + /** + * Sets [Builder.place] to an arbitrary JSON value. + * + * You should usually call [Builder.place] with a well-typed [Place] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported value. + */ + fun place(place: JsonField) = apply { this.place = place } + + fun possiblySensitive(possiblySensitive: Boolean) = + possiblySensitive(JsonField.of(possiblySensitive)) + + /** + * Sets [Builder.possiblySensitive] to an arbitrary JSON value. + * + * You should usually call [Builder.possiblySensitive] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun possiblySensitive(possiblySensitive: JsonField) = apply { + this.possiblySensitive = possiblySensitive + } + + /** Engagement counts retained from a prior tweet edit. */ + fun previousCounts(previousCounts: PreviousCounts) = + previousCounts(JsonField.of(previousCounts)) + + /** + * Sets [Builder.previousCounts] to an arbitrary JSON value. + * + * You should usually call [Builder.previousCounts] with a well-typed [PreviousCounts] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previousCounts(previousCounts: JsonField) = apply { + this.previousCounts = previousCounts + } + /** * Quoted or retweeted tweet context. Every object includes id, text, and engagement * metrics. A zero metric can mean X did not report the count. Author, media, and @@ -1069,6 +1394,17 @@ private constructor( */ fun url(url: JsonField) = apply { this.url = url } + fun viewState(viewState: String) = viewState(JsonField.of(viewState)) + + /** + * Sets [Builder.viewState] to an arbitrary JSON value. + * + * You should usually call [Builder.viewState] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun viewState(viewState: JsonField) = apply { this.viewState = viewState } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1117,11 +1453,15 @@ private constructor( checkRequired("retweetCount", retweetCount), checkRequired("text", text), checkRequired("viewCount", viewCount), + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, (displayTextRange ?: JsonMissing.of()).map { it.toImmutable() }, + edit, entities, inReplyToId, inReplyToUserId, @@ -1130,13 +1470,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, (media ?: JsonMissing.of()).map { it.toImmutable() }, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, additionalProperties.toMutableMap(), ) } @@ -1164,11 +1510,15 @@ private constructor( retweetCount() text() viewCount() + article().ifPresent { it.validate() } author().ifPresent { it.validate() } + card().ifPresent { it.validate() } + communityNote().ifPresent { it.validate() } contentDisclosure().ifPresent { it.validate() } conversationId() createdAt() displayTextRange() + edit().ifPresent { it.validate() } entities().ifPresent { it.validate() } inReplyToId() inReplyToUserId() @@ -1177,13 +1527,19 @@ private constructor( isNoteTweet() isQuoteStatus() isReply() + isTranslatable() lang() media().ifPresent { it.forEach { it.validate() } } + noteTweet().ifPresent { it.validate() } + place().ifPresent { it.validate() } + possiblySensitive() + previousCounts().ifPresent { it.validate() } quotedTweet().ifPresent { it.validate() } retweetedTweet().ifPresent { it.validate() } source() type() url() + viewState() validated = true } @@ -1210,11 +1566,15 @@ private constructor( (if (retweetCount.asKnown().isPresent) 1 else 0) + (if (text.asKnown().isPresent) 1 else 0) + (if (viewCount.asKnown().isPresent) 1 else 0) + + (article.asKnown().getOrNull()?.validity() ?: 0) + (author.asKnown().getOrNull()?.validity() ?: 0) + + (card.asKnown().getOrNull()?.validity() ?: 0) + + (communityNote.asKnown().getOrNull()?.validity() ?: 0) + (contentDisclosure.asKnown().getOrNull()?.validity() ?: 0) + (if (conversationId.asKnown().isPresent) 1 else 0) + (if (createdAt.asKnown().isPresent) 1 else 0) + (displayTextRange.asKnown().getOrNull()?.size ?: 0) + + (edit.asKnown().getOrNull()?.validity() ?: 0) + (entities.asKnown().getOrNull()?.validity() ?: 0) + (if (inReplyToId.asKnown().isPresent) 1 else 0) + (if (inReplyToUserId.asKnown().isPresent) 1 else 0) + @@ -1223,44 +1583,184 @@ private constructor( (if (isNoteTweet.asKnown().isPresent) 1 else 0) + (if (isQuoteStatus.asKnown().isPresent) 1 else 0) + (if (isReply.asKnown().isPresent) 1 else 0) + + (if (isTranslatable.asKnown().isPresent) 1 else 0) + (if (lang.asKnown().isPresent) 1 else 0) + (media.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (noteTweet.asKnown().getOrNull()?.validity() ?: 0) + + (place.asKnown().getOrNull()?.validity() ?: 0) + + (if (possiblySensitive.asKnown().isPresent) 1 else 0) + + (previousCounts.asKnown().getOrNull()?.validity() ?: 0) + (quotedTweet.asKnown().getOrNull()?.validity() ?: 0) + (retweetedTweet.asKnown().getOrNull()?.validity() ?: 0) + (if (source.asKnown().isPresent) 1 else 0) + (if (type.asKnown().isPresent) 1 else 0) + - (if (url.asKnown().isPresent) 1 else 0) + (if (url.asKnown().isPresent) 1 else 0) + + (if (viewState.asKnown().isPresent) 1 else 0) - /** Parsed entities from the tweet text (URLs, mentions, hashtags, media) */ - class Entities - @JsonCreator + /** Article metadata attached to a tweet. */ + class Article + @JsonCreator(mode = JsonCreator.Mode.DISABLED) private constructor( - @com.fasterxml.jackson.annotation.JsonValue - private val additionalProperties: Map + private val id: JsonField, + private val coverMediaUrl: JsonField, + private val previewText: JsonField, + private val title: JsonField, + private val additionalProperties: MutableMap, ) { + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("coverMediaUrl") + @ExcludeMissing + coverMediaUrl: JsonField = JsonMissing.of(), + @JsonProperty("previewText") + @ExcludeMissing + previewText: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + ) : this(id, coverMediaUrl, previewText, title, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun coverMediaUrl(): Optional = coverMediaUrl.getOptional("coverMediaUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun previewText(): Optional = previewText.getOptional("previewText") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [coverMediaUrl]. + * + * Unlike [coverMediaUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("coverMediaUrl") + @ExcludeMissing + fun _coverMediaUrl(): JsonField = coverMediaUrl + + /** + * Returns the raw JSON value of [previewText]. + * + * Unlike [previewText], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("previewText") + @ExcludeMissing + fun _previewText(): JsonField = previewText + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + @JsonAnyGetter @ExcludeMissing - fun _additionalProperties(): Map = additionalProperties + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) fun toBuilder() = Builder().from(this) companion object { - /** Returns a mutable builder for constructing an instance of [Entities]. */ + /** Returns a mutable builder for constructing an instance of [Article]. */ @JvmStatic fun builder() = Builder() } - /** A builder for [Entities]. */ + /** A builder for [Article]. */ class Builder internal constructor() { + private var id: JsonField = JsonMissing.of() + private var coverMediaUrl: JsonField = JsonMissing.of() + private var previewText: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() private var additionalProperties: MutableMap = mutableMapOf() @JvmSynthetic - internal fun from(entities: Entities) = apply { - additionalProperties = entities.additionalProperties.toMutableMap() + internal fun from(article: Article) = apply { + id = article.id + coverMediaUrl = article.coverMediaUrl + previewText = article.previewText + title = article.title + additionalProperties = article.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun coverMediaUrl(coverMediaUrl: String) = coverMediaUrl(JsonField.of(coverMediaUrl)) + + /** + * Sets [Builder.coverMediaUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.coverMediaUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun coverMediaUrl(coverMediaUrl: JsonField) = apply { + this.coverMediaUrl = coverMediaUrl } + fun previewText(previewText: String) = previewText(JsonField.of(previewText)) + + /** + * Sets [Builder.previewText] to an arbitrary JSON value. + * + * You should usually call [Builder.previewText] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun previewText(previewText: JsonField) = apply { + this.previewText = previewText + } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + fun additionalProperties(additionalProperties: Map) = apply { this.additionalProperties.clear() putAllAdditionalProperties(additionalProperties) @@ -1281,11 +1781,12 @@ private constructor( } /** - * Returns an immutable instance of [Entities]. + * Returns an immutable instance of [Article]. * * Further updates to this [Builder] will not mutate the returned instance. */ - fun build(): Entities = Entities(additionalProperties.toImmutable()) + fun build(): Article = + Article(id, coverMediaUrl, previewText, title, additionalProperties.toMutableMap()) } private var validated: Boolean = false @@ -1299,11 +1800,15 @@ private constructor( * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't * match its expected type. */ - fun validate(): Entities = apply { + fun validate(): Article = apply { if (validated) { return@apply } + id() + coverMediaUrl() + previewText() + title() validated = true } @@ -1322,23 +1827,2658 @@ private constructor( * Used for best match union deserialization. */ @JvmSynthetic - internal fun validity(): Int = additionalProperties.count { (_, value) -> - !value.isNull() && !value.isMissing() - } + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (coverMediaUrl.asKnown().isPresent) 1 else 0) + + (if (previewText.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) override fun equals(other: Any?): Boolean { if (this === other) { return true } - return other is Entities && additionalProperties == other.additionalProperties + return other is Article && + id == other.id && + coverMediaUrl == other.coverMediaUrl && + previewText == other.previewText && + title == other.title && + additionalProperties == other.additionalProperties } - private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + private val hashCode: Int by lazy { + Objects.hash(id, coverMediaUrl, previewText, title, additionalProperties) + } override fun hashCode(): Int = hashCode - override fun toString() = "Entities{additionalProperties=$additionalProperties}" + override fun toString() = + "Article{id=$id, coverMediaUrl=$coverMediaUrl, previewText=$previewText, title=$title, additionalProperties=$additionalProperties}" + } + + /** Public card metadata attached to a tweet. */ + class Card + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val bindingValues: JsonField, + private val name: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("bindingValues") + @ExcludeMissing + bindingValues: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this(id, bindingValues, name, url, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bindingValues(): Optional = bindingValues.getOptional("bindingValues") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [bindingValues]. + * + * Unlike [bindingValues], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bindingValues") + @ExcludeMissing + fun _bindingValues(): JsonField = bindingValues + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Card]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Card]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var bindingValues: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(card: Card) = apply { + id = card.id + bindingValues = card.bindingValues + name = card.name + url = card.url + additionalProperties = card.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun bindingValues(bindingValues: BindingValues) = + bindingValues(JsonField.of(bindingValues)) + + /** + * Sets [Builder.bindingValues] to an arbitrary JSON value. + * + * You should usually call [Builder.bindingValues] with a well-typed [BindingValues] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun bindingValues(bindingValues: JsonField) = apply { + this.bindingValues = bindingValues + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Card]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Card = + Card(id, bindingValues, name, url, additionalProperties.toMutableMap()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Card = apply { + if (validated) { + return@apply + } + + id() + bindingValues().ifPresent { it.validate() } + name() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (bindingValues.asKnown().getOrNull()?.validity() ?: 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BindingValues + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BindingValues]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BindingValues]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(bindingValues: BindingValues) = apply { + additionalProperties = bindingValues.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BindingValues]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BindingValues = BindingValues(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BindingValues = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BindingValues && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BindingValues{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Card && + id == other.id && + bindingValues == other.bindingValues && + name == other.name && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(id, bindingValues, name, url, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Card{id=$id, bindingValues=$bindingValues, name=$name, url=$url, additionalProperties=$additionalProperties}" + } + + /** Community Note presentation metadata returned by X. */ + class CommunityNote + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val destinationUrl: JsonField, + private val footer: JsonField, + private val shortTitle: JsonField, + private val subtitle: JsonField, + private val title: JsonField, + private val visualStyle: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("destinationUrl") + @ExcludeMissing + destinationUrl: JsonField = JsonMissing.of(), + @JsonProperty("footer") @ExcludeMissing footer: JsonField = JsonMissing.of(), + @JsonProperty("shortTitle") + @ExcludeMissing + shortTitle: JsonField = JsonMissing.of(), + @JsonProperty("subtitle") + @ExcludeMissing + subtitle: JsonField = JsonMissing.of(), + @JsonProperty("title") @ExcludeMissing title: JsonField = JsonMissing.of(), + @JsonProperty("visualStyle") + @ExcludeMissing + visualStyle: JsonField = JsonMissing.of(), + ) : this( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun destinationUrl(): Optional = destinationUrl.getOptional("destinationUrl") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun footer(): Optional = footer.getOptional("footer") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun shortTitle(): Optional = shortTitle.getOptional("shortTitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun subtitle(): Optional = subtitle.getOptional("subtitle") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun title(): Optional = title.getOptional("title") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun visualStyle(): Optional = visualStyle.getOptional("visualStyle") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [destinationUrl]. + * + * Unlike [destinationUrl], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("destinationUrl") + @ExcludeMissing + fun _destinationUrl(): JsonField = destinationUrl + + /** + * Returns the raw JSON value of [footer]. + * + * Unlike [footer], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("footer") @ExcludeMissing fun _footer(): JsonField = footer + + /** + * Returns the raw JSON value of [shortTitle]. + * + * Unlike [shortTitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("shortTitle") + @ExcludeMissing + fun _shortTitle(): JsonField = shortTitle + + /** + * Returns the raw JSON value of [subtitle]. + * + * Unlike [subtitle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("subtitle") @ExcludeMissing fun _subtitle(): JsonField = subtitle + + /** + * Returns the raw JSON value of [title]. + * + * Unlike [title], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("title") @ExcludeMissing fun _title(): JsonField = title + + /** + * Returns the raw JSON value of [visualStyle]. + * + * Unlike [visualStyle], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("visualStyle") + @ExcludeMissing + fun _visualStyle(): JsonField = visualStyle + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [CommunityNote]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [CommunityNote]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var destinationUrl: JsonField = JsonMissing.of() + private var footer: JsonField = JsonMissing.of() + private var shortTitle: JsonField = JsonMissing.of() + private var subtitle: JsonField = JsonMissing.of() + private var title: JsonField = JsonMissing.of() + private var visualStyle: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(communityNote: CommunityNote) = apply { + id = communityNote.id + destinationUrl = communityNote.destinationUrl + footer = communityNote.footer + shortTitle = communityNote.shortTitle + subtitle = communityNote.subtitle + title = communityNote.title + visualStyle = communityNote.visualStyle + additionalProperties = communityNote.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun destinationUrl(destinationUrl: String) = + destinationUrl(JsonField.of(destinationUrl)) + + /** + * Sets [Builder.destinationUrl] to an arbitrary JSON value. + * + * You should usually call [Builder.destinationUrl] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun destinationUrl(destinationUrl: JsonField) = apply { + this.destinationUrl = destinationUrl + } + + fun footer(footer: String) = footer(JsonField.of(footer)) + + /** + * Sets [Builder.footer] to an arbitrary JSON value. + * + * You should usually call [Builder.footer] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun footer(footer: JsonField) = apply { this.footer = footer } + + fun shortTitle(shortTitle: String) = shortTitle(JsonField.of(shortTitle)) + + /** + * Sets [Builder.shortTitle] to an arbitrary JSON value. + * + * You should usually call [Builder.shortTitle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun shortTitle(shortTitle: JsonField) = apply { this.shortTitle = shortTitle } + + fun subtitle(subtitle: String) = subtitle(JsonField.of(subtitle)) + + /** + * Sets [Builder.subtitle] to an arbitrary JSON value. + * + * You should usually call [Builder.subtitle] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun subtitle(subtitle: JsonField) = apply { this.subtitle = subtitle } + + fun title(title: String) = title(JsonField.of(title)) + + /** + * Sets [Builder.title] to an arbitrary JSON value. + * + * You should usually call [Builder.title] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun title(title: JsonField) = apply { this.title = title } + + fun visualStyle(visualStyle: String) = visualStyle(JsonField.of(visualStyle)) + + /** + * Sets [Builder.visualStyle] to an arbitrary JSON value. + * + * You should usually call [Builder.visualStyle] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun visualStyle(visualStyle: JsonField) = apply { + this.visualStyle = visualStyle + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [CommunityNote]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): CommunityNote = + CommunityNote( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): CommunityNote = apply { + if (validated) { + return@apply + } + + id() + destinationUrl() + footer() + shortTitle() + subtitle() + title() + visualStyle() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (if (destinationUrl.asKnown().isPresent) 1 else 0) + + (if (footer.asKnown().isPresent) 1 else 0) + + (if (shortTitle.asKnown().isPresent) 1 else 0) + + (if (subtitle.asKnown().isPresent) 1 else 0) + + (if (title.asKnown().isPresent) 1 else 0) + + (if (visualStyle.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is CommunityNote && + id == other.id && + destinationUrl == other.destinationUrl && + footer == other.footer && + shortTitle == other.shortTitle && + subtitle == other.subtitle && + title == other.title && + visualStyle == other.visualStyle && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + destinationUrl, + footer, + shortTitle, + subtitle, + title, + visualStyle, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "CommunityNote{id=$id, destinationUrl=$destinationUrl, footer=$footer, shortTitle=$shortTitle, subtitle=$subtitle, title=$title, visualStyle=$visualStyle, additionalProperties=$additionalProperties}" + } + + /** Edit history metadata returned by X. */ + class Edit + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val editableUntilMsecs: JsonField, + private val editTweetIds: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + editableUntilMsecs: JsonField = JsonMissing.of(), + @JsonProperty("editTweetIds") + @ExcludeMissing + editTweetIds: JsonField> = JsonMissing.of(), + ) : this(editableUntilMsecs, editTweetIds, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editableUntilMsecs(): Optional = + editableUntilMsecs.getOptional("editableUntilMsecs") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun editTweetIds(): Optional> = editTweetIds.getOptional("editTweetIds") + + /** + * Returns the raw JSON value of [editableUntilMsecs]. + * + * Unlike [editableUntilMsecs], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("editableUntilMsecs") + @ExcludeMissing + fun _editableUntilMsecs(): JsonField = editableUntilMsecs + + /** + * Returns the raw JSON value of [editTweetIds]. + * + * Unlike [editTweetIds], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("editTweetIds") + @ExcludeMissing + fun _editTweetIds(): JsonField> = editTweetIds + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Edit]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Edit]. */ + class Builder internal constructor() { + + private var editableUntilMsecs: JsonField = JsonMissing.of() + private var editTweetIds: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(edit: Edit) = apply { + editableUntilMsecs = edit.editableUntilMsecs + editTweetIds = edit.editTweetIds.map { it.toMutableList() } + additionalProperties = edit.additionalProperties.toMutableMap() + } + + fun editableUntilMsecs(editableUntilMsecs: String) = + editableUntilMsecs(JsonField.of(editableUntilMsecs)) + + /** + * Sets [Builder.editableUntilMsecs] to an arbitrary JSON value. + * + * You should usually call [Builder.editableUntilMsecs] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editableUntilMsecs(editableUntilMsecs: JsonField) = apply { + this.editableUntilMsecs = editableUntilMsecs + } + + fun editTweetIds(editTweetIds: List) = editTweetIds(JsonField.of(editTweetIds)) + + /** + * Sets [Builder.editTweetIds] to an arbitrary JSON value. + * + * You should usually call [Builder.editTweetIds] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun editTweetIds(editTweetIds: JsonField>) = apply { + this.editTweetIds = editTweetIds.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [editTweetIds]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addEditTweetId(editTweetId: String) = apply { + editTweetIds = + (editTweetIds ?: JsonField.of(mutableListOf())).also { + checkKnown("editTweetIds", it).add(editTweetId) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Edit]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Edit = + Edit( + editableUntilMsecs, + (editTweetIds ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Edit = apply { + if (validated) { + return@apply + } + + editableUntilMsecs() + editTweetIds() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (editableUntilMsecs.asKnown().isPresent) 1 else 0) + + (editTweetIds.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Edit && + editableUntilMsecs == other.editableUntilMsecs && + editTweetIds == other.editTweetIds && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(editableUntilMsecs, editTweetIds, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Edit{editableUntilMsecs=$editableUntilMsecs, editTweetIds=$editTweetIds, additionalProperties=$additionalProperties}" + } + + /** Parsed entities from the tweet text (URLs, mentions, hashtags, media) */ + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + /** Complete Note Tweet content and rich-text metadata. */ + class NoteTweet + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val text: JsonField, + private val id: JsonField, + private val entities: JsonField, + private val isExpandable: JsonField, + private val richtextTags: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("entities") + @ExcludeMissing + entities: JsonField = JsonMissing.of(), + @JsonProperty("isExpandable") + @ExcludeMissing + isExpandable: JsonField = JsonMissing.of(), + @JsonProperty("richtextTags") + @ExcludeMissing + richtextTags: JsonField> = JsonMissing.of(), + ) : this(text, id, entities, isExpandable, richtextTags, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun text(): String = text.getRequired("text") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun entities(): Optional = entities.getOptional("entities") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun isExpandable(): Optional = isExpandable.getOptional("isExpandable") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun richtextTags(): Optional> = richtextTags.getOptional("richtextTags") + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [entities]. + * + * Unlike [entities], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("entities") @ExcludeMissing fun _entities(): JsonField = entities + + /** + * Returns the raw JSON value of [isExpandable]. + * + * Unlike [isExpandable], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("isExpandable") + @ExcludeMissing + fun _isExpandable(): JsonField = isExpandable + + /** + * Returns the raw JSON value of [richtextTags]. + * + * Unlike [richtextTags], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("richtextTags") + @ExcludeMissing + fun _richtextTags(): JsonField> = richtextTags + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [NoteTweet]. + * + * The following fields are required: + * ```java + * .text() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [NoteTweet]. */ + class Builder internal constructor() { + + private var text: JsonField? = null + private var id: JsonField = JsonMissing.of() + private var entities: JsonField = JsonMissing.of() + private var isExpandable: JsonField = JsonMissing.of() + private var richtextTags: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(noteTweet: NoteTweet) = apply { + text = noteTweet.text + id = noteTweet.id + entities = noteTweet.entities + isExpandable = noteTweet.isExpandable + richtextTags = noteTweet.richtextTags.map { it.toMutableList() } + additionalProperties = noteTweet.additionalProperties.toMutableMap() + } + + fun text(text: String) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun text(text: JsonField) = apply { this.text = text } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun entities(entities: Entities) = entities(JsonField.of(entities)) + + /** + * Sets [Builder.entities] to an arbitrary JSON value. + * + * You should usually call [Builder.entities] with a well-typed [Entities] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun entities(entities: JsonField) = apply { this.entities = entities } + + fun isExpandable(isExpandable: Boolean) = isExpandable(JsonField.of(isExpandable)) + + /** + * Sets [Builder.isExpandable] to an arbitrary JSON value. + * + * You should usually call [Builder.isExpandable] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun isExpandable(isExpandable: JsonField) = apply { + this.isExpandable = isExpandable + } + + fun richtextTags(richtextTags: List) = + richtextTags(JsonField.of(richtextTags)) + + /** + * Sets [Builder.richtextTags] to an arbitrary JSON value. + * + * You should usually call [Builder.richtextTags] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun richtextTags(richtextTags: JsonField>) = apply { + this.richtextTags = richtextTags.map { it.toMutableList() } + } + + /** + * Adds a single [RichtextTag] to [richtextTags]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addRichtextTag(richtextTag: RichtextTag) = apply { + richtextTags = + (richtextTags ?: JsonField.of(mutableListOf())).also { + checkKnown("richtextTags", it).add(richtextTag) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [NoteTweet]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .text() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): NoteTweet = + NoteTweet( + checkRequired("text", text), + id, + entities, + isExpandable, + (richtextTags ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): NoteTweet = apply { + if (validated) { + return@apply + } + + text() + id() + entities().ifPresent { it.validate() } + isExpandable() + richtextTags().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (text.asKnown().isPresent) 1 else 0) + + (if (id.asKnown().isPresent) 1 else 0) + + (entities.asKnown().getOrNull()?.validity() ?: 0) + + (if (isExpandable.asKnown().isPresent) 1 else 0) + + (richtextTags.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + class Entities + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Entities]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Entities]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(entities: Entities) = apply { + additionalProperties = entities.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Entities]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Entities = Entities(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Entities = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Entities && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "Entities{additionalProperties=$additionalProperties}" + } + + class RichtextTag + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val fromIndex: JsonField, + private val toIndex: JsonField, + private val types: JsonField>, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("fromIndex") + @ExcludeMissing + fromIndex: JsonField = JsonMissing.of(), + @JsonProperty("toIndex") + @ExcludeMissing + toIndex: JsonField = JsonMissing.of(), + @JsonProperty("types") + @ExcludeMissing + types: JsonField> = JsonMissing.of(), + ) : this(fromIndex, toIndex, types, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun fromIndex(): Long = fromIndex.getRequired("fromIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun toIndex(): Long = toIndex.getRequired("toIndex") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun types(): List = types.getRequired("types") + + /** + * Returns the raw JSON value of [fromIndex]. + * + * Unlike [fromIndex], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("fromIndex") @ExcludeMissing fun _fromIndex(): JsonField = fromIndex + + /** + * Returns the raw JSON value of [toIndex]. + * + * Unlike [toIndex], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("toIndex") @ExcludeMissing fun _toIndex(): JsonField = toIndex + + /** + * Returns the raw JSON value of [types]. + * + * Unlike [types], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("types") @ExcludeMissing fun _types(): JsonField> = types + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [RichtextTag]. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [RichtextTag]. */ + class Builder internal constructor() { + + private var fromIndex: JsonField? = null + private var toIndex: JsonField? = null + private var types: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(richtextTag: RichtextTag) = apply { + fromIndex = richtextTag.fromIndex + toIndex = richtextTag.toIndex + types = richtextTag.types.map { it.toMutableList() } + additionalProperties = richtextTag.additionalProperties.toMutableMap() + } + + fun fromIndex(fromIndex: Long) = fromIndex(JsonField.of(fromIndex)) + + /** + * Sets [Builder.fromIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.fromIndex] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun fromIndex(fromIndex: JsonField) = apply { this.fromIndex = fromIndex } + + fun toIndex(toIndex: Long) = toIndex(JsonField.of(toIndex)) + + /** + * Sets [Builder.toIndex] to an arbitrary JSON value. + * + * You should usually call [Builder.toIndex] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun toIndex(toIndex: JsonField) = apply { this.toIndex = toIndex } + + fun types(types: List) = types(JsonField.of(types)) + + /** + * Sets [Builder.types] to an arbitrary JSON value. + * + * You should usually call [Builder.types] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun types(types: JsonField>) = apply { + this.types = types.map { it.toMutableList() } + } + + /** + * Adds a single [String] to [types]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addType(type: String) = apply { + types = + (types ?: JsonField.of(mutableListOf())).also { + checkKnown("types", it).add(type) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [RichtextTag]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .fromIndex() + * .toIndex() + * .types() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): RichtextTag = + RichtextTag( + checkRequired("fromIndex", fromIndex), + checkRequired("toIndex", toIndex), + checkRequired("types", types).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): RichtextTag = apply { + if (validated) { + return@apply + } + + fromIndex() + toIndex() + types() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (fromIndex.asKnown().isPresent) 1 else 0) + + (if (toIndex.asKnown().isPresent) 1 else 0) + + (types.asKnown().getOrNull()?.size ?: 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is RichtextTag && + fromIndex == other.fromIndex && + toIndex == other.toIndex && + types == other.types && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(fromIndex, toIndex, types, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "RichtextTag{fromIndex=$fromIndex, toIndex=$toIndex, types=$types, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is NoteTweet && + text == other.text && + id == other.id && + entities == other.entities && + isExpandable == other.isExpandable && + richtextTags == other.richtextTags && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash(text, id, entities, isExpandable, richtextTags, additionalProperties) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "NoteTweet{text=$text, id=$id, entities=$entities, isExpandable=$isExpandable, richtextTags=$richtextTags, additionalProperties=$additionalProperties}" + } + + /** Public place metadata attached to a tweet. */ + class Place + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val id: JsonField, + private val boundingBox: JsonField, + private val country: JsonField, + private val countryCode: JsonField, + private val fullName: JsonField, + private val name: JsonField, + private val placeType: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("id") @ExcludeMissing id: JsonField = JsonMissing.of(), + @JsonProperty("boundingBox") + @ExcludeMissing + boundingBox: JsonField = JsonMissing.of(), + @JsonProperty("country") @ExcludeMissing country: JsonField = JsonMissing.of(), + @JsonProperty("countryCode") + @ExcludeMissing + countryCode: JsonField = JsonMissing.of(), + @JsonProperty("fullName") + @ExcludeMissing + fullName: JsonField = JsonMissing.of(), + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("placeType") + @ExcludeMissing + placeType: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun id(): Optional = id.getOptional("id") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun boundingBox(): Optional = boundingBox.getOptional("boundingBox") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun country(): Optional = country.getOptional("country") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun countryCode(): Optional = countryCode.getOptional("countryCode") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun fullName(): Optional = fullName.getOptional("fullName") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun name(): Optional = name.getOptional("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun placeType(): Optional = placeType.getOptional("placeType") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun url(): Optional = url.getOptional("url") + + /** + * Returns the raw JSON value of [id]. + * + * Unlike [id], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("id") @ExcludeMissing fun _id(): JsonField = id + + /** + * Returns the raw JSON value of [boundingBox]. + * + * Unlike [boundingBox], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("boundingBox") + @ExcludeMissing + fun _boundingBox(): JsonField = boundingBox + + /** + * Returns the raw JSON value of [country]. + * + * Unlike [country], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("country") @ExcludeMissing fun _country(): JsonField = country + + /** + * Returns the raw JSON value of [countryCode]. + * + * Unlike [countryCode], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("countryCode") + @ExcludeMissing + fun _countryCode(): JsonField = countryCode + + /** + * Returns the raw JSON value of [fullName]. + * + * Unlike [fullName], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("fullName") @ExcludeMissing fun _fullName(): JsonField = fullName + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [placeType]. + * + * Unlike [placeType], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("placeType") @ExcludeMissing fun _placeType(): JsonField = placeType + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [Place]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Place]. */ + class Builder internal constructor() { + + private var id: JsonField = JsonMissing.of() + private var boundingBox: JsonField = JsonMissing.of() + private var country: JsonField = JsonMissing.of() + private var countryCode: JsonField = JsonMissing.of() + private var fullName: JsonField = JsonMissing.of() + private var name: JsonField = JsonMissing.of() + private var placeType: JsonField = JsonMissing.of() + private var url: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(place: Place) = apply { + id = place.id + boundingBox = place.boundingBox + country = place.country + countryCode = place.countryCode + fullName = place.fullName + name = place.name + placeType = place.placeType + url = place.url + additionalProperties = place.additionalProperties.toMutableMap() + } + + fun id(id: String) = id(JsonField.of(id)) + + /** + * Sets [Builder.id] to an arbitrary JSON value. + * + * You should usually call [Builder.id] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun id(id: JsonField) = apply { this.id = id } + + fun boundingBox(boundingBox: BoundingBox) = boundingBox(JsonField.of(boundingBox)) + + /** + * Sets [Builder.boundingBox] to an arbitrary JSON value. + * + * You should usually call [Builder.boundingBox] with a well-typed [BoundingBox] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun boundingBox(boundingBox: JsonField) = apply { + this.boundingBox = boundingBox + } + + fun country(country: String) = country(JsonField.of(country)) + + /** + * Sets [Builder.country] to an arbitrary JSON value. + * + * You should usually call [Builder.country] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun country(country: JsonField) = apply { this.country = country } + + fun countryCode(countryCode: String) = countryCode(JsonField.of(countryCode)) + + /** + * Sets [Builder.countryCode] to an arbitrary JSON value. + * + * You should usually call [Builder.countryCode] with a well-typed [String] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun countryCode(countryCode: JsonField) = apply { + this.countryCode = countryCode + } + + fun fullName(fullName: String) = fullName(JsonField.of(fullName)) + + /** + * Sets [Builder.fullName] to an arbitrary JSON value. + * + * You should usually call [Builder.fullName] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun fullName(fullName: JsonField) = apply { this.fullName = fullName } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun placeType(placeType: String) = placeType(JsonField.of(placeType)) + + /** + * Sets [Builder.placeType] to an arbitrary JSON value. + * + * You should usually call [Builder.placeType] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun placeType(placeType: JsonField) = apply { this.placeType = placeType } + + fun url(url: String) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [String] value instead. This + * method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Place]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): Place = + Place( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Place = apply { + if (validated) { + return@apply + } + + id() + boundingBox().ifPresent { it.validate() } + country() + countryCode() + fullName() + name() + placeType() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (id.asKnown().isPresent) 1 else 0) + + (boundingBox.asKnown().getOrNull()?.validity() ?: 0) + + (if (country.asKnown().isPresent) 1 else 0) + + (if (countryCode.asKnown().isPresent) 1 else 0) + + (if (fullName.asKnown().isPresent) 1 else 0) + + (if (name.asKnown().isPresent) 1 else 0) + + (if (placeType.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + class BoundingBox + @JsonCreator + private constructor( + @com.fasterxml.jackson.annotation.JsonValue + private val additionalProperties: Map + ) { + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = additionalProperties + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [BoundingBox]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [BoundingBox]. */ + class Builder internal constructor() { + + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(boundingBox: BoundingBox) = apply { + additionalProperties = boundingBox.additionalProperties.toMutableMap() + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [BoundingBox]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): BoundingBox = BoundingBox(additionalProperties.toImmutable()) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): BoundingBox = apply { + if (validated) { + return@apply + } + + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = additionalProperties.count { (_, value) -> + !value.isNull() && !value.isMissing() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is BoundingBox && additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { Objects.hash(additionalProperties) } + + override fun hashCode(): Int = hashCode + + override fun toString() = "BoundingBox{additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Place && + id == other.id && + boundingBox == other.boundingBox && + country == other.country && + countryCode == other.countryCode && + fullName == other.fullName && + name == other.name && + placeType == other.placeType && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + id, + boundingBox, + country, + countryCode, + fullName, + name, + placeType, + url, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Place{id=$id, boundingBox=$boundingBox, country=$country, countryCode=$countryCode, fullName=$fullName, name=$name, placeType=$placeType, url=$url, additionalProperties=$additionalProperties}" + } + + /** Engagement counts retained from a prior tweet edit. */ + class PreviousCounts + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val bookmarkCount: JsonField, + private val likeCount: JsonField, + private val quoteCount: JsonField, + private val replyCount: JsonField, + private val retweetCount: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("bookmarkCount") + @ExcludeMissing + bookmarkCount: JsonField = JsonMissing.of(), + @JsonProperty("likeCount") + @ExcludeMissing + likeCount: JsonField = JsonMissing.of(), + @JsonProperty("quoteCount") + @ExcludeMissing + quoteCount: JsonField = JsonMissing.of(), + @JsonProperty("replyCount") + @ExcludeMissing + replyCount: JsonField = JsonMissing.of(), + @JsonProperty("retweetCount") + @ExcludeMissing + retweetCount: JsonField = JsonMissing.of(), + ) : this(bookmarkCount, likeCount, quoteCount, replyCount, retweetCount, mutableMapOf()) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun bookmarkCount(): Optional = bookmarkCount.getOptional("bookmarkCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun likeCount(): Optional = likeCount.getOptional("likeCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun quoteCount(): Optional = quoteCount.getOptional("quoteCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun replyCount(): Optional = replyCount.getOptional("replyCount") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * (e.g. if the server responded with an unexpected value). + */ + fun retweetCount(): Optional = retweetCount.getOptional("retweetCount") + + /** + * Returns the raw JSON value of [bookmarkCount]. + * + * Unlike [bookmarkCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("bookmarkCount") + @ExcludeMissing + fun _bookmarkCount(): JsonField = bookmarkCount + + /** + * Returns the raw JSON value of [likeCount]. + * + * Unlike [likeCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("likeCount") @ExcludeMissing fun _likeCount(): JsonField = likeCount + + /** + * Returns the raw JSON value of [quoteCount]. + * + * Unlike [quoteCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("quoteCount") @ExcludeMissing fun _quoteCount(): JsonField = quoteCount + + /** + * Returns the raw JSON value of [replyCount]. + * + * Unlike [replyCount], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("replyCount") @ExcludeMissing fun _replyCount(): JsonField = replyCount + + /** + * Returns the raw JSON value of [retweetCount]. + * + * Unlike [retweetCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("retweetCount") + @ExcludeMissing + fun _retweetCount(): JsonField = retweetCount + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** Returns a mutable builder for constructing an instance of [PreviousCounts]. */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [PreviousCounts]. */ + class Builder internal constructor() { + + private var bookmarkCount: JsonField = JsonMissing.of() + private var likeCount: JsonField = JsonMissing.of() + private var quoteCount: JsonField = JsonMissing.of() + private var replyCount: JsonField = JsonMissing.of() + private var retweetCount: JsonField = JsonMissing.of() + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(previousCounts: PreviousCounts) = apply { + bookmarkCount = previousCounts.bookmarkCount + likeCount = previousCounts.likeCount + quoteCount = previousCounts.quoteCount + replyCount = previousCounts.replyCount + retweetCount = previousCounts.retweetCount + additionalProperties = previousCounts.additionalProperties.toMutableMap() + } + + fun bookmarkCount(bookmarkCount: Long) = bookmarkCount(JsonField.of(bookmarkCount)) + + /** + * Sets [Builder.bookmarkCount] to an arbitrary JSON value. + * + * You should usually call [Builder.bookmarkCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun bookmarkCount(bookmarkCount: JsonField) = apply { + this.bookmarkCount = bookmarkCount + } + + fun likeCount(likeCount: Long) = likeCount(JsonField.of(likeCount)) + + /** + * Sets [Builder.likeCount] to an arbitrary JSON value. + * + * You should usually call [Builder.likeCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun likeCount(likeCount: JsonField) = apply { this.likeCount = likeCount } + + fun quoteCount(quoteCount: Long) = quoteCount(JsonField.of(quoteCount)) + + /** + * Sets [Builder.quoteCount] to an arbitrary JSON value. + * + * You should usually call [Builder.quoteCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun quoteCount(quoteCount: JsonField) = apply { this.quoteCount = quoteCount } + + fun replyCount(replyCount: Long) = replyCount(JsonField.of(replyCount)) + + /** + * Sets [Builder.replyCount] to an arbitrary JSON value. + * + * You should usually call [Builder.replyCount] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun replyCount(replyCount: JsonField) = apply { this.replyCount = replyCount } + + fun retweetCount(retweetCount: Long) = retweetCount(JsonField.of(retweetCount)) + + /** + * Sets [Builder.retweetCount] to an arbitrary JSON value. + * + * You should usually call [Builder.retweetCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun retweetCount(retweetCount: JsonField) = apply { + this.retweetCount = retweetCount + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [PreviousCounts]. + * + * Further updates to this [Builder] will not mutate the returned instance. + */ + fun build(): PreviousCounts = + PreviousCounts( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): PreviousCounts = apply { + if (validated) { + return@apply + } + + bookmarkCount() + likeCount() + quoteCount() + replyCount() + retweetCount() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (bookmarkCount.asKnown().isPresent) 1 else 0) + + (if (likeCount.asKnown().isPresent) 1 else 0) + + (if (quoteCount.asKnown().isPresent) 1 else 0) + + (if (replyCount.asKnown().isPresent) 1 else 0) + + (if (retweetCount.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is PreviousCounts && + bookmarkCount == other.bookmarkCount && + likeCount == other.likeCount && + quoteCount == other.quoteCount && + replyCount == other.replyCount && + retweetCount == other.retweetCount && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + bookmarkCount, + likeCount, + quoteCount, + replyCount, + retweetCount, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "PreviousCounts{bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, additionalProperties=$additionalProperties}" } override fun equals(other: Any?): Boolean { @@ -1355,11 +4495,15 @@ private constructor( retweetCount == other.retweetCount && text == other.text && viewCount == other.viewCount && + article == other.article && author == other.author && + card == other.card && + communityNote == other.communityNote && contentDisclosure == other.contentDisclosure && conversationId == other.conversationId && createdAt == other.createdAt && displayTextRange == other.displayTextRange && + edit == other.edit && entities == other.entities && inReplyToId == other.inReplyToId && inReplyToUserId == other.inReplyToUserId && @@ -1368,13 +4512,19 @@ private constructor( isNoteTweet == other.isNoteTweet && isQuoteStatus == other.isQuoteStatus && isReply == other.isReply && + isTranslatable == other.isTranslatable && lang == other.lang && media == other.media && + noteTweet == other.noteTweet && + place == other.place && + possiblySensitive == other.possiblySensitive && + previousCounts == other.previousCounts && quotedTweet == other.quotedTweet && retweetedTweet == other.retweetedTweet && source == other.source && type == other.type && url == other.url && + viewState == other.viewState && additionalProperties == other.additionalProperties } @@ -1388,11 +4538,15 @@ private constructor( retweetCount, text, viewCount, + article, author, + card, + communityNote, contentDisclosure, conversationId, createdAt, displayTextRange, + edit, entities, inReplyToId, inReplyToUserId, @@ -1401,13 +4555,19 @@ private constructor( isNoteTweet, isQuoteStatus, isReply, + isTranslatable, lang, media, + noteTweet, + place, + possiblySensitive, + previousCounts, quotedTweet, retweetedTweet, source, type, url, + viewState, additionalProperties, ) } @@ -1415,5 +4575,5 @@ private constructor( override fun hashCode(): Int = hashCode override fun toString() = - "TweetDetail{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, author=$author, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, lang=$lang, media=$media, quotedTweet=$quotedTweet, retweetedTweet=$retweetedTweet, source=$source, type=$type, url=$url, additionalProperties=$additionalProperties}" + "TweetDetail{id=$id, bookmarkCount=$bookmarkCount, likeCount=$likeCount, quoteCount=$quoteCount, replyCount=$replyCount, retweetCount=$retweetCount, text=$text, viewCount=$viewCount, article=$article, author=$author, card=$card, communityNote=$communityNote, contentDisclosure=$contentDisclosure, conversationId=$conversationId, createdAt=$createdAt, displayTextRange=$displayTextRange, edit=$edit, entities=$entities, inReplyToId=$inReplyToId, inReplyToUserId=$inReplyToUserId, inReplyToUsername=$inReplyToUsername, isLimitedReply=$isLimitedReply, isNoteTweet=$isNoteTweet, isQuoteStatus=$isQuoteStatus, isReply=$isReply, isTranslatable=$isTranslatable, lang=$lang, media=$media, noteTweet=$noteTweet, place=$place, possiblySensitive=$possiblySensitive, previousCounts=$previousCounts, quotedTweet=$quotedTweet, retweetedTweet=$retweetedTweet, source=$source, type=$type, url=$url, viewState=$viewState, additionalProperties=$additionalProperties}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetQuotesParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetQuotesParams.kt index 8d1b6ce..ab20c84 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetQuotesParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetQuotesParams.kt @@ -110,10 +110,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -395,10 +393,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParams.kt index 00aca1a..8ef7a7e 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParams.kt @@ -19,10 +19,10 @@ import java.util.Optional import kotlin.jvm.optionals.getOrNull /** - * Returns visible replies. For an unfiltered first page, Xquik compares a terminal page with the - * post's reported reply count. If the page is visibly incomplete, the endpoint returns 424 - * `replies_incomplete` instead of presenting partial coverage as complete. Use tweet search with a - * `conversation_id:{id}` query as the broader fallback. + * Returns direct replies. Complete mode merges available timeline views, supported rankings, every + * forward cursor module, labeled hidden-content branches, exact-parent time partitions scaled to + * the reported reply count, and search. It separates nested replies and returns 424 below 80% + * coverage. */ class TweetGetRepliesParams private constructor( @@ -37,12 +37,14 @@ private constructor( private val hashtags: String?, private val inReplyToTweetId: String?, private val language: String?, + private val limit: Long?, private val mediaType: MediaType?, private val mentioning: String?, private val minFaves: Long?, private val minQuotes: Long?, private val minReplies: Long?, private val minRetweets: Long?, + private val mode: Mode?, private val pageSize: Long?, private val quotes: Quotes?, private val quotesOfTweetId: String?, @@ -92,6 +94,12 @@ private constructor( /** Language code filter, e.g. en or tr. */ fun language(): Optional = Optional.ofNullable(language) + /** + * With mode=complete, maximum combined direct and nested reply rows (1-25000). Without complete + * mode, this is the deprecated pageSize alias and uses the normal 1-100 page range. + */ + fun limit(): Optional = Optional.ofNullable(limit) + /** Filter by media type. */ fun mediaType(): Optional = Optional.ofNullable(mediaType) @@ -111,10 +119,14 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Set complete for maximum-coverage collection. Complete mode accepts only limit. Remove + * cursor, pageSize, count, time ranges, and tweet filters. + */ + fun mode(): Optional = Optional.ofNullable(mode) + + /** + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -184,12 +196,14 @@ private constructor( private var hashtags: String? = null private var inReplyToTweetId: String? = null private var language: String? = null + private var limit: Long? = null private var mediaType: MediaType? = null private var mentioning: String? = null private var minFaves: Long? = null private var minQuotes: Long? = null private var minReplies: Long? = null private var minRetweets: Long? = null + private var mode: Mode? = null private var pageSize: Long? = null private var quotes: Quotes? = null private var quotesOfTweetId: String? = null @@ -219,12 +233,14 @@ private constructor( hashtags = tweetGetRepliesParams.hashtags inReplyToTweetId = tweetGetRepliesParams.inReplyToTweetId language = tweetGetRepliesParams.language + limit = tweetGetRepliesParams.limit mediaType = tweetGetRepliesParams.mediaType mentioning = tweetGetRepliesParams.mentioning minFaves = tweetGetRepliesParams.minFaves minQuotes = tweetGetRepliesParams.minQuotes minReplies = tweetGetRepliesParams.minReplies minRetweets = tweetGetRepliesParams.minRetweets + mode = tweetGetRepliesParams.mode pageSize = tweetGetRepliesParams.pageSize quotes = tweetGetRepliesParams.quotes quotesOfTweetId = tweetGetRepliesParams.quotesOfTweetId @@ -313,6 +329,23 @@ private constructor( /** Alias for calling [Builder.language] with `language.orElse(null)`. */ fun language(language: Optional) = language(language.getOrNull()) + /** + * With mode=complete, maximum combined direct and nested reply rows (1-25000). Without + * complete mode, this is the deprecated pageSize alias and uses the normal 1-100 page + * range. + */ + fun limit(limit: Long?) = apply { this.limit = limit } + + /** + * Alias for [Builder.limit]. + * + * This unboxed primitive overload exists for backwards compatibility. + */ + fun limit(limit: Long) = limit(limit as Long?) + + /** Alias for calling [Builder.limit] with `limit.orElse(null)`. */ + fun limit(limit: Optional) = limit(limit.getOrNull()) + /** Filter by media type. */ fun mediaType(mediaType: MediaType?) = apply { this.mediaType = mediaType } @@ -378,10 +411,17 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Set complete for maximum-coverage collection. Complete mode accepts only limit. Remove + * cursor, pageSize, count, time ranges, and tweet filters. + */ + fun mode(mode: Mode?) = apply { this.mode = mode } + + /** Alias for calling [Builder.mode] with `mode.orElse(null)`. */ + fun mode(mode: Optional) = mode(mode.getOrNull()) + + /** + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } @@ -596,12 +636,14 @@ private constructor( hashtags, inReplyToTweetId, language, + limit, mediaType, mentioning, minFaves, minQuotes, minReplies, minRetweets, + mode, pageSize, quotes, quotesOfTweetId, @@ -641,12 +683,14 @@ private constructor( hashtags?.let { put("hashtags", it) } inReplyToTweetId?.let { put("inReplyToTweetId", it) } language?.let { put("language", it) } + limit?.let { put("limit", it.toString()) } mediaType?.let { put("mediaType", it.toString()) } mentioning?.let { put("mentioning", it) } minFaves?.let { put("minFaves", it.toString()) } minQuotes?.let { put("minQuotes", it.toString()) } minReplies?.let { put("minReplies", it.toString()) } minRetweets?.let { put("minRetweets", it.toString()) } + mode?.let { put("mode", it.toString()) } pageSize?.let { put("pageSize", it.toString()) } quotes?.let { put("quotes", it.toString()) } quotesOfTweetId?.let { put("quotesOfTweetId", it) } @@ -827,6 +871,140 @@ private constructor( override fun toString() = value.toString() } + /** + * Set complete for maximum-coverage collection. Complete mode accepts only limit. Remove + * cursor, pageSize, count, time ranges, and tweet filters. + */ + class Mode @JsonCreator private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that doesn't + * match any known member, and you want to know that value. For example, if the SDK is on an + * older version than the API, then the API may respond with new members that the SDK is + * unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val COMPLETE = of("complete") + + @JvmStatic fun of(value: String) = Mode(JsonField.of(value)) + } + + /** An enum containing [Mode]'s known values. */ + enum class Known { + COMPLETE + } + + /** + * An enum containing [Mode]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [Mode] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, if the + * SDK is on an older version than the API, then the API may respond with new members that + * the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + COMPLETE, + /** An enum member indicating that [Mode] was instantiated with an unknown value. */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or [Value._UNKNOWN] + * if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if you want + * to throw for the unknown case. + */ + fun value(): Value = + when (this) { + COMPLETE -> Value.COMPLETE + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and don't + * want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a not a + * known member. + */ + fun known(): Known = + when (this) { + COMPLETE -> Known.COMPLETE + else -> throw XTwitterScraperInvalidDataException("Unknown Mode: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for debugging + * and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does not have + * the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Mode = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Mode && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + /** Quote mode. */ class Quotes @JsonCreator private constructor(private val value: JsonField) : Enum { @@ -1273,12 +1451,14 @@ private constructor( hashtags == other.hashtags && inReplyToTweetId == other.inReplyToTweetId && language == other.language && + limit == other.limit && mediaType == other.mediaType && mentioning == other.mentioning && minFaves == other.minFaves && minQuotes == other.minQuotes && minReplies == other.minReplies && minRetweets == other.minRetweets && + mode == other.mode && pageSize == other.pageSize && quotes == other.quotes && quotesOfTweetId == other.quotesOfTweetId && @@ -1309,12 +1489,14 @@ private constructor( hashtags, inReplyToTweetId, language, + limit, mediaType, mentioning, minFaves, minQuotes, minReplies, minRetweets, + mode, pageSize, quotes, quotesOfTweetId, @@ -1333,5 +1515,5 @@ private constructor( ) override fun toString() = - "TweetGetRepliesParams{id=$id, anyWords=$anyWords, cashtags=$cashtags, conversationId=$conversationId, cursor=$cursor, exactPhrase=$exactPhrase, excludeWords=$excludeWords, fromUser=$fromUser, hashtags=$hashtags, inReplyToTweetId=$inReplyToTweetId, language=$language, mediaType=$mediaType, mentioning=$mentioning, minFaves=$minFaves, minQuotes=$minQuotes, minReplies=$minReplies, minRetweets=$minRetweets, pageSize=$pageSize, quotes=$quotes, quotesOfTweetId=$quotesOfTweetId, replies=$replies, retweets=$retweets, retweetsOfTweetId=$retweetsOfTweetId, sinceDate=$sinceDate, sinceTime=$sinceTime, toUser=$toUser, untilDate=$untilDate, untilTime=$untilTime, url=$url, verifiedOnly=$verifiedOnly, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" + "TweetGetRepliesParams{id=$id, anyWords=$anyWords, cashtags=$cashtags, conversationId=$conversationId, cursor=$cursor, exactPhrase=$exactPhrase, excludeWords=$excludeWords, fromUser=$fromUser, hashtags=$hashtags, inReplyToTweetId=$inReplyToTweetId, language=$language, limit=$limit, mediaType=$mediaType, mentioning=$mentioning, minFaves=$minFaves, minQuotes=$minQuotes, minReplies=$minReplies, minRetweets=$minRetweets, mode=$mode, pageSize=$pageSize, quotes=$quotes, quotesOfTweetId=$quotesOfTweetId, replies=$replies, retweets=$retweets, retweetsOfTweetId=$retweetsOfTweetId, sinceDate=$sinceDate, sinceTime=$sinceTime, toUser=$toUser, untilDate=$untilDate, untilTime=$untilTime, url=$url, verifiedOnly=$verifiedOnly, additionalHeaders=$additionalHeaders, additionalQueryParams=$additionalQueryParams}" } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponse.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponse.kt new file mode 100644 index 0000000..b1d9b6d --- /dev/null +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponse.kt @@ -0,0 +1,2654 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.tweets + +import com.fasterxml.jackson.annotation.JsonAnyGetter +import com.fasterxml.jackson.annotation.JsonAnySetter +import com.fasterxml.jackson.annotation.JsonCreator +import com.fasterxml.jackson.annotation.JsonProperty +import com.x_twitter_scraper.api.core.Enum +import com.x_twitter_scraper.api.core.ExcludeMissing +import com.x_twitter_scraper.api.core.JsonField +import com.x_twitter_scraper.api.core.JsonMissing +import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.checkKnown +import com.x_twitter_scraper.api.core.checkRequired +import com.x_twitter_scraper.api.core.toImmutable +import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException +import com.x_twitter_scraper.api.models.PaginatedTweets +import com.x_twitter_scraper.api.models.SearchTweet +import java.util.Collections +import java.util.Objects +import java.util.Optional +import kotlin.jvm.optionals.getOrNull + +/** + * Reply rows. Complete mode also returns nested replies and coverage diagnostics. Keep nested + * replies separate from direct coverage. + */ +class TweetGetRepliesResponse +@JsonCreator(mode = JsonCreator.Mode.DISABLED) +private constructor( + private val hasNextPage: JsonField, + private val nextCursor: JsonField, + private val tweets: JsonField>, + private val diagnostic: JsonField, + private val nestedReplies: JsonField>, + private val additionalProperties: MutableMap, +) { + + @JsonCreator + private constructor( + @JsonProperty("has_next_page") + @ExcludeMissing + hasNextPage: JsonField = JsonMissing.of(), + @JsonProperty("next_cursor") + @ExcludeMissing + nextCursor: JsonField = JsonMissing.of(), + @JsonProperty("tweets") + @ExcludeMissing + tweets: JsonField> = JsonMissing.of(), + @JsonProperty("diagnostic") + @ExcludeMissing + diagnostic: JsonField = JsonMissing.of(), + @JsonProperty("nested_replies") + @ExcludeMissing + nestedReplies: JsonField> = JsonMissing.of(), + ) : this(hasNextPage, nextCursor, tweets, diagnostic, nestedReplies, mutableMapOf()) + + fun toPaginatedTweets(): PaginatedTweets = + PaginatedTweets.builder() + .hasNextPage(hasNextPage) + .nextCursor(nextCursor) + .tweets(tweets) + .build() + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun hasNextPage(): Boolean = hasNextPage.getRequired("has_next_page") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun nextCursor(): String = nextCursor.getRequired("next_cursor") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or is + * unexpectedly missing or null (e.g. if the server responded with an unexpected value). + */ + fun tweets(): List = tweets.getRequired("tweets") + + /** + * Evidence for direct-reply coverage and collector behavior. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun diagnostic(): Optional = diagnostic.getOptional("diagnostic") + + /** + * Nested replies. Excluded from direct coverage. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type (e.g. if + * the server responded with an unexpected value). + */ + fun nestedReplies(): Optional> = nestedReplies.getOptional("nested_replies") + + /** + * Returns the raw JSON value of [hasNextPage]. + * + * Unlike [hasNextPage], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("has_next_page") + @ExcludeMissing + fun _hasNextPage(): JsonField = hasNextPage + + /** + * Returns the raw JSON value of [nextCursor]. + * + * Unlike [nextCursor], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("next_cursor") @ExcludeMissing fun _nextCursor(): JsonField = nextCursor + + /** + * Returns the raw JSON value of [tweets]. + * + * Unlike [tweets], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("tweets") @ExcludeMissing fun _tweets(): JsonField> = tweets + + /** + * Returns the raw JSON value of [diagnostic]. + * + * Unlike [diagnostic], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("diagnostic") + @ExcludeMissing + fun _diagnostic(): JsonField = diagnostic + + /** + * Returns the raw JSON value of [nestedReplies]. + * + * Unlike [nestedReplies], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("nested_replies") + @ExcludeMissing + fun _nestedReplies(): JsonField> = nestedReplies + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [TweetGetRepliesResponse]. + * + * The following fields are required: + * ```java + * .hasNextPage() + * .nextCursor() + * .tweets() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [TweetGetRepliesResponse]. */ + class Builder internal constructor() { + + private var hasNextPage: JsonField? = null + private var nextCursor: JsonField? = null + private var tweets: JsonField>? = null + private var diagnostic: JsonField = JsonMissing.of() + private var nestedReplies: JsonField>? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(tweetGetRepliesResponse: TweetGetRepliesResponse) = apply { + hasNextPage = tweetGetRepliesResponse.hasNextPage + nextCursor = tweetGetRepliesResponse.nextCursor + tweets = tweetGetRepliesResponse.tweets.map { it.toMutableList() } + diagnostic = tweetGetRepliesResponse.diagnostic + nestedReplies = tweetGetRepliesResponse.nestedReplies.map { it.toMutableList() } + additionalProperties = tweetGetRepliesResponse.additionalProperties.toMutableMap() + } + + fun hasNextPage(hasNextPage: Boolean) = hasNextPage(JsonField.of(hasNextPage)) + + /** + * Sets [Builder.hasNextPage] to an arbitrary JSON value. + * + * You should usually call [Builder.hasNextPage] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun hasNextPage(hasNextPage: JsonField) = apply { this.hasNextPage = hasNextPage } + + fun nextCursor(nextCursor: String) = nextCursor(JsonField.of(nextCursor)) + + /** + * Sets [Builder.nextCursor] to an arbitrary JSON value. + * + * You should usually call [Builder.nextCursor] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet supported + * value. + */ + fun nextCursor(nextCursor: JsonField) = apply { this.nextCursor = nextCursor } + + fun tweets(tweets: List) = tweets(JsonField.of(tweets)) + + /** + * Sets [Builder.tweets] to an arbitrary JSON value. + * + * You should usually call [Builder.tweets] with a well-typed `List` value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun tweets(tweets: JsonField>) = apply { + this.tweets = tweets.map { it.toMutableList() } + } + + /** + * Adds a single [SearchTweet] to [tweets]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addTweet(tweet: SearchTweet) = apply { + tweets = + (tweets ?: JsonField.of(mutableListOf())).also { + checkKnown("tweets", it).add(tweet) + } + } + + /** Evidence for direct-reply coverage and collector behavior. */ + fun diagnostic(diagnostic: Diagnostic) = diagnostic(JsonField.of(diagnostic)) + + /** + * Sets [Builder.diagnostic] to an arbitrary JSON value. + * + * You should usually call [Builder.diagnostic] with a well-typed [Diagnostic] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun diagnostic(diagnostic: JsonField) = apply { this.diagnostic = diagnostic } + + /** Nested replies. Excluded from direct coverage. */ + fun nestedReplies(nestedReplies: List) = + nestedReplies(JsonField.of(nestedReplies)) + + /** + * Sets [Builder.nestedReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.nestedReplies] with a well-typed `List` + * value instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun nestedReplies(nestedReplies: JsonField>) = apply { + this.nestedReplies = nestedReplies.map { it.toMutableList() } + } + + /** + * Adds a single [SearchTweet] to [nestedReplies]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addNestedReply(nestedReply: SearchTweet) = apply { + nestedReplies = + (nestedReplies ?: JsonField.of(mutableListOf())).also { + checkKnown("nestedReplies", it).add(nestedReply) + } + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [TweetGetRepliesResponse]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .hasNextPage() + * .nextCursor() + * .tweets() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): TweetGetRepliesResponse = + TweetGetRepliesResponse( + checkRequired("hasNextPage", hasNextPage), + checkRequired("nextCursor", nextCursor), + checkRequired("tweets", tweets).map { it.toImmutable() }, + diagnostic, + (nestedReplies ?: JsonMissing.of()).map { it.toImmutable() }, + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't match + * its expected type. + */ + fun validate(): TweetGetRepliesResponse = apply { + if (validated) { + return@apply + } + + hasNextPage() + nextCursor() + tweets().forEach { it.validate() } + diagnostic().ifPresent { it.validate() } + nestedReplies().ifPresent { it.forEach { it.validate() } } + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (hasNextPage.asKnown().isPresent) 1 else 0) + + (if (nextCursor.asKnown().isPresent) 1 else 0) + + (tweets.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (diagnostic.asKnown().getOrNull()?.validity() ?: 0) + + (nestedReplies.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + /** Evidence for direct-reply coverage and collector behavior. */ + class Diagnostic + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val complete: JsonField, + private val coveragePercentage: JsonField, + private val cursorFailures: JsonField, + private val duplicateCount: JsonField, + private val emptyFalseProgressPages: JsonField, + private val malformedCount: JsonField, + private val missingResponseModulesOrFields: JsonField>, + private val nestedReplyCount: JsonField, + private val pagesAttempted: JsonField, + private val recommendedFallback: JsonField, + private val repeatedCursorCount: JsonField, + private val reportedReplyCount: JsonField, + private val responseTruncated: JsonField, + private val richness: JsonField, + private val strategiesAttempted: JsonField>, + private val targetDirectReplies: JsonField, + private val uniqueDirectReplies: JsonField, + private val unrelatedCount: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("complete") + @ExcludeMissing + complete: JsonField = JsonMissing.of(), + @JsonProperty("coveragePercentage") + @ExcludeMissing + coveragePercentage: JsonField = JsonMissing.of(), + @JsonProperty("cursorFailures") + @ExcludeMissing + cursorFailures: JsonField = JsonMissing.of(), + @JsonProperty("duplicateCount") + @ExcludeMissing + duplicateCount: JsonField = JsonMissing.of(), + @JsonProperty("emptyFalseProgressPages") + @ExcludeMissing + emptyFalseProgressPages: JsonField = JsonMissing.of(), + @JsonProperty("malformedCount") + @ExcludeMissing + malformedCount: JsonField = JsonMissing.of(), + @JsonProperty("missingResponseModulesOrFields") + @ExcludeMissing + missingResponseModulesOrFields: JsonField> = JsonMissing.of(), + @JsonProperty("nestedReplyCount") + @ExcludeMissing + nestedReplyCount: JsonField = JsonMissing.of(), + @JsonProperty("pagesAttempted") + @ExcludeMissing + pagesAttempted: JsonField = JsonMissing.of(), + @JsonProperty("recommendedFallback") + @ExcludeMissing + recommendedFallback: JsonField = JsonMissing.of(), + @JsonProperty("repeatedCursorCount") + @ExcludeMissing + repeatedCursorCount: JsonField = JsonMissing.of(), + @JsonProperty("reportedReplyCount") + @ExcludeMissing + reportedReplyCount: JsonField = JsonMissing.of(), + @JsonProperty("responseTruncated") + @ExcludeMissing + responseTruncated: JsonField = JsonMissing.of(), + @JsonProperty("richness") + @ExcludeMissing + richness: JsonField = JsonMissing.of(), + @JsonProperty("strategiesAttempted") + @ExcludeMissing + strategiesAttempted: JsonField> = JsonMissing.of(), + @JsonProperty("targetDirectReplies") + @ExcludeMissing + targetDirectReplies: JsonField = JsonMissing.of(), + @JsonProperty("uniqueDirectReplies") + @ExcludeMissing + uniqueDirectReplies: JsonField = JsonMissing.of(), + @JsonProperty("unrelatedCount") + @ExcludeMissing + unrelatedCount: JsonField = JsonMissing.of(), + ) : this( + complete, + coveragePercentage, + cursorFailures, + duplicateCount, + emptyFalseProgressPages, + malformedCount, + missingResponseModulesOrFields, + nestedReplyCount, + pagesAttempted, + recommendedFallback, + repeatedCursorCount, + reportedReplyCount, + responseTruncated, + richness, + strategiesAttempted, + targetDirectReplies, + uniqueDirectReplies, + unrelatedCount, + mutableMapOf(), + ) + + /** + * Whether coverage met the target without truncation. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun complete(): Boolean = complete.getRequired("complete") + + /** + * Unique direct replies as a percentage of the reported count. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun coveragePercentage(): Double = coveragePercentage.getRequired("coveragePercentage") + + /** + * Cursor requests that failed. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun cursorFailures(): Long = cursorFailures.getRequired("cursorFailures") + + /** + * Duplicate tweet IDs removed across pages and strategies. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun duplicateCount(): Long = duplicateCount.getRequired("duplicateCount") + + /** + * Empty pages rejected because they did not make progress. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun emptyFalseProgressPages(): Long = + emptyFalseProgressPages.getRequired("emptyFalseProgressPages") + + /** + * Malformed response items rejected. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun malformedCount(): Long = malformedCount.getRequired("malformedCount") + + /** + * Expected response modules or fields missing from X. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun missingResponseModulesOrFields(): List = + missingResponseModulesOrFields.getRequired("missingResponseModulesOrFields") + + /** + * Unique nested replies kept outside direct coverage. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun nestedReplyCount(): Long = nestedReplyCount.getRequired("nestedReplyCount") + + /** + * Total pages attempted across all strategies. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pagesAttempted(): Long = pagesAttempted.getRequired("pagesAttempted") + + /** + * Recommended next action when coverage is incomplete. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun recommendedFallback(): String = recommendedFallback.getRequired("recommendedFallback") + + /** + * Repeated cursors rejected to prevent loops. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun repeatedCursorCount(): Long = repeatedCursorCount.getRequired("repeatedCursorCount") + + /** + * Reply count reported on the source post. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun reportedReplyCount(): Long = reportedReplyCount.getRequired("reportedReplyCount") + + /** + * Whether the requested row limit truncated safe results. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun responseTruncated(): Boolean = responseTruncated.getRequired("responseTruncated") + + /** + * Field-presence counts across the collected direct replies. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun richness(): Richness = richness.getRequired("richness") + + /** + * Per-strategy pagination and contribution evidence. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun strategiesAttempted(): List = + strategiesAttempted.getRequired("strategiesAttempted") + + /** + * Minimum direct replies required for the coverage target. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun targetDirectReplies(): Long = targetDirectReplies.getRequired("targetDirectReplies") + + /** + * Unique replies whose parent ID equals the source post ID. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun uniqueDirectReplies(): Long = uniqueDirectReplies.getRequired("uniqueDirectReplies") + + /** + * Tweets rejected because they belonged elsewhere. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type or + * is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun unrelatedCount(): Long = unrelatedCount.getRequired("unrelatedCount") + + /** + * Returns the raw JSON value of [complete]. + * + * Unlike [complete], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("complete") @ExcludeMissing fun _complete(): JsonField = complete + + /** + * Returns the raw JSON value of [coveragePercentage]. + * + * Unlike [coveragePercentage], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("coveragePercentage") + @ExcludeMissing + fun _coveragePercentage(): JsonField = coveragePercentage + + /** + * Returns the raw JSON value of [cursorFailures]. + * + * Unlike [cursorFailures], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("cursorFailures") + @ExcludeMissing + fun _cursorFailures(): JsonField = cursorFailures + + /** + * Returns the raw JSON value of [duplicateCount]. + * + * Unlike [duplicateCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("duplicateCount") + @ExcludeMissing + fun _duplicateCount(): JsonField = duplicateCount + + /** + * Returns the raw JSON value of [emptyFalseProgressPages]. + * + * Unlike [emptyFalseProgressPages], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("emptyFalseProgressPages") + @ExcludeMissing + fun _emptyFalseProgressPages(): JsonField = emptyFalseProgressPages + + /** + * Returns the raw JSON value of [malformedCount]. + * + * Unlike [malformedCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("malformedCount") + @ExcludeMissing + fun _malformedCount(): JsonField = malformedCount + + /** + * Returns the raw JSON value of [missingResponseModulesOrFields]. + * + * Unlike [missingResponseModulesOrFields], this method doesn't throw if the JSON field has + * an unexpected type. + */ + @JsonProperty("missingResponseModulesOrFields") + @ExcludeMissing + fun _missingResponseModulesOrFields(): JsonField> = + missingResponseModulesOrFields + + /** + * Returns the raw JSON value of [nestedReplyCount]. + * + * Unlike [nestedReplyCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("nestedReplyCount") + @ExcludeMissing + fun _nestedReplyCount(): JsonField = nestedReplyCount + + /** + * Returns the raw JSON value of [pagesAttempted]. + * + * Unlike [pagesAttempted], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("pagesAttempted") + @ExcludeMissing + fun _pagesAttempted(): JsonField = pagesAttempted + + /** + * Returns the raw JSON value of [recommendedFallback]. + * + * Unlike [recommendedFallback], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("recommendedFallback") + @ExcludeMissing + fun _recommendedFallback(): JsonField = recommendedFallback + + /** + * Returns the raw JSON value of [repeatedCursorCount]. + * + * Unlike [repeatedCursorCount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("repeatedCursorCount") + @ExcludeMissing + fun _repeatedCursorCount(): JsonField = repeatedCursorCount + + /** + * Returns the raw JSON value of [reportedReplyCount]. + * + * Unlike [reportedReplyCount], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("reportedReplyCount") + @ExcludeMissing + fun _reportedReplyCount(): JsonField = reportedReplyCount + + /** + * Returns the raw JSON value of [responseTruncated]. + * + * Unlike [responseTruncated], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("responseTruncated") + @ExcludeMissing + fun _responseTruncated(): JsonField = responseTruncated + + /** + * Returns the raw JSON value of [richness]. + * + * Unlike [richness], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("richness") @ExcludeMissing fun _richness(): JsonField = richness + + /** + * Returns the raw JSON value of [strategiesAttempted]. + * + * Unlike [strategiesAttempted], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("strategiesAttempted") + @ExcludeMissing + fun _strategiesAttempted(): JsonField> = strategiesAttempted + + /** + * Returns the raw JSON value of [targetDirectReplies]. + * + * Unlike [targetDirectReplies], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("targetDirectReplies") + @ExcludeMissing + fun _targetDirectReplies(): JsonField = targetDirectReplies + + /** + * Returns the raw JSON value of [uniqueDirectReplies]. + * + * Unlike [uniqueDirectReplies], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("uniqueDirectReplies") + @ExcludeMissing + fun _uniqueDirectReplies(): JsonField = uniqueDirectReplies + + /** + * Returns the raw JSON value of [unrelatedCount]. + * + * Unlike [unrelatedCount], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("unrelatedCount") + @ExcludeMissing + fun _unrelatedCount(): JsonField = unrelatedCount + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Diagnostic]. + * + * The following fields are required: + * ```java + * .complete() + * .coveragePercentage() + * .cursorFailures() + * .duplicateCount() + * .emptyFalseProgressPages() + * .malformedCount() + * .missingResponseModulesOrFields() + * .nestedReplyCount() + * .pagesAttempted() + * .recommendedFallback() + * .repeatedCursorCount() + * .reportedReplyCount() + * .responseTruncated() + * .richness() + * .strategiesAttempted() + * .targetDirectReplies() + * .uniqueDirectReplies() + * .unrelatedCount() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Diagnostic]. */ + class Builder internal constructor() { + + private var complete: JsonField? = null + private var coveragePercentage: JsonField? = null + private var cursorFailures: JsonField? = null + private var duplicateCount: JsonField? = null + private var emptyFalseProgressPages: JsonField? = null + private var malformedCount: JsonField? = null + private var missingResponseModulesOrFields: JsonField>? = null + private var nestedReplyCount: JsonField? = null + private var pagesAttempted: JsonField? = null + private var recommendedFallback: JsonField? = null + private var repeatedCursorCount: JsonField? = null + private var reportedReplyCount: JsonField? = null + private var responseTruncated: JsonField? = null + private var richness: JsonField? = null + private var strategiesAttempted: JsonField>? = null + private var targetDirectReplies: JsonField? = null + private var uniqueDirectReplies: JsonField? = null + private var unrelatedCount: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(diagnostic: Diagnostic) = apply { + complete = diagnostic.complete + coveragePercentage = diagnostic.coveragePercentage + cursorFailures = diagnostic.cursorFailures + duplicateCount = diagnostic.duplicateCount + emptyFalseProgressPages = diagnostic.emptyFalseProgressPages + malformedCount = diagnostic.malformedCount + missingResponseModulesOrFields = + diagnostic.missingResponseModulesOrFields.map { it.toMutableList() } + nestedReplyCount = diagnostic.nestedReplyCount + pagesAttempted = diagnostic.pagesAttempted + recommendedFallback = diagnostic.recommendedFallback + repeatedCursorCount = diagnostic.repeatedCursorCount + reportedReplyCount = diagnostic.reportedReplyCount + responseTruncated = diagnostic.responseTruncated + richness = diagnostic.richness + strategiesAttempted = diagnostic.strategiesAttempted.map { it.toMutableList() } + targetDirectReplies = diagnostic.targetDirectReplies + uniqueDirectReplies = diagnostic.uniqueDirectReplies + unrelatedCount = diagnostic.unrelatedCount + additionalProperties = diagnostic.additionalProperties.toMutableMap() + } + + /** Whether coverage met the target without truncation. */ + fun complete(complete: Boolean) = complete(JsonField.of(complete)) + + /** + * Sets [Builder.complete] to an arbitrary JSON value. + * + * You should usually call [Builder.complete] with a well-typed [Boolean] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun complete(complete: JsonField) = apply { this.complete = complete } + + /** Unique direct replies as a percentage of the reported count. */ + fun coveragePercentage(coveragePercentage: Double) = + coveragePercentage(JsonField.of(coveragePercentage)) + + /** + * Sets [Builder.coveragePercentage] to an arbitrary JSON value. + * + * You should usually call [Builder.coveragePercentage] with a well-typed [Double] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun coveragePercentage(coveragePercentage: JsonField) = apply { + this.coveragePercentage = coveragePercentage + } + + /** Cursor requests that failed. */ + fun cursorFailures(cursorFailures: Long) = cursorFailures(JsonField.of(cursorFailures)) + + /** + * Sets [Builder.cursorFailures] to an arbitrary JSON value. + * + * You should usually call [Builder.cursorFailures] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun cursorFailures(cursorFailures: JsonField) = apply { + this.cursorFailures = cursorFailures + } + + /** Duplicate tweet IDs removed across pages and strategies. */ + fun duplicateCount(duplicateCount: Long) = duplicateCount(JsonField.of(duplicateCount)) + + /** + * Sets [Builder.duplicateCount] to an arbitrary JSON value. + * + * You should usually call [Builder.duplicateCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun duplicateCount(duplicateCount: JsonField) = apply { + this.duplicateCount = duplicateCount + } + + /** Empty pages rejected because they did not make progress. */ + fun emptyFalseProgressPages(emptyFalseProgressPages: Long) = + emptyFalseProgressPages(JsonField.of(emptyFalseProgressPages)) + + /** + * Sets [Builder.emptyFalseProgressPages] to an arbitrary JSON value. + * + * You should usually call [Builder.emptyFalseProgressPages] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun emptyFalseProgressPages(emptyFalseProgressPages: JsonField) = apply { + this.emptyFalseProgressPages = emptyFalseProgressPages + } + + /** Malformed response items rejected. */ + fun malformedCount(malformedCount: Long) = malformedCount(JsonField.of(malformedCount)) + + /** + * Sets [Builder.malformedCount] to an arbitrary JSON value. + * + * You should usually call [Builder.malformedCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun malformedCount(malformedCount: JsonField) = apply { + this.malformedCount = malformedCount + } + + /** Expected response modules or fields missing from X. */ + fun missingResponseModulesOrFields(missingResponseModulesOrFields: List) = + missingResponseModulesOrFields(JsonField.of(missingResponseModulesOrFields)) + + /** + * Sets [Builder.missingResponseModulesOrFields] to an arbitrary JSON value. + * + * You should usually call [Builder.missingResponseModulesOrFields] with a well-typed + * `List` value instead. This method is primarily for setting the field to an + * undocumented or not yet supported value. + */ + fun missingResponseModulesOrFields( + missingResponseModulesOrFields: JsonField> + ) = apply { + this.missingResponseModulesOrFields = missingResponseModulesOrFields.map { + it.toMutableList() + } + } + + /** + * Adds a single [String] to [missingResponseModulesOrFields]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addMissingResponseModulesOrField(missingResponseModulesOrField: String) = apply { + missingResponseModulesOrFields = + (missingResponseModulesOrFields ?: JsonField.of(mutableListOf())).also { + checkKnown("missingResponseModulesOrFields", it) + .add(missingResponseModulesOrField) + } + } + + /** Unique nested replies kept outside direct coverage. */ + fun nestedReplyCount(nestedReplyCount: Long) = + nestedReplyCount(JsonField.of(nestedReplyCount)) + + /** + * Sets [Builder.nestedReplyCount] to an arbitrary JSON value. + * + * You should usually call [Builder.nestedReplyCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun nestedReplyCount(nestedReplyCount: JsonField) = apply { + this.nestedReplyCount = nestedReplyCount + } + + /** Total pages attempted across all strategies. */ + fun pagesAttempted(pagesAttempted: Long) = pagesAttempted(JsonField.of(pagesAttempted)) + + /** + * Sets [Builder.pagesAttempted] to an arbitrary JSON value. + * + * You should usually call [Builder.pagesAttempted] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun pagesAttempted(pagesAttempted: JsonField) = apply { + this.pagesAttempted = pagesAttempted + } + + /** Recommended next action when coverage is incomplete. */ + fun recommendedFallback(recommendedFallback: String) = + recommendedFallback(JsonField.of(recommendedFallback)) + + /** + * Sets [Builder.recommendedFallback] to an arbitrary JSON value. + * + * You should usually call [Builder.recommendedFallback] with a well-typed [String] + * value instead. This method is primarily for setting the field to an undocumented or + * not yet supported value. + */ + fun recommendedFallback(recommendedFallback: JsonField) = apply { + this.recommendedFallback = recommendedFallback + } + + /** Repeated cursors rejected to prevent loops. */ + fun repeatedCursorCount(repeatedCursorCount: Long) = + repeatedCursorCount(JsonField.of(repeatedCursorCount)) + + /** + * Sets [Builder.repeatedCursorCount] to an arbitrary JSON value. + * + * You should usually call [Builder.repeatedCursorCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun repeatedCursorCount(repeatedCursorCount: JsonField) = apply { + this.repeatedCursorCount = repeatedCursorCount + } + + /** Reply count reported on the source post. */ + fun reportedReplyCount(reportedReplyCount: Long) = + reportedReplyCount(JsonField.of(reportedReplyCount)) + + /** + * Sets [Builder.reportedReplyCount] to an arbitrary JSON value. + * + * You should usually call [Builder.reportedReplyCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun reportedReplyCount(reportedReplyCount: JsonField) = apply { + this.reportedReplyCount = reportedReplyCount + } + + /** Whether the requested row limit truncated safe results. */ + fun responseTruncated(responseTruncated: Boolean) = + responseTruncated(JsonField.of(responseTruncated)) + + /** + * Sets [Builder.responseTruncated] to an arbitrary JSON value. + * + * You should usually call [Builder.responseTruncated] with a well-typed [Boolean] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun responseTruncated(responseTruncated: JsonField) = apply { + this.responseTruncated = responseTruncated + } + + /** Field-presence counts across the collected direct replies. */ + fun richness(richness: Richness) = richness(JsonField.of(richness)) + + /** + * Sets [Builder.richness] to an arbitrary JSON value. + * + * You should usually call [Builder.richness] with a well-typed [Richness] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun richness(richness: JsonField) = apply { this.richness = richness } + + /** Per-strategy pagination and contribution evidence. */ + fun strategiesAttempted(strategiesAttempted: List) = + strategiesAttempted(JsonField.of(strategiesAttempted)) + + /** + * Sets [Builder.strategiesAttempted] to an arbitrary JSON value. + * + * You should usually call [Builder.strategiesAttempted] with a well-typed + * `List` value instead. This method is primarily for setting the + * field to an undocumented or not yet supported value. + */ + fun strategiesAttempted(strategiesAttempted: JsonField>) = + apply { + this.strategiesAttempted = strategiesAttempted.map { it.toMutableList() } + } + + /** + * Adds a single [StrategiesAttempted] to [Builder.strategiesAttempted]. + * + * @throws IllegalStateException if the field was previously set to a non-list. + */ + fun addStrategiesAttempted(strategiesAttempted: StrategiesAttempted) = apply { + this.strategiesAttempted = + (this.strategiesAttempted ?: JsonField.of(mutableListOf())).also { + checkKnown("strategiesAttempted", it).add(strategiesAttempted) + } + } + + /** Minimum direct replies required for the coverage target. */ + fun targetDirectReplies(targetDirectReplies: Long) = + targetDirectReplies(JsonField.of(targetDirectReplies)) + + /** + * Sets [Builder.targetDirectReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.targetDirectReplies] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun targetDirectReplies(targetDirectReplies: JsonField) = apply { + this.targetDirectReplies = targetDirectReplies + } + + /** Unique replies whose parent ID equals the source post ID. */ + fun uniqueDirectReplies(uniqueDirectReplies: Long) = + uniqueDirectReplies(JsonField.of(uniqueDirectReplies)) + + /** + * Sets [Builder.uniqueDirectReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.uniqueDirectReplies] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun uniqueDirectReplies(uniqueDirectReplies: JsonField) = apply { + this.uniqueDirectReplies = uniqueDirectReplies + } + + /** Tweets rejected because they belonged elsewhere. */ + fun unrelatedCount(unrelatedCount: Long) = unrelatedCount(JsonField.of(unrelatedCount)) + + /** + * Sets [Builder.unrelatedCount] to an arbitrary JSON value. + * + * You should usually call [Builder.unrelatedCount] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun unrelatedCount(unrelatedCount: JsonField) = apply { + this.unrelatedCount = unrelatedCount + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { additionalProperties.remove(key) } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Diagnostic]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .complete() + * .coveragePercentage() + * .cursorFailures() + * .duplicateCount() + * .emptyFalseProgressPages() + * .malformedCount() + * .missingResponseModulesOrFields() + * .nestedReplyCount() + * .pagesAttempted() + * .recommendedFallback() + * .repeatedCursorCount() + * .reportedReplyCount() + * .responseTruncated() + * .richness() + * .strategiesAttempted() + * .targetDirectReplies() + * .uniqueDirectReplies() + * .unrelatedCount() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Diagnostic = + Diagnostic( + checkRequired("complete", complete), + checkRequired("coveragePercentage", coveragePercentage), + checkRequired("cursorFailures", cursorFailures), + checkRequired("duplicateCount", duplicateCount), + checkRequired("emptyFalseProgressPages", emptyFalseProgressPages), + checkRequired("malformedCount", malformedCount), + checkRequired("missingResponseModulesOrFields", missingResponseModulesOrFields) + .map { it.toImmutable() }, + checkRequired("nestedReplyCount", nestedReplyCount), + checkRequired("pagesAttempted", pagesAttempted), + checkRequired("recommendedFallback", recommendedFallback), + checkRequired("repeatedCursorCount", repeatedCursorCount), + checkRequired("reportedReplyCount", reportedReplyCount), + checkRequired("responseTruncated", responseTruncated), + checkRequired("richness", richness), + checkRequired("strategiesAttempted", strategiesAttempted).map { + it.toImmutable() + }, + checkRequired("targetDirectReplies", targetDirectReplies), + checkRequired("uniqueDirectReplies", uniqueDirectReplies), + checkRequired("unrelatedCount", unrelatedCount), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Diagnostic = apply { + if (validated) { + return@apply + } + + complete() + coveragePercentage() + cursorFailures() + duplicateCount() + emptyFalseProgressPages() + malformedCount() + missingResponseModulesOrFields() + nestedReplyCount() + pagesAttempted() + recommendedFallback() + repeatedCursorCount() + reportedReplyCount() + responseTruncated() + richness().validate() + strategiesAttempted().forEach { it.validate() } + targetDirectReplies() + uniqueDirectReplies() + unrelatedCount() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (complete.asKnown().isPresent) 1 else 0) + + (if (coveragePercentage.asKnown().isPresent) 1 else 0) + + (if (cursorFailures.asKnown().isPresent) 1 else 0) + + (if (duplicateCount.asKnown().isPresent) 1 else 0) + + (if (emptyFalseProgressPages.asKnown().isPresent) 1 else 0) + + (if (malformedCount.asKnown().isPresent) 1 else 0) + + (missingResponseModulesOrFields.asKnown().getOrNull()?.size ?: 0) + + (if (nestedReplyCount.asKnown().isPresent) 1 else 0) + + (if (pagesAttempted.asKnown().isPresent) 1 else 0) + + (if (recommendedFallback.asKnown().isPresent) 1 else 0) + + (if (repeatedCursorCount.asKnown().isPresent) 1 else 0) + + (if (reportedReplyCount.asKnown().isPresent) 1 else 0) + + (if (responseTruncated.asKnown().isPresent) 1 else 0) + + (richness.asKnown().getOrNull()?.validity() ?: 0) + + (strategiesAttempted.asKnown().getOrNull()?.sumOf { it.validity() } ?: 0) + + (if (targetDirectReplies.asKnown().isPresent) 1 else 0) + + (if (uniqueDirectReplies.asKnown().isPresent) 1 else 0) + + (if (unrelatedCount.asKnown().isPresent) 1 else 0) + + /** Field-presence counts across the collected direct replies. */ + class Richness + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val article: JsonField, + private val author: JsonField, + private val card: JsonField, + private val communityNote: JsonField, + private val createdAt: JsonField, + private val engagementCounts: JsonField, + private val entities: JsonField, + private val language: JsonField, + private val media: JsonField, + private val quotedOrRepostedTweet: JsonField, + private val text: JsonField, + private val totalReplies: JsonField, + private val url: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("article") + @ExcludeMissing + article: JsonField = JsonMissing.of(), + @JsonProperty("author") @ExcludeMissing author: JsonField = JsonMissing.of(), + @JsonProperty("card") @ExcludeMissing card: JsonField = JsonMissing.of(), + @JsonProperty("communityNote") + @ExcludeMissing + communityNote: JsonField = JsonMissing.of(), + @JsonProperty("createdAt") + @ExcludeMissing + createdAt: JsonField = JsonMissing.of(), + @JsonProperty("engagementCounts") + @ExcludeMissing + engagementCounts: JsonField = JsonMissing.of(), + @JsonProperty("entities") + @ExcludeMissing + entities: JsonField = JsonMissing.of(), + @JsonProperty("language") + @ExcludeMissing + language: JsonField = JsonMissing.of(), + @JsonProperty("media") @ExcludeMissing media: JsonField = JsonMissing.of(), + @JsonProperty("quotedOrRepostedTweet") + @ExcludeMissing + quotedOrRepostedTweet: JsonField = JsonMissing.of(), + @JsonProperty("text") @ExcludeMissing text: JsonField = JsonMissing.of(), + @JsonProperty("totalReplies") + @ExcludeMissing + totalReplies: JsonField = JsonMissing.of(), + @JsonProperty("url") @ExcludeMissing url: JsonField = JsonMissing.of(), + ) : this( + article, + author, + card, + communityNote, + createdAt, + engagementCounts, + entities, + language, + media, + quotedOrRepostedTweet, + text, + totalReplies, + url, + mutableMapOf(), + ) + + /** + * Replies with article content. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun article(): Long = article.getRequired("article") + + /** + * Replies with author details. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun author(): Long = author.getRequired("author") + + /** + * Replies with card metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun card(): Long = card.getRequired("card") + + /** + * Replies with community-note data. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun communityNote(): Long = communityNote.getRequired("communityNote") + + /** + * Replies with a creation timestamp. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun createdAt(): Long = createdAt.getRequired("createdAt") + + /** + * Replies with engagement counts. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun engagementCounts(): Long = engagementCounts.getRequired("engagementCounts") + + /** + * Replies with entity metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun entities(): Long = entities.getRequired("entities") + + /** + * Replies with a language value. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun language(): Long = language.getRequired("language") + + /** + * Replies with media metadata. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun media(): Long = media.getRequired("media") + + /** + * Replies with quoted or reposted tweet data. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun quotedOrRepostedTweet(): Long = + quotedOrRepostedTweet.getRequired("quotedOrRepostedTweet") + + /** + * Replies with text. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun text(): Long = text.getRequired("text") + + /** + * Total unique direct replies evaluated for richness. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun totalReplies(): Long = totalReplies.getRequired("totalReplies") + + /** + * Replies with a canonical URL. + * + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun url(): Long = url.getRequired("url") + + /** + * Returns the raw JSON value of [article]. + * + * Unlike [article], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("article") @ExcludeMissing fun _article(): JsonField = article + + /** + * Returns the raw JSON value of [author]. + * + * Unlike [author], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("author") @ExcludeMissing fun _author(): JsonField = author + + /** + * Returns the raw JSON value of [card]. + * + * Unlike [card], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("card") @ExcludeMissing fun _card(): JsonField = card + + /** + * Returns the raw JSON value of [communityNote]. + * + * Unlike [communityNote], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("communityNote") + @ExcludeMissing + fun _communityNote(): JsonField = communityNote + + /** + * Returns the raw JSON value of [createdAt]. + * + * Unlike [createdAt], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("createdAt") @ExcludeMissing fun _createdAt(): JsonField = createdAt + + /** + * Returns the raw JSON value of [engagementCounts]. + * + * Unlike [engagementCounts], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("engagementCounts") + @ExcludeMissing + fun _engagementCounts(): JsonField = engagementCounts + + /** + * Returns the raw JSON value of [entities]. + * + * Unlike [entities], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("entities") @ExcludeMissing fun _entities(): JsonField = entities + + /** + * Returns the raw JSON value of [language]. + * + * Unlike [language], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("language") @ExcludeMissing fun _language(): JsonField = language + + /** + * Returns the raw JSON value of [media]. + * + * Unlike [media], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("media") @ExcludeMissing fun _media(): JsonField = media + + /** + * Returns the raw JSON value of [quotedOrRepostedTweet]. + * + * Unlike [quotedOrRepostedTweet], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("quotedOrRepostedTweet") + @ExcludeMissing + fun _quotedOrRepostedTweet(): JsonField = quotedOrRepostedTweet + + /** + * Returns the raw JSON value of [text]. + * + * Unlike [text], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("text") @ExcludeMissing fun _text(): JsonField = text + + /** + * Returns the raw JSON value of [totalReplies]. + * + * Unlike [totalReplies], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("totalReplies") + @ExcludeMissing + fun _totalReplies(): JsonField = totalReplies + + /** + * Returns the raw JSON value of [url]. + * + * Unlike [url], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("url") @ExcludeMissing fun _url(): JsonField = url + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [Richness]. + * + * The following fields are required: + * ```java + * .article() + * .author() + * .card() + * .communityNote() + * .createdAt() + * .engagementCounts() + * .entities() + * .language() + * .media() + * .quotedOrRepostedTweet() + * .text() + * .totalReplies() + * .url() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [Richness]. */ + class Builder internal constructor() { + + private var article: JsonField? = null + private var author: JsonField? = null + private var card: JsonField? = null + private var communityNote: JsonField? = null + private var createdAt: JsonField? = null + private var engagementCounts: JsonField? = null + private var entities: JsonField? = null + private var language: JsonField? = null + private var media: JsonField? = null + private var quotedOrRepostedTweet: JsonField? = null + private var text: JsonField? = null + private var totalReplies: JsonField? = null + private var url: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(richness: Richness) = apply { + article = richness.article + author = richness.author + card = richness.card + communityNote = richness.communityNote + createdAt = richness.createdAt + engagementCounts = richness.engagementCounts + entities = richness.entities + language = richness.language + media = richness.media + quotedOrRepostedTweet = richness.quotedOrRepostedTweet + text = richness.text + totalReplies = richness.totalReplies + url = richness.url + additionalProperties = richness.additionalProperties.toMutableMap() + } + + /** Replies with article content. */ + fun article(article: Long) = article(JsonField.of(article)) + + /** + * Sets [Builder.article] to an arbitrary JSON value. + * + * You should usually call [Builder.article] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun article(article: JsonField) = apply { this.article = article } + + /** Replies with author details. */ + fun author(author: Long) = author(JsonField.of(author)) + + /** + * Sets [Builder.author] to an arbitrary JSON value. + * + * You should usually call [Builder.author] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun author(author: JsonField) = apply { this.author = author } + + /** Replies with card metadata. */ + fun card(card: Long) = card(JsonField.of(card)) + + /** + * Sets [Builder.card] to an arbitrary JSON value. + * + * You should usually call [Builder.card] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun card(card: JsonField) = apply { this.card = card } + + /** Replies with community-note data. */ + fun communityNote(communityNote: Long) = communityNote(JsonField.of(communityNote)) + + /** + * Sets [Builder.communityNote] to an arbitrary JSON value. + * + * You should usually call [Builder.communityNote] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun communityNote(communityNote: JsonField) = apply { + this.communityNote = communityNote + } + + /** Replies with a creation timestamp. */ + fun createdAt(createdAt: Long) = createdAt(JsonField.of(createdAt)) + + /** + * Sets [Builder.createdAt] to an arbitrary JSON value. + * + * You should usually call [Builder.createdAt] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun createdAt(createdAt: JsonField) = apply { this.createdAt = createdAt } + + /** Replies with engagement counts. */ + fun engagementCounts(engagementCounts: Long) = + engagementCounts(JsonField.of(engagementCounts)) + + /** + * Sets [Builder.engagementCounts] to an arbitrary JSON value. + * + * You should usually call [Builder.engagementCounts] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun engagementCounts(engagementCounts: JsonField) = apply { + this.engagementCounts = engagementCounts + } + + /** Replies with entity metadata. */ + fun entities(entities: Long) = entities(JsonField.of(entities)) + + /** + * Sets [Builder.entities] to an arbitrary JSON value. + * + * You should usually call [Builder.entities] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun entities(entities: JsonField) = apply { this.entities = entities } + + /** Replies with a language value. */ + fun language(language: Long) = language(JsonField.of(language)) + + /** + * Sets [Builder.language] to an arbitrary JSON value. + * + * You should usually call [Builder.language] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun language(language: JsonField) = apply { this.language = language } + + /** Replies with media metadata. */ + fun media(media: Long) = media(JsonField.of(media)) + + /** + * Sets [Builder.media] to an arbitrary JSON value. + * + * You should usually call [Builder.media] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun media(media: JsonField) = apply { this.media = media } + + /** Replies with quoted or reposted tweet data. */ + fun quotedOrRepostedTweet(quotedOrRepostedTweet: Long) = + quotedOrRepostedTweet(JsonField.of(quotedOrRepostedTweet)) + + /** + * Sets [Builder.quotedOrRepostedTweet] to an arbitrary JSON value. + * + * You should usually call [Builder.quotedOrRepostedTweet] with a well-typed [Long] + * value instead. This method is primarily for setting the field to an undocumented + * or not yet supported value. + */ + fun quotedOrRepostedTweet(quotedOrRepostedTweet: JsonField) = apply { + this.quotedOrRepostedTweet = quotedOrRepostedTweet + } + + /** Replies with text. */ + fun text(text: Long) = text(JsonField.of(text)) + + /** + * Sets [Builder.text] to an arbitrary JSON value. + * + * You should usually call [Builder.text] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun text(text: JsonField) = apply { this.text = text } + + /** Total unique direct replies evaluated for richness. */ + fun totalReplies(totalReplies: Long) = totalReplies(JsonField.of(totalReplies)) + + /** + * Sets [Builder.totalReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.totalReplies] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun totalReplies(totalReplies: JsonField) = apply { + this.totalReplies = totalReplies + } + + /** Replies with a canonical URL. */ + fun url(url: Long) = url(JsonField.of(url)) + + /** + * Sets [Builder.url] to an arbitrary JSON value. + * + * You should usually call [Builder.url] with a well-typed [Long] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun url(url: JsonField) = apply { this.url = url } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [Richness]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .article() + * .author() + * .card() + * .communityNote() + * .createdAt() + * .engagementCounts() + * .entities() + * .language() + * .media() + * .quotedOrRepostedTweet() + * .text() + * .totalReplies() + * .url() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): Richness = + Richness( + checkRequired("article", article), + checkRequired("author", author), + checkRequired("card", card), + checkRequired("communityNote", communityNote), + checkRequired("createdAt", createdAt), + checkRequired("engagementCounts", engagementCounts), + checkRequired("entities", entities), + checkRequired("language", language), + checkRequired("media", media), + checkRequired("quotedOrRepostedTweet", quotedOrRepostedTweet), + checkRequired("text", text), + checkRequired("totalReplies", totalReplies), + checkRequired("url", url), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): Richness = apply { + if (validated) { + return@apply + } + + article() + author() + card() + communityNote() + createdAt() + engagementCounts() + entities() + language() + media() + quotedOrRepostedTweet() + text() + totalReplies() + url() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (article.asKnown().isPresent) 1 else 0) + + (if (author.asKnown().isPresent) 1 else 0) + + (if (card.asKnown().isPresent) 1 else 0) + + (if (communityNote.asKnown().isPresent) 1 else 0) + + (if (createdAt.asKnown().isPresent) 1 else 0) + + (if (engagementCounts.asKnown().isPresent) 1 else 0) + + (if (entities.asKnown().isPresent) 1 else 0) + + (if (language.asKnown().isPresent) 1 else 0) + + (if (media.asKnown().isPresent) 1 else 0) + + (if (quotedOrRepostedTweet.asKnown().isPresent) 1 else 0) + + (if (text.asKnown().isPresent) 1 else 0) + + (if (totalReplies.asKnown().isPresent) 1 else 0) + + (if (url.asKnown().isPresent) 1 else 0) + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Richness && + article == other.article && + author == other.author && + card == other.card && + communityNote == other.communityNote && + createdAt == other.createdAt && + engagementCounts == other.engagementCounts && + entities == other.entities && + language == other.language && + media == other.media && + quotedOrRepostedTweet == other.quotedOrRepostedTweet && + text == other.text && + totalReplies == other.totalReplies && + url == other.url && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + article, + author, + card, + communityNote, + createdAt, + engagementCounts, + entities, + language, + media, + quotedOrRepostedTweet, + text, + totalReplies, + url, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Richness{article=$article, author=$author, card=$card, communityNote=$communityNote, createdAt=$createdAt, engagementCounts=$engagementCounts, entities=$entities, language=$language, media=$media, quotedOrRepostedTweet=$quotedOrRepostedTweet, text=$text, totalReplies=$totalReplies, url=$url, additionalProperties=$additionalProperties}" + } + + class StrategiesAttempted + @JsonCreator(mode = JsonCreator.Mode.DISABLED) + private constructor( + private val name: JsonField, + private val newDirectReplies: JsonField, + private val newNestedReplies: JsonField, + private val pagesAttempted: JsonField, + private val stopReason: JsonField, + private val additionalProperties: MutableMap, + ) { + + @JsonCreator + private constructor( + @JsonProperty("name") @ExcludeMissing name: JsonField = JsonMissing.of(), + @JsonProperty("newDirectReplies") + @ExcludeMissing + newDirectReplies: JsonField = JsonMissing.of(), + @JsonProperty("newNestedReplies") + @ExcludeMissing + newNestedReplies: JsonField = JsonMissing.of(), + @JsonProperty("pagesAttempted") + @ExcludeMissing + pagesAttempted: JsonField = JsonMissing.of(), + @JsonProperty("stopReason") + @ExcludeMissing + stopReason: JsonField = JsonMissing.of(), + ) : this( + name, + newDirectReplies, + newNestedReplies, + pagesAttempted, + stopReason, + mutableMapOf(), + ) + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun name(): String = name.getRequired("name") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun newDirectReplies(): Long = newDirectReplies.getRequired("newDirectReplies") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun newNestedReplies(): Long = newNestedReplies.getRequired("newNestedReplies") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun pagesAttempted(): Long = pagesAttempted.getRequired("pagesAttempted") + + /** + * @throws XTwitterScraperInvalidDataException if the JSON field has an unexpected type + * or is unexpectedly missing or null (e.g. if the server responded with an unexpected + * value). + */ + fun stopReason(): StopReason = stopReason.getRequired("stopReason") + + /** + * Returns the raw JSON value of [name]. + * + * Unlike [name], this method doesn't throw if the JSON field has an unexpected type. + */ + @JsonProperty("name") @ExcludeMissing fun _name(): JsonField = name + + /** + * Returns the raw JSON value of [newDirectReplies]. + * + * Unlike [newDirectReplies], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("newDirectReplies") + @ExcludeMissing + fun _newDirectReplies(): JsonField = newDirectReplies + + /** + * Returns the raw JSON value of [newNestedReplies]. + * + * Unlike [newNestedReplies], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("newNestedReplies") + @ExcludeMissing + fun _newNestedReplies(): JsonField = newNestedReplies + + /** + * Returns the raw JSON value of [pagesAttempted]. + * + * Unlike [pagesAttempted], this method doesn't throw if the JSON field has an + * unexpected type. + */ + @JsonProperty("pagesAttempted") + @ExcludeMissing + fun _pagesAttempted(): JsonField = pagesAttempted + + /** + * Returns the raw JSON value of [stopReason]. + * + * Unlike [stopReason], this method doesn't throw if the JSON field has an unexpected + * type. + */ + @JsonProperty("stopReason") + @ExcludeMissing + fun _stopReason(): JsonField = stopReason + + @JsonAnySetter + private fun putAdditionalProperty(key: String, value: JsonValue) { + additionalProperties.put(key, value) + } + + @JsonAnyGetter + @ExcludeMissing + fun _additionalProperties(): Map = + Collections.unmodifiableMap(additionalProperties) + + fun toBuilder() = Builder().from(this) + + companion object { + + /** + * Returns a mutable builder for constructing an instance of [StrategiesAttempted]. + * + * The following fields are required: + * ```java + * .name() + * .newDirectReplies() + * .newNestedReplies() + * .pagesAttempted() + * .stopReason() + * ``` + */ + @JvmStatic fun builder() = Builder() + } + + /** A builder for [StrategiesAttempted]. */ + class Builder internal constructor() { + + private var name: JsonField? = null + private var newDirectReplies: JsonField? = null + private var newNestedReplies: JsonField? = null + private var pagesAttempted: JsonField? = null + private var stopReason: JsonField? = null + private var additionalProperties: MutableMap = mutableMapOf() + + @JvmSynthetic + internal fun from(strategiesAttempted: StrategiesAttempted) = apply { + name = strategiesAttempted.name + newDirectReplies = strategiesAttempted.newDirectReplies + newNestedReplies = strategiesAttempted.newNestedReplies + pagesAttempted = strategiesAttempted.pagesAttempted + stopReason = strategiesAttempted.stopReason + additionalProperties = strategiesAttempted.additionalProperties.toMutableMap() + } + + fun name(name: String) = name(JsonField.of(name)) + + /** + * Sets [Builder.name] to an arbitrary JSON value. + * + * You should usually call [Builder.name] with a well-typed [String] value instead. + * This method is primarily for setting the field to an undocumented or not yet + * supported value. + */ + fun name(name: JsonField) = apply { this.name = name } + + fun newDirectReplies(newDirectReplies: Long) = + newDirectReplies(JsonField.of(newDirectReplies)) + + /** + * Sets [Builder.newDirectReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.newDirectReplies] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun newDirectReplies(newDirectReplies: JsonField) = apply { + this.newDirectReplies = newDirectReplies + } + + fun newNestedReplies(newNestedReplies: Long) = + newNestedReplies(JsonField.of(newNestedReplies)) + + /** + * Sets [Builder.newNestedReplies] to an arbitrary JSON value. + * + * You should usually call [Builder.newNestedReplies] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun newNestedReplies(newNestedReplies: JsonField) = apply { + this.newNestedReplies = newNestedReplies + } + + fun pagesAttempted(pagesAttempted: Long) = + pagesAttempted(JsonField.of(pagesAttempted)) + + /** + * Sets [Builder.pagesAttempted] to an arbitrary JSON value. + * + * You should usually call [Builder.pagesAttempted] with a well-typed [Long] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun pagesAttempted(pagesAttempted: JsonField) = apply { + this.pagesAttempted = pagesAttempted + } + + fun stopReason(stopReason: StopReason) = stopReason(JsonField.of(stopReason)) + + /** + * Sets [Builder.stopReason] to an arbitrary JSON value. + * + * You should usually call [Builder.stopReason] with a well-typed [StopReason] value + * instead. This method is primarily for setting the field to an undocumented or not + * yet supported value. + */ + fun stopReason(stopReason: JsonField) = apply { + this.stopReason = stopReason + } + + fun additionalProperties(additionalProperties: Map) = apply { + this.additionalProperties.clear() + putAllAdditionalProperties(additionalProperties) + } + + fun putAdditionalProperty(key: String, value: JsonValue) = apply { + additionalProperties.put(key, value) + } + + fun putAllAdditionalProperties(additionalProperties: Map) = + apply { + this.additionalProperties.putAll(additionalProperties) + } + + fun removeAdditionalProperty(key: String) = apply { + additionalProperties.remove(key) + } + + fun removeAllAdditionalProperties(keys: Set) = apply { + keys.forEach(::removeAdditionalProperty) + } + + /** + * Returns an immutable instance of [StrategiesAttempted]. + * + * Further updates to this [Builder] will not mutate the returned instance. + * + * The following fields are required: + * ```java + * .name() + * .newDirectReplies() + * .newNestedReplies() + * .pagesAttempted() + * .stopReason() + * ``` + * + * @throws IllegalStateException if any required field is unset. + */ + fun build(): StrategiesAttempted = + StrategiesAttempted( + checkRequired("name", name), + checkRequired("newDirectReplies", newDirectReplies), + checkRequired("newNestedReplies", newNestedReplies), + checkRequired("pagesAttempted", pagesAttempted), + checkRequired("stopReason", stopReason), + additionalProperties.toMutableMap(), + ) + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object doesn't + * match its expected type. + */ + fun validate(): StrategiesAttempted = apply { + if (validated) { + return@apply + } + + name() + newDirectReplies() + newNestedReplies() + pagesAttempted() + stopReason().validate() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic + internal fun validity(): Int = + (if (name.asKnown().isPresent) 1 else 0) + + (if (newDirectReplies.asKnown().isPresent) 1 else 0) + + (if (newNestedReplies.asKnown().isPresent) 1 else 0) + + (if (pagesAttempted.asKnown().isPresent) 1 else 0) + + (stopReason.asKnown().getOrNull()?.validity() ?: 0) + + class StopReason + @JsonCreator + private constructor(private val value: JsonField) : Enum { + + /** + * Returns this class instance's raw value. + * + * This is usually only useful if this instance was deserialized from data that + * doesn't match any known member, and you want to know that value. For example, if + * the SDK is on an older version than the API, then the API may respond with new + * members that the SDK is unaware of. + */ + @com.fasterxml.jackson.annotation.JsonValue fun _value(): JsonField = value + + companion object { + + @JvmField val DEADLINE = of("deadline") + + @JvmField val EMPTY_PAGES = of("empty_pages") + + @JvmField val ERROR = of("error") + + @JvmField val MISSING_CURSOR = of("missing_cursor") + + @JvmField val NO_NEXT_PAGE = of("no_next_page") + + @JvmField val PAGE_CAP = of("page_cap") + + @JvmField val REPEATED_CURSOR = of("repeated_cursor") + + @JvmStatic fun of(value: String) = StopReason(JsonField.of(value)) + } + + /** An enum containing [StopReason]'s known values. */ + enum class Known { + DEADLINE, + EMPTY_PAGES, + ERROR, + MISSING_CURSOR, + NO_NEXT_PAGE, + PAGE_CAP, + REPEATED_CURSOR, + } + + /** + * An enum containing [StopReason]'s known values, as well as an [_UNKNOWN] member. + * + * An instance of [StopReason] can contain an unknown value in a couple of cases: + * - It was deserialized from data that doesn't match any known member. For example, + * if the SDK is on an older version than the API, then the API may respond with + * new members that the SDK is unaware of. + * - It was constructed with an arbitrary value using the [of] method. + */ + enum class Value { + DEADLINE, + EMPTY_PAGES, + ERROR, + MISSING_CURSOR, + NO_NEXT_PAGE, + PAGE_CAP, + REPEATED_CURSOR, + /** + * An enum member indicating that [StopReason] was instantiated with an unknown + * value. + */ + _UNKNOWN, + } + + /** + * Returns an enum member corresponding to this class instance's value, or + * [Value._UNKNOWN] if the class was instantiated with an unknown value. + * + * Use the [known] method instead if you're certain the value is always known or if + * you want to throw for the unknown case. + */ + fun value(): Value = + when (this) { + DEADLINE -> Value.DEADLINE + EMPTY_PAGES -> Value.EMPTY_PAGES + ERROR -> Value.ERROR + MISSING_CURSOR -> Value.MISSING_CURSOR + NO_NEXT_PAGE -> Value.NO_NEXT_PAGE + PAGE_CAP -> Value.PAGE_CAP + REPEATED_CURSOR -> Value.REPEATED_CURSOR + else -> Value._UNKNOWN + } + + /** + * Returns an enum member corresponding to this class instance's value. + * + * Use the [value] method instead if you're uncertain the value is always known and + * don't want to throw for the unknown case. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value is a + * not a known member. + */ + fun known(): Known = + when (this) { + DEADLINE -> Known.DEADLINE + EMPTY_PAGES -> Known.EMPTY_PAGES + ERROR -> Known.ERROR + MISSING_CURSOR -> Known.MISSING_CURSOR + NO_NEXT_PAGE -> Known.NO_NEXT_PAGE + PAGE_CAP -> Known.PAGE_CAP + REPEATED_CURSOR -> Known.REPEATED_CURSOR + else -> + throw XTwitterScraperInvalidDataException("Unknown StopReason: $value") + } + + /** + * Returns this class instance's primitive wire representation. + * + * This differs from the [toString] method because that method is primarily for + * debugging and generally doesn't throw. + * + * @throws XTwitterScraperInvalidDataException if this class instance's value does + * not have the expected primitive type. + */ + fun asString(): String = + _value().asString().orElseThrow { + XTwitterScraperInvalidDataException("Value is not a String") + } + + private var validated: Boolean = false + + /** + * Validates that the types of all values in this object match their expected types + * recursively. + * + * This method is _not_ forwards compatible with new types from the API for existing + * fields. + * + * @throws XTwitterScraperInvalidDataException if any value type in this object + * doesn't match its expected type. + */ + fun validate(): StopReason = apply { + if (validated) { + return@apply + } + + known() + validated = true + } + + fun isValid(): Boolean = + try { + validate() + true + } catch (e: XTwitterScraperInvalidDataException) { + false + } + + /** + * Returns a score indicating how many valid values are contained in this object + * recursively. + * + * Used for best match union deserialization. + */ + @JvmSynthetic internal fun validity(): Int = if (value() == Value._UNKNOWN) 0 else 1 + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StopReason && value == other.value + } + + override fun hashCode() = value.hashCode() + + override fun toString() = value.toString() + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is StrategiesAttempted && + name == other.name && + newDirectReplies == other.newDirectReplies && + newNestedReplies == other.newNestedReplies && + pagesAttempted == other.pagesAttempted && + stopReason == other.stopReason && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + name, + newDirectReplies, + newNestedReplies, + pagesAttempted, + stopReason, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "StrategiesAttempted{name=$name, newDirectReplies=$newDirectReplies, newNestedReplies=$newNestedReplies, pagesAttempted=$pagesAttempted, stopReason=$stopReason, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is Diagnostic && + complete == other.complete && + coveragePercentage == other.coveragePercentage && + cursorFailures == other.cursorFailures && + duplicateCount == other.duplicateCount && + emptyFalseProgressPages == other.emptyFalseProgressPages && + malformedCount == other.malformedCount && + missingResponseModulesOrFields == other.missingResponseModulesOrFields && + nestedReplyCount == other.nestedReplyCount && + pagesAttempted == other.pagesAttempted && + recommendedFallback == other.recommendedFallback && + repeatedCursorCount == other.repeatedCursorCount && + reportedReplyCount == other.reportedReplyCount && + responseTruncated == other.responseTruncated && + richness == other.richness && + strategiesAttempted == other.strategiesAttempted && + targetDirectReplies == other.targetDirectReplies && + uniqueDirectReplies == other.uniqueDirectReplies && + unrelatedCount == other.unrelatedCount && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + complete, + coveragePercentage, + cursorFailures, + duplicateCount, + emptyFalseProgressPages, + malformedCount, + missingResponseModulesOrFields, + nestedReplyCount, + pagesAttempted, + recommendedFallback, + repeatedCursorCount, + reportedReplyCount, + responseTruncated, + richness, + strategiesAttempted, + targetDirectReplies, + uniqueDirectReplies, + unrelatedCount, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "Diagnostic{complete=$complete, coveragePercentage=$coveragePercentage, cursorFailures=$cursorFailures, duplicateCount=$duplicateCount, emptyFalseProgressPages=$emptyFalseProgressPages, malformedCount=$malformedCount, missingResponseModulesOrFields=$missingResponseModulesOrFields, nestedReplyCount=$nestedReplyCount, pagesAttempted=$pagesAttempted, recommendedFallback=$recommendedFallback, repeatedCursorCount=$repeatedCursorCount, reportedReplyCount=$reportedReplyCount, responseTruncated=$responseTruncated, richness=$richness, strategiesAttempted=$strategiesAttempted, targetDirectReplies=$targetDirectReplies, uniqueDirectReplies=$uniqueDirectReplies, unrelatedCount=$unrelatedCount, additionalProperties=$additionalProperties}" + } + + override fun equals(other: Any?): Boolean { + if (this === other) { + return true + } + + return other is TweetGetRepliesResponse && + hasNextPage == other.hasNextPage && + nextCursor == other.nextCursor && + tweets == other.tweets && + diagnostic == other.diagnostic && + nestedReplies == other.nestedReplies && + additionalProperties == other.additionalProperties + } + + private val hashCode: Int by lazy { + Objects.hash( + hasNextPage, + nextCursor, + tweets, + diagnostic, + nestedReplies, + additionalProperties, + ) + } + + override fun hashCode(): Int = hashCode + + override fun toString() = + "TweetGetRepliesResponse{hasNextPage=$hasNextPage, nextCursor=$nextCursor, tweets=$tweets, diagnostic=$diagnostic, nestedReplies=$nestedReplies, additionalProperties=$additionalProperties}" +} diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetThreadParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetThreadParams.kt index 709a9b2..58cdba8 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetThreadParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetThreadParams.kt @@ -29,10 +29,8 @@ private constructor( fun cursor(): Optional = Optional.ofNullable(cursor) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -82,10 +80,8 @@ private constructor( fun cursor(cursor: Optional) = cursor(cursor.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveLikesParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveLikesParams.kt index e6a7049..17a6de1 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveLikesParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveLikesParams.kt @@ -104,10 +104,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -361,10 +359,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMediaParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMediaParams.kt index 11f225b..09da7c6 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMediaParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMediaParams.kt @@ -104,10 +104,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -361,10 +359,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMentionsParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMentionsParams.kt index 83bcf8b..8b86d07 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMentionsParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveMentionsParams.kt @@ -106,10 +106,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -375,10 +373,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveRepliesParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveRepliesParams.kt index 3d049cd..36be519 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveRepliesParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveRepliesParams.kt @@ -108,10 +108,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -388,10 +386,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveTweetsParams.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveTweetsParams.kt index 3105fee..5b2578a 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveTweetsParams.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveTweetsParams.kt @@ -112,10 +112,8 @@ private constructor( fun minRetweets(): Optional = Optional.ofNullable(minRetweets) /** - * Maximum items requested from this page (1-100, default 20). The response can contain fewer - * items because the source returned fewer, filters removed items, or remaining credits cover - * fewer results. Keep requesting next_cursor while has_next_page is true, even when a page is - * empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(): Optional = Optional.ofNullable(pageSize) @@ -408,10 +406,8 @@ private constructor( fun minRetweets(minRetweets: Optional) = minRetweets(minRetweets.getOrNull()) /** - * Maximum items requested from this page (1-100, default 20). The response can contain - * fewer items because the source returned fewer, filters removed items, or remaining - * credits cover fewer results. Keep requesting next_cursor while has_next_page is true, - * even when a page is empty. The deprecated limit and count aliases remain accepted. + * Maximum page items (1-100, default 20). Source, filters, or credits can reduce results. + * Continue while has_next_page is true. Deprecated limit and count aliases remain accepted. */ fun pageSize(pageSize: Long?) = apply { this.pageSize = pageSize } diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsync.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsync.kt index 651d0cc..aff0000 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsync.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsync.kt @@ -18,6 +18,7 @@ import com.x_twitter_scraper.api.models.x.tweets.TweetDeleteResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetFavoritersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetQuotesParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesParams +import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetRetweetersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetThreadParams import com.x_twitter_scraper.api.models.x.tweets.TweetListParams @@ -198,12 +199,12 @@ interface TweetServiceAsync { getQuotes(id, TweetGetQuotesParams.none(), requestOptions) /** - * Returns visible replies. For an unfiltered first page, Xquik compares a terminal page with - * the post's reported reply count. If the page is visibly incomplete, the endpoint returns 424 - * `replies_incomplete` instead of presenting partial coverage as complete. Use tweet search - * with a `conversation_id:{id}` query as the broader fallback. + * Returns direct replies. Complete mode merges available timeline views, supported rankings, + * every forward cursor module, labeled hidden-content branches, exact-parent time partitions + * scaled to the reported reply count, and search. It separates nested replies and returns 424 + * below 80% coverage. */ - fun getReplies(id: String): CompletableFuture = + fun getReplies(id: String): CompletableFuture = getReplies(id, TweetGetRepliesParams.none()) /** @see getReplies */ @@ -211,27 +212,30 @@ interface TweetServiceAsync { id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture = + ): CompletableFuture = getReplies(params.toBuilder().id(id).build(), requestOptions) /** @see getReplies */ fun getReplies( id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), - ): CompletableFuture = getReplies(id, params, RequestOptions.none()) + ): CompletableFuture = getReplies(id, params, RequestOptions.none()) /** @see getReplies */ fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture + ): CompletableFuture /** @see getReplies */ - fun getReplies(params: TweetGetRepliesParams): CompletableFuture = + fun getReplies(params: TweetGetRepliesParams): CompletableFuture = getReplies(params, RequestOptions.none()) /** @see getReplies */ - fun getReplies(id: String, requestOptions: RequestOptions): CompletableFuture = + fun getReplies( + id: String, + requestOptions: RequestOptions, + ): CompletableFuture = getReplies(id, TweetGetRepliesParams.none(), requestOptions) /** List users who retweeted a tweet */ @@ -514,7 +518,7 @@ interface TweetServiceAsync { * Returns a raw HTTP response for `get /x/tweets/{id}/replies`, but is otherwise the same * as [TweetServiceAsync.getReplies]. */ - fun getReplies(id: String): CompletableFuture> = + fun getReplies(id: String): CompletableFuture> = getReplies(id, TweetGetRepliesParams.none()) /** @see getReplies */ @@ -522,33 +526,33 @@ interface TweetServiceAsync { id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> = + ): CompletableFuture> = getReplies(params.toBuilder().id(id).build(), requestOptions) /** @see getReplies */ fun getReplies( id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), - ): CompletableFuture> = + ): CompletableFuture> = getReplies(id, params, RequestOptions.none()) /** @see getReplies */ fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions = RequestOptions.none(), - ): CompletableFuture> + ): CompletableFuture> /** @see getReplies */ fun getReplies( params: TweetGetRepliesParams - ): CompletableFuture> = + ): CompletableFuture> = getReplies(params, RequestOptions.none()) /** @see getReplies */ fun getReplies( id: String, requestOptions: RequestOptions, - ): CompletableFuture> = + ): CompletableFuture> = getReplies(id, TweetGetRepliesParams.none(), requestOptions) /** diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncImpl.kt index c99ddf8..f28b137 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncImpl.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncImpl.kt @@ -29,6 +29,7 @@ import com.x_twitter_scraper.api.models.x.tweets.TweetDeleteResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetFavoritersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetQuotesParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesParams +import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetRetweetersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetThreadParams import com.x_twitter_scraper.api.models.x.tweets.TweetListParams @@ -110,7 +111,7 @@ class TweetServiceAsyncImpl internal constructor(private val clientOptions: Clie override fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions, - ): CompletableFuture = + ): CompletableFuture = // get /x/tweets/{id}/replies withRawResponse().getReplies(params, requestOptions).thenApply { it.parse() } @@ -356,13 +357,13 @@ class TweetServiceAsyncImpl internal constructor(private val clientOptions: Clie } } - private val getRepliesHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val getRepliesHandler: Handler = + jsonHandler(clientOptions.jsonMapper) override fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions, - ): CompletableFuture> { + ): CompletableFuture> { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("id", params.id().getOrNull()) diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetService.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetService.kt index ae8c638..50a7dbc 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetService.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetService.kt @@ -19,6 +19,7 @@ import com.x_twitter_scraper.api.models.x.tweets.TweetDeleteResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetFavoritersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetQuotesParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesParams +import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetRetweetersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetThreadParams import com.x_twitter_scraper.api.models.x.tweets.TweetListParams @@ -185,38 +186,39 @@ interface TweetService { getQuotes(id, TweetGetQuotesParams.none(), requestOptions) /** - * Returns visible replies. For an unfiltered first page, Xquik compares a terminal page with - * the post's reported reply count. If the page is visibly incomplete, the endpoint returns 424 - * `replies_incomplete` instead of presenting partial coverage as complete. Use tweet search - * with a `conversation_id:{id}` query as the broader fallback. + * Returns direct replies. Complete mode merges available timeline views, supported rankings, + * every forward cursor module, labeled hidden-content branches, exact-parent time partitions + * scaled to the reported reply count, and search. It separates nested replies and returns 424 + * below 80% coverage. */ - fun getReplies(id: String): PaginatedTweets = getReplies(id, TweetGetRepliesParams.none()) + fun getReplies(id: String): TweetGetRepliesResponse = + getReplies(id, TweetGetRepliesParams.none()) /** @see getReplies */ fun getReplies( id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): PaginatedTweets = getReplies(params.toBuilder().id(id).build(), requestOptions) + ): TweetGetRepliesResponse = getReplies(params.toBuilder().id(id).build(), requestOptions) /** @see getReplies */ fun getReplies( id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), - ): PaginatedTweets = getReplies(id, params, RequestOptions.none()) + ): TweetGetRepliesResponse = getReplies(id, params, RequestOptions.none()) /** @see getReplies */ fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions = RequestOptions.none(), - ): PaginatedTweets + ): TweetGetRepliesResponse /** @see getReplies */ - fun getReplies(params: TweetGetRepliesParams): PaginatedTweets = + fun getReplies(params: TweetGetRepliesParams): TweetGetRepliesResponse = getReplies(params, RequestOptions.none()) /** @see getReplies */ - fun getReplies(id: String, requestOptions: RequestOptions): PaginatedTweets = + fun getReplies(id: String, requestOptions: RequestOptions): TweetGetRepliesResponse = getReplies(id, TweetGetRepliesParams.none(), requestOptions) /** List users who retweeted a tweet */ @@ -501,7 +503,7 @@ interface TweetService { * as [TweetService.getReplies]. */ @MustBeClosed - fun getReplies(id: String): HttpResponseFor = + fun getReplies(id: String): HttpResponseFor = getReplies(id, TweetGetRepliesParams.none()) /** @see getReplies */ @@ -510,7 +512,7 @@ interface TweetService { id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor = + ): HttpResponseFor = getReplies(params.toBuilder().id(id).build(), requestOptions) /** @see getReplies */ @@ -518,18 +520,18 @@ interface TweetService { fun getReplies( id: String, params: TweetGetRepliesParams = TweetGetRepliesParams.none(), - ): HttpResponseFor = getReplies(id, params, RequestOptions.none()) + ): HttpResponseFor = getReplies(id, params, RequestOptions.none()) /** @see getReplies */ @MustBeClosed fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions = RequestOptions.none(), - ): HttpResponseFor + ): HttpResponseFor /** @see getReplies */ @MustBeClosed - fun getReplies(params: TweetGetRepliesParams): HttpResponseFor = + fun getReplies(params: TweetGetRepliesParams): HttpResponseFor = getReplies(params, RequestOptions.none()) /** @see getReplies */ @@ -537,7 +539,7 @@ interface TweetService { fun getReplies( id: String, requestOptions: RequestOptions, - ): HttpResponseFor = + ): HttpResponseFor = getReplies(id, TweetGetRepliesParams.none(), requestOptions) /** diff --git a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceImpl.kt b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceImpl.kt index 21fa25a..05394bb 100644 --- a/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceImpl.kt +++ b/x-twitter-scraper-java-core/src/main/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceImpl.kt @@ -29,6 +29,7 @@ import com.x_twitter_scraper.api.models.x.tweets.TweetDeleteResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetFavoritersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetQuotesParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesParams +import com.x_twitter_scraper.api.models.x.tweets.TweetGetRepliesResponse import com.x_twitter_scraper.api.models.x.tweets.TweetGetRetweetersParams import com.x_twitter_scraper.api.models.x.tweets.TweetGetThreadParams import com.x_twitter_scraper.api.models.x.tweets.TweetListParams @@ -106,7 +107,7 @@ class TweetServiceImpl internal constructor(private val clientOptions: ClientOpt override fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions, - ): PaginatedTweets = + ): TweetGetRepliesResponse = // get /x/tweets/{id}/replies withRawResponse().getReplies(params, requestOptions).parse() @@ -334,13 +335,13 @@ class TweetServiceImpl internal constructor(private val clientOptions: ClientOpt } } - private val getRepliesHandler: Handler = - jsonHandler(clientOptions.jsonMapper) + private val getRepliesHandler: Handler = + jsonHandler(clientOptions.jsonMapper) override fun getReplies( params: TweetGetRepliesParams, requestOptions: RequestOptions, - ): HttpResponseFor { + ): HttpResponseFor { // We check here instead of in the params builder because this can be specified // positionally or in the params class. checkRequired("id", params.id().getOrNull()) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/ContentDisclosureTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/ContentDisclosureTest.kt index aa2d268..cf2eeb4 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/ContentDisclosureTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/ContentDisclosureTest.kt @@ -20,7 +20,6 @@ internal class ContentDisclosureTest { .advertising(ContentDisclosure.Advertising.builder().isPaidPromotion(true).build()) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -32,7 +31,6 @@ internal class ContentDisclosureTest { assertThat(contentDisclosure.aiGenerated()) .contains( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -47,7 +45,6 @@ internal class ContentDisclosureTest { .advertising(ContentDisclosure.Advertising.builder().isPaidPromotion(true).build()) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweetTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweetTest.kt index c785855..527c235 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweetTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/EmbeddedTweetTest.kt @@ -27,27 +27,63 @@ internal class EmbeddedTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -57,19 +93,46 @@ internal class EmbeddedTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -77,7 +140,6 @@ internal class EmbeddedTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -87,6 +149,12 @@ internal class EmbeddedTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -99,12 +167,46 @@ internal class EmbeddedTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -112,11 +214,58 @@ internal class EmbeddedTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() assertThat(embeddedTweet.id()).isEqualTo("id") @@ -127,28 +276,65 @@ internal class EmbeddedTweetTest { assertThat(embeddedTweet.retweetCount()).isEqualTo(0L) assertThat(embeddedTweet.text()).isEqualTo("text") assertThat(embeddedTweet.viewCount()).isEqualTo(0L) + assertThat(embeddedTweet.article()) + .contains( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) assertThat(embeddedTweet.author()) .contains( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -158,19 +344,48 @@ internal class EmbeddedTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + assertThat(embeddedTweet.card()) + .contains( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + assertThat(embeddedTweet.communityNote()) + .contains( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) assertThat(embeddedTweet.contentDisclosure()) .contains( ContentDisclosure.builder() @@ -179,7 +394,6 @@ internal class EmbeddedTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -189,6 +403,13 @@ internal class EmbeddedTweetTest { assertThat(embeddedTweet.conversationId()).contains("conversationId") assertThat(embeddedTweet.createdAt()).contains("createdAt") assertThat(embeddedTweet.displayTextRange().getOrNull()).containsExactly(0L) + assertThat(embeddedTweet.edit()) + .contains( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) assertThat(embeddedTweet.entities()) .contains( EmbeddedTweet.Entities.builder() @@ -202,6 +423,7 @@ internal class EmbeddedTweetTest { assertThat(embeddedTweet.isNoteTweet()).contains(true) assertThat(embeddedTweet.isQuoteStatus()).contains(true) assertThat(embeddedTweet.isReply()).contains(true) + assertThat(embeddedTweet.isTranslatable()).contains(true) assertThat(embeddedTweet.lang()).contains("lang") assertThat(embeddedTweet.media().getOrNull()) .containsExactly( @@ -209,6 +431,37 @@ internal class EmbeddedTweetTest { .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -216,11 +469,61 @@ internal class EmbeddedTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + assertThat(embeddedTweet.noteTweet()) + .contains( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + assertThat(embeddedTweet.place()) + .contains( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + assertThat(embeddedTweet.possiblySensitive()).contains(true) + assertThat(embeddedTweet.previousCounts()) + .contains( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) assertThat(embeddedTweet.source()).contains("source") assertThat(embeddedTweet.type()).contains("type") assertThat(embeddedTweet.url()).contains("url") + assertThat(embeddedTweet.viewState()).contains("viewState") } @Test @@ -236,27 +539,63 @@ internal class EmbeddedTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -266,19 +605,46 @@ internal class EmbeddedTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -286,7 +652,6 @@ internal class EmbeddedTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -296,6 +661,12 @@ internal class EmbeddedTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -308,12 +679,46 @@ internal class EmbeddedTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -321,11 +726,58 @@ internal class EmbeddedTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() val roundtrippedEmbeddedTweet = diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/GeneratedModelContractTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/GeneratedModelContractTest.kt index 3af9d07..82734bb 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/GeneratedModelContractTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/GeneratedModelContractTest.kt @@ -107,7 +107,10 @@ internal class GeneratedModelContractTest { val serializedModel = MAPPER.writeValueAsString(populatedModel) val roundTripModel = MAPPER.readValue(serializedModel, modelClass) val populatedCopy = copyOf(populatedModel) - val rawGetters = rawFieldGetters(modelClass) + val rawGetters = + rawFieldGetters(modelClass).filterNot { + referencesAncestor(it.genericReturnType, setOf(modelClass)) + } verifyValidation(populatedModel, expectedValid = true) verifyValidation(roundTripModel, expectedValid = true) @@ -348,7 +351,12 @@ internal class GeneratedModelContractTest { validModelValue(nestedModel, populatedAncestors) } }, - ::preservesDefaultJsonLiteral, + { method -> + preservesDefaultJsonLiteral(method) || + method.genericParameterTypes.any { + referencesAncestor(it, populatedAncestors) + } + }, ) check(unsupportedMethods.isEmpty()) { @@ -363,6 +371,19 @@ internal class GeneratedModelContractTest { JsonValue::class.java.isAssignableFrom(it) } == true + private fun referencesAncestor(type: Type, ancestors: Set>): Boolean = + when (type) { + is Class<*> -> type in ancestors + is GenericArrayType -> referencesAncestor(type.genericComponentType, ancestors) + is ParameterizedType -> + referencesAncestor(type.rawType, ancestors) || + type.actualTypeArguments.any { referencesAncestor(it, ancestors) } + is TypeVariable<*> -> type.bounds.any { referencesAncestor(it, ancestors) } + is WildcardType -> + (type.lowerBounds + type.upperBounds).any { referencesAncestor(it, ancestors) } + else -> false + } + private fun builderMethodOrder(method: Method): Int = when { method.name == "body" -> 0 diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedTweetsTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedTweetsTest.kt index 8c68991..335b4eb 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedTweetsTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedTweetsTest.kt @@ -30,27 +30,63 @@ internal class PaginatedTweetsTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -62,19 +98,46 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -84,7 +147,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -95,6 +157,12 @@ internal class PaginatedTweetsTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( SearchTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -107,12 +175,50 @@ internal class PaginatedTweetsTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -120,6 +226,52 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -132,29 +284,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -172,21 +360,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -196,7 +411,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -206,6 +420,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -218,12 +438,64 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -231,11 +503,58 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -248,29 +567,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -288,21 +643,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -312,7 +694,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -322,6 +703,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -334,12 +721,64 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -347,16 +786,64 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) .build() @@ -374,27 +861,63 @@ internal class PaginatedTweetsTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -404,19 +927,46 @@ internal class PaginatedTweetsTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -426,7 +976,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -437,6 +986,12 @@ internal class PaginatedTweetsTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( SearchTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -449,12 +1004,48 @@ internal class PaginatedTweetsTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -462,6 +1053,52 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -474,29 +1111,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -514,21 +1187,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -538,7 +1238,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -548,6 +1247,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -560,12 +1265,60 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -573,11 +1326,58 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -590,29 +1390,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -630,21 +1466,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -654,7 +1517,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -664,6 +1526,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -676,12 +1544,60 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -689,16 +1605,64 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) } @@ -720,27 +1684,63 @@ internal class PaginatedTweetsTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -752,19 +1752,46 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -774,7 +1801,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -785,6 +1811,12 @@ internal class PaginatedTweetsTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( SearchTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -797,12 +1829,50 @@ internal class PaginatedTweetsTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -810,6 +1880,52 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -822,29 +1938,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -862,21 +2014,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -886,7 +2065,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -896,6 +2074,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -908,12 +2092,64 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -921,11 +2157,58 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -938,29 +2221,65 @@ internal class PaginatedTweetsTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -978,21 +2297,48 @@ internal class PaginatedTweetsTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -1002,7 +2348,6 @@ internal class PaginatedTweetsTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -1012,6 +2357,12 @@ internal class PaginatedTweetsTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -1024,12 +2375,64 @@ internal class PaginatedTweetsTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -1037,16 +2440,64 @@ internal class PaginatedTweetsTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedUsersTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedUsersTest.kt index 0c9e58f..ec2d85d 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedUsersTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/PaginatedUsersTest.kt @@ -25,22 +25,50 @@ internal class PaginatedUsersTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -50,16 +78,20 @@ internal class PaginatedUsersTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -73,22 +105,50 @@ internal class PaginatedUsersTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -98,16 +158,20 @@ internal class PaginatedUsersTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -125,22 +189,50 @@ internal class PaginatedUsersTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -150,16 +242,20 @@ internal class PaginatedUsersTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/SearchTweetTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/SearchTweetTest.kt index 65ae171..8426f22 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/SearchTweetTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/SearchTweetTest.kt @@ -27,27 +27,63 @@ internal class SearchTweetTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -57,19 +93,46 @@ internal class SearchTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -77,7 +140,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -88,6 +150,12 @@ internal class SearchTweetTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( SearchTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -100,12 +168,46 @@ internal class SearchTweetTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -113,6 +215,52 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -125,27 +273,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -157,19 +341,46 @@ internal class SearchTweetTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -179,7 +390,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -189,6 +399,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -201,12 +417,50 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -214,11 +468,58 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -231,27 +532,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -263,19 +600,46 @@ internal class SearchTweetTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -285,7 +649,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -295,6 +658,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -307,12 +676,50 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -320,16 +727,64 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() assertThat(searchTweet.id()).isEqualTo("1234567890") @@ -340,28 +795,65 @@ internal class SearchTweetTest { assertThat(searchTweet.retweetCount()).isEqualTo(5L) assertThat(searchTweet.text()).isEqualTo("Just launched our new feature!") assertThat(searchTweet.viewCount()).isEqualTo(1500L) + assertThat(searchTweet.article()) + .contains( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) assertThat(searchTweet.author()) .contains( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -371,19 +863,48 @@ internal class SearchTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + assertThat(searchTweet.card()) + .contains( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + assertThat(searchTweet.communityNote()) + .contains( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) assertThat(searchTweet.contentDisclosure()) .contains( ContentDisclosure.builder() @@ -392,7 +913,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -402,6 +922,13 @@ internal class SearchTweetTest { assertThat(searchTweet.conversationId()).contains("1234567890") assertThat(searchTweet.createdAt()).contains("2025-01-15T12:00:00Z") assertThat(searchTweet.displayTextRange().getOrNull()).containsExactly(0L, 31L) + assertThat(searchTweet.edit()) + .contains( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) assertThat(searchTweet.entities()) .contains( SearchTweet.Entities.builder() @@ -415,6 +942,7 @@ internal class SearchTweetTest { assertThat(searchTweet.isNoteTweet()).contains(false) assertThat(searchTweet.isQuoteStatus()).contains(false) assertThat(searchTweet.isReply()).contains(false) + assertThat(searchTweet.isTranslatable()).contains(true) assertThat(searchTweet.lang()).contains("en") assertThat(searchTweet.media().getOrNull()) .containsExactly( @@ -422,6 +950,37 @@ internal class SearchTweetTest { .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -429,6 +988,55 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + assertThat(searchTweet.noteTweet()) + .contains( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + assertThat(searchTweet.place()) + .contains( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + assertThat(searchTweet.possiblySensitive()).contains(true) + assertThat(searchTweet.previousCounts()) + .contains( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) assertThat(searchTweet.quotedTweet()) @@ -442,27 +1050,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -472,19 +1116,46 @@ internal class SearchTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -494,7 +1165,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -504,6 +1174,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -516,12 +1192,48 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -529,11 +1241,58 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) assertThat(searchTweet.retweetedTweet()) @@ -547,27 +1306,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -577,19 +1372,46 @@ internal class SearchTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -599,7 +1421,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -609,6 +1430,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -621,12 +1448,48 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -634,16 +1497,64 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) assertThat(searchTweet.source()).contains("Twitter Web App") assertThat(searchTweet.type()).contains("tweet") assertThat(searchTweet.url()).contains("https://x.com/example_user/status/1234567890") + assertThat(searchTweet.viewState()).contains("viewState") } @Test @@ -659,27 +1570,63 @@ internal class SearchTweetTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -689,19 +1636,46 @@ internal class SearchTweetTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -709,7 +1683,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -720,6 +1693,12 @@ internal class SearchTweetTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( SearchTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -732,12 +1711,46 @@ internal class SearchTweetTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -745,6 +1758,52 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -757,27 +1816,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -789,19 +1884,46 @@ internal class SearchTweetTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -811,7 +1933,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -821,6 +1942,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -833,12 +1960,50 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -846,11 +2011,58 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -863,27 +2075,63 @@ internal class SearchTweetTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -895,19 +2143,46 @@ internal class SearchTweetTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -917,7 +2192,6 @@ internal class SearchTweetTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -927,6 +2201,12 @@ internal class SearchTweetTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -939,12 +2219,50 @@ internal class SearchTweetTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -952,16 +2270,64 @@ internal class SearchTweetTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() val roundtrippedSearchTweet = diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/TweetMediaTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/TweetMediaTest.kt index edc98f0..728bd8d 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/TweetMediaTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/TweetMediaTest.kt @@ -7,6 +7,7 @@ package com.x_twitter_scraper.api.models import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.jsonMapper import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat @@ -21,6 +22,35 @@ internal class TweetMediaTest { .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0))), + ) + .build() + ) + .addFocusRect(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -28,11 +58,44 @@ internal class TweetMediaTest { .bitrate(0L) .build() ) + .width(0L) .build() assertThat(tweetMedia.mediaUrl()).isEqualTo("mediaUrl") assertThat(tweetMedia.type()).isEqualTo(TweetMedia.Type.PHOTO) assertThat(tweetMedia.url()).isEqualTo("url") + assertThat(tweetMedia.id()).contains("id") + assertThat(tweetMedia.allowDownload()).contains(true) + assertThat(tweetMedia.altText()).contains("altText") + assertThat(tweetMedia.aspectRatio().getOrNull()).containsExactly(0L) + assertThat(tweetMedia.availabilityStatus()).contains("availabilityStatus") + assertThat(tweetMedia.displayUrl()).contains("displayUrl") + assertThat(tweetMedia.durationMillis()).contains(0L) + assertThat(tweetMedia.expandedUrl()).contains("expandedUrl") + assertThat(tweetMedia.faceRects()) + .contains( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0))), + ) + .build() + ) + assertThat(tweetMedia.focusRects().getOrNull()) + .containsExactly(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + assertThat(tweetMedia.height()).contains(0L) + assertThat(tweetMedia.indices().getOrNull()).containsExactly(0L) + assertThat(tweetMedia.mediaKey()).contains("mediaKey") + assertThat(tweetMedia.monetizable()).contains(true) + assertThat(tweetMedia.sizes()) + .contains( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) assertThat(tweetMedia.videoVariants().getOrNull()) .containsExactly( TweetMedia.VideoVariant.builder() @@ -41,6 +104,7 @@ internal class TweetMediaTest { .bitrate(0L) .build() ) + assertThat(tweetMedia.width()).contains(0L) } @Test @@ -51,6 +115,35 @@ internal class TweetMediaTest { .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0))), + ) + .build() + ) + .addFocusRect(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -58,6 +151,7 @@ internal class TweetMediaTest { .bitrate(0L) .build() ) + .width(0L) .build() val roundtrippedTweetMedia = diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/UserProfileTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/UserProfileTest.kt index 6481caf..cc47fdf 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/UserProfileTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/UserProfileTest.kt @@ -22,22 +22,50 @@ internal class UserProfileTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -47,39 +75,74 @@ internal class UserProfileTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() assertThat(userProfile.id()).isEqualTo("9876543210") assertThat(userProfile.name()).isEqualTo("Elon Musk") assertThat(userProfile.username()).isEqualTo("elonmusk") + assertThat(userProfile.affiliatesHighlightedLabel()) + .contains( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) assertThat(userProfile.automatedBy()).contains("example_user") - assertThat(userProfile.canDm()).contains(false) + assertThat(userProfile.businessAccountAffiliatesCount()).contains(0L) assertThat(userProfile.communityRole()).contains("Member") assertThat(userProfile.coverPicture()) .contains("https://pbs.twimg.com/profile_banners/example.jpg") assertThat(userProfile.createdAt()).contains("2009-06-02T20:12:29Z") + assertThat(userProfile.creatorSubscriptionsCount()).contains(0L) assertThat(userProfile.description()).contains("CEO of Tesla, SpaceX, and X") assertThat(userProfile.favouritesCount()).contains(18000L) assertThat(userProfile.followers()).contains(150000000L) assertThat(userProfile.following()).contains(500L) assertThat(userProfile.hasCustomTimelines()).contains(true) + assertThat(userProfile.hasGraduatedAccess()).contains(true) + assertThat(userProfile.hasHiddenSubscriptionsOnProfile()).contains(true) + assertThat(userProfile.highlightsInfo()) + .contains( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + assertThat(userProfile.identityVerification()) + .contains( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) assertThat(userProfile.isAutomated()).contains(false) assertThat(userProfile.isBlueVerified()).contains(true) + assertThat(userProfile.isProfileTranslatable()).contains(true) assertThat(userProfile.isTranslator()).contains(false) assertThat(userProfile.isVerified()).contains(true) assertThat(userProfile.location()).contains("Austin, TX") assertThat(userProfile.mediaCount()).contains(1200L) + assertThat(userProfile.parodyCommentaryFanLabel()).contains("parodyCommentaryFanLabel") assertThat(userProfile.pinnedTweetIds().getOrNull()).containsExactly("1234567890") assertThat(userProfile.possiblySensitive()).contains(false) assertThat(userProfile.profileBio()) @@ -91,17 +154,21 @@ internal class UserProfileTest { ) assertThat(userProfile.profileBannerUrl()) .contains("https://pbs.twimg.com/profile_banners/example.jpg") + assertThat(userProfile.profileDescriptionLanguage()).contains("profileDescriptionLanguage") + assertThat(userProfile.profileImageShape()).contains("profileImageShape") + assertThat(userProfile.profileInterstitialType()).contains("profileInterstitialType") assertThat(userProfile.profilePicture()) .contains("https://pbs.twimg.com/profile_images/example.jpg") + assertThat(userProfile.profileSortEnabled()).contains(true) + assertThat(userProfile.profileTranslatorType()).contains("profileTranslatorType") assertThat(userProfile.protected_()).contains(false) assertThat(userProfile.statusesCount()).contains(35000L) + assertThat(userProfile.superFollowEligible()).contains(true) assertThat(userProfile.unavailable()).contains(false) assertThat(userProfile.unavailableReason()).contains("suspended") assertThat(userProfile.url()).contains("https://xquik.com") assertThat(userProfile.verified()).contains(true) assertThat(userProfile.verifiedType()).contains("Business") - assertThat(userProfile.viewerFollowedBy()).contains(false) - assertThat(userProfile.viewerFollowing()).contains(true) assertThat(userProfile.withheldInCountries().getOrNull()).containsExactly("DE") } @@ -113,22 +180,50 @@ internal class UserProfileTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -138,16 +233,20 @@ internal class UserProfileTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponseTest.kt index 0bf81b9..449b80c 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketListResponseTest.kt @@ -9,7 +9,6 @@ package com.x_twitter_scraper.api.models.support.tickets import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.x_twitter_scraper.api.core.jsonMapper import java.time.OffsetDateTime -import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -24,20 +23,20 @@ internal class TicketListResponseTest { .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .messageCount(2L) .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("open") + .status(TicketListResponse.Ticket.Status.OPEN) .subject("Cannot connect X account") .updatedAt(OffsetDateTime.parse("2025-01-16T09:30:00Z")) .build() ) .build() - assertThat(ticketListResponse.tickets().getOrNull()) + assertThat(ticketListResponse.tickets()) .containsExactly( TicketListResponse.Ticket.builder() .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .messageCount(2L) .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("open") + .status(TicketListResponse.Ticket.Status.OPEN) .subject("Cannot connect X account") .updatedAt(OffsetDateTime.parse("2025-01-16T09:30:00Z")) .build() @@ -54,7 +53,7 @@ internal class TicketListResponseTest { .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .messageCount(2L) .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("open") + .status(TicketListResponse.Ticket.Status.OPEN) .subject("Cannot connect X account") .updatedAt(OffsetDateTime.parse("2025-01-16T09:30:00Z")) .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponseTest.kt index 8121b3e..5217d4d 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketRetrieveResponseTest.kt @@ -9,7 +9,6 @@ package com.x_twitter_scraper.api.models.support.tickets import com.fasterxml.jackson.module.kotlin.jacksonTypeRef import com.x_twitter_scraper.api.core.jsonMapper import java.time.OffsetDateTime -import kotlin.jvm.optionals.getOrNull import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test @@ -37,18 +36,18 @@ internal class TicketRetrieveResponseTest { ) .body("I am unable to connect my X account.") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - .sender("user") + .sender(TicketRetrieveResponse.Message.Sender.USER) .build() ) .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("open") + .status(TicketRetrieveResponse.Status.OPEN) .subject("Cannot connect X account") .updatedAt(OffsetDateTime.parse("2025-01-16T09:30:00Z")) .build() assertThat(ticketRetrieveResponse.createdAt()) - .contains(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - assertThat(ticketRetrieveResponse.messages().getOrNull()) + .isEqualTo(OffsetDateTime.parse("2025-01-15T12:00:00Z")) + assertThat(ticketRetrieveResponse.messages()) .containsExactly( TicketRetrieveResponse.Message.builder() .addAttachment( @@ -66,14 +65,14 @@ internal class TicketRetrieveResponseTest { ) .body("I am unable to connect my X account.") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - .sender("user") + .sender(TicketRetrieveResponse.Message.Sender.USER) .build() ) - assertThat(ticketRetrieveResponse.publicId()).contains("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - assertThat(ticketRetrieveResponse.status()).contains("open") - assertThat(ticketRetrieveResponse.subject()).contains("Cannot connect X account") + assertThat(ticketRetrieveResponse.publicId()).isEqualTo("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") + assertThat(ticketRetrieveResponse.status()).isEqualTo(TicketRetrieveResponse.Status.OPEN) + assertThat(ticketRetrieveResponse.subject()).isEqualTo("Cannot connect X account") assertThat(ticketRetrieveResponse.updatedAt()) - .contains(OffsetDateTime.parse("2025-01-16T09:30:00Z")) + .isEqualTo(OffsetDateTime.parse("2025-01-16T09:30:00Z")) } @Test @@ -99,11 +98,11 @@ internal class TicketRetrieveResponseTest { ) .body("I am unable to connect my X account.") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) - .sender("user") + .sender(TicketRetrieveResponse.Message.Sender.USER) .build() ) .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("open") + .status(TicketRetrieveResponse.Status.OPEN) .subject("Cannot connect X account") .updatedAt(OffsetDateTime.parse("2025-01-16T09:30:00Z")) .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponseTest.kt index 3a9cac9..51dc3d6 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/support/tickets/TicketUpdateResponseTest.kt @@ -18,11 +18,11 @@ internal class TicketUpdateResponseTest { val ticketUpdateResponse = TicketUpdateResponse.builder() .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("resolved") + .status(TicketUpdateResponse.Status.RESOLVED) .build() - assertThat(ticketUpdateResponse.publicId()).contains("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - assertThat(ticketUpdateResponse.status()).contains("resolved") + assertThat(ticketUpdateResponse.publicId()).isEqualTo("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") + assertThat(ticketUpdateResponse.status()).isEqualTo(TicketUpdateResponse.Status.RESOLVED) } @Test @@ -31,7 +31,7 @@ internal class TicketUpdateResponseTest { val ticketUpdateResponse = TicketUpdateResponse.builder() .publicId("tkt_a1b2c3d4e5f6a1b2c3d4e5f6") - .status("resolved") + .status(TicketUpdateResponse.Status.RESOLVED) .build() val roundtrippedTicketUpdateResponse = diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponseTest.kt index a3ed5c7..f8a1ac6 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/trends/TrendListResponseTest.kt @@ -22,8 +22,11 @@ internal class TrendListResponseTest { TrendListResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent("promotedContent") .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://example.com") .build() ) .woeid(1L) @@ -35,8 +38,11 @@ internal class TrendListResponseTest { TrendListResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent("promotedContent") .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://example.com") .build() ) assertThat(trendListResponse.woeid()).isEqualTo(1L) @@ -52,8 +58,11 @@ internal class TrendListResponseTest { TrendListResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent("promotedContent") .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://example.com") .build() ) .woeid(1L) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponseTest.kt index 9c7fa4a..0467b88 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetArticleResponseTest.kt @@ -52,7 +52,6 @@ internal class XGetArticleResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") - .canDm(true) .createdAt("createdAt") .description("description") .favouritesCount(0L) @@ -109,7 +108,6 @@ internal class XGetArticleResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") - .canDm(true) .createdAt("createdAt") .description("description") .favouritesCount(0L) @@ -169,7 +167,6 @@ internal class XGetArticleResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") - .canDm(true) .createdAt("createdAt") .description("description") .favouritesCount(0L) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponseTest.kt index f11cdff..b483db8 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/XGetTrendsResponseTest.kt @@ -22,8 +22,11 @@ internal class XGetTrendsResponseTest { XGetTrendsResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent(null) .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://x.com/search?q=%23AI") .build() ) .woeid(1L) @@ -35,8 +38,11 @@ internal class XGetTrendsResponseTest { XGetTrendsResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent(null) .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://x.com/search?q=%23AI") .build() ) assertThat(xGetTrendsResponse.woeid()).isEqualTo(1L) @@ -52,8 +58,11 @@ internal class XGetTrendsResponseTest { XGetTrendsResponse.Trend.builder() .name("#AI") .description("Artificial intelligence discussions") + .promotedContent(null) .query("%23AI") .rank(1L) + .tweetVolume(250000L) + .url("https://x.com/search?q=%23AI") .build() ) .woeid(1L) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt index 676228c..ec53a7c 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionattempts/AccountConnectionAttemptRetrieveResponseTest.kt @@ -16,33 +16,28 @@ import org.junit.jupiter.params.provider.EnumSource internal class AccountConnectionAttemptRetrieveResponseTest { @Test - fun ofXAccountConnectionAttemptPending() { - val xAccountConnectionAttemptPending = - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptPending.builder() + fun ofPending() { + val pending = + AccountConnectionAttemptRetrieveResponse.Pending.builder() .id("xatt_0123456789abcdef0123456789abcdef") .pollAfterMs(3000L) .build() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptPending( - xAccountConnectionAttemptPending - ) + AccountConnectionAttemptRetrieveResponse.ofPending(pending) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) - .contains(xAccountConnectionAttemptPending) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.pending()).contains(pending) + assertThat(accountConnectionAttemptRetrieveResponse.success()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.failed()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.requiresEmailCode()).isEmpty } @Test - fun ofXAccountConnectionAttemptPendingRoundtrip() { + fun ofPendingRoundtrip() { val jsonMapper = jsonMapper() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptPending( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptPending.builder() + AccountConnectionAttemptRetrieveResponse.ofPending( + AccountConnectionAttemptRetrieveResponse.Pending.builder() .id("xatt_0123456789abcdef0123456789abcdef") .pollAfterMs(3000L) .build() @@ -59,32 +54,27 @@ internal class AccountConnectionAttemptRetrieveResponseTest { } @Test - fun ofXAccountConnectionAttemptSuccess() { - val xAccountConnectionAttemptSuccess = - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptSuccess.builder() + fun ofSuccess() { + val success = + AccountConnectionAttemptRetrieveResponse.Success.builder() .id("xatt_0123456789abcdef0123456789abcdef") .build() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptSuccess( - xAccountConnectionAttemptSuccess - ) + AccountConnectionAttemptRetrieveResponse.ofSuccess(success) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) - .contains(xAccountConnectionAttemptSuccess) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.pending()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.success()).contains(success) + assertThat(accountConnectionAttemptRetrieveResponse.failed()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.requiresEmailCode()).isEmpty } @Test - fun ofXAccountConnectionAttemptSuccessRoundtrip() { + fun ofSuccessRoundtrip() { val jsonMapper = jsonMapper() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptSuccess( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptSuccess.builder() + AccountConnectionAttemptRetrieveResponse.ofSuccess( + AccountConnectionAttemptRetrieveResponse.Success.builder() .id("xatt_0123456789abcdef0123456789abcdef") .build() ) @@ -100,9 +90,9 @@ internal class AccountConnectionAttemptRetrieveResponseTest { } @Test - fun ofXAccountConnectionAttemptFailed() { - val xAccountConnectionAttemptFailed = - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptFailed.builder() + fun ofFailed() { + val failed = + AccountConnectionAttemptRetrieveResponse.Failed.builder() .id("xatt_0123456789abcdef0123456789abcdef") .error("service_unavailable") .retryable(true) @@ -110,25 +100,20 @@ internal class AccountConnectionAttemptRetrieveResponseTest { .build() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptFailed( - xAccountConnectionAttemptFailed - ) + AccountConnectionAttemptRetrieveResponse.ofFailed(failed) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) - .contains(xAccountConnectionAttemptFailed) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.pending()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.success()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.failed()).contains(failed) + assertThat(accountConnectionAttemptRetrieveResponse.requiresEmailCode()).isEmpty } @Test - fun ofXAccountConnectionAttemptFailedRoundtrip() { + fun ofFailedRoundtrip() { val jsonMapper = jsonMapper() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionAttemptFailed( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionAttemptFailed.builder() + AccountConnectionAttemptRetrieveResponse.ofFailed( + AccountConnectionAttemptRetrieveResponse.Failed.builder() .id("xatt_0123456789abcdef0123456789abcdef") .error("service_unavailable") .retryable(true) @@ -147,55 +132,34 @@ internal class AccountConnectionAttemptRetrieveResponseTest { } @Test - fun ofXAccountConnectionChallenge() { - val xAccountConnectionChallenge = - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.builder() + fun ofRequiresEmailCode() { + val requiresEmailCode = + AccountConnectionAttemptRetrieveResponse.RequiresEmailCode.builder() .id("xch_8vGd8Y9JvH6dV0xA") .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) .message("Enter the email verification code to continue.") - .object_( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Object - .X_ACCOUNT_CONNECTION_CHALLENGE - ) - .status( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Status - .REQUIRES_EMAIL_CODE - ) .username("elonmusk") .build() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionChallenge( - xAccountConnectionChallenge - ) + AccountConnectionAttemptRetrieveResponse.ofRequiresEmailCode(requiresEmailCode) - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptPending()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptSuccess()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionAttemptFailed()) - .isEmpty - assertThat(accountConnectionAttemptRetrieveResponse.xAccountConnectionChallenge()) - .contains(xAccountConnectionChallenge) + assertThat(accountConnectionAttemptRetrieveResponse.pending()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.success()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.failed()).isEmpty + assertThat(accountConnectionAttemptRetrieveResponse.requiresEmailCode()) + .contains(requiresEmailCode) } @Test - fun ofXAccountConnectionChallengeRoundtrip() { + fun ofRequiresEmailCodeRoundtrip() { val jsonMapper = jsonMapper() val accountConnectionAttemptRetrieveResponse = - AccountConnectionAttemptRetrieveResponse.ofXAccountConnectionChallenge( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.builder() + AccountConnectionAttemptRetrieveResponse.ofRequiresEmailCode( + AccountConnectionAttemptRetrieveResponse.RequiresEmailCode.builder() .id("xch_8vGd8Y9JvH6dV0xA") .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) .message("Enter the email verification code to continue.") - .object_( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Object - .X_ACCOUNT_CONNECTION_CHALLENGE - ) - .status( - AccountConnectionAttemptRetrieveResponse.XAccountConnectionChallenge.Status - .REQUIRES_EMAIL_CODE - ) .username("elonmusk") .build() ) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponseTest.kt index 0ec446d..dbb27af 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accountconnectionchallenges/AccountConnectionChallengeSubmitResponseTest.kt @@ -21,7 +21,6 @@ internal class AccountConnectionChallengeSubmitResponseTest { .id("42") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .health(AccountConnectionChallengeSubmitResponse.Health.HEALTHY) - .status("active") .xUserId("9876543210") .xUsername("elonmusk") .build() @@ -31,7 +30,6 @@ internal class AccountConnectionChallengeSubmitResponseTest { .isEqualTo(OffsetDateTime.parse("2025-01-15T12:00:00Z")) assertThat(accountConnectionChallengeSubmitResponse.health()) .isEqualTo(AccountConnectionChallengeSubmitResponse.Health.HEALTHY) - assertThat(accountConnectionChallengeSubmitResponse.status()).isEqualTo("active") assertThat(accountConnectionChallengeSubmitResponse.xUserId()).isEqualTo("9876543210") assertThat(accountConnectionChallengeSubmitResponse.xUsername()).isEqualTo("elonmusk") } @@ -44,7 +42,6 @@ internal class AccountConnectionChallengeSubmitResponseTest { .id("42") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .health(AccountConnectionChallengeSubmitResponse.Health.HEALTHY) - .status("active") .xUserId("9876543210") .xUsername("elonmusk") .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt index 4c0e2b3..6e82604 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountCreateResponseTest.kt @@ -7,21 +7,49 @@ package com.x_twitter_scraper.api.models.x.accounts import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.JsonValue import com.x_twitter_scraper.api.core.jsonMapper +import com.x_twitter_scraper.api.errors.XTwitterScraperInvalidDataException +import java.time.OffsetDateTime import org.assertj.core.api.Assertions.assertThat import org.junit.jupiter.api.Test +import org.junit.jupiter.api.assertThrows +import org.junit.jupiter.params.ParameterizedTest +import org.junit.jupiter.params.provider.EnumSource internal class AccountCreateResponseTest { @Test - fun create() { - val accountCreateResponse = AccountCreateResponse.builder().build() + fun ofSanitizedXAccount() { + val sanitizedXAccount = + AccountCreateResponse.SanitizedXAccount.builder() + .id("42") + .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) + .health(AccountCreateResponse.SanitizedXAccount.Health.HEALTHY) + .xUserId("9876543210") + .xUsername("elonmusk") + .build() + + val accountCreateResponse = AccountCreateResponse.ofSanitizedXAccount(sanitizedXAccount) + + assertThat(accountCreateResponse.sanitizedXAccount()).contains(sanitizedXAccount) + assertThat(accountCreateResponse.xAccountConnectionAttemptPending()).isEmpty + assertThat(accountCreateResponse.xAccountConnectionChallenge()).isEmpty } @Test - fun roundtrip() { + fun ofSanitizedXAccountRoundtrip() { val jsonMapper = jsonMapper() - val accountCreateResponse = AccountCreateResponse.builder().build() + val accountCreateResponse = + AccountCreateResponse.ofSanitizedXAccount( + AccountCreateResponse.SanitizedXAccount.builder() + .id("42") + .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) + .health(AccountCreateResponse.SanitizedXAccount.Health.HEALTHY) + .xUserId("9876543210") + .xUsername("elonmusk") + .build() + ) val roundtrippedAccountCreateResponse = jsonMapper.readValue( @@ -31,4 +59,103 @@ internal class AccountCreateResponseTest { assertThat(roundtrippedAccountCreateResponse).isEqualTo(accountCreateResponse) } + + @Test + fun ofXAccountConnectionAttemptPending() { + val xAccountConnectionAttemptPending = + AccountCreateResponse.XAccountConnectionAttemptPending.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .pollAfterMs(3000L) + .build() + + val accountCreateResponse = + AccountCreateResponse.ofXAccountConnectionAttemptPending( + xAccountConnectionAttemptPending + ) + + assertThat(accountCreateResponse.sanitizedXAccount()).isEmpty + assertThat(accountCreateResponse.xAccountConnectionAttemptPending()) + .contains(xAccountConnectionAttemptPending) + assertThat(accountCreateResponse.xAccountConnectionChallenge()).isEmpty + } + + @Test + fun ofXAccountConnectionAttemptPendingRoundtrip() { + val jsonMapper = jsonMapper() + val accountCreateResponse = + AccountCreateResponse.ofXAccountConnectionAttemptPending( + AccountCreateResponse.XAccountConnectionAttemptPending.builder() + .id("xatt_0123456789abcdef0123456789abcdef") + .pollAfterMs(3000L) + .build() + ) + + val roundtrippedAccountCreateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountCreateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountCreateResponse).isEqualTo(accountCreateResponse) + } + + @Test + fun ofXAccountConnectionChallenge() { + val xAccountConnectionChallenge = + AccountCreateResponse.XAccountConnectionChallenge.builder() + .id("xch_8vGd8Y9JvH6dV0xA") + .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) + .message("Enter the email verification code to continue.") + .username("elonmusk") + .build() + + val accountCreateResponse = + AccountCreateResponse.ofXAccountConnectionChallenge(xAccountConnectionChallenge) + + assertThat(accountCreateResponse.sanitizedXAccount()).isEmpty + assertThat(accountCreateResponse.xAccountConnectionAttemptPending()).isEmpty + assertThat(accountCreateResponse.xAccountConnectionChallenge()) + .contains(xAccountConnectionChallenge) + } + + @Test + fun ofXAccountConnectionChallengeRoundtrip() { + val jsonMapper = jsonMapper() + val accountCreateResponse = + AccountCreateResponse.ofXAccountConnectionChallenge( + AccountCreateResponse.XAccountConnectionChallenge.builder() + .id("xch_8vGd8Y9JvH6dV0xA") + .expiresAt(OffsetDateTime.parse("2026-05-08T12:10:00Z")) + .message("Enter the email verification code to continue.") + .username("elonmusk") + .build() + ) + + val roundtrippedAccountCreateResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(accountCreateResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedAccountCreateResponse).isEqualTo(accountCreateResponse) + } + + enum class IncompatibleJsonShapeTestCase(val value: JsonValue) { + BOOLEAN(JsonValue.from(false)), + STRING(JsonValue.from("invalid")), + INTEGER(JsonValue.from(-1)), + FLOAT(JsonValue.from(3.14)), + ARRAY(JsonValue.from(listOf("invalid", "array"))), + } + + @ParameterizedTest + @EnumSource + fun incompatibleJsonShapeDeserializesToUnknown(testCase: IncompatibleJsonShapeTestCase) { + val accountCreateResponse = + jsonMapper().convertValue(testCase.value, jacksonTypeRef()) + + val e = + assertThrows { accountCreateResponse.validate() } + assertThat(e).hasMessageStartingWith("Unknown ") + } } diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponseTest.kt index 5bceda6..58d4a46 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/accounts/AccountReauthResponseTest.kt @@ -21,7 +21,6 @@ internal class AccountReauthResponseTest { .id("42") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .health(AccountReauthResponse.Health.HEALTHY) - .status("active") .xUserId("9876543210") .xUsername("elonmusk") .build() @@ -30,7 +29,6 @@ internal class AccountReauthResponseTest { assertThat(accountReauthResponse.createdAt()) .isEqualTo(OffsetDateTime.parse("2025-01-15T12:00:00Z")) assertThat(accountReauthResponse.health()).isEqualTo(AccountReauthResponse.Health.HEALTHY) - assertThat(accountReauthResponse.status()).isEqualTo("active") assertThat(accountReauthResponse.xUserId()).isEqualTo("9876543210") assertThat(accountReauthResponse.xUsername()).isEqualTo("elonmusk") } @@ -43,7 +41,6 @@ internal class AccountReauthResponseTest { .id("42") .createdAt(OffsetDateTime.parse("2025-01-15T12:00:00Z")) .health(AccountReauthResponse.Health.HEALTHY) - .status("active") .xUserId("9876543210") .xUsername("elonmusk") .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponseTest.kt index a59b906..cc0ea5a 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/communities/CommunityRetrieveInfoResponseTest.kt @@ -32,7 +32,6 @@ internal class CommunityRetrieveInfoResponseTest { ) .description("description") .invitesPolicy("invites_policy") - .isMember(true) .isNsfw(true) .joinPolicy("join_policy") .memberCount(0L) @@ -44,7 +43,6 @@ internal class CommunityRetrieveInfoResponseTest { .name("name") .build() ) - .role("role") .addRule( CommunityRetrieveInfoResponse.Community.Rule.builder() .id("id") @@ -72,7 +70,6 @@ internal class CommunityRetrieveInfoResponseTest { ) .description("description") .invitesPolicy("invites_policy") - .isMember(true) .isNsfw(true) .joinPolicy("join_policy") .memberCount(0L) @@ -84,7 +81,6 @@ internal class CommunityRetrieveInfoResponseTest { .name("name") .build() ) - .role("role") .addRule( CommunityRetrieveInfoResponse.Community.Rule.builder() .id("id") @@ -116,7 +112,6 @@ internal class CommunityRetrieveInfoResponseTest { ) .description("description") .invitesPolicy("invites_policy") - .isMember(true) .isNsfw(true) .joinPolicy("join_policy") .memberCount(0L) @@ -128,7 +123,6 @@ internal class CommunityRetrieveInfoResponseTest { .name("name") .build() ) - .role("role") .addRule( CommunityRetrieveInfoResponse.Community.Rule.builder() .id("id") diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthorTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthorTest.kt index 345f520..47f9548 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthorTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetAuthorTest.kt @@ -23,22 +23,50 @@ internal class TweetAuthorTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -48,39 +76,74 @@ internal class TweetAuthorTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() assertThat(tweetAuthor.id()).isEqualTo("9876543210") assertThat(tweetAuthor.name()).isEqualTo("Elon Musk") assertThat(tweetAuthor.username()).isEqualTo("elonmusk") + assertThat(tweetAuthor.affiliatesHighlightedLabel()) + .contains( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) assertThat(tweetAuthor.automatedBy()).contains("example_user") - assertThat(tweetAuthor.canDm()).contains(false) + assertThat(tweetAuthor.businessAccountAffiliatesCount()).contains(0L) assertThat(tweetAuthor.communityRole()).contains("Member") assertThat(tweetAuthor.coverPicture()) .contains("https://pbs.twimg.com/profile_banners/example.jpg") assertThat(tweetAuthor.createdAt()).contains("2009-06-02T20:12:29Z") + assertThat(tweetAuthor.creatorSubscriptionsCount()).contains(0L) assertThat(tweetAuthor.description()).contains("CEO of Tesla, SpaceX, and X") assertThat(tweetAuthor.favouritesCount()).contains(18000L) assertThat(tweetAuthor.followers()).contains(150000000L) assertThat(tweetAuthor.following()).contains(500L) assertThat(tweetAuthor.hasCustomTimelines()).contains(true) + assertThat(tweetAuthor.hasGraduatedAccess()).contains(true) + assertThat(tweetAuthor.hasHiddenSubscriptionsOnProfile()).contains(true) + assertThat(tweetAuthor.highlightsInfo()) + .contains( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + assertThat(tweetAuthor.identityVerification()) + .contains( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) assertThat(tweetAuthor.isAutomated()).contains(false) assertThat(tweetAuthor.isBlueVerified()).contains(true) + assertThat(tweetAuthor.isProfileTranslatable()).contains(true) assertThat(tweetAuthor.isTranslator()).contains(false) assertThat(tweetAuthor.isVerified()).contains(true) assertThat(tweetAuthor.location()).contains("Austin, TX") assertThat(tweetAuthor.mediaCount()).contains(1200L) + assertThat(tweetAuthor.parodyCommentaryFanLabel()).contains("parodyCommentaryFanLabel") assertThat(tweetAuthor.pinnedTweetIds().getOrNull()).containsExactly("1234567890") assertThat(tweetAuthor.possiblySensitive()).contains(false) assertThat(tweetAuthor.profileBio()) @@ -92,17 +155,21 @@ internal class TweetAuthorTest { ) assertThat(tweetAuthor.profileBannerUrl()) .contains("https://pbs.twimg.com/profile_banners/example.jpg") + assertThat(tweetAuthor.profileDescriptionLanguage()).contains("profileDescriptionLanguage") + assertThat(tweetAuthor.profileImageShape()).contains("profileImageShape") + assertThat(tweetAuthor.profileInterstitialType()).contains("profileInterstitialType") assertThat(tweetAuthor.profilePicture()) .contains("https://pbs.twimg.com/profile_images/example.jpg") + assertThat(tweetAuthor.profileSortEnabled()).contains(true) + assertThat(tweetAuthor.profileTranslatorType()).contains("profileTranslatorType") assertThat(tweetAuthor.protected_()).contains(false) assertThat(tweetAuthor.statusesCount()).contains(35000L) + assertThat(tweetAuthor.superFollowEligible()).contains(true) assertThat(tweetAuthor.unavailable()).contains(false) assertThat(tweetAuthor.unavailableReason()).contains("suspended") assertThat(tweetAuthor.url()).contains("https://xquik.com") assertThat(tweetAuthor.verified()).contains(true) assertThat(tweetAuthor.verifiedType()).contains("Business") - assertThat(tweetAuthor.viewerFollowedBy()).contains(false) - assertThat(tweetAuthor.viewerFollowing()).contains(true) assertThat(tweetAuthor.withheldInCountries().getOrNull()).containsExactly("DE") } @@ -114,22 +181,50 @@ internal class TweetAuthorTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -139,16 +234,20 @@ internal class TweetAuthorTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetailTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetailTest.kt index 984583e..8513e9e 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetailTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetDetailTest.kt @@ -31,27 +31,63 @@ internal class TweetDetailTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -61,19 +97,46 @@ internal class TweetDetailTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -81,7 +144,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -92,6 +154,12 @@ internal class TweetDetailTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( TweetDetail.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -104,12 +172,46 @@ internal class TweetDetailTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -117,6 +219,52 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -129,27 +277,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -161,19 +345,46 @@ internal class TweetDetailTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -183,7 +394,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -193,6 +403,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -205,12 +421,50 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -218,11 +472,58 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -235,27 +536,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -267,19 +604,46 @@ internal class TweetDetailTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -289,7 +653,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -299,6 +662,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -311,12 +680,50 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -324,16 +731,64 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() assertThat(tweetDetail.id()).isEqualTo("1234567890") @@ -344,28 +799,65 @@ internal class TweetDetailTest { assertThat(tweetDetail.retweetCount()).isEqualTo(5L) assertThat(tweetDetail.text()).isEqualTo("Just launched our new feature!") assertThat(tweetDetail.viewCount()).isEqualTo(1500L) + assertThat(tweetDetail.article()) + .contains( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) assertThat(tweetDetail.author()) .contains( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -375,19 +867,48 @@ internal class TweetDetailTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + assertThat(tweetDetail.card()) + .contains( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + assertThat(tweetDetail.communityNote()) + .contains( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) assertThat(tweetDetail.contentDisclosure()) .contains( ContentDisclosure.builder() @@ -396,7 +917,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -406,6 +926,13 @@ internal class TweetDetailTest { assertThat(tweetDetail.conversationId()).contains("1234567890") assertThat(tweetDetail.createdAt()).contains("2025-01-15T12:00:00Z") assertThat(tweetDetail.displayTextRange().getOrNull()).containsExactly(0L, 31L) + assertThat(tweetDetail.edit()) + .contains( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) assertThat(tweetDetail.entities()) .contains( TweetDetail.Entities.builder() @@ -419,6 +946,7 @@ internal class TweetDetailTest { assertThat(tweetDetail.isNoteTweet()).contains(false) assertThat(tweetDetail.isQuoteStatus()).contains(false) assertThat(tweetDetail.isReply()).contains(false) + assertThat(tweetDetail.isTranslatable()).contains(true) assertThat(tweetDetail.lang()).contains("en") assertThat(tweetDetail.media().getOrNull()) .containsExactly( @@ -426,6 +954,37 @@ internal class TweetDetailTest { .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect(TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build()) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -433,6 +992,55 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + assertThat(tweetDetail.noteTweet()) + .contains( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + assertThat(tweetDetail.place()) + .contains( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + assertThat(tweetDetail.possiblySensitive()).contains(true) + assertThat(tweetDetail.previousCounts()) + .contains( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) assertThat(tweetDetail.quotedTweet()) @@ -446,27 +1054,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -476,19 +1120,46 @@ internal class TweetDetailTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -498,7 +1169,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -508,6 +1178,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -520,12 +1196,48 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -533,11 +1245,58 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) assertThat(tweetDetail.retweetedTweet()) @@ -551,27 +1310,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -581,19 +1376,46 @@ internal class TweetDetailTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -603,7 +1425,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -613,6 +1434,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -625,12 +1452,48 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -638,16 +1501,64 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) assertThat(tweetDetail.source()).contains("Twitter Web App") assertThat(tweetDetail.type()).contains("tweet") assertThat(tweetDetail.url()).contains("https://x.com/example_user/status/1234567890") + assertThat(tweetDetail.viewState()).contains("viewState") } @Test @@ -663,27 +1574,63 @@ internal class TweetDetailTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -693,19 +1640,46 @@ internal class TweetDetailTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -713,7 +1687,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -724,6 +1697,12 @@ internal class TweetDetailTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( TweetDetail.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -736,12 +1715,46 @@ internal class TweetDetailTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from(mapOf("h" to 0, "resize" to "resize", "w" to 0)), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -749,6 +1762,52 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -761,27 +1820,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -793,19 +1888,46 @@ internal class TweetDetailTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -815,7 +1937,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -825,6 +1946,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -837,12 +1964,50 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -850,11 +2015,58 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -867,27 +2079,63 @@ internal class TweetDetailTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -899,19 +2147,46 @@ internal class TweetDetailTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -921,7 +2196,6 @@ internal class TweetDetailTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -931,6 +2205,12 @@ internal class TweetDetailTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -943,12 +2223,50 @@ internal class TweetDetailTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -956,16 +2274,64 @@ internal class TweetDetailTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() val roundtrippedTweetDetail = diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParamsTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParamsTest.kt index a00853f..0c95139 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParamsTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesParamsTest.kt @@ -27,12 +27,14 @@ internal class TweetGetRepliesParamsTest { .hashtags("hashtags") .inReplyToTweetId("inReplyToTweetId") .language("language") + .limit(1L) .mediaType(TweetGetRepliesParams.MediaType.IMAGES) .mentioning("mentioning") .minFaves(0L) .minQuotes(0L) .minReplies(0L) .minRetweets(0L) + .mode(TweetGetRepliesParams.Mode.COMPLETE) .pageSize(1L) .quotes(TweetGetRepliesParams.Quotes.INCLUDE) .quotesOfTweetId("quotesOfTweetId") @@ -73,12 +75,14 @@ internal class TweetGetRepliesParamsTest { .hashtags("hashtags") .inReplyToTweetId("inReplyToTweetId") .language("language") + .limit(1L) .mediaType(TweetGetRepliesParams.MediaType.IMAGES) .mentioning("mentioning") .minFaves(0L) .minQuotes(0L) .minReplies(0L) .minRetweets(0L) + .mode(TweetGetRepliesParams.Mode.COMPLETE) .pageSize(1L) .quotes(TweetGetRepliesParams.Quotes.INCLUDE) .quotesOfTweetId("quotesOfTweetId") @@ -109,12 +113,14 @@ internal class TweetGetRepliesParamsTest { .put("hashtags", "hashtags") .put("inReplyToTweetId", "inReplyToTweetId") .put("language", "language") + .put("limit", "1") .put("mediaType", "images") .put("mentioning", "mentioning") .put("minFaves", "0") .put("minQuotes", "0") .put("minReplies", "0") .put("minRetweets", "0") + .put("mode", "complete") .put("pageSize", "1") .put("quotes", "include") .put("quotesOfTweetId", "quotesOfTweetId") diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponseTest.kt new file mode 100644 index 0000000..2cf7d46 --- /dev/null +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetGetRepliesResponseTest.kt @@ -0,0 +1,5132 @@ +// File generated from our OpenAPI spec by Stainless. + +package com.x_twitter_scraper.api.models.x.tweets + +import com.fasterxml.jackson.module.kotlin.jacksonTypeRef +import com.x_twitter_scraper.api.core.JsonValue +import com.x_twitter_scraper.api.core.jsonMapper +import com.x_twitter_scraper.api.models.ContentDisclosure +import com.x_twitter_scraper.api.models.EmbeddedTweet +import com.x_twitter_scraper.api.models.SearchTweet +import com.x_twitter_scraper.api.models.TweetMedia +import com.x_twitter_scraper.api.models.UserProfile +import kotlin.jvm.optionals.getOrNull +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test + +internal class TweetGetRepliesResponseTest { + + @Test + fun create() { + val tweetGetRepliesResponse = + TweetGetRepliesResponse.builder() + .hasNextPage(true) + .nextCursor("DAACCgACGRElMJcAAA") + .addTweet( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + .diagnostic( + TweetGetRepliesResponse.Diagnostic.builder() + .complete(true) + .coveragePercentage(0.0) + .cursorFailures(0L) + .duplicateCount(0L) + .emptyFalseProgressPages(0L) + .malformedCount(0L) + .addMissingResponseModulesOrField("string") + .nestedReplyCount(0L) + .pagesAttempted(0L) + .recommendedFallback("recommendedFallback") + .repeatedCursorCount(0L) + .reportedReplyCount(0L) + .responseTruncated(true) + .richness( + TweetGetRepliesResponse.Diagnostic.Richness.builder() + .article(0L) + .author(0L) + .card(0L) + .communityNote(0L) + .createdAt(0L) + .engagementCounts(0L) + .entities(0L) + .language(0L) + .media(0L) + .quotedOrRepostedTweet(0L) + .text(0L) + .totalReplies(0L) + .url(0L) + .build() + ) + .addStrategiesAttempted( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted.builder() + .name("name") + .newDirectReplies(0L) + .newNestedReplies(0L) + .pagesAttempted(0L) + .stopReason( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted + .StopReason + .DEADLINE + ) + .build() + ) + .targetDirectReplies(0L) + .uniqueDirectReplies(0L) + .unrelatedCount(0L) + .build() + ) + .addNestedReply( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + .build() + + assertThat(tweetGetRepliesResponse.hasNextPage()).isEqualTo(true) + assertThat(tweetGetRepliesResponse.nextCursor()).isEqualTo("DAACCgACGRElMJcAAA") + assertThat(tweetGetRepliesResponse.tweets()) + .containsExactly( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + assertThat(tweetGetRepliesResponse.diagnostic()) + .contains( + TweetGetRepliesResponse.Diagnostic.builder() + .complete(true) + .coveragePercentage(0.0) + .cursorFailures(0L) + .duplicateCount(0L) + .emptyFalseProgressPages(0L) + .malformedCount(0L) + .addMissingResponseModulesOrField("string") + .nestedReplyCount(0L) + .pagesAttempted(0L) + .recommendedFallback("recommendedFallback") + .repeatedCursorCount(0L) + .reportedReplyCount(0L) + .responseTruncated(true) + .richness( + TweetGetRepliesResponse.Diagnostic.Richness.builder() + .article(0L) + .author(0L) + .card(0L) + .communityNote(0L) + .createdAt(0L) + .engagementCounts(0L) + .entities(0L) + .language(0L) + .media(0L) + .quotedOrRepostedTweet(0L) + .text(0L) + .totalReplies(0L) + .url(0L) + .build() + ) + .addStrategiesAttempted( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted.builder() + .name("name") + .newDirectReplies(0L) + .newNestedReplies(0L) + .pagesAttempted(0L) + .stopReason( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted.StopReason + .DEADLINE + ) + .build() + ) + .targetDirectReplies(0L) + .uniqueDirectReplies(0L) + .unrelatedCount(0L) + .build() + ) + assertThat(tweetGetRepliesResponse.nestedReplies().getOrNull()) + .containsExactly( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + } + + @Test + fun roundtrip() { + val jsonMapper = jsonMapper() + val tweetGetRepliesResponse = + TweetGetRepliesResponse.builder() + .hasNextPage(true) + .nextCursor("DAACCgACGRElMJcAAA") + .addTweet( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + .diagnostic( + TweetGetRepliesResponse.Diagnostic.builder() + .complete(true) + .coveragePercentage(0.0) + .cursorFailures(0L) + .duplicateCount(0L) + .emptyFalseProgressPages(0L) + .malformedCount(0L) + .addMissingResponseModulesOrField("string") + .nestedReplyCount(0L) + .pagesAttempted(0L) + .recommendedFallback("recommendedFallback") + .repeatedCursorCount(0L) + .reportedReplyCount(0L) + .responseTruncated(true) + .richness( + TweetGetRepliesResponse.Diagnostic.Richness.builder() + .article(0L) + .author(0L) + .card(0L) + .communityNote(0L) + .createdAt(0L) + .engagementCounts(0L) + .entities(0L) + .language(0L) + .media(0L) + .quotedOrRepostedTweet(0L) + .text(0L) + .totalReplies(0L) + .url(0L) + .build() + ) + .addStrategiesAttempted( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted.builder() + .name("name") + .newDirectReplies(0L) + .newNestedReplies(0L) + .pagesAttempted(0L) + .stopReason( + TweetGetRepliesResponse.Diagnostic.StrategiesAttempted + .StopReason + .DEADLINE + ) + .build() + ) + .targetDirectReplies(0L) + .uniqueDirectReplies(0L) + .unrelatedCount(0L) + .build() + ) + .addNestedReply( + SearchTweet.builder() + .id("1234567890") + .bookmarkCount(2L) + .likeCount(42L) + .quoteCount(1L) + .replyCount(3L) + .retweetCount(5L) + .text("Just launched our new feature!") + .viewCount(1500L) + .article( + SearchTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty("description", JsonValue.from("bar")) + .putAdditionalProperty("entities", JsonValue.from("bar")) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + SearchTweet.Card.builder() + .id("id") + .bindingValues( + SearchTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + SearchTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("1234567890") + .createdAt("2025-01-15T12:00:00Z") + .addDisplayTextRange(0L) + .addDisplayTextRange(31L) + .edit( + SearchTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + SearchTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("1234567890") + .inReplyToUserId("9876543210") + .inReplyToUsername("example_user") + .isLimitedReply(false) + .isNoteTweet(false) + .isQuoteStatus(false) + .isReply(false) + .isTranslatable(true) + .lang("en") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + SearchTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + SearchTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + SearchTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + SearchTweet.Place.builder() + .id("id") + .boundingBox( + SearchTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + SearchTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .quotedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .retweetedTweet( + EmbeddedTweet.builder() + .id("id") + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .text("text") + .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) + .author( + UserProfile.builder() + .id("9876543210") + .name("Elon Musk") + .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) + .automatedBy("example_user") + .businessAccountAffiliatesCount(0L) + .communityRole("Member") + .coverPicture( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) + .description("CEO of Tesla, SpaceX, and X") + .favouritesCount(18000L) + .followers(150000000L) + .following(500L) + .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) + .isAutomated(false) + .isBlueVerified(true) + .isProfileTranslatable(true) + .isTranslator(false) + .isVerified(true) + .location("Austin, TX") + .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") + .addPinnedTweetId("1234567890") + .possiblySensitive(false) + .profileBio( + UserProfile.ProfileBio.builder() + .putAdditionalProperty( + "description", + JsonValue.from("bar"), + ) + .putAdditionalProperty( + "entities", + JsonValue.from("bar"), + ) + .build() + ) + .profileBannerUrl( + "https://pbs.twimg.com/profile_banners/example.jpg" + ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") + .profilePicture( + "https://pbs.twimg.com/profile_images/example.jpg" + ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") + .protected_(false) + .statusesCount(35000L) + .superFollowEligible(true) + .unavailable(false) + .unavailableReason("suspended") + .url("https://xquik.com") + .verified(true) + .verifiedType("Business") + .addWithheldInCountry("DE") + .build() + ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) + .contentDisclosure( + ContentDisclosure.builder() + .advertising( + ContentDisclosure.Advertising.builder() + .isPaidPromotion(true) + .build() + ) + .aiGenerated( + ContentDisclosure.AiGenerated.builder() + .detectionSource("UserDeclared") + .hasAiGeneratedMedia(true) + .build() + ) + .build() + ) + .conversationId("conversationId") + .createdAt("createdAt") + .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) + .entities( + EmbeddedTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .inReplyToId("inReplyToId") + .inReplyToUserId("inReplyToUserId") + .inReplyToUsername("inReplyToUsername") + .isLimitedReply(true) + .isNoteTweet(true) + .isQuoteStatus(true) + .isReply(true) + .isTranslatable(true) + .lang("lang") + .addMedia( + TweetMedia.builder() + .mediaUrl("mediaUrl") + .type(TweetMedia.Type.PHOTO) + .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) + .addVideoVariant( + TweetMedia.VideoVariant.builder() + .contentType("contentType") + .url("url") + .bitrate(0L) + .build() + ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) + .build() + ) + .source("source") + .type("type") + .url("url") + .viewState("viewState") + .build() + ) + .source("Twitter Web App") + .type("tweet") + .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") + .build() + ) + .build() + + val roundtrippedTweetGetRepliesResponse = + jsonMapper.readValue( + jsonMapper.writeValueAsString(tweetGetRepliesResponse), + jacksonTypeRef(), + ) + + assertThat(roundtrippedTweetGetRepliesResponse).isEqualTo(tweetGetRepliesResponse) + } +} diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetRetrieveResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetRetrieveResponseTest.kt index e50b792..33ca769 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetRetrieveResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/tweets/TweetRetrieveResponseTest.kt @@ -32,27 +32,63 @@ internal class TweetRetrieveResponseTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -64,19 +100,46 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -86,7 +149,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -97,6 +159,12 @@ internal class TweetRetrieveResponseTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( TweetDetail.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -109,12 +177,50 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -122,6 +228,52 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -134,29 +286,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -174,21 +362,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -198,7 +413,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -208,6 +422,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -220,12 +440,64 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -233,11 +505,58 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -250,29 +569,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -290,21 +645,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -314,7 +696,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -324,6 +705,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -336,12 +723,64 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -349,16 +788,64 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) .author( @@ -366,22 +853,50 @@ internal class TweetRetrieveResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -391,16 +906,20 @@ internal class TweetRetrieveResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -417,27 +936,63 @@ internal class TweetRetrieveResponseTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -447,19 +1002,46 @@ internal class TweetRetrieveResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -469,7 +1051,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -480,6 +1061,12 @@ internal class TweetRetrieveResponseTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( TweetDetail.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -492,12 +1079,48 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf(mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0)) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -505,6 +1128,52 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -517,29 +1186,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -557,21 +1262,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -581,7 +1313,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -591,6 +1322,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -603,12 +1340,60 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -616,11 +1401,58 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -633,29 +1465,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -673,21 +1541,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -697,7 +1592,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -707,6 +1601,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -719,12 +1619,60 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -732,16 +1680,64 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) assertThat(tweetRetrieveResponse.author()) @@ -750,22 +1746,50 @@ internal class TweetRetrieveResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -775,16 +1799,20 @@ internal class TweetRetrieveResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -805,27 +1833,63 @@ internal class TweetRetrieveResponseTest { .retweetCount(5L) .text("Just launched our new feature!") .viewCount(1500L) + .article( + TweetDetail.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( TweetAuthor.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -837,19 +1901,46 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + TweetDetail.Card.builder() + .id("id") + .bindingValues( + TweetDetail.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + TweetDetail.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -859,7 +1950,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -870,6 +1960,12 @@ internal class TweetRetrieveResponseTest { .createdAt("2025-01-15T12:00:00Z") .addDisplayTextRange(0L) .addDisplayTextRange(31L) + .edit( + TweetDetail.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( TweetDetail.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -882,12 +1978,50 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(false) .isQuoteStatus(false) .isReply(false) + .isTranslatable(true) .lang("en") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf("h" to 0, "w" to 0, "x" to 0, "y" to 0) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder().h(0L).w(0L).x(0L).y(0L).build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf("h" to 0, "resize" to "resize", "w" to 0) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -895,6 +2029,52 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + TweetDetail.NoteTweet.builder() + .text("text") + .id("id") + .entities( + TweetDetail.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + TweetDetail.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + TweetDetail.Place.builder() + .id("id") + .boundingBox( + TweetDetail.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + TweetDetail.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .quotedTweet( @@ -907,29 +2087,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -947,21 +2163,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -971,7 +2214,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -981,6 +2223,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -993,12 +2241,64 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -1006,11 +2306,58 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .retweetedTweet( @@ -1023,29 +2370,65 @@ internal class TweetRetrieveResponseTest { .retweetCount(0L) .text("text") .viewCount(0L) + .article( + EmbeddedTweet.Article.builder() + .id("id") + .coverMediaUrl("coverMediaUrl") + .previewText("previewText") + .title("title") + .build() + ) .author( UserProfile.builder() .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture( "https://pbs.twimg.com/profile_banners/example.jpg" ) .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -1063,21 +2446,48 @@ internal class TweetRetrieveResponseTest { .profileBannerUrl( "https://pbs.twimg.com/profile_banners/example.jpg" ) + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture( "https://pbs.twimg.com/profile_images/example.jpg" ) + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) + .card( + EmbeddedTweet.Card.builder() + .id("id") + .bindingValues( + EmbeddedTweet.Card.BindingValues.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .name("name") + .url("url") + .build() + ) + .communityNote( + EmbeddedTweet.CommunityNote.builder() + .id("id") + .destinationUrl("destinationUrl") + .footer("footer") + .shortTitle("shortTitle") + .subtitle("subtitle") + .title("title") + .visualStyle("visualStyle") + .build() + ) .contentDisclosure( ContentDisclosure.builder() .advertising( @@ -1087,7 +2497,6 @@ internal class TweetRetrieveResponseTest { ) .aiGenerated( ContentDisclosure.AiGenerated.builder() - .canEdit(true) .detectionSource("UserDeclared") .hasAiGeneratedMedia(true) .build() @@ -1097,6 +2506,12 @@ internal class TweetRetrieveResponseTest { .conversationId("conversationId") .createdAt("createdAt") .addDisplayTextRange(0L) + .edit( + EmbeddedTweet.Edit.builder() + .editableUntilMsecs("editableUntilMsecs") + .addEditTweetId("string") + .build() + ) .entities( EmbeddedTweet.Entities.builder() .putAdditionalProperty("foo", JsonValue.from("bar")) @@ -1109,12 +2524,64 @@ internal class TweetRetrieveResponseTest { .isNoteTweet(true) .isQuoteStatus(true) .isReply(true) + .isTranslatable(true) .lang("lang") .addMedia( TweetMedia.builder() .mediaUrl("mediaUrl") .type(TweetMedia.Type.PHOTO) .url("url") + .id("id") + .allowDownload(true) + .altText("altText") + .addAspectRatio(0L) + .availabilityStatus("availabilityStatus") + .displayUrl("displayUrl") + .durationMillis(0L) + .expandedUrl("expandedUrl") + .faceRects( + TweetMedia.FaceRects.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + listOf( + mapOf( + "h" to 0, + "w" to 0, + "x" to 0, + "y" to 0, + ) + ) + ), + ) + .build() + ) + .addFocusRect( + TweetMedia.FocusRect.builder() + .h(0L) + .w(0L) + .x(0L) + .y(0L) + .build() + ) + .height(0L) + .addIndex(0L) + .mediaKey("mediaKey") + .monetizable(true) + .sizes( + TweetMedia.Sizes.builder() + .putAdditionalProperty( + "foo", + JsonValue.from( + mapOf( + "h" to 0, + "resize" to "resize", + "w" to 0, + ) + ), + ) + .build() + ) .addVideoVariant( TweetMedia.VideoVariant.builder() .contentType("contentType") @@ -1122,16 +2589,64 @@ internal class TweetRetrieveResponseTest { .bitrate(0L) .build() ) + .width(0L) + .build() + ) + .noteTweet( + EmbeddedTweet.NoteTweet.builder() + .text("text") + .id("id") + .entities( + EmbeddedTweet.NoteTweet.Entities.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .isExpandable(true) + .addRichtextTag( + EmbeddedTweet.NoteTweet.RichtextTag.builder() + .fromIndex(0L) + .toIndex(0L) + .addType("string") + .build() + ) + .build() + ) + .place( + EmbeddedTweet.Place.builder() + .id("id") + .boundingBox( + EmbeddedTweet.Place.BoundingBox.builder() + .putAdditionalProperty("foo", JsonValue.from("bar")) + .build() + ) + .country("country") + .countryCode("countryCode") + .fullName("fullName") + .name("name") + .placeType("placeType") + .url("url") + .build() + ) + .possiblySensitive(true) + .previousCounts( + EmbeddedTweet.PreviousCounts.builder() + .bookmarkCount(0L) + .likeCount(0L) + .quoteCount(0L) + .replyCount(0L) + .retweetCount(0L) .build() ) .source("source") .type("type") .url("url") + .viewState("viewState") .build() ) .source("Twitter Web App") .type("tweet") .url("https://x.com/example_user/status/1234567890") + .viewState("viewState") .build() ) .author( @@ -1139,22 +2654,50 @@ internal class TweetRetrieveResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -1164,16 +2707,20 @@ internal class TweetRetrieveResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveBatchResponseTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveBatchResponseTest.kt index 7f5034b..9eabd3f 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveBatchResponseTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/models/x/users/UserRetrieveBatchResponseTest.kt @@ -30,22 +30,50 @@ internal class UserRetrieveBatchResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -55,16 +83,20 @@ internal class UserRetrieveBatchResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -82,22 +114,50 @@ internal class UserRetrieveBatchResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -107,16 +167,20 @@ internal class UserRetrieveBatchResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) @@ -138,22 +202,50 @@ internal class UserRetrieveBatchResponseTest { .id("9876543210") .name("Elon Musk") .username("elonmusk") + .affiliatesHighlightedLabel( + UserProfile.AffiliatesHighlightedLabel.builder() + .badgeUrl("badgeUrl") + .description("description") + .url("url") + .urlType("urlType") + .userLabelDisplayType("userLabelDisplayType") + .userLabelType("userLabelType") + .build() + ) .automatedBy("example_user") - .canDm(false) + .businessAccountAffiliatesCount(0L) .communityRole("Member") .coverPicture("https://pbs.twimg.com/profile_banners/example.jpg") .createdAt("2009-06-02T20:12:29Z") + .creatorSubscriptionsCount(0L) .description("CEO of Tesla, SpaceX, and X") .favouritesCount(18000L) .followers(150000000L) .following(500L) .hasCustomTimelines(true) + .hasGraduatedAccess(true) + .hasHiddenSubscriptionsOnProfile(true) + .highlightsInfo( + UserProfile.HighlightsInfo.builder() + .canHighlightTweets(true) + .highlightedTweets("highlightedTweets") + .build() + ) + .identityVerification( + UserProfile.IdentityVerification.builder() + .description("description") + .isIdentityVerified(true) + .verifiedSinceMsec("verifiedSinceMsec") + .build() + ) .isAutomated(false) .isBlueVerified(true) + .isProfileTranslatable(true) .isTranslator(false) .isVerified(true) .location("Austin, TX") .mediaCount(1200L) + .parodyCommentaryFanLabel("parodyCommentaryFanLabel") .addPinnedTweetId("1234567890") .possiblySensitive(false) .profileBio( @@ -163,16 +255,20 @@ internal class UserRetrieveBatchResponseTest { .build() ) .profileBannerUrl("https://pbs.twimg.com/profile_banners/example.jpg") + .profileDescriptionLanguage("profileDescriptionLanguage") + .profileImageShape("profileImageShape") + .profileInterstitialType("profileInterstitialType") .profilePicture("https://pbs.twimg.com/profile_images/example.jpg") + .profileSortEnabled(true) + .profileTranslatorType("profileTranslatorType") .protected_(false) .statusesCount(35000L) + .superFollowEligible(true) .unavailable(false) .unavailableReason("suspended") .url("https://xquik.com") .verified(true) .verifiedType("Business") - .viewerFollowedBy(false) - .viewerFollowing(true) .addWithheldInCountry("DE") .build() ) diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncTest.kt index a3ae175..9bce81d 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/async/x/TweetServiceAsyncTest.kt @@ -183,7 +183,7 @@ internal class TweetServiceAsyncTest { .build() val tweetServiceAsync = client.x().tweets() - val paginatedTweetsFuture = + val responseFuture = tweetServiceAsync.getReplies( TweetGetRepliesParams.builder() .id("id") @@ -197,12 +197,14 @@ internal class TweetServiceAsyncTest { .hashtags("hashtags") .inReplyToTweetId("inReplyToTweetId") .language("language") + .limit(1L) .mediaType(TweetGetRepliesParams.MediaType.IMAGES) .mentioning("mentioning") .minFaves(0L) .minQuotes(0L) .minReplies(0L) .minRetweets(0L) + .mode(TweetGetRepliesParams.Mode.COMPLETE) .pageSize(1L) .quotes(TweetGetRepliesParams.Quotes.INCLUDE) .quotesOfTweetId("quotesOfTweetId") @@ -219,8 +221,8 @@ internal class TweetServiceAsyncTest { .build() ) - val paginatedTweets = paginatedTweetsFuture.get() - kotlin.test.assertNotNull(paginatedTweets) + val response = responseFuture.get() + kotlin.test.assertNotNull(response) } @Test diff --git a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceTest.kt b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceTest.kt index 871a4bc..5c3eaae 100644 --- a/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceTest.kt +++ b/x-twitter-scraper-java-core/src/test/kotlin/com/x_twitter_scraper/api/services/blocking/x/TweetServiceTest.kt @@ -176,7 +176,7 @@ internal class TweetServiceTest { .build() val tweetService = client.x().tweets() - val paginatedTweets = + val response = tweetService.getReplies( TweetGetRepliesParams.builder() .id("id") @@ -190,12 +190,14 @@ internal class TweetServiceTest { .hashtags("hashtags") .inReplyToTweetId("inReplyToTweetId") .language("language") + .limit(1L) .mediaType(TweetGetRepliesParams.MediaType.IMAGES) .mentioning("mentioning") .minFaves(0L) .minQuotes(0L) .minReplies(0L) .minRetweets(0L) + .mode(TweetGetRepliesParams.Mode.COMPLETE) .pageSize(1L) .quotes(TweetGetRepliesParams.Quotes.INCLUDE) .quotesOfTweetId("quotesOfTweetId") @@ -212,7 +214,7 @@ internal class TweetServiceTest { .build() ) - kotlin.test.assertNotNull(paginatedTweets) + kotlin.test.assertNotNull(response) } @Test