TagLib Nim wrapper.

This commit is contained in:
Jonathan Bernard 2025-03-04 15:49:54 -06:00
parent 3f3a6b286b
commit 2d44d2c328

View File

@ -0,0 +1,167 @@
import std/[paths, strutils]
{.passl: "-ltag_c".}
{.passc: "-ltag_c".}
type
TagLibFileType* {.size: sizeof(cint).} = enum
MPEG, OggVorbis, FLAC, MPC, OggFlac, WavPack, Speex, TrueAudio, MP4, ASF,
AIFF, WAV, APE, IT, Mod, S3M, XM, Opus, DSF, DSDIFF, SHORTEN
TagLibID3v2Encoding* {.size: sizeof(cint).} = enum
Latin1, UTF16, UTF16BE, UTF8, Encoding
CFile = pointer
CTag* = pointer
CAudioProperties = pointer
TagLibFIle* = object
path*: Path
cfile*: CFile
tag*: CTag
ap*: CAudioProperties
{.push importc.}
{.push cdecl.}
proc taglib_set_strings_unicode*(unicode: cint)
proc taglib_set_string_management_enabled*(enabled: cint)
proc taglib_free*(p: pointer)
proc taglib_file_new(filename: cstring): CFile
proc taglib_file_new_type(filename: cstring, `type`: TagLibFileType): CFile
proc taglib_file_free(file: CFile)
proc taglib_file_is_valid(file: CFile): cint
proc taglib_file_tag(file: CFile): CTag
proc taglib_file_audioproperties(file: CFile): CAudioProperties
proc taglib_file_save(file: CFile): cint
proc taglib_tag_title(tag: CTag): cstring
proc taglib_tag_artist(tag: CTag): cstring
proc taglib_tag_album(tag: CTag): cstring
proc taglib_tag_comment(tag: CTag): cstring
proc taglib_tag_genre(tag: CTag): cstring
proc taglib_tag_year(tag: CTag): cuint
proc taglib_tag_track(tag: CTag): cuint
proc taglib_tag_set_title(tag: CTag, title: cstring)
proc taglib_tag_set_artist(tag: CTag, artist: cstring)
proc taglib_tag_set_album(tag: CTag, album: cstring)
proc taglib_tag_set_comment(tag: CTag, comment: cstring)
proc taglib_tag_set_genre(tag: CTag, genre: cstring)
proc taglib_tag_set_year(tag: CTag, year: cuint)
proc taglib_tag_set_track(tag: CTag, year: cuint)
proc taglib_tag_free_strings()
proc taglib_audioproperties_length(ap: CAudioProperties): cint
proc taglib_audioproperties_bitrate(ap: CAudioProperties): cint
proc taglib_audioproperties_samplerate(ap: CAudioProperties): cint
proc taglib_audioproperties_channels(ap: CAudioProperties): cint
proc taglib_id3v2_set_default_text_encoding(encoding: TagLibID3v2Encoding)
proc taglib_property_set(file: CFile, prop: cstring, value: cstring)
proc taglib_property_set_append(file: CFile, prop: cstring, value: cstring)
#proc taglib_property_keys(file: CFile): cstring[]
proc taglib_property_get(file: CFile, prop: cstring): cstring
proc taglib_property_free(props: pointer)
{.pop.} # cdecl
{.pop.} # importc
taglib_set_strings_unicode(1)
proc initTagLibFile(path: Path, cfile: CFile): TagLibFile =
if cfile.isNil:
raise newException(IOError, "Failed to open file: " & $path)
if taglib_file_is_valid(cfile) < 0:
taglib_file_free(cfile)
raise newException(IOError, "Invalid TagLib file: " & $path)
result.path = path
result.cfile = cfile
result.tag = taglib_file_tag(cfile)
result.ap = taglib_file_audioproperties(cfile)
proc openTags*(path: Path): TagLibFile =
## Open a file and return a TagLibFile object.
let cfile = taglib_file_new(path.cstring)
initTagLibFile(path, cfile)
proc openTags*(path: Path, fileType: TagLibFileType): TagLibFile =
## Open a file of a specific type and return a TagLibFile object.
let cfile = taglib_file_new_type(path.cstring, fileType)
initTagLibFile(path, cfile)
proc writeTags*(file: TagLibFile) =
## Write tags to the file.
discard taglib_file_save(file.cfile)
proc close*(file: var TagLibFile) =
## Close the file and free resources.
if not file.cfile.isNil:
taglib_tag_free_strings()
taglib_file_free(file.cfile)
file.cfile = nil
file.tag = nil
file.ap = nil
#proc `=destroy`*(file: TagLibFile) =
# ## Destroy the file and free resources.
# close(file)
{.push inline.}
proc length*(file: TagLibFile): int = taglib_audioproperties_length(file.ap)
proc bitrate*(file: TagLibFile): int = taglib_audioproperties_bitrate(file.ap)
proc samplerate*(file: TagLibFile): int = taglib_audioproperties_samplerate(file.ap)
proc channels*(file: TagLibFile): int = taglib_audioproperties_channels(file.ap)
proc title*(file: TagLibFile): string = $taglib_tag_title(file.tag)
proc artist*(file: TagLibFile): string = $taglib_tag_artist(file.tag)
proc album*(file: TagLibFile): string = $taglib_tag_album(file.tag)
proc comment*(file: TagLibFile): string = $taglib_tag_comment(file.tag)
proc genre*(file: TagLibFile): string = $taglib_tag_genre(file.tag)
proc year*(file: TagLibFile): int = taglib_tag_year(file.tag).int
proc track*(file: TagLibFile): int = taglib_tag_track(file.tag).int
proc `title=`*(file: var TagLibFile, title: string) = taglib_tag_set_title(file.tag, title.cstring)
proc `artist=`*(file: var TagLibFile, artist: string) = taglib_tag_set_artist(file.tag, artist.cstring)
proc `album=`*(file: var TagLibFile, album: string) = taglib_tag_set_album(file.tag, album.cstring)
proc `comment=`*(file: var TagLibFile, comment: string) = taglib_tag_set_comment(file.tag, comment.cstring)
proc `genre=`*(file: var TagLibFile, genre: string) = taglib_tag_set_genre(file.tag, genre.cstring)
proc `year=`*(file: var TagLibFile, year: int) = taglib_tag_set_year(file.tag, year.cuint)
proc `track=`*(file: var TagLibFile, track: int) = taglib_tag_set_track(file.tag, track.cuint)
proc albumArtist*(file: TagLibFile): string =
## Get the album artist of the file.
let albumArtist = taglib_property_get(file.cfile, "ALBUMARTIST")
if albumArtist.isNil:
return ""
else:
return $albumArtist
proc `albumArtist=`*(file: var TagLibFile, albumArtist: string) =
## Set the album artist of the file.
taglib_property_set(file.cfile, "ALBUMARTIST", albumArtist.cstring)
proc discNumber*(file: TagLibFile): int =
## Get the disc number of the file.
let discNumber = taglib_property_get(file.cfile, "DISCNUMBER")
if discNumber.isNil:
return 0
else:
return parseInt($discNumber)
proc `discNumber=`*(file: var TagLibFile, discNumber: int) =
## Set the disc number of the file.
taglib_property_set(file.cfile, "DISCNUMBER".cstring, ($discNumber).cstring)
# Other properties we could use:
# - SUBTITLE
# - DATE
# - COMPOSER
# - TITLESORT
# - ARTISTSORT
# - ALBUMSORT
# - ALBUMARTISTSORT
{.pop.} # inline