diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index a577a8c..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "web-api-auth-examples"] - path = web-api-auth-examples - url = https://github.com/zhenyu0519/web-api-auth-examples.git diff --git a/README.md b/README.md index 6f5915e..1795720 100644 --- a/README.md +++ b/README.md @@ -2,69 +2,11 @@

Spotbash

Spotify Control API ~ Written in bash, using curl.

*** -## Setup -1. Go to the [developer dashboard](https://developer.spotify.com/dashboard/applications) and create a new app. -2. Remember the `Client ID` and the `Client Secret`\ -2a. Open settings and add `http://localhost:5000/` to the redircet_uri whitelist -> You can optionally edit `app.patch` to change the scopes, note that doing this can break somethings. -> > You shouldn't mess with the patches unless you understand JS (`app.patch`) and HTML (`index.patch`) -3. `./setup.sh` ---- - -# Musl -Those on musl won't be able to run `./setup` as it requires nodejs to be installed, which isn't yet compatible with musl libc...\ -But Spotbash can still be used from musl, the user just has to create `$HOME/.cache/spotbash/authkeys`\ -``` -$ cat authkeys -REKEY=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -CLID=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -CLSEC=XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX -``` -The client ID and secret can be found in set 1 of [Setup](#Setup)\ -While REKEY is a bit harder to get... And requires a browser and server to make a request to Spotifys API\ -Spotify then returns the Auth key, and a Refresh key, the Refresh key is used to request new Auth keys since the expire 1 hour after being created\ -[REKEY](https://www.thatgeekyweeb.is-dummy-thi.cc/REKEY/), can be used to get the `REKEY` -## Usage -1. `./spotbash help` -```text -Spotbash: Spotify Control API ~ Written in bash ~ By ThatGeekyWeeb (Mia) -Usage: spotbash: -[auth|device|search_*|play_track|*_volume|get_info|pre|trans|skip|pause|resume|loop|repeat|state|set|play*|*left|shuffle*] -*** -auth: Print $AUTHKEY and exit -device: Print first device ID and exit -devices: List ALL devices and exit -search_play: Search for "arg2" and play -search_track: Search for "arg2" and output URI & Artist & name | "arg2" is interpreted as a track -search_album: Seach for "arg2" and output URI, Artist, & name | "arg2" is interpreted as a album -play_track: Play URI -get_volume: Output player volume and exit -set_volume: Set player volume to "arg2" and exit -get_info: Get debugging info about currently playing device -pre: Change playback to previous song -trans: Transfer playback to "arg2" | arg2 must be DeviceID | Uses device func if "arg2" is empty -skip: Change playback to next song -pause: Pause playback -resume: Resume playback -loop: Loop track -repeat: Repeat current album/playlist -state: Output playback status and exit -repeat_off: Disable loop/repeat -repeat_state: Output playback repeat status and exit -set: Move playback to "arg2" | "arg2" must be a device ID -playlists: Output list of users playlists and exit -play: Play "arg2" | "arg2" must be Album or Playlist URI -playing: Print Song name followed by artist and exit -left: Print time left in MS (exact) and exit -minleft: Print time left in Mins (approximate) and exit -shuffle: Enable/Disable Shuffle | Set to "arg2" if specified -shuffle_state: Print state of shuffle and exit -*** -"arg2" Usage: - <"arg2"> -IE: search_play "Man of The Year" -NOTE: Use qoutes! -*** -``` -*** -potbash is a "Control API" which means it only controls the Spotify playback of devices. +## Installation +1. Head [here (`https://developer.spotify.com/dashboard/applications`)](https://developer.spotify.com/dashboard/applications) + - Create or use and existing app + - Remember it's Client ID and Client Secret + - Edit it's settings to add `http://www.thatgeekyweeb.is-dummy-thi.cc/REKEY/callback/` and `https://www.thatgeekyweeb.is-dummy-thi.cc/REKEY/callback/` as callback URI's (`HTTP` & `HTTPS`) +2. Head to [REKEY (`https://www.thatgeekyweeb.is-dummy-thi.cc/REKEY/`)](https://www.thatgeekyweeb.is-dummy-thi.cc/REKEY/) + - Press start and input the requested data +3. Click "`Click to save AUTHKEYS`" and save to `~/.cache/spotbash/authkeys` diff --git a/app.patch b/app.patch deleted file mode 100644 index e8bca76..0000000 --- a/app.patch +++ /dev/null @@ -1,64 +0,0 @@ -diff --git a/authorization_code/app.js b/authorization_code/app.js -index 8a1634a..f6d88b3 100644 ---- a/authorization_code/app.js -+++ b/authorization_code/app.js -@@ -9,13 +9,14 @@ - - const express = require("express"); // Express web server framework - const axios = require("axios"); --const cors = require("cors"); - const querystring = require("querystring"); - const cookieParser = require("cookie-parser"); -+/// CORS breaks, like everything I try to do browser side -+/// So, no more CORS + It doesn't matter, since this is a opensource project, and it's up to the user to protect their client_secret - --const client_id = "CLIENT_ID"; // Your client id --const client_secret = "CLIENT_SECRET"; // Your secret --const redirect_uri = "REDIRECT_URI"; // Your redirect uri -+const client_id = 'id'; // Your client id -+const client_secret = 'sec'; // Your secret -+const redirect_uri = 'http://localhost:5000/callback'; // Your redirect uri - - /** - * Generates a random string containing numbers and letters -@@ -39,15 +40,15 @@ const app = express(); - - app - .use(express.static(__dirname + "/public")) -- .use(cors()) - .use(cookieParser()); -+// Again, no more CORS - - app.get("/login", function(req, res) { - let state = generateRandomString(16); - res.cookie(stateKey, state); - - // your application requests authorization -- let scope = "user-read-private user-read-email"; -+ let scope = 'user-read-private user-read-email user-library-read playlist-modify-private user-read-currently-playing user-modify-playback-state playlist-read-collaborative user-read-playback-state streaming playlist-read-private'; - res.redirect( - "https://accounts.spotify.com/authorize?" + - querystring.stringify({ -@@ -99,12 +100,14 @@ app.get("/callback", function(req, res) { - res.redirect( - "/#" + querystring.stringify({ access_token, refresh_token }) - ); -+ console.log('REKEY=' + refresh_token); - }) - .catch(e => { - res.redirect( - "/#" + querystring.stringify({ error: e.response.data }) - ); - }); -+ // I removed the function from here, as it has 0 effect on the Playback SDK, and is 100% useless - }) - .catch(e => console.error(e.response.data)); - } -@@ -137,6 +140,4 @@ app.get("/refresh_token", function(req, res) { - console.error(e.response.data); - }); - }); -- --console.log("Listening on 8888"); --app.listen(8888); -+app.listen(5000); diff --git a/index.patch b/index.patch deleted file mode 100644 index ec84891..0000000 --- a/index.patch +++ /dev/null @@ -1,191 +0,0 @@ -diff --git a/authorization_code/public/index.html b/authorization_code/public/index.html -index 9c57f1c..ebb4fa9 100644 ---- a/authorization_code/public/index.html -+++ b/authorization_code/public/index.html -@@ -1,8 +1,9 @@ - - - -- Example of the Authorization Code flow with Spotify -+ Spotbash Playback SDK - -+ - - - - -
-
--

This is an example of the Authorization Code flow

- Log in with Spotify -
-
-@@ -46,6 +49,9 @@ -
Link
{{href}}
-
Profile Image
{{images.0.url}}
-
Country
{{country}}
-+
Client ID
-+
Client Secret
-+
Device ID
- -
-
-@@ -61,7 +67,13 @@ - - - -- -+ -+ -+ window.onSpotifyWebPlaybackSDKReady = () => { -+ const player = new Spotify.Player({ -+ name: 'Web Playback SDK Quick Start Player', -+ getOAuthToken: cb => { cb(access_token); } -+ }); -+ -+ // Error handling -+ player.addListener('initialization_error', ({ message }) => { console.error(message); }); -+ player.addListener('authentication_error', ({ message }) => { console.error(message); }); -+ player.addListener('account_error', ({ message }) => { console.error(message); }); -+ player.addListener('playback_error', ({ message }) => { console.error(message); }); -+ -+ // Ready -+ player.addListener('ready', ({ device_id }) => { -+ console.log('Ready with Device ID', device_id); -+ document.getElementById('DEVID').innerHTML = device_id; -+ document.getElementById('CLID').innerHTML = client_id; -+ document.getElementById('sec').innerHTML = client_secret; -+ }); -+ -+ // Not Ready -+ player.addListener('not_ready', ({ device_id }) => { -+ console.log('Device ID has gone offline', device_id); -+ }); -+ -+player.addListener("player_state_changed", (state) => { -+console.log(state); -+if ( -+ state && state.track_window.previous_tracks.find(x => x.id === state.track_window.current_track.id) && !state.paused && state.paused -+ ) { -+ console.log('Track ended'); -+ setTrackEnd(true); -+ } -+state = state; -+}); -+ -+console.log('Is ' + client_id + ' the client_id?' + '\n Is ' + client_secret + ' the client_secret?'); -+console.log('Our refresh_token is ' + refresh_token); -+ -+function startTimer(duration, display) { -+ var timer = duration, minutes, seconds; -+ setInterval(function () { -+ minutes = parseInt(timer / 60, 10); -+ seconds = parseInt(timer % 60, 10); -+ -+ minutes = minutes < 10 ? "0" + minutes : minutes; -+ seconds = seconds < 10 ? "0" + seconds : seconds; -+ -+ display.textContent = minutes + ":" + seconds; -+ -+ if (--timer < 0) { -+ timer = duration; -+ } -+ }, 1000); -+} -+ -+window.onload = function () { -+ var fiveMinutes = 60 * 5, -+ display = document.querySelector('#time'); -+ startTimer(fiveMinutes, display); -+}; -+function refresh() { -+$.ajax({ -+ url: '/refresh_token', -+ data: { -+ 'refresh_token': params.refresh_token -+ } -+ }).done(function(data) { -+ var access_token = data.access_token; -+ console.log('AUTHKEY = ' + access_token); -+ oauthPlaceholder.innerHTML = oauthTemplate({ -+ access_token: access_token, -+ refresh_token: params.refresh_token -+ }); -+ }); -+if (typeof authkey === "function") { -+ authkey();} -+} -+ setInterval(refresh(), 1000 * 58 * 58); -+ player.connect(); -+ }; -+})(); -+ - - -- diff --git a/setup.sh b/setup.sh deleted file mode 100755 index b7e0ba9..0000000 --- a/setup.sh +++ /dev/null @@ -1,99 +0,0 @@ -#!/usr/bin/env bash -IFS="" -reuri="http://localhost:5000/callback" # Callback uri -echo "Notice: THIS REQUIRES NODE TO BE INSTALLED! ~ Unless 'authkeys' is present within the folder and contains the correct data!" -pkill node &>/dev/null -if [ ! -f ./authkeys ];then # This allows one to avoid the nodeJS setup by just having a autkeys file - if [ ! -d ./web-api-auth-examples ]; then - if [ -f $(which git) ]; then - git submodule update --init - git clone git://github.com/zhenyu0519/web-api-auth-examples.git &>/dev/null - elif [ -f $(which curl) ] && [ -f $(which tar) ]; then - curl -#L "http://github.com/zhenyu0519/web-api-auth-examples/archive/master.tar.gz" | tar xfz - && mv ./web-api-auth-examples-master/ ./web-api-auth-examples - else - echo "Couldn't find a way to clone github/zhenyu0519/web-api-auth-examples/" - echo "Supported ways are:" - printf 'Tar & cURL\nGit Clone\n' - echo "Please download and safe github/zhenyu0519/web-api-auth-examples/ to ./web-api-auth-examples" - exit 1 - fi - fi -fi -# Ik Ik https is better, but some devices have issues with ssl, (as does mine), thus I am trying to avoid it -## - if [ ! -f ./authkeys ]; then - cd ./web-api-auth-examples/authorization_code - cp ../../app.patch ./ - patch -Np0 ./app.js < ./app.patch - cd ./public - cp ../../../index.patch ./ - patch -Np0 ./index.html < ./index.patch - cd ../../../ - cp ./web-api-auth-examples/authorization_code/* -r ./ - cp ./web-api-auth-examples/authorization_code/public -r ./ - fi -## -if [ ! -f ./authkeys ]; then - if [ ! -f ./clients ]; then - echo -n 'Client ID =' - read CLID - echo -n 'Client Secret =' - read CLSEC - else - source ./clients - fi - sed -i "s/'id';/'${CLID}';/g" ./app.js - sed -i "s/'sec';/'${CLSEC}';/g" ./app.js -fi -if [ ! -f ./authkeys ] && [ ! -f "$(which npm 2/dev/null)" ]; then - echo "npm is required!" - exit 1 -elif [ ! -d ./node_modules/fs ]; then - [ -f "$(which npm 2>/dev/null)" ] && npm install --save fs -fi -if [ ! -f ./authkeys ] && [ ! -d ./node_modules/http ]; then - [ -f "$(which npm 2>/dev/null)" ] && npm install --save http -fi - -if [ -d ./node_modules/ ] && [ $(ls ./node_modules/ | wc -l) -lt 54 ] || [ -d ./node_modules/ ] && [ $(ls ./node_modules | wc -l ) != 54 ] ; then -# Might be POSIX compatible now... IDK - rm ./node_modules -rf - cd ./web-api-auth-examples/ - echo "Re-Installing auth examples" - npm install &>/dev/null - mv ./node_modules ../ - cd ../ -elif [ ! -f ./authkeys ] && [ ! -d ./node_modules/ ]; then - cd ./web-api-auth-examples/ - echo "Installing auth examples" - npm install &>/dev/null - mv ./node_modules ../ - cd ../ -fi -[ -d ./web-api-auth-examples ] && rm ./web-api-auth-examples/ -rf -if [ ! -f ./authkeys ]; then -cat << EOF > ./public/consts.js - const client_id = "${CLID}"; - const client_secret = "${CLSEC}"; - console.log("client_id is: " + client_id + "\n client_secret is: " + client_secret); -EOF - echo "Please open 'localhost:5000' in your browser" - [ -f $(node) ] && node ./app.js > ./authkeys & disown - until [ -f ./authkeys ] && [ $(cat ./authkeys) != "" ]; do - sleep 1 - done - echo $(cat ./authkeys | sed -z 's/%\n/REKEY=/g') > ./authkeys - echo "Authkeys were written to ./authkeys" - sed -i "s/client_id = '.*'/client_id = 'id'/g" ./app.js - sed -i "s/client_secret = '.*'/client_secret = 'sec'/g" ./app.js - printf 'CLID=%b\nCLSEC=%b' "${CLID}" "${CLSEC}" > ./clients - echo "ID and Secrets have been written to ./clients" - mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache/}//spotbash - cat ./clients >> ./authkeys - cp ./authkeys ${XDG_CACHE_HOME:-$HOME/.cache/}//spotbash -fi -if [ -f ./authkeys ] && [ ! -f ${XDG_CACHE_HOME:-$HOME/.cache/}//spotbash/authkeys ]; then - echo "Creating and copying 'authkeys' to ${XDG_CACHE_HOME:-$HOME/.cache/}/spotbash/" - mkdir -p ${XDG_CACHE_HOME:-$HOME/.cache/}//spotbash - cp ./authkeys ${XDG_CACHE_HOME:-$HOME/.cache/}//spotbash/ -fi