@pbvision/partner-sdk 0.1.19 → 0.1.20

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +8 -4
  2. package/package.json +1 -1
  3. package/src/index.js +30 -10
package/README.md CHANGED
@@ -169,6 +169,7 @@ entirely, or provide some or all of these fields:
169
169
  | `facility` | `string` | Name of the facility where the game was recorded, e.g. `"Cool Club #3 - Barcelona"`. Useful for facility and Court Insight integrations. |
170
170
  | `court` | `string` | Court identifier where the game was recorded, e.g. `"11A"`. Useful for facility and Court Insight integrations. |
171
171
  | `fid` | `integer` | Folder ID, e.g. from `getOrCreateFolder()` (see [Folders](#folders)). Puts the video in that folder in your partner account's library. A `fid` that isn't one of your folders is refused with a 400 error (`unknown folder`). |
172
+ | `playersFolderPath` | `string[]` | Where the video goes in the PB Vision library of everyone it's shared with: the folder names from the top of their library down, e.g. `['Mon Oct 19 open play']`. 1 to 5 names, each 1 to 200 characters with no leading or trailing whitespace. Folders they don't have are made for them. |
172
173
  | `playersForTagging` | `object` | The players to **auto-tag** once processing completes, each by a name, an email, or both (see [Auto-tagging players](#auto-tagging-players)). Honored by all of `uploadVideo()`, `sendVideoUrlToDownload()`, `makeVideoId()`, and `makeRecordingLink()`. |
173
174
 
174
175
  The `facility` and `court` fields are primarily used by facility partners
@@ -219,7 +220,8 @@ games automatically.
219
220
 
220
221
  Folders organize the videos in your partner account's library. To put a new
221
222
  video in a folder, pass the folder's ID as the `fid` [metadata](#video-metadata)
222
- field.
223
+ field. To file it in the libraries of the people it's shared with, pass
224
+ `playersFolderPath`.
223
225
 
224
226
  `getOrCreateFolder()` returns the folder with the name you give (inside
225
227
  `parent`, if you pass one), creating it if needed, so it's safe to retry. Use a
@@ -357,9 +359,11 @@ await pbv.setGameScore({ nonce: `${eventId}-${gameId}`, server: 11, receiver: 7
357
359
 
358
360
  You can report before the video is processed, or even recorded: the game gets
359
361
  the score when processing finishes, and the response's `applied` says whether
360
- it has it yet. Report again to correct a score; the latest report wins. Each
361
- team's result is its points, or `'won'` or `'lost'` if that is all you know.
362
- The score is for a video of one game.
362
+ it has it yet. Report again to correct a score; the latest report wins. A
363
+ score someone enters in PB Vision itself stands, though: a report never
364
+ replaces it, and `applied` is false. Each team's result is its points, or
365
+ `'won'` or `'lost'` if that is all you know. The score is for a video of one
366
+ game.
363
367
 
364
368
  ### Video Editors and Viewers
365
369
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@pbvision/partner-sdk",
3
3
  "description": "SDK for interacting with the PB Vision pickleball AI engine.",
4
- "version": "0.1.19",
4
+ "version": "0.1.20",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "engines": {
package/src/index.js CHANGED
@@ -139,13 +139,14 @@ export class PBVision {
139
139
  * @param {VideoMetadata} [metadata]
140
140
  * @returns {VideoUrlToDownloadResponse}
141
141
  */
142
- async sendVideoUrlToDownload (videoUrl, { userEmails = [], name, desc, gameStartEpoch, facility, court, fid, playersForTagging } = {}) {
142
+ async sendVideoUrlToDownload (videoUrl, { userEmails = [], name, desc, gameStartEpoch, facility, court, fid, playersFolderPath, playersForTagging } = {}) {
143
143
  assert(typeof videoUrl === 'string' && videoUrl.startsWith('http'),
144
144
  'URL must be a string beginning with http')
145
145
  assert(videoUrl.split('?')[0].endsWith('.mp4'), 'video URL must have the .mp4 extension')
146
+ assertFolderPath(playersFolderPath)
146
147
  const resp = await this.__callAPI(
147
148
  'add_video_by_url',
148
- { url: videoUrl, userEmails, name, desc, gameStartEpoch, facility, court, fid, playersForTagging })
149
+ { url: videoUrl, userEmails, name, desc, gameStartEpoch, facility, court, fid, playersFolderPath, playersForTagging })
149
150
  return JSON.parse(resp)
150
151
  }
151
152
 
@@ -182,6 +183,12 @@ export class PBVision {
182
183
  * @property {integer} [fid] the ID of the folder in your partner account's
183
184
  * library to add this video to (see getOrCreateFolder()). A fid that is
184
185
  * not one of your folders is refused.
186
+ * @property {Array<string>} [playersFolderPath] where this video goes in
187
+ * the PB Vision library of everyone it's shared with: the folder names
188
+ * from the top of their library down, e.g. ['Mon Oct 19 open play'] or
189
+ * ['Open play', 'Oct 19']. Folders they don't have are made for them.
190
+ * 1 to 5 names, each 1 to 200 characters with no leading or trailing
191
+ * whitespace.
185
192
  * @property {PlayersForTagging} [playersForTagging] the players to tag
186
193
  * automatically once processing completes, each by a name, an email, or
187
194
  * both. Identify players by their role at the start of the first game.
@@ -238,9 +245,10 @@ export class PBVision {
238
245
  * no `vid`, when the account paying for the video can't pay for it; for
239
246
  * passthrough partners it is always present.
240
247
  */
241
- async makeVideoId ({ fileExt = 'mp4', userEmails = [], name, desc, gameStartEpoch, facility, court, fid, playersForTagging, nonce } = {}) {
248
+ async makeVideoId ({ fileExt = 'mp4', userEmails = [], name, desc, gameStartEpoch, facility, court, fid, playersFolderPath, playersForTagging, nonce } = {}) {
249
+ assertFolderPath(playersFolderPath)
242
250
  const resp = await this.__callAPI('make_video_id',
243
- { platform: getPlatform(), fileExt, userEmails, name, desc, gameStartEpoch, facility, court, fid, playersForTagging, nonce })
251
+ { platform: getPlatform(), fileExt, userEmails, name, desc, gameStartEpoch, facility, court, fid, playersFolderPath, playersForTagging, nonce })
244
252
  const { hasCredits, vid } = JSON.parse(resp)
245
253
  const ret = { vid, uid: this.uid }
246
254
  if (hasCredits !== undefined) {
@@ -262,6 +270,8 @@ export class PBVision {
262
270
  * @property {string} [court] the court where the game is played
263
271
  * @property {integer} [fid] the ID of the folder in your partner account's
264
272
  * library to add the video to (see getOrCreateFolder())
273
+ * @property {Array<string>} [playersFolderPath] where the video goes in
274
+ * the library of everyone it's shared with (see VideoMetadata)
265
275
  * @property {PlayersForTagging} [playersForTagging] the players to tag
266
276
  * automatically once processing completes
267
277
  * @property {string} [nonce] identifies the game, e.g. your own ID for it:
@@ -320,7 +330,7 @@ export class PBVision {
320
330
  */
321
331
  async makeRecordingLink ({
322
332
  resolution = '1080p', fps = 30, mayChangeResolution = false, mayChangeFPS = false,
323
- gameStartEpoch, userEmails, name, desc, facility, court, fid, playersForTagging, nonce
333
+ gameStartEpoch, userEmails, name, desc, facility, court, fid, playersFolderPath, playersForTagging, nonce
324
334
  } = {}) {
325
335
  assert(gameStartEpoch === undefined,
326
336
  'makeRecordingLink() does not take gameStartEpoch: the game\'s time comes from its recording, and a time set now would override it')
@@ -329,6 +339,7 @@ export class PBVision {
329
339
  assert(RECORDING_FPS.includes(fps), `fps must be 30 or 60, not ${JSON.stringify(fps)}`)
330
340
  assert(typeof mayChangeResolution === 'boolean', 'mayChangeResolution must be a boolean')
331
341
  assert(typeof mayChangeFPS === 'boolean', 'mayChangeFPS must be a boolean')
342
+ assertFolderPath(playersFolderPath)
332
343
 
333
344
  // checked before making the video, so a 4K link that PB Vision wouldn't
334
345
  // analyze never gets one; only a yes is remembered, so an account that
@@ -338,7 +349,7 @@ export class PBVision {
338
349
  }
339
350
 
340
351
  const { vid, uid, hasCredits } = await this.makeVideoId({
341
- fileExt: 'mp4', userEmails, name, desc, facility, court, fid, playersForTagging, nonce })
352
+ fileExt: 'mp4', userEmails, name, desc, facility, court, fid, playersFolderPath, playersForTagging, nonce })
342
353
  if (hasCredits === false) {
343
354
  throw new Error('PB Vision did not make a video for this recording link: the account paying for it has no credits available (hasCredits is false)')
344
355
  }
@@ -369,9 +380,11 @@ export class PBVision {
369
380
  /**
370
381
  * @typedef {Object} SetGameScoreResponse
371
382
  * @property {string} vid the video
372
- * @property {boolean} applied whether the game has the score yet; false
373
- * while the video awaits processing, which gives the game the score when
374
- * it finishes
383
+ * @property {boolean} applied whether the game has the score now. While
384
+ * the video awaits processing, false, and processing gives the game the
385
+ * score when it finishes. After, false means the game keeps the score it
386
+ * has: someone entered it in PB Vision, or PB Vision couldn't tell which
387
+ * team served first
375
388
  */
376
389
 
377
390
  /**
@@ -380,7 +393,8 @@ export class PBVision {
380
393
  * first serve, as playersForTagging names the players: the team that
381
394
  * served the first point, and the team that received it. You can report
382
395
  * before the video is processed, or even recorded. Report again to correct
383
- * it: the latest report wins.
396
+ * it: the latest report wins, though never over a score someone entered in
397
+ * PB Vision itself.
384
398
  *
385
399
  * @param {Object} score
386
400
  * @param {string} [score.vid] the video; give this or nonce
@@ -646,6 +660,12 @@ async function startResumableUpload (bucket, objName, numBytesTotal) {
646
660
  }
647
661
  }
648
662
 
663
+ // playersFolderPath is a list of folder names, not a single name
664
+ function assertFolderPath (playersFolderPath) {
665
+ assert(playersFolderPath === undefined || Array.isArray(playersFolderPath),
666
+ 'playersFolderPath must be an array of folder names, e.g. [\'Mon Oct 19 open play\']')
667
+ }
668
+
649
669
  // GCS asks clients to retry these, with exponential backoff
650
670
  function isTemporaryStatus (status) {
651
671
  return status >= 500 || status === 408 || status === 429