Skip to content

Instantly share code, notes, and snippets.

@Ratsuky
Last active March 26, 2021 11:33
Show Gist options
  • Select an option

  • Save Ratsuky/3f98694ed9baab5f707cd57003c72519 to your computer and use it in GitHub Desktop.

Select an option

Save Ratsuky/3f98694ed9baab5f707cd57003c72519 to your computer and use it in GitHub Desktop.
Simple script to add key-bindings on spotify
// ==UserScript==
// @name Spotify Keybinding
// @namespace http://tampermonkey.net/
// @version 0.1
// @description try to take over the world!
// @author You
// @match https://open.spotify.com/*
// @grant none
// @require http://code.jquery.com/jquery-3.4.1.min.js
// ==/UserScript==
/*
||============================================||
||integrates changes to match ui modifications||
||============================================||
adjusts height of playlist to match the height
increase introduced be the acompaniing stylus style
||============================================||
|| Adds ability to use keybindings ||
||============================================||
[control] + [alt] + [f]
-- like the currently playing song
||============================================||
[control] + [alt] + [d]
-- toggle repeat
||============================================||
[control] + [alt] + [w] - Previous
[control] + [alt] + [s] - Next
-- vertically placed keys for the prev/next bindings
||============================================||
[control] + [alt] + [q] - Go to current playlist
||============================================||
||============================================||
|| WIP features ||
||============================================||
[control] + [alt] + [a] - scroll current song into view
// [ control ] + [ alt ] + [ home ] -- set player to start of song
*/
(function () {
'use strict';
let nowPlayingClassName = 'now-playing-tracklist-row'
let playlistRows = $('div[data-testid="tracklist-row"]');
let buffer = [];
let bindings = [
{binding: ["control", "alt", "q"], action: kbd_viewCrtPlaylist},
{binding: ["control", "alt", "a"], action: kbd_viewCrtPlaying},
{binding: ["control", "alt", "f"], action: kbd_likeCrtPlaying},
{binding: ["control", "alt", "d"], action: kbd_repeatToggle},
{binding: ["control", "alt", "w"], action: kbd_previousSong},
{binding: ["control", "alt", "s"], action: kbd_nextSong},
{binding: ["control", "alt", "home"], action: kbd_startOfSong},
];
Array.prototype.last = function () {
return this[this.length - 1];
}
function arraysMatch(arr1, arr2) {
if (arr1.length !== arr2.length) {
return false;
}
for (let i = 0; i < arr1.length; i++) {
if (arr1[i] !== arr2[i]) return false;
}
return true;
}
function enforceAdjustedPlaylistHeight() {
let contentBoxes = $('.contentSpacing > div[role="grid"]');
$.each(contentBoxes, function (k, contentBox) {
let tracklistRows = $(contentBox).find('[data-testid="tracklist-row"]');
let rowsCount = tracklistRows.length;
let tracklistRowsBox = $(tracklistRows[0]).parent().parent().parent();
let hasCurrentlyPLaying = tracklistRowsBox.find('.' + nowPlayingClassName);
let rowHeight = 65;
let playingRowHeight = 85;
let finalHeight = rowHeight * rowsCount;
if (hasCurrentlyPLaying) {
finalHeight = (rowHeight * (rowsCount - 1)) + playingRowHeight;
}
tracklistRowsBox.css('height', finalHeight);
});
}
function highlightCurrentlyPLaying() {
playlistRows = $('div[data-testid="tracklist-row"]');
playlistRows.each(function (k, v) {
let hasPauseBtn = $(v).find('button[aria-label="Pause"]');
if (hasPauseBtn.length === 1) {
$(v).addClass(nowPlayingClassName)
} else {
if ($(v).hasClass(nowPlayingClassName)) {
$(v).removeClass(nowPlayingClassName);
}
}
});
}
function __triggerPlayBtn() {
$('.Root__now-playing-bar button[data-testid="control-button-play"]').trigger('click');
}
function __jumpToPlaylist() {
$('.Root__now-playing-bar img[data-testid="cover-art-image"]').trigger('click');
}
function __changeSong(direction) {
playlistRows = $('div[data-testid="tracklist-row"]');
playlistRows.each(function (k, v) {
let hasPauseBtn = $(v).find('button[aria-label="Pause"]');
if (hasPauseBtn.length == 1) {
let index = k;
if (direction == 'prev') {
index -= 1;
} else if (direction == 'next') {
index += 1;
}
$(playlistRows[index]).find('button[aria-label^="Play"]').trigger('click');
}
}).bind(direction);
highlightCurrentlyPLaying();
}
function kbd_nextSong() {
__jumpToPlaylist();
__triggerPlayBtn();
setTimeout(function () {__changeSong('next');}, 2000);
}
function kbd_previousSong() {
__jumpToPlaylist();
__triggerPlayBtn();
setTimeout(function () {__changeSong('prev');}, 2000);
}
function kbd_viewCrtPlaylist() {
__jumpToPlaylist();
}
async function kbd_viewCrtPlaying() {
await __jumpToPlaylist();
window.addEventListener()
playlistRows = $('div[data-testid="tracklist-row"]');
var currentlyPlayingKey = 0;
var offset = {};
playlistRows.each(function (k, v) {
var hasPauseBtn = $(v).find('button[aria-label="Pause"]');
if (hasPauseBtn.length == 1) {
currentlyPlayingKey = k;
}
});
// console.log('currentlyPlayingKey', currentlyPlayingKey);
offset = $(playlistRows[currentlyPlayingKey]).offset();
// console.log(offset);
$('html, body').animate({scrollTop: offset.top, scrollLeft: offset.left});
}
function kbd_likeCrtPlaying() {
$('.Root__now-playing-bar').find('.control-button.control-button-heart > button').trigger('click');
}
function kbd_repeatToggle() {
let repeatListBtn = $('.Root__now-playing-bar button[data-testid="control-button-repeat"]');
if (repeatListBtn.length > 0) {
repeatListBtn.trigger('click');
return;
}
}
// attempt to go to start of song
function kbd_startOfSong() {
var progressBarBg = $('.Root__now-playing-bar .playback-bar .progress-bar__bg');
var progressBarBtn = $('.Root__now-playing-bar .playback-bar .progress-bar__slider');
progressBarBtn.css('left', '0%');
}
// register handling for keybindings
document.addEventListener('keydown', event => {
let key = event.key.toLowerCase();
if (key == 'control') {
buffer = [];
}
if (buffer.last() != key) {
buffer.push(key);
}
bindings.filter(function (item) {
if (arraysMatch(item.binding, buffer)) {
item.action();
}
});
});
// Interact with navigation somehow
window.addEventListener('loadstart', function (event) {
console.log('loadstart event');
console.log(event);
});
window.addEventListener('loadstop', function (event) {
console.log('loadstop event');
console.log(event);
});
// register interval handler for tracklist highliting
setInterval(highlightCurrentlyPLaying, '1s');
setInterval(enforceAdjustedPlaylistHeight, '3s');
})();
@Ratsuky
Copy link
Author

Ratsuky commented Nov 3, 2020

TODO :: update next & prev to navigate to current playlist, hit play on next song then hit back on the nav to return the user to where he was watching

@Ratsuky
Copy link
Author

Ratsuky commented Nov 3, 2020

TODO :: [ control ] + [ alt ] + [ a ] -- scroll curently playing song into view ( in case not on playing playlist jump to it )

@Ratsuky
Copy link
Author

Ratsuky commented Feb 17, 2021

Small patch to __jumpToPlaylist() due to failing execution

@Ratsuky
Copy link
Author

Ratsuky commented Mar 26, 2021

Noticed disfunction and fixed a number of the key bindings to reflect said changes
Changed timeout of song switcher in order to make it able to switch songs when away from the currently playing playlist

  • unintended behavior is great delay when used whilst the playlist is active

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment