Miva LMS Study Assistant is a full-stack, modular web application that automates the study-material workflow for Miva Open University students. It logs into Miva Open University's portal through the SIS→LMS SSO redirect, downloads the week's PDF slides, intercepts closed-caption WebVTT transcripts from embedded Vimeo lecture videos, parses the PDF text, and synthesizes a comprehensive Markdown study guide using Gemini 2.5 Flash.
The product exists to remove four hours of manual re-reading and re-watching from a student's week. The student supplies a course name, a week identifier, and the target LMS week URL; the system performs authentication, extraction, parsing, and synthesis; the student reads the rendered study notes, inspects the raw extracted context, reviews the downloaded file list, and downloads the finished .md document.
Audience: Miva Open University students who are technically literate enough to run a Playwright-based pipeline, who study late and under time pressure, and who want the output to feel like a finished gift rather than a raw dump.
The current delivery is a single-operator, self-service automation tool with an application-owned identity layer, a protected run workspace, and a protected results surface.
Actors
https://sis.miva.university) — external identity provider and login surface. Owns credential verification and the OAuth handshake.https://lms.miva.university/**) — external content host. Owns the week page, the PDF resources, and the embedded Vimeo players..vtt / text-track endpoints the pipeline listens for.gemini-2.5-flash) — external synthesis provider. Owns note generation from the unified context payload.Accepted behavior in scope
sis.miva.university with a page.wait_for_url() wait on the cross-domain redirect to lms.miva.university/**.miva_session.json via context.storage_state(), reuse via browser.new_context(storage_state="miva_session.json"), and expiry recovery that deletes the file and re-authenticates.page.on("response", handle_response") filtering for .vtt, texttrack, and Vimeo caption tracks, plus iframe discovery and play-button triggering.WEBVTT headers, timestamp cues, and inline HTML tags.downloads/week_content/.pdfplumber and a pypdf fallback, plus the zero-character scanned-PDF warning.=== VIMEO LECTURE TRANSCRIPT === and === DOCUMENT: <filename> === markers.temperature=0.2 under a strict academic-tutor system instruction producing a four-section Markdown study guide.playwright install chromium, directory creation, and try/except wrapping of navigation and selector interactions.Narrow exclusions
system-ui typefaces.The product is delivered as a first-party web application with its own identity layer, because the student must privately own and resume durable generated study materials across sessions. The application owns the Landing, Sign Up, Login, Dashboard, Session, Pipeline, Notes, Context, and Files surfaces. The Miva SIS login form, the Miva LMS week page, and the Vimeo player remain provider-owned surfaces that the pipeline drives but does not replace; the student never types Miva credentials into this application's own forms — those credentials live in .env as PORTAL_USER and PORTAL_PASS and are consumed by the automation layer.
The application's own identity is separate from the Miva SSO session. Application identity governs access to saved run configuration and generated results. The Miva SSO session governs access to the LMS content and is persisted separately to miva_session.json.
Everything described in this document is current. No future-horizon capabilities are accepted.
Not applicable — no reference directive in this project declares content_source.
#111318 ink panel with four stacked monospace pipeline rows, each with a status dot; right 58% #F5F2EC paper panel with an oversized real Markdown study-note fragment starting mid-sentence, headed Data Science — Week 1.miva_session.json · valid.sis.miva.university → [OAuth] → lms.miva.university/** with a small orange dot marking the wait_for_url() handshake.PORTAL_USER, PORTAL_PASS, and GEMINI_API_KEY, and holds the run configuration for the next pipeline execution.Data Science).Week 1)..env or fill the missing field and re-check.miva_session.json currently exists and is being reused.miva_session.json, so the next pipeline run authenticates again. Supporting action: Return to Dashboard.miva_session.json, session validity.Authenticating at sis.miva.university / Restoring session...Intercepting Vimeo transcripts & downloading PDFs from LMS...Parsing PDF text buffers & cleaning VTT captions...Synthesizing notes with Gemini 2.5 Flash....md file in output_notes/.# [Course Name] — Week [Number] Study Notes.**Term**: Definition and context referenced in lectures or slides.#FF4A1C top border that thickens to 3px on hover.output_notes/). Empty (no notes generated for this run yet). Success (notes rendered and downloadable). Error (synthesis failed or the output file is unreadable) with a route back to Pipeline. Recovery: re-run the pipeline from Pipeline.=== VIMEO LECTURE TRANSCRIPT === marker, === DOCUMENT: <filename> === marker, WebVTT cue, cleaned transcript sentence, scanned-PDF warning.=== DOCUMENT: Lecture_Slides_Week1.pdf === rendered as a sticky monospace section header with a 1px ink rule, as literal UI chrome rather than escaped text.00:01:20 --> 00:01:23) rendered struck through in muted grey directly above their cleaned sentence, so the cleaning step is shown rather than hidden.[WARNING: Scanned/Image PDF detected for <filename>] rendered inline where a PDF yielded zero characters.downloads/week_content/.downloads/week_content/ with hairline connectors.#7A756C) for timestamps, file sizes, and metadata rows.FR-1 — SSO login flow (explicit)
As a Miva Open University Student, I should have the pipeline start at https://sis.miva.university, fill in PORTAL_USER and PORTAL_PASS, submit the form, and wait for the cross-domain OAuth redirect to https://lms.miva.university/** using page.wait_for_url(), so that the automation reaches the LMS without me logging in by hand.
lms.miva.university/** URL.miva_session.json is deleted, and re-authentication is attempted.FR-2 — Session storage (explicit)
As a Miva Open University Student, I should have the browser context saved to miva_session.json using context.storage_state() after a successful login, so that later runs do not repeat the login form.
miva_session.json exists on disk.FR-3 — Session reuse (explicit)
As a Miva Open University Student, I should have subsequent runs check whether miva_session.json exists and load it into browser.new_context(storage_state="miva_session.json") to bypass the login form, so that repeat runs start faster.
miva_session.json is deleted, and re-authentication is performed.FR-4 — Vimeo transcript interception (explicit)
As a Miva Open University Student, I should have the pipeline attach page.on("response", handle_response") and inspect all incoming response URLs for .vtt, texttrack, or Vimeo caption tracks, so that lecture captions are captured automatically.
FR-5 — WebVTT cleaning (explicit)
As a Miva Open University Student, I should have raw WebVTT text cleaned by stripping WEBVTT headers, timestamp cues (00:01:20 --> 00:01:23), and inline HTML tags (<c>, <i>), so that the transcript reads as prose.
FR-6 — Vimeo iframe handling (explicit)
As a Miva Open University Student, I should have the pipeline find all embedded <iframe> elements matching vimeo.com on the LMS page and trigger play button clicks to force the player to load caption network requests, so that captions are requested even when the player has not been played.
FR-7 — PDF downloads (explicit)
As a Miva Open University Student, I should have the pipeline locate all downloadable PDF links (a[href*='.pdf'] or a[href*='resource/view.php']) and download the files into downloads/week_content/, so that the week's slides are available locally.
downloads/week_content/.FR-8 — PDF text extraction with fallback (explicit)
As a Miva Open University Student, I should have every PDF in downloads/week_content/ read using pdfplumber, falling back to pypdf if pdfplumber fails, so that slide text is extracted even from awkward files.
downloads/week_content/.pdfplumber failure triggers the pypdf fallback for that file.FR-9 — Unified context payload (explicit)
As a Miva Open University Student, I should have all extracted PDF texts and intercepted Vimeo transcripts formatted into a unified context payload using === VIMEO LECTURE TRANSCRIPT === and === DOCUMENT: <filename> === section markers, so that the synthesis input is legible and traceable.
FR-10 — Scanned-PDF warning (explicit)
As a Miva Open University Student, I should have [WARNING: Scanned/Image PDF detected for <filename>] appended when a PDF yields zero characters, so that I know which slides contributed no text.
FR-11 — Gemini synthesis call (explicit)
As a Miva Open University Student, I should have the Google GenAI client initialized with from google import genai and gemini-2.5-flash called with temperature=0.2 and the strict academic-tutor system instruction, so that the study guide is generated under controlled, low-variance conditions.
output_notes/ and rendered on Notes.FR-12 — Required study-guide structure (explicit)
As a Miva Open University Student, I should receive a study guide structured as # [Course Name] — Week [Number] Study Notes with section 1. Executive Summary (3 to 4 sentences synthesizing spoken lecture points and slide readings), section 2. Key Terminology & Definitions (**Term**: Definition and context referenced in lectures or slides.), section 3. Core Concepts & Lecture Breakdown (topics grouped into logical subsections synthesizing slide theories alongside key verbal points or emphasis made by the lecturer during the video), and section 4. Practice & Exam Review Questions (5 high-yield revision questions with brief answer hints), so that the output is a consistent, exam-oriented revision document.
.md.FR-13 — Environment status check (explicit)
As a Miva Open University Student, I should see a status check for PORTAL_USER, PORTAL_PASS, and GEMINI_API_KEY in the sidebar, so that I know whether the run can proceed before starting it.
.env..env or proceeds once all three are present.FR-14 — Run configuration fields (explicit)
As a Miva Open University Student, I should have fields for Course Name (e.g., Data Science), Week Identifier (e.g., Week 1), and Target LMS Week URL, so that the run is scoped to the correct week.
FR-15 — Clear Saved Session (explicit)
As a Miva Open University Student, I should have a Clear Saved Session button that removes miva_session.json, so that the next run authenticates again when the saved session is stale or belongs to the wrong account.
miva_session.json no longer exists.FR-16 — Run action (explicit) As a Miva Open University Student, I should have a Run Auto-Extraction & Generate Notes action button, so that I can start the whole pipeline with one action.
FR-17 — Live progress tracker (explicit)
As a Miva Open University Student, I should see a live progress tracker showing Authenticating at sis.miva.university / Restoring session..., Intercepting Vimeo transcripts & downloading PDFs from LMS..., Parsing PDF text buffers & cleaning VTT captions..., and Synthesizing notes with Gemini 2.5 Flash..., so that I can tell which stage the run is in.
FR-18 — Study Notes tab (explicit) As a Miva Open University Student, I should see Tab 1: Study Notes as a rendered Markdown preview with a Download Notes (.md) button, so that I can read and keep the generated guide.
.md or switches tabs.FR-19 — Extracted Context tab (explicit) As a Miva Open University Student, I should see Tab 2: Extracted Context showing the combined PDF text plus intercepted Vimeo transcripts, so that I can verify what the synthesis was based on.
FR-20 — Downloaded Files tab *(

miva_session.json · valid
…and the cleaned lecture transcript aligns with the slide definitions, so gradient descent here is a descent on the loss surface rather than a claim about the optimiser’s speed. The lecturer restates the learning-rate trade-off twice, and the terms below are the ones you are most likely to be examined on.
The run does not poll for the redirect. It calls page.wait_for_url() and holds until the browser lands on the LMS host — the single orange mark above sits on that endpoint, not on the OAuth hop. Once the session is stored to miva_session.json, later runs reload the context and skip this diagram entirely.
Entry
Sign in once and the assistant runs the wholelogininterceptparsesynthesizesequence for the week you name, then hands you back a study guide.

miva_session.json · valid
…and the cleaned lecture transcript aligns with the slide definitions, so gradient descent here is a descent on the loss surface rather than a claim about the optimiser’s speed. The lecturer restates the learning-rate trade-off twice, and the terms below are the ones you are most likely to be examined on.
The run does not poll for the redirect. It calls page.wait_for_url() and holds until the browser lands on the LMS host — the single orange mark above sits on that endpoint, not on the OAuth hop. Once the session is stored to miva_session.json, later runs reload the context and skip this diagram entirely.
Entry
Sign in once and the assistant runs the wholelogininterceptparsesynthesizesequence for the week you name, then hands you back a study guide.
No comments yet. Be the first!