summaryrefslogtreecommitdiff
path: root/apps/web/src/lib/time.ts
blob: f24c59613b4d7dc5f9d7c4d5bddd5d2a18af6799 (plain) (blame)
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
// Time-related utility functions

// Helper function to format time in various formats (MM:SS, HH:MM:SS, HH:MM:SS:CS, HH:MM:SS:FF)
export const formatTimeCode = (
  timeInSeconds: number,
  format: "MM:SS" | "HH:MM:SS" | "HH:MM:SS:CS" | "HH:MM:SS:FF" = "HH:MM:SS:CS",
  fps = 30
): string => {
  const hours = Math.floor(timeInSeconds / 3600);
  const minutes = Math.floor((timeInSeconds % 3600) / 60);
  const seconds = Math.floor(timeInSeconds % 60);
  const centiseconds = Math.floor((timeInSeconds % 1) * 100);
  const frames = Math.floor((timeInSeconds % 1) * fps);

  switch (format) {
    case "MM:SS":
      return `${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
    case "HH:MM:SS":
      return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}`;
    case "HH:MM:SS:CS":
      return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}:${centiseconds.toString().padStart(2, "0")}`;
    case "HH:MM:SS:FF":
      return `${hours.toString().padStart(2, "0")}:${minutes.toString().padStart(2, "0")}:${seconds.toString().padStart(2, "0")}:${frames.toString().padStart(2, "0")}`;
  }
};

export const parseTimeCode = (
  timeCode: string,
  format: "MM:SS" | "HH:MM:SS" | "HH:MM:SS:CS" | "HH:MM:SS:FF" = "HH:MM:SS:CS",
  fps = 30
): number | null => {
  if (!timeCode || typeof timeCode !== "string") return null;

  // Remove any extra whitespace
  const cleanTimeCode = timeCode.trim();

  try {
    switch (format) {
      case "MM:SS": {
        const parts = cleanTimeCode.split(":");
        if (parts.length !== 2) return null;
        const [minutes, seconds] = parts.map((part) => parseInt(part, 10));
        if (isNaN(minutes) || isNaN(seconds)) return null;
        if (minutes < 0 || seconds < 0 || seconds >= 60) return null;
        return minutes * 60 + seconds;
      }

      case "HH:MM:SS": {
        const parts = cleanTimeCode.split(":");
        if (parts.length !== 3) return null;
        const [hours, minutes, seconds] = parts.map((part) =>
          parseInt(part, 10)
        );
        if (isNaN(hours) || isNaN(minutes) || isNaN(seconds)) return null;
        if (
          hours < 0 ||
          minutes < 0 ||
          seconds < 0 ||
          minutes >= 60 ||
          seconds >= 60
        )
          return null;
        return hours * 3600 + minutes * 60 + seconds;
      }

      case "HH:MM:SS:CS": {
        const parts = cleanTimeCode.split(":");
        if (parts.length !== 4) return null;
        const [hours, minutes, seconds, centiseconds] = parts.map((part) =>
          parseInt(part, 10)
        );
        if (
          isNaN(hours) ||
          isNaN(minutes) ||
          isNaN(seconds) ||
          isNaN(centiseconds)
        )
          return null;
        if (
          hours < 0 ||
          minutes < 0 ||
          seconds < 0 ||
          centiseconds < 0 ||
          minutes >= 60 ||
          seconds >= 60 ||
          centiseconds >= 100
        )
          return null;
        return hours * 3600 + minutes * 60 + seconds + centiseconds / 100;
      }

      case "HH:MM:SS:FF": {
        const parts = cleanTimeCode.split(":");
        if (parts.length !== 4) return null;
        const [hours, minutes, seconds, frames] = parts.map((part) =>
          parseInt(part, 10)
        );
        if (isNaN(hours) || isNaN(minutes) || isNaN(seconds) || isNaN(frames))
          return null;
        if (
          hours < 0 ||
          minutes < 0 ||
          seconds < 0 ||
          frames < 0 ||
          minutes >= 60 ||
          seconds >= 60 ||
          frames >= fps
        )
          return null;
        return hours * 3600 + minutes * 60 + seconds + frames / fps;
      }
    }
  } catch {
    return null;
  }

  return null;
};