package shakuhachi

  1. Overview
  2. Docs
A music collection manager

Install

dune-project
 Dependency

Authors

Maintainers

Sources

0.1.0.tar.gz
sha256=bb7f91cc44c09f922d2a614e9e01fd0d2976840bacf839a8b99de63c6fc5b3b8
sha512=f02827db4228b017bb2ad7d64cb1c0667831ec2341e6f759266ec834e40627c2affeace143c6d5e769b3acce63f889b3cbd1a9ca4768091840e8fce1d4750f86

doc/src/shakuhachi.query/queryMusic.ml.html

Source file queryMusic.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
(**********************************************************************************************)
(*                                                                                            *)
(* This file is part of shakuhachi: a music collection manager                                *)
(* Copyright (C) 2025 Yves Ndiaye                                                             *)
(*                                                                                            *)
(* shakuhachi is free software: you can redistribute it and/or modify it under the terms      *)
(* of the GNU General Public License as published by the Free Software Foundation,            *)
(* either version 3 of the License, or (at your option) any later version.                    *)
(*                                                                                            *)
(* shakuhachi is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;    *)
(* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR           *)
(* PURPOSE.  See the GNU General Public License for more details.                             *)
(* You should have received a copy of the GNU General Public License along with shakuhachi.   *)
(* If not, see <http://www.gnu.org/licenses/>.                                                *)
(*                                                                                            *)
(**********************************************************************************************)

module Metadata = SkhcMetadata.Metadata
module Ids = SkhcDb.Ids
module Roles = SkhcDb.Roles
include QueryUtil

let matches_node subfields (music_file, album, participants, properties) node =
  let metadata = SkhcMetadata.Metadata.init None [||] properties in
  let album_name = SkhcDb.Album.name album in
  let id = SkhcDb.MusicFile.id music_file in
  let path = SkhcDb.MusicFile.path music_file in
  let extension = Filename.extension path in
  let size = SkhcDb.MusicFile.size music_file in
  let play_count = SkhcDb.MusicFile.play_count music_file in
  let flag = SkhcDb.MusicFile.flag music_file in
  let rating = SkhcDb.MusicFile.rating music_file in
  let duration = SkhcDb.MusicFile.duration music_file in
  let has_cover = SkhcDb.MusicFile.has_cover music_file in
  let title = Metadata.title metadata in
  let sort_name = Metadata.title_sort metadata in
  let track_number = Metadata.track metadata in
  let disc_number = Metadata.disc metadata in
  let year = Metadata.year metadata in
  let genre = Metadata.genre metadata in

  match node with
  | Node.Substring s ->
      let fields = match_participants participants in
      let fields =
        Substring.(
          SubFields.(
            fields
            |> add_field_if_some STitle title
            |> add_field_if_some SSortName sort_name
            |> add SAlbum album_name
            |> add_field_if_some SGenre genre
            |> filter (fun key _ -> List.mem key subfields)
            |> bindings |> List.map snd
          )
        )
      in
      List.exists (matches ~insensible:true false s) fields
  | Field (FString s) -> (
      let regex = Field.String.regex s in
      let insensible = Field.String.insensible s in
      let field = Field.String.field s in
      match field with
      | Title ftitle ->
          omatches ~insensible regex ftitle title
      | SortName fsort_name ->
          omatches ~insensible regex fsort_name sort_name
      | Artist fartist ->
          Ids.Map.exists
            (fun _ (artist_name, roles) ->
              Roles.mem Artist roles
              && matches ~insensible regex fartist artist_name
            )
            participants
      | Album falbum ->
          matches ~insensible regex falbum album_name
      | AlbumArtist falbum_artist ->
          Ids.Map.exists
            (fun _ (artist_name, roles) ->
              Roles.mem AlbumArtist roles
              && matches ~insensible regex falbum_artist artist_name
            )
            participants
      | Composer fcomposer ->
          Ids.Map.exists
            (fun _ (artist_name, roles) ->
              Roles.mem Composer roles
              && matches ~insensible regex fcomposer artist_name
            )
            participants
      | Genre fgenre ->
          omatches ~insensible regex fgenre genre
      | Path fpath ->
          matches ~insensible regex fpath path
      | FileExtension fextension ->
          matches ~insensible regex fextension extension
    )
  | Field (FBool b) -> (
      match b with Art b -> b = has_cover | Flag b -> flag = b
    )
  | Field (FInt i) -> (
      match i with
      | Id fid ->
          Range.matches fid id
      | Size fsize ->
          Range.matches fsize (Int64.of_int size)
      | Track ftrack ->
          track_number
          |> Option.map (Range.matches ftrack)
          |> Option.value ~default:false
      | Year fyear ->
          year
          |> Option.map (Range.matches fyear)
          |> Option.value ~default:false
      | Disc fdisc ->
          Option.fold ~none:false ~some:(Range.matches fdisc) disc_number
      | Plays fcount ->
          Range.matches fcount play_count
      | Length flength ->
          Range.matches flength duration
      | Rating frating ->
          rating
          |> Option.map (Range.matches frating)
          |> Option.value ~default:false
      | AlbumCount fcount ->
          Range.matches fcount 1
    )
  | Field (FFloat f) -> (
      match f with
      | AvgDuration favg_duration ->
          Range.matches favg_duration (Float.of_int duration)
      | AvgRating favg_rating ->
          rating
          |> Option.map (fun rating ->
              let rating = Float.of_int rating in
              Range.matches favg_rating rating
          )
          |> Option.value ~default:false
      | AvgSize favg_size ->
          Range.matches favg_size (Int.to_float size)
    )