Привет, Habr!
Меня зовут Игорь, я разработчик на удалёнке *хлоп-хлоп. У меня, как и положено серьёзному разработчику, куча входящих сообщений и пиликающих мессенджеров.
Сказать, что заниматься творческой деятельностью в виде написания кода в таких условиях сложно - ничего не сказать.
Сотни уловок и ухищрений, секретных техник концентрации и полноразмерные наушники с активным шумоподавлением призваны помогать мне выходить в астрал входить в состояния потока и укладываться в дедлайны.
Идея этой статьи родилась из коментария одного комментария @Xregn к статье Как меньше отвлекаться и прокрастинировать..., где ребята обсуждали идею Pomodoro-таймера для spotify.
Идея проста: заводишь таймер и влючаешь музыку, по истечении времени музыка должна встать на стоп. Супер, если можно слушать музыку с ноута, чтобы не переключать наушиники с телефона на ноут и обратно, когда бегаешь по созвонам.
Первая версия кода родилась моментально, ведь есть кнопка control-button-playpause, которая поставит музыку на паузу.
setTimeout(() => { document.querySelector("[data-testid='control-button-playpause']").click()}, 5000)
Код работает, ставя музыку на паузу через 5 секунд. Что именно тут происходит: setTimeout()— принимает в себя функцию и промежуток времени в милисекундах, после которого надо вызвать функцию, что бы она сделала то, что вам надо.
Функция и таймер разделены запятой: () => {document.querySelector("[data-testid='control-button-playpause']").click()} — собственно, сама функция, где между фигурными скобками мы находим кнопку по дата-атрибутуdocument.querySelector("[data-testid=play-button]") , и кликаем на неё .click()
Вместо 5000 мы напишем 1000 60 25 , что будет равно 25 минутам. Да, мы превратили милисикунды в минуты, и теперь просто умножаем эти 60 000 милисикунд на нужное количество минут. Справедливости ради 60_000 * 25 тоже прекрасно работает.
Что не так с этим таймером, кроме того что он работает? Да собственно всё:
вам нужно его где-то хранить или набирать каждый раз по памяти;
его надо выполнять в консоли браузера;
если кнопки не будет, то всё сломается;
он работает только со spotify.
Давайте быстренько решим эти проблемы, погнали!
Первые два пункта можно решить через создание закладки в браузере.
Как сделать закладку
Правый клик мыши по панели закладок, затем пишем название закладки и вставнаш код.
javascript:setTimeout(() => { document.querySelector("[data-testid='control-button-playpause']") .click() }, 5000)
По сути, это обычная закладка, где вместо адреса сайта мы пишем javascript: и наш код.
Отлично, всё работает, идем дальше!
А кнопки-то и нет!
По-хорошему, перед установкой таймера нам нужно проверить, что кнопка вообще есть. Да и в принципе узнать, что он запустился тоже было бы неплохо. Поэтому добавляем простую проверку:
(() => { const stopButton = document.querySelector("[data-testid='control-button-playpause']"); if (!stopButton) { alert("А кнопки-то и нет 😭"); return; } setTimeout(() => {stopButton.click()}, 5000); alert("Таймер запущен 🍅⏰") })()
Иногда бывает ситуация, что ты запустил таймер, начал работать и тебе надо прерваться.
Можно, конечно, остановить таймер, просто перезагрузив страницу. Но было бы хорошо иметь возможность его останавливать как-то проще (и запускать снова с нуля).
javascript:(() => { const time = 1000 * 60 * 25; const stopButton = document.querySelector("[data-testid='control-button-playpause']"); const timerID = document.cookie.split('; ').find(row => row.startsWith('myPomodoroMusic='))?.split('=')[1]; if (!stopButton) { alert("А кнопки-то и нет 😭"); return; } if (timerID) { clearTimeout(Number(timerID)); alert(`Таймер остановлен`); document.cookie = `myPomodoroMusic=${timerID}; expires=${ new Date().toUTCString() }; path=/;`; return; } window.myPomodoroMusic = setTimeout(() => {stopButton.click()}, time); document.cookie = `myPomodoroMusic=${window.myPomodoroMusic}; expires=${ new Date(Date.now() + time).toUTCString() }; path=/;`; alert(`Запущен таймер на ${time / 1000 / 60} мин`); })()
Не Spotify единым...
Окей, вроде уже норм. Правда, я сам пользуюсь Яндекс.Музыкой, а моя жена Звуком. Давайте допишем скрипт, чтобы он подходил под наиболее частые кейсы:
spotify
Яндекс.Музыка
Звук
ВК музыка
и куда же мы без youtube
Не забудьте написать в комментариях, если забыл что-то мега-популярное 😁
У вк и spotify в кнопку прописан testid, тут всё просто. У ребят из Яндекса есть aria-label, а у YouTube aria-keyshortcuts.
Самый сложный селектор оказался у Звука: там ни testid для удобства тестирования, ни aria labels для доступности. Ребят, если вы это читаете, прокиньте в свой сервис хотя бы атрибуты для читалок, позаботьтесь о слабовидящих.
Итог
В общем, вспомнив css-селекторы, я победил: теперь есть код под все популярные платформы, где можно слушать музыку.
Вот так он выглядит для таймера на 25 минут для закладки:
javascript:(() => { const time = 1000 * 60 * 25; const getPauseButton = () => { const url = window.location.href; const domain = new URL(url).hostname; switch (domain) { case "open.spotify.com": document.querySelector("[data-testid='control-button-playpause']"); case "music.yandex.ru": return document.querySelector("[aria-label='Пауза']"); case "zvuk.com": return document.querySelector("[id='theme-provider'] > div > div > div:nth-of-type(2) > div > div > div:nth-of-type(2) > div > button:nth-of-type(2)"); case "vk.com": return document.querySelector("[data-testid='audio-player-controls-state-button']"); case "www.youtube.com": return document.querySelector("[aria-keyshortcuts='k']"); default: return null; } } const stopButton = getPauseButton(); const timerID = document.cookie.split('; ').find(row => row.startsWith('myPomodoroMusic='))?.split('=')[1]; if (!stopButton) { alert("А кнопки-то и нет 😭"); return; } if (timerID) { clearTimeout(Number(timerID)); alert(`Таймер остановлен`); document.cookie = `myPomodoroMusic=${timerID}; expires=${ new Date().toUTCString() }; path=/;`; return; } window.myPomodoroMusic = setTimeout(() => {stopButton.click()}, time); document.cookie = `myPomodoroMusic=${window.myPomodoroMusic}; expires=${ new Date(Date.now() + time).toUTCString() }; path=/;`; alert(`Запущен таймер на ${time / 1000 / 60} мин`); })()
Данный скрипт написан по приколу за несколько минут. Он работает, записывая id таймера в cookies, и использует адрес сайта на которым вы находитесь, но никому ничего не передает.
