mirror of
https://github.com/cranci1/Sora.git
synced 2026-03-11 17:45:37 +00:00
yes -DownloadManager
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
Some checks are pending
Build and Release IPA / Build IPA (push) Waiting to run
This commit is contained in:
parent
020c753eb8
commit
7e611ce77f
3 changed files with 106 additions and 4 deletions
93
Sora/DownloadManager/DownloadManager.swift
Normal file
93
Sora/DownloadManager/DownloadManager.swift
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// DownloadManager.swift
|
||||
// Sulfur
|
||||
//
|
||||
// Created by Francesco on 09/03/25.
|
||||
//
|
||||
|
||||
import Foundation
|
||||
import FFmpegSupport
|
||||
|
||||
class DownloadManager {
|
||||
static let shared = DownloadManager()
|
||||
|
||||
private init() {}
|
||||
|
||||
/// Downloads and converts an HLS stream to MP4, or downloads an MP4 stream normally.
|
||||
/// - Parameters:
|
||||
/// - url: The stream URL (either .m3u8 or .mp4).
|
||||
/// - title: The title used for creating the folder.
|
||||
/// - episode: The episode number used for naming the output file.
|
||||
/// - completion: Completion handler with a Bool indicating success and the URL of the output file.
|
||||
func downloadAndConvertHLS(from url: URL, title: String, episode: Int, completion: @escaping (Bool, URL?) -> Void) {
|
||||
guard let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first else {
|
||||
completion(false, nil)
|
||||
return
|
||||
}
|
||||
|
||||
let folderURL = documentsDirectory.appendingPathComponent(title)
|
||||
if !FileManager.default.fileExists(atPath: folderURL.path) {
|
||||
do {
|
||||
try FileManager.default.createDirectory(at: folderURL, withIntermediateDirectories: true, attributes: nil)
|
||||
} catch {
|
||||
print("Error creating folder: \(error)")
|
||||
completion(false, nil)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
let outputFileName = "\(title)_Episode\(episode).mp4"
|
||||
let outputFileURL = folderURL.appendingPathComponent(outputFileName)
|
||||
|
||||
let fileExtension = url.pathExtension.lowercased()
|
||||
|
||||
if fileExtension == "mp4" {
|
||||
let task = URLSession.shared.downloadTask(with: url) { tempLocalURL, response, error in
|
||||
if let tempLocalURL = tempLocalURL {
|
||||
do {
|
||||
try FileManager.default.moveItem(at: tempLocalURL, to: outputFileURL)
|
||||
DispatchQueue.main.async {
|
||||
Logger.shared.log("✅ Download successful: \(outputFileURL)")
|
||||
completion(true, outputFileURL)
|
||||
}
|
||||
} catch {
|
||||
DispatchQueue.main.async {
|
||||
Logger.shared.log("❌ Download failed: \(error)")
|
||||
completion(false, nil)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
DispatchQueue.main.async {
|
||||
Logger.shared.log("❌ Download failed: \(error?.localizedDescription ?? "Unknown error")")
|
||||
completion(false, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
task.resume()
|
||||
} else if fileExtension == "m3u8" {
|
||||
let ffmpegCommand = [
|
||||
"ffmpeg",
|
||||
"-threads", "0",
|
||||
"-i", url.absoluteString,
|
||||
"-c", "copy",
|
||||
outputFileURL.path
|
||||
]
|
||||
|
||||
DispatchQueue.global(qos: .background).async {
|
||||
let success = ffmpeg(ffmpegCommand)
|
||||
DispatchQueue.main.async {
|
||||
if (success == 0) {
|
||||
Logger.shared.log("✅ Conversion successful: \(outputFileURL)")
|
||||
completion(true, outputFileURL)
|
||||
} else {
|
||||
Logger.shared.log("❌ Conversion failed")
|
||||
completion(false, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Logger.shared.log("❌ Unsupported file type: \(fileExtension)")
|
||||
completion(false, nil)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -21,7 +21,7 @@ struct LibraryView: View {
|
|||
var body: some View {
|
||||
NavigationView {
|
||||
ScrollView {
|
||||
VStack(alignment: .leading, spacing: 32) {
|
||||
VStack(alignment: .leading, spacing: 16) {
|
||||
Group {
|
||||
Text("Continue Watching")
|
||||
.font(.title2)
|
||||
|
|
@ -92,7 +92,6 @@ struct LibraryView: View {
|
|||
.aspectRatio(contentMode: .fit)
|
||||
.frame(width: 35, height: 35)
|
||||
.clipShape(Circle())
|
||||
.padding(5)
|
||||
}
|
||||
|
||||
Text(item.title)
|
||||
|
|
@ -100,7 +99,6 @@ struct LibraryView: View {
|
|||
.foregroundColor(.primary)
|
||||
.lineLimit(2)
|
||||
.multilineTextAlignment(.leading)
|
||||
.padding(.horizontal, 8)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -139,7 +137,6 @@ struct LibraryView: View {
|
|||
}
|
||||
}
|
||||
|
||||
// ContinueWatchingSection and ContinueWatchingCell remain unchanged
|
||||
struct ContinueWatchingSection: View {
|
||||
@Binding var items: [ContinueWatchingItem]
|
||||
var markAsWatched: (ContinueWatchingItem) -> Void
|
||||
|
|
|
|||
|
|
@ -53,6 +53,7 @@
|
|||
13D99CF72D4E73C300250A86 /* ModuleAdditionSettingsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13D99CF62D4E73C300250A86 /* ModuleAdditionSettingsView.swift */; };
|
||||
13DB7CC32D7D99C0004371D3 /* SubtitleSettingsManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13DB7CC22D7D99C0004371D3 /* SubtitleSettingsManager.swift */; };
|
||||
13DB7CC62D7DC7D2004371D3 /* FFmpeg-iOS-Lame in Frameworks */ = {isa = PBXBuildFile; productRef = 13DB7CC52D7DC7D2004371D3 /* FFmpeg-iOS-Lame */; };
|
||||
13DB7CEC2D7DED5D004371D3 /* DownloadManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13DB7CEB2D7DED5D004371D3 /* DownloadManager.swift */; };
|
||||
13DC0C462D302C7500D0F966 /* VideoPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13DC0C452D302C7500D0F966 /* VideoPlayer.swift */; };
|
||||
13EA2BD52D32D97400C1EBD7 /* CustomPlayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EA2BD12D32D97400C1EBD7 /* CustomPlayer.swift */; };
|
||||
13EA2BD62D32D97400C1EBD7 /* Double+Extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = 13EA2BD32D32D97400C1EBD7 /* Double+Extension.swift */; };
|
||||
|
|
@ -107,6 +108,7 @@
|
|||
13D842542D45267500EBBFA6 /* DropManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DropManager.swift; sourceTree = "<group>"; };
|
||||
13D99CF62D4E73C300250A86 /* ModuleAdditionSettingsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ModuleAdditionSettingsView.swift; sourceTree = "<group>"; };
|
||||
13DB7CC22D7D99C0004371D3 /* SubtitleSettingsManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SubtitleSettingsManager.swift; sourceTree = "<group>"; };
|
||||
13DB7CEB2D7DED5D004371D3 /* DownloadManager.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DownloadManager.swift; sourceTree = "<group>"; };
|
||||
13DC0C412D2EC9BA00D0F966 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
|
||||
13DC0C452D302C7500D0F966 /* VideoPlayer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = VideoPlayer.swift; sourceTree = "<group>"; };
|
||||
13EA2BD12D32D97400C1EBD7 /* CustomPlayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CustomPlayer.swift; sourceTree = "<group>"; };
|
||||
|
|
@ -230,6 +232,7 @@
|
|||
133D7C6C2D2BE2500075467E /* Sora */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13DB7CEA2D7DED50004371D3 /* DownloadManager */,
|
||||
130C6BF82D53A4C200DC1432 /* Sora.entitlements */,
|
||||
13DC0C412D2EC9BA00D0F966 /* Info.plist */,
|
||||
13103E802D589D6C000F0673 /* Tracking Services */,
|
||||
|
|
@ -398,6 +401,14 @@
|
|||
path = Drops;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13DB7CEA2D7DED50004371D3 /* DownloadManager */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
13DB7CEB2D7DED5D004371D3 /* DownloadManager.swift */,
|
||||
);
|
||||
path = DownloadManager;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
13DC0C442D302C6A00D0F966 /* MediaPlayer */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
|
@ -526,6 +537,7 @@
|
|||
136F21B92D5B8DD8006409AC /* AniList-MediaInfo.swift in Sources */,
|
||||
13DB7CC32D7D99C0004371D3 /* SubtitleSettingsManager.swift in Sources */,
|
||||
133D7C702D2BE2500075467E /* ContentView.swift in Sources */,
|
||||
13DB7CEC2D7DED5D004371D3 /* DownloadManager.swift in Sources */,
|
||||
1334FF522D7871B7007E289F /* TMDBItem.swift in Sources */,
|
||||
13D99CF72D4E73C300250A86 /* ModuleAdditionSettingsView.swift in Sources */,
|
||||
13C0E5EC2D5F85F800E7F619 /* ContinueWatchingItem.swift in Sources */,
|
||||
|
|
|
|||
Loading…
Reference in a new issue