Skip to content

Instantly share code, notes, and snippets.

@walfie
Last active April 14, 2024 03:43
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save walfie/87bcb9e5a14d97af6fe39c8d3eb9468e to your computer and use it in GitHub Desktop.
Save walfie/87bcb9e5a14d97af6fe39c8d3eb9468e to your computer and use it in GitHub Desktop.
ClubDAM API docs

ClubDAM API

ClubDAM has a mobile app called デンモクmini ("Denmoku mini") which uses an undocumented API.

Table of Contents

DkDamSearchServlet

The main search endpoint is located at:

POST https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet

The POST body is JSON, but the specific fields depend on the content you want to retrieve.

Required fields

The following fields are required for all requests, or it will return an error response.

  • appVer: The version of the Denmoku Mini app (e.g., current version is "2.1.0")
  • deviceId: A hex string uniquely identifying your device (e.g., "abcdef123456789")
  • deviceNm: The name of your device (e.g., "Walf's Phone")
  • osVer: Your OS-specific version (e.g., "4.4.4" if you're on Android 4.4.4)
  • categoryCd: 6-digit ID depending on what you're searching for (artist, song, etc)

Besides categoryCd, the values don't seem to matter. Presumably they're used for internal reporting purposes.

Categories

A list of categoryCd values as extracted from the app:

ID     | Description
------ | -----------------------------------
010000 | `ARTIST_NAME`
020000 | `SONG_NAME`
030100 | `NEW_SONG_ALL_SONG`
030201 | `NEW_SONG_LIVE_KARAOKE`
030202 | `NEW_SONG_CAST_PICTURE`
030203 | `NEW_SONG_CLIP_JUST_NOW`
030301 | `NEW_SONG_ANIME_GAME`
030302 | `NEW_SONG_SPECIAL_EFFECTS`
030401 | `NEW_SONG_CM`
030402 | `NEW_SONG_DRAMA_MOVIE`
030403 | `NEW_SONG_VARIETY`
030404 | `NEW_SONG_MUSIC_PROGRAM`
030405 | `NEW_SONG_INFORMATION_PROGRAM`
030406 | `NEW_SONG_SPORTS`
030500 | `NEW_SONG_SOON_DELIVERY`
040000 | `CAST_PICTURE`
050100 | `ANIMATION_SPECIAL_EFFECTS_ANIME`
050200 | `ANIMATION_SPECIAL_EFFECTS_SPECIAL`
050300 | `ANIMATION_SPECIAL_EFFECTS_IMAGE`
060100 | `VOCALOID_HATSUNE_MIKU`
060200 | `VOCALOID_KAGAMINE_RIN_REN`
060300 | `VOCALOID_MEGURINE_RUKA`
060400 | `VOCALOID_KAITO_MEIKO`
060500 | `VOCALOID_GUMI`
060600 | `VOCALOID_KAMUI_GAKUPO`
060700 | `VOCALOID_LILY`
060800 | `VOCALOID_OTHER`
060900 | `VOCALOID_IMAGE`
070100 | `DAM_BEST_POPS`
070200 | `DAM_BEST_BALLAD`
070300 | `DAM_BEST_WESTERN_MUSIC`
070400 | `DAM_BEST_DUET`
070500 | `DAM_BEST_ANIME_SPECIAL`
071100 | `DAM_BEST_RECOMMENDED_1`
071200 | `DAM_BEST_RECOMMENDED_2`
071300 | `DAM_BEST_RECOMMENDED_3`
071400 | `DAM_BEST_RECOMMENDED_4`
071500 | `DAM_BEST_RECOMMENDED_5`
080100 | `CNTNTS_RANKING_BATTLE`
080200 | `CNTNTS_PRECISION_GRADING`
080300 | `CNTNTS_PRECISION_GRADING_II`
080400 | `CNTNTS_PRECISION_GRADING_DX`
080500 | `CNTNTS_FULL_CHORUS`
080600 | `CNTNTS_OTHER_HISTORY`
080700 | `CNTNTS_VOICE_TRAINING_LOG`
080800 | `CNTNTS_PRECISION_GRADING_DX_G`
080900 | `CNTNTS_PRECISION_GRADING_DX_DUET`

Filter by machine (Optional)

By default, when doing song searches, it will return songs for the highest tier machine (LiveDAM). If you're on a lower tier machine (such as Premier DAM), many of these songs aren't actually available.

The Denmoku app has a way to link the app to the actual ClubDAM machine, by using a QR code. In the app, it will tell you to enter a specific song ID into the karaoke machine, which will put a QR code up on the screen. Scanning the QR code will tell the app which machine you're on, and will add a serialNo field to the request JSON.

Once you know the serialNo, you can reuse it in future requests. For example, I did this at a karaoke place last year, and "AB316238" is known to be Premier DAM.

Find songs by title

songMatchType specifies how songName should match, and can be either:

  • "0" for "starts with"
  • "1" for "contains"

Here, we search for any song beginning with "passion fl".

Note that we're specifying serialNo to be a Premier DAM machine. If we search for "wake up my music" instead (which is not available on Premier DAM), nothing shows up, unless we remove the serialNo field entirely.

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "020000",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "songMatchType": "0",
    "serialNo": "AB316238",
    "songName": "passion fl"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "107891",
      "artistName": "みほ・もな from AIKATSU☆STARS!",
      "distEnd": "99999999",
      "distStart": "20150228",
      "firstBars": "胸がときめく リズム 魔法かけてく",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "",
      "reqNo": "372915",
      "songName": "Passion flower",
      "titleFirstKana": ""
    }
  ],
  "totalCount": "1",
  "totalPage": "1"
}

Find artists by name

artistMatchType specifies how artistName should match, and can be either:

  • "0" for "starts with"
  • "1" for "contains"

Here, we search for any artist with "aikatsu" in the name. The result will give us an artistId that we can use to find songs by that artist.

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "010000",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "artistMatchType": "1",
    "serialNo": "AB316238",
    "artistName": "aikatsu"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "112822",
      "artistName": "AIKATSU☆STARS!",
      "distEnd": "",
      "distStart": "",
      "firstBars": "",
      "funcAnimePicture": "",
      "funcPersonPicture": "",
      "funcRecording": "",
      "funcScore": "",
      "indicationMonth": "",
      "myKey": "",
      "orgKey": "",
      "programTitle": "",
      "reqNo": "",
      "songName": "",
      "titleFirstKana": ""
    },
    {
      "artistId": "110872",
      "artistName": "かな・るか from AIKATSU☆STARS!",
      "distEnd": "",
      "distStart": "",
      "firstBars": "",
      "funcAnimePicture": "",
      "funcPersonPicture": "",
      "funcRecording": "",
      "funcScore": "",
      "indicationMonth": "",
      "myKey": "",
      "orgKey": "",
      "programTitle": "",
      "reqNo": "",
      "songName": "",
      "titleFirstKana": ""
    },
    // etc
  ],
  "totalCount": "15",
  "totalPage": "1"
}

Find songs by artist ID

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "010000",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "serialNo": "AB316238",
    "artistId": "112822"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "112822",
      "artistName": "AIKATSU☆STARS!",
      "distEnd": "99999999",
      "distStart": "20151028",
      "firstBars": "今日が生まれかわる",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "",
      "reqNo": "374166",
      "songName": "START DASH SENSATION",
      "titleFirstKana": ""
    },
    {
      "artistId": "112822",
      "artistName": "AIKATSU☆STARS!",
      "distEnd": "99999999",
      "distStart": "20151028",
      "firstBars": "きみと ハピハピ ピカピカ",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "",
      "reqNo": "374167",
      "songName": "lucky train!",
      "titleFirstKana": ""
    }
  ],
  "totalCount": "2",
  "totalPage": "1"
}

New anime songs

This uses categoryCd "030301" which corresponds to NEW_SONG_ANIME_GAME. You can use the other NEW_SONG_ categories for other results.

The results are sorted by series title (programTitle) instead of release date (distStart), so you will need to sort client-side.

Although the results might say there's more than 1 page, there's really just one page with all the songs.

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "030301",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "songMatchType": "0",
    "serialNo": "AB316238"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "121081",
      "artistName": "るか・せな from AIKATSU☆STARS!",
      "distEnd": "99999999",
      "distStart": "20161102",
      "firstBars": "ページをめくるたびに 新しいキミ",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "999999",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "アイカツスターズ!",
      "reqNo": "376977",
      "songName": "So Beautiful Story",
      "titleFirstKana": ""
    },
    // ... etc
  ],
  "totalCount": "308",
  "totalPage": "4"
}

List all anime series

This request is used by the app to list all anime series. There's no pagination, it just returns a huge list of all of them (currently 3.6k songs, with a 1.4MB response). It's very slow.

It actually returns one song for each series, but the app only uses the programTitle and titleFirstKana (to group series together for sorting/navigation purposes) from the request.

This uses categoryCd of "050100" which corresponds to ANIMATION_SPECIAL_EFFECTS_ANIME. Other categories will yield different results.

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "050100",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "serialNo": "AB316238"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "39298",
      "artistName": "UNCO☆STAR",
      "distEnd": "99999999",
      "distStart": "20070126",
      "firstBars": "U.N.C.O. U.N.C.O. U.N.C.O.",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "アークエとガッチンポー てんこもり",
      "reqNo": "643758",
      "songName": "ウラ・ガッチンポーのテーマ",
      "titleFirstKana": "ア"
    },
    // ... etc
  ],
  "totalCount": "3618",
  "totalPage": "37"
}

Again, the totalPage count is a lie, there's only one page available, with 3.6k items.

Find songs by anime series

If you know the programTitle (series name) of the series, you can find songs for that series, assuming you use the same categoryCd that the series belongs to.

Request:

curl -XPOST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamSearchServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "categoryCd": "050300",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "page": "1",
    "programTitle": "アイカツ!",
    "serialNo": "AB316238"
  }'

Response:

{
  "searchResult": [
    {
      "artistId": "91801",
      "artistName": "わか、ふうり、すなお from STAR☆ANIS",
      "distEnd": "99999999",
      "distStart": "20130330",
      "firstBars": "さぁ! 行こう 光る未来へ ホラ",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "indicationMonth": "",
      "myKey": "0",
      "orgKey": "0",
      "programTitle": "アイカツ!",
      "reqNo": "360715",
      "songName": "アイドル活動!",
      "titleFirstKana": "ア"
    },
    // ... etc
  ],
  "totalCount": "45",
  "totalPage": "1"
}

DkDamIsExistServlet

The Denmoku app also has a feature where you can select songs on your phone and check if they exist in the system. This will send the song name and artist name, and return any matches.

It uses a different endpoint from the search one:

POST https://denmoku.clubdam.com/dkdenmoku/DkDamIsExistServlet

It accepts the same required fields, and optional serialNo.

Find songs on device

If the song isn't present, it will return empty strings in the response. Note that artistName isn't required, it's only used for disambiguation. You can leave artistName as an empty string if you know the songName is unique. If there are multiple matches for the song name, it will pick one for you (which may not be the one you want).

Request:

curl --request POST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamIsExistServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "serialNo": "AB316238",
    "isExist": [
      { "artistName": "SUPER☆GiRLS", "songName": "胸キュンLove Song" },
      { "artistName": "りさ、えいみ", "songName": "wake up my music" }
    ]
  }'

Response:

{
  "QRcode": "",
  "appVer": "",
  "cdmNo": "",
  "deviceId": "",
  "deviceNm": "",
  "isExist": [
    {
      "artistId": "76729",
      "artistName": "SUPER☆GiRLS",
      "distEnd": "99999999",
      "distStart": "20150815",
      "firstBars": "キミがそっと打ち明けた",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "myKey": "0",
      "orgKey": "0",
      "reqNo": "489143",
      "songName": "胸キュンLove Song"
    },
    {
      "artistId": "",
      "artistName": "りさ、えいみ",
      "distEnd": "",
      "distStart": "",
      "firstBars": "",
      "funcAnimePicture": "",
      "funcPersonPicture": "",
      "funcRecording": "",
      "funcScore": "",
      "myKey": "",
      "orgKey": "",
      "reqNo": "",
      "songName": "wake up my music"
    }
  ],
  "osVer": "",
  "reqNo": "",
  "serialNo": ""
}

Find song by ID

The app doesn't actually have this functionality, but I found it by messing around with the request params. If you know the song ID, you can find out which song matches it.

Request:

curl --request POST \
  --url https://denmoku.clubdam.com/dkdenmoku/DkDamIsExistServlet \
  --header 'content-type: application/json' \
  --data '{
    "appVer": "2.1.0",
    "deviceId": "abcdef123456789",
    "deviceNm": "cURL",
    "osVer": "4.4.4",
    "serialNo": "AB316238",
    "isExist": [
      { "reqNo": "369073" }
    ]
  }'

Response:

{
  "QRcode": "",
  "appVer": "",
  "cdmNo": "",
  "deviceId": "",
  "deviceNm": "",
  "isExist": [
    {
      "artistId": "19111",
      "artistName": "すなお from STAR☆ANIS",
      "distEnd": "99999999",
      "distStart": "20140208",
      "firstBars": "We wish you a merry Christmas,",
      "funcAnimePicture": "0",
      "funcPersonPicture": "0",
      "funcRecording": "11",
      "funcScore": "1",
      "myKey": "0",
      "orgKey": "0",
      "reqNo": "369073",
      "songName": "We wish you a merry Christmas AIKATSU! Ver."
    }
  ],
  "osVer": "",
  "reqNo": "",
  "serialNo": ""
}

GetRecommendSongs.api

In the app, when you go to a song page, it'll have a carousel of recommended (similar) songs. This uses a different endpoint:

POST https://csgw.clubdam.com/minsei/recommend/GetRecommendSongs.api

This one uses form params instead of JSON. I don't know what all of them mean, but the following are hardcoded into the app:

  • compId: 1
  • contractId: 1
  • compAuthKey: 2/Qb9R@8s*
  • format: json

The following are specific to the request:

  • requestNoList: Song ID (e.g., "3729-15")
  • serial: Same as serialNo in the other endpoints (e.g., "AB316238")

Get recommended songs

Request:

curl --request POST \
  --url https://csgw.clubdam.com/minsei/recommend/GetRecommendSongs.api \
  --header 'content-type: application/x-www-form-urlencoded' \
  --data 'compId=1&contractId=1&compAuthKey=2%2FQb9R%408s*&format=json&requestNoList=3729-15&serial=AB316238'

Response:

{
  "data": {
    "recommendCount": "64",
    "requestNo": [
      "3729-15"
    ]
  },
  "list": [
    {
      "artist": "せな・りえ from AIKATSU☆STARS!",
      "artistCode": "476404",
      "contents": "スタートライン!",
      "contentsId": "5616135",
      "contentsYomi": "スタートライン",
      "dArtistNameYomi": "セナリエフロムアイカツスターズ",
      "dSongNameYomi": "スタートライン",
      "damArtistCode": "117590",
      "denmokuArtist": "せな・りえ from AIKATSU☆STARS!",
      "denmokuContents": "スタートライン!",
      "nameYomi": "セナリエフロムアイカツスターズ",
      "requestNo": "3762-82"
    },
    {
      "artist": "るか・せな from AIKATSU☆STARS!",
      "artistCode": "477795",
      "contents": "So Beautiful Story",
      "contentsId": "5639199",
      "contentsYomi": "ソービューティフルストーリー",
      "dArtistNameYomi": "ルカセナフロムアイカツスターズ",
      "dSongNameYomi": "ソービューティフルストーリー",
      "damArtistCode": "121081",
      "denmokuArtist": "るか・せな from AIKATSU☆STARS!",
      "denmokuContents": "So Beautiful Story",
      "nameYomi": "ルカセナフロムアイカツスターズ",
      "requestNo": "3769-77"
    },
    // ... etc
  ],
  "message": "",
  "status": "OK",
  "statusCode": "0000",
  "type": "2.2"
}

The response includes the katakana pronunciation of the artist/title.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment