214 lines
9.1 KiB
Swift
214 lines
9.1 KiB
Swift
//
|
||
// AddViewController.swift
|
||
// MusicPlayer
|
||
//
|
||
// Created by Mr.Zhou on 2024/3/27.
|
||
//
|
||
|
||
import UIKit
|
||
import AVFoundation
|
||
import Photos
|
||
class AddViewController: UIViewController {
|
||
|
||
override func viewDidLoad() {
|
||
super.viewDidLoad()
|
||
//设置圆角
|
||
view.layer.masksToBounds = true
|
||
view.layer.maskedCorners = [.layerMinXMinYCorner, .layerMaxXMinYCorner]
|
||
view.layer.cornerRadius = 18*width
|
||
}
|
||
override func viewWillAppear(_ animated: Bool) {
|
||
super.viewWillAppear(animated)
|
||
NotificationCenter.notificationKey.add(observer: self, selector: #selector(successfullCreateAction), notificationName: .creat_music)
|
||
}
|
||
override func viewWillDisappear(_ animated: Bool) {
|
||
super.viewWillDisappear(animated)
|
||
NotificationCenter.default.removeObserver(self)
|
||
}
|
||
//前往相册获取音视频文件
|
||
@IBAction func action1Click(_ sender: UIButton) {
|
||
getVideo()
|
||
}
|
||
//前往文件夹获取音视频文件
|
||
@IBAction func action2Click(_ sender: UIButton) {
|
||
var documentPicker:UIDocumentPickerViewController?
|
||
if #available(iOS 14, *) {
|
||
//访问原始路径,展示类型为视频,音频
|
||
documentPicker = UIDocumentPickerViewController(forOpeningContentTypes: [.mp3,.mpeg4Movie,.mpeg4Audio, .audio, .movie], asCopy: false)
|
||
}else {
|
||
//允许展示的数据格式(视频,音频)
|
||
let types:[String] = ["public.movie","public.audio"]
|
||
// 创建并配置UIDocumentPickerViewController实例
|
||
documentPicker = UIDocumentPickerViewController(documentTypes: types, in: .open)
|
||
}
|
||
documentPicker!.delegate = self
|
||
documentPicker!.modalPresentationStyle = .formSheet
|
||
// 展示文档选择器
|
||
present(documentPicker!, animated: true)
|
||
}
|
||
//创建一个新的音乐实体
|
||
private func createMusic(_ title:String, duration:Double, cover:UIImage, url:URL) {
|
||
//创建一个沙盒地址存放视频/音频
|
||
let number = Int(arc4random_uniform(8999) + 1000)
|
||
let path = "\(number)\(Date().timeZone().toString(.custom("HH:mm:ss-MMMdd-YYYY")))\(title)"
|
||
//视频沙盒保存地址
|
||
let videoSaveUrl = URL(fileURLWithPath: NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first!).appendingPathComponent(path).path
|
||
let urlAsset = AVURLAsset(url:url)
|
||
let session = AVAssetExportSession(asset: urlAsset, presetName: AVAssetExportPresetHighestQuality)
|
||
session?.outputURL = URL(fileURLWithPath: videoSaveUrl)
|
||
session?.outputFileType = .mp4
|
||
session?.exportAsynchronously(completionHandler: {
|
||
let exportState = session?.status
|
||
switch exportState{
|
||
case .failed:
|
||
print("Export Failed:\(String(describing: session?.error))")
|
||
break
|
||
case .completed:
|
||
//导出完成
|
||
print("Export Complete")
|
||
break
|
||
default:
|
||
break
|
||
}
|
||
})
|
||
//处理完成
|
||
let music = MusicModel.create()
|
||
music.identifier = Date().timeZone().toString(.custom("HH:mm:ss/MM-dd/YYYY"))
|
||
//获取路径最后一个组件作为标题
|
||
music.title = title
|
||
music.duration = duration
|
||
music.cover = cover.pngData()!
|
||
music.isLocal = false
|
||
music.path = path
|
||
music.creationTime = Date().timeZone()
|
||
music.lastTime = nil
|
||
MusicModel.save()
|
||
print("Resources have been successfully accessed")
|
||
}
|
||
@objc private func successfullCreateAction() {
|
||
DispatchQueue.main.async {
|
||
[weak self] in
|
||
self?.dismiss(animated: true)
|
||
}
|
||
}
|
||
}
|
||
//MARK: - 相册与文件选择处理
|
||
extension AddViewController: UIImagePickerControllerDelegate & UINavigationControllerDelegate, UIDocumentPickerDelegate {
|
||
//取消
|
||
func imagePickerControllerDidCancel(_ picker: UIImagePickerController) {
|
||
picker.dismiss(animated: true) {
|
||
print("Failure to complete selection event")
|
||
}
|
||
}
|
||
//获取选择的图像内容
|
||
func imagePickerController(_ picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [UIImagePickerController.InfoKey : Any]) {
|
||
picker.dismiss(animated: true) {[weak self] in
|
||
let videoUrl = info[.mediaURL] as! URL
|
||
print(videoUrl)
|
||
//根据路径设置图片
|
||
let asset = AVURLAsset(url: videoUrl, options: nil)
|
||
print("Select the real path of the file:\(videoUrl)")
|
||
let data = self?.setPathToData(videoUrl, asset: asset)
|
||
self?.createMusic(data!.2, duration: data!.0, cover: data!.1, url: videoUrl)
|
||
NotificationCenter.notificationKey.post(notificationName: .creat_music)
|
||
// //更新选择视频
|
||
// picker.dismiss(animated: true) {
|
||
// [weak self] in
|
||
// //获取资源库信息
|
||
// guard let passet = info[.phAsset] as? PHAsset else {
|
||
// print("Selected resources failed to load")
|
||
// return
|
||
// }
|
||
// //视频数据选项
|
||
// let options:PHVideoRequestOptions = .init()
|
||
// //视频保持原始版本
|
||
// options.version = .original
|
||
// options.deliveryMode = .automatic
|
||
// //开通网络访问权限
|
||
//// options.isNetworkAccessAllowed = true
|
||
// PHImageManager.default().requestAVAsset(forVideo: passet, options: options) { [weak self] (asset, audioMix, info) in
|
||
// var videoUrl:URL?
|
||
// guard let urlAsset = asset as? AVURLAsset else {
|
||
// print("Selected resources failed to load")
|
||
// return
|
||
// }
|
||
// videoUrl = urlAsset.url as URL
|
||
// print("Select the real path of the file:\(videoUrl!)")
|
||
// let data = self?.setPathToData(videoUrl!, asset: urlAsset)
|
||
// self?.createMusic(data!.2, duration: data!.0, cover: data!.1, path: videoUrl!)
|
||
// NotificationCenter.notificationKey.post(notificationName: .creat_music)
|
||
// }
|
||
// }
|
||
}
|
||
}
|
||
//文件选择
|
||
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL]) {
|
||
guard let selectedFileURL = urls.first else {
|
||
return
|
||
}
|
||
progressData(selectedFileURL)
|
||
}
|
||
|
||
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController) {
|
||
// 用户取消选取
|
||
print("Failure to complete selection event")
|
||
}
|
||
|
||
//安全协议加载用户选择的数据
|
||
private func progressData(_ url:URL) {
|
||
//获取是否能够安全访问路径权限
|
||
let authozied = url.startAccessingSecurityScopedResource()
|
||
if authozied == true {
|
||
//允许安全访问,通过文件协调器读取文件真实地址
|
||
let fileCoordinator = NSFileCoordinator()
|
||
fileCoordinator.coordinate(readingItemAt: url, options: .withoutChanges, error: nil) { [weak self] (newUrl) in
|
||
// 处理选取的音频文件
|
||
print("Select the real path of the file:\(newUrl)")
|
||
let data = self?.setPathToData(newUrl, asset: .init(url: newUrl))
|
||
self?.createMusic(data!.2, duration: data!.0, cover: data!.1, url: newUrl)
|
||
NotificationCenter.notificationKey.post(notificationName: .creat_music)
|
||
}
|
||
}else {
|
||
print("Selected resources failed to load")
|
||
}
|
||
//停止安全访问权限
|
||
url.stopAccessingSecurityScopedResource()
|
||
}
|
||
//根据真实路径获取视频/音频长度,第一帧,标题
|
||
private func setPathToData(_ url:URL, asset:AVURLAsset) -> (TimeInterval,UIImage,String){
|
||
//长度
|
||
var duration:TimeInterval = 0
|
||
let time = asset.duration
|
||
// if #available(iOS 16, *) {
|
||
// do {
|
||
// time = try await asset.load(.duration)
|
||
// } catch {
|
||
// print("Conversion to time failed")
|
||
// }
|
||
// }else {
|
||
// time = asset.duration
|
||
// }
|
||
duration = CMTimeGetSeconds(time)
|
||
//获取第一帧
|
||
let gen = AVAssetImageGenerator(asset: asset)
|
||
gen.appliesPreferredTrackTransform = true
|
||
//获取时间点
|
||
let firstTime = CMTimeMakeWithSeconds(0.0, preferredTimescale: 1)
|
||
var actualTime:CMTime = CMTimeMakeWithSeconds(0, preferredTimescale: 0)
|
||
var firstImage:UIImage!
|
||
do {
|
||
//获取第一帧作为封面
|
||
let image = try gen.copyCGImage(at: firstTime, actualTime: &actualTime)
|
||
firstImage = UIImage(cgImage: image)
|
||
} catch {
|
||
//获取失败
|
||
print("Failed to get file the first image")
|
||
//给予初始值
|
||
firstImage = .init(named: "End Of Days")
|
||
}
|
||
//获取地址最后一组内容作为标题
|
||
let title:String = url.lastPathComponent
|
||
return (duration,firstImage,title)
|
||
}
|
||
}
|