{"id":15010934,"url":"https://github.com/mrkkrp/htaglib","last_synced_at":"2025-06-13T21:34:05.124Z","repository":{"id":1935290,"uuid":"45071448","full_name":"mrkkrp/htaglib","owner":"mrkkrp","description":"Haskell bindings for TagLib, an audio meta-data library","archived":false,"fork":false,"pushed_at":"2025-01-31T16:05:23.000Z","size":179,"stargazers_count":20,"open_issues_count":2,"forks_count":4,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-06-03T10:29:50.374Z","etag":null,"topics":["bindings","haskell","taglib"],"latest_commit_sha":null,"homepage":"","language":"Haskell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mrkkrp.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2015-10-27T21:33:38.000Z","updated_at":"2025-01-31T16:05:27.000Z","dependencies_parsed_at":"2024-06-15T18:44:21.632Z","dependency_job_id":"4f5f9f4a-71b2-408e-a748-47204335c6a8","html_url":"https://github.com/mrkkrp/htaglib","commit_stats":{"total_commits":141,"total_committers":3,"mean_commits":47.0,"dds":"0.46808510638297873","last_synced_commit":"d30866dc88009ec80b5d97f0d5095d07ef9e7306"},"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/mrkkrp/htaglib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fhtaglib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fhtaglib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fhtaglib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fhtaglib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mrkkrp","download_url":"https://codeload.github.com/mrkkrp/htaglib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mrkkrp%2Fhtaglib/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":259723638,"owners_count":22901945,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["bindings","haskell","taglib"],"created_at":"2024-09-24T19:37:38.738Z","updated_at":"2025-06-13T21:34:05.106Z","avatar_url":"https://github.com/mrkkrp.png","language":"Haskell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# HTagLib\n\n[![License BSD3](https://img.shields.io/badge/license-BSD3-brightgreen.svg)](http://opensource.org/licenses/BSD-3-Clause)\n[![Hackage](https://img.shields.io/hackage/v/htaglib.svg?style=flat)](https://hackage.haskell.org/package/htaglib)\n[![Stackage Nightly](http://stackage.org/package/htaglib/badge/nightly)](http://stackage.org/nightly/package/htaglib)\n[![Stackage LTS](http://stackage.org/package/htaglib/badge/lts)](http://stackage.org/lts/package/htaglib)\n[![CI](https://github.com/mrkkrp/htaglib/actions/workflows/ci.yaml/badge.svg)](https://github.com/mrkkrp/htaglib/actions/workflows/ci.yaml)\n\n* [Alternatives](#alternatives)\n* [A note for FLAC users](#a-note-for-flac-users)\n* [Quick start](#quick-start)\n    * [Reading meta data](#reading-meta-data)\n    * [Writing meta data](#writing-meta-data)\n    * [Conclusion](#conclusion)\n* [License](#license)\n\nThis is Haskell bindings to [TagLib](https://taglib.github.io/), a library\nfor reading and editing meta-data of several popular audio formats.\n\nIt works with the following formats:\n\n* MP3\n* FLAC\n* MPC\n* Speex\n* WavPack TrueAudio\n* WAV\n* AIFF\n* MP4\n* ASF\n\nThis happens in an abstract, uniform way, so you don't need to handle any\nlow-level details. As a consequence, it's currently not possible to work\nwith format-specific functionality.\n\n## Alternatives\n\nThere is at least two other Haskell bindings to TagLib:\n\n* [`libtagc`](https://hackage.haskell.org/package/libtagc)\n* [`taglib`](https://hackage.haskell.org/package/taglib)\n\nBoth are low level, without any type safety or higher-level abstractions.\n\n## A note for FLAC users\n\nIf you want to work with FLAC, there is a [complete Haskell\nbinding](https://github.com/mrkkrp/flac) to `libFLAC`—the reference FLAC\nimplementation. It allows us to work with all FLAC metadata (read and write)\nand also provides a Haskell API to the stream encoder and the stream\ndecoder. Please prefer that package if you don't need to work with other\naudio formats.\n\n## Quick start\n\nFirst, since this is bindings to C-interface of the library, you'll need to\ninstall the library itself. If you're on a Unix-like system, chances are\nyou'll have it in the official repositories of your distro.\n\n### Reading meta data\n\nNow to the hacking. It's recommended that you define a record representing\nmeta-data of audio track in your program, like this:\n\n```haskell\nmodule Main (main) where\n\nimport Data.Monoid\nimport Sound.HTagLib\nimport System.Environment (getArgs)\n\ndata AudioTrack = AudioTrack\n  { atTitle :: Title,\n    atArtist :: Artist,\n    atAlbum :: Album,\n    atComment :: Comment,\n    atGenre :: Genre,\n    atYear :: Maybe Year,\n    atTrack :: Maybe TrackNumber\n  }\n  deriving (Show)\n```\n\nWe use unique types for every component of meta data, so it's more difficult\nto use a track title instead of a track artist, for example. String meta\ndata types have smart constructors, but `Title`, `Artist`, `Album`,\n`Comment`, and `Genre` all are instances of `IsString`, so it is enough to\nturn on the `OverloadedStrings` language extension to use normal string\nliterals to create values of these types.\n\n`Year` and `TrackNumber` may be not set or missing, in this case you get\n`Nothing`. This is possible with string-based fields too, but in that case\nyou just get empty strings. `Year` and `TrackNumber` have smart constructors\nthat make sure that the values are positive (i.e. zero is not allowed).\n\nOK, it's time to read some info. There is `TagGetter` type which is an\napplicative functor. You first construct `TagGetter` which will retrieve\nentire `AudioTrack` for you using the applicative style:\n\n```haskell\naudioTrackGetter :: TagGetter AudioTrack\naudioTrackGetter =\n  AudioTrack\n    \u003c$\u003e titleGetter\n    \u003c*\u003e artistGetter\n    \u003c*\u003e albumGetter\n    \u003c*\u003e commentGetter\n    \u003c*\u003e genreGetter\n    \u003c*\u003e yearGetter\n    \u003c*\u003e trackNumberGetter\n```\n\nPerfect, now use `getTags` to read the entire record:\n\n```haskell\nmain :: IO ()\nmain = do\n  path \u003c- head \u003c$\u003e getArgs\n  track \u003c- getTags path audioTrackGetter\n  print track\n```\n\nFor example (alignment is added):\n\n```\n$ ./example \"/home/mark/music/David Bowie/1977, Low/01 Speed of Life.flac\"\nAudioTrack\n  { atTitle = Title \"Speed of Life\",\n    atArtist = Artist \"David Bowie\",\n    atAlbum = Album \"Low\",\n    atComment = Comment \"\",\n    atGenre = Genre \"\",\n    atYear = Just (Year 1977),\n    atTrack = Just (TrackNumber 1)\n  }\n```\n\nSuccess! It's also possible to extract audio properties like sample rate,\netc. but it's not shown here for simplicity, consult Haddocks for more\ninformation.\n\nN.B. If you need to extract the duration, TagLib only returns the number of\nseconds as an integer. This means that if you want to calculate the total\nduration of an album, you'll get a slightly incorrect result. The right\nsolution is to extract the duration as floating-point number, for that we\nrecommend the bindings to\n`libsndfile`—[`hsndfile`](https://hackage.haskell.org/package/hsndfile) (or\nthe above-mentioned `flac` package for Haskell if you work with FLAC).\n\n### Writing meta data\n\n`TagSetter` is an instance of `Monoid`. This means that we can set title and\nartist of audio track like this:\n\n```haskell\nmain :: IO ()\nmain = do\n  (path : title : artist : _) \u003c- getArgs\n  setTags path Nothing $\n    titleSetter (mkTitle title)\n      \u003c\u003e artistSetter (mkArtist artist)\n  track \u003c- getTags path audioTrackGetter\n  print track\n```\n\nThis code loads a file and changes the “title” and “artist” meta data\nfields.\n\n## Contribution\n\nIssues, bugs, and questions may be reported in [the GitHub issue tracker for\nthis project](https://github.com/mrkkrp/htaglib/issues).\n\nPull requests are also welcome.\n\n## License\n\nCopyright © 2015–present Mark Karpov\n\nDistributed under BSD 3 clause license.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrkkrp%2Fhtaglib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmrkkrp%2Fhtaglib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmrkkrp%2Fhtaglib/lists"}