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.0_1.tar.gz
sha256=541a7ac078a520730a71edf4d2fe0f17cc98f0b9ad82060db62120a7d2519ae5
sha512=37b98cb52dab8293adb92f71e91394cf1c5d0d481d03893c320cc8aa550459a30dabdfdc0018f512d3a7a547f2899b493a20d86f450bc084b78e30b40234a911
doc/src/shakuhachi.database/util.ml.html
Source file util.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(*****************************************************************************) (* *) (* 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 Metadata = SkhcMetadata.Metadata module Parser = struct open Angstrom let is_digit = function '0' .. '9' -> true | _ -> false let number = map ~f:int_of_string (take_while1 is_digit) let number64 = map ~f:Int64.of_string (take_while1 is_digit) let string_all k = map (take_while (Fun.const true)) ~f:k end module Stats = struct let init ~init' ~music_count ~duration ~play_count ~size ~avg_rating = let avg what = if music_count = 0 then Float.zero else Int.to_float what /. Int.to_float music_count in let avg_duration = avg duration in let avg_size = Int64.to_float size /. Int.to_float music_count in init' ~music_count ~duration ~play_count ~size ~avg_duration ~avg_rating ~avg_size end let bind_ok database rc f = match rc with | Sqlite3.Rc.OK | Sqlite3.Rc.DONE -> f () | rc -> let message = Sqlite3.errmsg database in Error (rc, message) let bind_constraint_ok database rc f = match rc with | Sqlite3.Rc.OK | Sqlite3.Rc.DONE | Sqlite3.Rc.CONSTRAINT -> f () | rc -> let message = Sqlite3.errmsg database in Error (rc, message) let bind_option fbind statement n value = match value with | None -> Sqlite3.Rc.OK | Some value -> fbind statement n value let sql_participants_format ~ss ~id ~role ~name = Printf.sprintf "group_concat(%s || ':' || %s || '_' || %s, '%c')" id role name ss (* ss like split string sv like split value *) let sql_participants ~ss s = let participant_parse s = let open Angstrom in let parser = map2 ~f:(fun id d -> (id, d)) (Parser.number64 <* char ':') @@ choice [ map2 Parser.number (char '_' *> Parser.string_all Fun.id) ~f:(fun role name -> let role = Role.of_int role in (name, role) ); map (Parser.string_all Fun.id) ~f:(fun s -> (s, Role.Unknown)); ] in match parse_string ~consume:All parser s with | Ok e -> Some e | Error _ -> None in s |> String.split_on_char ss |> List.fold_left (fun ids s -> match participant_parse s with | None -> ids | Some (id, (name, role)) -> Ids.Map.update id (function | None -> Some (name, Roles.singleton role) | Some (_, roles) -> Some (name, Roles.add role roles) ) ids ) Ids.Map.empty let sql_properties ~ss ~sv s = s |> String.split_on_char ss |> List.fold_left (fun properties s -> let key_vals = String.split_on_char sv s in match key_vals with | [] | _ :: [] -> properties | key :: values -> let values = String.concat " " values in Metadata.Properties.update key (function | None -> Some (Metadata.Values.singleton values) | Some v -> Some (Metadata.Values.add values v) ) properties ) Metadata.Properties.empty
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>