├── README.md ├── bonus ├── remove-all-audios.js └── remove-all-videos.js └── chrome-snippet.js /README.md: -------------------------------------------------------------------------------- 1 | # Как перенести музыку из Вконтакте (ВК) в Яндекс Музыку 2 | 3 | Экспорт своего плейлиста из ВК в текстовый файл и импорт в яндекс музыку. 4 | Скрипт может сработать и не в своих плейлистах. 5 | 6 | ## 2 простых шага 7 | 8 | - [Шаг 1 - экспортировать музыку в текстовый файл](#шаг-1---экспорт-в-файл) 9 | - [Шаг 2 - импортировать в яндекс музыку](#шаг-2---импорт-в-яндекс-музыку) 10 | 11 | ### Шаг 1 - экспорт в файл 12 | 13 | Открыть в ВК страницу со своей музыкой, нажать `F12`. 14 | 15 | Скопировать скрипт со страницы 16 | https://raw.githubusercontent.com/fivemru/export-vk-playlist-to-file/main/chrome-snippet.js 17 | вставить его в консоль на странице ВК, и нажать `Enter`. 18 | 19 | *Скрипт проскроллит страницу до конца, чтобы прогрузился весь список и сохранит в файл `vk-playlist.txt`* 20 | 21 | __Скрины:__ 22 | ![image](https://user-images.githubusercontent.com/30273470/131132113-f00dc4d0-4bf1-4e96-be4f-5c22ef640695.png) 23 | 24 | Список песен в файле 25 | ![image](https://user-images.githubusercontent.com/30273470/131132412-d9f8453f-babd-4d9d-b439-84a9df2ec586.png) 26 | 27 | 28 | 29 | ### Шаг 2 - импорт в яндекс музыку 30 | 31 | Открыть https://music.yandex.ru/import/ 32 | 33 | ![image](https://user-images.githubusercontent.com/30273470/131132766-8a2ca036-b883-48ab-ac17-159245154743.png) 34 | 35 | 36 | Выбрать файл сохраненный на шаге 1. 37 | 38 | ![image](https://user-images.githubusercontent.com/30273470/131132638-0abe0d1a-38eb-4404-a0ba-93b3c5c2a15b.png) 39 | 40 | 41 | Готово. 42 | 43 | ![image](https://user-images.githubusercontent.com/30273470/131132836-00b51ef4-7faf-4f53-a89c-471a64d61493.png) 44 | 45 | -------------------------------------------------------------------------------- /bonus/remove-all-audios.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const scroll = (top) => window.scrollTo({ top }); 3 | const delay = (ms) => new Promise((r) => setTimeout(r, ms)); 4 | 5 | async function loadFullPlaylist() { 6 | let pageHeight = 0; 7 | do { 8 | pageHeight = document.body.clientHeight; 9 | scroll(pageHeight); 10 | await delay(450); 11 | } while (pageHeight < document.body.clientHeight); 12 | } 13 | 14 | function parseAudioList() { 15 | return [...document.querySelectorAll('.audio_row')]; 16 | } 17 | 18 | async function deleteAudioList(list) { 19 | const queue = [...list]; 20 | const bulkSize = 30; 21 | do { 22 | const chunk = queue.splice(0, bulkSize); 23 | for (const item of chunk) { 24 | const audioData = JSON.parse(item.dataset.audio); 25 | 26 | ajax.post('al_audio.php', { 27 | act: 'delete_audio', 28 | oid: audioData[1], 29 | aid: audioData[0], 30 | hash: audioData[13]?.split('/')[3], 31 | restore: 1, 32 | track_code: audioData[20], 33 | }); 34 | 35 | item.remove(); 36 | await delay(80); 37 | } 38 | } while (queue.length); 39 | } 40 | 41 | // Main 42 | await loadFullPlaylist(); 43 | const list = parseAudioList(); 44 | scroll(0); 45 | await deleteAudioList(list); 46 | })(); 47 | -------------------------------------------------------------------------------- /bonus/remove-all-videos.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const scroll = (top) => window.scrollTo({ top }); 3 | const delay = (ms) => new Promise((r) => setTimeout(r, ms)); 4 | 5 | async function loadFullPlaylist() { 6 | let pageHeight = 0; 7 | do { 8 | pageHeight = document.body.clientHeight; 9 | scroll(pageHeight); 10 | await delay(250); 11 | } while (pageHeight < document.body.clientHeight); 12 | } 13 | 14 | function parseVideos() { 15 | return [...document.querySelectorAll('.video_item')]; 16 | } 17 | 18 | async function deleteVideos(list) { 19 | const queue = [...list]; 20 | const bulkSize = 80; 21 | do { 22 | const chunk = queue.splice(0, bulkSize); 23 | for (const item of chunk) { 24 | const deleteBtn = item.querySelector('.video_thumb_action_delete'); 25 | deleteBtn.click(); 26 | } 27 | await delay(350); 28 | } while (queue.length); 29 | } 30 | 31 | // Main 32 | await loadFullPlaylist(); 33 | const list = parseVideos(); 34 | await deleteVideos(list); 35 | })(); 36 | -------------------------------------------------------------------------------- /chrome-snippet.js: -------------------------------------------------------------------------------- 1 | (async () => { 2 | const scroll = (top) => window.scrollTo({ top }); 3 | const delay = (ms) => new Promise((r) => setTimeout(r, ms)); 4 | 5 | async function scrollPlaylist() { 6 | const spinner = document.querySelector('.CatalogBlock__autoListLoader'); 7 | let pageHeight = 0; 8 | do { 9 | pageHeight = document.body.clientHeight; 10 | scroll(pageHeight); 11 | await delay(400); 12 | } while ( 13 | pageHeight < document.body.clientHeight || 14 | spinner?.style.display === '' 15 | ); 16 | } 17 | 18 | function parsePlaylist() { 19 | return [...document.querySelectorAll('.audio_row__performer_title')].map( 20 | (row) => { 21 | const [artist, title] = ['.audio_row__performers', '.audio_row__title'] 22 | .map(selector => row.querySelector(selector)?.textContent || '') 23 | .map((v) => v.replace(/[\s\n ]+/g, ' ').trim()); 24 | 25 | return [artist, title].join(' - '); 26 | }, 27 | ); 28 | } 29 | 30 | function saveToFile(filename, content) { 31 | const data = content.replace(/\n/g, '\r\n'); 32 | const blob = new Blob([data], { type: 'text/plain' }); 33 | const link = document.createElement('a'); 34 | link.download = filename; 35 | link.href = URL.createObjectURL(blob); 36 | link.target = '_blank'; 37 | link.style.display = 'none'; 38 | document.body.appendChild(link); 39 | link.click(); 40 | document.body.removeChild(link); 41 | } 42 | 43 | // Main 44 | await scrollPlaylist(); 45 | const list = parsePlaylist(); 46 | saveToFile('vk-playlist.txt', list.join('\n')); 47 | })(); 48 | --------------------------------------------------------------------------------