Skip to content

Commit

Permalink
feat(chrome): Improve mdns discovery for docker
Browse files Browse the repository at this point in the history
* Switch to lower-level mdns library for more control during debugging
* Use avahi-browse with host avahi-daemon to circumvent musl (alpline) issues with mdns resolution https://johnsiu.com/blog/alpine-linux/
  • Loading branch information
FoxxMD committed Jan 12, 2024
1 parent 7008ae8 commit e2dfe31
Show file tree
Hide file tree
Showing 9 changed files with 190 additions and 55 deletions.
2 changes: 2 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ RUN \
echo "**** install build packages ****" && \
apk add --no-cache \
alpine-base \
avahi \
avahi-tools \
git \
nodejs \
npm \
Expand Down
24 changes: 23 additions & 1 deletion docsite/docs/configuration/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -701,7 +701,29 @@ If your media device can be **Cast** to using this button ![Chromecast Icon](htt

**Note:** This source relies on common, **basic** music data provided by the cast device which will always be less exhaustive than data parsed from full source integrations. If there is an existing [Source](#source-configurations) it is recommended to configure for it and blacklist the app on Google Cast, rather than relying solely on Google Cast for scrobbling.

The machine and/or container running multi-scrobbler must be configured to allow [mDNS traffic on port 5353/UDP](https://book.hacktricks.xyz/network-services-pentesting/5353-udp-multicast-dns-mdns).
#### Networking Requirements

The host machine running multi-scrobbler must be configured to allow [mDNS traffic on port 5353/UDP](https://book.hacktricks.xyz/network-services-pentesting/5353-udp-multicast-dns-mdns).

##### Linux

**Docker**

The host machine must have [avahi-daemon](https://avahi.org/) running to circumvent limitations with DNS resolution due to musl in Alpine. All major linux distributions package avahi and many have it built-in. Once avahi is running you must pass D-Bus and the avahi daemon socket to your container like so:

```
docker run ... -v /var/run/dbus:/var/run/dbus -v /var/run/avahi-daemon/socket:/var/run/avahi-daemon/socket ... foxxmd/multi-scrobbler
```

**Flatpak**

No additional steps are required.

##### Windows

**Docker**

Unsupported at this time.

#### Cast Troubleshooting

Expand Down
39 changes: 36 additions & 3 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"private": true,
"homepage": ".",
"dependencies": {
"@astronautlabs/mdns": "^1.0.7",
"@awaitjs/express": "^0.6.3",
"@fortawesome/fontawesome-svg-core": "^6.4.2",
"@fortawesome/free-solid-svg-icons": "^6.4.2",
Expand All @@ -59,9 +60,9 @@
"@supercharge/promise-pool": "^3.0.0",
"address": "^1.2.2",
"ajv": "^7.2.4",
"avahi-browse": "^1.1.4",
"better-sse": "^0.8.0",
"body-parser": "^1.19.0",
"bonjour-service": "^1.2.1",
"castv2": "^0.1.10",
"chromecast-client": "github:foxxmd/chromecast-client#dist",
"clsx": "^2.0.0",
Expand Down
6 changes: 6 additions & 0 deletions src/backend/common/infrastructure/Atomic.ts
Original file line number Diff line number Diff line change
Expand Up @@ -226,3 +226,9 @@ export interface Authenticatable {
authFailure?: boolean
testAuth: () => Promise<any>
}

export interface MdnsDeviceInfo {
name: string
type: string
addresses: string[]
}
9 changes: 9 additions & 0 deletions src/backend/common/infrastructure/config/source/chromecast.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,15 @@ export interface ChromecastData extends CommonSourceData {
* @examples [["spotify","pandora"]]
* */
whitelistApps?: string | string[]

/**
* Try to use Avahi and avahi-browse to resolve mDNS devices instead of native mDNS querying
*
* Useful for docker (alpine) container where mDNS resolution is not yet supported. Avahi socket must be exposed to the container and avahi-tools must be installed.
*
* @default false
* */
useAvahi?: boolean
}

export interface ChromecastSourceConfig extends CommonSourceConfig {
Expand Down
8 changes: 4 additions & 4 deletions src/backend/common/vendor/chromecast/ChromecastClientUtils.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {REPORTED_PLAYER_STATUSES, ReportedPlayerStatus} from "../../infrastructure/Atomic";
import {MdnsDeviceInfo, REPORTED_PLAYER_STATUSES, ReportedPlayerStatus} from "../../infrastructure/Atomic";
import {PlatformApplication, PlatformType} from "./interfaces";
import {connect, createPlatform, Media, MediaController, PersistentClient, Result} from "chromecast-client";
import {ErrorWithCause} from "pony-cause";
Expand Down Expand Up @@ -43,13 +43,13 @@ export const getCurrentPlatformApplications = async (platform: PlatformType): Pr
}
}

export const initializeClientPlatform = async (service: Service): Promise<[CastClient, PersistentClient, PlatformType]> => {
export const initializeClientPlatform = async (device: MdnsDeviceInfo): Promise<[CastClient, PersistentClient, PlatformType]> => {
let client: PersistentClient;
let castClient = new CastClient;
try {
client = await connect({host: service.addresses?.[0]});
client = await connect({host: device.addresses?.[0]});
} catch (e) {
throw new ErrorWithCause(`Could not connect to ${service.name}`, {cause: e});
throw new ErrorWithCause(`Could not connect to ${device.name}`, {cause: e});
}

const platform = createPlatform(client);
Expand Down
Loading

0 comments on commit e2dfe31

Please sign in to comment.