fediverse-archiving-tools/bin/image_archiver.dart
2022-01-15 00:17:38 -05:00

103 lines
3 KiB
Dart

import 'dart:convert';
import 'dart:io';
import 'package:path/path.dart' as p;
import 'package:uuid/uuid.dart';
import 'extensions.dart';
import 'friendica_client.dart';
import 'models.dart';
class ImageArchiver {
final FriendicaClient client;
final _images = <String, ImageEntry>{};
late final Directory imageDirectory;
List<ImageEntry> get images => List.unmodifiable(_images.values);
ImageArchiver(this.client, Directory baseDirectory) {
final imageDirPath = p.join(baseDirectory.path, 'images');
imageDirectory = Directory(imageDirPath);
imageDirectory.createSync(recursive: true);
}
bool addDirectEntries(ImageEntry entry) {
final alreadyExists = _images.containsKey(entry.url);
_images[entry.url] = entry;
return alreadyExists;
}
Future<List<ImageEntry>> addEntryImages(FriendicaEntry entry) async {
final imageEntries = <ImageEntry>[];
for (final imageUrl in entry.images) {
if (_images.containsKey(imageUrl)) {
continue;
}
final url = Uri.parse(imageUrl);
final imageResponse = await client.getUrl(url);
if (imageResponse.isFailure) {
print(imageResponse.error);
continue;
}
if (imageResponse.value.statusCode == 200) {
final contents = <int>[];
await for (var data in imageResponse.value) {
contents.addAll(data);
}
final extension = calculateExtensions(contents);
final filename = Uuid().v4().replaceAll('-', '') + extension;
final filePath = p.join(imageDirectory.path, filename);
await File(filePath).writeAsBytes(contents);
final newEntry = ImageEntry(
postId: entry.id.toString(),
localFilename: filename,
url: imageUrl);
_images[imageUrl] = newEntry;
imageEntries.add(newEntry);
} else {
print(
'Error response attempting to retrieve image $imageUrl: ${imageResponse.value.statusCode}');
}
}
return imageEntries;
}
String calculateExtensions(List<int> imageBytes) {
// Using table from https://www.sparkhound.com/blog/detect-image-file-types-through-byte-arrays
final bmp = ascii.encode("BM").toList(); // BMP
final gif = ascii.encode("GIF").toList(); // GIF
const png = <int>[137, 80, 78, 71]; // PNG
const tiff = <int>[73, 73, 42]; // TIFF
const tiff2 = <int>[77, 77, 42]; // TIFF
const jpeg = <int>[255, 216, 255, 224]; // jpeg
const jpeg2 = <int>[255, 216, 255, 225]; // jpeg canon
final firstFour = imageBytes.sublist(0, 4);
if (firstFour.equals(jpeg) || firstFour.equals(jpeg2)) {
return '.jpg';
}
if (firstFour.equals(png)) {
return '.png';
}
final firstThree = imageBytes.sublist(0, 3);
if (firstThree.equals(gif)) {
return '.gif';
}
if (firstThree.equals(tiff) || firstThree.equals(tiff2)) {
return '.tif';
}
final firstTwo = imageBytes.sublist(0, 2);
if (firstTwo.equals(bmp)) {
return '.bmp';
}
return '';
}
}