瀏覽代碼

4.3a改造:移除无用代码

kln 1 周之前
父節點
當前提交
167cb13607
共有 25 個文件被更改,包括 894 次插入977 次删除
  1. 17 53
      AIPlayRingtones.xcodeproj/project.pbxproj
  2. 1 0
      AIPlayRingtones/AppPage/ASRingGeneratorVC/ASRingGeneratorVC.swift
  3. 93 0
      AIPlayRingtones/Common/ASDownloadManager/ASMediaDownloader.swift
  4. 141 0
      AIPlayRingtones/Common/ASResourceCacheHandler.swift
  5. 9 0
      AIPlayRingtones/Common/Common.swift
  6. 433 0
      AIPlayRingtones/Common/TSAudioPlayer/ASMediaPlayerController.swift
  7. 0 294
      AIPlayRingtones/Common/TSAudioPlayer/TSAudioPlayer.swift
  8. 156 0
      AIPlayRingtones/Common/TSAudioPlayer/TSBusinessAudioPlayer.swift
  9. 0 48
      AIPlayRingtones/Common/TSBandRingTool/AudioTool.swift
  10. 41 1
      AIPlayRingtones/Common/TSBandRingTool/TSBandRingTool.swift
  11. 0 55
      AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHAudioProcessing.swift
  12. 0 37
      AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHCroppedDelegate.swift
  13. 0 36
      AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHTrackProcessing.swift
  14. 0 311
      AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHWaveformView.swift
  15. 0 19
      AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHWaveformViewDelegate.swift
  16. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Contents/PkgInfo
  17. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Media/kong.txt
  18. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Output/assetsmetadata.plist
  19. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Output/metadata.plist
  20. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Output/output.plist
  21. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/Output/output.xyz
  22. 0 0
      AIPlayRingtones/Common/TSBandRingTool/null.band/projectData
  23. 2 63
      AIPlayRingtones/Common/TSNetWork/TSNetWork+Business.swift
  24. 1 41
      AIPlayRingtones/Common/TSNetWork/TSNetworkManager.swift
  25. 0 19
      AIPlayRingtones/Common/TSPurchaseTool/TSPurchaseTool.swift

+ 17 - 53
AIPlayRingtones.xcodeproj/project.pbxproj

@@ -52,25 +52,20 @@
 		3DBEA17A2DE6FFA1000C6859 /* ASInputView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA1792DE6FFA0000C6859 /* ASInputView.swift */; };
 		3DBEA17C2DE70336000C6859 /* ASSaveResultManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA17B2DE70335000C6859 /* ASSaveResultManager.swift */; };
 		3DBEA17E2DE703D6000C6859 /* ASDynamicContainer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA17D2DE703D1000C6859 /* ASDynamicContainer.swift */; };
+		3DBEA1802DE714A1000C6859 /* ASResourceCacheHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA17F2DE7149E000C6859 /* ASResourceCacheHandler.swift */; };
+		3DBEA1822DE7152C000C6859 /* ASMediaDownloader.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA1812DE71529000C6859 /* ASMediaDownloader.swift */; };
+		3DBEA1842DE71703000C6859 /* ASMediaPlayerController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DBEA1832DE71700000C6859 /* ASMediaPlayerController.swift */; };
 		3DCD56F32DDAE3E3004AAB5B /* ASRingToneCellView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56F22DDAE3DF004AAB5B /* ASRingToneCellView.swift */; };
 		3DCD56F52DDAE42A004AAB5B /* ASViewTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56F42DDAE421004AAB5B /* ASViewTool.swift */; };
 		3DCD56F92DDAE481004AAB5B /* TSBusinessAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56F62DDAE481004AAB5B /* TSBusinessAudioPlayer.swift */; };
-		3DCD56FA2DDAE481004AAB5B /* TSAudioPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56F72DDAE481004AAB5B /* TSAudioPlayer.swift */; };
 		3DCD56FD2DDAFBE5004AAB5B /* ASDownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56FC2DDAFBE4004AAB5B /* ASDownloadManager.swift */; };
 		3DCD56FF2DDAFC1B004AAB5B /* ASBusinessFileManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD56FE2DDAFC17004AAB5B /* ASBusinessFileManager.swift */; };
-		3DCD57052DDB1120004AAB5B /* TSPurchaseTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57042DDB111F004AAB5B /* TSPurchaseTool.swift */; };
 		3DCD57182DDB1158004AAB5B /* libmp3lame.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3DCD57092DDB1158004AAB5B /* libmp3lame.a */; };
-		3DCD57192DDB1158004AAB5B /* AudioTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD570D2DDB1158004AAB5B /* AudioTool.swift */; };
 		3DCD571A2DDB1158004AAB5B /* ExtAudioConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD570A2DDB1158004AAB5B /* ExtAudioConverter.m */; };
 		3DCD571B2DDB1158004AAB5B /* AudioConverter.m in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57072DDB1158004AAB5B /* AudioConverter.m */; };
-		3DCD571C2DDB1158004AAB5B /* ZHCroppedDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57152DDB1158004AAB5B /* ZHCroppedDelegate.swift */; };
-		3DCD571D2DDB1158004AAB5B /* ZHAudioProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57112DDB1158004AAB5B /* ZHAudioProcessing.swift */; };
-		3DCD571E2DDB1158004AAB5B /* ZHWaveformViewDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57122DDB1158004AAB5B /* ZHWaveformViewDelegate.swift */; };
 		3DCD571F2DDB1158004AAB5B /* TSBandRingTool.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD570F2DDB1158004AAB5B /* TSBandRingTool.swift */; };
-		3DCD57202DDB1158004AAB5B /* ZHTrackProcessing.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57132DDB1158004AAB5B /* ZHTrackProcessing.swift */; };
-		3DCD57212DDB1158004AAB5B /* ZHWaveformView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57142DDB1158004AAB5B /* ZHWaveformView.swift */; };
 		3DCD57222DDB1158004AAB5B /* tutorial-ring.mp4 in Resources */ = {isa = PBXBuildFile; fileRef = 3DCD570E2DDB1158004AAB5B /* tutorial-ring.mp4 */; };
-		3DCD57232DDB1158004AAB5B /* placeholder.band in Resources */ = {isa = PBXBuildFile; fileRef = 3DCD57102DDB1158004AAB5B /* placeholder.band */; };
+		3DCD57232DDB1158004AAB5B /* null.band in Resources */ = {isa = PBXBuildFile; fileRef = 3DCD57102DDB1158004AAB5B /* null.band */; };
 		3DCD572F2DDB1D8A004AAB5B /* ASRingLoadingView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD572E2DDB1D87004AAB5B /* ASRingLoadingView.swift */; };
 		3DCD57312DDB2A66004AAB5B /* ASGenerateRingToRingOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3DCD57302DDB2A5D004AAB5B /* ASGenerateRingToRingOperation.swift */; };
 		3DCD57342DDB38E7004AAB5B /* ringAnimation.gif in Resources */ = {isa = PBXBuildFile; fileRef = 3DCD57322DDB38E7004AAB5B /* ringAnimation.gif */; };
@@ -187,28 +182,23 @@
 		3DBEA1792DE6FFA0000C6859 /* ASInputView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASInputView.swift; sourceTree = "<group>"; };
 		3DBEA17B2DE70335000C6859 /* ASSaveResultManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASSaveResultManager.swift; sourceTree = "<group>"; };
 		3DBEA17D2DE703D1000C6859 /* ASDynamicContainer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASDynamicContainer.swift; sourceTree = "<group>"; };
+		3DBEA17F2DE7149E000C6859 /* ASResourceCacheHandler.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASResourceCacheHandler.swift; sourceTree = "<group>"; };
+		3DBEA1812DE71529000C6859 /* ASMediaDownloader.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASMediaDownloader.swift; sourceTree = "<group>"; };
+		3DBEA1832DE71700000C6859 /* ASMediaPlayerController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASMediaPlayerController.swift; sourceTree = "<group>"; };
 		3DCD56F22DDAE3DF004AAB5B /* ASRingToneCellView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASRingToneCellView.swift; sourceTree = "<group>"; };
 		3DCD56F42DDAE421004AAB5B /* ASViewTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASViewTool.swift; sourceTree = "<group>"; };
 		3DCD56F62DDAE481004AAB5B /* TSBusinessAudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBusinessAudioPlayer.swift; sourceTree = "<group>"; };
-		3DCD56F72DDAE481004AAB5B /* TSAudioPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSAudioPlayer.swift; sourceTree = "<group>"; };
 		3DCD56FC2DDAFBE4004AAB5B /* ASDownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASDownloadManager.swift; sourceTree = "<group>"; };
 		3DCD56FE2DDAFC17004AAB5B /* ASBusinessFileManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASBusinessFileManager.swift; sourceTree = "<group>"; };
-		3DCD57042DDB111F004AAB5B /* TSPurchaseTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSPurchaseTool.swift; sourceTree = "<group>"; };
 		3DCD57062DDB1158004AAB5B /* AudioConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AudioConverter.h; sourceTree = "<group>"; };
 		3DCD57072DDB1158004AAB5B /* AudioConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AudioConverter.m; sourceTree = "<group>"; };
 		3DCD57082DDB1158004AAB5B /* ExtAudioConverter.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExtAudioConverter.h; sourceTree = "<group>"; };
 		3DCD57092DDB1158004AAB5B /* libmp3lame.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; path = libmp3lame.a; sourceTree = "<group>"; };
 		3DCD570A2DDB1158004AAB5B /* ExtAudioConverter.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ExtAudioConverter.m; sourceTree = "<group>"; };
 		3DCD570B2DDB1158004AAB5B /* lame.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = lame.h; sourceTree = "<group>"; };
-		3DCD570D2DDB1158004AAB5B /* AudioTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AudioTool.swift; sourceTree = "<group>"; };
 		3DCD570E2DDB1158004AAB5B /* tutorial-ring.mp4 */ = {isa = PBXFileReference; lastKnownFileType = file; path = "tutorial-ring.mp4"; sourceTree = "<group>"; };
 		3DCD570F2DDB1158004AAB5B /* TSBandRingTool.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TSBandRingTool.swift; sourceTree = "<group>"; };
-		3DCD57102DDB1158004AAB5B /* placeholder.band */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = placeholder.band; sourceTree = "<group>"; };
-		3DCD57112DDB1158004AAB5B /* ZHAudioProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZHAudioProcessing.swift; sourceTree = "<group>"; };
-		3DCD57122DDB1158004AAB5B /* ZHWaveformViewDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZHWaveformViewDelegate.swift; sourceTree = "<group>"; };
-		3DCD57132DDB1158004AAB5B /* ZHTrackProcessing.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZHTrackProcessing.swift; sourceTree = "<group>"; };
-		3DCD57142DDB1158004AAB5B /* ZHWaveformView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZHWaveformView.swift; sourceTree = "<group>"; };
-		3DCD57152DDB1158004AAB5B /* ZHCroppedDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ZHCroppedDelegate.swift; sourceTree = "<group>"; };
+		3DCD57102DDB1158004AAB5B /* null.band */ = {isa = PBXFileReference; lastKnownFileType = wrapper; path = null.band; sourceTree = "<group>"; };
 		3DCD572D2DDB1976004AAB5B /* AIPlayRingtones-Bridging-Header.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "AIPlayRingtones-Bridging-Header.h"; sourceTree = "<group>"; };
 		3DCD572E2DDB1D87004AAB5B /* ASRingLoadingView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASRingLoadingView.swift; sourceTree = "<group>"; };
 		3DCD57302DDB2A5D004AAB5B /* ASGenerateRingToRingOperation.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ASGenerateRingToRingOperation.swift; sourceTree = "<group>"; };
@@ -370,7 +360,7 @@
 			isa = PBXGroup;
 			children = (
 				3DCD56F62DDAE481004AAB5B /* TSBusinessAudioPlayer.swift */,
-				3DCD56F72DDAE481004AAB5B /* TSAudioPlayer.swift */,
+				3DBEA1832DE71700000C6859 /* ASMediaPlayerController.swift */,
 			);
 			path = TSAudioPlayer;
 			sourceTree = "<group>";
@@ -379,18 +369,11 @@
 			isa = PBXGroup;
 			children = (
 				3DCD56FC2DDAFBE4004AAB5B /* ASDownloadManager.swift */,
+				3DBEA1812DE71529000C6859 /* ASMediaDownloader.swift */,
 			);
 			path = ASDownloadManager;
 			sourceTree = "<group>";
 		};
-		3DCD57032DDB1118004AAB5B /* TSPurchaseTool */ = {
-			isa = PBXGroup;
-			children = (
-				3DCD57042DDB111F004AAB5B /* TSPurchaseTool.swift */,
-			);
-			path = TSPurchaseTool;
-			sourceTree = "<group>";
-		};
 		3DCD570C2DDB1158004AAB5B /* libmp3 */ = {
 			isa = PBXGroup;
 			children = (
@@ -402,29 +385,15 @@
 			path = libmp3;
 			sourceTree = "<group>";
 		};
-		3DCD57162DDB1158004AAB5B /* ZHWaveform */ = {
-			isa = PBXGroup;
-			children = (
-				3DCD57112DDB1158004AAB5B /* ZHAudioProcessing.swift */,
-				3DCD57122DDB1158004AAB5B /* ZHWaveformViewDelegate.swift */,
-				3DCD57132DDB1158004AAB5B /* ZHTrackProcessing.swift */,
-				3DCD57142DDB1158004AAB5B /* ZHWaveformView.swift */,
-				3DCD57152DDB1158004AAB5B /* ZHCroppedDelegate.swift */,
-			);
-			path = ZHWaveform;
-			sourceTree = "<group>";
-		};
 		3DCD57172DDB1158004AAB5B /* TSBandRingTool */ = {
 			isa = PBXGroup;
 			children = (
+				3DCD570F2DDB1158004AAB5B /* TSBandRingTool.swift */,
 				3DCD57062DDB1158004AAB5B /* AudioConverter.h */,
 				3DCD57072DDB1158004AAB5B /* AudioConverter.m */,
 				3DCD570C2DDB1158004AAB5B /* libmp3 */,
-				3DCD570D2DDB1158004AAB5B /* AudioTool.swift */,
 				3DCD570E2DDB1158004AAB5B /* tutorial-ring.mp4 */,
-				3DCD570F2DDB1158004AAB5B /* TSBandRingTool.swift */,
-				3DCD57102DDB1158004AAB5B /* placeholder.band */,
-				3DCD57162DDB1158004AAB5B /* ZHWaveform */,
+				3DCD57102DDB1158004AAB5B /* null.band */,
 			);
 			path = TSBandRingTool;
 			sourceTree = "<group>";
@@ -546,8 +515,8 @@
 				3DBEA1392DE6DBE6000C6859 /* BaseClass */,
 				3DB4D4AD2DDDCED00082596A /* Ex */,
 				3DCD57172DDB1158004AAB5B /* TSBandRingTool */,
-				3DCD57032DDB1118004AAB5B /* TSPurchaseTool */,
 				3DCD56FE2DDAFC17004AAB5B /* ASBusinessFileManager.swift */,
+				3DBEA17F2DE7149E000C6859 /* ASResourceCacheHandler.swift */,
 				3DCD56FB2DDAFBD8004AAB5B /* ASDownloadManager */,
 				3DCD56F82DDAE481004AAB5B /* TSAudioPlayer */,
 				A848F8F92DD7536300B746EC /*  Notification+Ex.swift */,
@@ -824,7 +793,7 @@
 				A848F8822DD6D1AF00B746EC /* Assets.xcassets in Resources */,
 				A848F8D52DD719B600B746EC /* ring_duration.json in Resources */,
 				3DCD57222DDB1158004AAB5B /* tutorial-ring.mp4 in Resources */,
-				3DCD57232DDB1158004AAB5B /* placeholder.band in Resources */,
+				3DCD57232DDB1158004AAB5B /* null.band in Resources */,
 				3DCD57382DDB3FFA004AAB5B /* Dance.mp3 in Resources */,
 				3DCD57392DDB3FFA004AAB5B /* Gentle.mp3 in Resources */,
 				A848F8842DD6D1AF00B746EC /* LaunchScreen.storyboard in Resources */,
@@ -898,12 +867,12 @@
 				3DBEA1652DE6F390000C6859 /* ASRandomTextTool.m in Sources */,
 				A848F8E82DD74DFD00B746EC /* ASDBHistoryManager.swift in Sources */,
 				A848F89E2DD6D59C00B746EC /* TSNetWork+Business.swift in Sources */,
+				3DBEA1802DE714A1000C6859 /* ASResourceCacheHandler.swift in Sources */,
 				3DB4D4B52DE025920082596A /* ASTutorialsVC.swift in Sources */,
 				A848F8AB2DD6D75300B746EC /* ASMyRingVC.swift in Sources */,
 				A848F89F2DD6D59C00B746EC /* TSNetworkManager.swift in Sources */,
 				A848F8E32DD7286A00B746EC /* ASGenerateStyleModel.swift in Sources */,
 				3DBEA1782DE6FC66000C6859 /* ASTLLabel.swift in Sources */,
-				3DCD57052DDB1120004AAB5B /* TSPurchaseTool.swift in Sources */,
 				3DB4D4992DDC28E70082596A /* APAudioToRingVC+StackView.swift in Sources */,
 				3DBEA15A2DE6EDF1000C6859 /* UIViewController+AS.swift in Sources */,
 				3DBEA11E2DE6B229000C6859 /* NSString+AS.m in Sources */,
@@ -925,12 +894,12 @@
 				3DBEA11A2DE6B086000C6859 /* CustomTabBarController.m in Sources */,
 				A848F8B32DD6D82300B746EC /* APConfig.swift in Sources */,
 				A848F8FC2DD753A000B746EC /* ASProgressState.swift in Sources */,
+				3DBEA1822DE7152C000C6859 /* ASMediaDownloader.swift in Sources */,
 				A848F8A92DD6D74A00B746EC /* APAudioToRingVC.swift in Sources */,
 				3DBEA16A2DE6F4F2000C6859 /* ASColObserver.m in Sources */,
 				A848F8AD2DD6D75900B746EC /* APSettingVC.swift in Sources */,
 				3DBEA1442DE6E018000C6859 /* ASBaseViewController.m in Sources */,
 				A848F8912DD6D50000B746EC /* Common.swift in Sources */,
-				3DCD57192DDB1158004AAB5B /* AudioTool.swift in Sources */,
 				3DBEA13D2DE6DC38000C6859 /* ASBaseNavContentBarView.m in Sources */,
 				3DCD571A2DDB1158004AAB5B /* ExtAudioConverter.m in Sources */,
 				3DBEA1402DE6DD18000C6859 /* ASNormalNavigationBarView.m in Sources */,
@@ -939,18 +908,13 @@
 				3DBEA17A2DE6FFA1000C6859 /* ASInputView.swift in Sources */,
 				3DBEA14D2DE6E8AB000C6859 /* UILabel+AS.swift in Sources */,
 				3DB4D4932DDC25C10082596A /* APAudioToRingVM.swift in Sources */,
-				3DCD571C2DDB1158004AAB5B /* ZHCroppedDelegate.swift in Sources */,
-				3DCD571D2DDB1158004AAB5B /* ZHAudioProcessing.swift in Sources */,
-				3DCD571E2DDB1158004AAB5B /* ZHWaveformViewDelegate.swift in Sources */,
 				3DCD571F2DDB1158004AAB5B /* TSBandRingTool.swift in Sources */,
-				3DCD57202DDB1158004AAB5B /* ZHTrackProcessing.swift in Sources */,
-				3DCD57212DDB1158004AAB5B /* ZHWaveformView.swift in Sources */,
 				3DCD56F92DDAE481004AAB5B /* TSBusinessAudioPlayer.swift in Sources */,
-				3DCD56FA2DDAE481004AAB5B /* TSAudioPlayer.swift in Sources */,
 				A800FEBB2DDACAF3009DABDC /* ASRingGeneratorVC.swift in Sources */,
 				A848F8F32DD7528D00B746EC /* ASBaseOperation.swift in Sources */,
 				A848F8BB2DD6E30600B746EC /* APRingTonesVM.swift in Sources */,
 				3DBEA1712DE6F794000C6859 /* ASWindTool.swift in Sources */,
+				3DBEA1842DE71703000C6859 /* ASMediaPlayerController.swift in Sources */,
 				3DB4D49B2DDC28F20082596A /* APAudioToRingVC+Upload.swift in Sources */,
 				3DBEA1272DE6BA99000C6859 /* GlobalMacros.h in Sources */,
 				3DB4D4B22DDF0B960082596A /* FakeBlurView.swift in Sources */,

+ 1 - 0
AIPlayRingtones/AppPage/ASRingGeneratorVC/ASRingGeneratorVC.swift

@@ -107,6 +107,7 @@ class ASRingGeneratorVC: ASRingGeneratorBaseVC {
             return
         }
         audioPlayer.stop()
+
         ASDownloadManager.getDownLoadRing(urlString: model.response.musicUrl){ url,downLoad in
             if let path = url {
                 _ = kshareBand(needVip: model.response.vip, vc: self, fileURL: path, fileName: model.response.title)

+ 93 - 0
AIPlayRingtones/Common/ASDownloadManager/ASMediaDownloader.swift

@@ -0,0 +1,93 @@
+//
+//  ASMediaDownloader.swift
+//  AIPlayRingtones
+//
+//  Created by mini on 2025/5/28.
+//
+
+import AVFoundation
+import Alamofire
+
+class ASMediaDownloader {
+    
+    // MARK: - 铃声下载
+    
+    static func fetchMediaResource(
+        remoteURL: String,
+        progressUpdate: ((Double) -> Void)? = nil,
+        completion: @escaping (URL?, Bool) -> Void
+    ) {
+        if let cachedPath = ASResourceCacheHandler.locateCachedResource(
+            originalURL: remoteURL,
+            preferredExtension: nil,
+            alternativeExtension: "mp3"
+        ) {
+            completion(cachedPath, false)
+        } else {
+            _ = initiateMediaDownload(
+                sourceURL: remoteURL,
+                fallbackExtension: "mp3",
+                progressTracker: progressUpdate
+            ) { destinationURL, error in
+                completion(destinationURL, true)
+            }
+        }
+    }
+    
+    // MARK: - 下载核心方法
+    
+    static func initiateMediaDownload(
+        sourceURL: String,
+        fileExtension: String? = nil,
+        fallbackExtension: String? = nil,
+        progressTracker: ((Double) -> Void)? = nil,
+        onCompletion: @escaping (URL?, Error?) -> Void
+    ) -> DownloadRequest? {
+        
+        // 检查缓存是否存在
+        if let existingFile = ASResourceCacheHandler.locateCachedResource(
+            originalURL: sourceURL,
+            preferredExtension: fileExtension,
+            alternativeExtension: fallbackExtension
+        ) {
+            onCompletion(existingFile, nil)
+            return nil
+        }
+        
+        // 准备存储路径
+        guard let saveLocation = ASResourceCacheHandler.prepareCacheLocation(
+            for: sourceURL,
+            withExtension: fileExtension,
+            defaultExtension: fallbackExtension,
+            in: ASResourceCacheHandler.ringStoragePath,
+            completion: { _, error in
+                onCompletion(nil, error)
+            }
+        ) else {
+            return nil
+        }
+        
+        // 启动下载任务
+        return TSNetworkShared.downloadFile(urlString: sourceURL,to: saveLocation, progressHandler:progressTracker,completion: onCompletion)
+    }
+}
+
+// MARK: - 网络服务扩展
+extension ASMediaDownloader {
+    
+    private enum Constants {
+        static let audioExtension = "mp3"
+    }
+    
+    static func downloadAudioResource(
+        url: String,
+        onProgress: ((Double) -> Void)? = nil,
+        completion: @escaping (URL?, Bool) -> Void
+    ) {
+        fetchMediaResource(
+            remoteURL: url,
+            progressUpdate: onProgress,
+            completion: completion
+        )
+    }
+}

+ 141 - 0
AIPlayRingtones/Common/ASResourceCacheHandler.swift

@@ -0,0 +1,141 @@
+//
+//  ASResourceCacheHandler.swift
+//  AIPlayRingtones
+//
+//  Created by mini on 2025/5/28.
+//
+
+class ASResourceCacheHandler {
+    
+    // MARK: - 存储路径
+    
+    static var ringStoragePath: URL = {
+        return FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
+            .appendingPathComponent("ring")
+    }()
+    
+    static var universalCachePath: URL = {
+        return FileManager.default.urls(for: .cachesDirectory, in: .userDomainMask).first!
+            .appendingPathComponent("cacheAll")
+    }()
+    
+    // MARK: - 文件名生成
+    
+    static func createHashedFilename(
+        from urlString: String,
+        forcedExtension: String? = nil,
+        fallbackExtension: String? = nil
+    ) -> String? {
+        guard let sourceURL = URL(string: urlString) else { return nil }
+        
+        let baseName = sourceURL.path.md5
+        var extensionToUse = ""
+        
+        if let explicitExtension = forcedExtension {
+            extensionToUse = explicitExtension
+        } else {
+            let backupExtension = fallbackExtension ?? ""
+            extensionToUse = sourceURL.pathExtension.isEmpty ? backupExtension : sourceURL.pathExtension
+        }
+        
+        return extensionToUse.isEmpty ? baseName : "\(baseName).\(extensionToUse)"
+    }
+    
+    // MARK: - 本地缓存查询
+    
+    static func locateCachedResource(
+        originalURL: String,
+        preferredExtension: String? = nil,
+        alternativeExtension: String? = nil
+    ) -> URL? {
+        guard let filename = createHashedFilename(
+            from: originalURL,
+            forcedExtension: preferredExtension,
+            fallbackExtension: alternativeExtension
+        ) else { return nil }
+        
+        let possiblePaths = [
+            ringStoragePath.appendingPathComponent(filename),
+            universalCachePath.appendingPathComponent(filename)
+        ]
+        
+        for path in possiblePaths {
+            if FileManager.default.fileExists(atPath: path.path) {
+                print("发现缓存资源: \(path)")
+                return path
+            }
+        }
+        
+        return nil
+    }
+    
+    // MARK: - 缓存路径处理
+    
+    static func prepareCacheLocation(
+        for resourceURL: String,
+        withExtension: String? = nil,
+        defaultExtension: String? = nil,
+        in directory: URL,
+        completion: ((String?, Error?) -> Void)? = nil
+    ) -> URL? {
+        // 验证URL有效性
+        guard let validatedURL = URL(string: resourceURL) else {
+            completion?(nil, NSError(domain: "无效URL", code: 1001))
+            return nil
+        }
+        
+        // 处理本地路径情况
+        if !resourceURL.contains("http") && resourceURL.contains("/") {
+            let fullPath = resourceURL.fillCachePath
+            completion?(fullPath, nil)
+            return nil
+        }
+        
+        // 确保目录存在
+        let fileManager = FileManager.default
+        if !fileManager.fileExists(atPath: directory.path) {
+            do {
+                try fileManager.createDirectory(
+                    at: directory,
+                    withIntermediateDirectories: true,
+                    attributes: nil
+                )
+            } catch {
+                completion?(nil, error)
+                return nil
+            }
+        }
+        
+        // 生成最终文件名
+        guard let finalFilename = createHashedFilename(
+            from: resourceURL,
+            forcedExtension: withExtension,
+            fallbackExtension: defaultExtension
+        ) else {
+            completion?(nil, NSError(domain: "文件名生成失败", code: 1002))
+            return nil
+        }
+        
+        return directory.appendingPathComponent(finalFilename)
+    }
+}
+
+// MARK: - 路径扩展
+extension ASResourceCacheHandler {
+    
+    static func generateCachePath(
+        for urlString: String,
+        withExtension: String? = nil,
+        defaultExtension: String? = nil,
+        in directory: URL,
+        completion: ((String?, Error?) -> Void)? = nil
+    ) -> URL? {
+        return prepareCacheLocation(
+            for: urlString,
+            withExtension: withExtension,
+            defaultExtension: defaultExtension,
+            in: directory,
+            completion: completion
+        )
+    }
+}

+ 9 - 0
AIPlayRingtones/Common/Common.swift

@@ -344,3 +344,12 @@ public extension UIImage {
 }
 
 
+func kshareBand(needVip:Bool,
+               vc:UIViewController,
+                fileURL:URL,
+                fileName:String,
+                completion:((Bool)->Void)? = nil) -> Bool {
+
+    TSBandRingTool.creatBandRingTool().shareBandVC(vc: vc, fileURL: fileURL, fileName: fileName,completion: completion)
+    return false
+}

+ 433 - 0
AIPlayRingtones/Common/TSAudioPlayer/ASMediaPlayerController.swift

@@ -0,0 +1,433 @@
+//
+//  ASMediaPlayerController.swift
+//  AIPlayRingtones
+//
+//  Created by mini on 2025/5/28.
+//
+
+import AVFoundation
+import Alamofire
+
+class ASMediaPlayerController {
+    
+    // MARK: - 单例与状态管理
+    
+    static let main = ASMediaPlayerController()
+    
+    enum PlaybackStatus: Equatable {
+        case playing
+        case paused
+        case stopped
+        case buffering(Float)
+        case volumeAdjusted(Float)
+        case timeUpdated(Double)
+    }
+    
+    private var mediaEngine: ASAudioEngine?
+    
+    var onStatusChange: ((PlaybackStatus) -> Void)?
+    var onTimeUpdate: ((Double, Double) -> Void)?
+    
+    private(set) var currentStatus: PlaybackStatus = .stopped
+    var totalDuration: Double {
+        return mediaEngine?.trackDuration ?? 0.0
+    }
+    
+    var isActive: Bool {
+        return mediaEngine?.isActive ?? false
+    }
+    
+    var isBuffering: Bool {
+        if case .buffering(let progress) = currentStatus {
+            return progress < 1.0
+        }
+        return false
+    }
+    
+    var currentPosition: Double {
+        return mediaEngine?.currentPosition ?? 0.0
+    }
+    
+    var playbackProgress: Double {
+        let progress = currentPosition / totalDuration
+        return progress.isNaN ? 0.0 : progress
+    }
+    
+    var isReady: Bool {
+        return mediaEngine?.isReady ?? false
+    }
+    
+    var activeMediaURL: String = ""
+    var localMediaPath: URL?
+    var mediaIndex: IndexPath?
+    
+    private var shouldCancelAfterLoad = false
+
+    // MARK: - 播放控制
+    
+    func navigateTo(time: Double) {
+        mediaEngine?.seek(to: time)
+    }
+    
+    func isCurrentMedia(url: String, localPath: URL? = nil, index: IndexPath? = nil) -> Bool {
+        guard activeMediaURL == url else { return false }
+        
+        if let currentIndex = mediaIndex,
+           let newIndex = index,
+           currentIndex != newIndex {
+            return false
+        }
+        
+        if let currentLocalPath = localMediaPath,
+           let newLocalPath = localPath,
+           currentLocalPath != newLocalPath {
+            return false
+        }
+        
+        return true
+    }
+    
+    func prepareLocalMedia(at url: URL) {
+        self.mediaEngine = ASAudioEngine(mediaURL: url)
+    }
+    
+    func startPlayback(
+        of urlString: String?,
+        localPath: URL? = nil,
+        shouldLoop: Bool = false,
+        index: IndexPath? = nil
+    ) {
+        stopPlayback()
+        
+        guard let mediaURL = urlString else { return }
+        
+        activeMediaURL = mediaURL
+        localMediaPath = localPath
+        mediaIndex = index
+        
+        let playbackHandler: (URL) -> Void = { [weak self] url in
+            guard let self = self else { return }
+            
+            print("正在播放媒体: \(self.activeMediaURL)")
+            print("媒体路径: \(url)")
+            
+            self.mediaEngine = ASAudioEngine(mediaURL: url)
+            self.mediaEngine?.loopEnabled = shouldLoop
+            
+            if self.mediaEngine?.volumeLevel == 0 {
+                self.adjustVolume(to: 1.0)
+            }
+            
+            self.mediaEngine?.onTimeUpdate = { [weak self] position, duration in
+                self?.onTimeUpdate?(position, duration)
+                self?.updateStatus(.timeUpdated(position))
+            }
+            
+            self.beginPlayback()
+            print(self.mediaEngine?.trackDuration)
+            
+            self.mediaEngine?.onCompletion = { [weak self] finished in
+                guard let self = self else { return }
+                if finished, !(self.mediaEngine?.loopEnabled ?? false) {
+                    self.stopPlayback()
+                }
+            }
+        }
+        
+        shouldCancelAfterLoad = false
+        
+        if let localURL = self.localMediaPath, FileManager.default.fileExists(atPath: localURL.path) {
+            playbackHandler(localURL)
+        } else {
+            self.updateStatus(.buffering(0.0))
+            
+            _ = ASMediaDownloader.fetchMediaResource(
+                remoteURL: mediaURL,
+                progressUpdate: { progress in
+                    print("下载进度: \(progress)")
+                },
+                completion: { [weak self] url, success in
+                    guard let self = self else { return }
+                    
+                    self.updateStatus(.buffering(1.0))
+                
+                    if self.shouldCancelAfterLoad || self.activeMediaURL != mediaURL {
+                        self.shouldCancelAfterLoad = false
+                        return
+                    }
+                    
+                    if let url = url {
+                        playbackHandler(url)
+                    } else {
+                        self.stopPlayback()
+                    }
+                }
+            )
+        }
+    }
+    
+    func beginPlayback() {
+        self.mediaEngine?.play()
+        updateStatus(.playing)
+    }
+    
+    func stopPlayback() {
+        self.mediaEngine?.onTimeUpdate = nil
+        shouldCancelAfterLoad = true
+        activeMediaURL = ""
+        self.mediaEngine?.stop()
+        updateStatus(.stopped)
+    }
+    
+    func pausePlayback() {
+        shouldCancelAfterLoad = true
+        self.mediaEngine?.pause()
+        updateStatus(.paused)
+    }
+    
+    func adjustVolume(to level: Float) {
+        self.mediaEngine?.volumeLevel = level
+        updateStatus(.volumeAdjusted(level))
+    }
+    
+    func toggleMute() -> Float {
+        let newVolume:Float = (mediaEngine?.volumeLevel ?? 0.0) == 0.0 ? 1.0 : 0.0
+        adjustVolume(to: newVolume)
+        return newVolume
+    }
+    
+    private func updateStatus(_ status: PlaybackStatus) {
+        if case .timeUpdated(let time) = status {} else {
+            print("播放状态更新: \(status)")
+        }
+        currentStatus = status
+        DispatchQueue.main.async {
+            self.onStatusChange?(status)
+        }
+    }
+    
+    deinit {
+        print("播放控制器已释放")
+    }
+}
+
+// MARK: - 音频文件信息扩展
+extension ASMediaPlayerController {
+    struct MediaFileDetails {
+        let fileSize: UInt64?
+        let duration: Double?
+        let title: String?
+    }
+
+    static func analyzeMediaFile(at path: String) -> MediaFileDetails? {
+        guard let url = URL(string: path) else {
+            print("无效的URL路径")
+            return nil
+        }
+        
+        guard FileManager.default.fileExists(atPath: url.path) else {
+            print("文件不存在")
+            return nil
+        }
+        
+        let size = getFileSize(at: url)
+        let length = getAudioDuration(from: url)
+        let name = extractMediaTitle(from: url)
+        
+        return MediaFileDetails(
+            fileSize: size,
+            duration: length,
+            title: name
+        )
+    }
+    
+    private static func getFileSize(at url: URL) -> UInt64? {
+        do {
+            let attributes = try FileManager.default.attributesOfItem(atPath: url.path)
+            return attributes[.size] as? UInt64
+        } catch {
+            print("获取文件大小失败: \(error.localizedDescription)")
+            return nil
+        }
+    }
+    
+    private static func getAudioDuration(from url: URL) -> TimeInterval? {
+        var audioFile: AudioFileID?
+        let status = AudioFileOpenURL(url as CFURL, .readPermission, 0, &audioFile)
+        
+        guard status == noErr, let file = audioFile else {
+            print("音频文件打开失败: \(status)")
+            return nil
+        }
+        
+        var duration: Float64 = 0
+        var propertySize = UInt32(MemoryLayout.size(ofValue: duration))
+        let durationStatus = AudioFileGetProperty(
+            file,
+            kAudioFilePropertyEstimatedDuration,
+            &propertySize,
+            &duration
+        )
+        
+        AudioFileClose(file)
+        
+        return durationStatus == noErr ? duration : nil
+    }
+    
+    private static func extractMediaTitle(from fileURL: URL) -> String? {
+        guard FileManager.default.fileExists(atPath: fileURL.path) else {
+            print("文件不存在")
+            return nil
+        }
+        
+        let asset = AVAsset(url: fileURL)
+        var title: String? = nil
+        
+        for format in asset.availableMetadataFormats {
+            for item in asset.metadata(forFormat: format) {
+                if item.commonKey == .commonKeyTitle,
+                   let value = item.value as? String {
+                    title = value
+                    break
+                }
+                
+                if item.key as? String == "TIT2",
+                   let value = item.value as? String {
+                    title = value
+                    break
+                }
+            }
+            
+            if title != nil { break }
+        }
+        
+        return title ?? fileURL.deletingPathExtension().lastPathComponent
+    }
+}
+
+// MARK: - 音频引擎实现
+class ASAudioEngine: NSObject {
+    private var playbackEngine: AVPlayer?
+    private var timeObserver: Any?
+    var loopEnabled: Bool = false
+    
+    var isActive: Bool {
+        if let engine = playbackEngine {
+            if #available(iOS 10.0, *) {
+                return engine.timeControlStatus == .playing
+            } else {
+                return engine.rate > 0
+            }
+        }
+        return false
+    }
+    
+    var trackDuration: Double {
+        return playbackEngine?.currentItem?.asset.duration.seconds ?? 0.0
+    }
+    
+    var volumeLevel: Float {
+        get { return playbackEngine?.volume ?? 0.0 }
+        set { playbackEngine?.volume = newValue.clamped(to: 0.0...1.0) }
+    }
+    
+    var currentPosition: Double {
+        return playbackEngine?.currentItem?.currentTime().seconds ?? 0.0
+    }
+    
+    var isReady: Bool {
+        return playbackEngine != nil
+    }
+    
+    var onTimeUpdate: ((Double, Double) -> Void)?
+    var onCompletion: ((Bool) -> Void)?
+    
+    init?(mediaURL: URL) {
+        super.init()
+        
+        let item = AVPlayerItem(url: mediaURL)
+        playbackEngine = AVPlayer(playerItem: item)
+        
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(playbackDidFinish),
+            name: .AVPlayerItemDidPlayToEndTime,
+            object: item
+        )
+        
+        do {
+            try AVAudioSession.sharedInstance().setCategory(.playback)
+            try AVAudioSession.sharedInstance().setActive(true)
+        } catch {
+            print("音频会话配置失败: \(error.localizedDescription)")
+            return nil
+        }
+    }
+    
+    deinit {
+        stop()
+    }
+    
+    func play() {
+        guard let engine = playbackEngine else { return }
+        
+        let systemVolume = AVAudioSession.sharedInstance().outputVolume
+        print("系统音量: \(systemVolume)")
+        
+        if systemVolume == 0.0 {
+            print("请调高音量")
+        }
+        
+        engine.play()
+        observePlaybackTime()
+    }
+    
+    func pause() {
+        playbackEngine?.pause()
+    }
+    
+    func stop() {
+        playbackEngine?.pause()
+        playbackEngine?.replaceCurrentItem(with: nil)
+        playbackEngine = nil
+        removeTimeObserver()
+    }
+    
+    func seek(to time: Double) {
+        playbackEngine?.seek(to: CMTime(seconds: time, preferredTimescale: 600))
+    }
+    
+    @objc private func playbackDidFinish() {
+        if loopEnabled {
+            seek(to: 0.0)
+            play()
+        }
+        onCompletion?(true)
+    }
+    
+    private func observePlaybackTime() {
+        let interval = CMTime(seconds: 0.1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
+        timeObserver = playbackEngine?.addPeriodicTimeObserver(
+            forInterval: interval,
+            queue: .main
+        ) { [weak self] time in
+            guard let self = self else { return }
+            let position = time.seconds
+            self.onTimeUpdate?(position, self.trackDuration)
+        }
+    }
+    
+    private func removeTimeObserver() {
+        if let observer = timeObserver {
+            playbackEngine?.removeTimeObserver(observer)
+            timeObserver = nil
+        }
+    }
+}
+
+// MARK: - 扩展工具
+extension Float {
+    func clamped(to range: ClosedRange<Float>) -> Float {
+        return max(range.lowerBound, min(self, range.upperBound))
+    }
+}

+ 0 - 294
AIPlayRingtones/Common/TSAudioPlayer/TSAudioPlayer.swift

@@ -1,294 +0,0 @@
-//
-//  TSAudioPlayer.swift
-//  Girly
-//
-//  Created by 100Years on 2025/1/9.
-//
-
-import AVFoundation
-
-class TSAudioPlayer: NSObject {
-    private var player: AVPlayer?
-    private var timeObserverToken: Any?
-    var isLooping: Bool = false
-    
-    override init() {
-        super.init()
-    }
-    
-    var isPlaying: Bool {
-//        return player?.rate != 0 && player?.error == nil
-        
-        if let player = player {
-            if #available(iOS 10.0, *) {
-                return player.timeControlStatus == .playing
-            } else {
-                return player.rate > 0
-            }
-        }
-        return false
-    }
-    
-    var duration: Double {
-        if let currentItem = player?.currentItem {
-            return CMTimeGetSeconds(currentItem.asset.duration)
-        }
-        return 0.0
-    }
-    
-    var volume: Float {
-        get {
-            return player?.volume ?? 0.0
-        }
-        set {
-            player?.volume = max(0.0, min(newValue, 1.0))
-        }
-    }
-    
-    var currentTime: Double {
-        if let currentItem = player?.currentItem {
-            return CMTimeGetSeconds(currentItem.currentTime())
-        }
-        return 0.0
-    }
-    
-    var playerUsable: Bool {
-        return player != nil
-    }
-    
-    var currentTimeChanged: ((Double,Double) -> Void)?
-    var audioPlayerDidFinishHandle: ((Bool) -> Void)?
-    
-    /// 初始化播放器
-    /// - Parameter url: 音频文件的 URL
-    init?(url: URL) {
-        super.init()
-        
-        let playerItem = AVPlayerItem(url: url)
-        player = AVPlayer(playerItem: playerItem)
-        
-        // 监听播放完成事件
-        NotificationCenter.default.addObserver(
-            self,
-            selector: #selector(playerDidFinishPlaying),
-            name: .AVPlayerItemDidPlayToEndTime,
-            object: playerItem
-        )
-        
-        // 设置音频会话
-        do {
-            let audioSession = AVAudioSession.sharedInstance()
-            try audioSession.setCategory(.playback)
-            try audioSession.setActive(true)
-        } catch {
-            print("TSAudioPlayer 音频会话设置失败: \(error.localizedDescription)")
-            return nil
-        }
-    }
-    
-    deinit {
-        stop()
-    }
-    
-    /// 开始播放音频
-    func play() {
-        guard let player = player else { return }
-        
-        let outputVolume = AVAudioSession.sharedInstance().outputVolume
-        print("TSAudioPlayer outputVolume: \(outputVolume)")
-        
-        if outputVolume == 0.0 {
-            print("Please turn up the volume".localized)
-        }
-        
-        player.play()
-        
-        // 监听播放进度
-        addTimeObserver()
-    }
-    
-    /// 暂停播放音频
-    func pause() {
-        player?.pause()
-    }
-    
-    /// 停止并销毁播放器
-    func stop() {
-        player?.pause()
-        player?.replaceCurrentItem(with: nil)
-        player = nil
-        removeTimeObserver()
-    }
-    
-    /// 设置是否重复播放
-    /// - Parameter loop: 是否循环播放
-    func setLoop(_ loop: Bool) {
-        isLooping = loop
-    }
-    
-    /// 跳转到指定时间
-    /// - Parameter time: 目标时间(秒)
-    func seek(to time: Double) {
-        if let player = player {
-            let targetTime = CMTimeMakeWithSeconds(time, preferredTimescale: 600)
-            player.seek(to: targetTime)
-        }
-    }
-    
-    /// 监听播放完成
-    @objc private func playerDidFinishPlaying() {
-        if isLooping {
-            seek(to: 0.0)
-            play()
-        }
-        audioPlayerDidFinishHandle?(true)
-    }
-    
-    /// 添加时间观察者
-    private func addTimeObserver() {
-        let interval = CMTime(seconds: 0.1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
-        timeObserverToken = player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
-            guard let self = self else { return }
-            let currentTime = CMTimeGetSeconds(time)
-            self.currentTimeChanged?(currentTime,duration)
-        }
-    }
-    
-    /// 移除时间观察者
-    private func removeTimeObserver() {
-        if let token = timeObserverToken {
-            player?.removeTimeObserver(token)
-            timeObserverToken = nil
-        }
-    }
-}
-
-//class TSAudioPlayer : NSObject, AVAudioPlayerDelegate{
-//    private var audioPlayer: AVAudioPlayer?
-//    var isLooping: Bool = false
-//    
-//    override init() {
-//        super.init()
-//    }
-//    
-//    var isPlaying:Bool{
-//        if let audioPlayer = audioPlayer {
-//            return audioPlayer.isPlaying
-//        }
-//        return false
-//    }
-//    
-//    var duration:Double{
-//        if let audioPlayer = audioPlayer {
-//            return audioPlayer.duration
-//        }
-//        return 0.0
-//    }
-//    
-//    var volume:Float{
-//        if let audioPlayer = audioPlayer {
-//            return audioPlayer.volume
-//        }
-//        return 0
-//    }
-//    
-//    var currentTime:Double{
-//        if let audioPlayer = audioPlayer {
-//            return audioPlayer.currentTime
-//        }
-//        return 0.0
-//    }
-//    
-//    //播放器是否可用
-//    var playerUsable:Bool {
-//        if audioPlayer != nil  {
-//            return true
-//        }
-//        return false
-//    }
-//
-//    var timer:GCDTimer = GCDTimer()
-//    
-//    var currentTimeChanged:((Double)->Void)?
-//    
-//    /// 初始化播放器
-//    /// - Parameter url: 音频文件的 URL
-//    init?(url: URL) {
-//        super.init()
-//        do {
-//            audioPlayer = try AVAudioPlayer(contentsOf: url)
-//            audioPlayer?.prepareToPlay()
-//            audioPlayer?.delegate = self
-//            let audioSession = AVAudioSession.sharedInstance()
-//            try audioSession.setCategory(.playback) // 设置类别为 playback
-//            try audioSession.setActive(true) // 激活音频会话
-//
-//        } catch {
-//            logPrint("TSAudioPlayer 音频文件加载失败: \(error.localizedDescription)")
-//            return nil
-//        }
-//    }
-//    
-//    /// 开始播放音频
-//    func play() {
-//        guard let audioPlayer = audioPlayer else { return }
-//        let outputVolume = AVAudioSession.sharedInstance().outputVolume
-//        logPrint("TSAudioPlayer outputVolume\(outputVolume)")
-//        
-//        if outputVolume == 0.0 {
-//            TSToastShared.showToast(text: "Please turn up the volume".localized)
-//        }
-//    
-//        audioPlayer.numberOfLoops = isLooping ? -1 : 0
-//        audioPlayer.play()
-//        
-//        timer.start(interval: 0.5, repeats: true) { [weak self]  in
-//            guard let self = self else { return }
-//            
-//            let currentTime = audioPlayer.currentTime
-//            logPrint("TSAudioPlayer Current playback time: \(currentTime) seconds")
-//            currentTimeChanged?(currentTime)
-//          }
-//    }
-//    
-//    /// 暂停播放音频
-//    func pause() {
-//        audioPlayer?.pause()
-//    }
-//    
-//    /// 停止并销毁播放器
-//    func stop() {
-//        audioPlayer?.stop()
-//        audioPlayer = nil
-//        timer.stop()
-//    }
-//    
-//    /// 设置是否重复播放
-//    /// - Parameter loop: 是否循环播放
-//    func setLoop(_ loop: Bool) {
-//        isLooping = loop
-//        audioPlayer?.numberOfLoops = loop ? -1 : 0
-//    }
-//    
-//    /// 设置音量
-//    /// - Parameter volume: 音量大小 (0.0 静音, 1.0 最大)
-//    func setVolume(_ volume: Float) {
-//        audioPlayer?.volume = max(0.0, min(volume, 1.0))
-//    }
-//    
-//    deinit {
-//        stop()
-//    }
-//
-//    var audioPlayerDidFinishHandle:((Bool)->Void)?
-//    // 实现 AVAudioPlayerDelegate 方法
-//    func audioPlayerDidFinishPlaying(_ player: AVAudioPlayer, successfully flag: Bool) {
-//        if flag {
-//            print("TSAudioPlayer 音频播放完成")
-//            
-//        } else {
-//            print("TSAudioPlayer 音频播放中断")
-//        }
-//        audioPlayerDidFinishHandle?(flag)
-//    }
-//}

+ 156 - 0
AIPlayRingtones/Common/TSAudioPlayer/TSBusinessAudioPlayer.swift

@@ -335,3 +335,159 @@ extension TSBusinessAudioPlayer{
         return songName ?? fileURL.deletingPathExtension().lastPathComponent
     }
 }
+
+class TSAudioPlayer: NSObject {
+    private var player: AVPlayer?
+    private var timeObserverToken: Any?
+    var isLooping: Bool = false
+    
+    override init() {
+        super.init()
+    }
+    
+    var isPlaying: Bool {
+//        return player?.rate != 0 && player?.error == nil
+        
+        if let player = player {
+            if #available(iOS 10.0, *) {
+                return player.timeControlStatus == .playing
+            } else {
+                return player.rate > 0
+            }
+        }
+        return false
+    }
+    
+    var duration: Double {
+        if let currentItem = player?.currentItem {
+            return CMTimeGetSeconds(currentItem.asset.duration)
+        }
+        return 0.0
+    }
+    
+    var volume: Float {
+        get {
+            return player?.volume ?? 0.0
+        }
+        set {
+            player?.volume = max(0.0, min(newValue, 1.0))
+        }
+    }
+    
+    var currentTime: Double {
+        if let currentItem = player?.currentItem {
+            return CMTimeGetSeconds(currentItem.currentTime())
+        }
+        return 0.0
+    }
+    
+    var playerUsable: Bool {
+        return player != nil
+    }
+    
+    var currentTimeChanged: ((Double,Double) -> Void)?
+    var audioPlayerDidFinishHandle: ((Bool) -> Void)?
+    
+    /// 初始化播放器
+    /// - Parameter url: 音频文件的 URL
+    init?(url: URL) {
+        super.init()
+        
+        let playerItem = AVPlayerItem(url: url)
+        player = AVPlayer(playerItem: playerItem)
+        
+        // 监听播放完成事件
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(playerDidFinishPlaying),
+            name: .AVPlayerItemDidPlayToEndTime,
+            object: playerItem
+        )
+        
+        // 设置音频会话
+        do {
+            let audioSession = AVAudioSession.sharedInstance()
+            try audioSession.setCategory(.playback)
+            try audioSession.setActive(true)
+        } catch {
+            print("TSAudioPlayer 音频会话设置失败: \(error.localizedDescription)")
+            return nil
+        }
+    }
+    
+    deinit {
+        stop()
+    }
+    
+    /// 开始播放音频
+    func play() {
+        guard let player = player else { return }
+        
+        let outputVolume = AVAudioSession.sharedInstance().outputVolume
+        print("TSAudioPlayer outputVolume: \(outputVolume)")
+        
+        if outputVolume == 0.0 {
+            print("Please turn up the volume".localized)
+        }
+        
+        player.play()
+        
+        // 监听播放进度
+        addTimeObserver()
+    }
+    
+    /// 暂停播放音频
+    func pause() {
+        player?.pause()
+    }
+    
+    /// 停止并销毁播放器
+    func stop() {
+        player?.pause()
+        player?.replaceCurrentItem(with: nil)
+        player = nil
+        removeTimeObserver()
+    }
+    
+    /// 设置是否重复播放
+    /// - Parameter loop: 是否循环播放
+    func setLoop(_ loop: Bool) {
+        isLooping = loop
+    }
+    
+    /// 跳转到指定时间
+    /// - Parameter time: 目标时间(秒)
+    func seek(to time: Double) {
+        if let player = player {
+            let targetTime = CMTimeMakeWithSeconds(time, preferredTimescale: 600)
+            player.seek(to: targetTime)
+        }
+    }
+    
+    /// 监听播放完成
+    @objc private func playerDidFinishPlaying() {
+        if isLooping {
+            seek(to: 0.0)
+            play()
+        }
+        audioPlayerDidFinishHandle?(true)
+    }
+    
+    /// 添加时间观察者
+    private func addTimeObserver() {
+        let interval = CMTime(seconds: 0.1, preferredTimescale: CMTimeScale(NSEC_PER_SEC))
+        timeObserverToken = player?.addPeriodicTimeObserver(forInterval: interval, queue: .main) { [weak self] time in
+            guard let self = self else { return }
+            let currentTime = CMTimeGetSeconds(time)
+            self.currentTimeChanged?(currentTime,duration)
+        }
+    }
+    
+    /// 移除时间观察者
+    private func removeTimeObserver() {
+        if let token = timeObserverToken {
+            player?.removeTimeObserver(token)
+            timeObserverToken = nil
+        }
+    }
+}

+ 0 - 48
AIPlayRingtones/Common/TSBandRingTool/AudioTool.swift

@@ -1,48 +0,0 @@
-//
-//  AudioTool.swift
-//  ContactPoster
-//
-//  Created by TSYH on 2024/1/24.
-//
-
-import AVFoundation
-typealias AudioCompletionHandler = (URL?, String?) -> Void
-
-class AudioTool {
-
-    /// 创建用于分享库乐队的band文件
-    func convertToBand(from fileURL: URL, to filePath: String,
-                       bandFileURL: URL,
-                       completion: ((URL?) -> Void)?) {
-        
-        let copyBandURL = URL(fileURLWithPath: filePath).deletingPathExtension().appendingPathExtension("band")
-        // 步骤3:复制band文件
-        try? FileManager.default.copyItem(atPath: bandFileURL.path, toPath: copyBandURL.path)
-        
-        guard FileManager.default.fileExists(atPath: copyBandURL.path) else {
-            // 复制失败
-            completion?(nil)
-            return
-        }
-        
-        // 步骤4:格式转换为aiff
-        let converter = ExtAudioConverter()
-        converter.inputFile = fileURL.path
-        converter.outputFile = copyBandURL.path.appending("/Media/ringtone.aiff")
-        converter.outputFileType = kAudioFileAIFFType
-        let success = converter.convert()
-        
-        guard success,
-              FileManager.default.fileExists(atPath: copyBandURL.path) else {
-            // 转换失败
-            completion?(nil)
-            return
-        }
-        
-        completion?(copyBandURL)
-        logPrint("===bandPath: \(copyBandURL)")
-    }
-    
-
-
-}

+ 41 - 1
AIPlayRingtones/Common/TSBandRingTool/TSBandRingTool.swift

@@ -204,7 +204,7 @@ extension TSBandRingTool {
         
         // 步骤1
         if !FileManager.default.fileExists(atPath: path),
-            let localFile = Bundle.main.path(forResource: "placeholder.band", ofType: nil) {
+            let localFile = Bundle.main.path(forResource: "null.band", ofType: nil) {
             try? FileManager.default.copyItem(atPath: localFile, toPath: path)
         }
         return path
@@ -246,3 +246,43 @@ extension FileManager {
         }
     }
 }
+
+
+class AudioTool {
+
+    /// 创建用于分享库乐队的band文件
+    func convertToBand(from fileURL: URL, to filePath: String,
+                       bandFileURL: URL,
+                       completion: ((URL?) -> Void)?) {
+        
+        let copyBandURL = URL(fileURLWithPath: filePath).deletingPathExtension().appendingPathExtension("band")
+        // 步骤3:复制band文件
+        try? FileManager.default.copyItem(atPath: bandFileURL.path, toPath: copyBandURL.path)
+        
+        guard FileManager.default.fileExists(atPath: copyBandURL.path) else {
+            // 复制失败
+            completion?(nil)
+            return
+        }
+        
+        // 步骤4:格式转换为aiff
+        let converter = ExtAudioConverter()
+        converter.inputFile = fileURL.path
+        converter.outputFile = copyBandURL.path.appending("/Media/ringtone.aiff")
+        converter.outputFileType = kAudioFileAIFFType
+        let success = converter.convert()
+        
+        guard success,
+              FileManager.default.fileExists(atPath: copyBandURL.path) else {
+            // 转换失败
+            completion?(nil)
+            return
+        }
+        
+        completion?(copyBandURL)
+        logPrint("===bandPath: \(copyBandURL)")
+    }
+    
+
+
+}

+ 0 - 55
AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHAudioProcessing.swift

@@ -1,55 +0,0 @@
-//
-//  ZHAudioProcessing.swift
-//  ZHWaveform_Example
-//
-//  Created by wow250250 on 2018/1/2.
-//  Copyright © 2018年 wow250250. All rights reserved.
-//
-
-import UIKit
-import AVFoundation
-
-struct ZHAudioProcessing {
-    
-    typealias BufferRefSuccessHandler = (NSMutableData) -> Swift.Void
-    typealias BufferRefFailureHandler = (Error?) -> Swift.Void
-    
-    public static func bufferRef(
-        asset: AVAsset,
-        track: AVAssetTrack,
-        success: BufferRefSuccessHandler?,
-        failure: BufferRefFailureHandler?
-        ) {
-        let data = NSMutableData()
-        let dict: [String: Any] = [AVFormatIDKey: kAudioFormatLinearPCM,
-                                   AVLinearPCMIsBigEndianKey: false,
-                                   AVLinearPCMIsFloatKey: false,
-                                   AVLinearPCMBitDepthKey: 16]
-        do {
-            let reader: AVAssetReader = try AVAssetReader(asset: asset)
-            let output: AVAssetReaderTrackOutput = AVAssetReaderTrackOutput(track: track, outputSettings: dict)
-            reader.add(output)
-            reader.startReading()
-            while reader.status == .reading {
-                if let sampleBuffer: CMSampleBuffer = output.copyNextSampleBuffer() {
-                    if let blockBuffer: CMBlockBuffer = CMSampleBufferGetDataBuffer(sampleBuffer) {
-                        let length: Int = CMBlockBufferGetDataLength(blockBuffer)
-                        var sampleBytes = [Int16](repeating: Int16(), count: length)
-                        CMBlockBufferCopyDataBytes(blockBuffer, atOffset: 0, dataLength: length, destination: &sampleBytes)
-//                        CMBlockBufferCopyDataBytes(blockBuffer, 0, length, &sampleBytes)
-                        data.append(&sampleBytes, length: length)
-                        CMSampleBufferInvalidate(sampleBuffer)
-                    }
-                }
-            }
-            if reader.status == .completed {
-                print("读取结束")
-                success?(data)
-            } else {
-                failure?(nil)
-            }
-        } catch let err {
-            failure?(err)
-        }
-    }
-}

+ 0 - 37
AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHCroppedDelegate.swift

@@ -1,37 +0,0 @@
-//
-//  ZHCroppedDelegate.swift
-//  ZHWaveform_Example
-//
-//  Created by wow250250 on 2018/1/2.
-//  Copyright © 2018年 wow250250. All rights reserved.
-//
-
-import UIKit
-
-@objc public protocol ZHCroppedDelegate {
-    /**
-     start cropped
-     */
-    @objc optional func waveformView(startCropped: UIView, progress rate: CGFloat)
-    
-    /**
-     end cropped
-     */
-    @objc optional func waveformView(endCropped: UIView, progress rate: CGFloat)
-    
-    /**
-     will
-     */
-    @objc optional func waveformView(croppedStartDragging cropped: UIView)
-    
-    /**
-     ing
-     */
-    @objc optional func waveformView(croppedDragIn cropped: UIView)
-    
-    /**
-     ed
-     */
-    @objc optional func waveformView(croppedDragFinish cropped: UIView)
-    
-}

+ 0 - 36
AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHTrackProcessing.swift

@@ -1,36 +0,0 @@
-//
-//  ZHTrackProcessing.swift
-//  ZHWaveform_Example
-//
-//  Created by wow250250 on 2018/1/2.
-//  Copyright © 2018年 wow250250. All rights reserved.
-//
-
-import UIKit
-import AVFoundation
-
-struct ZHTrackProcessing {
-    public static func cutAudioData(size: CGSize, recorder data: NSMutableData, scale: CGFloat) -> [CGFloat] {
-        var filteredSamplesMA: [CGFloat] = []
-        let sampleCount = data.length / MemoryLayout<Int>.size
-        let binSize = CGFloat(sampleCount) / (size.width * scale)
-        var i = 0
-        while i < sampleCount {
-            let rangeData = data.subdata(with: NSRange(location: i, length: 1))
-            let item = rangeData.withUnsafeBytes({ (ptr: UnsafePointer<Int>) -> Int in
-                return ptr.pointee
-            })
-            filteredSamplesMA.append(CGFloat(item))
-            i += Int(binSize)
-        }
-        return trackScale(size: size, source: filteredSamplesMA)
-    }
-    
-    private static func trackScale(size: CGSize, source: [CGFloat]) -> [CGFloat] {
-        if let max = source.max() {
-            let k = size.height / max
-            return source.map{ $0 * k }
-        }
-        return source
-    }
-}

+ 0 - 311
AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHWaveformView.swift

@@ -1,311 +0,0 @@
-//
-//  ZHWaveformView.swift
-//  ZHWaveform_Example
-//
-//  Created by wow250250 on 2018/1/2.
-//  Copyright © 2018年 wow250250. All rights reserved.
-//
-
-import UIKit
-import AVFoundation
-
-public class ZHWaveformView: UIView {
-    
-    /** waves color */
-    public var wavesColor: UIColor = .red {
-        didSet {
-            DispatchQueue.main.async {
-                _ = self.trackLayer.map({ [unowned self] in
-                    $0.strokeColor = self.wavesColor.cgColor
-                })
-            }
-        }
-    }
-    
-    /** Cut off the beginning part color */
-    public var beginningPartColor: UIColor = .gray
-    
-    /** Cut out the end part color */
-    public var endPartColor: UIColor = .gray
-    
-    /** Track Scale normal 0.5, max 1*/
-    public var trackScale: CGFloat = 0.5 {
-        didSet {
-            if let `assetMutableData` = assetMutableData {
-                croppedViewZero()
-                trackProcessingCut = ZHTrackProcessing.cutAudioData(size: self.frame.size, recorder: assetMutableData, scale: trackScale)
-                drawTrack(
-                    with: CGRect(x: (startCroppedView?.bounds.width ?? 0),
-                                 y: 0,
-                                 width: self.frame.width - (startCroppedView?.bounds.width ?? 0) - (endCroppedView?.bounds.width ?? 0),
-                                 height: self.frame.height),
-                    filerSamples: trackProcessingCut ?? []
-                )
-            }
-        }
-    }
-    
-    public weak var croppedDelegate: ZHCroppedDelegate? {
-        didSet { layoutIfNeeded() }
-    }
-    
-    public weak var waveformDelegate: ZHWaveformViewDelegate?
-    
-    private var fileURL: URL
-    
-    private var asset: AVAsset?
-    
-    private var track: AVAssetTrack?
-    
-    private var trackLayer: [CAShapeLayer] = []
-    
-    private var startCroppedView: UIView?
-    
-    private var endCroppedView: UIView?
-    
-    private var leftCorppedCurrentX: CGFloat = 0
-    
-    private var rightCorppedCurrentX: CGFloat = 0
-    
-    private var trackWidth: CGFloat = 0
-    
-    private var startCorppedIndex: Int = 0
-    
-    private var endCorppedIndex: Int = 0
-    
-    private var trackProcessingCut: [CGFloat]?
-    
-    private var assetMutableData: NSMutableData?
-    
-    private(set) var startCroppedRate: CGFloat = 0
-    private(set) var endCroppedRate: CGFloat = 0
-    
-    public init(frame: CGRect, fileURL: URL) {
-        self.fileURL = fileURL
-        super.init(frame: frame)
-        waveformDelegate?.waveformViewStartDrawing?(waveformView: self)
-        backgroundColor = .white
-        
-        let asset = AVAsset(url: fileURL)
-        guard let track = asset.tracks(withMediaType: .audio).first else {
-            return
-        }
-        self.asset = asset
-        self.track = track
-        ZHAudioProcessing.bufferRef(asset: asset, track: track, success: { [unowned self] (data) in
-            self.assetMutableData = data
-            self.trackProcessingCut = ZHTrackProcessing.cutAudioData(size: frame.size, recorder: data, scale: self.trackScale)
-            self.drawTrack(with: CGRect(origin: .zero, size: frame.size), filerSamples: self.trackProcessingCut ?? [])
-            self.waveformDelegate?.waveformViewDrawComplete?(waveformView: self)
-        }) { (error) in
-            assert(true, error?.localizedDescription ?? "Error, AudioProcessing.bufferRef")
-        }
-    }
-    
-    override public func layoutIfNeeded() {
-        super.layoutIfNeeded()
-        if let samples = trackProcessingCut {
-            creatCroppedView()
-            drawTrack(
-                with: CGRect(x: startCroppedView?.bounds.width ?? 0,
-                             y: 0,
-                             width: frame.width - (startCroppedView?.bounds.width ?? 0) - (endCroppedView?.bounds.width ?? 0),
-                             height: frame.height),
-                filerSamples: samples
-            )
-        }
-    }
-    
-    private func drawTrack(with rect: CGRect, filerSamples: [CGFloat]) {
-        _ = trackLayer.map{ $0.removeFromSuperlayer() }
-        trackLayer.removeAll()
-        startCroppedView?.removeFromSuperview()
-        endCroppedView?.removeFromSuperview()
-        // bezier width
-        trackWidth = rect.width / (CGFloat(filerSamples.count - 1) + CGFloat(filerSamples.count))
-        endCorppedIndex = filerSamples.count
-        for t in 0..<filerSamples.count {
-            let layer = CAShapeLayer()
-            layer.frame = CGRect(
-                x: CGFloat(t) * trackWidth * 2 + (startCroppedView?.bounds.width ?? 0),
-                y: 0,
-                width: trackWidth,
-                height: rect.height
-            )
-            layer.lineCap = CAShapeLayerLineCap.butt
-            layer.lineJoin = CAShapeLayerLineJoin.round
-            layer.lineWidth = trackWidth
-            layer.strokeColor = wavesColor.cgColor
-            self.layer.addSublayer(layer)
-            self.trackLayer.append(layer)
-        }
-        
-        for i in 0..<filerSamples.count {
-            let itemLinePath = UIBezierPath()
-            let y: CGFloat = (rect.height - filerSamples[i]) / 2
-            let height: CGFloat = filerSamples[i] + y
-            itemLinePath.move(to: CGPoint(x: 0, y: y))
-            itemLinePath.addLine(to: CGPoint(x: 0, y: height))
-            itemLinePath.close()
-            itemLinePath.lineWidth = trackWidth
-            let itemLayer = trackLayer[i]
-            itemLayer.path = itemLinePath.cgPath
-        }
-        if let l = startCroppedView {
-            addSubview(l)
-        }
-        if let r = endCroppedView {
-            addSubview(r)
-        }
-        
-    }
-    
-    required public init?(coder aDecoder: NSCoder) {
-        fatalError("init(coder:) has not been implemented")
-    }
-    
-}
-
-extension ZHWaveformView {
-    
-    private func croppedViewZero() {
-        if let leftCropped = startCroppedView {
-            leftCropped.frame = CGRect(x: 0, y: leftCropped.frame.origin.y, width: leftCropped.bounds.width, height: leftCropped.bounds.height)
-        }
-        if let rightCropped = endCroppedView {
-            rightCropped.frame = CGRect(x: bounds.width - rightCropped.bounds.width, y: rightCropped.frame.origin.y, width: rightCropped.bounds.width, height: rightCropped.bounds.height)
-        }
-        
-    }
-    
-    private func creatCroppedView() {
-//        if let leftCropped = croppedDelegate?.waveformView(startCropped: self) {
-//            leftCropped.frame = CGRect(x: 0, y: leftCropped.frame.origin.y, width: leftCropped.bounds.width, height: leftCropped.bounds.height)
-//            leftCorppedCurrentX = 0
-//            let leftPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.leftCroppedPanRecognizer(sender:)))
-//            leftCropped.addGestureRecognizer(leftPanRecognizer)
-//            leftCropped.isUserInteractionEnabled = true
-//            startCroppedView = leftCropped
-//        }
-        
-//        if let rightCropped = croppedDelegate?.waveformView(endCropped: self) {
-//            rightCropped.frame = CGRect(x: bounds.width - rightCropped.bounds.width, y: rightCropped.frame.origin.y, width: rightCropped.bounds.width, height: rightCropped.bounds.height)
-//            rightCorppedCurrentX = bounds.width - rightCropped.bounds.width
-//            let rightPanRecognizer = UIPanGestureRecognizer(target: self, action: #selector(self.rightCroppedPanRecognizer(sender:)))
-//            rightCropped.addGestureRecognizer(rightPanRecognizer)
-//            rightCropped.isUserInteractionEnabled = true
-//            endCroppedView = rightCropped
-//        }
-    }
-    
-    @objc private func leftCroppedPanRecognizer(sender: UIPanGestureRecognizer) {
-        let limitMinX: CGFloat = frame.minX
-        let limitMaxX: CGFloat = endCroppedView?.frame.minX ?? bounds.width
-        if sender.state == .began {
-            croppedDelegate?.waveformView?(croppedDragIn: startCroppedView ?? UIView())
-        } else if sender.state == .changed {
-            croppedDelegate?.waveformView?(croppedDragIn: startCroppedView ?? UIView())
-            let newPoint = sender.translation(in: self)
-            var center = startCroppedView?.center
-            center?.x = leftCorppedCurrentX + newPoint.x
-            guard (center?.x ?? 0) > limitMinX && (center?.x ?? 0) < limitMaxX else { return }
-            startCroppedView?.center = center ?? .zero
-        } else if sender.state == .ended || sender.state == .failed {
-            croppedDelegate?.waveformView?(croppedDragFinish: startCroppedView ?? UIView())
-            leftCorppedCurrentX = startCroppedView?.center.x ?? 0
-        }
-        if (startCroppedView?.frame.minX ?? 0) < 0 {
-            var leftFrame = startCroppedView?.frame
-            leftFrame?.origin.x = 0
-            startCroppedView?.frame = leftFrame ?? .zero
-        }
-        
-        if (startCroppedView?.frame.maxX ?? 0) > limitMaxX {
-            var leftFrame = startCroppedView?.frame
-            leftFrame?.origin.x = limitMaxX - (startCroppedView?.bounds.width ?? 0)
-            startCroppedView?.frame = leftFrame ?? .zero
-        } // floorf ceilf
-        let lenght = ceilf(Float((((startCroppedView?.frame.maxX ?? 0) - (startCroppedView?.bounds.width ?? 0)) / trackWidth)))
-        let bzrLenght = ceilf(lenght/2)
-        startCorppedIndex = Int(bzrLenght) > trackLayer.count ? trackLayer.count : Int(bzrLenght)
-        self.croppedWaveform(start: startCorppedIndex, end: endCorppedIndex)
-        let bezierWidth = self.frame.width - (startCroppedView?.frame.width ?? 0) - (endCroppedView?.frame.width ?? 0)
-        croppedDelegate?.waveformView?(startCropped: startCroppedView ?? UIView(), progress: ((startCroppedView?.frame.maxX ?? 0) - 20)/bezierWidth)
-    }
-    
-    func updateLeftCroppedPosition(_ position: CGFloat) {
-        let lenght = ceilf(Float((position / trackWidth)))
-        let bzrLenght = ceilf(lenght/2)
-        startCorppedIndex = Int(bzrLenght) > trackLayer.count ? trackLayer.count : Int(bzrLenght)
-        self.croppedWaveform(start: startCorppedIndex, end: endCorppedIndex)
-        let bezierWidth = self.frame.width
-        self.startCroppedRate = position/bezierWidth
-    }
-    
-    func updateRightCroppedPosition(_ position: CGFloat) {
-        let lenght = ceilf(Float(position / trackWidth))
-        let bzrLenght = floorf(lenght/2) < 0 ? 0 : ceilf(lenght/2)
-        endCorppedIndex = Int(bzrLenght)
-        self.croppedWaveform(start: startCorppedIndex, end: endCorppedIndex)
-        let bezierWidth = self.frame.width
-        self.endCroppedRate = position/bezierWidth
-    }
-    
-    @objc private func rightCroppedPanRecognizer(sender: UIPanGestureRecognizer) {
-        let limitMinX: CGFloat = startCroppedView?.frame.maxX ?? 0
-        let limitMaxX: CGFloat = frame.maxX
-        if sender.state == .began {
-            croppedDelegate?.waveformView?(croppedStartDragging: endCroppedView ?? UIView())
-        } else if sender.state == .changed {
-            croppedDelegate?.waveformView?(croppedDragIn: endCroppedView ?? UIView())
-            let newPoint = sender.translation(in: self)
-            var center = endCroppedView?.center
-            center?.x = rightCorppedCurrentX + newPoint.x
-            guard (center?.x ?? 0) > limitMinX && (center?.x ?? 0) < limitMaxX else { return }
-            endCroppedView?.center = center ?? .zero
-        } else if sender.state == .ended || sender.state == .failed {
-            croppedDelegate?.waveformView?(croppedDragFinish: endCroppedView ?? UIView())
-            rightCorppedCurrentX = endCroppedView?.center.x ?? (bounds.width - (endCroppedView?.bounds.width ?? 0))
-        }
-        if (endCroppedView?.frame.maxX ?? 0) > frame.maxX {
-            var rightFrame = endCroppedView?.frame
-            rightFrame?.origin.x = frame.maxX - (endCroppedView?.bounds.width ?? 0)
-            endCroppedView?.frame = rightFrame ?? .zero
-        }
-        if (endCroppedView?.frame.minX ?? 0) < limitMinX {
-            var rightFrame = endCroppedView?.frame
-            rightFrame?.origin.x = limitMinX
-            endCroppedView?.frame = rightFrame ?? .zero
-        }
-        let lenght = ceilf(Float(((endCroppedView?.frame.minX ?? 0) - (startCroppedView?.bounds.width ?? 0)) / trackWidth))
-        let bzrLenght = floorf(lenght/2) < 0 ? 0 : ceilf(lenght/2)
-        endCorppedIndex = Int(bzrLenght)
-        self.croppedWaveform(start: startCorppedIndex, end: endCorppedIndex)
-        let bezierWidth = self.frame.width - (startCroppedView?.frame.width ?? 0) - (endCroppedView?.frame.width ?? 0)
-        croppedDelegate?.waveformView?(endCropped: endCroppedView ?? UIView(), progress: ((endCroppedView?.frame.minX ?? 0)-20)/bezierWidth)
-    }
-    
-    typealias TrackIndex = Int
-    
-    func croppedWaveform(start: TrackIndex, end: TrackIndex) {
-        guard start > 0, start < trackLayer.count,
-              end > start, end <= trackLayer.count else {
-            return
-        }
-        let beginLayers = trackLayer[0..<start]
-        let wavesLayers = trackLayer[start..<end]
-        let endLayers = trackLayer[end..<trackLayer.count]
-        DispatchQueue.main.async {
-            _ = beginLayers.map({ [unowned self] in
-                $0.strokeColor = self.beginningPartColor.cgColor
-            })
-            _ = wavesLayers.map({ [unowned self] in
-                $0.strokeColor = self.wavesColor.cgColor
-            })
-            _ = endLayers.map({ [unowned self] in
-                $0.strokeColor = self.endPartColor.cgColor
-            })
-        }
-    }
-    
-}

+ 0 - 19
AIPlayRingtones/Common/TSBandRingTool/ZHWaveform/ZHWaveformViewDelegate.swift

@@ -1,19 +0,0 @@
-//
-//  ZHWaveformViewDelegate.swift
-//  ZHWaveform_Example
-//
-//  Created by wow250250 on 2018/1/2.
-//  Copyright © 2018年 wow250250. All rights reserved.
-//
-
-import UIKit
-
-@objc public protocol ZHWaveformViewDelegate {
-    
-    // start
-    @objc optional func waveformViewStartDrawing(waveformView: ZHWaveformView)
-    
-    // complete
-    @objc optional func waveformViewDrawComplete(waveformView: ZHWaveformView)
-    
-}

+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Contents/PkgInfo → AIPlayRingtones/Common/TSBandRingTool/null.band/Contents/PkgInfo


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Media/kong.txt → AIPlayRingtones/Common/TSBandRingTool/null.band/Media/kong.txt


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Output/assetsmetadata.plist → AIPlayRingtones/Common/TSBandRingTool/null.band/Output/assetsmetadata.plist


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Output/metadata.plist → AIPlayRingtones/Common/TSBandRingTool/null.band/Output/metadata.plist


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Output/output.plist → AIPlayRingtones/Common/TSBandRingTool/null.band/Output/output.plist


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/Output/output.xyz → AIPlayRingtones/Common/TSBandRingTool/null.band/Output/output.xyz


+ 0 - 0
AIPlayRingtones/Common/TSBandRingTool/placeholder.band/projectData → AIPlayRingtones/Common/TSBandRingTool/null.band/projectData


+ 2 - 63
AIPlayRingtones/Common/TSNetWork/TSNetWork+Business.swift

@@ -5,23 +5,14 @@
 //  Created by 100Years on 2025/1/16.
 //
 
-/// 基础 URL(根据需求修改)
 private let baseURL = "http://ai.soundmove.cn"
-//private let baseChinaURL = "http://ai.100yearslater100.com"
 import Alamofire
 enum TSNeURLType:String {
     
     case musicCreate = "/api/music/create"         //音乐生成
     case actionInfo = "/api/action/info"         //查询生成过程接口
     case upload = "/api/upload"                  //上传
-   
-//    func getUrlString() -> String {
-//        if Locale.current.identifier.contains("_CN") {//中国区
-//            return baseChinaURL + self.rawValue
-//        }else{
-//            return baseURL + self.rawValue
-//        }
-//    }
+
     
     func getUrlString() -> String {
         return baseURL + self.rawValue
@@ -59,7 +50,6 @@ func getLanguageCode()->String{
         return "zh-Hant"
     }
     if let languageCode = Locale.current.languageCode {
-//        print("当前设备语言简写: \(languageCode)") // 输出如 "en", "ja", "zh" 等
         return languageCode
     }
     return "en"
@@ -110,25 +100,6 @@ extension TSNetworkManager {
         }
     }
     
-    /// 通用 POST Stream 请求
-    /// - Parameters:
-    ///   - endpoint: 接口路径
-    ///   - parameters: 请求参数
-    ///   - responseType: 响应数据模型(可选)
-    ///   - completion: 请求完成的回调
-    func postStream<T: ASBaseModel>(
-        urlType: TSNeURLType,
-        parameters: [String: Any]? = nil,
-        responseType: T.Type? = nil,
-        streamHandler:@escaping (String) -> Void,
-        completion: @escaping (Result<Any, Error>) -> Void
-    ) -> Request?{
-        let urlString = urlType.getUrlString()
-        let streamRequest = postStreamRequest(urlString: urlString, parameters: parameters, streamHandler: streamHandler, completion: completion)
-        return streamRequest
-    }
-
-    
     /// 上传多个 Data 数据
     /// - Parameters:
     ///   - urlType: TSNeURLType
@@ -181,39 +152,7 @@ extension TSNetworkManager {
 }
 
 extension TSNetworkManager {
-    
-//    func uploadAudio(
-//        fileURL:URL,
-//        progressHandler: @escaping (Float) -> Void, // 上传进度回调
-//        completion: @escaping (Any?, Error?) -> Void)
-//    -> Request?{
-//
-//        let urlString = TSNeURLType.upload.getUrlString()
-//        
-//        let request = uploadFile(urlString: urlString, fileURL: fileURL, multipartBuilder: { multipart in
-//            multipart.append(fileURL, withName: "file", fileName: "audio.mp3", mimeType: "audio/mp3")
-//        }) { progress in
-//            progressHandler(Float(progress.fractionCompleted))
-//        } completion: { [weak self] result in
-//            guard let self = self else { return }
-//            switch result {
-//            case .success(let data):
-//                if let dataDict = kNetWorkCodeSuccess(data: data),
-//                   let picUrl = dataDict["result"] as? String{
-//                    completion(picUrl,nil)
-//                }else{
-//                    let error = NSError(domain: "Service exception", code: 0)
-//                    completion(nil,error)
-//                }
-//            case .failure(let error):
-//                completion(nil,error)
-//            }
-//        }
-//        
-//        return request
-//    }
-    
-    
+
     func uploadAudio(
         fileURL:URL,
         progressHandler: @escaping (Float) -> Void, // 上传进度回调

+ 1 - 41
AIPlayRingtones/Common/TSNetWork/TSNetworkManager.swift

@@ -21,17 +21,10 @@ class TSNetworkManager {
     private var defaultHeaders: HTTPHeaders {
         return ["Content-Type": "application/json",
                 "accept": "application/json",
-//            "Authorization": "Bearer YOUR_ACCESS_TOKEN" // 按需修改
         ]
     }
     
     lazy var afSession: Session = {
-//        let configuration = URLSessionConfiguration.af.default
-//        configuration.timeoutIntervalForRequest = 15  // 请求超时时间(秒)
-//        configuration.timeoutIntervalForResource = 30 // 资源超时时间(秒)
-//        let session = Session(configuration: configuration)
-//        return session
-        
         return AF
     }()
     lazy var encoder: JSONEncoding = {
@@ -111,32 +104,12 @@ class TSNetworkManager {
         return request
     }
     
-    
 
     
 }
 
 extension TSNetworkManager {
     
-    
-    /*
-     // Data 数组
-     let dataArray: [[String: Any]] = [
-         [
-             "data": imageData,
-             "fieldName": "file1", // 字段名
-             "fileName": "App-Icon.png", // 文件名
-             "mimeType": "image/png" // MIME 类型
-         ],
-         [
-             "data": textData,
-             "fieldName": "file2", // 字段名
-             "fileName": "hello.txt", // 文件名
-             "mimeType": "text/plain" // MIME 类型
-         ]
-     ]
-     */
-    
     /// 上传多个 Data 数据
     /// - Parameters:
     ///   - url: 上传地址
@@ -319,21 +292,8 @@ extension TSNetworkManager {
         
         switch response.result {
         case .success(let value):
-            
             if let resultDict = dataToJSONObject(data:response.data) as? [String:Any] {
-                
-//                let code = resultDict.safeInt(forKey: "code")
-//                if responseType != nil {
-//                    if let model = T(JSONString: value) {
-//                        handleSuccess(data: model, response: response, completion: completion)
-//                    } else {
-//                        let models = Mapper<T>().mapArray(JSONString: value)
-//                        handleSuccess(data: models ?? [], response: response, completion: completion)
-//                    }
-//                } else {
-                    handleSuccess(data: resultDict, response: response, completion: completion)
-//                }
-                
+                handleSuccess(data: resultDict, response: response, completion: completion)
             }else{
                 handleFail(error: NSError(domain: "Unable to parse data", code: 0), response: response, completion: completion)
             }

+ 0 - 19
AIPlayRingtones/Common/TSPurchaseTool/TSPurchaseTool.swift

@@ -1,19 +0,0 @@
-//
-//  TSPurchaseTool.swift
-//  AIPlayRingtones
-//
-//  Created by mini on 2025/5/19.
-//
-
-
-
-
-func kshareBand(needVip:Bool,
-               vc:UIViewController,
-                fileURL:URL,
-                fileName:String,
-                completion:((Bool)->Void)? = nil) -> Bool {
-
-    TSBandRingTool.creatBandRingTool().shareBandVC(vc: vc, fileURL: fileURL, fileName: fileName,completion: completion)
-    return false
-}