mirror of
https://github.com/GLEGram/GLEGram-iOS.git
synced 2026-04-30 06:47:53 +02:00
4647310322
Based on Swiftgram 12.5 (Telegram iOS 12.5). All GLEGram features ported and organized in GLEGram/ folder. Features: Ghost Mode, Saved Deleted Messages, Content Protection Bypass, Font Replacement, Fake Profile, Chat Export, Plugin System, and more. See CHANGELOG_12.5.md for full details.
189 lines
8.3 KiB
Swift
Executable File
189 lines
8.3 KiB
Swift
Executable File
import Foundation
|
|
import Postbox
|
|
import TelegramApi
|
|
import SGSimpleSettings
|
|
|
|
// MARK: - AyuGram-style Saved Attachments for SavedDeleted snapshots
|
|
|
|
func sgSavedDeletedAttachmentsDirectoryPath(mediaBox: MediaBox) -> String {
|
|
let path = mediaBox.basePath + "/saved-deleted-attachments"
|
|
let _ = try? FileManager.default.createDirectory(atPath: path, withIntermediateDirectories: true, attributes: nil)
|
|
return path
|
|
}
|
|
|
|
private func sgSanitizeFileName(_ value: String) -> String {
|
|
var result = value
|
|
for ch in ["/", ":", "\\", "\n", "\r", "\t"] {
|
|
result = result.replacingOccurrences(of: ch, with: "_")
|
|
}
|
|
return result
|
|
}
|
|
|
|
private func sgCopyCompletedResourceIfPossible(mediaBox: MediaBox, resource: TelegramMediaResource, destinationDirectory: String) -> TelegramMediaResource? {
|
|
guard let sourcePath = mediaBox.completedResourcePath(resource) else {
|
|
return nil
|
|
}
|
|
let ext = URL(fileURLWithPath: sourcePath).pathExtension
|
|
let baseName = sgSanitizeFileName(resource.id.stringRepresentation)
|
|
let fileName = ext.isEmpty ? baseName : "\(baseName).\(ext)"
|
|
let destinationPath = destinationDirectory + "/" + fileName
|
|
|
|
if FileManager.default.fileExists(atPath: destinationPath) {
|
|
return LocalFileReferenceMediaResource(localFilePath: destinationPath, randomId: Int64.random(in: Int64.min ... Int64.max), isUniquelyReferencedTemporaryFile: false, size: fileSize(destinationPath))
|
|
}
|
|
|
|
do {
|
|
try FileManager.default.copyItem(atPath: sourcePath, toPath: destinationPath)
|
|
return LocalFileReferenceMediaResource(localFilePath: destinationPath, randomId: Int64.random(in: Int64.min ... Int64.max), isUniquelyReferencedTemporaryFile: false, size: fileSize(destinationPath))
|
|
} catch {
|
|
return nil
|
|
}
|
|
}
|
|
|
|
private func sgCopyTelegramMediaImageForSavedDeleted(_ image: TelegramMediaImage, mediaBox: MediaBox, destinationDirectory: String) -> TelegramMediaImage {
|
|
var updatedRepresentations: [TelegramMediaImageRepresentation] = []
|
|
updatedRepresentations.reserveCapacity(image.representations.count)
|
|
for rep in image.representations {
|
|
if let localResource = sgCopyCompletedResourceIfPossible(mediaBox: mediaBox, resource: rep.resource, destinationDirectory: destinationDirectory) {
|
|
updatedRepresentations.append(TelegramMediaImageRepresentation(
|
|
dimensions: rep.dimensions,
|
|
resource: localResource,
|
|
progressiveSizes: rep.progressiveSizes,
|
|
immediateThumbnailData: rep.immediateThumbnailData,
|
|
hasVideo: rep.hasVideo,
|
|
isPersonal: rep.isPersonal,
|
|
typeHint: rep.typeHint
|
|
))
|
|
} else {
|
|
updatedRepresentations.append(rep)
|
|
}
|
|
}
|
|
|
|
var updatedVideoRepresentations: [TelegramMediaImage.VideoRepresentation] = []
|
|
updatedVideoRepresentations.reserveCapacity(image.videoRepresentations.count)
|
|
for rep in image.videoRepresentations {
|
|
if let localResource = sgCopyCompletedResourceIfPossible(mediaBox: mediaBox, resource: rep.resource, destinationDirectory: destinationDirectory) {
|
|
updatedVideoRepresentations.append(TelegramMediaImage.VideoRepresentation(dimensions: rep.dimensions, resource: localResource, startTimestamp: rep.startTimestamp))
|
|
} else {
|
|
updatedVideoRepresentations.append(rep)
|
|
}
|
|
}
|
|
|
|
return TelegramMediaImage(
|
|
imageId: image.imageId,
|
|
representations: updatedRepresentations,
|
|
videoRepresentations: updatedVideoRepresentations,
|
|
immediateThumbnailData: image.immediateThumbnailData,
|
|
emojiMarkup: image.emojiMarkup,
|
|
reference: image.reference,
|
|
partialReference: image.partialReference,
|
|
flags: image.flags
|
|
)
|
|
}
|
|
|
|
private func sgCopyTelegramMediaFileForSavedDeleted(_ file: TelegramMediaFile, mediaBox: MediaBox, destinationDirectory: String) -> TelegramMediaFile {
|
|
let updatedResource: TelegramMediaResource = sgCopyCompletedResourceIfPossible(mediaBox: mediaBox, resource: file.resource, destinationDirectory: destinationDirectory) ?? file.resource
|
|
|
|
var updatedPreviewRepresentations: [TelegramMediaImageRepresentation] = []
|
|
updatedPreviewRepresentations.reserveCapacity(file.previewRepresentations.count)
|
|
for rep in file.previewRepresentations {
|
|
if let localResource = sgCopyCompletedResourceIfPossible(mediaBox: mediaBox, resource: rep.resource, destinationDirectory: destinationDirectory) {
|
|
updatedPreviewRepresentations.append(TelegramMediaImageRepresentation(
|
|
dimensions: rep.dimensions,
|
|
resource: localResource,
|
|
progressiveSizes: rep.progressiveSizes,
|
|
immediateThumbnailData: rep.immediateThumbnailData,
|
|
hasVideo: rep.hasVideo,
|
|
isPersonal: rep.isPersonal,
|
|
typeHint: rep.typeHint
|
|
))
|
|
} else {
|
|
updatedPreviewRepresentations.append(rep)
|
|
}
|
|
}
|
|
|
|
var updatedVideoThumbnails: [TelegramMediaFile.VideoThumbnail] = []
|
|
updatedVideoThumbnails.reserveCapacity(file.videoThumbnails.count)
|
|
for thumb in file.videoThumbnails {
|
|
if let localResource = sgCopyCompletedResourceIfPossible(mediaBox: mediaBox, resource: thumb.resource, destinationDirectory: destinationDirectory) {
|
|
updatedVideoThumbnails.append(TelegramMediaFile.VideoThumbnail(dimensions: thumb.dimensions, resource: localResource))
|
|
} else {
|
|
updatedVideoThumbnails.append(thumb)
|
|
}
|
|
}
|
|
|
|
let updatedVideoCover = file.videoCover.flatMap { sgCopyTelegramMediaImageForSavedDeleted($0, mediaBox: mediaBox, destinationDirectory: destinationDirectory) }
|
|
|
|
return TelegramMediaFile(
|
|
fileId: file.fileId,
|
|
partialReference: file.partialReference,
|
|
resource: updatedResource,
|
|
previewRepresentations: updatedPreviewRepresentations,
|
|
videoThumbnails: updatedVideoThumbnails,
|
|
videoCover: updatedVideoCover,
|
|
immediateThumbnailData: file.immediateThumbnailData,
|
|
mimeType: file.mimeType,
|
|
size: file.size,
|
|
attributes: file.attributes,
|
|
alternativeRepresentations: file.alternativeRepresentations
|
|
)
|
|
}
|
|
|
|
func sgTransformMediaForSavedDeletedSnapshot(message: Message, mediaBox: MediaBox) -> [Media] {
|
|
guard SGSimpleSettings.shared.saveDeletedMessagesMedia else {
|
|
return message.media
|
|
}
|
|
let destinationDirectory = sgSavedDeletedAttachmentsDirectoryPath(mediaBox: mediaBox)
|
|
|
|
return message.media.map { media in
|
|
if let image = media as? TelegramMediaImage {
|
|
return sgCopyTelegramMediaImageForSavedDeleted(image, mediaBox: mediaBox, destinationDirectory: destinationDirectory)
|
|
} else if let file = media as? TelegramMediaFile {
|
|
return sgCopyTelegramMediaFileForSavedDeleted(file, mediaBox: mediaBox, destinationDirectory: destinationDirectory)
|
|
} else {
|
|
return media
|
|
}
|
|
}
|
|
}
|
|
|
|
private func sgCollectLocalPaths(from resource: TelegramMediaResource, into result: inout [String]) {
|
|
if let resource = resource as? LocalFileReferenceMediaResource {
|
|
result.append(resource.localFilePath)
|
|
}
|
|
}
|
|
|
|
private func sgCollectLocalPaths(from media: Media, into result: inout [String]) {
|
|
if let image = media as? TelegramMediaImage {
|
|
for rep in image.representations {
|
|
sgCollectLocalPaths(from: rep.resource, into: &result)
|
|
}
|
|
for rep in image.videoRepresentations {
|
|
sgCollectLocalPaths(from: rep.resource, into: &result)
|
|
}
|
|
} else if let file = media as? TelegramMediaFile {
|
|
sgCollectLocalPaths(from: file.resource, into: &result)
|
|
for rep in file.previewRepresentations {
|
|
sgCollectLocalPaths(from: rep.resource, into: &result)
|
|
}
|
|
for thumb in file.videoThumbnails {
|
|
sgCollectLocalPaths(from: thumb.resource, into: &result)
|
|
}
|
|
if let cover = file.videoCover {
|
|
sgCollectLocalPaths(from: cover, into: &result)
|
|
}
|
|
}
|
|
}
|
|
|
|
func sgDeleteSavedDeletedAttachmentsForMessage(_ message: Message) {
|
|
var paths: [String] = []
|
|
for media in message.media {
|
|
sgCollectLocalPaths(from: media, into: &paths)
|
|
}
|
|
guard !paths.isEmpty else { return }
|
|
|
|
for path in Set(paths) {
|
|
let _ = try? FileManager.default.removeItem(atPath: path)
|
|
}
|
|
}
|
|
|