/
Setter.hs
153 lines (126 loc) · 4.29 KB
/
Setter.hs
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
-- |
-- Module : Sound.HTagLib.Setter
-- Copyright : © 2015–2017 Mark Karpov
-- License : BSD 3 clause
--
-- Maintainer : Mark Karpov <markkarpov92@gmail.com>
-- Stability : experimental
-- Portability : portable
--
-- A high-level interface for writing audio meta data. You don't need to
-- import this module directly, import "Sound.HTagLib" instead.
{-# LANGUAGE CPP #-}
{-# LANGUAGE RecordWildCards #-}
module Sound.HTagLib.Setter
( -- * High-level API
TagSetter
, setTags
, setTags'
-- * Built-in setters
, titleSetter
, artistSetter
, albumSetter
, commentSetter
, genreSetter
, yearSetter
, trackNumberSetter )
where
import Control.Applicative ((<|>))
import Control.Monad.IO.Class
import Data.Foldable (forM_)
import Sound.HTagLib.Type
import qualified Sound.HTagLib.Internal as I
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
-- | A composable entity that can be used together with the 'setTags' or the
-- 'setTags'' functions to write meta data to an audio file.
--
-- Note that in case of (for example):
--
-- > titleSetter "foo" <> titleSetter "bar"
--
-- The first value wins.
data TagSetter = TagSetter
{ sdTitle :: Maybe Title
, sdArtist :: Maybe Artist
, sdAlbum :: Maybe Album
, sdComment :: Maybe Comment
, sdGenre :: Maybe Genre
, sdYear :: Maybe (Maybe Year)
, sdTrackNumber :: Maybe (Maybe TrackNumber) }
instance Monoid TagSetter where
mempty = TagSetter
{ sdTitle = Nothing
, sdArtist = Nothing
, sdAlbum = Nothing
, sdComment = Nothing
, sdGenre = Nothing
, sdYear = Nothing
, sdTrackNumber = Nothing }
mappend x y = let f g = g x <|> g y in TagSetter
{ sdTitle = f sdTitle
, sdArtist = f sdArtist
, sdAlbum = f sdAlbum
, sdComment = f sdComment
, sdGenre = f sdGenre
, sdYear = f sdYear
, sdTrackNumber = f sdTrackNumber }
-- | Set tags in specified file using the given setter.
--
-- In the case of trouble 'I.HTagLibException' will be thrown.
setTags :: MonadIO m
=> FilePath -- ^ Path to audio file
-> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
-> TagSetter -- ^ Setter
-> m ()
setTags path enc = execSetter path enc Nothing
-- | Similar to 'setTags', but you can also specify type of audio file
-- explicitly (otherwise it's guessed from file extension).
setTags' :: MonadIO m
=> FilePath -- ^ Path to audio file
-> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
-> FileType -- ^ Type of audio file
-> TagSetter -- ^ Setter
-> m ()
setTags' path enc t = execSetter path enc (Just t)
-- | The most general way to set meta data. 'setTags' and 'setTags'' are
-- just wrappers around this function.
execSetter :: MonadIO m
=> FilePath -- ^ Path to audio file
-> Maybe ID3v2Encoding -- ^ Encoding for ID3v2 frames
-> Maybe FileType -- ^ Type of audio file (if known)
-> TagSetter -- ^ Setter
-> m ()
execSetter path enc t TagSetter {..} = liftIO . I.withFile path t $ \fid -> do
forM_ enc I.id3v2SetEncoding
let writeTag x f = forM_ x (`f` fid)
writeTag sdTitle I.setTitle
writeTag sdArtist I.setArtist
writeTag sdAlbum I.setAlbum
writeTag sdComment I.setComment
writeTag sdGenre I.setGenre
writeTag sdYear I.setYear
writeTag sdTrackNumber I.setTrackNumber
I.saveFile path fid
-- | Setter for track title.
titleSetter :: Title -> TagSetter
titleSetter x = mempty { sdTitle = Just x }
-- | Setter for track artist.
artistSetter :: Artist -> TagSetter
artistSetter x = mempty { sdArtist = Just x }
-- | Setter for track album.
albumSetter :: Album -> TagSetter
albumSetter x = mempty { sdAlbum = Just x }
-- | Setter for track comment.
commentSetter :: Comment -> TagSetter
commentSetter x = mempty { sdComment = Just x }
-- | Setter for track genre.
genreSetter :: Genre -> TagSetter
genreSetter x = mempty { sdGenre = Just x }
-- | Setter for year tag, use 'Nothing' to clear the field.
yearSetter :: Maybe Year -> TagSetter
yearSetter x = mempty { sdYear = Just x }
-- | Setter for track number, use 'Nothing' to clear the field.
trackNumberSetter :: Maybe TrackNumber -> TagSetter
trackNumberSetter x = mempty { sdTrackNumber = Just x }