diff --git a/src/main/nim/wdiwtlt/taglib.nim b/src/main/nim/wdiwtlt/taglib.nim new file mode 100644 index 0000000..c5dea18 --- /dev/null +++ b/src/main/nim/wdiwtlt/taglib.nim @@ -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