Commit 4b9dcdaf authored by CZ1004's avatar CZ1004

修改方法测试

parent c6f00afb
......@@ -92,29 +92,64 @@ class HomeViewController:BaseViewController {
}
func setupData() {
let model1:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.duplicates.rawValue, allFileSize: 0, assets: [])
PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
self?.homeView?.model = model
})
let model2:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.similar.rawValue, allFileSize: 0, assets: [])
PhotoAndVideoMananger.mananger.fetchAllFile {[weak self] index, FileSize in
guard let self else {return}
self.homeView?.model?.allFileNumber = index
self.homeView?.model?.allFileSize = FileSize
self.homeView?.setTitle()
} completion: {[weak self] fileSize,index in
guard let self else {return}
self.homeView?.model?.allFileNumber = index
self.homeView?.model?.allFileSize = fileSize
self.homeView?.setTitle()
let model3:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.videos.rawValue, allFileSize: 0, assets: [])
let model4:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.similarScreenshots.rawValue, allFileSize: 0, assets: [])
let model5:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.screenshots.rawValue, allFileSize: 0, assets: [])
let model6:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.SimilarVideos.rawValue, allFileSize: 0, assets: [])
let model7:HomePhotosModel = HomePhotosModel(folderName: PhotsFileType.Other.rawValue, allFileSize: 0, assets: [])
PhotoVideoManager.shared.findResourceInfo { progress, model in
Print("--------\(progress)")
model1.assets = model.dupPhotos.map { innerArray in
innerArray.map { $0.localIdentifier }
}
model2.assets = model.similarPhotos.map { innerArray in
innerArray.map { $0.localIdentifier }
}
model3.assets = [model.videos.map { $0.localIdentifier }]
model4.assets = model.similarScreenShots.map { innerArray in
innerArray.map { $0.localIdentifier }
}
model5.assets = [model.screenShots.map { $0.localIdentifier }]
model6.assets = model.similarVideos.map { innerArray in
innerArray.map { $0.localIdentifier }
}
model7.assets = [model.others.map { $0.localIdentifier }]
let allModel:PhotosManagerModel = PhotosManagerModel(allFileNumber: 0, allFileSize: 0, titleModelArray: [model1,model2], otherModelArray: [model3,model4,model5,model6,model7])
self.homeView?.model = allModel
}
// PhotoDataManager.manager.loadFromFileSystem(resultModel: {[weak self] model in
//
// self?.homeView?.model = model
// })
//
// PhotoAndVideoMananger.mananger.fetchAllFile {[weak self] index, FileSize in
//
// guard let self else {return}
//
// self.homeView?.model?.allFileNumber = index
// self.homeView?.model?.allFileSize = FileSize
// self.homeView?.setTitle()
// } completion: {[weak self] fileSize,index in
//
// guard let self else {return}
//
// self.homeView?.model?.allFileNumber = index
// self.homeView?.model?.allFileSize = fileSize
// self.homeView?.setTitle()
//
// }
}
override func viewDidAppear(_ animated: Bool) {
......
import Foundation
import Photos
enum SourceType {
case video
case shotScreen
case photo
case other
}
struct AssetModel {
var resourceType: SourceType
var localIdentifier: String
var createTime: Date
var assetSize: Double
var isCloud: Bool
var width: Int
var height: Int
}
struct ResourceAllModel {
var dupPhotos: [[AssetModel]]
var similarPhotos: [[AssetModel]]
var similarScreenShots: [[AssetModel]]
var similarVideos: [[AssetModel]]
var photos: [AssetModel]
var videos: [AssetModel]
var screenShots: [AssetModel]
var others: [AssetModel]
}
class PhotoVideoManager {
static let shared = PhotoVideoManager()
private let processingQueue = DispatchQueue(label: "com.photoVideoManager.processing", qos: .userInitiated)
// MARK: - 核心方法
func findResourceInfo(progress: @escaping (Double, ResourceAllModel) -> Void) {
processingQueue.async {
let allAssets = self.findAllResource()
var resourceModel = self.createEmptyModel()
for (index, asset) in allAssets.enumerated() {
let model = self.getPropertyFromAsset(asset: asset)
self.classifyAsset(model, into: &resourceModel)
let currentProgress = Double(index + 1) / Double(allAssets.count) * 0.4
self.safeUpdateProgress(currentProgress, model: resourceModel, progress: progress)
}
self.processAdvancedFeatures(model: &resourceModel, progress: progress)
}
}
// MARK: - 私有方法
private func processAdvancedFeatures(model: inout ResourceAllModel, progress: @escaping (Double, ResourceAllModel) -> Void) {
let totalSteps = 4.0
var currentStep = 0.0
// 阶段1:处理重复照片(同时收集所有重复项的ID)
model.dupPhotos = self.findDuplicates(in: model.photos)
let duplicateIDs = self.getAllDuplicateIdentifiers(dupGroups: model.dupPhotos)
currentStep += 1
self.updateStageProgress(
currentStep: currentStep,
totalSteps: totalSteps,
model: model,
baseProgress: 0.4,
progress: progress
)
// 阶段2:处理相似照片(排除已标记重复的)
let filteredPhotos = model.photos.filter { !duplicateIDs.contains($0.localIdentifier) }
model.similarPhotos = self.findSimilar(in: filteredPhotos)
currentStep += 1
self.updateStageProgress(
currentStep: currentStep,
totalSteps: totalSteps,
model: model,
baseProgress: 0.4,
progress: progress
)
// 阶段3:处理相似截图(保持原逻辑)
model.similarScreenShots = self.findSimilar(in: model.screenShots)
currentStep += 1
self.updateStageProgress(
currentStep: currentStep,
totalSteps: totalSteps,
model: model,
baseProgress: 0.4,
progress: progress
)
// 阶段4:处理相似视频(保持原逻辑)
model.similarVideos = self.findSimilar(in: model.videos)
currentStep += 1
self.updateStageProgress(
currentStep: currentStep,
totalSteps: totalSteps,
model: model,
baseProgress: 0.4,
progress: progress
)
}
// 新增辅助方法:获取所有重复项的标识符
private func getAllDuplicateIdentifiers(dupGroups: [[AssetModel]]) -> Set<String> {
var identifiers = Set<String>()
for group in dupGroups {
for asset in group {
identifiers.insert(asset.localIdentifier)
}
}
return identifiers
}
// MARK: - 核心算法
private func findDuplicates(in assets: [AssetModel]) -> [[AssetModel]] {
var groupingDict = [String: [AssetModel]]()
for asset in assets {
// 使用更精确的组合键(时间戳+尺寸+宽高)
let timeStamp = String(format: "%.0f", asset.createTime.timeIntervalSince1970)
let key = "\(timeStamp)_\(asset.assetSize)_\(asset.width)_\(asset.height)"
groupingDict[key, default: []].append(asset)
}
return groupingDict.values.filter { $0.count > 1 }
}
private func findSimilar(in assets: [AssetModel]) -> [[AssetModel]] {
guard !assets.isEmpty else { return [] }
// 根据资源类型设置不同阈值
let typeThresholds: [SourceType: (time: TimeInterval, sizeDiff: Double)] = [
.photo: (300, 0.2), // 5分钟,20%大小差异
.shotScreen: (60, 0.1), // 1分钟,10%差异
.video: (600, 0.3) // 10分钟,30%差异
]
let threshold = typeThresholds[assets[0].resourceType] ?? (300, 0.2)
let sortedAssets = assets.sorted { $0.createTime < $1.createTime }
var groups = [[AssetModel]]()
var currentGroup: [AssetModel] = []
for asset in sortedAssets {
if let last = currentGroup.last {
let timeDiff = asset.createTime.timeIntervalSince(last.createTime)
let sizeRatio = asset.assetSize / last.assetSize
let sizeValid = sizeRatio > (1 - threshold.sizeDiff) && sizeRatio < (1 + threshold.sizeDiff)
let sameAspect = asset.width * last.height == asset.height * last.width
if timeDiff <= threshold.time && sameAspect && sizeValid {
currentGroup.append(asset)
} else {
if currentGroup.count > 1 {
groups.append(currentGroup)
}
currentGroup = [asset]
}
} else {
currentGroup.append(asset)
}
}
if currentGroup.count > 1 {
groups.append(currentGroup)
}
return groups
}
// MARK: - 辅助方法
private func safeUpdateProgress(_ value: Double, model: ResourceAllModel, progress: @escaping (Double, ResourceAllModel) -> Void) {
DispatchQueue.main.async {
progress(min(max(value, 0.0), 1.0), model)
}
}
private func updateStageProgress(
currentStep: Double,
totalSteps: Double,
model: ResourceAllModel,
baseProgress: Double,
progress: @escaping (Double, ResourceAllModel) -> Void
) {
let stageProgress = baseProgress + (currentStep / totalSteps) * (1.0 - baseProgress)
safeUpdateProgress(stageProgress, model: model, progress: progress)
}
}
// MARK: - 基础功能扩展
extension PhotoVideoManager {
private func findAllResource() -> [PHAsset] {
let fetchOptions = PHFetchOptions()
fetchOptions.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
var results = [PHAsset]()
let photoAssets = PHAsset.fetchAssets(with: .image, options: fetchOptions)
let videoAssets = PHAsset.fetchAssets(with: .video, options: fetchOptions)
photoAssets.enumerateObjects { asset, _, _ in results.append(asset) }
videoAssets.enumerateObjects { asset, _, _ in results.append(asset) }
return results
}
private func createEmptyModel() -> ResourceAllModel {
ResourceAllModel(
dupPhotos: [],
similarPhotos: [],
similarScreenShots: [],
similarVideos: [],
photos: [],
videos: [],
screenShots: [],
others: []
)
}
private func getPropertyFromAsset(asset: PHAsset) -> AssetModel {
let isCloud = !(asset.sourceType == .typeUserLibrary)
return AssetModel(
resourceType: determineResourceType(asset: asset),
localIdentifier: asset.localIdentifier,
createTime: asset.creationDate ?? Date(),
assetSize: getAssetSize(asset: asset),
isCloud: isCloud,
width: asset.pixelWidth, // 新增宽度
height: asset.pixelHeight // 新增高度
)
}
private func determineResourceType(asset: PHAsset) -> SourceType {
if asset.mediaType == .video {
return .video
}
if asset.mediaSubtypes.contains(.photoScreenshot) {
return .shotScreen
}
return asset.mediaType == .image ? .photo : .other
}
private func getAssetSize(asset: PHAsset) -> Double {
return PHAssetResource.assetResources(for: asset)
.first?.value(forKey: "fileSize") as? Double ?? 0
}
private func classifyAsset(_ asset: AssetModel, into model: inout ResourceAllModel) {
switch asset.resourceType {
case .photo: model.photos.append(asset)
case .video: model.videos.append(asset)
case .shotScreen: model.screenShots.append(asset)
case .other: model.others.append(asset)
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment