diff --git a/package.json b/package.json index 70e22263..6cad8ece 100644 --- a/package.json +++ b/package.json @@ -39,7 +39,7 @@ "@sentry/electron": "^3.0.7", "@sentry/integrations": "^6.19.6", "adm-zip": "0.4.10", - "airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git", + "airtunes2": "git+https://github.com/vapormusic/node_airtunes2.git#hap", "castv2-client": "^1.2.0", "chokidar": "^3.5.3", "discord-rpc": "^4.0.1", diff --git a/src/main/base/browserwindow.ts b/src/main/base/browserwindow.ts index afb38607..2089686c 100644 --- a/src/main/base/browserwindow.ts +++ b/src/main/base/browserwindow.ts @@ -95,6 +95,7 @@ export class BrowserWindow { "components/fullscreen", "components/miniplayer", "components/castmenu", + "components/airplay-modal", "components/artist-chip", "components/hello-world", "components/inline-collection-list", @@ -897,6 +898,10 @@ export class BrowserWindow { event.returnValue = process.platform; }); + ipcMain.on("get-port", (event) => { + event.returnValue = this.clientPort; + }); + ipcMain.on("is-dev", (event) => { event.returnValue = this.devMode; }); diff --git a/src/main/plugins/chromecast.ts b/src/main/plugins/chromecast.ts index 5702fefc..0cac3506 100644 --- a/src/main/plugins/chromecast.ts +++ b/src/main/plugins/chromecast.ts @@ -28,7 +28,7 @@ export default class ChromecastPlugin { // private GCstream = new Stream.PassThrough(), private connectedHosts: any = {}; private connectedPlayer: any; - // private port = false; + private ciderPort :any = 9000; // private server = false; // private bufcount = 0; // private bufcount2 = 0; @@ -148,7 +148,7 @@ export default class ChromecastPlugin { } let media = { // Here you can plug an URL to any mp4, webm, mp3 or jpg file with the proper contentType. - contentId: 'http://' + this.getIp() + ':9000/audio.wav', + contentId: 'http://' + this.getIp() + ':'+ this.ciderPort +'/audio.wav', contentType: 'audio/wav', streamType: 'LIVE', // or LIVE @@ -361,4 +361,12 @@ export default class ChromecastPlugin { } + onRendererReady(): void { + this._win.webContents.executeJavaScript( + `ipcRenderer.sendSync('get-port')` + ).then((result: any) => { + this.ciderPort = result; + }); + } + } \ No newline at end of file diff --git a/src/main/plugins/raop.ts b/src/main/plugins/raop.ts index e6908375..77f9f8d1 100644 --- a/src/main/plugins/raop.ts +++ b/src/main/plugins/raop.ts @@ -147,14 +147,28 @@ export default class RAOP { browser.on('ready', browser.discover); browser.on('update', (service: any) => { - if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) { + if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) { // console.log(service.txt) this._win.webContents.executeJavaScript(`console.log( "${service.name} ${service.host}:${service.port} ${service.addresses}" )`); - this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt);} + this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt); + } }); + + // const browser2 = this.mdns.createBrowser(this.mdns.tcp('airplay')); + // browser2.on('ready', browser2.discover); + // browser2.on('update', (service: any) => { + // if (service.addresses && service.fullname && (service.fullname.includes('_raop._tcp') || service.fullname.includes('_airplay._tcp'))) { + // // console.log(service.txt) + // this._win.webContents.executeJavaScript(`console.log( + // "${service.name} ${service.host}:${service.port} ${service.addresses}" + // )`); + // this.ondeviceup(service.name, service.host, service.port, service.addresses, service.txt); + // } + // }); + }); @@ -178,6 +192,12 @@ export default class RAOP { this._win.webContents.setAudioMuted(true); this._win.webContents.executeJavaScript(`CiderAudio.sendAudio()`).catch((err: any) => console.error(err)); } + if (status == "need_password"){ + this._win.webContents.executeJavaScript(`app.setAirPlayCodeUI()`) + } + if (status == "pair_success"){ + this._win.webContents.executeJavaScript(`app.sendAirPlaySuccess()`) + } if (status == 'stopped') { this.airtunes.stopAll(() => { console.log('end'); @@ -210,6 +230,12 @@ export default class RAOP { }); + electron.ipcMain.on('setAirPlayPasscode', (event, passcode) => { + if (this.device){ + this.device.setPasscode(passcode) + } + }) + electron.ipcMain.on('writeWAV', (event, leftbuffer, rightbuffer) => { if (this.airtunes != null) { if (this.worker == null) { diff --git a/src/renderer/less/helpers.less b/src/renderer/less/helpers.less index db659232..245cce92 100644 --- a/src/renderer/less/helpers.less +++ b/src/renderer/less/helpers.less @@ -70,10 +70,11 @@ .spatialproperties-panel { .modal-window { + &:not(.airplay-modal){ height : 700px; max-height: 700px; width : 800px; - max-width : 800px; + max-width : 800px;} overflow : hidden; .info-header { diff --git a/src/renderer/main/vueapp.js b/src/renderer/main/vueapp.js index a00c345d..1811fa3d 100644 --- a/src/renderer/main/vueapp.js +++ b/src/renderer/main/vueapp.js @@ -207,6 +207,7 @@ const app = new Vue({ showPlaylist: false, castMenu: false, moreInfo: false, + airplayPW: false, }, socialBadges: { badgeMap: {}, @@ -3830,6 +3831,12 @@ const app = new Vue({ // tracks are found in relationship.data }, + setAirPlayCodeUI() { + this.modals.airplayPW = true + }, + sendAirPlaySuccess(){ + notyf.success('Device paired successfully!'); + }, windowFocus(val) { if (val) { document.querySelectorAll(".animated-artwork-video").forEach(el => { diff --git a/src/renderer/views/app/panels.ejs b/src/renderer/views/app/panels.ejs index 69a6f18e..eaccb5f2 100644 --- a/src/renderer/views/app/panels.ejs +++ b/src/renderer/views/app/panels.ejs @@ -28,6 +28,9 @@ + + + diff --git a/src/renderer/views/components/airplay-modal.ejs b/src/renderer/views/components/airplay-modal.ejs new file mode 100644 index 00000000..16ab91a4 --- /dev/null +++ b/src/renderer/views/components/airplay-modal.ejs @@ -0,0 +1,42 @@ + + \ No newline at end of file