Skip to content

Commit c90f43d

Browse files
committed
Add the property API
1 parent 6aa9270 commit c90f43d

File tree

9 files changed

+94
-7
lines changed

9 files changed

+94
-7
lines changed

Sound/HTagLib.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ module Sound.HTagLib
2424
bitRateGetter,
2525
sampleRateGetter,
2626
channelsGetter,
27+
propertyGetter,
2728

2829
-- * Setters
2930
setTags,
@@ -35,6 +36,7 @@ module Sound.HTagLib
3536
genreSetter,
3637
yearSetter,
3738
trackNumberSetter,
39+
propertySetter,
3840

3941
-- * Data types
4042
Title,

Sound/HTagLib/Getter.hs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,10 +29,12 @@ module Sound.HTagLib.Getter
2929
bitRateGetter,
3030
sampleRateGetter,
3131
channelsGetter,
32+
propertyGetter,
3233
)
3334
where
3435

3536
import Control.Monad.IO.Class
37+
import Data.Text (Text)
3638
import Sound.HTagLib.Internal qualified as I
3739
import Sound.HTagLib.Type
3840

@@ -137,3 +139,7 @@ sampleRateGetter = TagGetter I.getSampleRate
137139
-- | Getter to retrieve the number of channels of the audio data.
138140
channelsGetter :: TagGetter Channels
139141
channelsGetter = TagGetter I.getChannels
142+
143+
-- | Getter to retrieve a property by its name.
144+
propertyGetter :: Text -> TagGetter [Text]
145+
propertyGetter = TagGetter . I.propertyGet

Sound/HTagLib/Internal.hs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,11 @@ module Sound.HTagLib.Internal
4343

4444
-- * Special convenience ID3v2 functions
4545
id3v2SetEncoding,
46+
47+
-- * Properties API
48+
propertySet,
49+
propertySetAppend,
50+
propertyGet,
4651
)
4752
where
4853

@@ -162,6 +167,21 @@ foreign import ccall unsafe "taglib/tag_c.h taglib_audioproperties_channels"
162167
foreign import ccall unsafe "taglib/tag_c.h taglib_id3v2_set_default_text_encoding"
163168
c_taglib_id3v2_set_default_text_encoding :: CInt -> IO ()
164169

170+
----------------------------------------------------------------------------
171+
-- Properties API
172+
173+
foreign import ccall unsafe "taglib/tag_c.h taglib_property_set"
174+
c_taglib_property_set :: Ptr TagLibFile -> CString -> CString -> IO ()
175+
176+
foreign import ccall unsafe "taglib/tag_c.h taglib_property_set_append"
177+
c_taglib_property_set_append :: Ptr TagLibFile -> CString -> CString -> IO ()
178+
179+
foreign import ccall unsafe "taglib/tag_c.h taglib_property_get"
180+
c_taglib_property_get :: Ptr TagLibFile -> CString -> IO (Ptr CString)
181+
182+
foreign import ccall unsafe "taglib/tag_c.h taglib_property_free"
183+
c_taglib_property_free :: Ptr CString -> IO ()
184+
165185
----------------------------------------------------------------------------
166186
-- File API
167187

@@ -313,6 +333,43 @@ getChannels =
313333
id3v2SetEncoding :: T.ID3v2Encoding -> IO ()
314334
id3v2SetEncoding = c_taglib_id3v2_set_default_text_encoding . enumToCInt
315335

336+
----------------------------------------------------------------------------
337+
-- Properties API
338+
339+
propertySet :: Text -> Maybe Text -> FileId -> IO ()
340+
propertySet = propertySetHelper c_taglib_property_set
341+
342+
propertySetAppend :: Text -> Maybe Text -> FileId -> IO ()
343+
propertySetAppend = propertySetHelper c_taglib_property_set_append
344+
345+
propertySetHelper ::
346+
(Ptr TagLibFile -> CString -> CString -> IO ()) ->
347+
Text ->
348+
Maybe Text ->
349+
FileId ->
350+
IO ()
351+
propertySetHelper f prop mvalue (FileId ptr) =
352+
useAsCString (encodeUtf8 prop) $ \cprop ->
353+
case mvalue of
354+
Nothing -> f ptr cprop nullPtr
355+
Just value -> useAsCString (encodeUtf8 value) $ f ptr cprop
356+
357+
propertyGet :: Text -> FileId -> IO [Text]
358+
propertyGet prop (FileId ptr) =
359+
useAsCString (encodeUtf8 prop) $ \cprop ->
360+
bracket
361+
(c_taglib_property_get ptr cprop)
362+
c_taglib_property_free
363+
(ppCharToTexts [])
364+
where
365+
ppCharToTexts texts ppchar = do
366+
pchar <- peek ppchar
367+
if pchar == nullPtr
368+
then return (reverse texts)
369+
else do
370+
text <- decodeUtf8 <$> packCString pchar
371+
ppCharToTexts (text:texts) (advancePtr ppchar 1)
372+
316373
----------------------------------------------------------------------------
317374
-- Helpers
318375

Sound/HTagLib/Setter.hs

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,12 +25,14 @@ module Sound.HTagLib.Setter
2525
genreSetter,
2626
yearSetter,
2727
trackNumberSetter,
28+
propertySetter,
2829
)
2930
where
3031

3132
import Control.Applicative ((<|>))
3233
import Control.Monad.IO.Class
3334
import Data.Foldable (forM_)
35+
import Data.Text (Text)
3436
import Sound.HTagLib.Internal qualified as I
3537
import Sound.HTagLib.Type
3638

@@ -49,7 +51,8 @@ data TagSetter = TagSetter
4951
sdComment :: Maybe Comment,
5052
sdGenre :: Maybe Genre,
5153
sdYear :: Maybe (Maybe Year),
52-
sdTrackNumber :: Maybe (Maybe TrackNumber)
54+
sdTrackNumber :: Maybe (Maybe TrackNumber),
55+
sdProperties :: [(Text, [Text])]
5356
}
5457

5558
-- | @since 1.2.0
@@ -63,7 +66,8 @@ instance Semigroup TagSetter where
6366
sdComment = f sdComment,
6467
sdGenre = f sdGenre,
6568
sdYear = f sdYear,
66-
sdTrackNumber = f sdTrackNumber
69+
sdTrackNumber = f sdTrackNumber,
70+
sdProperties = f sdProperties
6771
}
6872

6973
instance Monoid TagSetter where
@@ -75,7 +79,8 @@ instance Monoid TagSetter where
7579
sdComment = Nothing,
7680
sdGenre = Nothing,
7781
sdYear = Nothing,
78-
sdTrackNumber = Nothing
82+
sdTrackNumber = Nothing,
83+
sdProperties = []
7984
}
8085
mappend = (<>)
8186

@@ -131,7 +136,13 @@ execSetter path enc t TagSetter {..} = liftIO . I.withFile path t $ \fid -> do
131136
writeTag sdGenre I.setGenre
132137
writeTag sdYear I.setYear
133138
writeTag sdTrackNumber I.setTrackNumber
139+
forM_ sdProperties (writeProperty fid)
134140
I.saveFile path fid
141+
where
142+
writeProperty fid (k, []) = I.propertySet k Nothing fid
143+
writeProperty fid (k, v : vs) = do
144+
I.propertySet k (Just v) fid
145+
forM_ vs $ \v' -> I.propertySetAppend k (Just v') fid
135146

136147
-- | Setter for the track title.
137148
titleSetter :: Title -> TagSetter
@@ -160,3 +171,7 @@ yearSetter x = mempty {sdYear = Just x}
160171
-- | Setter for the track number, use 'Nothing' to clear the field.
161172
trackNumberSetter :: Maybe TrackNumber -> TagSetter
162173
trackNumberSetter x = mempty {sdTrackNumber = Just x}
174+
175+
-- | Setter for a property with a given key, use an empty list to clear it.
176+
propertySetter :: Text -> [Text] -> TagSetter
177+
propertySetter k v = mempty {sdProperties = [(k, v)]}

audio-samples/sample.flac

27 Bytes
Binary file not shown.

audio-samples/sample.mp3

128 Bytes
Binary file not shown.

htaglib.cabal

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,8 @@ test-suite tests
6969
directory >=1.2 && <1.4,
7070
filepath >=1.4 && <2,
7171
hspec >=2 && <3,
72-
htaglib
72+
htaglib,
73+
text >=1 && <2.2
7374

7475
if flag(dev)
7576
ghc-options:

tests/Sound/HTagLib/SetterSpec.hs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,8 @@ updateSampleTags tags =
2929
atComment = mkComment "comment'",
3030
atGenre = mkGenre "genre'",
3131
atYear = mkYear 2056,
32-
atTrackNumber = mkTrackNumber 8
32+
atTrackNumber = mkTrackNumber 8,
33+
atAlbumArtistProperty = ["albumartist'"]
3334
}
3435

3536
simpleSetter :: AudioTags -> Expectation

tests/Sound/HTagLib/Test/Util.hs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ module Sound.HTagLib.Test.Util
1111
where
1212

1313
import Data.Maybe (fromJust)
14+
import Data.Text (Text)
1415
import Sound.HTagLib
1516
import Test.Hspec
1617

@@ -26,7 +27,8 @@ data AudioTags = AudioTags
2627
atDuration :: Duration,
2728
atBitRate :: BitRate,
2829
atSampleRate :: SampleRate,
29-
atChannels :: Channels
30+
atChannels :: Channels,
31+
atAlbumArtistProperty :: [Text]
3032
}
3133
deriving (Show, Eq)
3234

@@ -45,6 +47,7 @@ sampleGetter path =
4547
<*> bitRateGetter
4648
<*> sampleRateGetter
4749
<*> channelsGetter
50+
<*> propertyGetter "ALBUMARTIST"
4851

4952
sampleSetter :: TagSetter
5053
sampleSetter =
@@ -56,6 +59,7 @@ sampleSetter =
5659
<> genreSetter (mkGenre "genre'")
5760
<> yearSetter (mkYear 2056)
5861
<> trackNumberSetter (mkTrackNumber 8)
62+
<> propertySetter "ALBUMARTIST" ["albumartist'"]
5963

6064
sampleTags :: AudioTags
6165
sampleTags =
@@ -71,7 +75,8 @@ sampleTags =
7175
atDuration = fromJust $ mkDuration 0,
7276
atBitRate = fromJust $ mkBitRate 0,
7377
atSampleRate = fromJust $ mkSampleRate 44100,
74-
atChannels = fromJust $ mkChannels 2
78+
atChannels = fromJust $ mkChannels 2,
79+
atAlbumArtistProperty = ["albumartist"]
7580
}
7681

7782
fileList :: [(FileType, AudioTags)]

0 commit comments

Comments
 (0)