Something went wrong. Try again.
[READ-ONLY] Mirror of https://github.com/FoxxMD/multi-scrobbler. Scrobble plays from multiple sources to multiple clients docs.multi-scrobbler.app
deezer docker jellyfin koito lastfm listenbrainz maloja mopidy mpris music music-assistant plex scrobble self-hosted spotify subsonic tautulli youtube-music
Something went wrong. Try again.
5.4 kB · 154 lines
TypeScript
at strict
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155import { Browser, type Service, ServiceType } from "@astronautlabs/mdns";import type {Logger} from "@foxxmd/logging";import AvahiBrowser from 'avahi-browse';import type {MdnsDeviceInfo} from "../common/infrastructure/Atomic.ts";import { MaybeLogger } from '../common/MaybeLogger.ts';import { sleep } from "../utils.ts";import { debounce, type DebouncedFunction } from "./debounce.ts";
export interface AvahiService { service_name: string target: { service_type: string domain: string host: string hostname: string port: string }}
export interface DiscoveryOptions<T> { sanity?: boolean onDiscover?: (service: MdnsDeviceInfo) => void onDnsError?: (err: Error) => void duration?: number, logger?: Logger}
export const discoveryAvahi = async (service: string, options?: DiscoveryOptions<AvahiService>) => { const { logger, duration = 10000, sanity = false, onDiscover, onDnsError } = options ?? {};
const maybeLogger = new MaybeLogger(logger, 'Avahi mDNS'); maybeLogger.debug(`Starting mDNS discovery with Avahi => Listening for ${(duration / 1000).toFixed(2)}s`); let anyDiscovered = false;
const services = new Map<string, MdnsDeviceInfo>();
const triggerDiscovery = () => { for(const [k,v] of services.entries()) { maybeLogger.debug(`Discovered device "${v.name}" with ${v.addresses.length} interfaces`); onDiscover?.(v); services.delete(k); } }
let debouncedFunc: DebouncedFunction;
try { const browser = new AvahiBrowser(service); browser.on(AvahiBrowser.EVENT_SERVICE_UP, async (service: AvahiService) => { anyDiscovered = true;
if(onDiscover !== undefined) {
let foundService = services.get(service.service_name); if(foundService === undefined) { foundService = { name: service.service_name, addresses: [service.target.host], type: service.target.service_type, } } else { foundService.addresses.push(service.target.host); } services.set(foundService.name, foundService);
if(debouncedFunc === undefined) { debouncedFunc = debounce(() => triggerDiscovery(), 1000); } else { await debouncedFunc(); } } }); browser.on(AvahiBrowser.EVENT_DNSSD_ERROR, (err: any) => { const e = new Error('Error occurred while using avahi-browse', {cause: err}); if (onDnsError) { onDnsError(e) } else { maybeLogger.error(e); } }); browser.start(); if (sanity) { await sleep(1500); if (!anyDiscovered) { maybeLogger.debug('Did not find any mdns services after 1.5s! Do you have port 5353 open?'); } await sleep(duration - 1500); } else { await sleep(duration); } maybeLogger.debug('Stopped discovery'); } catch (e) { maybeLogger.warn(new Error('mDNS device discovery with avahi-browse failed', {cause: e})); }}
export const discoveryNative = async (service: string, options?: DiscoveryOptions<Service>) => { const { logger, duration = 10000, sanity = false, onDiscover, onDnsError } = options ?? {};
const maybeLogger = new MaybeLogger(logger, 'mDNS'); maybeLogger.debug(`Starting mDNS discovery => Listening for ${(duration / 1000).toFixed(2)}s`);
if (sanity) { const services: ServiceType[] = []; const testBrowser = new Browser(ServiceType.all()) .on('serviceUp', (service: ServiceType) => { services.push(service) }) .start(); testBrowser.on('error', (err) => { maybeLogger.error(new Error('Error occurred during mDNS service discovery', {cause: err})); }); maybeLogger.debug('Waiting 1s to gather advertised mdns services...'); await sleep(1000); testBrowser.stop(); if (services.length === 0) { maybeLogger.debug('Did not find any mdns services! Do you have port 5353 open?'); } else { maybeLogger.debug(`Found services: ${services.map(x => `${x.name}-${x.protocol}`).join(' ,')}`); } }
const browser = new Browser(service, {resolve: true}) .on('serviceUp', async (service) => { maybeLogger.debug(`Discovered device "${service.name}" with ${service.addresses.length} interfaces`); if (onDiscover) { onDiscover({name: service.name, addresses: service.addresses, type: service.service_type}); } }) browser.on('error', (err) => { const e = new Error('Error occurred during mDNS discovery', {cause: err}); if (onDnsError) { onDnsError(e) } else { maybeLogger.error(e); } }); browser.start(); await sleep(duration); maybeLogger.debug('Stopped discovery'); browser.stop();}