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.
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:
Related Topics
Blue Highlighting/Focus Ring on Catalyst App
Example of Dispatch_Once in Swift
Does Kotlin Has Extension Class to Interface Like Swift
Key-Value Coding (Kvc) with Array/Dictionary in Swift
How to Properly Implement the Equatable Protocol in a Class Hierarchy
Navigationview Doesn't Display Correctly When Using Tabview in Swiftui
Display All Available Wifi Connections with Swift in Os X
Why Do I Need to Declare an Optional Value as Nil Explicitly in Struct - Swift
Iterating Through an Enum in Swift 3.0
How to Change Gb-2312 Encoding to Utf-8
Multi-Component Picker (Uipickerview) in Swiftui
How to Make Apple Sign in Revoke Token Post Request
How to Use Image Literal in Xcode 13
Find Item of Specific Type in Array
Target Parameter in Dispatchqueue
How to Handle Multiple Network Call in Alamofire