From 5012f3df7d16468fe37c40d487e6a4fd915a3b54 Mon Sep 17 00:00:00 2001 From: Karl Date: Tue, 10 Mar 2020 10:19:58 +0000 Subject: [PATCH] newCast --- bin/chromecast.js | 37 ++++++-- bin/newCast.js | 224 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 16 ++++ package.json | 2 + 4 files changed, 273 insertions(+), 6 deletions(-) create mode 100644 bin/newCast.js diff --git a/bin/chromecast.js b/bin/chromecast.js index 9e897d6..0eacf93 100644 --- a/bin/chromecast.js +++ b/bin/chromecast.js @@ -1,11 +1,36 @@ const ChromecastAPI = require('chromecast-api') -const client = new ChromecastAPI() +async function getDevice() { + const client = new ChromecastAPI() + return new Promise(function (resolve, reject) { + client.on('device', function (device) { + // console.log(device) + if (device.friendlyName === 'Downstairs') { + resolve(device); + } + }) + }) +} -client.on('device', function (device) { - var mediaURL = 'http://commondatastorage.googleapis.com/gtv-videos-bucket/big_buck_bunny_1080p.mp4'; - - device.play(mediaURL, function (err) { +async function test() { + var mediaURL = 'https://www.youtube.com/watch?v=pb05OXz7-Ko&list=PLATQ8iWXs4GzKzUhHyImBCvVVQWkTnmeM'; + test = await getDevice() + console.log(test) + test.play(mediaURL, function (err) { if (!err) console.log('Playing in your chromecast') }) -}) \ No newline at end of file +} + +test() + + // console.log(device) + // if (device.friendlyName === 'Downstairs') { + // test.friendlyName = device.friendlyName, + // test.name = device.name, + // test.host = device.host + // } + + // // device.play(mediaURL, function (err) { + // // if (!err) console.log('Playing in your chromecast') + // // }) +// }) \ No newline at end of file diff --git a/bin/newCast.js b/bin/newCast.js new file mode 100644 index 0000000..a8f60eb --- /dev/null +++ b/bin/newCast.js @@ -0,0 +1,224 @@ +const express = require('express'); +const bodyParser = require('body-parser'); +const mdns = require('mdns'); +const Client = require('castv2-client').Client; +const DefaultMediaReceiver = require('castv2-client').DefaultMediaReceiver; +const request = require('request'); +const os = require('os'); +const fs = require('fs'); +const path = require('path'); +const querystring = require('querystring'); + +const PORT = process.env.PORT || 3002; +const app = express(); +const devices = new Map(); +let playlist = []; + +const browser = mdns.createBrowser(mdns.tcp('googlecast')); + +function deviceRegister(name, address, port) { + let id = devices.size; + let client = new Client(); + + return new Promise((resolve, reject) => { + client.connect(address, () => { + client.launch(DefaultMediaReceiver, (err, player) => { + if (err) { + reject(err); + return; + } + + devices.set(id, { name, address, port, client, player }); + resolve(player); + }); + }); + }); +} + +function createEventListeners(player) { + player.on('status', function(status) { + console.log('status broadcast playerState=%s', status.playerState); + if (status.playerState === 'IDLE') { + playlist.splice(0, 1); + writePlaylist(); + if (playlist.length > 0) { + player.load(playlist[0], { autoplay: true}, (err, status) => { + console.log('Play!'); + }); + } + } + }); +} + +function writePlaylist() { + let songs = playlist.map(p => p.metadata.title).join('\n'); + let content = `http://dk.ngrok.io/api +${songs}` + fs.writeFileSync(path.join(os.homedir(), 'playlist.txt'), content, 'utf8'); +} + +function getMediaObject(name, artist, songUrl, picture) { + return { + contentId: songUrl, + contentType: 'audio/mpeg3', + streamType: 'LIVE', // or LIVE + + // Title and cover displayed while buffering + metadata: { + type: 0, + metadataType: 0, + title: `${name} - ${artist}`, + images: [ + { url: picture } + ] + } + }; +} + +let idx = 0; +browser.on('serviceUp', (service) => { + if (idx !== 0) { + return; + } + idx = 1; + console.log('found device "%s" at %s:%d', service.name, service.addresses[0], service.port); + // ondeviceup(service.addresses[0]); + deviceRegister(service.name, service.addresses[0], service.port).then(player => { + console.log('Player registered'); + return player; + }).then(createEventListeners).catch((err) => { + console.error(err.message); + }); + browser.stop(); +}); + +browser.start(); + +app.use(bodyParser.urlencoded({ extended: false })); +app.use(bodyParser.json()); + +app.get('/api', (req, res, next) => { + let stack = app._router.stack; + let methodList = []; + Object.keys(stack).forEach(key => { + let route = stack[key].route; + if (route) { + methodList.push(`${route.stack[0].method.toUpperCase()} ${route.path}`); + } + }); + res.type('text/plain').send(`Available routes: + +${methodList.join('\n')} +`); +}); + +app.get('/api/devices', (req, res, next) => { + let result = []; + + for (let [id, { name, address }] of devices) { + result.push({id, name, address}); + } + + res.send({result}); +}); + +app.get('/api/devices/:id', (req, res, next) => { + let device = devices.get(parseInt(req.params.id, 10)); + let result = {} + if (device) { + result.name = device.name; + result.address = device.address; + result.port = device.port; + } + + res.send(result); +}); + +app.patch('/api/devices/:id', (req, res, next) => { + let state = req.body.state.toLowerCase(); + let device = devices.get(parseInt(req.params.id, 10)); + + if (!device) { + res.send(500, 'FAIL'); + return; + } + + if (state === 'pause') { + playlist = [playlist[0], ...playlist]; + device.player.pause((err, state) => { + console.log('Pause'); + }); + return res.send('PAUSED'); + } else if (state === 'play') { + device.player.play((err, state) => { + console.log('Play'); + }); + return res.send('PLAY'); + } else if (state === 'skip') { + playlist.splice(0, 1); + if (playlist.length > 0) { + device.player.load(playlist[0], { autoplay: true }, (err, state) => { + }); + } + res.send('SKIP'); + writePlaylist(); + } +}); + +app.post('/api/devices/:id/songs', (req, res, next) => { + let song = req.body.song; + let { player } = devices.get(parseInt(req.params.id, 10)); + + if (!song) { + res.send(400, 'Please submit a "song" post paramater'); + return; + } + + request.get(`https://api.spotify.com/v1/search?q=${querystring.escape(song)}&type=track&market=DE`, (err, data, body) => { + if (err || data.statusCode !== 200) { + // console.error(err, data); + res.send(500, 'FAIL'); + return; + } + + body = JSON.parse(body); + let track = body.tracks.items[0]; + if (track) { + let id = track.id; + + request.get(`https://api.spotify.com/v1/tracks/${id}`, (err, data, body) => { + if (err || data.statusCode !== 200) { + // console.error(err, data); + res.send(500, 'FAIL'); + return; + } + body = JSON.parse(body); + + if (body) { + let albumImage = body.album.images[0].url; + let title = body.name; + let artist = body.artists[0].name; + let url = body.preview_url; + + let media = getMediaObject(title, artist, url, albumImage); + + playlist.push(media); + console.log(playlist); + writePlaylist(); + + if (playlist.length === 1) { + player.load(media, { autoplay: true }, (err, status) => { + console.log('PLAY'); + }); + } + + res.send({albumImage, artist, title, url}); + } + }); + } + }); +}); + +app.listen(PORT, () => { + console.log(`Listening on port ${PORT}`); +}); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index a83ce04..bdd6fed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1548,6 +1548,22 @@ "resolved": "https://registry.npmjs.org/longest/-/longest-1.0.1.tgz", "integrity": "sha1-MKCy2jj3N3DoKUoNIuZiXtd9AJc=" }, + "mdns": { + "version": "2.5.1", + "resolved": "https://registry.npmjs.org/mdns/-/mdns-2.5.1.tgz", + "integrity": "sha512-JglS7Ed3Yf0BCpyC7LXA1MUrumMV8jj4g67nT3+m886SFYllz2HWBg8ObywFXWbBSv5gW0meMOOS4vVa2jZGCw==", + "requires": { + "bindings": "~1.2.1", + "nan": "^2.14.0" + }, + "dependencies": { + "bindings": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bindings/-/bindings-1.2.1.tgz", + "integrity": "sha1-FK1hE4EtLTfXLme0ystLtyZQXxE=" + } + } + }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", diff --git a/package.json b/package.json index 9bb3d87..85aa08c 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ }, "dependencies": { "body-parser": "^1.19.0", + "castv2-client": "^1.2.0", "chromecast-api": "^0.3.1", "cookie-parser": "~1.4.4", "debug": "~2.6.9", @@ -18,6 +19,7 @@ "fs": "0.0.1-security", "http-errors": "~1.6.3", "inquirer": "^7.0.6", + "mdns": "^2.5.1", "morgan": "~1.9.1", "net": "^1.0.2", "path": "^0.12.7",