+41
src/components/class-view.ts
+41
src/components/class-view.ts
·········
·········
+436
src/components/pending-recordings-view.ts
+436
src/components/pending-recordings-view.ts
···
···+Vote for the best quality recording. The winner will be automatically transcribed when 40% of class votes or after 30 minutes.+<div class="recording-card ${this.userVote === recording.id ? "voted" : ""} ${this.winningRecordingId === recording.id ? "winning" : ""}">
+330
-81
src/components/upload-recording-modal.ts
+330
-81
src/components/upload-recording-modal.ts
·········<option value="">Use my section ${this.userSection ? `(${this.sections.find((s) => s.id === this.userSection)?.section_number})` : ""}</option>···
······+formData.append("recording_date", Math.floor(this.selectedFile.lastModified / 1000).toString());···+style="padding: 0.75rem; border: 1px solid var(--secondary); border-radius: 4px; font-size: 0.875rem; color: var(--text); background: var(--background);"+class="meeting-time-button ${this.selectedMeetingTimeId === meeting.id ? "selected" : ""} ${this.detectedMeetingTime === meeting.id ? "detected" : ""}"<option value="">Use my section ${this.userSection ? `(${this.sections.find((s) => s.id === this.userSection)?.section_number})` : ""}</option>+<div style="background: color-mix(in srgb, var(--primary) 5%, transparent); border-radius: 8px; padding: 1rem;">+<div style="background: var(--secondary); border-radius: 4px; height: 8px; overflow: hidden;">+<div style="background: var(--accent); height: 100%; width: ${this.uploadProgress}%; transition: width 0.3s;"></div>···+<button class="btn-cancel" @click=${this.handleClose} ?disabled=${this.uploading || this.submitting}>
+40
src/db/schema.ts
+40
src/db/schema.ts
···+CREATE INDEX IF NOT EXISTS idx_recording_votes_transcription_id ON recording_votes(transcription_id);+CREATE INDEX IF NOT EXISTS idx_transcriptions_recording_date ON transcriptions(recording_date);
+357
-5
src/index.ts
+357
-5
src/index.ts
············-"INSERT INTO transcriptions (id, user_id, class_id, meeting_time_id, section_id, filename, original_filename, status) VALUES (?, ?, ?, ?, ?, ?, ?, ?)",
············+"INSERT INTO transcriptions (id, user_id, class_id, meeting_time_id, section_id, filename, original_filename, status, recording_date) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)",
+55
src/lib/audio-metadata.integration.test.ts
+55
src/lib/audio-metadata.integration.test.ts
···
···+await Bun.$`ffmpeg -f lavfi -i anullsrc=r=44100:cl=mono -t 1 -metadata creation_time=${creationTime} -y ${testAudioPath}`.quiet();
+128
src/lib/audio-metadata.test.ts
+128
src/lib/audio-metadata.test.ts
···
···
+144
src/lib/audio-metadata.ts
+144
src/lib/audio-metadata.ts
···
···+`[AudioMetadata] Extracted creation date from metadata: ${date.toISOString()} from ${filePath}`,+`[AudioMetadata] No meeting time found matching ${dayName} in available options: ${meetingTimes.map((mt) => mt.label).join(", ")}`,
+1
-1
src/lib/classes.ts
+1
-1
src/lib/classes.ts
+227
src/lib/voting.ts
+227
src/lib/voting.ts
···
···+let query = `SELECT id, user_id, filename, original_filename, vote_count, created_at, section_id+`[Voting] Auto-submitting ${topRecording.id} - reached ${topRecording.vote_count}/${voteThreshold} votes (40% threshold)`,