package shakuhachi
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A music collection manager
Install
dune-project
Dependency
Authors
Maintainers
Sources
0.3.2.tar.gz
sha256=c72807d303de137441b643fec1c7630c930ebc792b576783c7961b237c2114db
sha512=770f878bbdac8033d90e904ce8e9c84fc75331c7ff9b35e2204fafe3746f432f2664296dac91942a788b82a2da07478d91b76ed85cd880758d2def8a55144840
doc/src/shakuhachi.libs/format.ml.html
Source file format.ml
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 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320(*****************************************************************************) (* *) (* Copyright (C) 2026 Yves Ndiaye *) (* *) (* This Source Code Form is subject to the terms of the Mozilla Public *) (* License, v. 2.0. If a copy of the MPL was not distributed with this *) (* file, You can obtain one at https://mozilla.org/MPL/2.0/. *) (* *) (*****************************************************************************) module Ids = SkhcDb.Ids.Map module Strings = Map.Make (String) module Roles = SkhcDb.Roles module Metadata = SkhcMetadata.Metadata let names s = String.concat " | " s let participants' participants = let a, b, c = Ids.fold (fun _ (name, roles) -> Roles.fold (fun role ((artist_names, album_artist, compositors) as aac) -> match role with | SkhcDb.Role.Artist -> (name :: artist_names, album_artist, compositors) | AlbumArtist -> (artist_names, name :: album_artist, compositors) | Composer -> (artist_names, album_artist, name :: compositors) | Unknown -> aac ) roles ) participants ([], [], []) in (List.rev a, List.rev b, List.rev c) let substitute_f ?metadata m format = let format = match metadata with | None -> format | Some metadata -> SkhcQuery.Format.map (function | String (Arbitrary s) -> let s = String.uppercase_ascii s in let s = metadata |> SkhcMetadata.Metadata.property_list s |> String.concat " | " in Text s | s -> s ) format in SkhcQuery.Format.(format |> substitute m |> to_string) let substitute_safe_f ?metadata map format = let map = List.map (fun (key, value) -> let value = SkhcUtil.StringUtil.make_path_safe value in (key, value) ) map in substitute_f ?metadata map format let filename_f ~extension config metadata format = let title = let default = SkhcConfig.Config.default_title config in Option.value ~default @@ Metadata.title metadata in let artist_names = match Metadata.artists metadata with | [] -> SkhcConfig.Config.default_artist config | _ :: _ as a -> names a in let album_artists = Metadata.album_artists metadata in let album = let default = config |> SkhcConfig.Config.default_album in Option.value ~default @@ Metadata.album metadata in let composers = Metadata.composers metadata in let title_sort = Metadata.title_sort metadata in let year = Metadata.year metadata in let track = Metadata.track metadata in let disc = Metadata.disc metadata in let genre = Option.value ~default:String.empty @@ Metadata.genre metadata in let some_f = Printf.sprintf "%02d" in let zero = "0" in let map = SkhcQuery.Format.Node. [ (String Title, title); (String SortName, Option.value ~default:String.empty title_sort); (String Artist, artist_names); (String AlbumArtist, names album_artists); (String Composer, names composers); (String Album, album); (String Genre, genre); (String FileExtension, extension); (Int Track, Option.fold ~some:some_f ~none:zero track); (Int Year, Option.fold ~some:some_f ~none:zero year); (Int Disc, Option.fold ~some:some_f ~none:zero disc); ] in substitute_safe_f map format let filename ~extension config metadata format = filename_f ~extension config metadata (SkhcQuery.Format.of_string format) let music_f music album artist_roles properties format = (* Cannot open SkhcDb otherwise ocaml/dune treat SkhcDb.Artist like Artist and it causes dependencies cycles *) let artist_names, album_artists, composers = participants' artist_roles in let metadata = Metadata.init None [||] properties in let zero = "0" in let title = Metadata.title metadata in let title_sort = Metadata.title_sort metadata in let year = Metadata.year metadata in let track = Metadata.track metadata in let disc = Metadata.disc metadata in let music_path = SkhcDb.MusicFile.path music in let extension = Filename.extension music_path in let map = SkhcQuery.Format.Node. [ (String Title, Option.value ~default:String.empty title); (String SortName, Option.value ~default:String.empty title_sort); (String Artist, names artist_names); (String Album, SkhcDb.Album.name album); (String AlbumArtist, names album_artists); (String Composer, names composers); ( String Genre, Option.value ~default:String.empty @@ SkhcDb.Album.genre album ); (String Path, music_path); (String FileExtension, extension); (Bool Art, Bool.to_string @@ SkhcDb.MusicFile.has_cover music); (Bool Flag, Bool.to_string @@ SkhcDb.MusicFile.flag music); (Int64 Id, Printf.sprintf "%Lu" (SkhcDb.MusicFile.id music)); (Int64 Size, Printf.sprintf "%u" (SkhcDb.MusicFile.size music)); (Int Track, Option.fold ~some:string_of_int ~none:zero track); (Int Disc, Option.fold ~some:string_of_int ~none:zero disc); (Int Year, Option.fold ~some:string_of_int ~none:zero year); (Int Plays, string_of_int (SkhcDb.MusicFile.play_count music)); (Int Length, string_of_int (SkhcDb.MusicFile.duration music)); ( Int Rating, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.MusicFile.rating music) ); (Int AlbumCount, string_of_int 1); (Float AvgDuration, string_of_int (SkhcDb.MusicFile.duration music)); ( Float AvgRating, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.MusicFile.rating music) ); (Float AvgSize, Printf.sprintf "%u" (SkhcDb.MusicFile.size music)); ] in substitute_f ~metadata map format let music music album artist_roles properties format = music_f music album artist_roles properties (SkhcQuery.Format.of_string format) let album_f ~safe ~extension album stats participants format = let artist_names, album_artists, composers = participants' participants in let album_name = SkhcDb.Album.name album in let artwork = album |> SkhcDb.Album.cover_path |> Option.is_some |> Bool.to_string in let flag = album |> SkhcDb.Album.flag |> Bool.to_string in let map = SkhcQuery.Format.Node. [ (String Title, album_name); ( String SortName, Option.value ~default:String.empty (SkhcDb.Album.sort_name album) ); (String Artist, names artist_names); (String Album, album_name); (String AlbumArtist, names album_artists); (String Composer, names composers); ( String Genre, Option.value ~default:String.empty @@ SkhcDb.Album.genre album ); (Bool Art, artwork); (Bool Flag, flag); (Int64 Id, Printf.sprintf "%Lu" (SkhcDb.Album.id album)); (Int64 Size, Printf.sprintf "%Lu" (SkhcDb.Album.Stats.size stats)); ( Int Year, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.Album.year album) ); (Int Plays, string_of_int (SkhcDb.Album.Stats.play_count stats)); (Int Length, string_of_int (SkhcDb.Album.Stats.duration stats)); ( Int Rating, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.Album.rating album) ); (Int AlbumCount, string_of_int (SkhcDb.Album.Stats.music_count stats)); ( Float AvgDuration, string_of_float (SkhcDb.Album.Stats.avg_duration stats) ); (Float AvgRating, string_of_float (SkhcDb.Album.Stats.avg_rating stats)); (Float AvgSize, string_of_float (SkhcDb.Album.Stats.avg_size stats)); ] in let map = match extension with | None -> map | Some extension -> (String FileExtension, extension) :: map in match safe with | false -> substitute_f map format | true -> substitute_safe_f map format let album ~safe ~extension album stats participants format = album_f ~safe ~extension album stats participants (SkhcQuery.Format.of_string format) let album_metadata_f ~safe ~extension metadata format = let artist_names = SkhcMetadata.Metadata.artist ~sep:", " metadata in let album_artists = SkhcMetadata.Metadata.album_artist ~sep:", " metadata in let composers = SkhcMetadata.Metadata.composer ~sep:", " metadata in let album_name = Option.value ~default:String.empty @@ SkhcMetadata.Metadata.album metadata in let sort_name = SkhcMetadata.Metadata.album_sort metadata in let genre = SkhcMetadata.Metadata.genre metadata in let artwork = metadata |> SkhcMetadata.Metadata.covers |> Array.length |> ( <> ) 0 |> Bool.to_string in let map = SkhcQuery.Format.Node. [ (String Title, album_name); (String SortName, Option.value ~default:String.empty sort_name); (String Artist, artist_names); (String AlbumArtist, album_artists); (String Album, album_name); (String Composer, composers); (String Genre, Option.value ~default:String.empty genre); (Bool Art, artwork); ] in let map = match extension with | None -> map | Some extension -> (String FileExtension, extension) :: map in match safe with | false -> substitute_f map format | true -> substitute_safe_f map format let album_metadata ~safe ~extension metadata format = album_metadata_f ~safe ~extension metadata (SkhcQuery.Format.of_string format) let artist_f ~safe ~extension artist format = let artist_name = SkhcDb.Artist.name artist in let artwork = artist |> SkhcDb.Artist.artwork |> Option.is_some |> Bool.to_string in let flag = artist |> SkhcDb.Artist.flag |> Bool.to_string in let map = SkhcQuery.Format.Node. [ (Int64 Id, Printf.sprintf "%Lu" (SkhcDb.Artist.id artist)); ( String SortName, Option.value ~default:String.empty (SkhcDb.Artist.sort_name artist) ); (String Artist, artist_name); (String AlbumArtist, artist_name); (String Composer, artist_name); (Bool Art, artwork); (Bool Flag, flag); ( Int Rating, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.Artist.rating artist) ); ( Float AvgRating, Option.fold ~some:string_of_int ~none:String.empty (SkhcDb.Artist.rating artist) ); ] in let map = match extension with | None -> map | Some extension -> (String FileExtension, extension) :: map in match safe with | false -> substitute_f map format | true -> substitute_safe_f map format let artist ~safe ~extension artist format = artist_f ~safe ~extension artist (SkhcQuery.Format.of_string format)
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>