-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathProgram.fs
155 lines (137 loc) · 6.83 KB
/
Program.fs
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
open Argu
open CDG
open CDG.ImageProcessing
open CDG.KaraokeGenerator
open CDG.LrcToKaraoke
open CDG.LrcParser
open CDG.Serializer
open SixLabors.ImageSharp
open System
open System.IO
open System.Text.RegularExpressions
type FormatArgs =
| [<AltCommandLine("-f")>] File_Path of path:string
interface IArgParserTemplate with
member this.Usage =
match this with
| File_Path _ -> "The path to the .cdg file."
type ExplainArgs =
| [<AltCommandLine("-f")>] File_Path of path:string
interface IArgParserTemplate with
member this.Usage =
match this with
| File_Path _ -> "The path to the .cdg file."
type RenderImagesArgs =
| [<AltCommandLine("-f")>] File_Path of path:string
| [<AltCommandLine("-o")>] Output_Directory of path:string
interface IArgParserTemplate with
member this.Usage =
match this with
| File_Path _ -> "The path to the .cdg file."
| Output_Directory _ -> "The target directory for the output images."
type ConvertLrcArgs =
| [<AltCommandLine("-f")>] File_Path of path:string
| [<AltCommandLine("-u")>] Uppercase_Text
| [<AltCommandLine("-m")>] Modify_Timestamps of seconds:float
| Bg_Color of color:string
| Text_Color of color:string
| Sung_Text_Color of color:string
| Font of name_or_path:string
| Font_Size of size:int
| Font_Style of name:string
interface IArgParserTemplate with
member this.Usage =
match this with
| File_Path _ -> "The path to the .lrc file."
| Uppercase_Text _ -> "Transform text to uppercase."
| Modify_Timestamps _ -> "Modify every timestamp in the .lrc file to align the lyrics with the audio file."
| Bg_Color _ -> "Background color (RGB, 4 bits per channel, defaults to '#008')."
| Text_Color _ -> "Text color (RGB, 4 bits per channel, defaults to '#FFF')."
| Sung_Text_Color _ -> "Text color for sung text (RGB, 4 bits per channel, defaults to '#666')."
| Font _ -> "Name of a system font or path to a custom font, defaults to 'Arial'."
| Font_Size _ -> "Font size, defaults to '16'."
| Font_Style _ -> "Font style, 'Regular' or 'Bold', defaults to 'Regular'."
type CliArgs =
| [<CliPrefix(CliPrefix.None)>] Format of ParseResults<FormatArgs>
| [<CliPrefix(CliPrefix.None)>] Explain of ParseResults<ExplainArgs>
| [<CliPrefix(CliPrefix.None)>] Render_Images of ParseResults<RenderImagesArgs>
| [<CliPrefix(CliPrefix.None)>] Convert_Lrc of ParseResults<ConvertLrcArgs>
interface IArgParserTemplate with
member this.Usage =
match this with
| Format _ -> "Format packets of a .cdg file."
| Explain _ -> "Explain packets of a .cdg file."
| Render_Images _ -> "Render images of a .cdg file."
| Convert_Lrc _ -> "Convert an .lrc file into a .cdg file."
let parseColorChannel v =
Convert.ToByte(v, 16)
let parseColor (v: string) =
let m = Regex.Match(v, "^#([0-9A-F]){3}$")
if m.Success then
let r = m.Groups.[1].Captures.[0].Value |> parseColorChannel
let g = m.Groups.[1].Captures.[1].Value |> parseColorChannel
let b = m.Groups.[1].Captures.[2].Value |> parseColorChannel
{ Red = ColorChannel r; Green = ColorChannel g; Blue = ColorChannel b }
else failwith $"Can't parse \"%s{v}\" as color."
let parseFontStyle (v: string) =
if v.Equals("Regular", StringComparison.InvariantCultureIgnoreCase) then Regular
elif v.Equals("Bold", StringComparison.InvariantCultureIgnoreCase) then Bold
else failwith $"Can't parse \"%s{v}\" as font style."
[<EntryPoint>]
let main args =
try
let parser = ArgumentParser.Create<CliArgs>()
let parseResults = parser.ParseCommandLine(inputs = args)
match parseResults.GetSubCommand() with
| Format v ->
let filePath = v.GetResult(FormatArgs.File_Path)
Formatter.formatFile filePath
| Explain v ->
let filePath = v.GetResult(ExplainArgs.File_Path)
Explainer.explainFile filePath
| Render_Images v ->
let filePath = v.GetResult(RenderImagesArgs.File_Path)
let targetDir =
let baseDir = v.GetResult(RenderImagesArgs.Output_Directory, defaultValue = ".")
Path.Combine(baseDir, Path.GetFileNameWithoutExtension(filePath))
try
Directory.Delete(targetDir, recursive = true)
with :? DirectoryNotFoundException -> ()
Directory.CreateDirectory(targetDir) |> ignore
ImageRenderer.renderImagesFromFile filePath
|> Seq.iter (fun (time, image) -> image.SaveAsBmp(Path.Combine(targetDir, $"{(time):``mm\-ss\-fffffff``}.bmp")))
| Convert_Lrc v ->
let filePath = v.GetResult(ConvertLrcArgs.File_Path)
let targetFilePath = Path.ChangeExtension(filePath, ".cdg")
let uppercaseText = v.Contains(ConvertLrcArgs.Uppercase_Text)
let modifyTimes = v.GetResult(ConvertLrcArgs.Modify_Timestamps, defaultValue = 0.) |> TimeSpan.FromSeconds
let settings = {
BackgroundColor =
v.TryPostProcessResult(ConvertLrcArgs.Bg_Color, parseColor)
|> Option.defaultValue { Red = ColorChannel 0uy; Green = ColorChannel 0uy; Blue = ColorChannel 8uy }
DefaultTextColor =
v.TryPostProcessResult(ConvertLrcArgs.Text_Color, parseColor)
|> Option.defaultValue { Red = ColorChannel 15uy; Green = ColorChannel 15uy; Blue = ColorChannel 15uy }
SungTextColor =
v.TryPostProcessResult(ConvertLrcArgs.Sung_Text_Color, parseColor)
|> Option.defaultValue { Red = ColorChannel 6uy; Green = ColorChannel 6uy; Blue = ColorChannel 6uy }
DefaultFont = {
Type =
v.GetResult(ConvertLrcArgs.Font, defaultValue = "Arial")
|> fun v -> if File.Exists v then CustomFont v else SystemFont v
Size = v.GetResult(ConvertLrcArgs.Font_Size, defaultValue = 16)
Style =
v.TryPostProcessResult(ConvertLrcArgs.Font_Style, parseFontStyle)
|> Option.defaultValue Regular
}
}
LrcFile.parseFile filePath
|> if uppercaseText then LrcFile.textToUpper else id
|> if modifyTimes <> TimeSpan.Zero then LrcFile.modifyTimes (fun v -> v.Add(modifyTimes)) else id
|> LrcToKaraoke.getKaraokeCommands settings
|> KaraokeGenerator.generate
|> Serializer.serializePackets
|> fun content -> File.WriteAllBytes(targetFilePath, content)
with e ->
printfn "%s" e.Message
0