user6777252
user6777252

Reputation:

Is it possible to save a music from the Ipod library into my app with swift?

I have the reference of an MPMediaItem when a user selects an audio from the iPod library. I am getting the asset URL of that item by using

 let url = item.valueForProperty(MPMediaItemPropertyAssetURL)

But this is not giving me the exact physical location of the file, instead, it is giving me an URL w.r.t iPod library.

ipod-library://item/item.mp3?id=1840064795502796074

Is there a way to get the physical URL of a song from an iPod library?

EDIT - actually I want to extract NSData from the physical file and send it to my backend server, so I need the physical file URL and not the relative URL

MPmediaPickerController is working, I select the song and its playing but I don't want to play the song.I have tried to upload the audio files to a server. And I have using MPMedia Picker view in list audio, when I am going select the audio I will upload to server(HTTP), How can I do this??? How to accessing the media library with Swift code?

Upvotes: 9

Views: 3504

Answers (2)

Rob
Rob

Reputation: 438287

Adapting Krishna's answer, which uses AVAssetExportSession to save the MPMediaItem to a file, you can do something like the following in Swift 3:

/// Export MPMediaItem to temporary file.
///
/// - Parameters:
///   - assetURL: The `assetURL` of the `MPMediaItem`.
///   - completionHandler: Closure to be called when the export is done. The parameters are a boolean `success`, the `URL` of the temporary file, and an optional `Error` if there was any problem. The parameters of the closure are:
///
///   - fileURL: The `URL` of the temporary file created for the exported results.
///   - error: The `Error`, if any, of the asynchronous export process.

func export(_ assetURL: URL, completionHandler: @escaping (_ fileURL: URL?, _ error: Error?) -> ()) {
    let asset = AVURLAsset(url: assetURL)
    guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
        completionHandler(nil, ExportError.unableToCreateExporter)
        return
    }

    let fileURL = URL(fileURLWithPath: NSTemporaryDirectory())
        .appendingPathComponent(NSUUID().uuidString)
        .appendingPathExtension("m4a")

    exporter.outputURL = fileURL
    exporter.outputFileType = "com.apple.m4a-audio"

    exporter.exportAsynchronously {
        if exporter.status == .completed {
            completionHandler(fileURL, nil)
        } else {
            completionHandler(nil, exporter.error)
        }
    }
}

func exampleUsage(with mediaItem: MPMediaItem) {
    if let assetURL = mediaItem.assetURL {
        export(assetURL) { fileURL, error in
            guard let fileURL = fileURL, error == nil else {
                print("export failed: \(error)")
                return
            }

            // use fileURL of temporary file here
            print("\(fileURL)")
        }
    }
}

enum ExportError: Error {
    case unableToCreateExporter
}

Or, in Swift 2:

/// Export MPMediaItem to temporary file.
///
/// - Parameters:
///   - assetURL: The `assetURL` of the `MPMediaItem`.
///   - completionHandler: Closure to be called when the export is done. The parameters are a boolean `success`, the `URL` of the temporary file, and an optional `Error` if there was any problem. The parameters of the closure are:
///
///   - fileURL: The `URL` of the temporary file created for the exported results.
///   - error: The `Error`, if any, of the asynchronous export process.

func export(assetURL: NSURL, completionHandler: (NSURL?, ErrorType?) -> ()) {
    let asset = AVURLAsset(URL: assetURL)
    guard let exporter = AVAssetExportSession(asset: asset, presetName: AVAssetExportPresetAppleM4A) else {
        completionHandler(nil, ExportError.unableToCreateExporter)
        return
    }

    let fileURL = NSURL(fileURLWithPath: NSTemporaryDirectory())
        .URLByAppendingPathComponent(NSUUID().UUIDString)!
        .URLByAppendingPathExtension("m4a")

    exporter.outputURL = fileURL
    exporter.outputFileType = "com.apple.m4a-audio"

    exporter.exportAsynchronouslyWithCompletionHandler {
        if exporter.status == .Completed {
            completionHandler(fileURL, nil)
        } else {
            completionHandler(nil, exporter.error)
        }
    }
}

func exampleUsage(with mediaItem: MPMediaItem) {
    if let assetURL = mediaItem.assetURL {
        export(assetURL) { fileURL, error in
            guard let fileURL = fileURL where error == nil else {
                print("export failed: \(error)")
                return
            }

            // use fileURL of temporary file here
            print("\(fileURL)")
        }
    }
}

enum ExportError: ErrorType {
    case unableToCreateExporter
}

As you can see, I put it in a temporary folder rather than the Documents folder. Also, I use UUID rather than the number of seconds since some reference date to generate the temporary file. But the idea is basically the same.

Upvotes: 10

Krishna Datt Shukla
Krishna Datt Shukla

Reputation: 997

After selecting the song from library convert your MPMediaItem object into NSData and upload it to server using multipart form data.

Convert MPMediaItem to NSData

-( void)mediaItemToData : (MPMediaItem * ) curItem
{
    NSURL *url = [curItem valueForProperty: MPMediaItemPropertyAssetURL];
    AVURLAsset *songAsset = [AVURLAsset URLAssetWithURL: url options:nil];

    AVAssetExportSession *exporter = [[AVAssetExportSession alloc] initWithAsset: songAsset
                                                                      presetName:AVAssetExportPresetAppleM4A];

    exporter.outputFileType =   @"com.apple.m4a-audio";

    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString * myDocumentsDirectory = ([paths count] > 0) ? [paths objectAtIndex:0] : nil;

    [[NSDate date] timeIntervalSince1970];
    NSTimeInterval seconds = [[NSDate date] timeIntervalSince1970];
    NSString *intervalSeconds = [NSString stringWithFormat:@"%0.0f",seconds];

    NSString * fileName = [NSString stringWithFormat:@"%@.m4a",intervalSeconds];

    NSString *exportFile = [myDocumentsDirectory stringByAppendingPathComponent:fileName];

    NSURL *exportURL = [NSURL fileURLWithPath:exportFile];
    exporter.outputURL = exportURL;

    // do the export
    // (completion handler block omitted)
    [exporter exportAsynchronouslyWithCompletionHandler:
     ^{
         int exportStatus = exporter.status;

         switch (exportStatus)
         {
             case AVAssetExportSessionStatusFailed:
             {
                 NSError *exportError = exporter.error;
                 NSLog (@"AVAssetExportSessionStatusFailed: %@", exportError);
                 break;
             }
             case AVAssetExportSessionStatusCompleted:
             {
                 NSLog (@"AVAssetExportSessionStatusCompleted");

                 NSData *data = [NSData dataWithContentsOfFile: [myDocumentsDirectory
                                                                 stringByAppendingPathComponent:fileName]];

                 [arrayMusic addObject:data];
                 data = nil;

                 break;
             }
             case AVAssetExportSessionStatusUnknown:
             {
                 NSLog (@"AVAssetExportSessionStatusUnknown"); break;
             }
             case AVAssetExportSessionStatusExporting:
             {
                 NSLog (@"AVAssetExportSessionStatusExporting"); break;
             }
             case AVAssetExportSessionStatusCancelled:
             {
                 NSLog (@"AVAssetExportSessionStatusCancelled"); break;
             }
             case AVAssetExportSessionStatusWaiting:
             {
                 NSLog (@"AVAssetExportSessionStatusWaiting"); break;
             }
             default:
             {
                 NSLog (@"didn't get export status"); break;
             }
         }
     }];

}

Upvotes: 2

Related Questions