Spaces:
Sleeping
Sleeping
| const mongoose = require('mongoose'); | |
| const subtitleSchema = new mongoose.Schema({ | |
| segmentId: { | |
| type: Number, | |
| required: true, | |
| unique: true | |
| }, | |
| startTime: { | |
| type: String, | |
| required: true, | |
| validate: { | |
| validator: function(v) { | |
| // Validate time format: HH:MM:SS,mmm | |
| return /^\d{2}:\d{2}:\d{2},\d{3}$/.test(v); | |
| }, | |
| message: 'Start time must be in format HH:MM:SS,mmm' | |
| } | |
| }, | |
| endTime: { | |
| type: String, | |
| required: true, | |
| validate: { | |
| validator: function(v) { | |
| // Validate time format: HH:MM:SS,mmm | |
| return /^\d{2}:\d{2}:\d{2},\d{3}$/.test(v); | |
| }, | |
| message: 'End time must be in format HH:MM:SS,mmm' | |
| } | |
| }, | |
| duration: { | |
| type: String, | |
| required: true | |
| }, | |
| englishText: { | |
| type: String, | |
| required: true, | |
| trim: true | |
| }, | |
| chineseTranslation: { | |
| type: String, | |
| default: '', | |
| trim: true | |
| }, | |
| isProtected: { | |
| type: Boolean, | |
| default: false | |
| }, | |
| protectedReason: { | |
| type: String | |
| }, | |
| lastModified: { | |
| type: Date, | |
| default: Date.now | |
| }, | |
| modificationHistory: [{ | |
| action: { | |
| type: String, | |
| required: true | |
| }, | |
| timestamp: { | |
| type: Date, | |
| default: Date.now | |
| }, | |
| reason: { | |
| type: String | |
| } | |
| }] | |
| }, { | |
| timestamps: true | |
| }); | |
| // Index for efficient queries | |
| subtitleSchema.index({ segmentId: 1 }); | |
| subtitleSchema.index({ startTime: 1 }); | |
| subtitleSchema.index({ isProtected: 1 }); | |
| // Virtual for calculating duration in seconds | |
| subtitleSchema.virtual('durationInSeconds').get(function() { | |
| const start = this.parseTimeToSeconds(this.startTime); | |
| const end = this.parseTimeToSeconds(this.endTime); | |
| return end - start; | |
| }); | |
| // Method to parse time string to seconds | |
| subtitleSchema.methods.parseTimeToSeconds = function(timeString) { | |
| const parts = timeString.split(':'); | |
| const seconds = parseInt(parts[2].split(',')[0]); | |
| const minutes = parseInt(parts[1]); | |
| const hours = parseInt(parts[0]); | |
| return hours * 3600 + minutes * 60 + seconds; | |
| }; | |
| // Static method to get all subtitles ordered by segment ID | |
| subtitleSchema.statics.getAllOrdered = function() { | |
| return this.find().sort({ segmentId: 1 }); | |
| }; | |
| // Static method to get protected subtitles | |
| subtitleSchema.statics.getProtected = function() { | |
| return this.find({ isProtected: true }); | |
| }; | |
| // Static method to update subtitle safely | |
| subtitleSchema.statics.safeUpdate = function(segmentId, updateData) { | |
| return this.findOneAndUpdate( | |
| { segmentId: segmentId }, | |
| { | |
| ...updateData, | |
| lastModified: new Date(), | |
| $push: { | |
| modificationHistory: { | |
| action: 'update', | |
| timestamp: new Date(), | |
| reason: updateData.reason || 'Manual update' | |
| } | |
| } | |
| }, | |
| { new: true, runValidators: true } | |
| ); | |
| }; | |
| // Static method to protect subtitle | |
| subtitleSchema.statics.protectSubtitle = function(segmentId, reason) { | |
| return this.findOneAndUpdate( | |
| { segmentId: segmentId }, | |
| { | |
| isProtected: true, | |
| protectedReason: reason, | |
| lastModified: new Date(), | |
| $push: { | |
| modificationHistory: { | |
| action: 'protect', | |
| timestamp: new Date(), | |
| reason: reason | |
| } | |
| } | |
| }, | |
| { new: true } | |
| ); | |
| }; | |
| // Static method to unlock subtitle | |
| subtitleSchema.statics.unlockSubtitle = function(segmentId, unlockKey) { | |
| // In a real implementation, you'd verify the unlock key | |
| if (unlockKey !== 'ADMIN_UNLOCK_KEY_2024') { | |
| throw new Error('Invalid unlock key'); | |
| } | |
| return this.findOneAndUpdate( | |
| { segmentId: segmentId }, | |
| { | |
| isProtected: false, | |
| protectedReason: null, | |
| lastModified: new Date(), | |
| $push: { | |
| modificationHistory: { | |
| action: 'unlock', | |
| timestamp: new Date(), | |
| reason: 'Admin unlock' | |
| } | |
| } | |
| }, | |
| { new: true } | |
| ); | |
| }; | |
| module.exports = mongoose.model('Subtitle', subtitleSchema); |