From def0d18915bb81c27bb444526a3005cca4e27ec7 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Tue, 18 May 2021 23:39:43 +0300 Subject: [PATCH 01/15] chromecast first try --- package.json | 1 + plugins/chromecast/back.js | 39 +++++++ yarn.lock | 214 +++++++++++++++++++++++++++++++++++-- 3 files changed, 248 insertions(+), 6 deletions(-) create mode 100644 plugins/chromecast/back.js diff --git a/package.json b/package.json index 4a41c6de07..d1692b6c7d 100644 --- a/package.json +++ b/package.json @@ -70,6 +70,7 @@ "async-mutex": "^0.3.1", "browser-id3-writer": "^4.4.0", "chokidar": "^3.5.1", + "chromecast-api": "^0.3.4", "custom-electron-titlebar": "^3.2.6", "discord-rpc": "^3.2.0", "electron-debug": "^3.2.0", diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js new file mode 100644 index 0000000000..abe68e5a9f --- /dev/null +++ b/plugins/chromecast/back.js @@ -0,0 +1,39 @@ +const registerCallback = require('../../providers/song-info'); + +const ChromecastAPI = require('chromecast-api') + +module.exports = () => { + const client = new ChromecastAPI() + + client.on('device', registerDevice); +}; + +function registerDevice(device) { + let currentUrl; + let isPaused; + + registerCallback(songInfo => { + if (!songInfo?.title) { + return; + } + if (currentUrl !== songInfo.url) { //new song + currentUrl = songInfo.url; + isPaused = songInfo.isPaused; + + device.play(transformURL(songInfo.url), function (err) { + if (!err) console.log(`Playing in your chromecast: "${songInfo.title}"`) + }); + + } else if (isPaused !== songInfo.isPaused ) { //paused status changed + isPaused = songInfo.isPaused; + isPaused ? + device.pause() : + device.resume(); + } + }); +} + +function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 + const videoId = url.match(/http(?:s?):\/\/(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/); + return videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"; +} diff --git a/yarn.lock b/yarn.lock index 4a6bc17acf..2fc3fe6d80 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1077,6 +1077,59 @@ "@nodelib/fs.scandir" "2.1.4" fastq "^1.6.0" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= + "@remusao/guess-url-type@^1.1.2": version "1.2.1" resolved "https://registry.yarnpkg.com/@remusao/guess-url-type/-/guess-url-type-1.2.1.tgz#b3e7c32abdf98d0fb4f93cc67cad580b5fe4ba57" @@ -1291,6 +1344,11 @@ dependencies: "@types/node" "*" +"@types/long@^4.0.1": + version "4.0.1" + resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" + integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== + "@types/minimatch@*": version "3.0.3" resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" @@ -1306,6 +1364,11 @@ resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.25.tgz#15967a7b577ff81383f9b888aa6705d43fbbae93" integrity sha512-EPpXLOVqDvisVxtlbvzfyqSsFeQxltFbluZNRndIb8tr9KiBnYNLzrc1N3pyKUCww2RNrfHDViqDWWE1LCJQtQ== +"@types/node@>=13.7.0": + version "15.3.0" + resolved "https://registry.yarnpkg.com/@types/node/-/node-15.3.0.tgz#d6fed7d6bc6854306da3dea1af9f874b00783e26" + integrity sha512-8/bnjSZD86ZfpBsDlCIkNXIvm+h6wi9g7IqL+kmFkQ+Wvu3JrasgLElfiPgoo8V8vVfnEi0QVS12gbl94h9YsQ== + "@types/node@^14.6.2": version "14.14.44" resolved "https://registry.yarnpkg.com/@types/node/-/node-14.14.44.tgz#df7503e6002847b834371c004b372529f3f85215" @@ -1878,6 +1941,13 @@ async@0.9.x: resolved "https://registry.yarnpkg.com/async/-/async-0.9.2.tgz#aea74d5e61c1f899613bf64bda66d4c78f2fd17d" integrity sha1-rqdNXmHB+JlhO/ZL2mbUx48v0X0= +async@^2.6.0: + version "2.6.3" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.3.tgz#d72625e2344a3656e3a3ad4fa749fa83299d82ff" + integrity sha512-zflvls11DCy+dQWzTW2dzuilv8Z5X/pjfmZOWba6TNIVDm+2UDaJmXSOXlasHKfNBs8oo3M0aT50fDEWfKZjXg== + dependencies: + lodash "^4.17.14" + async@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/async/-/async-3.2.0.tgz#b3a2685c5ebb641d3de02d161002c60fc9f85720" @@ -2030,7 +2100,7 @@ bluebird-lst@^1.0.9: dependencies: bluebird "^3.5.5" -bluebird@^3.5.5: +bluebird@^3.5.1, bluebird@^3.5.5: version "3.7.2" resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== @@ -2219,6 +2289,11 @@ buffer-from@^1.0.0: resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== +buffer-indexof@^1.0.0: + version "1.1.1" + resolved "https://registry.yarnpkg.com/buffer-indexof/-/buffer-indexof-1.1.1.tgz#52fabcc6a606d1a00302802648ef68f639da268c" + integrity sha512-4/rOEg86jivtPTeOUUT61jJO1Ya1TrR/OkqCSZDyq84WJh3LuuiphBYJN+fm5xufIk4XAFcEwte/8WzC8If/1g== + buffer-xor@^1.0.3: version "1.0.3" resolved "https://registry.yarnpkg.com/buffer-xor/-/buffer-xor-1.0.3.tgz#26e61ed1422fb70dd42e6e36729ed51d855fe8d9" @@ -2384,6 +2459,22 @@ caseless@~0.12.0: resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= +castv2-client@1.2.0: + version "1.2.0" + resolved "https://registry.yarnpkg.com/castv2-client/-/castv2-client-1.2.0.tgz#a9193b1a5448b8cb9a0415bd021c8811ed7b0544" + integrity sha1-qRk7GlRIuMuaBBW9AhyIEe17BUQ= + dependencies: + castv2 "~0.1.4" + debug "^2.2.0" + +castv2@~0.1.4: + version "0.1.10" + resolved "https://registry.yarnpkg.com/castv2/-/castv2-0.1.10.tgz#d3df00124f1ba8a97691c69dd44221d3b5f93c56" + integrity sha512-3QWevHrjT22KdF08Y2a217IYCDQDP7vEJaY4n0lPBeC5UBYbMFMadDfVTsaQwq7wqsEgYUHElPGm3EO1ey+TNw== + dependencies: + debug "^4.1.1" + protobufjs "^6.8.8" + chalk@1.1.3: version "1.1.3" resolved "https://registry.yarnpkg.com/chalk/-/chalk-1.1.3.tgz#a8115c55e4a702fe4d150abd3872822a7e09fc98" @@ -2454,6 +2545,20 @@ chrome-launcher@^0.13.1: mkdirp "^0.5.3" rimraf "^3.0.2" +chromecast-api@^0.3.4: + version "0.3.4" + resolved "https://registry.yarnpkg.com/chromecast-api/-/chromecast-api-0.3.4.tgz#7c4a30f29dc8a76aa725da893c926dcfb616d647" + integrity sha512-b7+qyms+78cRMUiygPW/x8E5SL3gFRycmZDO5JWKYp0NS3wY4S620j0Xo6oQumQFMKUEvnVlEIPqPcDwzlam3A== + dependencies: + castv2-client "1.2.0" + debug "^4.1.1" + dns-txt "^2.0.2" + mime "^2.3.1" + multicast-dns "^7.2.0" + node-ssdp "^4.0.0" + xml2js "^0.4.23" + youtube-remote "^1.0.0" + chromium-pickle-js@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/chromium-pickle-js/-/chromium-pickle-js-0.2.0.tgz#04a106672c18b085ab774d983dfa3ea138f22205" @@ -2924,6 +3029,13 @@ debug@^2.2.0, debug@^2.3.3, debug@^2.6.8, debug@^2.6.9: dependencies: ms "2.0.0" +debug@^3.1.0, debug@^3.2.6: + version "3.2.7" + resolved "https://registry.yarnpkg.com/debug/-/debug-3.2.7.tgz#72580b7e9145fb39b6676f9c5e5fb100b934179a" + integrity sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ== + dependencies: + ms "^2.1.1" + debug@^4.3.2: version "4.3.2" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.2.tgz#f0a49c18ac8779e31d4a0c6029dfb76873c7428b" @@ -3164,6 +3276,21 @@ dmg-license@^1.0.8: smart-buffer "^4.0.2" verror "^1.10.0" +dns-packet@^4.0.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-4.2.0.tgz#3fd6f5ff5a4ec3194ed0b15312693ffe8776b343" + integrity sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw== + dependencies: + ip "^1.1.5" + safe-buffer "^5.1.1" + +dns-txt@^2.0.2: + version "2.0.2" + resolved "https://registry.yarnpkg.com/dns-txt/-/dns-txt-2.0.2.tgz#b91d806f5d27188e4ab3e7d107d881a1cc4642b6" + integrity sha1-uR2Ab10nGI5Ks+fRB9iBocxGQrY= + dependencies: + buffer-indexof "^1.0.0" + doctrine@1.5.0: version "1.5.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-1.5.0.tgz#379dce730f6166f76cefa4e6707a159b02c5a6fa" @@ -3981,7 +4108,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2: assign-symbols "^1.0.0" is-extendable "^1.0.1" -extend@~3.0.2: +extend@^3.0.1, extend@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== @@ -4804,7 +4931,7 @@ iconv-corefoundation@^1.1.5: cli-truncate "^1.1.0" node-addon-api "^1.6.3" -iconv-lite@0.4.24: +iconv-lite@0.4.24, iconv-lite@^0.4.4: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== @@ -4927,6 +5054,11 @@ ip-regex@^2.1.0: resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-2.1.0.tgz#fa78bf5d2e6913c911ce9f819ee5146bb6d844e9" integrity sha1-+ni/XS5pE8kRzp+BnuUUa7bYROk= +ip@^1.1.5: + version "1.1.5" + resolved "https://registry.yarnpkg.com/ip/-/ip-1.1.5.tgz#bdded70114290828c0a039e72ef25f5aaec4354a" + integrity sha1-vd7XARQpCCjAoDnnLvJfWq7ENUo= + irregular-plurals@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/irregular-plurals/-/irregular-plurals-3.2.0.tgz#b19c490a0723798db51b235d7e39add44dab0822" @@ -6197,7 +6329,7 @@ lodash@^4.13.1, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20: resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.20.tgz#b44a9b6297bcb698f1c51a3545a2b3b368d59c52" integrity sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA== -lodash@^4.17.10, lodash@^4.17.21: +lodash@^4.17.10, lodash@^4.17.14, lodash@^4.17.21, lodash@^4.17.4: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -6219,6 +6351,11 @@ loglevel@^1.6.0: resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.7.1.tgz#005fde2f5e6e47068f935ff28573e125ef72f197" integrity sha512-Hesni4s5UkWkwCGJMQGAh71PaLUmKFM60dHvq0zi/vDhhrzuk+4GgNbTXJ12YYQJn6ZKBDNIjYcuQGKudvqrIw== +long@^4.0.0: + version "4.0.0" + resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" + integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== + lowercase-keys@^1.0.0, lowercase-keys@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f" @@ -6400,7 +6537,7 @@ mime@^1.3.4: resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== -mime@^2.5.0: +mime@^2.3.1, mime@^2.5.0: version "2.5.2" resolved "https://registry.yarnpkg.com/mime/-/mime-2.5.2.tgz#6e3dc6cc2b9510643830e5f19d5cb753da5eeabe" integrity sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg== @@ -6508,6 +6645,19 @@ ms@2.1.2: resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.1: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + +multicast-dns@^7.2.0: + version "7.2.2" + resolved "https://registry.yarnpkg.com/multicast-dns/-/multicast-dns-7.2.2.tgz#5731da04f47d1e435ac457e5ac7b4b39d866a5a1" + integrity sha512-XqSMeO8EWV/nOXOpPV8ztIpNweVfE1dSpz6SQvDPp71HD74lMXjt4m/mWB1YBMG0kHtOodxRWc5WOb/UNN1A5g== + dependencies: + dns-packet "^4.0.0" + thunky "^1.0.2" + multimap@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/multimap/-/multimap-1.1.0.tgz#5263febc085a1791c33b59bb3afc6a76a2a10ca8" @@ -6535,6 +6685,15 @@ natural-compare@^1.4.0: resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" integrity sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc= +needle@^2.5.0: + version "2.6.0" + resolved "https://registry.yarnpkg.com/needle/-/needle-2.6.0.tgz#24dbb55f2509e2324b4a99d61f413982013ccdbe" + integrity sha512-KKYdza4heMsEfSWD7VPUIz3zX2XDwOyX2d+geb4vrERZMT5RMU6ujjaD+I5Yr54uZxQ2w6XRTAhHBbSCyovZBg== + dependencies: + debug "^3.2.6" + iconv-lite "^0.4.4" + sax "^1.2.4" + nice-try@^1.0.4: version "1.0.5" resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" @@ -6618,6 +6777,17 @@ node-releases@^1.1.70: resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.71.tgz#cb1334b179896b1c89ecfdd4b725fb7bbdfc7dbb" integrity sha512-zR6HoT6LrLCRBwukmrVbHv0EpEQjksO6GmFcZQQuCAy139BEsoVKPYnf3jongYW83fAa1torLGYwxxky/p28sg== +node-ssdp@^4.0.0: + version "4.0.1" + resolved "https://registry.yarnpkg.com/node-ssdp/-/node-ssdp-4.0.1.tgz#ea5b2e9a287823b58b3ede348b22a08159cf718f" + integrity sha512-uJXkLZVuyaMg1qNbMbGQ6YzNzyOD+NLxYyxIJocPTKTVECPDokOiCZA686jTLXHMUnV34uY/lcUSJ+/5fhY43A== + dependencies: + async "^2.6.0" + bluebird "^3.5.1" + debug "^3.1.0" + extend "^3.0.1" + ip "^1.1.5" + normalize-package-data@^2.3.2, normalize-package-data@^2.5.0: version "2.5.0" resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8" @@ -7314,6 +7484,25 @@ proto-props@^2.0.0: resolved "https://registry.yarnpkg.com/proto-props/-/proto-props-2.0.0.tgz#8ac6e6dec658545815c623a3bc81580deda9a181" integrity sha512-2yma2tog9VaRZY2mn3Wq51uiSW4NcPYT1cQdBagwyrznrilKSZwIZ0UG3ZPL/mx+axEns0hE35T5ufOYZXEnBQ== +protobufjs@^6.8.8: + version "6.11.2" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.11.2.tgz#de39fabd4ed32beaa08e9bb1e30d08544c1edf8b" + integrity sha512-4BQJoPooKJl2G9j3XftkIXjoC9C0Av2NOrWmbLWT1vH32GcSUHjM0Arra6UfTsVyfMAuFzaLucXn1sadxJydAw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/long" "^4.0.1" + "@types/node" ">=13.7.0" + long "^4.0.0" + proxy-from-env@^1.0.0: version "1.1.0" resolved "https://registry.yarnpkg.com/proxy-from-env/-/proxy-from-env-1.1.0.tgz#e102f16ca355424865755d2c9e8ea4f24d58c3e2" @@ -8488,6 +8677,11 @@ through@2, through@^2.3.8: resolved "https://registry.yarnpkg.com/through/-/through-2.3.8.tgz#0dd4c9ffaabc357960b1b724115d7e0e86a2e1f5" integrity sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU= +thunky@^1.0.2: + version "1.1.0" + resolved "https://registry.yarnpkg.com/thunky/-/thunky-1.1.0.tgz#5abaf714a9405db0504732bbccd2cedd9ef9537d" + integrity sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA== + timers-browserify@^2.0.4: version "2.0.12" resolved "https://registry.yarnpkg.com/timers-browserify/-/timers-browserify-2.0.12.tgz#44a45c11fbf407f34f97bccd1577c652361b00ee" @@ -9143,7 +9337,7 @@ xml-parse-from-string@^1.0.0: resolved "https://registry.yarnpkg.com/xml-parse-from-string/-/xml-parse-from-string-1.0.1.tgz#a9029e929d3dbcded169f3c6e28238d95a5d5a28" integrity sha1-qQKekp09vN7RafPG4oI42VpdWig= -xml2js@^0.4.5: +xml2js@^0.4.23, xml2js@^0.4.5: version "0.4.23" resolved "https://registry.yarnpkg.com/xml2js/-/xml2js-0.4.23.tgz#a0c69516752421eb2ac758ee4d4ccf58843eac66" integrity sha512-ySPiMjM0+pLDftHgXY4By0uswI3SPKLDw/i3UXbnO8M/p28zqexCUoPmQFrYD+/1BzhGJSs2i1ERWKJAtiLrug== @@ -9330,6 +9524,14 @@ yocto-queue@^0.1.0: resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== +youtube-remote@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/youtube-remote/-/youtube-remote-1.0.2.tgz#873acdd3b206762da011ebdb6a61284454418bc8" + integrity sha512-IR7OtIuk7NA4wcrRDBbWtLQtM/hcZdtrxgelAwzajvrzzbwGFTf1O+yDzhUWcqOdw2QAp8fKXxS4QQR3e3k24A== + dependencies: + lodash "^4.17.4" + needle "^2.5.0" + ytdl-core@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/ytdl-core/-/ytdl-core-4.5.0.tgz#f07733387c548e5c3a5614c93ef55bde666eeaf4" From 598abf33fff7b76b4861e3d288ba2424f13d4c63 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Tue, 18 May 2021 23:55:59 +0300 Subject: [PATCH 02/15] log more info --- plugins/chromecast/back.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index abe68e5a9f..a40b8eabed 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -11,7 +11,7 @@ module.exports = () => { function registerDevice(device) { let currentUrl; let isPaused; - + console.log(`Registered a new device: ${device.friendlyName}`) registerCallback(songInfo => { if (!songInfo?.title) { return; @@ -29,6 +29,7 @@ function registerDevice(device) { isPaused ? device.pause() : device.resume(); + console.log(isPaused ? "Paused" : "Resumed" + "palyback on your chromecast device") } }); } From f35bc815d3ba660639e4924fc7f03c7e632c61a5 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 19 May 2021 00:03:29 +0300 Subject: [PATCH 03/15] update broken music.youtube detection --- plugins/chromecast/back.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index a40b8eabed..518b224e57 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -36,5 +36,5 @@ function registerDevice(device) { function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 const videoId = url.match(/http(?:s?):\/\/(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/); - return videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"; + return "https://youtube.com/watch?v=" + (videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"); } From a4f06f5b9e21eb99eccbaa10bec9b457404247dd Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 19 May 2021 00:58:29 +0300 Subject: [PATCH 04/15] added messagebox debugging --- plugins/chromecast/back.js | 19 +++++++++++++++---- 1 file changed, 15 insertions(+), 4 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index 518b224e57..ea81e493c1 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -3,7 +3,7 @@ const registerCallback = require('../../providers/song-info'); const ChromecastAPI = require('chromecast-api') module.exports = () => { - const client = new ChromecastAPI() + const client = new ChromecastAPI(); client.on('device', registerDevice); }; @@ -11,7 +11,7 @@ module.exports = () => { function registerDevice(device) { let currentUrl; let isPaused; - console.log(`Registered a new device: ${device.friendlyName}`) + log(`Registered a new device: ${device.friendlyName}`) registerCallback(songInfo => { if (!songInfo?.title) { return; @@ -21,7 +21,7 @@ function registerDevice(device) { isPaused = songInfo.isPaused; device.play(transformURL(songInfo.url), function (err) { - if (!err) console.log(`Playing in your chromecast: "${songInfo.title}"`) + if (!err) log(`Playing in your chromecast: "${songInfo.title}"`) }); } else if (isPaused !== songInfo.isPaused ) { //paused status changed @@ -29,7 +29,7 @@ function registerDevice(device) { isPaused ? device.pause() : device.resume(); - console.log(isPaused ? "Paused" : "Resumed" + "palyback on your chromecast device") + log(isPaused ? "Paused" : "Resumed" + "palyback on your chromecast device") } }); } @@ -38,3 +38,14 @@ function transformURL(url) {// will not be needed after https://github.com/alxho const videoId = url.match(/http(?:s?):\/\/(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/); return "https://youtube.com/watch?v=" + (videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"); } + +const { dialog } = require('electron') + +async function log(msg) { + dialog.showMessageBox(null, { + type: 'info', + buttons: ['Ok'], + title: 'Chromecast Status', + message: msg, + }); +} From ba87b35809d30315efa14be40fb7e6328acb1d23 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Wed, 19 May 2021 21:51:40 +0300 Subject: [PATCH 05/15] Chromecast v0.9.0 --- plugins/chromecast/back.js | 110 ++++++++++++++++++++++++------- plugins/chromecast/front.js | 29 ++++++++ plugins/chromecast/menu.js | 40 +++++++++++ providers/front-logger.js | 3 + providers/song-controls-front.js | 33 ++++++---- 5 files changed, 179 insertions(+), 36 deletions(-) create mode 100644 plugins/chromecast/front.js create mode 100644 plugins/chromecast/menu.js diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index ea81e493c1..76042c17b9 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -1,37 +1,93 @@ -const registerCallback = require('../../providers/song-info'); +const getSongInfo = require("../../providers/song-info"); +const { ipcMain } = require('electron') +const ChromecastAPI = require('chromecast-api'); +const { setOptions } = require("../../config/plugins"); -const ChromecastAPI = require('chromecast-api') +let client; +let deviceList = []; -module.exports = () => { - const client = new ChromecastAPI(); +let registerCallback; - client.on('device', registerDevice); +let win; + +let options; + +module.exports = (winImport, initialOptions) => { + win = winImport; + options = initialOptions; + registerCallback = getSongInfo(win); + + client = new ChromecastAPI(); + + client.on('device', (device) => { + if (!deviceList.includes(device.name)) { + registerDevice(device); + } + }); + ipcMain.on('volume-change', (_, v) => setVolume(v)); + ipcMain.on('seeked-to', (_, s) => seekTo(s)); }; +function setVolume(volume) { + if (!options.syncVolume) return; + + for (const device of client.devices) { + device.setVolume(volume); + } +} + +function seekTo(seconds, device = null) { + if (device) { + device.seekTo(seconds); + } else { + win.webContents.send("log", `Seeking to "${seconds}" seconds`); + for (const device_ of client.devices) { + device_.seekTo(seconds); + } + } +} + +async function getTime() { + return win.webContents.executeJavaScript(`document.querySelector("video").currentTime`); +} + function registerDevice(device) { + deviceList.push(device.name); + + device.on('status', async (status) => { + win.webContents.send("log", JSON.stringify(status, null, "\t")); + if (status.playerState === "PLAYING") { + if (options.syncChromecastTime) { + const currentTime = await getTime(); + const timeDiff = Math.abs(status.currentTime - currentTime); + if (timeDiff > 1) { + win.webContents.send("log", `Time difference = ${timeDiff}, Setting Chromecast to "${currentTime}" seconds`); + seekTo(currentTime, device); + } + } else if (options.syncAppTime) { + win.webContents.send("setPlaybackTime", status.currentTime); + } + } + }) + let currentUrl; let isPaused; - log(`Registered a new device: ${device.friendlyName}`) registerCallback(songInfo => { if (!songInfo?.title) { return; - } + } if (currentUrl !== songInfo.url) { //new song currentUrl = songInfo.url; isPaused = songInfo.isPaused; + device.play(transformURL(songInfo.url)); - device.play(transformURL(songInfo.url), function (err) { - if (!err) log(`Playing in your chromecast: "${songInfo.title}"`) - }); - - } else if (isPaused !== songInfo.isPaused ) { //paused status changed + } else if (isPaused !== songInfo.isPaused) { //paused status changed isPaused = songInfo.isPaused; isPaused ? device.pause() : device.resume(); - log(isPaused ? "Paused" : "Resumed" + "palyback on your chromecast device") } - }); + }); } function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 @@ -39,13 +95,23 @@ function transformURL(url) {// will not be needed after https://github.com/alxho return "https://youtube.com/watch?v=" + (videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"); } -const { dialog } = require('electron') +function setOption(value, ...keys) { + for (const key of keys) { + if (typeof key === "string") { + options[key] = value; + } else if (key.name && key.value){ + options[key.name] = key.value; + } + } + setOptions("chromecast", options); +} -async function log(msg) { - dialog.showMessageBox(null, { - type: 'info', - buttons: ['Ok'], - title: 'Chromecast Status', - message: msg, - }); +module.exports.setOption = setOption; + +module.exports.menuCheck = (options_) => { + if (!options) options = options_; +} + +module.exports.refreshChromecast = () => { + if (client) client.update(); } diff --git a/plugins/chromecast/front.js b/plugins/chromecast/front.js new file mode 100644 index 0000000000..f3f1eada3b --- /dev/null +++ b/plugins/chromecast/front.js @@ -0,0 +1,29 @@ +const { ipcRenderer } = require('electron'); + +const { playPause } = require("../../providers/song-controls-front"); + +const sendVolume = (volume) => ipcRenderer.send('volume-change', volume); +const sendTime = (seconds) => ipcRenderer.send('seeked-to', seconds); + +module.exports = function checkVideoLoaded() { + const video = document.querySelector("video"); + video ? setup(video) : setTimeout(checkVideoLoaded, 500); +} + +function setup(video) { + + sendVolume(video.volume); + + video.addEventListener('volumechange', e => sendVolume(e.target.volume)); + + video.addEventListener('seeking', e => sendTime(e.target.currentTime)); //or 'seeked' + + ipcRenderer.on("setPlaybackTime", seconds => { + const timeDiff = Math.abs(video.currentTime - seconds); + console.log(`Time difference = ${timeDiff}, Setting App Video to "${seconds}" seconds`); + + playPause(); + video.currentTime = seconds; + playPause(); + }) +} diff --git a/plugins/chromecast/menu.js b/plugins/chromecast/menu.js new file mode 100644 index 0000000000..9ae3b875aa --- /dev/null +++ b/plugins/chromecast/menu.js @@ -0,0 +1,40 @@ +const { menuCheck, setOption, refreshChromecast } = require("./back"); + +module.exports = (_win, options) => { + menuCheck(options); + return [ + { type: "separator" }, + { + label: "Sync Volume", + type: "checkbox", + checked: !!options.syncVolume, + click: (item) => setOption(item.checked, "syncVolume") + }, + { type: "separator" }, + { + label: "Sync Chromecast time with App", + type: "radio", + checked: !!options.syncChromecastTime, + click: () => + setOption(true, "syncChromecastTime", { name: "syncAppTime", value: false }) + }, + { + label: "Sync App time with Chromecast", + type: "radio", + checked: !!options.syncAppTime, + click: () => + setOption(true, "syncAppTime", { name: "syncChromecastTime", value: false }) + }, + { + label: "Disable time sync", + type: "radio", + checked: !options.syncAppTime && !options.syncChromecastTime, + click: () => setOption(false, "syncAppTime", "syncChromecastTime") + }, + { type: "separator" }, + { + label: "Refresh Device List", + click: refreshChromecast + } + ] +}; diff --git a/providers/front-logger.js b/providers/front-logger.js index 99da232916..f435a8c660 100644 --- a/providers/front-logger.js +++ b/providers/front-logger.js @@ -10,4 +10,7 @@ module.exports = () => { ipcRenderer.on("log", (_event, log) => { console.log(logToString(log)); }); + ipcRenderer.on("logObject", (_event, logObject) => { + console.log(JSON.parse(logObject)); + }); }; diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js index 1860e7614e..7d21b80490 100644 --- a/providers/song-controls-front.js +++ b/providers/song-controls-front.js @@ -1,18 +1,23 @@ const { ipcRenderer } = require("electron"); -let videoStream = document.querySelector(".video-stream"); -module.exports = () => { - ipcRenderer.on("playPause", () => { - if (!videoStream) { - videoStream = document.querySelector(".video-stream"); - } +let video = document.querySelector("video"); + +function playPause() { + if (!video) { + video = document.querySelector(".video-stream"); + } + + if (video.paused) { + video.play(); + } else { + video.yns_pause ? + video.yns_pause() : + video.pause(); + } +} - if (videoStream.paused) { - videoStream.play(); - } else { - videoStream.yns_pause ? - videoStream.yns_pause() : - videoStream.pause(); - } - }); +module.exports = () => { + ipcRenderer.on("playPause", playPause); }; + +module.exports.playPause = playPause; From 2f55710687cbd916c37f8c341242fd8464746d22 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Thu, 20 May 2021 01:06:04 +0300 Subject: [PATCH 06/15] Chromecast v0.9.1 --- plugins/chromecast/back.js | 39 ++++++++++++++++++++------------ plugins/chromecast/front.js | 15 ++++++------ providers/song-controls-front.js | 2 +- 3 files changed, 32 insertions(+), 24 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index 76042c17b9..8c2095d1cf 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -25,7 +25,7 @@ module.exports = (winImport, initialOptions) => { } }); ipcMain.on('volume-change', (_, v) => setVolume(v)); - ipcMain.on('seeked-to', (_, s) => seekTo(s)); + ipcMain.on('seeked-to', (_, s) => seekTo(s + 1.5)); }; function setVolume(volume) { @@ -37,6 +37,7 @@ function setVolume(volume) { } function seekTo(seconds, device = null) { + if (options.syncChromecastTime) return; if (device) { device.seekTo(seconds); } else { @@ -53,19 +54,23 @@ async function getTime() { function registerDevice(device) { deviceList.push(device.name); - + let currentStatus; device.on('status', async (status) => { - win.webContents.send("log", JSON.stringify(status, null, "\t")); - if (status.playerState === "PLAYING") { - if (options.syncChromecastTime) { - const currentTime = await getTime(); - const timeDiff = Math.abs(status.currentTime - currentTime); - if (timeDiff > 1) { - win.webContents.send("log", `Time difference = ${timeDiff}, Setting Chromecast to "${currentTime}" seconds`); - seekTo(currentTime, device); + currentStatus = status.playerState; + //win.webContents.send("log", JSON.stringify(status, null, "\t")); + if (currentStatus === "PLAYING") { + const currentTime = await getTime(); + const timeDiff = Math.abs(status.currentTime - currentTime); + if (timeDiff > 1) { + if (options.syncChromecastTime) { + seekTo(currentTime + 1.5, device); + win.webContents.send("log", 'options.syncChromecastTime = ' + options.syncChromecastTime + + ` \nTime difference = ${timeDiff}, Setting Chromecast to "${currentTime}" +1.5 seconds`); + } else if (options.syncAppTime) { + win.webContents.send("setPlaybackTime", status.currentTime); + win.webContents.send("log", 'options.syncAppTime = ' + options.syncAppTime + + ` \nTime difference = ${timeDiff}, Setting AppVideo to "${status.currentTime}" seconds`); } - } else if (options.syncAppTime) { - win.webContents.send("setPlaybackTime", status.currentTime); } } }) @@ -83,9 +88,13 @@ function registerDevice(device) { } else if (isPaused !== songInfo.isPaused) { //paused status changed isPaused = songInfo.isPaused; - isPaused ? - device.pause() : + if (isPaused) { + if (currentStatus === "PLAYING") { + device.pause() + } + } else { device.resume(); + } } }); } @@ -99,7 +108,7 @@ function setOption(value, ...keys) { for (const key of keys) { if (typeof key === "string") { options[key] = value; - } else if (key.name && key.value){ + } else if (typeof key.name == "string" && typeof key.value === "boolean") { options[key.name] = key.value; } } diff --git a/plugins/chromecast/front.js b/plugins/chromecast/front.js index f3f1eada3b..e48888b4e1 100644 --- a/plugins/chromecast/front.js +++ b/plugins/chromecast/front.js @@ -1,7 +1,5 @@ const { ipcRenderer } = require('electron'); -const { playPause } = require("../../providers/song-controls-front"); - const sendVolume = (volume) => ipcRenderer.send('volume-change', volume); const sendTime = (seconds) => ipcRenderer.send('seeked-to', seconds); @@ -14,16 +12,17 @@ function setup(video) { sendVolume(video.volume); - video.addEventListener('volumechange', e => sendVolume(e.target.volume)); + video.addEventListener('volumechange', e => sendVolume(e.target.volume), {passive: true}); - video.addEventListener('seeking', e => sendTime(e.target.currentTime)); //or 'seeked' + video.addEventListener('seeking', e => sendTime(e.target.currentTime), {passive: true}); //or 'seeked' - ipcRenderer.on("setPlaybackTime", seconds => { + ipcRenderer.on("setPlaybackTime", (_e, seconds) => { const timeDiff = Math.abs(video.currentTime - seconds); - console.log(`Time difference = ${timeDiff}, Setting App Video to "${seconds}" seconds`); - playPause(); + console.log(`Actual Time difference = ${timeDiff}`); + + video.yns_pause ? video.yns_pause() : video.pause(); video.currentTime = seconds; - playPause(); + video.play(); }) } diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js index 7d21b80490..94f9d94d2b 100644 --- a/providers/song-controls-front.js +++ b/providers/song-controls-front.js @@ -4,7 +4,7 @@ let video = document.querySelector("video"); function playPause() { if (!video) { - video = document.querySelector(".video-stream"); + video = document.querySelector("video"); } if (video.paused) { From 713120f186be5190413e5499088421e17485a530 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 23 May 2021 17:47:59 +0300 Subject: [PATCH 07/15] chromecast v1.0.0 --- plugins/chromecast/back.js | 69 +++++++++++++------------------- plugins/chromecast/front.js | 16 ++------ plugins/chromecast/menu.js | 26 ++++-------- providers/song-controls-front.js | 40 +++++++++++++----- providers/song-controls.js | 3 +- 5 files changed, 71 insertions(+), 83 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index 8c2095d1cf..218e168d26 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -1,4 +1,6 @@ const getSongInfo = require("../../providers/song-info"); +const getSongControls = require('../../providers/song-controls'); + const { ipcMain } = require('electron') const ChromecastAPI = require('chromecast-api'); const { setOptions } = require("../../config/plugins"); @@ -10,10 +12,16 @@ let registerCallback; let win; +let play, pause; + let options; module.exports = (winImport, initialOptions) => { win = winImport; + const { playPause } = getSongControls(win); + play = () => playPause(true); + pause = () => playPause(false); + options = initialOptions; registerCallback = getSongInfo(win); @@ -29,49 +37,29 @@ module.exports = (winImport, initialOptions) => { }; function setVolume(volume) { - if (!options.syncVolume) return; - - for (const device of client.devices) { - device.setVolume(volume); + if (options.syncVolume) { + for (const device of client.devices) { + device.setVolume(volume); + } } } -function seekTo(seconds, device = null) { - if (options.syncChromecastTime) return; - if (device) { - device.seekTo(seconds); - } else { - win.webContents.send("log", `Seeking to "${seconds}" seconds`); - for (const device_ of client.devices) { - device_.seekTo(seconds); +function seekTo(seconds) { + if (options.syncSeek) { + for (const device of client.devices) { + device.seekTo(seconds); } } } -async function getTime() { - return win.webContents.executeJavaScript(`document.querySelector("video").currentTime`); -} - function registerDevice(device) { deviceList.push(device.name); let currentStatus; device.on('status', async (status) => { + win.webContents.send("log", status.playerState); currentStatus = status.playerState; - //win.webContents.send("log", JSON.stringify(status, null, "\t")); - if (currentStatus === "PLAYING") { - const currentTime = await getTime(); - const timeDiff = Math.abs(status.currentTime - currentTime); - if (timeDiff > 1) { - if (options.syncChromecastTime) { - seekTo(currentTime + 1.5, device); - win.webContents.send("log", 'options.syncChromecastTime = ' + options.syncChromecastTime + - ` \nTime difference = ${timeDiff}, Setting Chromecast to "${currentTime}" +1.5 seconds`); - } else if (options.syncAppTime) { - win.webContents.send("setPlaybackTime", status.currentTime); - win.webContents.send("log", 'options.syncAppTime = ' + options.syncAppTime + - ` \nTime difference = ${timeDiff}, Setting AppVideo to "${status.currentTime}" seconds`); - } - } + if (options.syncStartTime) { + currentStatus === "PLAYING" ? play() : pause(); } }) @@ -83,15 +71,18 @@ function registerDevice(device) { } if (currentUrl !== songInfo.url) { //new song currentUrl = songInfo.url; - isPaused = songInfo.isPaused; + if (options.syncStartTime) { + isPaused = true; + pause(); + } else { + isPaused = songInfo.isPaused; + } device.play(transformURL(songInfo.url)); } else if (isPaused !== songInfo.isPaused) { //paused status changed isPaused = songInfo.isPaused; - if (isPaused) { - if (currentStatus === "PLAYING") { - device.pause() - } + if (isPaused && currentStatus === "PLAYING") { + device.pause(); } else { device.resume(); } @@ -106,11 +97,7 @@ function transformURL(url) {// will not be needed after https://github.com/alxho function setOption(value, ...keys) { for (const key of keys) { - if (typeof key === "string") { - options[key] = value; - } else if (typeof key.name == "string" && typeof key.value === "boolean") { - options[key.name] = key.value; - } + options[key] = value; } setOptions("chromecast", options); } diff --git a/plugins/chromecast/front.js b/plugins/chromecast/front.js index e48888b4e1..4f63efe022 100644 --- a/plugins/chromecast/front.js +++ b/plugins/chromecast/front.js @@ -12,17 +12,9 @@ function setup(video) { sendVolume(video.volume); - video.addEventListener('volumechange', e => sendVolume(e.target.volume), {passive: true}); + video.addEventListener('volumechange', e => sendVolume( + e.target.muted ? 0 : e.target.volume), + { passive: true }); - video.addEventListener('seeking', e => sendTime(e.target.currentTime), {passive: true}); //or 'seeked' - - ipcRenderer.on("setPlaybackTime", (_e, seconds) => { - const timeDiff = Math.abs(video.currentTime - seconds); - - console.log(`Actual Time difference = ${timeDiff}`); - - video.yns_pause ? video.yns_pause() : video.pause(); - video.currentTime = seconds; - video.play(); - }) + video.addEventListener('seeking', e => sendTime(e.target.currentTime), { passive: true }); } diff --git a/plugins/chromecast/menu.js b/plugins/chromecast/menu.js index 9ae3b875aa..e15d90bff4 100644 --- a/plugins/chromecast/menu.js +++ b/plugins/chromecast/menu.js @@ -3,33 +3,23 @@ const { menuCheck, setOption, refreshChromecast } = require("./back"); module.exports = (_win, options) => { menuCheck(options); return [ - { type: "separator" }, { label: "Sync Volume", type: "checkbox", checked: !!options.syncVolume, click: (item) => setOption(item.checked, "syncVolume") }, - { type: "separator" }, - { - label: "Sync Chromecast time with App", - type: "radio", - checked: !!options.syncChromecastTime, - click: () => - setOption(true, "syncChromecastTime", { name: "syncAppTime", value: false }) - }, { - label: "Sync App time with Chromecast", - type: "radio", - checked: !!options.syncAppTime, - click: () => - setOption(true, "syncAppTime", { name: "syncChromecastTime", value: false }) + label: "Sync Start Time", + type: "checkbox", + checked: !!options.syncStartTime, + click: (item) => setOption(item.checked, "syncStartTime") }, { - label: "Disable time sync", - type: "radio", - checked: !options.syncAppTime && !options.syncChromecastTime, - click: () => setOption(false, "syncAppTime", "syncChromecastTime") + label: "Sync Seek", + type: "checkbox", + checked: !!options.syncSeek, + click: (item) => setOption(item.checked, "syncSeek") }, { type: "separator" }, { diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js index 94f9d94d2b..837653b1d2 100644 --- a/providers/song-controls-front.js +++ b/providers/song-controls-front.js @@ -2,22 +2,42 @@ const { ipcRenderer } = require("electron"); let video = document.querySelector("video"); -function playPause() { - if (!video) { - video = document.querySelector("video"); +module.exports = () => { + ipcRenderer.on("playPause", (_e, toPlay) => playPause(toPlay)); +}; +module.exports.playPause = playPause; + +function playPause(toPlay = undefined) { + if (!checkVideo()) return; + + switch(toPlay) { + case undefined: + video.paused ? play() : pause(); + break; + case true: + play(); + break; + case false: + pause(); } - if (video.paused) { + function play() { video.play(); - } else { + } + + function pause() { video.yns_pause ? video.yns_pause() : video.pause(); } + } -module.exports = () => { - ipcRenderer.on("playPause", playPause); -}; - -module.exports.playPause = playPause; +function checkVideo() { + if (!video) { + video = document.querySelector("video"); + if (!video) { + return false; + } + } return true; +} diff --git a/providers/song-controls.js b/providers/song-controls.js index 5d3ad953d2..52a25c951e 100644 --- a/providers/song-controls.js +++ b/providers/song-controls.js @@ -12,8 +12,7 @@ module.exports = (win) => { // Playback previous: () => pressKey(win, "k"), next: () => pressKey(win, "j"), - playPause: () => win.webContents.send("playPause"), - like: () => pressKey(win, "_"), + playPause: (toPlay = undefined) => win.webContents.send("playPause", toPlay), dislike: () => pressKey(win, "+"), go10sBack: () => pressKey(win, "h"), go10sForward: () => pressKey(win, "l"), From 3d5b51b758c80b1869a2385358b901415e606cf3 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 23 May 2021 18:33:34 +0300 Subject: [PATCH 08/15] lint --- plugins/chromecast/back.js | 17 ++++++----------- providers/front-logger.js | 3 --- 2 files changed, 6 insertions(+), 14 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index 218e168d26..e5065c1a74 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -10,14 +10,11 @@ let deviceList = []; let registerCallback; -let win; - let play, pause; let options; -module.exports = (winImport, initialOptions) => { - win = winImport; +module.exports = (win, initialOptions) => { const { playPause } = getSongControls(win); play = () => playPause(true); pause = () => playPause(false); @@ -56,7 +53,6 @@ function registerDevice(device) { deviceList.push(device.name); let currentStatus; device.on('status', async (status) => { - win.webContents.send("log", status.playerState); currentStatus = status.playerState; if (options.syncStartTime) { currentStatus === "PLAYING" ? play() : pause(); @@ -90,19 +86,18 @@ function registerDevice(device) { }); } -function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 - const videoId = url.match(/http(?:s?):\/\/(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)(&(amp;)?‌​[\w\?‌​=]*)?/); +function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 (chromecastAPI v0.3.5) + const videoId = url.match(/(?:http(?:s?):\/\/)?(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)/); + // videoId[1] should always be valid since regex should always be valid return "https://youtube.com/watch?v=" + (videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"); } -function setOption(value, ...keys) { +module.exports.setOption = (value, ...keys) => { for (const key of keys) { options[key] = value; } setOptions("chromecast", options); -} - -module.exports.setOption = setOption; +}; module.exports.menuCheck = (options_) => { if (!options) options = options_; diff --git a/providers/front-logger.js b/providers/front-logger.js index f435a8c660..99da232916 100644 --- a/providers/front-logger.js +++ b/providers/front-logger.js @@ -10,7 +10,4 @@ module.exports = () => { ipcRenderer.on("log", (_event, log) => { console.log(logToString(log)); }); - ipcRenderer.on("logObject", (_event, logObject) => { - console.log(JSON.parse(logObject)); - }); }; From 48fc2cccd06ad2fc646fc2be11d6e17be1279502 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 23 May 2021 21:31:31 +0300 Subject: [PATCH 09/15] add defaults options to chromecast --- config/defaults.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/config/defaults.js b/config/defaults.js index 12f6a2486b..bc229038b2 100644 --- a/config/defaults.js +++ b/config/defaults.js @@ -63,6 +63,12 @@ const defaultConfig = { volumeDown: "Shift+PageDown" }, savedVolume: undefined //plugin save volume between session here + }, + chromecast: { + enabled: false, + syncVolume: true, + syncStartTime: true, + syncSeek: true } }, }; From 1484dd0cdec9688f76d4be22a490589ff757b45b Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sat, 29 May 2021 02:00:46 +0300 Subject: [PATCH 10/15] update `registerCallback()` in chromecast plugin --- plugins/chromecast/back.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index e5065c1a74..6d7d7646c8 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -1,4 +1,4 @@ -const getSongInfo = require("../../providers/song-info"); +const registerCallback = require("../../providers/song-info"); const getSongControls = require('../../providers/song-controls'); const { ipcMain } = require('electron') @@ -8,8 +8,6 @@ const { setOptions } = require("../../config/plugins"); let client; let deviceList = []; -let registerCallback; - let play, pause; let options; @@ -20,7 +18,6 @@ module.exports = (win, initialOptions) => { pause = () => playPause(false); options = initialOptions; - registerCallback = getSongInfo(win); client = new ChromecastAPI(); From 9d22a2b5988e5c5355600a37989bba0870569c79 Mon Sep 17 00:00:00 2001 From: Araxeus <78568641+Araxeus@users.noreply.github.com> Date: Sun, 30 May 2021 02:38:31 +0300 Subject: [PATCH 11/15] remove redundant passive listener attribute --- plugins/chromecast/front.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/plugins/chromecast/front.js b/plugins/chromecast/front.js index 4f63efe022..e10aef7c01 100644 --- a/plugins/chromecast/front.js +++ b/plugins/chromecast/front.js @@ -12,9 +12,9 @@ function setup(video) { sendVolume(video.volume); - video.addEventListener('volumechange', e => sendVolume( - e.target.muted ? 0 : e.target.volume), - { passive: true }); + video.addEventListener('volumechange', e => + sendVolume(e.target.muted ? 0 : e.target.volume)); - video.addEventListener('seeking', e => sendTime(e.target.currentTime), { passive: true }); + video.addEventListener('seeking', e => + sendTime(e.target.currentTime)); } From 0bdd6fa4920fb41147829cb1ff34eafe9357860f Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 20 Jun 2021 00:45:15 +0300 Subject: [PATCH 12/15] chromecast fixes --- plugins/chromecast/back.js | 10 +++++----- plugins/taskbar-mediacontrol/back.js | 6 +++--- providers/song-controls-front.js | 25 ++++++++++--------------- providers/song-controls.js | 4 +++- 4 files changed, 21 insertions(+), 24 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index 6d7d7646c8..e9c9a42a4e 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -13,9 +13,8 @@ let play, pause; let options; module.exports = (win, initialOptions) => { - const { playPause } = getSongControls(win); - play = () => playPause(true); - pause = () => playPause(false); + const { _play, _pause } = getSongControls(win); + play = _play; pause = _pause; options = initialOptions; @@ -83,9 +82,10 @@ function registerDevice(device) { }); } -function transformURL(url) {// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 (chromecastAPI v0.3.5) +// will not be needed after https://github.com/alxhotel/chromecast-api/pull/69 (chromecastAPI v0.3.5) +function transformURL(url) { const videoId = url.match(/(?:http(?:s?):\/\/)?(?:www\.)?(?:music\.)?youtu(?:be\.com\/watch\?v=|\.be\/)([\w\-\_]*)/); - // videoId[1] should always be valid since regex should always be valid + // videoId[1] should always be valid since regex should always be valid - rickroll video should never happen :) return "https://youtube.com/watch?v=" + (videoId.length > 1 ? videoId[1] : "dQw4w9WgXcQ"); } diff --git a/plugins/taskbar-mediacontrol/back.js b/plugins/taskbar-mediacontrol/back.js index 26a117320b..fabdf0c48b 100644 --- a/plugins/taskbar-mediacontrol/back.js +++ b/plugins/taskbar-mediacontrol/back.js @@ -33,16 +33,16 @@ function setThumbar(win, songInfo) { { tooltip: 'Previous', icon: get('backward.png'), - click() { controls.previous(win.webContents); } + click() { controls.previous(); } }, { tooltip: 'Play/Pause', // Update icon based on play state icon: songInfo.isPaused ? get('play.png') : get('pause.png'), - click() { controls.playPause(win.webContents); } + click() { controls.playPause(); } }, { tooltip: 'Next', icon: get('forward.png'), - click() { controls.next(win.webContents); } + click() { controls.next(); } } ]); } diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js index 837653b1d2..59cd1f320c 100644 --- a/providers/song-controls-front.js +++ b/providers/song-controls-front.js @@ -9,35 +9,30 @@ module.exports.playPause = playPause; function playPause(toPlay = undefined) { if (!checkVideo()) return; - - switch(toPlay) { - case undefined: - video.paused ? play() : pause(); - break; + + switch (toPlay) { case true: - play(); + video.play(); break; case false: pause(); + break; + case undefined: + default: + video.paused ? video.play() : pause(); } - function play() { - video.play(); - } - function pause() { video.yns_pause ? video.yns_pause() : video.pause(); } - } function checkVideo() { if (!video) { video = document.querySelector("video"); - if (!video) { - return false; - } - } return true; + } + + return !!video; } diff --git a/providers/song-controls.js b/providers/song-controls.js index 52a25c951e..0f955c05c0 100644 --- a/providers/song-controls.js +++ b/providers/song-controls.js @@ -12,7 +12,9 @@ module.exports = (win) => { // Playback previous: () => pressKey(win, "k"), next: () => pressKey(win, "j"), - playPause: (toPlay = undefined) => win.webContents.send("playPause", toPlay), + playPause: () => win.webContents.send("playPause"), + play: () => win.webContents.send("playPause", true), + pause: () => win.webContents.send("playPause", false), dislike: () => pressKey(win, "+"), go10sBack: () => pressKey(win, "h"), go10sForward: () => pressKey(win, "l"), From 81c48d41c600b7107a54f50b4864c86989f4c1cd Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 20 Jun 2021 00:49:57 +0300 Subject: [PATCH 13/15] force dns-packet version resolution use "dns-packet": "5.2.4" https://snyk.io/vuln/SNYK-JS-DNSPACKET-1293563 --- package.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 69d79676ec..64a04b2574 100644 --- a/package.json +++ b/package.json @@ -98,7 +98,8 @@ "xo": "^0.38.2" }, "resolutions": { - "yargs-parser": "18.1.3" + "yargs-parser": "18.1.3", + "dns-packet": "5.2.4" }, "xo": { "envs": [ From 8dc1ab09cc814a4619a2080f277bd15b26c547a3 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 20 Jun 2021 00:56:40 +0300 Subject: [PATCH 14/15] Update yarn.lock --- yarn.lock | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/yarn.lock b/yarn.lock index 63a276ac0c..786a44e2e3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3276,13 +3276,12 @@ dmg-license@^1.0.8: smart-buffer "^4.0.2" verror "^1.10.0" -dns-packet@^4.0.0: - version "4.2.0" - resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-4.2.0.tgz#3fd6f5ff5a4ec3194ed0b15312693ffe8776b343" - integrity sha512-bn1AKpfkFbm0MIioOMHZ5qJzl2uypdBwI4nYNsqvhjsegBhcKJUlCrMPWLx6JEezRjxZmxhtIz/FkBEur2l8Cw== +dns-packet@5.2.4, dns-packet@^4.0.0: + version "5.2.4" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.2.4.tgz#e004f409eadfa8ec861964dcb9eb395884fcf67d" + integrity sha512-vgu5Bx5IV8mXmh/9cn1lzn+J7okFlXe1vBRp+kCBJXg1nBED6Z/Q4e+QaDxQRSozMr14p/VQmdXwsf/I2wGjUA== dependencies: ip "^1.1.5" - safe-buffer "^5.1.1" dns-txt@^2.0.2: version "2.0.2" From 207a058f69e33d8c00314b3b6d3e9b4b09329a89 Mon Sep 17 00:00:00 2001 From: Araxeus Date: Sun, 20 Jun 2021 02:09:50 +0300 Subject: [PATCH 15/15] lint --- plugins/chromecast/back.js | 10 +++++----- providers/song-controls-front.js | 3 +-- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/plugins/chromecast/back.js b/plugins/chromecast/back.js index e9c9a42a4e..3e8cc9ac2e 100644 --- a/plugins/chromecast/back.js +++ b/plugins/chromecast/back.js @@ -8,13 +8,13 @@ const { setOptions } = require("../../config/plugins"); let client; let deviceList = []; -let play, pause; +let controls; let options; module.exports = (win, initialOptions) => { - const { _play, _pause } = getSongControls(win); - play = _play; pause = _pause; + const { play, pause } = getSongControls(win); + controls = { play, pause }; options = initialOptions; @@ -51,7 +51,7 @@ function registerDevice(device) { device.on('status', async (status) => { currentStatus = status.playerState; if (options.syncStartTime) { - currentStatus === "PLAYING" ? play() : pause(); + currentStatus === "PLAYING" ? controls.play() : controls.pause(); } }) @@ -65,7 +65,7 @@ function registerDevice(device) { currentUrl = songInfo.url; if (options.syncStartTime) { isPaused = true; - pause(); + controls.pause(); } else { isPaused = songInfo.isPaused; } diff --git a/providers/song-controls-front.js b/providers/song-controls-front.js index 59cd1f320c..01f6563846 100644 --- a/providers/song-controls-front.js +++ b/providers/song-controls-front.js @@ -17,8 +17,7 @@ function playPause(toPlay = undefined) { case false: pause(); break; - case undefined: - default: + default: //usually undefined video.paused ? video.play() : pause(); }