unified-video-framework
Version:
Cross-platform video player framework supporting iOS, Android, Web, Smart TVs (Samsung/LG), Roku, and more
155 lines • 5.99 kB
JavaScript
export const parseTime = (isoString) => {
return new Date(isoString).getTime();
};
export const formatTime = (timestamp, format = '12h') => {
const date = new Date(timestamp);
const hours = date.getHours();
const minutes = date.getMinutes();
if (format === '24h') {
return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}`;
}
const displayHours = hours === 0 ? 12 : hours > 12 ? hours - 12 : hours;
const ampm = hours >= 12 ? 'PM' : 'AM';
return `${displayHours}:${minutes.toString().padStart(2, '0')} ${ampm}`;
};
export const formatDateTime = (timestamp) => {
const date = new Date(timestamp);
const today = new Date();
const tomorrow = new Date(today);
tomorrow.setDate(today.getDate() + 1);
if (date.toDateString() === today.toDateString()) {
return `Today ${formatTime(timestamp)}`;
}
if (date.toDateString() === tomorrow.toDateString()) {
return `Tomorrow ${formatTime(timestamp)}`;
}
const options = {
weekday: 'short',
month: 'short',
day: 'numeric',
hour: 'numeric',
minute: '2-digit',
hour12: true,
};
return date.toLocaleDateString('en-US', options);
};
export const getProgramDuration = (program) => {
const start = parseTime(program.since);
const end = parseTime(program.till);
return Math.round((end - start) / (1000 * 60));
};
export const generateTimeSlots = (startTime, visibleHours, slotDuration = 60) => {
const slots = [];
const slotMs = slotDuration * 60 * 1000;
const roundedStart = Math.floor(startTime / slotMs) * slotMs;
for (let i = 0; i <= visibleHours; i++) {
const timestamp = roundedStart + (i * slotMs);
const date = new Date(timestamp);
const hour = date.getHours();
slots.push({
hour,
label: formatTime(timestamp),
timestamp,
});
}
return slots;
};
export const calculateProgramBlock = (program, channel, timelineStart, timelineEnd, containerWidth, channelHeight = 80, maxProgramWidth = 280, programGap = 4) => {
const programStart = parseTime(program.since);
const programEnd = parseTime(program.till);
if (programEnd <= timelineStart || programStart >= timelineEnd) {
return null;
}
const visibleStart = Math.max(programStart, timelineStart);
const visibleEnd = Math.min(programEnd, timelineEnd);
const visibleDuration = visibleEnd - visibleStart;
const totalTimelineRange = timelineEnd - timelineStart;
const calculatedWidth = (visibleDuration / totalTimelineRange) * containerWidth;
const width = Math.round(Math.max(10, calculatedWidth));
const left = Math.round(((visibleStart - timelineStart) / totalTimelineRange) * containerWidth);
return {
program,
channel,
start: programStart,
end: programEnd,
duration: programEnd - programStart,
width,
left,
};
};
export const isProgramLive = (program, currentTime = Date.now()) => {
const start = parseTime(program.since);
const end = parseTime(program.till);
return currentTime >= start && currentTime < end;
};
export const getProgramProgress = (program, currentTime = Date.now()) => {
const start = parseTime(program.since);
const end = parseTime(program.till);
if (currentTime < start)
return 0;
if (currentTime >= end)
return 100;
return ((currentTime - start) / (end - start)) * 100;
};
export const findProgramAtTime = (channel, timestamp) => {
return channel.data.find(program => {
const start = parseTime(program.since);
const end = parseTime(program.till);
return timestamp >= start && timestamp < end;
}) || null;
};
export const getCurrentTimePosition = (currentTime, timelineStart, timelineEnd, containerWidth) => {
if (currentTime < timelineStart || currentTime > timelineEnd) {
return -1;
}
const totalRange = timelineEnd - timelineStart;
const elapsed = currentTime - timelineStart;
return (elapsed / totalRange) * containerWidth;
};
export const snapToTimeSlot = (timestamp, slotDuration = 60) => {
const slotMs = slotDuration * 60 * 1000;
return Math.round(timestamp / slotMs) * slotMs;
};
export const calculateOptimalTimeRange = (currentTime = Date.now(), visibleHours = 4) => {
const currentHour = new Date(currentTime);
currentHour.setMinutes(0, 0, 0);
const start = currentHour.getTime() - (60 * 60 * 1000);
const end = start + (visibleHours * 60 * 60 * 1000);
return { start, end };
};
export const getProgramsInRange = (channels, startTime, endTime, paddingHours = 1) => {
const paddingMs = paddingHours * 60 * 60 * 1000;
const extendedStart = startTime - paddingMs;
const extendedEnd = endTime + paddingMs;
return channels.map(channel => ({
...channel,
data: channel.data.filter(program => {
const programStart = parseTime(program.since);
const programEnd = parseTime(program.till);
return programEnd > extendedStart && programStart < extendedEnd;
}),
}));
};
export const calculateScrollPosition = (targetTime, timelineStart, timelineEnd, containerWidth, visibleWidth) => {
const timelineRange = timelineEnd - timelineStart;
const targetPosition = ((targetTime - timelineStart) / timelineRange) * containerWidth;
return Math.max(0, targetPosition - (visibleWidth / 2));
};
export const debounce = (func, wait) => {
let timeout;
return (...args) => {
clearTimeout(timeout);
timeout = setTimeout(() => func(...args), wait);
};
};
export const throttle = (func, limit) => {
let inThrottle;
return (...args) => {
if (!inThrottle) {
func(...args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
};
//# sourceMappingURL=EPGUtils.js.map