mirror of
https://github.com/Swiftgram/Telegram-iOS.git
synced 2025-06-16 05:55:20 +00:00
189 lines
8.8 KiB
Swift
189 lines
8.8 KiB
Swift
import Foundation
|
|
import TelegramCore
|
|
import SwiftSignalKit
|
|
import Postbox
|
|
import LegacyComponents
|
|
|
|
private func importMediaFromMessageData(_ data: Data, basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
|
if let message = TGMessage(keyValueCoder: PSKeyValueDecoder(data: data)) {
|
|
if let mediaAttachments = message.mediaAttachments {
|
|
importMediaFromMediaList(mediaAttachments, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
|
}
|
|
}
|
|
}
|
|
|
|
private func importMediaFromMediaData(_ data: Data, basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
|
if let mediaAttachments = TGMessage.parseMediaAttachments(data) {
|
|
importMediaFromMediaList(mediaAttachments, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
|
}
|
|
}
|
|
|
|
private func importMediaFromMediaList(_ mediaAttachments: [Any], basePath: String, copyLocalFiles: inout [(MediaResource, String)], cache: TGCache) {
|
|
for media in mediaAttachments {
|
|
if let media = media as? TGDocumentMediaAttachment {
|
|
var fileName = "file"
|
|
if let itemAttributes = media.attributes {
|
|
for attribute in itemAttributes {
|
|
if let attribute = attribute as? TGDocumentAttributeFilename {
|
|
fileName = attribute.filename ?? "file"
|
|
}
|
|
}
|
|
}
|
|
|
|
if media.documentId != 0 {
|
|
let filePath = pathFromLegacyFile(basePath: basePath, fileId: media.documentId, isLocal: false, fileName: TGDocumentMediaAttachment.safeFileName(forFileName: fileName) ?? "")
|
|
if FileManager.default.fileExists(atPath: filePath) {
|
|
copyLocalFiles.append((CloudDocumentMediaResource(datacenterId: Int(media.datacenterId), fileId: media.documentId, accessHash: media.accessHash, size: nil, fileReference: nil, fileName: nil), filePath))
|
|
}
|
|
}
|
|
} else if let media = media as? TGVideoMediaAttachment {
|
|
if media.videoId != 0, let videoUrl = media.videoInfo?.url(withQuality: 1, actualQuality: nil, actualSize: nil) {
|
|
if let (id, accessHash, datacenterId, path) = pathFromLegacyVideoUrl(basePath: basePath, url: videoUrl) {
|
|
copyLocalFiles.append((CloudDocumentMediaResource(datacenterId: Int(datacenterId), fileId: id, accessHash: accessHash, size: nil, fileReference: nil, fileName: nil), path))
|
|
}
|
|
}
|
|
} else if let media = media as? TGImageMediaAttachment {
|
|
if let allSizes = media.imageInfo?.allSizes() as? [String: NSValue] {
|
|
for (imageUrl, _) in allSizes {
|
|
if let path = cache.path(forCachedData: imageUrl), let resource = resourceFromLegacyImageUrl(imageUrl), FileManager.default.fileExists(atPath: path) {
|
|
copyLocalFiles.append((resource, path))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
private func makeMessageSortKey(tag: Int32, conversationId: Int64, space: Int8, timestamp: Int32, messageId: Int32) -> Data {
|
|
let key = ValueBoxKey(length: 4 + 8 + 1 + 4 + 4)
|
|
key.setInt32(0, value: tag.byteSwapped)
|
|
key.setInt64(4, value: conversationId.byteSwapped)
|
|
key.setInt8(4 + 8, value: space)
|
|
key.setInt32(4 + 8 + 1, value: timestamp)
|
|
key.setInt32(4 + 8 + 1 + 4, value: messageId.byteSwapped)
|
|
return Data(bytes: key.memory, count: key.length)
|
|
}
|
|
|
|
func loadLegacyFiles(account: TemporaryAccount, basePath: String, accountPeerId: PeerId, database: SqliteInterface) -> Signal<Float, NoError> {
|
|
return Signal<Float, NoError> { subscriber in
|
|
let _ = registeredAttachmentParsers
|
|
|
|
subscriber.putNext(0.0)
|
|
|
|
var channelIds: [Int64] = []
|
|
database.select("SELECT DISTINCT cid FROM channel_message_tags_v29", { cursor in
|
|
channelIds.append(cursor.getInt64(at: 0))
|
|
return true
|
|
})
|
|
print(database.explain("SELECT DISTINCT cid FROM channel_message_tags_v29"))
|
|
|
|
var channelMessageIds: [(Int64, Int32)] = []
|
|
|
|
print(database.explain("SELECT mid FROM channel_message_tags_v29 WHERE tag_sort_key<100 AND tag_sort_key>0 ORDER BY tag_sort_key DESC LIMIT 4000"))
|
|
|
|
if !channelIds.isEmpty {
|
|
/*
|
|
TGSharedMediaCacheItemTypePhoto = 0,
|
|
TGSharedMediaCacheItemTypeVideo = 1,
|
|
TGSharedMediaCacheItemTypeFile = 2,
|
|
TGSharedMediaCacheItemTypePhotoVideo = 3,
|
|
TGSharedMediaCacheItemTypePhotoVideoFile = 4,
|
|
TGSharedMediaCacheItemTypeAudio = 5,
|
|
TGSharedMediaCacheItemTypeLink = 6,
|
|
TGSharedMediaCacheItemTypeSticker = 7,
|
|
TGSharedMediaCacheItemTypeGif = 8,
|
|
TGSharedMediaCacheItemTypeVoiceVideoMessage = 9
|
|
*/
|
|
let tags: [Int32] = [
|
|
2, // File
|
|
5, // Audio
|
|
3, // PhotoVideo
|
|
]
|
|
database.withStatement("SELECT mid FROM channel_message_tags_v29 WHERE tag_sort_key<? AND tag_sort_key>? ORDER BY tag_sort_key DESC LIMIT 4000", { select in
|
|
for channelId in channelIds {
|
|
for tag in tags {
|
|
select([.data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 0, timestamp: Int32.max - 1, messageId: 0)), .data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 0, timestamp: 0, messageId: 0))], { cursor in
|
|
channelMessageIds.append((channelId, cursor.getInt32(at: 0)))
|
|
return true
|
|
})
|
|
select([.data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 1, timestamp: Int32.max - 1, messageId: 0)), .data(makeMessageSortKey(tag: tag, conversationId: channelId, space: 1, timestamp: 0, messageId: 0))], { cursor in
|
|
channelMessageIds.append((channelId, cursor.getInt32(at: 0)))
|
|
return true
|
|
})
|
|
}
|
|
}
|
|
})
|
|
}
|
|
|
|
var chatMessageIds: [Int32] = []
|
|
let mediaTypes: [Int32] = [
|
|
1, // video
|
|
2, // image
|
|
3, // file
|
|
]
|
|
for type in mediaTypes {
|
|
database.select("SELECT mids FROM media_cache_v29 WHERE media_type=\(type) ORDER BY date DESC LIMIT 32000", { cursor in
|
|
let midsData = cursor.getData(at: 0)
|
|
let reader = LegacyBufferReader(LegacyBuffer(data: midsData))
|
|
while true {
|
|
if let mid = reader.readInt32() {
|
|
chatMessageIds.append(mid)
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return true
|
|
})
|
|
}
|
|
|
|
var copyLocalFiles: [(MediaResource, String)] = []
|
|
|
|
let totalCount = channelMessageIds.count + chatMessageIds.count
|
|
let reportBase = max(1, totalCount / 100)
|
|
|
|
var itemIndex = -1
|
|
|
|
let cache = TGCache(cachesPath: basePath + "/Caches")!
|
|
|
|
if !channelMessageIds.isEmpty {
|
|
database.withStatement("SELECT data FROM channel_messages_v29 WHERE cid=? AND mid=?", { select in
|
|
for (peerId, messageId) in channelMessageIds {
|
|
itemIndex += 1
|
|
if itemIndex % reportBase == 0 {
|
|
subscriber.putNext(Float(itemIndex) / Float(totalCount))
|
|
}
|
|
select([.int64(peerId), .int32(messageId)], { cursor in
|
|
let data = cursor.getData(at: 0)
|
|
importMediaFromMessageData(data, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
|
return true
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
if !chatMessageIds.isEmpty {
|
|
database.withStatement("SELECT media FROM messages_v29 WHERE mid=?", { select in
|
|
for messageId in chatMessageIds {
|
|
itemIndex += 1
|
|
if itemIndex % reportBase == 0 {
|
|
subscriber.putNext(Float(itemIndex) / Float(totalCount))
|
|
}
|
|
select([.int32(messageId)], { cursor in
|
|
let data = cursor.getData(at: 0)
|
|
importMediaFromMediaData(data, basePath: basePath, copyLocalFiles: ©LocalFiles, cache: cache)
|
|
return true
|
|
})
|
|
}
|
|
})
|
|
}
|
|
|
|
for (resource, path) in copyLocalFiles {
|
|
account.postbox.mediaBox.copyResourceData(resource.id, fromTempPath: path)
|
|
}
|
|
|
|
subscriber.putCompletion()
|
|
|
|
return EmptyDisposable
|
|
}
|
|
}
|