mirror of
https://github.com/mediacms-io/mediacms.git
synced 2025-12-09 21:42:31 -05:00
Compare commits
2 Commits
c035bcddf5
...
ba2c31b1e6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ba2c31b1e6 | ||
|
|
5eb6fafb8c |
@@ -26,18 +26,6 @@ const mediaPageLinkStyles = {
|
|||||||
},
|
},
|
||||||
} as const;
|
} as const;
|
||||||
|
|
||||||
// Helper function to parse time string (HH:MM:SS.mmm) to seconds
|
|
||||||
const parseTimeToSeconds = (timeString: string): number => {
|
|
||||||
const parts = timeString.split(':');
|
|
||||||
if (parts.length !== 3) return 0;
|
|
||||||
|
|
||||||
const hours = parseInt(parts[0], 10) || 0;
|
|
||||||
const minutes = parseInt(parts[1], 10) || 0;
|
|
||||||
const seconds = parseFloat(parts[2]) || 0;
|
|
||||||
|
|
||||||
return hours * 3600 + minutes * 60 + seconds;
|
|
||||||
};
|
|
||||||
|
|
||||||
interface TimelineControlsProps {
|
interface TimelineControlsProps {
|
||||||
currentTime: number;
|
currentTime: number;
|
||||||
duration: number;
|
duration: number;
|
||||||
@@ -203,17 +191,7 @@ const TimelineControls = ({
|
|||||||
setIsAutoSaving(true);
|
setIsAutoSaving(true);
|
||||||
|
|
||||||
// Format segments data for API request - use ref to get latest segments and sort by start time
|
// Format segments data for API request - use ref to get latest segments and sort by start time
|
||||||
// ONLY save chapters that have custom titles - filter out chapters without titles or with default names
|
|
||||||
const chapters = clipSegmentsRef.current
|
const chapters = clipSegmentsRef.current
|
||||||
.filter((segment) => {
|
|
||||||
// Filter out empty titles
|
|
||||||
if (!segment.chapterTitle || !segment.chapterTitle.trim()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Filter out default chapter names like "Chapter 1", "Chapter 2", etc.
|
|
||||||
const isDefaultName = /^Chapter \d+$/.test(segment.chapterTitle);
|
|
||||||
return !isDefaultName;
|
|
||||||
})
|
|
||||||
.sort((a, b) => a.startTime - b.startTime) // Sort by start time chronologically
|
.sort((a, b) => a.startTime - b.startTime) // Sort by start time chronologically
|
||||||
.map((chapter) => ({
|
.map((chapter) => ({
|
||||||
startTime: formatDetailedTime(chapter.startTime),
|
startTime: formatDetailedTime(chapter.startTime),
|
||||||
@@ -221,7 +199,7 @@ const TimelineControls = ({
|
|||||||
chapterTitle: chapter.chapterTitle,
|
chapterTitle: chapter.chapterTitle,
|
||||||
}));
|
}));
|
||||||
|
|
||||||
logger.debug('Filtered chapters (only custom titles):', chapters);
|
logger.debug('chapters', chapters);
|
||||||
|
|
||||||
const mediaId = (typeof window !== 'undefined' && (window as any).MEDIA_DATA?.mediaId) || null;
|
const mediaId = (typeof window !== 'undefined' && (window as any).MEDIA_DATA?.mediaId) || null;
|
||||||
// For testing, use '1234' if no mediaId is available
|
// For testing, use '1234' if no mediaId is available
|
||||||
@@ -229,13 +207,12 @@ const TimelineControls = ({
|
|||||||
|
|
||||||
logger.debug('mediaId', finalMediaId);
|
logger.debug('mediaId', finalMediaId);
|
||||||
|
|
||||||
if (!finalMediaId) {
|
if (!finalMediaId || chapters.length === 0) {
|
||||||
logger.debug('No mediaId, skipping auto-save');
|
logger.debug('No mediaId or segments, skipping auto-save');
|
||||||
setIsAutoSaving(false);
|
setIsAutoSaving(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save chapters (empty array if no chapters have titles)
|
|
||||||
logger.debug('Auto-saving segments:', { mediaId: finalMediaId, chapters });
|
logger.debug('Auto-saving segments:', { mediaId: finalMediaId, chapters });
|
||||||
|
|
||||||
const response = await autoSaveVideo(finalMediaId, { chapters });
|
const response = await autoSaveVideo(finalMediaId, { chapters });
|
||||||
@@ -291,13 +268,8 @@ const TimelineControls = ({
|
|||||||
// Update editing title when selected segment changes
|
// Update editing title when selected segment changes
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
if (selectedSegment) {
|
if (selectedSegment) {
|
||||||
// Check if the chapter title is a default generated name (e.g., "Chapter 1", "Chapter 2", etc.)
|
// Always show the chapter title in the textarea, whether it's default or custom
|
||||||
const isDefaultChapterName = selectedSegment.chapterTitle &&
|
setEditingChapterTitle(selectedSegment.chapterTitle || '');
|
||||||
/^Chapter \d+$/.test(selectedSegment.chapterTitle);
|
|
||||||
|
|
||||||
// If it's a default name, show empty string so placeholder appears
|
|
||||||
// If it's a custom title, show the actual title
|
|
||||||
setEditingChapterTitle(isDefaultChapterName ? '' : (selectedSegment.chapterTitle || ''));
|
|
||||||
} else {
|
} else {
|
||||||
setEditingChapterTitle('');
|
setEditingChapterTitle('');
|
||||||
}
|
}
|
||||||
@@ -522,20 +494,11 @@ const TimelineControls = ({
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Format chapters data for API request - sort by start time first
|
// Format chapters data for API request - sort by start time first
|
||||||
// ONLY save chapters that have custom titles - filter out chapters without titles or with default names
|
|
||||||
const chapters = clipSegments
|
const chapters = clipSegments
|
||||||
.filter((segment) => {
|
.filter((segment) => segment.chapterTitle && segment.chapterTitle.trim())
|
||||||
// Filter out empty titles
|
|
||||||
if (!segment.chapterTitle || !segment.chapterTitle.trim()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
// Filter out default chapter names like "Chapter 1", "Chapter 2", etc.
|
|
||||||
const isDefaultName = /^Chapter \d+$/.test(segment.chapterTitle);
|
|
||||||
return !isDefaultName;
|
|
||||||
})
|
|
||||||
.sort((a, b) => a.startTime - b.startTime) // Sort by start time chronologically
|
.sort((a, b) => a.startTime - b.startTime) // Sort by start time chronologically
|
||||||
.map((segment) => ({
|
.map((segment) => ({
|
||||||
chapterTitle: segment.chapterTitle,
|
chapterTitle: segment.chapterTitle || `Chapter ${segment.id}`,
|
||||||
from: formatDetailedTime(segment.startTime),
|
from: formatDetailedTime(segment.startTime),
|
||||||
to: formatDetailedTime(segment.endTime),
|
to: formatDetailedTime(segment.endTime),
|
||||||
}));
|
}));
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ const useVideoChapters = () => {
|
|||||||
// Create a default segment that spans the entire video on first load
|
// Create a default segment that spans the entire video on first load
|
||||||
const initialSegment: Segment = {
|
const initialSegment: Segment = {
|
||||||
id: 1,
|
id: 1,
|
||||||
chapterTitle: '',
|
chapterTitle: 'Chapter 1',
|
||||||
startTime: 0,
|
startTime: 0,
|
||||||
endTime: video.duration,
|
endTime: video.duration,
|
||||||
};
|
};
|
||||||
|
|||||||
19
frontend/src/static/js/utils/hoc/withBulkActions.jsx
Normal file
19
frontend/src/static/js/utils/hoc/withBulkActions.jsx
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import { useBulkActions } from '../hooks/useBulkActions';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Higher-Order Component that provides bulk actions functionality
|
||||||
|
* to class components via props
|
||||||
|
*/
|
||||||
|
export function withBulkActions(WrappedComponent) {
|
||||||
|
return function WithBulkActionsComponent(props) {
|
||||||
|
const bulkActions = useBulkActions();
|
||||||
|
|
||||||
|
return (
|
||||||
|
<WrappedComponent
|
||||||
|
{...props}
|
||||||
|
bulkActions={bulkActions}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user