Spaces:
Sleeping
Sleeping
File size: 3,932 Bytes
da819ac |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 |
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); |