Pull to refresh

Пишем расширение для Chrome «загрузка аудиозаписей с Вконтакте»

JavaScript *HTML *
Recovery mode
В магазине расширений chrome наверняка уже есть загрузчики песен с вконтакте, но мы попробуем написать свой.
Наше расширение будет добавлять ссылку в каждую из песен раздела Мои Аудиозаписи, которая будет скачивать песню.

Выглядеть должно примерно так:
Изначально: Попробуем сделать так:

Давайте начнем.
Вообще, писать расширения не так уж и сложно. Расширение — это всего лишь это файл-описание + html/js/css контент. Наше будет состоять из трех файлов — файла описания (manifest.json), внедряемого js скрипта (vk_inject.js), и внедряемого файла стилей vk_styles.css).

Главный файл в расширении — это, конечно, manifest.json. В нем содержится дескриптор расширения, и ссылки на внедряемые файлы.

mainfest.json
{
  "manifest_version": 2,

  "name": "Загрузчик музыки из vk.com",
  "description": "Позволяет вам загрузить музыку из социальной сети Вконтакте.",
  "version": "1.0",

  "content_scripts": [
    {
      "matches": ["*://vk.com/audios*"],
      "js": ["vk_inject.js"],
      "css": ["vk_styles.css"]
    }
  ]
}

Пока ничего сложного. Кроме описания, здесь содержится тег «content_scripts», который определяет, какие js и css файлы будут внедрены в страницу.
В данном случае, наше расширение будет встраивать файлы vk_inject.js и vk_styles.css в каждую страницу, подходящую по адресу к маскам http://vk.com/audios* или https://vk.com/audios*. Это как раз те адреса, где содержатся наши (или других пользователей) аудиозаписи на сайте Вконтакте.

Файл стилей (vk_styles.css) будет очень простой. Мы всего лишь определим css класс для внедряемой ссылки.
Обязательно нужно следить, чтобы класс не пересекался со стилями исходной страницы.
Конечно, мы можем обойтись и без внедряемого css файла, и просто задать все стили в коде при создании элемента ссылки, но я
хочу показать вам возможность внедрения стилей. Вы также можете переопределить стили для своих ссылок.

vk_styles.css
.downloadLink {
	float: right;
}

Практически все действия будут происходить во внедряемом коде vk_inject.js.
Итак, что будем делать:
Страница vk.com/audios* содержит два списка песен — 1) изначальные аудиозаписи на вашей странице — элемент <div id=«initial_list»> и 2) список поиска — <div id=«search_list»>. В списке поиска будут отображаться найденные композиции, если вы перейдете в режим поиска. Оба эти элемента изначально присутствуют на странице аудиозаписей, так что мы можем поменять каждый из них.
Проблема в том, в каждом их этих списков могут добавляться или удаляться записи. Нам нужно следить за этим.
Внедряемый скрипт исполняется в отдельной виртуальной машине, и не может взаимодействовать со скриптом на станице. Поэтому мы не можем переопределять исходные функции или как-то иначе перехватывать js код на исходной странице.
Но, к счастью, оба эти скрипта разделяют DOM-дерево, так что мы будем следить за обновлениями DOM элементов списка с помощью MutationObserver.

vk_insert.js
(function (){	// обернем все в безымянную функцию, чтобы не создавать глобальных переменных - просто хороший тон
	var observer = new MutationObserver(listModified);	// создаем объект observer -> вызывает listModified при каждом изменении DOM

	var initialList = document.getElementById('initial_list');	// список изначальной музыки на нашей странице
	if (initialList)
	{
		// список уже был заполнен при подключении расширения - добавляем ссылку "Скачать" для каждой записи в нем
		var rows = initialList.children;
		for (var i = 0; i < rows.length; i++)
		{
			addDownloadLink(rows[i]);	// добавляем ссылку
		}

		observer.observe(initialList, {childList: true});	// следим за изменениями в изначальном списке тоже
	}

	// список аудиозаписей при поиске
	var searchList = document.getElementById('search_list');
	if (searchList)
	{
		// search_list изначально всегда пустой, нам нужно только отрабатывать добавление песен в него
		observer.observe(searchList, {childList: true});	// следим за ним
	}

	// вызывается, когда в список песен добавляются (или удаляются) элементы
	function listModified(mutations)
	{
		for (var i = 0; i < mutations.length; i++)
		{
			var mut = mutations[i];
			if (mut.type != 'childList')
			{
				return;
			}
			// пройдемся по добавленным песням
			for (var j = 0; j < mut.addedNodes.length; j++)
			{
				addDownloadLink(mut.addedNodes[j]);
			}
			// удаленные записи - mut.removedNodes игнорируем
		}
	}

	// функция добавляет ссылку "Скачать" к разметке песни
	function addDownloadLink(row)
	{
		var titleNode = row.querySelector('div.title_wrap');	// Исполнитель песни + название
		if (!titleNode)	// если ничего не работает (может, разметка была изменена?)- выйдем
		{
			return;
		}
		var input = row.querySelector('div.play_btn > input');	// найдем input, в котором хранится url
		if (!input)
		{
			return;
		}
		var ref = input.getAttribute('value');	// сам URL файла
		ref = ref.substr(0, ref.indexOf('?'));	// обрежем все после '?', чтобы оставить только ссылку на mp3

		var link = document.createElement('a');
		link.className = 'downloadLink';	// добавим css класс 'downloadLink' для нашей ссылки
		link.textContent = "Скачать";
		link.setAttribute('download', titleNode.textContent + '.mp3');	// имя файла для загрузки
		link.setAttribute('href', ref);
		link.addEventListener('click', function(event){	// при клике на нашу ссылку, отменим запуск проигрывателя
			event.stopPropagation();
		});
		titleNode.appendChild(link);
	}
})();

Устанавливаем расширение.


Итак, все три файла готовы. Вы можете скопировать их из поста или загрузить архивом.
В браузере войдите на страницу настроек, выберите вкладку Расширения (или просто введите «chrome://extensions» в адресную строку). Обязательно нужно включить Режим разработчика. Потом нажмите Загрузить распакованное расширение....


Выберите папку, куда вы сохранили эти три файла. В моем случае это D:\Droopy\work\habr\plugin.
Расширение должно появиться в списке. Включите его.



Давайте проверим, как оно работает. Для этого зайдем на vk.com, и выберем раздел Мои аудиозаписи.

Так, ничего не работает…

Почему? Потому что Вконтакте при переходе со страницы на страницу самостоятельно обновляет html и программно изменяет url в адресной строке. Это не является классическим браузерным переходом со страницы на страницу.
Поэтому браузер и не запустил наше расширение, хотя адрес страницы и стал «https://vk.com/audios*».
Для запуска нашего скрипта, нам нужно явно обновить страницу аудиозаписей.
Обновляем.



Ура, ссылки «Скачать» появились!
Причем, если мы начнем поиск аудиозаписей на этой же странице, то для каждой найденной песни автоматически будет добавляться ссылка на скачивание. Расширение работает.

Но есть одна сложность с названием скачиваемой песни. Когда вы нажимаете на ссылку «Скачать», в диалоге сохранения файла вам будет предлагаться имя файла из набора цифр. Нам же нужно нормальное название песни.
Дело в том, что вконтакте хранит аудиозаписи на отдельном домене, и хром для этого случая будет использовать имя файла на сервере вместо предложенного в ссылке.
В багтрекере хрома сказано, что в этом случае нужно выбирать пункт Сохранить ссылку как... в контекстном меню. Тогда нам будет предложено нормальное имя файла.



Наше расширение, конечно, не всегда работает на всех страницах вконтакте, но для скачивания любимых песен из своих аудиозаписей вполне подходит.
Tags:
Hubs:
Total votes 34: ↑10 and ↓24 -14
Views 15K
Comments Comments 8