Привет, 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, и использует адрес сайта на которым вы находитесь, но никому ничего не передает.

Только зарегистрированные пользователи могут участвовать в опросе. Войдите, пожалуйста.
Запилить расширение для браузера?
33.33%И так сойдет1
66.67%Пили2
Проголосовали 3 пользователя. Воздержавшихся нет.