Id3 Tags with Swift

ID3 tags with Swift

I was faced with this same problem over and over so I decided to make a swift framework for it. You can find it here: https://github.com/philiphardy/ID3Edit

Add it into your Xcode project and then make sure to embed it by going to your project settings > General > Embedded Binaries

Here is how to implement it in your code:

import ID3Edit
...
do
{
// Open the file
let mp3File = try MP3File(path: "/Users/Example/Music/example.mp3")
// Use MP3File(data: data) data being an NSData object
// to load an MP3 file from memory
// NOTE: If you use the MP3File(data: NSData?) initializer make
// sure to set the path before calling writeTag() or an
// exception will be thrown

// Get song information
print("Title:\t\(mp3File.getTitle())")
print("Artist:\t\(mp3File.getArtist())")
print("Album:\t\(mp3File.getAlbum())")
print("Lyrics:\n\(mp3File.getLyrics())")

let artwork = mp3File.getArtwork()

// Write song information
mp3File.setTitle("The new song title")
mp3File.setArtist("The new artist")
mp3File.setAlbum("The new album")
mp3File.setLyrics("Yeah Yeah new lyrics")

if let newArt = NSImage(contentsOfFile: "/Users/Example/Pictures/example.png")
{
mp3File.setArtwork(newArt, isPNG: true)
}
else
{
print("The artwork referenced does not exist.")
}

// Save the information to the mp3 file
mp3File.writeTag() // or mp3.getMP3Data() returns the NSData
// of the mp3 file
}
catch ID3EditErrors.FileDoesNotExist
{
print("The file does not exist.")
}
catch ID3EditErrors.NotAnMP3
{
print("The file you attempted to open was not an mp3 file.")
}
catch {}

how to read id3 tags / other metadata from an HLS stream in swift / AVKIT

This is how I achieved it:

import UIKit
import AVKit
import AVFoundation
import MediaPlayer

class ViewController: UIViewController{

let player = AVPlayer()
var playerItem: AVPlayerItem!
let asset = AVAsset(url: URL(string: "https://db2.indexcom.com/bucket/ram/00/05/05.m3u8")!)

override func viewDidLoad() {
prepareToPlay()
player.play()
}

func prepareToPlay() {
playerItem = AVPlayerItem(asset: asset)
playerItem.addObserver(self, forKeyPath: "timedMetadata", options: [], context: nil)
player.replaceCurrentItem(with: playerItem)
printTimeStamp()
}

func printTimeStamp() {
print("▼⎺▼⎺▼⎺▼⎺▼⎺▼⎺▼⎺▼")
print("PROGRAM-DATE-TIME: ")
print(playerItem.currentDate() ?? "No timeStamp")
print("▲_▲_▲_▲_▲_▲_▲_▲\n\n")
}

override func observeValue(forKeyPath: String?, of: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) {
if forKeyPath != "timedMetadata" { return }

printTimeStamp()

let data: AVPlayerItem = of as! AVPlayerItem

guard let timedMetadata = data.timedMetadata else { return }

for item in timedMetadata {
switch item.commonKey {

case .commonKeyAlbumName?:
print("AlbumName: \(item.value!)")
case .commonKeyArtist?:
print("Artist: \(item.value!)")
case .commonKeyArtwork?:
print("Artwork: \(item.value!)")
case .commonKeyAuthor?:
print("Author: \(item.value!)")
case .commonKeyContributor?:
print("Contributor: \(item.value!)")
case .commonKeyCopyrights?:
print("Copyrights: \(item.value!)")
case .commonKeyCreationDate?:
print("CreationDate: \(item.value!)")
case .commonKeyCreator?:
print("creator: \(item.value!)")
case .commonKeyDescription?:
print("Description: \(item.value!)")
case .commonKeyFormat?:
print("Format: \(item.value!)")
case .commonKeyIdentifier?:
print("Identifier: \(item.value!)")
case .commonKeyLanguage?:
print("Language: \(item.value!)")
case .commonKeyMake?:
print("Make: \(item.value!)")
case .commonKeyModel?:
print("Model: \(item.value!)")
case .commonKeyPublisher?:
print("Publisher: \(item.value!)")
case .commonKeyRelation?:
print("Relation: \(item.value!)")
case .commonKeySoftware?:
print("Software: \(item.value!)")
case .commonKeySubject?:
print("Subject: \(item.value!)")
case .commonKeyTitle?:
print("Title: \(item.value!)")
case .commonKeyType?:
print("Type: \(item.value!)")

case .id3MetadataKeyAlbumTitle?:
print("id3MetadataKeyAlbumTitle: \(item.value!)")

default:
print("other data: \(item.value!)")
}
}
}
}

Writing ID3 tags via AVMetaDataItem

I've managed to add the year tag with your code with a few modifications:

let yearTag = AVMutableMetadataItem()
yearTag.keySpace = AVMetadataKeySpaceiTunes
yearTag.key = AVMetadataiTunesMetadataKeyReleaseDate
yearTag.value = "2123"

I couldn't make it work with the ID3 keys so I thought this could be the problem, and indeed it works with these iTunes keys. Also, the value has to be a String (or NSString), not a date object.

Sample Image

AVKit and ID3 metadata keys

There are two versions of tags: ID3 2.2's 3 byte tags, and 2.3+'s 4 byte tags. The constants declared in AVMetadataKey are the 4 byte tags.

If you're seeing the 3 byte tags as the key, then it must be a file tagged with the 21-year-old v2.2 tags and AVAsset is giving them to you as-is, so you'll just need to do the conversion yourself. There aren't that many tags, so you can easily make a conversion list yourself.

HLS Metadata ID3 tag not working

Your code works fine, the reason of this problem is caused by an issue from the server side.

You can use this tool mp3tag to edit the audio file - add meta data tags and upload it to server.

As examples, you can try these audios included metadata tags:

http://ice1.somafm.com/groovesalad-128-mp3

https://developer.jwplayer.com/jw-player/demos/basic/audio-metadata/assets/index.m3u8

To confirm, the above files should work fine with your code.

Unable to enumerate MP3 tags in a Swift playground

Playgrounds are sandboxed. You can't read from or write to the filesystem.

But you can read the files that are inside the Playground.

Open the project navigator:

View > Navigators > Show Project Navigator

And drop your MP3 in the Resources folder.

Once it's there, drag the file from inside the navigator to the source code area: it will make an icon representing the file URL.

You can then use your code with this file:

let url = (the file icon dragged from the project navigator)

let asset = AVURLAsset(URL: url, options: nil)
let metaData = asset.commonMetadata

for item in metaData {
if let key = item.commonKey, let value = item.stringValue {
print("key: \(key), value: \(value)")
}
}

Screenshot:

Sample Image



Related Topics



Leave a reply



Submit