Musicoin Player 만들기 - 2화 우물을 파봅니다.

in #kr7 years ago

이전 글에 언급했던 GET /json-api/track/ 를 살펴봅니다.

{
  "resourceUrl": "eipfs://QmSrPmr85LWZttc6MG7ghfa3WXhVEY2t4nEtKKHgN93her",
  "contentType": "audio/mp3",
  "createdBy": "0x6e1d33f195e7fadcc6da8ca9e36d6d4d717cf504",
  "totalShares": "1",
  "totalPending": "0",
  "title": "NoAU",
  "getContributorsLength": "1",
  "licenseVersion": "1",
  "metadataVersion": "0",
  "artistProfileAddress": "0x15d3efbf2f8df32bce36f3479cf99d5392714a7a",
  "artistName": "spectrum",
  "totalEarned": "693000000000000000000",
  "owner": "0x6e1d33f195e7fadcc6da8ca9e36d6d4d717cf504",
  "playCount": "693",
  "contractVersion": "v0.7",
  "imageUrl": "ipfs://QmZYWaDvBg5Wc6UxpX7TvBtiz7RqDZd8hM71AMmMomit28",
  "weiPerPlay": "1000000000000000000",
  "totalTipped": "0",
  "metadataUrl": "ipfs://Qmb5561nQV2yFot51RfBqgPah7t24wmyLseWb18qp4Vtjg",
  "tipCount": "0",
  "balance": "0",
  "contributors": [
    {
      "address": "0x15d3efbf2f8df32bce36f3479cf99d5392714a7a",
      "shares": "1"
    }
  ],
  "royalties": [],
  "coinsPerPlay": "1",
  "totalEarnedCoins": "693",
  "address": "0x10254eb7e07f223193c756b2b440892043cd3b7a",
  "image": "/media/cf3920a795f5db5a53b348b6f3550aeacb5b9b18333643c26d6996cca2820ceb5c6c3200bc84185622562132ed13",
  "audioUrl": "/ppp/38fb0c55aa339a47b1d64ffacd23a4ecf5c66aade88cbb1398128b8846c3b3a38ac881e1faed9e9d87238fb5f66b94c4b4befe56c825e23e",
  "genres": [
    "Beats & Instrumentals",
    "Electronic"
  ],
  "languages": [],
  "moods": [],
  "regions": [],
  "description": "easy listening. electronic peace",
  "timeSince": "7 months ago",
  "directTipCount": 12,
  "directPlayCount": 693,
  "releaseDate": "2017-06-20T10:04:55.297Z",
  "tx": "0xe917d2c3528fda8090e036e1c96a949bc441f2afbf1307202d60dfbcb4772ff7"
}

제 눈을 사로 잡는 것은

Musicoin은 음악(mp3)를 musicoin은 어디에 저장할까?

라는 질문의 답변이 될만한 단서가 보입니다.
"resourceUrl": "eipfs://QmSrPmr85LWZttc6MG7ghfa3WXhVEY2t4nEtKKHgN93her",
이와 같이 eipfs라는 프로토콜을 사용하고 있네요. eipfs?? ipfs(https://ipfs.io/)는 들어봤는데 d.tube(https://d.tube/) 같은데서도 사용하고 있는 분산 파일 저장시스템인 ipfs의 변종인 것 같은데
https://ipfs.github.io/public-gateway-checker/ 에서 참한 놈을 골라 한번 찝어봅니다.
ipfs gateways

✅ - Online  - https://ipfs.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://gateway.ipfs.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://ipfs.jes.xxx/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://siderus.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://www.eternum.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://hardbin.com/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://ipfs.infura.io/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a
✅ - Online  - https://xmine128.tk/ipfs/Qmaisz6NMhDB51cCvNWa1GMS7LU1pAxdF4Ld6Ft9kZEP2a

요정도가 참하군요.
불행히도 주소를 복붙해보니 잘 안되긴 합니다. 뭐 나중에 한번 잘 알아봐야겠네요. 그나저나 IPFS는 완전 재밌군요. go도 있고 js 버전도 있네요. 호호. 재밌당~
resource에 대한 의문은 해결이 되었습니다.
weiPerPlay 는 PPP(Pay per Play) 정책에 따라 지급하는 wei 그러니까 1/1,000,000,000,000,000,000 MC인거죠. ethereum 기반이라 단위가 완전히 같습니다. 현재 1MC 입니다. 만일 이게 ether라면 크으...
contributors 는 해당 트랙에 대해 여러명이 수익을 나눠가질 수 있는데 그 내용입니다.
address는 수익자, share는 수익비율을 나타냅니다.
어떻게 아냐고요? 제가 저렇게 설정했으니까요 :)

playCount 는 재생 횟수입니다. 중요한 부분인데 Musicoin Player를 만들고 나서 1회이상 재생했을 경우 저부분이 증가가 되는지를 검증해야겠지요.
만일, 카페 체인이나 상점등등에서 Musicoin Player로 음악을 틀고있다면.. 이라고 생각하니 두근두근해지네요.
장르, 이미지, 컨트랙트 버전, 분위기, 지역 등등 의미있는 메터데이터들이 가득합니다.
필요한 데이터는 이거면 충분해 보입니다.

https://musicoin.org/js/player.js 도 봅니다.
jquery를 쓰는 걸로 보아 $. 시리즈로 검색해봅니다.
player.js

$.post("/user/canPlay", { address: licenseAddress },
$.get("/json-api/track/" + licenseAddress, function(data) {

순서는 canPlay로 체크한 뒤 json-api/track에서 자세한 정보를 가져오는군요.
다른 것도 뭐 있나 볼까요?
random play?
보니까 random 재생이 있네요?!
https://musicoin.org/json-api/tracks/random/new?limit=5&artist=0x15d3efbf2f8df32bce36f3479cf99d5392714a7a
내용은 완전히
https://musicoin.org/json-api/track/0x10254eb7e07f223193c756b2b440892043cd3b7a
요거랑 같고 해당 아티스트의 모든 곡을 다 넣을 수 있네요.

아티스트 페이지에서 PLAY ALL 을 눌렀을 때랑 다릅니다.
PLAY ALL

꼭 해당 아티스트 뿐만 아니라 재생 이력에 있는 걸 다 가져오는군요?
https://musicoin.org/json-api/tracks/details?addresses%5B%5D=0xff254bbd44d10498ae47ee80229db127ad849f61&addresses%5B%5D=0x1e5d291507499791e81688a27b51fbfe10433569&addresses%5B%5D=0x10254eb7e07f223193c756b2b440892043cd3b7a&addresses%5B%5D=0x4ea29bf1ce43f7c152e458842e1e44ed3844e67a
이걸 이용하면 다른 아티스트의 다른 트랙들을 여러개 묶어서 재생할 수 있겠네요.

여튼 /json-api/track 을 가져온 후 실행하는 부분을 보면

            audioPlayer.currentlyPlayingTrack = data;
            var result = audioPlayer.playItem({
              element: null,
              audioUrl: data.audioUrl,
              title: data.title,
              artistName: data.artistName,
              image: data.image,
              playCount: data.playCount,
              tipCount: data.tipCount,
              artistProfileAddress: data.artistProfileAddress,
              address: data.address
            });

audioUrl, title, artistName, image, 등등을 사용합니다.

거의 다 왔네요.

playItem 구현을 살펴봅니다.
playItem
코드를 복붙하면 내용이 길어져서 스샷으로만 올리는 게 낫겠네요.

보니까 클라이언트 기준으로 new Date().getTime()를 now 에 넣고 이전 플레이시간하고 비교하는 부분이 있군요.
이게 너무 짧으면 거절하는 것으로 보아 now 가 중요한 값이군요.

이전 글 (https://steemit.com/kr/@acidsound/musicoin-player-1) 에서 audio src가 /ppp/38fb0c55aa339a47b1d64ffacd23a4ecf5c66aade88cbb1398128b8846c3b3a38ac881e1faed9e9d87238fb5f66b94c4b4bafe5ec721e13d?1515510836736 이런 식으로 되있다고 말씀드렸는데 ? 뒤에 있는 값은 결국 timestamp 값이겠네요.

var audioUrl = url + "?" + new Date().getTime();

네네 맞군요.

한번 검증해보겠습니다. Terminal 에서

$ date +%s
1515606786

로 timestamp 값을 따올 수 있으니 당연히

$ echo "바바바$(date +%s)나나나"
바바바1515606786나나나

이런 것도 되겠지요.
OS X에선 millisecond 옵션인 %N를 지원하지 않아서 node.js 를 사용합니다.
node -p 'new Date().getTime()' 으로 뽑습니다.
000 붙여도 되겠지만 역시 같은게 좋죠.
SoX(http://sox.sourceforge.net/)를 전에 설치했었는데 play 명령으로 위 ppp 주소랑 합쳐봅니다.

$ play -t mp3 "https://musicoin.org/ppp/38fb0c55aa339a47b1d64ffacd23a4ecf5c66aade88cbb1398128b8846c3b3a38ac881e1faed9e9d87238fb5f66b94c4b4bafe5ec721e13d?$(node -p 'new Date().getTime()')" 

"/ppp/38fb0c00ad629c1be2d41afdce7cafe9ffc636a6ba8db61d9b12dede47c2edf8de9d84e2adba9eca867b8fb5f66b94c7b5bdf250c921e033?"+(new Date().getTime())

      $.post("/user/canPlay", { address: licenseAddress }, function(eligibility) {
        if (eligibility.success) {
          console.log("Getting details for " + licenseAddress);
          $.get("/json-api/track/" + licenseAddress, function(data) {
.....
      var audioUrl = url + "?" + new Date().getTime();
      if(!audioPlayer.previewMode) {
        $("#player")[0].src = audioUrl;
        audioPlayer.audioElement.play();
      }
      else {
        $("#player").data('audioUrl', audioUrl);
      }

필요한 코드는 이게 전부인 거 같습니다.

/user/canPlay 부터 막히네요. CORS 문제입니다. 다른 도메인에서 요청을 하면 거절하는거죠. 일명 Same Origin Policy문제 흑흑.
그래서 musicoin embeded player 페이지(https://musicoin.org/embedded-player/0x1e5d291507499791e81688a27b51fbfe10433569)에서 크롬 개발자 도구를 열고

track = "0x1e5d291507499791e81688a27b51fbfe10433569";
fetch("https://musicoin.org/user/canPlay", {
  method: 'post',
  body: new URLSearchParams(`address=${track}`)
}).then(res=>res.json())
.then(data=>fetch(`https://musicoin.org/json-api/track/${track}`))
.then(res=>res.json())
.then(data=>console.log(data.audioUrl))

이렇게 요청 보내봅니다.
musicoin의 REST서버가 안정적이지 않아 500오류가 자주 뜨는군요.
아마도 서버 사이드도 구축해야할 것 같은 불길한 예감이 듭니다.

저도 오늘은 여기까지가 한계인가 봅니다.
다음 글에서 뵙죠~ 빠잉.

Coin Marketplace

STEEM 0.18
TRX 0.14
JST 0.030
BTC 58679.35
ETH 3155.04
USDT 1.00
SBD 2.44