diff --git a/src/schema.gql b/src/schema.gql index c0c68a4..7f63751 100644 --- a/src/schema.gql +++ b/src/schema.gql @@ -1,658 +1,3 @@ -directive @oneOf on INPUT_OBJECT - -type AddShotAnnotationErrors { - error: DoesNotOwnShotErrOtherErrorNeedsNote! -} - -type AddShotAnnotationReturn { - value: SuccessfulAddAddShotAnnotationErrors! -} - -input AggregateInputGQL { - aggregations: [AggregationInput!]! - filterInput: FilterInput -} - -type AggregateResultGQL { - aggregationIdentifiers: [AggregationIdentifierGQL!]! - targetMetrics: TargetMetricsGQL! -} - -type AggregationIdentifierGQL { - featureName: String! - groupName: String! -} - -input AggregationInput @oneOf { - bucketSet: BucketSetInputGQL - enum: EnumAggregation - datetimeRange: DatetimeRangeAggregationInput -} - -enum AlignedIntervalEnum { - MONTH - YEAR - WEEK - DAY -} - -type BankFeaturesGQL { - wallsHit: [WallTypeEnum!]! - bankAngle: Float! - distance: Float! -} - -type BannerGQL { - id: Int! - message: String! - color: String! - kind: BannerKindEnum! - dismissible: Boolean! - priority: Int! -} - -enum BannerKindEnum { - INFO - WARNING - ERROR -} - -type BoundingBoxGQL { - left: Float! - top: Float! - width: Float! - height: Float! -} - -input BoundingBoxInputGQL { - left: Float! - top: Float! - width: Float! - height: Float! -} - -type BucketGQL { - rangeKey: String! - lowerBound: Float! -} - -input BucketInputGQL { - rangeKey: String! - lowerBound: Float! -} - -type BucketSetGQL { - keyName: String! - feature: String! - buckets: [BucketGQL!]! -} - -input BucketSetInputGQL { - feature: String! - buckets: [BucketInputGQL!]! -} - -type Challenge { - id: ID! - name: String! - description: String - minimumShots: Int! - requiredTableSize: Float - requiredPocketSize: Float - isPublic: Boolean! - maxAttempts: Int - startDate: DateTime! - endDate: DateTime! - createdAt: DateTime! - updatedAt: DateTime! - ruleSet: RuleSet! - createdBy: UserGQL! - invitations: [ChallengeInvitation!]! - participantCount: Int! -} - -type ChallengeEntry { - id: ID! - status: String! - shotsCount: Int - makesCount: Int - makeRate: Float - qualified: Boolean - createdAt: DateTime! - attemptCount: Int - challenge: Challenge! - video: VideoGQL - user: UserGQL! -} - -type ChallengeInvitation { - id: ID! - status: String! - createdAt: DateTime! - challenge: Challenge! - inviter: UserGQL! - invitee: UserGQL! -} - -enum ClientUploadStatusEnum { - UPLOAD_ENABLED - UPLOAD_DISABLED -} - -type CommentGQL { - id: Int! - user: UserGQL! - message: String! - replies: [CommentGQL!]! -} - -type CountLeaderboardGQL { - entries: [UserShotCountEntry!]! -} - -input CreateBucketSetInput { - keyName: String! - feature: String! - buckets: [BucketInputGQL!]! -} - -type CreateSubscriptionResultGQL { - checkoutUrl: String! - sessionId: String! -} - -type CreateUploadStreamReturn { - videoId: Int! -} - -input CreatedAfter @oneOf { - videoId: Int - createdAt: DateTime -} - -type CueObjectFeaturesGQL { - cueObjectDistance: Float - cueObjectAngle: Float - cueBallSpeed: Float - shotDirection: ShotDirectionEnum - spinType: SpinTypeEnum -} - -""" -Date (isoformat) -""" -scalar Date - -input DateRangeFilter { - lessThan: Date = null - greaterThanEqualTo: Date = null - greaterThan: Date = null - includeOnNone: Boolean! = false - lessThanInclusive: Boolean! = false - greaterThanInclusive: Boolean! = true -} - -""" -Date with time (isoformat) -""" -scalar DateTime - -input DatetimeOrdering { - descending: Boolean! = true - startingAt: DateTime = null -} - -input DatetimeRangeAggregationInput { - startDatetime: DateTime = null - endDatetime: DateTime = null - interval: TimeInterval! - feature: String! = "created_at" -} - -type DeployedConfigGQL { - allowNewUsers: Boolean! - firebase: Boolean! - devMode: Boolean! - environment: String! - minimumAllowedAppVersion: String! - subscriptionGatingEnabled: Boolean! - bannerMessages: [BannerGQL!]! -} - -type DoesNotOwnShotErr { - shotId: Int! - msg: String -} - -union DoesNotOwnShotErrOtherErrorNeedsNote = - DoesNotOwnShotErr - | OtherErrorNeedsNote - -type EditShotReturn { - shot: ShotGQL - error: DoesNotOwnShotErr -} - -input EditUserInputGQL { - username: String = null - fargoRating: Int = null - videosPrivateByDefault: Boolean = null - agreesToMarketing: Boolean = null -} - -input EditableShotFieldInputGQL { - intendedPocketType: PocketEnum - shotDirection: ShotDirectionEnum - spinType: SpinTypeEnum - targetPocketAngleDirection: ShotDirectionEnum - make: Boolean - backcut: Boolean - excludeFromStats: Boolean - notes: String -} - -input EnumAggregation { - feature: String! -} - -input FilterInput @oneOf { - andFilters: [FilterInput!] - orFilters: [FilterInput!] - notFilter: FilterInput - cueObjectDistance: FloatRangeFilter - targetPocketDistance: FloatRangeFilter - cueObjectAngle: FloatRangeFilter - cueBallSpeed: FloatRangeFilter - difficulty: FloatRangeFilter - intendedPocketType: [PocketEnum!] - shotDirection: [ShotDirectionEnum!] - videoId: [Int!] - userId: [Int!] - runId: [Int!] - username: [String!] - fargoRating: FloatRangeFilter - make: [Boolean!] - tags: [VideoTagInput!] - annotations: [ShotAnnotationInput!] - isStraight: [Boolean!] - isRight: [Boolean!] - isLeft: [Boolean!] - isLeftMiss: [Boolean!] - isRightMiss: [Boolean!] - isDirect: [Boolean!] - isBreakHeuristic: [Boolean!] - tableSize: FloatRangeFilter - bankAngle: FloatRangeFilter - bankDistance: FloatRangeFilter - kickAngle: FloatRangeFilter - kickDistance: FloatRangeFilter - cueAngleAfterObject: FloatRangeFilter - spinType: [SpinTypeEnum!] - cueSpeedAfterObject: FloatRangeFilter - falsePositiveScore: FloatRangeFilter - backcut: [Boolean!] - targetPocketAngleDirection: [ShotDirectionEnum!] - targetPocketAngle: FloatRangeFilter - missAngleInDegrees: FloatRangeFilter - marginOfErrorInDegrees: FloatRangeFilter - createdAt: DateRangeFilter - totalDistance: FloatRangeFilter - runLength: FloatRangeFilter -} - -input FloatOrdering { - descending: Boolean! = true - startingAt: Float = null -} - -input FloatRangeFilter { - lessThan: Float = null - greaterThanEqualTo: Float = null - greaterThan: Float = null - includeOnNone: Boolean! = false - lessThanInclusive: Boolean! = false - greaterThanInclusive: Boolean! = true -} - -type GetProfileUploadLinkErrors { - error: TooManyProfileImageUploadsErr! -} - -type GetProfileUploadLinkReturn { - value: UploadLinkGetProfileUploadLinkErrors! -} - -input GetRunsOrdering { - orderings: [RunsOrderingComponent!]! -} - -type GetRunsResult { - runs: [RunGQL!]! - count: Int - runIds: [Int!]! -} - -input GetShotsOrdering { - orderings: [ShotsOrderingComponent!]! -} - -input GetShotsPagination { - createdAfter: CreatedAfter! - startFrameAfter: Int! -} - -type GetShotsResult { - shots: [ShotGQL!]! - count: Int - ids: [Int!]! -} - -type GetUploadLinkErrors { - error: MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr! -} - -type GetUploadLinkReturn { - value: UploadLinkGetUploadLinkErrors! - stream: UploadStreamGQL -} - -type HLSPlaylistGQL { - videoId: Int! - m3u8Text: String! - segmentDurations: [Float!]! -} - -type Header { - key: String! - value: String! -} - -type HomographyInfoGQL { - id: Int! - frameIndex: Int! - crop: BoundingBoxGQL! - pockets: [BoundingBoxGQL!]! - sourcePoints: PocketPointsGQL! - destPoints: PocketPointsGQL! -} - -input HomographyInputGQL { - crop: BoundingBoxInputGQL! - pockets: [BoundingBoxInputGQL!]! - sourcePoints: PocketPointsInputGQL! - destPoints: PocketPointsInputGQL! -} - -enum IncludePrivateEnum { - ALL - MINE - NONE -} - -enum InitPlaylistUploadStatusEnum { - NOT_APPLICABLE - NOT_UPLOADED - UPLOADED -} - -type InitUploadAlreadyCompletedErr { - segmentType: StreamSegmentTypeEnum! -} - -input IntOrdering { - descending: Boolean! = true - startingAt: Int = null -} - -type IntPoint2D { - x: Int! - y: Int! -} - -input IntPoint2DInput { - x: Int! - y: Int! -} - -""" -The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). -""" -scalar JSON - @specifiedBy( - url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf" - ) - -type MakePercentageIntervalGQL { - makePercentage: Float! - elapsedTime: Float! -} - -type MedalGQL { - count: Int! - nickname: String -} - -input MedalScope @oneOf { - videoId: Int - interval: TimeInterval - @deprecated(reason: "NO LONGER SUPPORTED, USE DATETIME_RANGE") - datetimeRange: DatetimeRangeAggregationInput -} - -type MustHaveSetForUploadLinkErr { - resolution: Boolean - framesPerSecond: Boolean -} - -union MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr = - MustHaveSetForUploadLinkErr - | SegmentAlreadyUploadedErr - | ProcessingFailedErr - | NoInitForChunkedUploadErr - | TooManyProfileImageUploadsErr - | InitUploadAlreadyCompletedErr - | TooManyInitUploadsErr - -type Mutation { - createBucketSet(params: CreateBucketSetInput!): BucketSetGQL! - createRuleSet(name: String!, description: String = null): RuleSet! - createChallenge( - name: String! - ruleSetId: ID! - minimumShots: Int! - startDate: DateTime! - endDate: DateTime! - description: String = null - requiredTableSize: Float = null - requiredPocketSize: Float = null - isPublic: Boolean! = false - maxAttempts: Int = null - ): Challenge! - inviteUsersToChallenge( - challengeId: ID! - userIds: [ID!]! - ): [ChallengeInvitation!]! - respondToChallengeInvitation( - invitationId: ID! - accept: Boolean! - ): ChallengeInvitation! - startChallenge(challengeId: ID!): ChallengeEntry! - recalculateChallengeEntry(entryId: ID!): ChallengeEntry! - submitChallengeEntry(entryId: ID!, videoId: ID!): ChallengeEntry! - dismissChallenge(challengeId: ID!): Boolean! - undismissChallenge(challengeId: ID!): Boolean! - setLoggerLevel(path: String!, level: String!): Boolean! - reactToVideo(videoId: Int!, reaction: ReactionEnum): Boolean! - commentOnVideo( - videoId: Int! - message: String! - parentCommentId: Int - ): Boolean! - editComment(videoId: Int!, commentId: Int!, newMessage: String!): Boolean! - deleteComment(videoId: Int!, commentId: Int!): Boolean! - blockContent(videoId: Int!): Boolean! - blockUser(userId: Int!): Boolean! - reportContent( - videoId: Int! - reason: ReportReasonEnum! - customReason: String = null - ): Boolean! - markNotificationAsRead(notificationId: Int!): Boolean! - markAllNotificationsAsRead: Boolean! - markNotificationsAsRead(notificationIds: [Int!]!): Boolean! - deleteNotification(notificationId: Int!): Boolean! - addAnnotationToShot( - shotId: Int! - annotationName: String! - notes: String = null - ): AddShotAnnotationReturn! - updateShotAnnotations( - shotId: Int! - annotations: [UpdateAnnotationInputGQL!]! - ): UpdateShotAnnotationReturn! - editShot( - shotId: Int! - fieldsToEdit: EditableShotFieldInputGQL! - ): EditShotReturn! - getProfileImageUploadLink( - fileExt: String = ".png" - ): GetProfileUploadLinkReturn! - editProfileImageUri(profileImageUri: String!): UserGQL! - editUser(input: EditUserInputGQL!): UserGQL! - followUser(followedUserId: Int!): UserGQL! - unfollowUser(followedUserId: Int!): UserGQL! - retireTags(tagIds: [Int!]!): Boolean! - ensureStripeCustomerExists: UserGQL! - deleteUser: Boolean! - createSubscription(priceId: String!): CreateSubscriptionResultGQL! - cancelSubscription: UserSubscriptionStatusGQL! - findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL - createUploadStream( - videoMetadata: VideoMetadataInput! - ): CreateUploadStreamReturn! - getUploadLink(videoId: Int!, segmentIndex: Int!): GetUploadLinkReturn! - getHlsInitUploadLink(videoId: Int!): GetUploadLinkReturn! - setSegmentDuration( - videoId: Int! - segmentIndex: Int! - duration: Float! - ): Boolean! - editUploadStream(videoId: Int!, videoMetadata: VideoMetadataInput!): Boolean! - deleteVideo(videoId: Int!): Boolean! - deleteTags(videoId: Int!, tagsToDelete: [VideoTagInput!]!): Boolean! -} - -type NoInitForChunkedUploadErr { - segmentType: StreamSegmentTypeEnum! -} - -type NotificationConnection { - notifications: [NotificationGQL!]! - totalCount: Int! - unreadCount: Int! - hasMore: Boolean! -} - -input NotificationFilters { - isRead: Boolean = null - notificationTypes: [NotificationTypeEnum!] = null -} - -type NotificationGQL { - id: Int! - notificationType: NotificationTypeEnum! - actor: UserGQL! - videoId: Int - challengeId: Int - challenge: Challenge - comment: CommentGQL - reactionType: String - isRead: Boolean! - createdAt: DateTime! - readAt: DateTime -} - -enum NotificationTypeEnum { - COMMENT - COMMENT_REPLY - REACTION - FOLLOW - CHALLENGE_INVITE -} - -type OtherErrorNeedsNote { - msg: String -} - -type PageInfoGQL { - hasNextPage: Boolean! - endCursor: String -} - -enum PocketEnum { - CORNER - SIDE -} - -enum PocketIdentifier { - TOP_LEFT - TOP_SIDE - TOP_RIGHT - BOTTOM_LEFT - BOTTOM_SIDE - BOTTOM_RIGHT -} - -type PocketPointsGQL { - topLeft: IntPoint2D! - topSide: IntPoint2D! - topRight: IntPoint2D! - bottomLeft: IntPoint2D! - bottomSide: IntPoint2D! - bottomRight: IntPoint2D! -} - -input PocketPointsInputGQL { - topLeft: IntPoint2DInput! - topSide: IntPoint2DInput! - topRight: IntPoint2DInput! - bottomLeft: IntPoint2DInput! - bottomSide: IntPoint2DInput! - bottomRight: IntPoint2DInput! -} - -type PocketingIntentionFeaturesGQL { - targetPocketDistance: Float - make: Boolean - intendedPocketType: PocketEnum - difficulty: Float - targetPocketAngle: Float - targetPocketAngleDirection: ShotDirectionEnum - marginOfErrorInDegrees: Float - backcut: Boolean -} - -type PocketingIntentionInfoGQL { - ballId: Int! - pocketId: PocketIdentifier! - pathMetadataIndex: Int! -} - -type ProcessingFailedErr { - processing: VideoProcessingGQL! -} - -enum ProcessingStatusEnum { - STARTED - FAILED - SUCCEEDED - SUSPENDED - CREATED - QUEUED - RUNNING - REEXTRACTING_FEATURES -} - type Query { getAggregatedShotMetrics( aggregateInput: AggregateInputGQL! @@ -764,11 +109,533 @@ type Query { getVideos(videoIds: [Int!]!): [VideoGQL!]! } -enum ReactionEnum { - LIKE - HEART - BULLSEYE - HUNDRED +type AggregateResultGQL { + aggregationIdentifiers: [AggregationIdentifierGQL!]! + targetMetrics: TargetMetricsGQL! +} + +type AggregationIdentifierGQL { + featureName: String! + groupName: String! +} + +type TargetMetricsGQL { + count: Int! + makePercentage: Float + averageDifficulty: Float + spinTypeCounts: SpinTypeCountsGQL + shotDirectionCounts: ShotDirectionCountsGQL +} + +type SpinTypeCountsGQL { + follow: Int! + draw: Int! + center: Int! + unknown: Int! +} + +type ShotDirectionCountsGQL { + left: Int! + right: Int! + straight: Int! +} + +input AggregateInputGQL { + aggregations: [AggregationInput!]! + filterInput: FilterInput +} + +input AggregationInput @oneOf { + bucketSet: BucketSetInputGQL + enum: EnumAggregation + datetimeRange: DatetimeRangeAggregationInput +} + +input BucketSetInputGQL { + feature: String! + buckets: [BucketInputGQL!]! +} + +input BucketInputGQL { + rangeKey: String! + lowerBound: Float! +} + +input EnumAggregation { + feature: String! +} + +input DatetimeRangeAggregationInput { + startDatetime: DateTime = null + endDatetime: DateTime = null + interval: TimeInterval! + feature: String! = "created_at" +} + +""" +Date with time (isoformat) +""" +scalar DateTime + +input TimeInterval @oneOf { + timedelta: TimeDeltaGQL + aligned: AlignedIntervalEnum +} + +input TimeDeltaGQL { + days: Int = 0 + weeks: Int = 0 + months: Int = 0 + years: Int = 0 +} + +enum AlignedIntervalEnum { + MONTH + YEAR + WEEK + DAY +} + +input FilterInput @oneOf { + andFilters: [FilterInput!] + orFilters: [FilterInput!] + notFilter: FilterInput + cueObjectDistance: FloatRangeFilter + targetPocketDistance: FloatRangeFilter + cueObjectAngle: FloatRangeFilter + cueBallSpeed: FloatRangeFilter + difficulty: FloatRangeFilter + intendedPocketType: [PocketEnum!] + shotDirection: [ShotDirectionEnum!] + videoId: [Int!] + userId: [Int!] + runId: [Int!] + username: [String!] + fargoRating: FloatRangeFilter + make: [Boolean!] + tags: [VideoTagInput!] + annotations: [ShotAnnotationInput!] + isStraight: [Boolean!] + isRight: [Boolean!] + isLeft: [Boolean!] + isLeftMiss: [Boolean!] + isRightMiss: [Boolean!] + isDirect: [Boolean!] + isBreakHeuristic: [Boolean!] + tableSize: FloatRangeFilter + bankAngle: FloatRangeFilter + bankDistance: FloatRangeFilter + kickAngle: FloatRangeFilter + kickDistance: FloatRangeFilter + cueAngleAfterObject: FloatRangeFilter + spinType: [SpinTypeEnum!] + cueSpeedAfterObject: FloatRangeFilter + falsePositiveScore: FloatRangeFilter + backcut: [Boolean!] + targetPocketAngleDirection: [ShotDirectionEnum!] + targetPocketAngle: FloatRangeFilter + missAngleInDegrees: FloatRangeFilter + marginOfErrorInDegrees: FloatRangeFilter + createdAt: DateRangeFilter + totalDistance: FloatRangeFilter + runLength: FloatRangeFilter +} + +input FloatRangeFilter { + lessThan: Float = null + greaterThanEqualTo: Float = null + greaterThan: Float = null + includeOnNone: Boolean! = false + lessThanInclusive: Boolean! = false + greaterThanInclusive: Boolean! = true +} + +enum PocketEnum { + CORNER + SIDE +} + +enum ShotDirectionEnum { + LEFT + RIGHT + STRAIGHT +} + +input VideoTagInput { + tagClasses: [VideoTagClassInput!]! = [] + name: String! +} + +input VideoTagClassInput { + name: String! +} + +input ShotAnnotationInput { + name: String! +} + +enum SpinTypeEnum { + DRAW + FOLLOW + CENTER + UNKNOWN +} + +input DateRangeFilter { + lessThan: Date = null + greaterThanEqualTo: Date = null + greaterThan: Date = null + includeOnNone: Boolean! = false + lessThanInclusive: Boolean! = false + greaterThanInclusive: Boolean! = true +} + +""" +Date (isoformat) +""" +scalar Date + +type BucketSetGQL { + keyName: String! + feature: String! + buckets: [BucketGQL!]! +} + +type BucketGQL { + rangeKey: String! + lowerBound: Float! +} + +type Challenge { + id: ID! + name: String! + description: String + minimumShots: Int! + requiredTableSize: Float + requiredPocketSize: Float + isPublic: Boolean! + maxAttempts: Int + startDate: DateTime! + endDate: DateTime! + createdAt: DateTime! + updatedAt: DateTime! + ruleSet: RuleSet! + createdBy: UserGQL! + invitations: [ChallengeInvitation!]! + participantCount: Int! +} + +type RuleSet { + id: ID! + name: String! + description: String + createdAt: DateTime! + updatedAt: DateTime! +} + +type UserGQL { + id: Int! + firebaseUid: String + username: String! + isAdmin: Boolean + fargoRating: Int + activeVideoId: Int + stripeCustomerId: String + profileImageUri: String + createdAt: DateTime + updatedAt: DateTime + videosPrivateByDefault: Boolean + agreesToMarketing: Boolean + following: [UserGQL!] + followers: [UserGQL!] + isFollowedByCurrentUser: Boolean +} + +type ChallengeInvitation { + id: ID! + status: String! + createdAt: DateTime! + challenge: Challenge! + inviter: UserGQL! + invitee: UserGQL! +} + +type ChallengeEntry { + id: ID! + status: String! + shotsCount: Int + makesCount: Int + makeRate: Float + qualified: Boolean + createdAt: DateTime! + attemptCount: Int + challenge: Challenge! + video: VideoGQL + user: UserGQL! +} + +type VideoGQL { + id: Int! + owner: UserGQL + name: String + screenshotUri: String + totalShotsMade: Int! + totalShots: Int! + makePercentage: Float! + medianRun: Float + averageTimeBetweenShots: Float + averageDifficulty: Float + createdAt: DateTime + updatedAt: DateTime + shots: [ShotGQL!]! + startTime: DateTime + endTime: DateTime + elapsedTime: Float + framesPerSecond: Float! + tableSize: Float! + pocketSize: Float + private: Boolean! + stream: UploadStreamGQL + playlist: HLSPlaylistGQL + tags: [VideoTag!]! + currentHomography: HomographyInfoGQL + homographyHistory: [HomographyInfoGQL!]! + currentProcessing: VideoProcessingGQL + reactions: [ReactionGQL!]! + comments: [CommentGQL!]! +} + +type ShotGQL { + id: Int! + videoId: Int! + startFrame: Int! + endFrame: Int! + createdAt: DateTime + updatedAt: DateTime + cueObjectFeatures: CueObjectFeaturesGQL + pocketingIntentionFeatures: PocketingIntentionFeaturesGQL + pocketingIntentionInfo: PocketingIntentionInfoGQL + bankFeatures: BankFeaturesGQL + serializedShotPaths: SerializedShotPathsGQL + user: UserGQL + annotations: [ShotAnnotationGQL!]! + falsePositiveScore: Float + video: VideoGQL + run: RunGQL + runFeatures: RunFeaturesGQL +} + +type CueObjectFeaturesGQL { + cueObjectDistance: Float + cueObjectAngle: Float + cueBallSpeed: Float + shotDirection: ShotDirectionEnum + spinType: SpinTypeEnum +} + +type PocketingIntentionFeaturesGQL { + targetPocketDistance: Float + make: Boolean + intendedPocketType: PocketEnum + difficulty: Float + targetPocketAngle: Float + targetPocketAngleDirection: ShotDirectionEnum + marginOfErrorInDegrees: Float + backcut: Boolean +} + +type PocketingIntentionInfoGQL { + ballId: Int! + pocketId: PocketIdentifier! + pathMetadataIndex: Int! +} + +enum PocketIdentifier { + TOP_LEFT + TOP_SIDE + TOP_RIGHT + BOTTOM_LEFT + BOTTOM_SIDE + BOTTOM_RIGHT +} + +type BankFeaturesGQL { + wallsHit: [WallTypeEnum!]! + bankAngle: Float! + distance: Float! +} + +enum WallTypeEnum { + LONG + SHORT +} + +type SerializedShotPathsGQL { + b64EncodedBuffer: String +} + +type ShotAnnotationGQL { + shotId: Int! + type: ShotAnnotationTypeGQL! + creator: UserGQL! + notes: String! + errorDefault: Boolean! + createdAt: DateTime + updatedAt: DateTime +} + +type ShotAnnotationTypeGQL { + id: Int! + name: String! +} + +type RunGQL { + id: Int! + runLength: Int! + videoId: Int! + userId: Int! + shots: [ShotGQL!]! + video: VideoGQL! + user: UserGQL! +} + +type RunFeaturesGQL { + runId: Int! + indexInRun: Int! +} + +type UploadStreamGQL { + id: ID! + linksRequested: Int! + uploadsCompleted: Int! + segmentProcessingCursor: Int! + lastIntendedSegmentBound: Int + isCompleted: Boolean! + initPlaylistUploadStatus: InitPlaylistUploadStatusEnum + lowestUnuploadedSegmentIndex: Int! + uploadCompletionCursor: Int! + errors: [StreamErrorGQL!]! + createdAt: DateTime! + updatedAt: DateTime! + segments: [UploadSegmentGQL!]! + clientUploadStatus: ClientUploadStatusEnum + resolution: VideoResolutionGQL! + streamSegmentType: StreamSegmentTypeEnum! +} + +enum InitPlaylistUploadStatusEnum { + NOT_APPLICABLE + NOT_UPLOADED + UPLOADED +} + +type StreamErrorGQL { + message: String! +} + +type UploadSegmentGQL { + segmentIndex: Int! + uploaded: Boolean! + valid: Boolean! + endFrameIndex: Int + framesPerSecond: Float + durationInSeconds: Float + linksRequested: Int! +} + +enum ClientUploadStatusEnum { + UPLOAD_ENABLED + UPLOAD_DISABLED +} + +type VideoResolutionGQL { + width: Int + height: Int +} + +enum StreamSegmentTypeEnum { + FRAGMENTED_MP4 + RB_CHUNKED_MP4 +} + +type HLSPlaylistGQL { + videoId: Int! + m3u8Text: String! + segmentDurations: [Float!]! +} + +type VideoTag { + tagClasses: [VideoTagClass!]! + name: String! +} + +type VideoTagClass { + name: String! +} + +type HomographyInfoGQL { + id: Int! + frameIndex: Int! + crop: BoundingBoxGQL! + pockets: [BoundingBoxGQL!]! + sourcePoints: PocketPointsGQL! + destPoints: PocketPointsGQL! +} + +type BoundingBoxGQL { + left: Float! + top: Float! + width: Float! + height: Float! +} + +type PocketPointsGQL { + topLeft: IntPoint2D! + topSide: IntPoint2D! + topRight: IntPoint2D! + bottomLeft: IntPoint2D! + bottomSide: IntPoint2D! + bottomRight: IntPoint2D! +} + +type IntPoint2D { + x: Int! + y: Int! +} + +type VideoProcessingGQL { + id: Int! + errors: [VideoProcessingErrorGQL!]! + status: ProcessingStatusEnum! + statuses: [VideoProcessingStatusGQL!]! + framesProcessed: Int + currentSegment: Int + progressPercentage: Float +} + +type VideoProcessingErrorGQL { + message: String! + startSegmentIndex: Int + endSegmentIndex: Int +} + +enum ProcessingStatusEnum { + STARTED + FAILED + SUCCEEDED + SUSPENDED + CREATED + QUEUED + RUNNING + REEXTRACTING_FEATURES +} + +type VideoProcessingStatusGQL { + status: ProcessingStatusEnum! + appVersion: String! + sequenceId: Int! + createdAt: DateTime + updatedAt: DateTime } type ReactionGQL { @@ -779,13 +646,95 @@ type ReactionGQL { updatedAt: DateTime } -enum ReportReasonEnum { - SPAM - NUDITY - VIOLENCE - HATE - COPYRIGHT - OTHER +enum ReactionEnum { + LIKE + HEART + BULLSEYE + HUNDRED +} + +type CommentGQL { + id: Int! + user: UserGQL! + message: String! + replies: [CommentGQL!]! +} + +type DeployedConfigGQL { + allowNewUsers: Boolean! + firebase: Boolean! + devMode: Boolean! + environment: String! + minimumAllowedAppVersion: String! + subscriptionGatingEnabled: Boolean! + bannerMessages: [BannerGQL!]! +} + +type BannerGQL { + id: Int! + message: String! + color: String! + kind: BannerKindEnum! + dismissible: Boolean! + priority: Int! +} + +enum BannerKindEnum { + INFO + WARNING + ERROR +} + +type VideoHistoryGQL { + videos: [VideoGQL!]! + pageInfo: PageInfoGQL! + hasFollowing: Boolean! +} + +type PageInfoGQL { + hasNextPage: Boolean! + endCursor: String +} + +enum IncludePrivateEnum { + ALL + MINE + NONE +} + +input VideoFilterInput { + isStreamCompleted: Boolean = null + requireCursorCompletion: Boolean! = true + createdAt: DateRangeFilter = null + excludeVideosWithNoShots: Boolean = null +} + +input VideoFeedInputGQL @oneOf { + followedByUserId: Int + userId: Int + allUsers: Boolean + home: Boolean +} + +type MakePercentageIntervalGQL { + makePercentage: Float! + elapsedTime: Float! +} + +type RunLeaderboardGQL { + entries: [RunGQL!]! +} + +type CountLeaderboardGQL { + entries: [UserShotCountEntry!]! +} + +type UserShotCountEntry { + user: UserGQL! + value: Int! + total: Int! + proportionMade: Float! + videos: Int! } type RequestedMedalsGQL { @@ -821,17 +770,56 @@ type RequestedMedalsGQL { dailyMakes250: MedalGQL } -type RuleSet { - id: ID! - name: String! - description: String - createdAt: DateTime! - updatedAt: DateTime! +type MedalGQL { + count: Int! + nickname: String } -type RunFeaturesGQL { - runId: Int! - indexInRun: Int! +input MedalScope @oneOf { + videoId: Int + interval: TimeInterval + @deprecated(reason: "NO LONGER SUPPORTED, USE DATETIME_RANGE") + datetimeRange: DatetimeRangeAggregationInput +} + +type NotificationConnection { + notifications: [NotificationGQL!]! + totalCount: Int! + unreadCount: Int! + hasMore: Boolean! +} + +type NotificationGQL { + id: Int! + notificationType: NotificationTypeEnum! + actor: UserGQL! + videoId: Int + challengeId: Int + challenge: Challenge + comment: CommentGQL + reactionType: String + isRead: Boolean! + createdAt: DateTime! + readAt: DateTime +} + +enum NotificationTypeEnum { + COMMENT + COMMENT_REPLY + REACTION + FOLLOW + CHALLENGE_INVITE +} + +input NotificationFilters { + isRead: Boolean = null + notificationTypes: [NotificationTypeEnum!] = null +} + +type GetRunsResult { + runs: [RunGQL!]! + count: Int + runIds: [Int!]! } input RunFilterInput { @@ -846,18 +834,8 @@ input RunFilterInput { runLength: FloatRangeFilter } -type RunGQL { - id: Int! - runLength: Int! - videoId: Int! - userId: Int! - shots: [ShotGQL!]! - video: VideoGQL! - user: UserGQL! -} - -type RunLeaderboardGQL { - entries: [RunGQL!]! +input GetRunsOrdering { + orderings: [RunsOrderingComponent!]! } input RunsOrderingComponent @oneOf { @@ -866,63 +844,57 @@ input RunsOrderingComponent @oneOf { videoCreation: DatetimeOrdering } -type SegmentAlreadyUploadedErr { - segmentId: Int! +input IntOrdering { + descending: Boolean! = true + startingAt: Int = null } -type SerializedShotPathsGQL { - b64EncodedBuffer: String +input DatetimeOrdering { + descending: Boolean! = true + startingAt: DateTime = null } -type ShotAnnotationGQL { - shotId: Int! - type: ShotAnnotationTypeGQL! - creator: UserGQL! - notes: String! - errorDefault: Boolean! - createdAt: DateTime - updatedAt: DateTime +type TableStateGQL { + identifierToPosition: [[Float!]!]! + homography: HomographyInfoGQL } -input ShotAnnotationInput { - name: String! +input HomographyInputGQL { + crop: BoundingBoxInputGQL! + pockets: [BoundingBoxInputGQL!]! + sourcePoints: PocketPointsInputGQL! + destPoints: PocketPointsInputGQL! } -type ShotAnnotationTypeGQL { - id: Int! - name: String! +input BoundingBoxInputGQL { + left: Float! + top: Float! + width: Float! + height: Float! } -type ShotDirectionCountsGQL { - left: Int! - right: Int! - straight: Int! +input PocketPointsInputGQL { + topLeft: IntPoint2DInput! + topSide: IntPoint2DInput! + topRight: IntPoint2DInput! + bottomLeft: IntPoint2DInput! + bottomSide: IntPoint2DInput! + bottomRight: IntPoint2DInput! } -enum ShotDirectionEnum { - LEFT - RIGHT - STRAIGHT +input IntPoint2DInput { + x: Int! + y: Int! } -type ShotGQL { - id: Int! - videoId: Int! - startFrame: Int! - endFrame: Int! - createdAt: DateTime - updatedAt: DateTime - cueObjectFeatures: CueObjectFeaturesGQL - pocketingIntentionFeatures: PocketingIntentionFeaturesGQL - pocketingIntentionInfo: PocketingIntentionInfoGQL - bankFeatures: BankFeaturesGQL - serializedShotPaths: SerializedShotPathsGQL - user: UserGQL - annotations: [ShotAnnotationGQL!]! - falsePositiveScore: Float - video: VideoGQL - run: RunGQL - runFeatures: RunFeaturesGQL +type GetShotsResult { + shots: [ShotGQL!]! + count: Int + ids: [Int!]! +} + +input GetShotsOrdering { + orderings: [ShotsOrderingComponent!]! } input ShotsOrderingComponent @oneOf { @@ -934,27 +906,42 @@ input ShotsOrderingComponent @oneOf { runLength: IntOrdering } -type SpinTypeCountsGQL { - follow: Int! - draw: Int! - center: Int! - unknown: Int! +input FloatOrdering { + descending: Boolean! = true + startingAt: Float = null } -enum SpinTypeEnum { - DRAW - FOLLOW - CENTER - UNKNOWN +input GetShotsPagination { + createdAfter: CreatedAfter! + startFrameAfter: Int! } -type StreamErrorGQL { - message: String! +input CreatedAfter @oneOf { + videoId: Int + createdAt: DateTime } -enum StreamSegmentTypeEnum { - FRAGMENTED_MP4 - RB_CHUNKED_MP4 +type UserRelationshipsResult { + inquiringUser: UserGQL! + relationships: [UserRelationship!]! +} + +type UserRelationship { + toUser: UserGQL! + toUserFollows: Boolean! + toUserIsFollowedBy: Boolean! +} + +type StripeSubscriptionOptionsGQL { + products: [StripeProductGQL!]! +} + +type StripeProductGQL { + id: String! + name: String! + description: String + active: Boolean! + prices: [StripePriceGQL!]! } type StripePriceGQL { @@ -967,16 +954,14 @@ type StripePriceGQL { active: Boolean! } -type StripeProductGQL { - id: String! - name: String! - description: String - active: Boolean! - prices: [StripePriceGQL!]! -} - -type StripeSubscriptionOptionsGQL { - products: [StripeProductGQL!]! +type UserSubscriptionStatusGQL { + hasActiveSubscription: Boolean! + subscriptionStatus: StripeSubscriptionStatusEnum + currentPeriodStart: DateTime + currentPeriodEnd: DateTime + validUntil: DateTime + stripePriceId: String + stripeSubscriptionId: String } enum StripeSubscriptionStatusEnum { @@ -990,22 +975,8 @@ enum StripeSubscriptionStatusEnum { PAUSED } -type SuccessfulAdd { - value: Boolean! -} - -union SuccessfulAddAddShotAnnotationErrors = - SuccessfulAdd - | AddShotAnnotationErrors - -type TableStateGQL { - identifierToPosition: [[Float!]!]! - homography: HomographyInfoGQL -} - -type TagClassGQL { - id: Int! - name: String! +type UserPlayTimeGQL { + totalSeconds: Float! } type TagGQL { @@ -1015,37 +986,150 @@ type TagGQL { retired: Boolean! } -type TargetMetricsGQL { - count: Int! - makePercentage: Float - averageDifficulty: Float - spinTypeCounts: SpinTypeCountsGQL - shotDirectionCounts: ShotDirectionCountsGQL -} - -input TimeDeltaGQL { - days: Int = 0 - weeks: Int = 0 - months: Int = 0 - years: Int = 0 -} - -input TimeInterval @oneOf { - timedelta: TimeDeltaGQL - aligned: AlignedIntervalEnum -} - -type TooManyInitUploadsErr { - linksRequested: Int! -} - -type TooManyProfileImageUploadsErr { - linksRequested: Int! -} - -input UpdateAnnotationInputGQL { +type TagClassGQL { + id: Int! name: String! - notes: String = null +} + +""" +The `JSON` scalar type represents JSON values as specified by [ECMA-404](https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf). +""" +scalar JSON + @specifiedBy( + url: "https://ecma-international.org/wp-content/uploads/ECMA-404_2nd_edition_december_2017.pdf" + ) + +type Mutation { + createBucketSet(params: CreateBucketSetInput!): BucketSetGQL! + createRuleSet(name: String!, description: String = null): RuleSet! + createChallenge( + name: String! + ruleSetId: ID! + minimumShots: Int! + startDate: DateTime! + endDate: DateTime! + description: String = null + requiredTableSize: Float = null + requiredPocketSize: Float = null + isPublic: Boolean! = false + maxAttempts: Int = null + ): Challenge! + inviteUsersToChallenge( + challengeId: ID! + userIds: [ID!]! + ): [ChallengeInvitation!]! + respondToChallengeInvitation( + invitationId: ID! + accept: Boolean! + ): ChallengeInvitation! + startChallenge(challengeId: ID!): ChallengeEntry! + recalculateChallengeEntry(entryId: ID!): ChallengeEntry! + submitChallengeEntry(entryId: ID!, videoId: ID!): ChallengeEntry! + dismissChallenge(challengeId: ID!): Boolean! + undismissChallenge(challengeId: ID!): Boolean! + setLoggerLevel(path: String!, level: String!): Boolean! + reactToVideo(videoId: Int!, reaction: ReactionEnum): Boolean! + commentOnVideo( + videoId: Int! + message: String! + parentCommentId: Int + ): Boolean! + editComment(videoId: Int!, commentId: Int!, newMessage: String!): Boolean! + deleteComment(videoId: Int!, commentId: Int!): Boolean! + blockContent(videoId: Int!): Boolean! + blockUser(userId: Int!): Boolean! + reportContent( + videoId: Int! + reason: ReportReasonEnum! + customReason: String = null + ): Boolean! + markNotificationAsRead(notificationId: Int!): Boolean! + markAllNotificationsAsRead: Boolean! + markNotificationsAsRead(notificationIds: [Int!]!): Boolean! + deleteNotification(notificationId: Int!): Boolean! + addAnnotationToShot( + shotId: Int! + annotationName: String! + notes: String = null + ): AddShotAnnotationReturn! + updateShotAnnotations( + shotId: Int! + annotations: [UpdateAnnotationInputGQL!]! + ): UpdateShotAnnotationReturn! + editShot( + shotId: Int! + fieldsToEdit: EditableShotFieldInputGQL! + ): EditShotReturn! + getProfileImageUploadLink( + fileExt: String = ".png" + ): GetProfileUploadLinkReturn! + editProfileImageUri(profileImageUri: String!): UserGQL! + editUser(input: EditUserInputGQL!): UserGQL! + followUser(followedUserId: Int!): UserGQL! + unfollowUser(followedUserId: Int!): UserGQL! + retireTags(tagIds: [Int!]!): Boolean! + ensureStripeCustomerExists: UserGQL! + deleteUser: Boolean! + createSubscription(priceId: String!): CreateSubscriptionResultGQL! + cancelSubscription: UserSubscriptionStatusGQL! + findPrerecordTableLayout(b64Image: String!, videoId: Int!): HomographyInfoGQL + createUploadStream( + videoMetadata: VideoMetadataInput! + ): CreateUploadStreamReturn! + getUploadLink(videoId: Int!, segmentIndex: Int!): GetUploadLinkReturn! + getHlsInitUploadLink(videoId: Int!): GetUploadLinkReturn! + setSegmentDuration( + videoId: Int! + segmentIndex: Int! + duration: Float! + ): Boolean! + editUploadStream(videoId: Int!, videoMetadata: VideoMetadataInput!): Boolean! + deleteVideo(videoId: Int!): Boolean! + deleteTags(videoId: Int!, tagsToDelete: [VideoTagInput!]!): Boolean! +} + +input CreateBucketSetInput { + keyName: String! + feature: String! + buckets: [BucketInputGQL!]! +} + +enum ReportReasonEnum { + SPAM + NUDITY + VIOLENCE + HATE + COPYRIGHT + OTHER +} + +type AddShotAnnotationReturn { + value: SuccessfulAddAddShotAnnotationErrors! +} + +union SuccessfulAddAddShotAnnotationErrors = + SuccessfulAdd + | AddShotAnnotationErrors + +type SuccessfulAdd { + value: Boolean! +} + +type AddShotAnnotationErrors { + error: DoesNotOwnShotErrOtherErrorNeedsNote! +} + +union DoesNotOwnShotErrOtherErrorNeedsNote = + DoesNotOwnShotErr + | OtherErrorNeedsNote + +type DoesNotOwnShotErr { + shotId: Int! + msg: String +} + +type OtherErrorNeedsNote { + msg: String } type UpdateShotAnnotationReturn { @@ -1053,146 +1137,67 @@ type UpdateShotAnnotationReturn { error: DoesNotOwnShotErr } -type UploadLink { - uploadUrl: String! - headers: [Header]! +input UpdateAnnotationInputGQL { + name: String! + notes: String = null +} + +type EditShotReturn { + shot: ShotGQL + error: DoesNotOwnShotErr +} + +input EditableShotFieldInputGQL { + intendedPocketType: PocketEnum + shotDirection: ShotDirectionEnum + spinType: SpinTypeEnum + targetPocketAngleDirection: ShotDirectionEnum + make: Boolean + backcut: Boolean + excludeFromStats: Boolean + notes: String +} + +type GetProfileUploadLinkReturn { + value: UploadLinkGetProfileUploadLinkErrors! } union UploadLinkGetProfileUploadLinkErrors = UploadLink | GetProfileUploadLinkErrors -union UploadLinkGetUploadLinkErrors = UploadLink | GetUploadLinkErrors +type UploadLink { + uploadUrl: String! + headers: [Header]! +} -type UploadSegmentGQL { - segmentIndex: Int! - uploaded: Boolean! - valid: Boolean! - endFrameIndex: Int - framesPerSecond: Float - durationInSeconds: Float +type Header { + key: String! + value: String! +} + +type GetProfileUploadLinkErrors { + error: TooManyProfileImageUploadsErr! +} + +type TooManyProfileImageUploadsErr { linksRequested: Int! } -type UploadStreamGQL { - id: ID! - linksRequested: Int! - uploadsCompleted: Int! - segmentProcessingCursor: Int! - lastIntendedSegmentBound: Int - isCompleted: Boolean! - initPlaylistUploadStatus: InitPlaylistUploadStatusEnum - lowestUnuploadedSegmentIndex: Int! - uploadCompletionCursor: Int! - errors: [StreamErrorGQL!]! - createdAt: DateTime! - updatedAt: DateTime! - segments: [UploadSegmentGQL!]! - clientUploadStatus: ClientUploadStatusEnum - resolution: VideoResolutionGQL! - streamSegmentType: StreamSegmentTypeEnum! +input EditUserInputGQL { + username: String = null + fargoRating: Int = null + videosPrivateByDefault: Boolean = null + agreesToMarketing: Boolean = null } -type UserGQL { - id: Int! - firebaseUid: String - username: String! - isAdmin: Boolean - fargoRating: Int - activeVideoId: Int - stripeCustomerId: String - profileImageUri: String - createdAt: DateTime - updatedAt: DateTime - videosPrivateByDefault: Boolean - agreesToMarketing: Boolean - following: [UserGQL!] - followers: [UserGQL!] - isFollowedByCurrentUser: Boolean +type CreateSubscriptionResultGQL { + checkoutUrl: String! + sessionId: String! } -type UserPlayTimeGQL { - totalSeconds: Float! -} - -type UserRelationship { - toUser: UserGQL! - toUserFollows: Boolean! - toUserIsFollowedBy: Boolean! -} - -type UserRelationshipsResult { - inquiringUser: UserGQL! - relationships: [UserRelationship!]! -} - -type UserShotCountEntry { - user: UserGQL! - value: Int! - total: Int! - proportionMade: Float! - videos: Int! -} - -type UserSubscriptionStatusGQL { - hasActiveSubscription: Boolean! - subscriptionStatus: StripeSubscriptionStatusEnum - currentPeriodStart: DateTime - currentPeriodEnd: DateTime - validUntil: DateTime - stripePriceId: String - stripeSubscriptionId: String -} - -input VideoFeedInputGQL @oneOf { - followedByUserId: Int - userId: Int - allUsers: Boolean - home: Boolean -} - -input VideoFilterInput { - isStreamCompleted: Boolean = null - requireCursorCompletion: Boolean! = true - createdAt: DateRangeFilter = null - excludeVideosWithNoShots: Boolean = null -} - -type VideoGQL { - id: Int! - owner: UserGQL - name: String - screenshotUri: String - totalShotsMade: Int! - totalShots: Int! - makePercentage: Float! - medianRun: Float - averageTimeBetweenShots: Float - averageDifficulty: Float - createdAt: DateTime - updatedAt: DateTime - shots: [ShotGQL!]! - startTime: DateTime - endTime: DateTime - elapsedTime: Float - framesPerSecond: Float! - tableSize: Float! - pocketSize: Float - private: Boolean! - stream: UploadStreamGQL - playlist: HLSPlaylistGQL - tags: [VideoTag!]! - currentHomography: HomographyInfoGQL - homographyHistory: [HomographyInfoGQL!]! - currentProcessing: VideoProcessingGQL - reactions: [ReactionGQL!]! - comments: [CommentGQL!]! -} - -type VideoHistoryGQL { - videos: [VideoGQL!]! - pageInfo: PageInfoGQL! - hasFollowing: Boolean! +type CreateUploadStreamReturn { + videoId: Int! } input VideoMetadataInput { @@ -1217,59 +1222,52 @@ input VideoMetadataInput { framesPerSecond: Float = null } -type VideoProcessingErrorGQL { - message: String! - startSegmentIndex: Int - endSegmentIndex: Int -} - -type VideoProcessingGQL { - id: Int! - errors: [VideoProcessingErrorGQL!]! - status: ProcessingStatusEnum! - statuses: [VideoProcessingStatusGQL!]! - framesProcessed: Int - currentSegment: Int - progressPercentage: Float -} - -type VideoProcessingStatusGQL { - status: ProcessingStatusEnum! - appVersion: String! - sequenceId: Int! - createdAt: DateTime - updatedAt: DateTime -} - input VideoResolution { width: Int! height: Int! } -type VideoResolutionGQL { - width: Int - height: Int +type GetUploadLinkReturn { + value: UploadLinkGetUploadLinkErrors! + stream: UploadStreamGQL } -type VideoTag { - tagClasses: [VideoTagClass!]! - name: String! +union UploadLinkGetUploadLinkErrors = UploadLink | GetUploadLinkErrors + +type GetUploadLinkErrors { + error: MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr! } -type VideoTagClass { - name: String! +union MustHaveSetForUploadLinkErrSegmentAlreadyUploadedErrProcessingFailedErrNoInitForChunkedUploadErrTooManyProfileImageUploadsErrInitUploadAlreadyCompletedErrTooManyInitUploadsErr = + MustHaveSetForUploadLinkErr + | SegmentAlreadyUploadedErr + | ProcessingFailedErr + | NoInitForChunkedUploadErr + | TooManyProfileImageUploadsErr + | InitUploadAlreadyCompletedErr + | TooManyInitUploadsErr + +type MustHaveSetForUploadLinkErr { + resolution: Boolean + framesPerSecond: Boolean } -input VideoTagClassInput { - name: String! +type SegmentAlreadyUploadedErr { + segmentId: Int! } -input VideoTagInput { - tagClasses: [VideoTagClassInput!]! = [] - name: String! +type ProcessingFailedErr { + processing: VideoProcessingGQL! } -enum WallTypeEnum { - LONG - SHORT +type NoInitForChunkedUploadErr { + segmentType: StreamSegmentTypeEnum! +} + +type InitUploadAlreadyCompletedErr { + segmentType: StreamSegmentTypeEnum! +} + +type TooManyInitUploadsErr { + linksRequested: Int! }