getImageByHash method

Future<ImageData<Object>?> getImageByHash(
  1. String hash, {
  2. Data? owner,
})

Implementation

Future<ImageData?> getImageByHash(String hash, {Data? owner}) async {
  final isPath = hash.contains('/');
  final scope = _scopeForData(owner);
  final legacyScope = scope.contains('undefined')
      ? scope.replaceAll('undefined', 'null')
      : scope;

  String displayNameFromStored(String storedName) {
    var base = storedName.split('/').where((e) => e.isNotEmpty).toList().last;
    // strip prefixes
    if (base.startsWith(LOCALLY_ADDED_PREFIX)) {
      base = base.substring(LOCALLY_ADDED_PREFIX.length);
    }
    // strip common extensions
    final lower = base.toLowerCase();
    const suffixes = [
      '.maybe.jpg',
      '.img',
      '.jpeg',
      '.jpg',
      '.webp',
      '.heic',
      '.png',
    ];
    for (final s in suffixes) {
      if (lower.endsWith(s)) {
        return base.substring(0, base.length - s.length);
      }
    }
    final dot = base.lastIndexOf('.');
    if (dot > 0 && dot > base.length - 8) return base.substring(0, dot);
    return base;
  }

  // Prefer the backend filename-based cache if present.
  if (!isPath) {
    try {
      final indexed = await OP.lookupImageNameForHash(
        hash,
        scope: scope,
      );
      if (indexed != null && indexed.isNotEmpty) {
        final img = await readImage(indexed, cacheSize: null);
        if (img != null)
          return ImageData(img,
              id: hash, name: displayNameFromStored(indexed));
      }
    } catch (_) {}
  }

  List<String> candidates = [];
  if (!isPath && scope.isNotEmpty) {
    final scoped = '$scope/$hash';
    candidates.add(scoped);
  }
  if (!isPath && legacyScope.isNotEmpty && legacyScope != scope) {
    final scoped = '$legacyScope/$hash';
    candidates.add(scoped);
  }
  candidates.add(hash);

  for (final name in candidates) {
    final img = await readImage(name, cacheSize: null);
    if (img != null) {
      // Best-effort migration: if we loaded from a legacy "null" folder, copy to the
      // canonical "undefined" folder so we stop accumulating both.
      if (!isPath &&
          scope.isNotEmpty &&
          legacyScope != scope &&
          name.startsWith('$legacyScope/')) {
        final migratedName = name.replaceFirst(legacyScope, scope);
        try {
          final src = await OP.localFile(name);
          final dst = await OP.localFile(migratedName);
          if (!dst.existsSync()) {
            await dst.parent.create(recursive: true);
            await src.copy(dst.path);
          }
          await OP.indexImageHash(
            hash: hash,
            storedName: migratedName,
            scope: scope,
          );
          final migratedImg = await readImage(migratedName, cacheSize: null);
          if (migratedImg != null) {
            return ImageData(migratedImg,
                id: hash, name: displayNameFromStored(migratedName));
          }
        } catch (_) {}
      }
      return ImageData(img, id: hash, name: displayNameFromStored(name));
    }
  }
  throw Exception("no img cached");
}