네이버 채팅방 링크
목록보기
  • [노하우]
  • MP3 다운로더 만들었다.
  • 조회수 :
  • 5977
  • 2022.05.17
  • 16:22:21
// MusicShake.mjs
// Written on May 17, 2022.
////////////////////////////////////// 80 //////////////////////////////////////

import NodeCrypto from "node:crypto";
import Got from "got";

export default class MusicShake {
static correct_the_title(mp3_data/*: Buffer */) {
const ID3V1_METADATA_CHUNK_SIZE = 128,
ID3V1_SIGNATURE = "TAG",
ID3V1_TITLE_AREA_SIZE = 30;
const id3v1_title_data_index = mp3_data.length
- ID3V1_METADATA_CHUNK_SIZE
+ ID3V1_SIGNATURE.length;
const id3v1_title_data = mp3_data.subarray(
id3v1_title_data_index,
id3v1_title_data_index +  ID3V1_TITLE_AREA_SIZE
);
const title = (new TextDecoder("EUC-KR", {fatal: true}))
.decode(id3v1_title_data)
.replace(/\0.*$/, "");
mp3_data.fill(
0,
id3v1_title_data_index,
id3v1_title_data_index + ID3V1_TITLE_AREA_SIZE
);
mp3_data.write(
title,
id3v1_title_data_index,
ID3V1_TITLE_AREA_SIZE
); // Write it in UTF-8.
return title;
} // -> string
static async download(music_identifier/*: number */ = 242261) {
const entry = await Got.get(
{
url: "http://msg.musicshake.com/getTicket.php",
searchParams: {
SONG_NUM: music_identifier,
LANG: "Kor"
},
resolveBodyOnly: true
}
);
const [api_endpoint, ticket_number] = entry.split("||");
const key = NodeCrypto
.createHash("MD5")
.update(ticket_number + "@#!mshaker")
.digest("hex");
const mp3_data = await Got.get(
{
url: api_endpoint,
searchParams: {
TICKET_NUM: ticket_number,
key
},
responseType: "buffer",
resolveBodyOnly: true
}
);
const title = MusicShake.correct_the_title(mp3_data);
return {title, mp3_data};
} // -> Promise -> object {title: string, mp3_data: Buffer}
}



/ / main.mjs
// Written on May 17, 2022.
////////////////////////////////////// 80 //////////////////////////////////////

import FileSystem from "node:fs/promises";
import MusicShake from "./MusicShake.mjs";

const to_download_music_identifiers = [242261];
Promise.all(
to_download_music_identifiers.map(async music_identifier => {
console.info(`Downloading the music #${music_identifier}.`);
const {title, mp3_data} =
await MusicShake.download(music_identifier);
const filename =
`${title} (#${music_identifier}@MusicShake.com).MP3`;
await FileSystem.writeFile(filename, mp3_data);
console.info(`Downloaded the music #${music_identifier}.`);
})
);


소류한(user #52773)이가 분석한 API 참고해서 작성했다.
CORS 정책 때문에 Node.js 썼다.
MP3 파일 끝에 ID3v1 메타데이터 청크 있는데 거기에 제목이 멍청하게도 EUC-KR로 박혀 있어서 UTF-8로 고쳐 박았다.
그 점 참고하고, 내 코드 쓸 줄 아는 놈은 써서 MP3 파일 받아라.

music_identifier는 그냥 곡 자랑 페이지 가서 F12 키로 개발자 도구 열어서
Array.from(document.querySelectorAll(".smallPlayer")).map(sp => Number.parseInt(sp.getAttribute("param").replace("SONG/", "")))
치면 나온다.
아쉽게도 ‘내 곡 저장 공간’에 들어 있는, 자랑 안 한 곡들의 ID는 뽑아 낼 방법이 없더라. 자랑한 곡 ID만 알 수 있음.

내 추억들 이걸로 export해 뒀으니 이만 가 본다.


서울시 서초구 서초동 1640-14 103호 (주)싸일런트뮤직밴드 대표이사 윤형식
사업자등록번호 : 120-86-79391 통신판매업 신고번호 : 강남 제 285호
Email : help@musicshake.com