feat: download meeting transcripts via SharePoint Stream#20
Merged
Conversation
Add `recordings` and `transcript` commands to list meeting recordings shared in a chat and download their transcripts, without using Graph. - recordings: parse RichText/Media_CallRecording messages (URIObject with a SharePoint sharing link); list with index, name, and date - transcript: resolve the recording (shares API -> media/transcripts expand -> JSON download) and convert to WebVTT, speaker-grouped text, or raw JSON (--format vtt|grouped|json, -o output, '-' for stdout) - SharePoint tokens aren't in localStorage; acquire on demand by opening the recording headlessly and intercepting the Bearer token off the player's /_api/ request, cached per host in tokens.sharepoint[host] - index.ts: print a clean error message instead of a raw stack trace - unit + mocked-fetch tests for converters, parser, and API functions - docs: CLAUDE.md, ARCHITECTURE.md, README.md, skill
Coverage Report
File Coverage
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||
Acquiring a SharePoint token by navigating straight to the recording's share link fails from a clean login: the browser profile has no SharePoint session (the Teams login never visits SharePoint), so the :v: link returns 'cannot access' and no /_api/ call fires. Navigate to the host root first, which triggers the SSO login redirect that establishes the session; the OneDrive/site SPA then makes an authenticated /_api/ call we can intercept. Keep the recording link as a fallback warmup, and ignore sub-100-char placeholder auth headers.
|
🎉 This PR is included in version 1.1.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds two commands to download Microsoft Teams meeting transcripts, without using Microsoft Graph (consistent with the repo's design rule):
teams recordings <chat>— lists meeting recordings shared in a chat (index, name, date)teams transcript <chat> [index]— downloads a recording's transcript as WebVTT (default), speaker-grouped text, or raw JSON (--format vtt|grouped|json,-o <path>,-for stdout)How it works
Teams stores recordings/transcripts in SharePoint/Stream, so this adds a fourth API surface:
parseRecordings()scans the meeting chat forRichText/Media_CallRecordingmessages (a<URIObject>carrying a SharePoint sharing link).resolveDriveItem()→GET /_api/v2.0/shares/u!{base64url}/driveItemfor{driveId, itemId}.getTranscriptMetadata()→GET /_api/v2.1/drives/.../items/...?$expand=media/transcriptsfor thetemporaryDownloadUrl.downloadTranscriptJson()fetches it with?format=json; converters produce VTT / grouped text.SharePoint token acquisition
SharePoint tokens aren't in localStorage (the Stream player holds them in memory). So on the first
transcriptfor a host, the recording is opened headlessly in the persistent browser profile and theBearertoken is intercepted off the player's/_api/request, then cached per host intokens.sharepoint[host].Testing
recordingslists 3 recordings;transcriptproduces valid VTT (313 cues), grouped text, and raw JSON. Old recordings with cleaned-up share links fail gracefully with a clear message.Notes