All files / app/pipe thumbnail.pipe.ts

52.17% Statements 24/46
47.82% Branches 22/46
71.42% Functions 5/7
56.75% Lines 21/37

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 8478x           78x               78x     5x 5x 5x       5x 5x 5x 5x 5x 2x   3x                                       3x           3x       2x 2x 1x     1x                       5x       13x    
import { Pipe, PipeTransform } from '@angular/core';
import { map, Observable, of } from 'rxjs';
import { Ref } from '../model/ref';
import { AdminService } from '../service/admin.service';
import { ProxyService } from '../service/api/proxy.service';
import { OembedStore } from '../store/oembed';
import { hasTag } from '../util/tag';
 
type ThumbnailRef = Pick<Ref, 'url' | 'origin' | 'plugins' | 'tags'>;
 
@Pipe({
    name: 'thumbnail',
    pure: true
})
export class ThumbnailPipe implements PipeTransform {
 
  constructor(
    private admin: AdminService,
    private store: OembedStore,
    private proxy: ProxyService,
  ) { }
 
  transform(refs: (ThumbnailRef | undefined)[], force = false, prefetch = true): Observable<string> {
    const imagesEnabled = !!this.admin.getPlugin('plugin/image');
    for (const ref of refs) {
      Iif (!ref) continue;
      const thumbnailUrl = refUrl(ref, 'plugin/thumbnail');
      if (thumbnailUrl && (imagesEnabled || isInlineSvg(thumbnailUrl))) {
        return of(this.fetchUrl(thumbnailUrl, ref.origin, 'plugin/thumbnail', prefetch));
      }
      Eif (!imagesEnabled) continue;
      for (const plugin of ['plugin/image', 'plugin/video']) {
        if (refUrl(ref, plugin)) return of(this.fetchUrl(refUrl(ref, plugin), ref.origin, plugin, prefetch));
      }
      if (hasTag('plugin/embed', ref)) {
        return this.store.get(ref.plugins?.['plugin/embed']?.url || ref.url).pipe(
          map(oembed => {
            if (oembed?.thumbnail_url) {
              return this.fetchUrl(oembed.thumbnail_url, ref.origin, 'plugin/thumbnail', prefetch);
            }
            return '';
          }),
        );
      }
      if (!this.validUrl(ref.url)) continue;
      const embedPlugins = this.admin.getEmbeds(ref);
      for (const plugin of ['plugin/image', 'plugin/video']) {
        if (embedPlugins.includes(plugin)) return of(this.fetchUrl(ref.url, ref.origin, plugin, prefetch));
      }
    }
    Iif (imagesEnabled && force) {
      for (const ref of refs) {
        if (!this.validUrl(ref?.url)) continue;
        return of(this.fetchUrl(ref!.url, ref!.origin, 'plugin/image', prefetch));
      }
    }
    return of('');
  }
 
  fetchUrl(url: string, origin: string | undefined, plugin: string, prefetch: boolean) {
    Iif (!url) return '';
    if (isInlineSvg(url)) return url;
    Iif (url.startsWith('cache:') || this.admin.getPlugin(plugin)?.config?.proxy) {
      return this.proxy.getFetch(url, origin, 'thumbnail', true, prefetch);
    }
    return url;
  }
 
  private validUrl(url?: string) {
    return url
      && !url.startsWith('data:')
      && !url.startsWith('comment:')
      && !url.startsWith('internal:');
  }
}
 
function refUrl(ref: Ref, plugin: string) {
  return ref.plugins?.[plugin]?.url;
}
 
export function isInlineSvg(url: string) {
  return /^data:image\/svg\+xml(?:[,;])/i.test(url);
}