Compare commits

..

23 Commits

Author SHA1 Message Date
e86dd1900f Add suggestPositionShot schema types and operation
Mirrors the backend's position-play search: SuggestPositionShotInputGQL
(pot lock + target-area polygon), PositionSuggestionGQL /
PositionShotCandidateGQL / CueStrikeGQL, the Query field, and a
SuggestPositionShot operation with a shared candidate fragment. Rebased
onto master's gql; index.tsx regenerated.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-20 16:47:27 -07:00
6d9cb4126e Merge pull request 'Add per-video HomographyBackendGQL selection to VideoMetadataInput' (#298) from colonelpanic/homography-backend-selection into master 2026-07-18 02:12:18 +00:00
feeb5b7038 Add HomographyBackendGQL enum and VideoMetadataInput.homographyBackend
All checks were successful
Tests / Tests (pull_request) Successful in 11s
Regenerated from backend Python: adds the HomographyBackendGQL enum
(CLASSIC/TABLENET) and the optional homographyBackend field on
VideoMetadataInput, for per-video homography backend selection.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-17 18:26:53 -07:00
3340314166 Merge pull request 'Add per-session Coach GraphQL contract' (#297) from loewy/session-coach-v1 into master
Reviewed-on: #297
2026-07-17 18:33:58 +00:00
6b8fdd4262 Add per-session Coach GraphQL contract
All checks were successful
Tests / Tests (pull_request) Successful in 10s
2026-07-16 16:45:55 -07:00
bfaed33c89 Merge pull request 'feed: select uploadCompletionCursor on VideoCardFields stream' (#296) from dean/feed-upload-completion-cursor into master
Reviewed-on: #296
2026-07-14 18:24:54 +00:00
Dean Wenstrand
1ce3aaed1b feed: select uploadCompletionCursor on VideoCardFields stream
All checks were successful
Tests / Tests (pull_request) Successful in 24s
Lets the client distinguish a finalized-but-not-fully-uploaded stream
(is_completed set, but received cursor short of last_intended_segment_bound)
from one that is genuinely processing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-14 11:15:41 -07:00
1bd03f2bbe Merge pull request 'dean/unify-shotlab-cohorts' (#295) from dean/unify-shotlab-cohorts into master
Reviewed-on: #295
2026-07-13 01:08:48 +00:00
Dean Wenstrand
4a1c41aae1 Regenerate schema and hooks from backend master
All checks were successful
Tests / Tests (pull_request) Successful in 12s
Union of the cohort funnel, Shot Lab picker queries, and transient
homography IDs — converges the three divergent submodule pointers
(gql master, railbird master, railbird-mobile master).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 18:03:33 -07:00
Dean Wenstrand
4122284bbd Merge Shot Lab queries with cohort funnel 2026-07-12 17:59:33 -07:00
b30dbd01f5 Fetch shot paths and features for the Shot Lab picker
All checks were successful
Tests / Tests (pull_request) Successful in 11s
The recorded-shot picker now renders per-shot table diagrams, so
GetRecordedStreamShots needs serializedShotPaths plus the pocketing and
cue-object features that PlaneShotDiagram consumes.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 11:13:17 -07:00
6d13dc3eb1 Merge remote-tracking branch 'origin/master' into colonelpanic/allow-transient-homography-ids 2026-07-12 00:19:46 -07:00
e3524cab97 Merge pull request 'Add weekly cohort funnel to getUsageStats' (#293) from dean/usage-stats-cohorts into master
Reviewed-on: #293
2026-07-12 04:07:43 +00:00
303261f2d7 Add recorded Shot Lab queries 2026-07-11 20:56:47 -07:00
20a70fad2a Allow transient homography IDs 2026-07-11 20:55:53 -07:00
Dean Wenstrand
35c7c23ba9 Add disjoint activated segment to cohorts for stacking
All checks were successful
Tests / Tests (pull_request) Successful in 10s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:45:01 -07:00
Dean Wenstrand
40c4b82a59 Add weekly cohort funnel to getUsageStats
All checks were successful
Tests / Tests (pull_request) Successful in 13s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 17:40:10 -07:00
9ebe2e61df Merge pull request 'dean/usage-stats' (#292) from dean/usage-stats into master
Reviewed-on: #292
2026-07-11 19:26:13 +00:00
Dean Wenstrand
6f356f9535 Add freemium epoch + era conversion to funnel
All checks were successful
Tests / Tests (pull_request) Successful in 12s
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 11:38:20 -07:00
Dean Wenstrand
5c0ff8c31b Add freemium funnel to getUsageStats
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 10:48:25 -07:00
Dean Wenstrand
582c20170d Add getUsageStats admin query + operation (schema regen on shot-lab tip)
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-11 10:36:47 -07:00
dc02fd8387 Merge pull request 'Select detected ball colors for Shot Lab' (#291) from colonelpanic/shot-lab-image-colors into master
Reviewed-on: #291
2026-07-10 17:20:37 +00:00
ef4782fc14 Select detected ball colors for Shot Lab
All checks were successful
Tests / Tests (pull_request) Successful in 33s
2026-07-10 00:12:06 -07:00
7 changed files with 962 additions and 18 deletions

View File

@@ -243,6 +243,15 @@ export type ClusterAssignmentInput = {
userId?: InputMaybe<Scalars['Int']['input']>; userId?: InputMaybe<Scalars['Int']['input']>;
}; };
export type CohortStatsGql = {
__typename?: 'CohortStatsGQL';
activated7d: Scalars['Int']['output'];
activatedNotPaid7d: Scalars['Int']['output'];
paid7d: Scalars['Int']['output'];
signups: Scalars['Int']['output'];
weekStart: Scalars['Date']['output'];
};
export type CommentGql = { export type CommentGql = {
__typename?: 'CommentGQL'; __typename?: 'CommentGQL';
id: Scalars['Int']['output']; id: Scalars['Int']['output'];
@@ -312,6 +321,15 @@ export type CueObjectFeaturesGql = {
spinType?: Maybe<SpinTypeEnum>; spinType?: Maybe<SpinTypeEnum>;
}; };
export type CueStrikeGql = {
__typename?: 'CueStrikeGQL';
a: Scalars['Float']['output'];
b: Scalars['Float']['output'];
phi: Scalars['Float']['output'];
theta: Scalars['Float']['output'];
v0: Scalars['Float']['output'];
};
export type CueStrikeInputGql = { export type CueStrikeInputGql = {
a?: Scalars['Float']['input']; a?: Scalars['Float']['input'];
b?: Scalars['Float']['input']; b?: Scalars['Float']['input'];
@@ -474,6 +492,20 @@ export type FloatRangeFilter = {
lessThanInclusive?: Scalars['Boolean']['input']; lessThanInclusive?: Scalars['Boolean']['input'];
}; };
export type FunnelStatsGql = {
__typename?: 'FunnelStatsGQL';
activationActivated: Scalars['Int']['output'];
activationCohort: Scalars['Int']['output'];
eraPaying: Scalars['Int']['output'];
eraSignups: Scalars['Int']['output'];
freemiumEpoch: Scalars['Date']['output'];
newPaid7d: Scalars['Int']['output'];
newPaid30d: Scalars['Int']['output'];
payingUsers: Scalars['Int']['output'];
retentionPrevActive: Scalars['Int']['output'];
retentionReturned: Scalars['Int']['output'];
};
export type GameTypeTagMetric = { export type GameTypeTagMetric = {
__typename?: 'GameTypeTagMetric'; __typename?: 'GameTypeTagMetric';
madeShots: Scalars['Int']['output']; madeShots: Scalars['Int']['output'];
@@ -556,12 +588,17 @@ export type Header = {
value: Scalars['String']['output']; value: Scalars['String']['output'];
}; };
export enum HomographyBackendGql {
Classic = 'CLASSIC',
Tablenet = 'TABLENET'
}
export type HomographyInfoGql = { export type HomographyInfoGql = {
__typename?: 'HomographyInfoGQL'; __typename?: 'HomographyInfoGQL';
crop: BoundingBoxGql; crop: BoundingBoxGql;
destPoints: PocketPointsGql; destPoints: PocketPointsGql;
frameIndex: Scalars['Int']['output']; frameIndex: Scalars['Int']['output'];
id: Scalars['Int']['output']; id?: Maybe<Scalars['Int']['output']>;
pockets: Array<BoundingBoxGql>; pockets: Array<BoundingBoxGql>;
sourcePoints: PocketPointsGql; sourcePoints: PocketPointsGql;
}; };
@@ -1215,6 +1252,27 @@ export type PoolHallCameraStreamCredentials = {
streamKey: Scalars['String']['output']; streamKey: Scalars['String']['output'];
}; };
export type PositionShotCandidateGql = {
__typename?: 'PositionShotCandidateGQL';
cueFinalPosition: Array<Scalars['Float']['output']>;
distanceToTargetArea: Scalars['Float']['output'];
inTargetArea: Scalars['Boolean']['output'];
potted: Scalars['Boolean']['output'];
projection?: Maybe<ShotProjectionGql>;
robustness: Scalars['Int']['output'];
scratched: Scalars['Boolean']['output'];
strike: CueStrikeGql;
};
export type PositionSuggestionGql = {
__typename?: 'PositionSuggestionGQL';
achievable: Scalars['Boolean']['output'];
alternates: Array<PositionShotCandidateGql>;
best?: Maybe<PositionShotCandidateGql>;
evaluatedCount: Scalars['Int']['output'];
successfulCount: Scalars['Int']['output'];
};
export type PotAimGql = { export type PotAimGql = {
__typename?: 'PotAimGQL'; __typename?: 'PotAimGQL';
converged: Scalars['Boolean']['output']; converged: Scalars['Boolean']['output'];
@@ -1279,7 +1337,9 @@ export type Query = {
getQuotaStatus: QuotaStatusGql; getQuotaStatus: QuotaStatusGql;
getResolvedTier: ResolvedTierGql; getResolvedTier: ResolvedTierGql;
getRuns: GetRunsResult; getRuns: GetRunsResult;
getSessionCoach: SessionCoachGql;
getShotAnnotationTypes: Array<ShotAnnotationTypeGql>; getShotAnnotationTypes: Array<ShotAnnotationTypeGql>;
getShotTableState: ShotTableStateGql;
getShots: Array<ShotGql>; getShots: Array<ShotGql>;
getShotsByIds: Array<ShotGql>; getShotsByIds: Array<ShotGql>;
getShotsWithMetadata: GetShotsResult; getShotsWithMetadata: GetShotsResult;
@@ -1306,6 +1366,7 @@ export type Query = {
poolHalls: Array<PoolHall>; poolHalls: Array<PoolHall>;
ruleSets: Array<RuleSet>; ruleSets: Array<RuleSet>;
simulateShot: ShotProjectionGql; simulateShot: ShotProjectionGql;
suggestPositionShot: PositionSuggestionGql;
unreadNotificationCount: Scalars['Int']['output']; unreadNotificationCount: Scalars['Int']['output'];
videoExportJob?: Maybe<VideoExportJobGql>; videoExportJob?: Maybe<VideoExportJobGql>;
videoPlayerClusters: Array<PlayerClusterGql>; videoPlayerClusters: Array<PlayerClusterGql>;
@@ -1442,11 +1503,21 @@ export type QueryGetRunsArgs = {
}; };
export type QueryGetSessionCoachArgs = {
videoId: Scalars['Int']['input'];
};
export type QueryGetShotAnnotationTypesArgs = { export type QueryGetShotAnnotationTypesArgs = {
errorTypes?: InputMaybe<Scalars['Boolean']['input']>; errorTypes?: InputMaybe<Scalars['Boolean']['input']>;
}; };
export type QueryGetShotTableStateArgs = {
shotId: Scalars['Int']['input'];
};
export type QueryGetShotsArgs = { export type QueryGetShotsArgs = {
countRespectsLimit?: Scalars['Boolean']['input']; countRespectsLimit?: Scalars['Boolean']['input'];
filterInput: FilterInput; filterInput: FilterInput;
@@ -1566,6 +1637,11 @@ export type QuerySimulateShotArgs = {
}; };
export type QuerySuggestPositionShotArgs = {
suggestionInput: SuggestPositionShotInputGql;
};
export type QueryVideoExportJobArgs = { export type QueryVideoExportJobArgs = {
jobId: Scalars['Int']['input']; jobId: Scalars['Int']['input'];
}; };
@@ -1775,6 +1851,84 @@ export type SerializedShotPathsGql = {
b64EncodedBuffer?: Maybe<Scalars['String']['output']>; b64EncodedBuffer?: Maybe<Scalars['String']['output']>;
}; };
export enum SessionCoachCandidateFamilyEnum {
Aiming = 'AIMING',
BackCut = 'BACK_CUT',
CueToObjectDistance = 'CUE_TO_OBJECT_DISTANCE',
CutAngle = 'CUT_ANGLE',
ObjectToPocketDistance = 'OBJECT_TO_POCKET_DISTANCE',
Spin = 'SPIN'
}
export type SessionCoachCandidateGql = {
__typename?: 'SessionCoachCandidateGQL';
action: Scalars['String']['output'];
body: Scalars['String']['output'];
drillId?: Maybe<Scalars['String']['output']>;
evidence: SessionCoachEvidenceGql;
family: SessionCoachCandidateFamilyEnum;
id: Scalars['ID']['output'];
kind: SessionCoachCandidateKindEnum;
limitations: Array<Scalars['String']['output']>;
rank: Scalars['Int']['output'];
supportingShotIds: Array<Scalars['Int']['output']>;
title: Scalars['String']['output'];
};
export enum SessionCoachCandidateKindEnum {
DirectionalMiss = 'DIRECTIONAL_MISS',
OutcomePattern = 'OUTCOME_PATTERN',
UsagePattern = 'USAGE_PATTERN'
}
export type SessionCoachEvidenceGql = {
__typename?: 'SessionCoachEvidenceGQL';
attemptCount: Scalars['Int']['output'];
bucketKey: Scalars['String']['output'];
bucketLabel: Scalars['String']['output'];
comparisonAttemptCount: Scalars['Int']['output'];
comparisonMadeCount: Scalars['Int']['output'];
comparisonMakePercentage?: Maybe<Scalars['Float']['output']>;
madeCount: Scalars['Int']['output'];
makePercentage: Scalars['Float']['output'];
missedCount: Scalars['Int']['output'];
patternShotCount: Scalars['Int']['output'];
rankReason: Scalars['String']['output'];
score: Scalars['Float']['output'];
};
export type SessionCoachGql = {
__typename?: 'SessionCoachGQL';
analysisVersion: Scalars['String']['output'];
analyzedShotCount: Scalars['Int']['output'];
candidates: Array<SessionCoachCandidateGql>;
generatedAt: Scalars['DateTime']['output'];
ineligibilityReason?: Maybe<SessionCoachIneligibilityReasonEnum>;
madeCount: Scalars['Int']['output'];
makePercentage?: Maybe<Scalars['Float']['output']>;
missedCount: Scalars['Int']['output'];
primaryCandidate?: Maybe<SessionCoachCandidateGql>;
processingId?: Maybe<Scalars['Int']['output']>;
processingStatus?: Maybe<Scalars['String']['output']>;
shotCount: Scalars['Int']['output'];
state: SessionCoachStateEnum;
summary?: Maybe<Scalars['String']['output']>;
unknownOutcomeCount: Scalars['Int']['output'];
videoId: Scalars['Int']['output'];
};
export enum SessionCoachIneligibilityReasonEnum {
Multiplayer = 'MULTIPLAYER'
}
export enum SessionCoachStateEnum {
Failed = 'FAILED',
Ineligible = 'INELIGIBLE',
NoTrackedShots = 'NO_TRACKED_SHOTS',
Processing = 'PROCESSING',
Ready = 'READY'
}
export type ShotAnnotationGql = { export type ShotAnnotationGql = {
__typename?: 'ShotAnnotationGQL'; __typename?: 'ShotAnnotationGQL';
createdAt?: Maybe<Scalars['DateTime']['output']>; createdAt?: Maybe<Scalars['DateTime']['output']>;
@@ -1847,6 +2001,14 @@ export type ShotProjectionGql = {
trajectories: Array<BallTrajectoryGql>; trajectories: Array<BallTrajectoryGql>;
}; };
export type ShotTableStateGql = {
__typename?: 'ShotTableStateGQL';
frameIndex: Scalars['Int']['output'];
shotId: Scalars['Int']['output'];
tableState: TableStateGql;
videoId: Scalars['Int']['output'];
};
export type ShotsOrderingComponent = export type ShotsOrderingComponent =
{ difficulty: FloatOrdering; marginOfError?: never; runLength?: never; startFrame?: never; videoCreation?: never; videoId?: never; } { difficulty: FloatOrdering; marginOfError?: never; runLength?: never; startFrame?: never; videoCreation?: never; videoId?: never; }
| { difficulty?: never; marginOfError: FloatOrdering; runLength?: never; startFrame?: never; videoCreation?: never; videoId?: never; } | { difficulty?: never; marginOfError: FloatOrdering; runLength?: never; startFrame?: never; videoCreation?: never; videoId?: never; }
@@ -2011,6 +2173,17 @@ export type SuccessfulAdd = {
export type SuccessfulAddAddShotAnnotationErrors = AddShotAnnotationErrors | SuccessfulAdd; export type SuccessfulAddAddShotAnnotationErrors = AddShotAnnotationErrors | SuccessfulAdd;
export type SuggestPositionShotInputGql = {
b64Image?: InputMaybe<Scalars['String']['input']>;
balls?: InputMaybe<Array<SimulationBallStateInputGql>>;
cueBallId: Scalars['Int']['input'];
pocket: PocketIdentifier;
tableSize?: InputMaybe<Scalars['Float']['input']>;
targetArea: Array<Array<Scalars['Float']['input']>>;
targetBallId: Scalars['Int']['input'];
useHomography?: InputMaybe<HomographyInputGql>;
};
export type SyncAppleSubscriptionInputGql = { export type SyncAppleSubscriptionInputGql = {
signedRenewalInfo?: InputMaybe<Scalars['String']['input']>; signedRenewalInfo?: InputMaybe<Scalars['String']['input']>;
signedTransactionInfo: Scalars['String']['input']; signedTransactionInfo: Scalars['String']['input'];
@@ -2177,7 +2350,9 @@ export type UsageStatsDailyGql = {
export type UsageStatsGql = { export type UsageStatsGql = {
__typename?: 'UsageStatsGQL'; __typename?: 'UsageStatsGQL';
cohorts: Array<CohortStatsGql>;
daily: Array<UsageStatsDailyGql>; daily: Array<UsageStatsDailyGql>;
funnel: FunnelStatsGql;
processingLast24h: Array<ProcessingStatusCountGql>; processingLast24h: Array<ProcessingStatusCountGql>;
totalRuns: Scalars['Int']['output']; totalRuns: Scalars['Int']['output'];
totalShots: Scalars['Int']['output']; totalShots: Scalars['Int']['output'];
@@ -2348,6 +2523,7 @@ export type VideoMetadataInput = {
framesPerSecond?: InputMaybe<Scalars['Float']['input']>; framesPerSecond?: InputMaybe<Scalars['Float']['input']>;
/** @deprecated `game_type` is deprecated. Use `tags` instead. */ /** @deprecated `game_type` is deprecated. Use `tags` instead. */
gameType?: InputMaybe<Scalars['String']['input']>; gameType?: InputMaybe<Scalars['String']['input']>;
homographyBackend?: InputMaybe<HomographyBackendGql>;
lastIntendedSegmentBound?: InputMaybe<Scalars['Int']['input']>; lastIntendedSegmentBound?: InputMaybe<Scalars['Int']['input']>;
pocketSize?: InputMaybe<Scalars['Float']['input']>; pocketSize?: InputMaybe<Scalars['Float']['input']>;
private?: InputMaybe<Scalars['Boolean']['input']>; private?: InputMaybe<Scalars['Boolean']['input']>;
@@ -2616,11 +2792,11 @@ export type GetFeedQueryVariables = Exact<{
}>; }>;
export type GetFeedQuery = { __typename?: 'Query', getUserVideos: { __typename?: 'VideoHistoryGQL', videos: Array<{ __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> }>, pageInfo: { __typename?: 'PageInfoGQL', hasNextPage: boolean, endCursor?: string | null } } }; export type GetFeedQuery = { __typename?: 'Query', getUserVideos: { __typename?: 'VideoHistoryGQL', videos: Array<{ __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, uploadCompletionCursor: number, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> }>, pageInfo: { __typename?: 'PageInfoGQL', hasNextPage: boolean, endCursor?: string | null } } };
export type UserSocialsFieldsFragment = { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }; export type UserSocialsFieldsFragment = { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null };
export type VideoCardFieldsFragment = { __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> }; export type VideoCardFieldsFragment = { __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, uploadCompletionCursor: number, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> };
export type GetVideoFeedSessionCountQueryVariables = Exact<{ export type GetVideoFeedSessionCountQueryVariables = Exact<{
limit?: Scalars['Int']['input']; limit?: Scalars['Int']['input'];
@@ -2651,7 +2827,7 @@ export type GetVideoFeedQueryVariables = Exact<{
}>; }>;
export type GetVideoFeedQuery = { __typename?: 'Query', getFeedVideos: { __typename?: 'VideoHistoryGQL', hasFollowing: boolean, followingCount: number, videos: Array<{ __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> }>, pageInfo: { __typename?: 'PageInfoGQL', hasNextPage: boolean, endCursor?: string | null } } }; export type GetVideoFeedQuery = { __typename?: 'Query', getFeedVideos: { __typename?: 'VideoHistoryGQL', hasFollowing: boolean, followingCount: number, videos: Array<{ __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, uploadCompletionCursor: number, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> }>, pageInfo: { __typename?: 'PageInfoGQL', hasNextPage: boolean, endCursor?: string | null } } };
export type GetMakesLeaderboardQueryVariables = Exact<{ export type GetMakesLeaderboardQueryVariables = Exact<{
interval?: InputMaybe<TimeInterval>; interval?: InputMaybe<TimeInterval>;
@@ -2945,6 +3121,21 @@ export type ReactToVideoMutationVariables = Exact<{
export type ReactToVideoMutation = { __typename?: 'Mutation', reactToVideo: boolean }; export type ReactToVideoMutation = { __typename?: 'Mutation', reactToVideo: boolean };
export type GetRecordedStreamsQueryVariables = Exact<{
limit?: Scalars['Int']['input'];
}>;
export type GetRecordedStreamsQuery = { __typename?: 'Query', getFeedVideos: { __typename?: 'VideoHistoryGQL', videos: Array<{ __typename?: 'VideoGQL', id: number, name?: string | null, createdAt?: any | null, screenshotUri?: string | null, framesPerSecond: number, totalShots: number, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null }> } };
export type GetRecordedStreamShotsQueryVariables = Exact<{
videoId: Scalars['Int']['input'];
limit?: Scalars['Int']['input'];
}>;
export type GetRecordedStreamShotsQuery = { __typename?: 'Query', getOrderedShots: { __typename?: 'GetShotsResult', shots: Array<{ __typename?: 'ShotGQL', id: number, videoId: number, startFrame: number, endFrame: number, serializedShotPaths?: { __typename?: 'SerializedShotPathsGQL', b64EncodedBuffer?: string | null } | null, cueObjectFeatures?: { __typename?: 'CueObjectFeaturesGQL', cueObjectDistance?: number | null, cueObjectAngle?: number | null, cueBallSpeed?: number | null, shotDirection?: ShotDirectionEnum | null, spinType?: SpinTypeEnum | null } | null, pocketingIntentionFeatures?: { __typename?: 'PocketingIntentionFeaturesGQL', make?: boolean | null, targetPocketDistance?: number | null, targetPocketAngle?: number | null, targetPocketAngleDirection?: ShotDirectionEnum | null, marginOfErrorInDegrees?: number | null, intendedPocketType?: PocketEnum | null, difficulty?: number | null } | null, pocketingIntentionInfo?: { __typename?: 'PocketingIntentionInfoGQL', ballId: number, pocketId: PocketIdentifier, pathMetadataIndex: number } | null }> } };
export type GetRunsForHighlightsQueryVariables = Exact<{ export type GetRunsForHighlightsQueryVariables = Exact<{
filterInput: RunFilterInput; filterInput: RunFilterInput;
runIds?: InputMaybe<Array<Scalars['Int']['input']> | Scalars['Int']['input']>; runIds?: InputMaybe<Array<Scalars['Int']['input']> | Scalars['Int']['input']>;
@@ -2967,6 +3158,15 @@ export type GetRunsWithTimestampsQueryVariables = Exact<{
export type GetRunsWithTimestampsQuery = { __typename?: 'Query', getRuns: { __typename?: 'GetRunsResult', count?: number | null, runIds: Array<number>, runs: Array<{ __typename?: 'RunGQL', id: number, runLength: number, userId: number, videoId: number, shots: Array<{ __typename?: 'ShotGQL', videoId: number, id: number, createdAt?: any | null, pocketingIntentionFeatures?: { __typename?: 'PocketingIntentionFeaturesGQL', make?: boolean | null, targetPocketDistance?: number | null, targetPocketAngle?: number | null, targetPocketAngleDirection?: ShotDirectionEnum | null, marginOfErrorInDegrees?: number | null, intendedPocketType?: PocketEnum | null, difficulty?: number | null } | null }> }> } }; export type GetRunsWithTimestampsQuery = { __typename?: 'Query', getRuns: { __typename?: 'GetRunsResult', count?: number | null, runIds: Array<number>, runs: Array<{ __typename?: 'RunGQL', id: number, runLength: number, userId: number, videoId: number, shots: Array<{ __typename?: 'ShotGQL', videoId: number, id: number, createdAt?: any | null, pocketingIntentionFeatures?: { __typename?: 'PocketingIntentionFeaturesGQL', make?: boolean | null, targetPocketDistance?: number | null, targetPocketAngle?: number | null, targetPocketAngleDirection?: ShotDirectionEnum | null, marginOfErrorInDegrees?: number | null, intendedPocketType?: PocketEnum | null, difficulty?: number | null } | null }> }> } };
export type GetSessionCoachQueryVariables = Exact<{
videoId: Scalars['Int']['input'];
}>;
export type GetSessionCoachQuery = { __typename?: 'Query', getSessionCoach: { __typename?: 'SessionCoachGQL', videoId: number, processingId?: number | null, analysisVersion: string, state: SessionCoachStateEnum, generatedAt: any, processingStatus?: string | null, ineligibilityReason?: SessionCoachIneligibilityReasonEnum | null, summary?: string | null, shotCount: number, madeCount: number, missedCount: number, unknownOutcomeCount: number, analyzedShotCount: number, makePercentage?: number | null, primaryCandidate?: { __typename?: 'SessionCoachCandidateGQL', id: string, rank: number, family: SessionCoachCandidateFamilyEnum, kind: SessionCoachCandidateKindEnum, title: string, body: string, action: string, supportingShotIds: Array<number>, drillId?: string | null, limitations: Array<string>, evidence: { __typename?: 'SessionCoachEvidenceGQL', bucketKey: string, bucketLabel: string, attemptCount: number, madeCount: number, missedCount: number, makePercentage: number, comparisonAttemptCount: number, comparisonMadeCount: number, comparisonMakePercentage?: number | null, patternShotCount: number, score: number, rankReason: string } } | null, candidates: Array<{ __typename?: 'SessionCoachCandidateGQL', id: string, rank: number, family: SessionCoachCandidateFamilyEnum, kind: SessionCoachCandidateKindEnum, title: string, body: string, action: string, supportingShotIds: Array<number>, drillId?: string | null, limitations: Array<string>, evidence: { __typename?: 'SessionCoachEvidenceGQL', bucketKey: string, bucketLabel: string, attemptCount: number, madeCount: number, missedCount: number, makePercentage: number, comparisonAttemptCount: number, comparisonMadeCount: number, comparisonMakePercentage?: number | null, patternShotCount: number, score: number, rankReason: string } }> } };
export type SessionCoachCandidateFieldsFragment = { __typename?: 'SessionCoachCandidateGQL', id: string, rank: number, family: SessionCoachCandidateFamilyEnum, kind: SessionCoachCandidateKindEnum, title: string, body: string, action: string, supportingShotIds: Array<number>, drillId?: string | null, limitations: Array<string>, evidence: { __typename?: 'SessionCoachEvidenceGQL', bucketKey: string, bucketLabel: string, attemptCount: number, madeCount: number, missedCount: number, makePercentage: number, comparisonAttemptCount: number, comparisonMadeCount: number, comparisonMakePercentage?: number | null, patternShotCount: number, score: number, rankReason: string } };
export type PlayerSummaryFieldsFragment = { __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }; export type PlayerSummaryFieldsFragment = { __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } };
export type PlayerClusterShotFieldsFragment = { __typename?: 'PlayerClusterShotGQL', shotId: number, bboxX1: number, bboxY1: number, bboxX2: number, bboxY2: number, confidence: number, isConfirmed: boolean, cropUrl?: string | null, fullFrameUrl?: string | null }; export type PlayerClusterShotFieldsFragment = { __typename?: 'PlayerClusterShotGQL', shotId: number, bboxX1: number, bboxY1: number, bboxX2: number, bboxY2: number, confidence: number, isConfirmed: boolean, cropUrl?: string | null, fullFrameUrl?: string | null };
@@ -2994,14 +3194,21 @@ export type GetTableStateQueryVariables = Exact<{
}>; }>;
export type GetTableStateQuery = { __typename?: 'Query', getTableState: { __typename?: 'TableStateGQL', identifierToPosition: Array<Array<number>> } }; export type GetTableStateQuery = { __typename?: 'Query', getTableState: { __typename?: 'TableStateGQL', identifierToPosition: Array<Array<number>>, identifierToColor: Array<{ __typename?: 'RGBColorGQL', hex: string } | null> } };
export type GetLiveTableStateQueryVariables = Exact<{ export type GetLiveTableStateQueryVariables = Exact<{
videoId: Scalars['Int']['input']; videoId: Scalars['Int']['input'];
}>; }>;
export type GetLiveTableStateQuery = { __typename?: 'Query', getLiveTableState: { __typename?: 'LiveTableStateGQL', videoId: number, frameIndex: number, tableState: { __typename?: 'TableStateGQL', identifierToPosition: Array<Array<number>>, homography?: { __typename?: 'HomographyInfoGQL', id: number, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } } | null } } }; export type GetLiveTableStateQuery = { __typename?: 'Query', getLiveTableState: { __typename?: 'LiveTableStateGQL', videoId: number, frameIndex: number, tableState: { __typename?: 'TableStateGQL', identifierToPosition: Array<Array<number>>, identifierToColor: Array<{ __typename?: 'RGBColorGQL', hex: string } | null> } } };
export type GetShotTableStateQueryVariables = Exact<{
shotId: Scalars['Int']['input'];
}>;
export type GetShotTableStateQuery = { __typename?: 'Query', getShotTableState: { __typename?: 'ShotTableStateGQL', shotId: number, videoId: number, frameIndex: number, tableState: { __typename?: 'TableStateGQL', identifierToPosition: Array<Array<number>>, identifierToColor: Array<{ __typename?: 'RGBColorGQL', hex: string } | null> } } };
export type SimulateShotQueryVariables = Exact<{ export type SimulateShotQueryVariables = Exact<{
simulationInput: SimulateShotInputGql; simulationInput: SimulateShotInputGql;
@@ -3019,6 +3226,15 @@ export type ComputePotAimQueryVariables = Exact<{
export type ComputePotAimQuery = { __typename?: 'Query', computePotAim: { __typename?: 'PotAimGQL', phi: number, geometricPhi: number, cutAngle: number, requiredPrecision: number, feasible: boolean, potted: boolean, converged: boolean, occludingBallIds: Array<number> } }; export type ComputePotAimQuery = { __typename?: 'Query', computePotAim: { __typename?: 'PotAimGQL', phi: number, geometricPhi: number, cutAngle: number, requiredPrecision: number, feasible: boolean, potted: boolean, converged: boolean, occludingBallIds: Array<number> } };
export type PositionShotCandidateFragment = { __typename?: 'PositionShotCandidateGQL', cueFinalPosition: Array<number>, inTargetArea: boolean, distanceToTargetArea: number, robustness: number, potted: boolean, scratched: boolean, strike: { __typename?: 'CueStrikeGQL', v0: number, phi: number, theta: number, a: number, b: number }, projection?: { __typename?: 'ShotProjectionGQL', pottedBallIds: Array<number>, trajectories: Array<{ __typename?: 'BallTrajectoryGQL', ballId: number, points: Array<{ __typename?: 'TrajectoryPointGQL', time: number, position: Array<number> }> }>, events: Array<{ __typename?: 'SimulationEventGQL', eventType: SimulationEventType, time: number, ballIds: Array<number>, position?: Array<number> | null }>, finalState: Array<{ __typename?: 'SimulationBallStateGQL', ballId: number, position: Array<number> }> } | null };
export type SuggestPositionShotQueryVariables = Exact<{
suggestionInput: SuggestPositionShotInputGql;
}>;
export type SuggestPositionShotQuery = { __typename?: 'Query', suggestPositionShot: { __typename?: 'PositionSuggestionGQL', achievable: boolean, evaluatedCount: number, successfulCount: number, best?: { __typename?: 'PositionShotCandidateGQL', cueFinalPosition: Array<number>, inTargetArea: boolean, distanceToTargetArea: number, robustness: number, potted: boolean, scratched: boolean, strike: { __typename?: 'CueStrikeGQL', v0: number, phi: number, theta: number, a: number, b: number }, projection?: { __typename?: 'ShotProjectionGQL', pottedBallIds: Array<number>, trajectories: Array<{ __typename?: 'BallTrajectoryGQL', ballId: number, points: Array<{ __typename?: 'TrajectoryPointGQL', time: number, position: Array<number> }> }>, events: Array<{ __typename?: 'SimulationEventGQL', eventType: SimulationEventType, time: number, ballIds: Array<number>, position?: Array<number> | null }>, finalState: Array<{ __typename?: 'SimulationBallStateGQL', ballId: number, position: Array<number> }> } | null } | null, alternates: Array<{ __typename?: 'PositionShotCandidateGQL', cueFinalPosition: Array<number>, inTargetArea: boolean, distanceToTargetArea: number, robustness: number, potted: boolean, scratched: boolean, strike: { __typename?: 'CueStrikeGQL', v0: number, phi: number, theta: number, a: number, b: number }, projection?: { __typename?: 'ShotProjectionGQL', pottedBallIds: Array<number>, trajectories: Array<{ __typename?: 'BallTrajectoryGQL', ballId: number, points: Array<{ __typename?: 'TrajectoryPointGQL', time: number, position: Array<number> }> }>, events: Array<{ __typename?: 'SimulationEventGQL', eventType: SimulationEventType, time: number, ballIds: Array<number>, position?: Array<number> | null }>, finalState: Array<{ __typename?: 'SimulationBallStateGQL', ballId: number, position: Array<number> }> } | null }> } };
export type GetSerializedShotPathsQueryVariables = Exact<{ export type GetSerializedShotPathsQueryVariables = Exact<{
filterInput: FilterInput; filterInput: FilterInput;
}>; }>;
@@ -3127,7 +3343,7 @@ export type GetUsageStatsQueryVariables = Exact<{
}>; }>;
export type GetUsageStatsQuery = { __typename?: 'Query', getUsageStats: { __typename?: 'UsageStatsGQL', totalUsers: number, totalVideos: number, totalShots: number, totalRuns: number, windows: Array<{ __typename?: 'UsageStatsWindowGQL', label: string, newUsers: number, activeUsers: number, sessions: number, shots: number }>, daily: Array<{ __typename?: 'UsageStatsDailyGQL', day: any, newUsers: number, activeUsers: number, sessions: number, shots: number }>, processingLast24h: Array<{ __typename?: 'ProcessingStatusCountGQL', status: string, count: number }> } }; export type GetUsageStatsQuery = { __typename?: 'Query', getUsageStats: { __typename?: 'UsageStatsGQL', totalUsers: number, totalVideos: number, totalShots: number, totalRuns: number, funnel: { __typename?: 'FunnelStatsGQL', freemiumEpoch: any, eraSignups: number, eraPaying: number, activationCohort: number, activationActivated: number, payingUsers: number, newPaid7d: number, newPaid30d: number, retentionPrevActive: number, retentionReturned: number }, cohorts: Array<{ __typename?: 'CohortStatsGQL', weekStart: any, signups: number, activated7d: number, paid7d: number, activatedNotPaid7d: number }>, windows: Array<{ __typename?: 'UsageStatsWindowGQL', label: string, newUsers: number, activeUsers: number, sessions: number, shots: number }>, daily: Array<{ __typename?: 'UsageStatsDailyGQL', day: any, newUsers: number, activeUsers: number, sessions: number, shots: number }>, processingLast24h: Array<{ __typename?: 'ProcessingStatusCountGQL', status: string, count: number }> } };
export type GetProfileImageUploadLinkMutationVariables = Exact<{ export type GetProfileImageUploadLinkMutationVariables = Exact<{
fileExt?: InputMaybe<Scalars['String']['input']>; fileExt?: InputMaybe<Scalars['String']['input']>;
@@ -3261,7 +3477,7 @@ export type GetStreamMonitoringDetailsQueryVariables = Exact<{
}>; }>;
export type GetStreamMonitoringDetailsQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, totalShots: number, makePercentage: number, elapsedTime?: number | null, currentHomography?: { __typename?: 'HomographyInfoGQL', id: number, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, linksRequested: number, lowestUnuploadedSegmentIndex: number, uploadsCompleted: number, segmentProcessingCursor: number, isCompleted: boolean, uploadCompletionCursor: number, lastIntendedSegmentBound?: number | null, initPlaylistUploadStatus?: InitPlaylistUploadStatusEnum | null } | null, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, errors: Array<{ __typename?: 'VideoProcessingErrorGQL', message: string, startSegmentIndex?: number | null, endSegmentIndex?: number | null }> } | null } }; export type GetStreamMonitoringDetailsQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, totalShots: number, makePercentage: number, elapsedTime?: number | null, currentHomography?: { __typename?: 'HomographyInfoGQL', id?: number | null, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, linksRequested: number, lowestUnuploadedSegmentIndex: number, uploadsCompleted: number, segmentProcessingCursor: number, isCompleted: boolean, uploadCompletionCursor: number, lastIntendedSegmentBound?: number | null, initPlaylistUploadStatus?: InitPlaylistUploadStatusEnum | null } | null, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, errors: Array<{ __typename?: 'VideoProcessingErrorGQL', message: string, startSegmentIndex?: number | null, endSegmentIndex?: number | null }> } | null } };
export type GetVideoUpdatePageDetailsQueryVariables = Exact<{ export type GetVideoUpdatePageDetailsQueryVariables = Exact<{
videoId: Scalars['Int']['input']; videoId: Scalars['Int']['input'];
@@ -3296,7 +3512,7 @@ export type GetVideoCardQueryVariables = Exact<{
}>; }>;
export type GetVideoCardQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> } }; export type GetVideoCardQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, name?: string | null, screenshotUri?: string | null, totalShots: number, makePercentage: number, averageTimeBetweenShots?: number | null, averageDifficulty?: number | null, startTime?: any | null, private: boolean, elapsedTime?: number | null, tableSize: number, pocketSize?: number | null, owner?: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null } | null, stream?: { __typename?: 'UploadStreamGQL', id: string, lastIntendedSegmentBound?: number | null, uploadCompletionCursor: number, streamSegmentType: StreamSegmentTypeEnum, isCompleted: boolean, lastSegmentUploadedAt?: any | null, clientUploadStatus?: ClientUploadStatusEnum | null } | null, tags: Array<{ __typename?: 'VideoTag', name: string, tagClasses: Array<{ __typename?: 'VideoTagClass', name: string }> }>, playerSummaries: Array<{ __typename?: 'PlayerSummaryGQL', clusterId: number, userId?: number | null, username?: string | null, profileImageUri?: string | null, representativeFullFrameUrl?: string | null, totalShots: number, totalShotsMade: number, makePercentage: number, score?: number | null, longestRun: number, runLengths: Array<number>, averageDifficulty?: number | null, averageTimeBetweenShots?: number | null, spinTypeBreakdown: { __typename?: 'SpinTypeBreakdownGQL', draw: number, center: number, follow: number } }>, currentProcessing?: { __typename?: 'VideoProcessingGQL', id: number, status: ProcessingStatusEnum } | null, reactions: Array<{ __typename?: 'ReactionGQL', videoId: number, reaction: ReactionEnum, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }>, comments: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null }, replies: Array<{ __typename?: 'CommentGQL', id: number, message: string, user: { __typename?: 'UserGQL', id: number, username: string, profileImageUri?: string | null, isFollowedByCurrentUser?: boolean | null } }> }> } };
export type GetVideosQueryVariables = Exact<{ export type GetVideosQueryVariables = Exact<{
videoIds: Array<Scalars['Int']['input']> | Scalars['Int']['input']; videoIds: Array<Scalars['Int']['input']> | Scalars['Int']['input'];
@@ -3319,7 +3535,7 @@ export type GetVideoQueryVariables = Exact<{
}>; }>;
export type GetVideoQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, playlist?: { __typename?: 'HLSPlaylistGQL', segmentDurations: Array<number> } | null, homographyHistory: Array<{ __typename?: 'HomographyInfoGQL', id: number, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } }>, stream?: { __typename?: 'UploadStreamGQL', id: string, streamSegmentType: StreamSegmentTypeEnum, segments: Array<{ __typename?: 'UploadSegmentGQL', segmentIndex: number, endFrameIndex?: number | null, framesPerSecond?: number | null }>, resolution: { __typename?: 'VideoResolutionGQL', width?: number | null, height?: number | null } } | null } }; export type GetVideoQuery = { __typename?: 'Query', getVideo: { __typename?: 'VideoGQL', id: number, playlist?: { __typename?: 'HLSPlaylistGQL', segmentDurations: Array<number> } | null, homographyHistory: Array<{ __typename?: 'HomographyInfoGQL', id?: number | null, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } }>, stream?: { __typename?: 'UploadStreamGQL', id: string, streamSegmentType: StreamSegmentTypeEnum, segments: Array<{ __typename?: 'UploadSegmentGQL', segmentIndex: number, endFrameIndex?: number | null, framesPerSecond?: number | null }>, resolution: { __typename?: 'VideoResolutionGQL', width?: number | null, height?: number | null } } | null } };
export type GetAverageTimePerShotForVideoQueryVariables = Exact<{ export type GetAverageTimePerShotForVideoQueryVariables = Exact<{
videoId: Scalars['Int']['input']; videoId: Scalars['Int']['input'];
@@ -3386,9 +3602,9 @@ export type FindPrerecordTableLayoutMutationVariables = Exact<{
}>; }>;
export type FindPrerecordTableLayoutMutation = { __typename?: 'Mutation', findPrerecordTableLayout?: { __typename?: 'HomographyInfoGQL', id: number, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } } | null }; export type FindPrerecordTableLayoutMutation = { __typename?: 'Mutation', findPrerecordTableLayout?: { __typename?: 'HomographyInfoGQL', id?: number | null, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } } | null };
export type HomographyInfoFragment = { __typename?: 'HomographyInfoGQL', id: number, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } }; export type HomographyInfoFragment = { __typename?: 'HomographyInfoGQL', id?: number | null, frameIndex: number, crop: { __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }, pockets: Array<{ __typename?: 'BoundingBoxGQL', left: number, top: number, width: number, height: number }>, sourcePoints: { __typename?: 'PocketPointsGQL', topLeft: { __typename?: 'IntPoint2D', x: number, y: number }, topSide: { __typename?: 'IntPoint2D', x: number, y: number }, topRight: { __typename?: 'IntPoint2D', x: number, y: number }, bottomLeft: { __typename?: 'IntPoint2D', x: number, y: number }, bottomSide: { __typename?: 'IntPoint2D', x: number, y: number }, bottomRight: { __typename?: 'IntPoint2D', x: number, y: number } } };
export type VideoExportJobFieldsFragment = { __typename?: 'VideoExportJobGQL', id: number, videoId: number, mode: VideoExportModeEnum, status: VideoExportStatusEnum, videoName?: string | null, videoThumbnailUri?: string | null, shotIds?: Array<number> | null, runId?: number | null, downloadUrl?: string | null, fileSizeBytes?: number | null, expiresAt?: any | null, createdAt?: any | null }; export type VideoExportJobFieldsFragment = { __typename?: 'VideoExportJobGQL', id: number, videoId: number, mode: VideoExportModeEnum, status: VideoExportStatusEnum, videoName?: string | null, videoThumbnailUri?: string | null, shotIds?: Array<number> | null, runId?: number | null, downloadUrl?: string | null, fileSizeBytes?: number | null, expiresAt?: any | null, createdAt?: any | null };
@@ -3555,6 +3771,7 @@ export const VideoCardFieldsFragmentDoc = gql`
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor
streamSegmentType streamSegmentType
isCompleted isCompleted
lastSegmentUploadedAt lastSegmentUploadedAt
@@ -3737,6 +3954,34 @@ export const PocketingIntentionFragmentFragmentDoc = gql`
difficulty difficulty
} }
`; `;
export const SessionCoachCandidateFieldsFragmentDoc = gql`
fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
id
rank
family
kind
title
body
action
supportingShotIds
drillId
limitations
evidence {
bucketKey
bucketLabel
attemptCount
madeCount
missedCount
makePercentage
comparisonAttemptCount
comparisonMadeCount
comparisonMakePercentage
patternShotCount
score
rankReason
}
}
`;
export const PlayerClusterShotFieldsFragmentDoc = gql` export const PlayerClusterShotFieldsFragmentDoc = gql`
fragment PlayerClusterShotFields on PlayerClusterShotGQL { fragment PlayerClusterShotFields on PlayerClusterShotGQL {
shotId shotId
@@ -3765,6 +4010,43 @@ export const PlayerClusterFieldsFragmentDoc = gql`
} }
} }
${PlayerClusterShotFieldsFragmentDoc}`; ${PlayerClusterShotFieldsFragmentDoc}`;
export const PositionShotCandidateFragmentDoc = gql`
fragment PositionShotCandidate on PositionShotCandidateGQL {
strike {
v0
phi
theta
a
b
}
cueFinalPosition
inTargetArea
distanceToTargetArea
robustness
potted
scratched
projection {
trajectories {
ballId
points {
time
position
}
}
events {
eventType
time
ballIds
position
}
finalState {
ballId
position
}
pottedBallIds
}
}
`;
export const ShotClipRangeFragmentDoc = gql` export const ShotClipRangeFragmentDoc = gql`
fragment ShotClipRange on ShotGQL { fragment ShotClipRange on ShotGQL {
id id
@@ -7019,6 +7301,137 @@ export function useReactToVideoMutation(baseOptions?: Apollo.MutationHookOptions
export type ReactToVideoMutationHookResult = ReturnType<typeof useReactToVideoMutation>; export type ReactToVideoMutationHookResult = ReturnType<typeof useReactToVideoMutation>;
export type ReactToVideoMutationResult = Apollo.MutationResult<ReactToVideoMutation>; export type ReactToVideoMutationResult = Apollo.MutationResult<ReactToVideoMutation>;
export type ReactToVideoMutationOptions = Apollo.BaseMutationOptions<ReactToVideoMutation, ReactToVideoMutationVariables>; export type ReactToVideoMutationOptions = Apollo.BaseMutationOptions<ReactToVideoMutation, ReactToVideoMutationVariables>;
export const GetRecordedStreamsDocument = gql`
query GetRecordedStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: {isStreamCompleted: true, excludeVideosWithNoShots: true}
includePrivate: MINE
feedInput: {allUsers: true}
) {
videos {
id
name
createdAt
screenshotUri
framesPerSecond
totalShots
owner {
id
username
profileImageUri
}
}
}
}
`;
/**
* __useGetRecordedStreamsQuery__
*
* To run a query within a React component, call `useGetRecordedStreamsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetRecordedStreamsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetRecordedStreamsQuery({
* variables: {
* limit: // value for 'limit'
* },
* });
*/
export function useGetRecordedStreamsQuery(baseOptions?: Apollo.QueryHookOptions<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>(GetRecordedStreamsDocument, options);
}
export function useGetRecordedStreamsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>(GetRecordedStreamsDocument, options);
}
export function useGetRecordedStreamsSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>(GetRecordedStreamsDocument, options);
}
export type GetRecordedStreamsQueryHookResult = ReturnType<typeof useGetRecordedStreamsQuery>;
export type GetRecordedStreamsLazyQueryHookResult = ReturnType<typeof useGetRecordedStreamsLazyQuery>;
export type GetRecordedStreamsSuspenseQueryHookResult = ReturnType<typeof useGetRecordedStreamsSuspenseQuery>;
export type GetRecordedStreamsQueryResult = Apollo.QueryResult<GetRecordedStreamsQuery, GetRecordedStreamsQueryVariables>;
export const GetRecordedStreamShotsDocument = gql`
query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
getOrderedShots(
filterInput: {videoId: [$videoId]}
shotsOrdering: {orderings: [{startFrame: {descending: false}}]}
limit: $limit
) {
shots {
id
videoId
startFrame
endFrame
serializedShotPaths {
b64EncodedBuffer
}
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures {
make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
}
pocketingIntentionInfo {
ballId
pocketId
pathMetadataIndex
}
}
}
}
`;
/**
* __useGetRecordedStreamShotsQuery__
*
* To run a query within a React component, call `useGetRecordedStreamShotsQuery` and pass it any options that fit your needs.
* When your component renders, `useGetRecordedStreamShotsQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetRecordedStreamShotsQuery({
* variables: {
* videoId: // value for 'videoId'
* limit: // value for 'limit'
* },
* });
*/
export function useGetRecordedStreamShotsQuery(baseOptions: Apollo.QueryHookOptions<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>(GetRecordedStreamShotsDocument, options);
}
export function useGetRecordedStreamShotsLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>(GetRecordedStreamShotsDocument, options);
}
export function useGetRecordedStreamShotsSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>(GetRecordedStreamShotsDocument, options);
}
export type GetRecordedStreamShotsQueryHookResult = ReturnType<typeof useGetRecordedStreamShotsQuery>;
export type GetRecordedStreamShotsLazyQueryHookResult = ReturnType<typeof useGetRecordedStreamShotsLazyQuery>;
export type GetRecordedStreamShotsSuspenseQueryHookResult = ReturnType<typeof useGetRecordedStreamShotsSuspenseQuery>;
export type GetRecordedStreamShotsQueryResult = Apollo.QueryResult<GetRecordedStreamShotsQuery, GetRecordedStreamShotsQueryVariables>;
export const GetRunsForHighlightsDocument = gql` export const GetRunsForHighlightsDocument = gql`
query GetRunsForHighlights($filterInput: RunFilterInput!, $runIds: [Int!] = null, $runsOrdering: GetRunsOrdering, $limit: Int! = 500, $countRespectsLimit: Boolean! = false) { query GetRunsForHighlights($filterInput: RunFilterInput!, $runIds: [Int!] = null, $runsOrdering: GetRunsOrdering, $limit: Int! = 500, $countRespectsLimit: Boolean! = false) {
getRuns( getRuns(
@@ -7137,6 +7550,65 @@ export type GetRunsWithTimestampsQueryHookResult = ReturnType<typeof useGetRunsW
export type GetRunsWithTimestampsLazyQueryHookResult = ReturnType<typeof useGetRunsWithTimestampsLazyQuery>; export type GetRunsWithTimestampsLazyQueryHookResult = ReturnType<typeof useGetRunsWithTimestampsLazyQuery>;
export type GetRunsWithTimestampsSuspenseQueryHookResult = ReturnType<typeof useGetRunsWithTimestampsSuspenseQuery>; export type GetRunsWithTimestampsSuspenseQueryHookResult = ReturnType<typeof useGetRunsWithTimestampsSuspenseQuery>;
export type GetRunsWithTimestampsQueryResult = Apollo.QueryResult<GetRunsWithTimestampsQuery, GetRunsWithTimestampsQueryVariables>; export type GetRunsWithTimestampsQueryResult = Apollo.QueryResult<GetRunsWithTimestampsQuery, GetRunsWithTimestampsQueryVariables>;
export const GetSessionCoachDocument = gql`
query GetSessionCoach($videoId: Int!) {
getSessionCoach(videoId: $videoId) {
videoId
processingId
analysisVersion
state
generatedAt
processingStatus
ineligibilityReason
summary
shotCount
madeCount
missedCount
unknownOutcomeCount
analyzedShotCount
makePercentage
primaryCandidate {
...SessionCoachCandidateFields
}
candidates {
...SessionCoachCandidateFields
}
}
}
${SessionCoachCandidateFieldsFragmentDoc}`;
/**
* __useGetSessionCoachQuery__
*
* To run a query within a React component, call `useGetSessionCoachQuery` and pass it any options that fit your needs.
* When your component renders, `useGetSessionCoachQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetSessionCoachQuery({
* variables: {
* videoId: // value for 'videoId'
* },
* });
*/
export function useGetSessionCoachQuery(baseOptions: Apollo.QueryHookOptions<GetSessionCoachQuery, GetSessionCoachQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetSessionCoachQuery, GetSessionCoachQueryVariables>(GetSessionCoachDocument, options);
}
export function useGetSessionCoachLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetSessionCoachQuery, GetSessionCoachQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetSessionCoachQuery, GetSessionCoachQueryVariables>(GetSessionCoachDocument, options);
}
export function useGetSessionCoachSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<GetSessionCoachQuery, GetSessionCoachQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetSessionCoachQuery, GetSessionCoachQueryVariables>(GetSessionCoachDocument, options);
}
export type GetSessionCoachQueryHookResult = ReturnType<typeof useGetSessionCoachQuery>;
export type GetSessionCoachLazyQueryHookResult = ReturnType<typeof useGetSessionCoachLazyQuery>;
export type GetSessionCoachSuspenseQueryHookResult = ReturnType<typeof useGetSessionCoachSuspenseQuery>;
export type GetSessionCoachQueryResult = Apollo.QueryResult<GetSessionCoachQuery, GetSessionCoachQueryVariables>;
export const VideoPlayerClustersDocument = gql` export const VideoPlayerClustersDocument = gql`
query VideoPlayerClusters($videoId: Int!) { query VideoPlayerClusters($videoId: Int!) {
videoPlayerClusters(videoId: $videoId) { videoPlayerClusters(videoId: $videoId) {
@@ -7218,6 +7690,9 @@ export const GetTableStateDocument = gql`
useHomography: $useHomography useHomography: $useHomography
) { ) {
identifierToPosition identifierToPosition
identifierToColor {
hex
}
} }
} }
`; `;
@@ -7263,13 +7738,13 @@ export const GetLiveTableStateDocument = gql`
frameIndex frameIndex
tableState { tableState {
identifierToPosition identifierToPosition
homography { identifierToColor {
...HomographyInfo hex
} }
} }
} }
} }
${HomographyInfoFragmentDoc}`; `;
/** /**
* __useGetLiveTableStateQuery__ * __useGetLiveTableStateQuery__
@@ -7303,6 +7778,54 @@ export type GetLiveTableStateQueryHookResult = ReturnType<typeof useGetLiveTable
export type GetLiveTableStateLazyQueryHookResult = ReturnType<typeof useGetLiveTableStateLazyQuery>; export type GetLiveTableStateLazyQueryHookResult = ReturnType<typeof useGetLiveTableStateLazyQuery>;
export type GetLiveTableStateSuspenseQueryHookResult = ReturnType<typeof useGetLiveTableStateSuspenseQuery>; export type GetLiveTableStateSuspenseQueryHookResult = ReturnType<typeof useGetLiveTableStateSuspenseQuery>;
export type GetLiveTableStateQueryResult = Apollo.QueryResult<GetLiveTableStateQuery, GetLiveTableStateQueryVariables>; export type GetLiveTableStateQueryResult = Apollo.QueryResult<GetLiveTableStateQuery, GetLiveTableStateQueryVariables>;
export const GetShotTableStateDocument = gql`
query GetShotTableState($shotId: Int!) {
getShotTableState(shotId: $shotId) {
shotId
videoId
frameIndex
tableState {
identifierToPosition
identifierToColor {
hex
}
}
}
}
`;
/**
* __useGetShotTableStateQuery__
*
* To run a query within a React component, call `useGetShotTableStateQuery` and pass it any options that fit your needs.
* When your component renders, `useGetShotTableStateQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useGetShotTableStateQuery({
* variables: {
* shotId: // value for 'shotId'
* },
* });
*/
export function useGetShotTableStateQuery(baseOptions: Apollo.QueryHookOptions<GetShotTableStateQuery, GetShotTableStateQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<GetShotTableStateQuery, GetShotTableStateQueryVariables>(GetShotTableStateDocument, options);
}
export function useGetShotTableStateLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<GetShotTableStateQuery, GetShotTableStateQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<GetShotTableStateQuery, GetShotTableStateQueryVariables>(GetShotTableStateDocument, options);
}
export function useGetShotTableStateSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<GetShotTableStateQuery, GetShotTableStateQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<GetShotTableStateQuery, GetShotTableStateQueryVariables>(GetShotTableStateDocument, options);
}
export type GetShotTableStateQueryHookResult = ReturnType<typeof useGetShotTableStateQuery>;
export type GetShotTableStateLazyQueryHookResult = ReturnType<typeof useGetShotTableStateLazyQuery>;
export type GetShotTableStateSuspenseQueryHookResult = ReturnType<typeof useGetShotTableStateSuspenseQuery>;
export type GetShotTableStateQueryResult = Apollo.QueryResult<GetShotTableStateQuery, GetShotTableStateQueryVariables>;
export const SimulateShotDocument = gql` export const SimulateShotDocument = gql`
query SimulateShot($simulationInput: SimulateShotInputGQL!) { query SimulateShot($simulationInput: SimulateShotInputGQL!) {
simulateShot(simulationInput: $simulationInput) { simulateShot(simulationInput: $simulationInput) {
@@ -7413,6 +7936,54 @@ export type ComputePotAimQueryHookResult = ReturnType<typeof useComputePotAimQue
export type ComputePotAimLazyQueryHookResult = ReturnType<typeof useComputePotAimLazyQuery>; export type ComputePotAimLazyQueryHookResult = ReturnType<typeof useComputePotAimLazyQuery>;
export type ComputePotAimSuspenseQueryHookResult = ReturnType<typeof useComputePotAimSuspenseQuery>; export type ComputePotAimSuspenseQueryHookResult = ReturnType<typeof useComputePotAimSuspenseQuery>;
export type ComputePotAimQueryResult = Apollo.QueryResult<ComputePotAimQuery, ComputePotAimQueryVariables>; export type ComputePotAimQueryResult = Apollo.QueryResult<ComputePotAimQuery, ComputePotAimQueryVariables>;
export const SuggestPositionShotDocument = gql`
query SuggestPositionShot($suggestionInput: SuggestPositionShotInputGQL!) {
suggestPositionShot(suggestionInput: $suggestionInput) {
achievable
evaluatedCount
successfulCount
best {
...PositionShotCandidate
}
alternates {
...PositionShotCandidate
}
}
}
${PositionShotCandidateFragmentDoc}`;
/**
* __useSuggestPositionShotQuery__
*
* To run a query within a React component, call `useSuggestPositionShotQuery` and pass it any options that fit your needs.
* When your component renders, `useSuggestPositionShotQuery` returns an object from Apollo Client that contains loading, error, and data properties
* you can use to render your UI.
*
* @param baseOptions options that will be passed into the query, supported options are listed on: https://www.apollographql.com/docs/react/api/react-hooks/#options;
*
* @example
* const { data, loading, error } = useSuggestPositionShotQuery({
* variables: {
* suggestionInput: // value for 'suggestionInput'
* },
* });
*/
export function useSuggestPositionShotQuery(baseOptions: Apollo.QueryHookOptions<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useQuery<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>(SuggestPositionShotDocument, options);
}
export function useSuggestPositionShotLazyQuery(baseOptions?: Apollo.LazyQueryHookOptions<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useLazyQuery<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>(SuggestPositionShotDocument, options);
}
export function useSuggestPositionShotSuspenseQuery(baseOptions?: Apollo.SuspenseQueryHookOptions<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>) {
const options = {...defaultOptions, ...baseOptions}
return Apollo.useSuspenseQuery<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>(SuggestPositionShotDocument, options);
}
export type SuggestPositionShotQueryHookResult = ReturnType<typeof useSuggestPositionShotQuery>;
export type SuggestPositionShotLazyQueryHookResult = ReturnType<typeof useSuggestPositionShotLazyQuery>;
export type SuggestPositionShotSuspenseQueryHookResult = ReturnType<typeof useSuggestPositionShotSuspenseQuery>;
export type SuggestPositionShotQueryResult = Apollo.QueryResult<SuggestPositionShotQuery, SuggestPositionShotQueryVariables>;
export const GetSerializedShotPathsDocument = gql` export const GetSerializedShotPathsDocument = gql`
query GetSerializedShotPaths($filterInput: FilterInput!) { query GetSerializedShotPaths($filterInput: FilterInput!) {
getShots(filterInput: $filterInput) { getShots(filterInput: $filterInput) {
@@ -7953,6 +8524,25 @@ export type DeleteTagsMutationOptions = Apollo.BaseMutationOptions<DeleteTagsMut
export const GetUsageStatsDocument = gql` export const GetUsageStatsDocument = gql`
query getUsageStats($days: Int! = 30) { query getUsageStats($days: Int! = 30) {
getUsageStats(days: $days) { getUsageStats(days: $days) {
funnel {
freemiumEpoch
eraSignups
eraPaying
activationCohort
activationActivated
payingUsers
newPaid7d
newPaid30d
retentionPrevActive
retentionReturned
}
cohorts {
weekStart
signups
activated7d
paid7d
activatedNotPaid7d
}
totalUsers totalUsers
totalVideos totalVideos
totalShots totalShots

View File

@@ -41,6 +41,7 @@ fragment VideoCardFields on VideoGQL {
stream { stream {
id id
lastIntendedSegmentBound lastIntendedSegmentBound
uploadCompletionCursor
streamSegmentType streamSegmentType
isCompleted isCompleted
lastSegmentUploadedAt lastSegmentUploadedAt

View File

@@ -0,0 +1,62 @@
# Lightweight two-step picker data for loading a recorded shot into Shot Lab.
query GetRecordedStreams($limit: Int! = 25) {
getFeedVideos(
limit: $limit
filters: { isStreamCompleted: true, excludeVideosWithNoShots: true }
includePrivate: MINE
feedInput: { allUsers: true }
) {
videos {
id
name
createdAt
screenshotUri
framesPerSecond
totalShots
owner {
id
username
profileImageUri
}
}
}
}
query GetRecordedStreamShots($videoId: Int!, $limit: Int! = 200) {
getOrderedShots(
filterInput: { videoId: [$videoId] }
shotsOrdering: { orderings: [{ startFrame: { descending: false } }] }
limit: $limit
) {
shots {
id
videoId
startFrame
endFrame
serializedShotPaths {
b64EncodedBuffer
}
cueObjectFeatures {
cueObjectDistance
cueObjectAngle
cueBallSpeed
shotDirection
spinType
}
pocketingIntentionFeatures {
make
targetPocketDistance
targetPocketAngle
targetPocketAngleDirection
marginOfErrorInDegrees
intendedPocketType
difficulty
}
pocketingIntentionInfo {
ballId
pocketId
pathMetadataIndex
}
}
}
}

View File

@@ -0,0 +1,51 @@
query GetSessionCoach($videoId: Int!) {
getSessionCoach(videoId: $videoId) {
videoId
processingId
analysisVersion
state
generatedAt
processingStatus
ineligibilityReason
summary
shotCount
madeCount
missedCount
unknownOutcomeCount
analyzedShotCount
makePercentage
primaryCandidate {
...SessionCoachCandidateFields
}
candidates {
...SessionCoachCandidateFields
}
}
}
fragment SessionCoachCandidateFields on SessionCoachCandidateGQL {
id
rank
family
kind
title
body
action
supportingShotIds
drillId
limitations
evidence {
bucketKey
bucketLabel
attemptCount
madeCount
missedCount
makePercentage
comparisonAttemptCount
comparisonMadeCount
comparisonMakePercentage
patternShotCount
score
rankReason
}
}

View File

@@ -9,6 +9,9 @@ query GetTableState(
useHomography: $useHomography useHomography: $useHomography
) { ) {
identifierToPosition identifierToPosition
identifierToColor {
hex
}
} }
} }
@@ -18,8 +21,22 @@ query GetLiveTableState($videoId: Int!) {
frameIndex frameIndex
tableState { tableState {
identifierToPosition identifierToPosition
homography { identifierToColor {
...HomographyInfo hex
}
}
}
}
query GetShotTableState($shotId: Int!) {
getShotTableState(shotId: $shotId) {
shotId
videoId
frameIndex
tableState {
identifierToPosition
identifierToColor {
hex
} }
} }
} }
@@ -68,3 +85,53 @@ query ComputePotAim(
occludingBallIds occludingBallIds
} }
} }
fragment PositionShotCandidate on PositionShotCandidateGQL {
strike {
v0
phi
theta
a
b
}
cueFinalPosition
inTargetArea
distanceToTargetArea
robustness
potted
scratched
projection {
trajectories {
ballId
points {
time
position
}
}
events {
eventType
time
ballIds
position
}
finalState {
ballId
position
}
pottedBallIds
}
}
query SuggestPositionShot($suggestionInput: SuggestPositionShotInputGQL!) {
suggestPositionShot(suggestionInput: $suggestionInput) {
achievable
evaluatedCount
successfulCount
best {
...PositionShotCandidate
}
alternates {
...PositionShotCandidate
}
}
}

View File

@@ -1,5 +1,24 @@
query getUsageStats($days: Int! = 30) { query getUsageStats($days: Int! = 30) {
getUsageStats(days: $days) { getUsageStats(days: $days) {
funnel {
freemiumEpoch
eraSignups
eraPaying
activationCohort
activationActivated
payingUsers
newPaid7d
newPaid30d
retentionPrevActive
retentionReturned
}
cohorts {
weekStart
signups
activated7d
paid7d
activatedNotPaid7d
}
totalUsers totalUsers
totalVideos totalVideos
totalShots totalShots

View File

@@ -65,6 +65,7 @@ type Query {
limit: Int! = 500 limit: Int! = 500
countRespectsLimit: Boolean! = false countRespectsLimit: Boolean! = false
): GetRunsResult! ): GetRunsResult!
getSessionCoach(videoId: Int!): SessionCoachGQL!
videoPlayerClusters(videoId: Int!): [PlayerClusterGQL!]! videoPlayerClusters(videoId: Int!): [PlayerClusterGQL!]!
getShotAnnotationTypes(errorTypes: Boolean = false): [ShotAnnotationTypeGQL!]! getShotAnnotationTypes(errorTypes: Boolean = false): [ShotAnnotationTypeGQL!]!
getTableState( getTableState(
@@ -73,12 +74,16 @@ type Query {
useHomography: HomographyInputGQL = null useHomography: HomographyInputGQL = null
): TableStateGQL! ): TableStateGQL!
getLiveTableState(videoId: Int!): LiveTableStateGQL! getLiveTableState(videoId: Int!): LiveTableStateGQL!
getShotTableState(shotId: Int!): ShotTableStateGQL!
simulateShot(simulationInput: SimulateShotInputGQL!): ShotProjectionGQL! simulateShot(simulationInput: SimulateShotInputGQL!): ShotProjectionGQL!
computePotAim( computePotAim(
simulationInput: SimulateShotInputGQL! simulationInput: SimulateShotInputGQL!
targetBallId: Int! targetBallId: Int!
pocket: PocketIdentifier! pocket: PocketIdentifier!
): PotAimGQL! ): PotAimGQL!
suggestPositionShot(
suggestionInput: SuggestPositionShotInputGQL!
): PositionSuggestionGQL!
getOrderedShots( getOrderedShots(
filterInput: FilterInput! filterInput: FilterInput!
ids: [Int!] = null ids: [Int!] = null
@@ -609,7 +614,7 @@ type VideoTagClass {
} }
type HomographyInfoGQL { type HomographyInfoGQL {
id: Int! id: Int
frameIndex: Int! frameIndex: Int!
crop: BoundingBoxGQL! crop: BoundingBoxGQL!
pockets: [BoundingBoxGQL!]! pockets: [BoundingBoxGQL!]!
@@ -994,6 +999,81 @@ input DatetimeOrdering {
startingAt: DateTime = null startingAt: DateTime = null
} }
type SessionCoachGQL {
videoId: Int!
processingId: Int
analysisVersion: String!
state: SessionCoachStateEnum!
generatedAt: DateTime!
processingStatus: String
ineligibilityReason: SessionCoachIneligibilityReasonEnum
summary: String
shotCount: Int!
madeCount: Int!
missedCount: Int!
unknownOutcomeCount: Int!
analyzedShotCount: Int!
makePercentage: Float
primaryCandidate: SessionCoachCandidateGQL
candidates: [SessionCoachCandidateGQL!]!
}
enum SessionCoachStateEnum {
PROCESSING
READY
NO_TRACKED_SHOTS
INELIGIBLE
FAILED
}
enum SessionCoachIneligibilityReasonEnum {
MULTIPLAYER
}
type SessionCoachCandidateGQL {
id: ID!
rank: Int!
family: SessionCoachCandidateFamilyEnum!
kind: SessionCoachCandidateKindEnum!
title: String!
body: String!
action: String!
supportingShotIds: [Int!]!
drillId: String
evidence: SessionCoachEvidenceGQL!
limitations: [String!]!
}
enum SessionCoachCandidateFamilyEnum {
AIMING
CUT_ANGLE
SPIN
OBJECT_TO_POCKET_DISTANCE
CUE_TO_OBJECT_DISTANCE
BACK_CUT
}
enum SessionCoachCandidateKindEnum {
DIRECTIONAL_MISS
OUTCOME_PATTERN
USAGE_PATTERN
}
type SessionCoachEvidenceGQL {
bucketKey: String!
bucketLabel: String!
attemptCount: Int!
madeCount: Int!
missedCount: Int!
makePercentage: Float!
comparisonAttemptCount: Int!
comparisonMadeCount: Int!
comparisonMakePercentage: Float
patternShotCount: Int!
score: Float!
rankReason: String!
}
type PlayerClusterGQL { type PlayerClusterGQL {
videoId: Int! videoId: Int!
clusterId: Int! clusterId: Int!
@@ -1065,6 +1145,13 @@ type LiveTableStateGQL {
tableState: TableStateGQL! tableState: TableStateGQL!
} }
type ShotTableStateGQL {
shotId: Int!
videoId: Int!
frameIndex: Int!
tableState: TableStateGQL!
}
type ShotProjectionGQL { type ShotProjectionGQL {
trajectories: [BallTrajectoryGQL!]! trajectories: [BallTrajectoryGQL!]!
events: [SimulationEventGQL!]! events: [SimulationEventGQL!]!
@@ -1135,6 +1222,44 @@ type PotAimGQL {
occludingBallIds: [Int!]! occludingBallIds: [Int!]!
} }
type PositionSuggestionGQL {
achievable: Boolean!
best: PositionShotCandidateGQL
alternates: [PositionShotCandidateGQL!]!
evaluatedCount: Int!
successfulCount: Int!
}
type PositionShotCandidateGQL {
strike: CueStrikeGQL!
cueFinalPosition: [Float!]!
inTargetArea: Boolean!
distanceToTargetArea: Float!
robustness: Int!
potted: Boolean!
scratched: Boolean!
projection: ShotProjectionGQL
}
type CueStrikeGQL {
v0: Float!
phi: Float!
theta: Float!
a: Float!
b: Float!
}
input SuggestPositionShotInputGQL {
cueBallId: Int!
targetBallId: Int!
pocket: PocketIdentifier!
targetArea: [[Float!]!]!
balls: [SimulationBallStateInputGQL!] = null
b64Image: String = null
useHomography: HomographyInputGQL = null
tableSize: Float = null
}
type GetShotsResult { type GetShotsResult {
shots: [ShotGQL!]! shots: [ShotGQL!]!
count: Int count: Int
@@ -1170,15 +1295,38 @@ input CreatedAfter @oneOf {
} }
type UsageStatsGQL { type UsageStatsGQL {
funnel: FunnelStatsGQL!
totalUsers: Int! totalUsers: Int!
totalVideos: Int! totalVideos: Int!
totalShots: Int! totalShots: Int!
totalRuns: Int! totalRuns: Int!
cohorts: [CohortStatsGQL!]!
windows: [UsageStatsWindowGQL!]! windows: [UsageStatsWindowGQL!]!
daily: [UsageStatsDailyGQL!]! daily: [UsageStatsDailyGQL!]!
processingLast24h: [ProcessingStatusCountGQL!]! processingLast24h: [ProcessingStatusCountGQL!]!
} }
type FunnelStatsGQL {
freemiumEpoch: Date!
eraSignups: Int!
eraPaying: Int!
activationCohort: Int!
activationActivated: Int!
payingUsers: Int!
newPaid7d: Int!
newPaid30d: Int!
retentionPrevActive: Int!
retentionReturned: Int!
}
type CohortStatsGQL {
weekStart: Date!
signups: Int!
activated7d: Int!
paid7d: Int!
activatedNotPaid7d: Int!
}
type UsageStatsWindowGQL { type UsageStatsWindowGQL {
label: String! label: String!
newUsers: Int! newUsers: Int!
@@ -1794,6 +1942,7 @@ input VideoMetadataInput {
clientUploadStatus: ClientUploadStatusEnum = null clientUploadStatus: ClientUploadStatusEnum = null
resolution: VideoResolution = null resolution: VideoResolution = null
framesPerSecond: Float = null framesPerSecond: Float = null
homographyBackend: HomographyBackendGQL = null
} }
input VideoResolution { input VideoResolution {
@@ -1801,6 +1950,11 @@ input VideoResolution {
height: Int! height: Int!
} }
enum HomographyBackendGQL {
CLASSIC
TABLENET
}
type GetUploadLinkReturn { type GetUploadLinkReturn {
value: UploadLinkGetUploadLinkErrors! value: UploadLinkGetUploadLinkErrors!
stream: UploadStreamGQL stream: UploadStreamGQL