musicapp application - fetching and updating songs, albums and videos from popular sites in VN


CLI Installation



Using nodejs


Their link's ids are encrypted in simple ways. They can be cracked by utilizing this func

decode  = (id) ->
    = ['bw bg bQ bA aw ag aQ aA Zw Zg'.split(' '),
         'U0 Uk UU UE V0 Vk VU VE W0 Wk'.split(' '),
         ' X1 XF XV Wl W1 WF WV Vl V1'.split(' ')]
    (id+'').split('').map((v,i)-> a[6-i][v]).join('')

EX: song_id : 345678 will become XVxUVURX

We can grasp data with these links

Using CLI
1250000 is songid.

Get cookie FPTID and Hash hash

curl\?display\=iframe -v

USING grep and sed

curl -s\?display\=iframe -i | grep -i -E "FPTID\=[0-9a-zA-Z]+|id\=\"hash\" value\=\"" | sed -e 's/Set\-Cookie\: //' -e 's/\; path=\///' -e 's/\                    <input type\=\"hidden\" name\=\"hash\" id\=\"hash\" value\=\"//' -e 's/\" \/\>//'

Get cookie Auth

curl -d "hash=a9785186138d519050ea35a178b749ff&" -b "FPTID=j96g6to8r0qvcvgsmlnn04he43" -v

bash and FPTID have to be consitent

curl -s\?display\=iframe -d "hash=a9785186138d519050ea35a178b749ff&" -b "FPTID=j96g6to8r0qvcvgsmlnn04he43" -i| grep -i 'Auth\=[0-9a-zA-Z\%]\+'| sed -e 's/Set\-Cookie\: //' -e 's/\; path\=\/\; domain\=\.fpt\.net\; httponly//'

Get song

curl "" -o sample.mp3 -b Auth=V0JAaVlcZkNEXlwAECkcCzVFAgNVAhwuXgtnBwdbAkkEPF1UbQ

Remember the cookie Auth=V0JAaVlcZkNEXlwAECkcCzVFAgNVAhwuXgtnBwdbAkkEPF1UbQ is valid in 24h

Auto login

Insert user-generated valid Auth .id=1240090058 in the link above is not necessary. ONLY use session ID Auth to log into your acccount! BAM! Security LEAK!


Direct link :

listIdsmeans you can pass parameters with the following pattern : para1,para2,para3,186,131,47,2088,2130,80,2407,17,55

Get similar songs w.r.t. song_id X1pUUkFdaA , 5092,186,131,47,2088,2130,80,2407,17,55are artistId

Get songlike,1260795

Get songtotallisten ; 1260796,1260795are songIds,1260795

Get songstatistic; 1260796,1260795 are songIds

View page source to get the structure. XML Format

NOTICE: Load Balancing: http://st01|


/id/X1xSV0Y can be replaced by id/14345

Get Subtitles

Get videostatistic


Request Method: POST , form data: id:14449 <= increase song plays. Use cURL command curl -XPOST -d "id=14449"

Request Method: POST , form data: listIds:10 <= get procedure. Use cURL command curl -XPOST -d "listIds=10"

Use HTML5 ªß

Use on the last parameter only,543700,543565,542242

Get album list stats 543996,543700,543565,542242 are albumIds

Get albumtotallisten

getstatistic of an album

Get albumtotallisten <= aggregation of included songs

gettotalsong of an album,543700,543565,542242

getdescandissuetime: get description and issued moment,321676,310104,310102



###e.Misc### Get Category,2,4,5

getcategory <= get list

Get Lyric

Lastest Songs:

Get Parse Amount Album: < >

Get Parse Amount Song of Artist

Get Artist
Get Suggestion
Get issued time

STATS: Get song_id from 1 to 1.261.000 on Jan 11, 2012.
On Jan 08, scan 541148 albums, filter and insert 165465 albums into database
On Jan 11, scan 977721 songs; ~14016 videos ~500000 abums

NOTE they use || as a delimiter Lê Minh Trung ||Như Ý

MICS : Check these links again

type=POST <= check in server script. Functions getObjectVideo()and getObjectSong()

Request Method: POST , form data: id:1142573 <= increase song plays. Use cURL command curl -XPOST -d "id=1260645"

STATS: Total songs: 173733. Total albums: 17556 .
Updated on December 12, 2012

STATS: ~279772 songs, ~24100 albums on Feb 02

Notice 2 and 4

The rule of finding the link of mp3 file: - .mp3?s=1 - Thanh Dai Sieu.mp3 - .mp3?s=1 - Dan Nguyen.mp3?s=1 - .mp3?s=1 - My-Linh.mp3?s=1 - .mp3 - Ho-Ngoc-Ha.mp3

< - .mp3?s=1>

STATS: ~313875 songs, ~ 4396 albums on Jan 31

XML-Format :
not complete

STATS: ~193285 songs, ~16084 albums on Feb 04 - JUNK##

STATUS: circa 8000 songs. This site will be ignored.

STATUS: circa 50000 songs. This site will be ignored.

STATUS: greater than 10^3 albums and about 800 songs. This site will be ignored.

STATUS: greater than 700 albums. This site will be ignored.

Get song
Crawl .html to get the value "decodeURIComponent"

Get quality 320kps,128kps or 32kps quality.php?q=320&redirect=mp3/vietnam/v-pop/your-link~1025225.html

Get album
Crawl .html to get the value "decodeURIComponent"…

curl '' --silent -H 'Cookie:  csn_sid=ca404dfca9556f5830b5fb96add51691;' | grep Download | grep '<a href="http:'  

NOTE: THE LINK{days of week}/1030109-056c7572/320/joke-link.mp3

0 => Sunday,1 => Monday ..... 5 => Friday, 6 => Saturday

STATS: get ~17721 albums, ~132052 songs on Feb 7

Turn ZW6W7IUO into 1382183235

convertToInt = (id)->
    = "0IWOUZ6789ABCDEF".split('')
    = "0123456789ABCDEF"
    parseInt id.split('').map((v)-> b[a.indexOf(v)]).join('')16

The format is ZGJGTknazzupuzaTZDJTDGLG

1.Create matrix Mx24 : M album items & 24-character string

1381585029 => "LHJnyknNBNALJbuTLbxTDmkH"
1381585030 => "LGxGTLHadNALJVHykFcTFnLn"
1381585043 => "knJHyLGNdNAkJSdtLDJtFnZG"
1381585044 => "ZncGyLnsBaSkJAltZbctFGkm"

2.Invert the matrix and find the repeated characters in each row. The more M rows are fetched, the more precise they are. Tested with ~70000 albums EX: a inversed matrix of 50x24 gonna be

HGHnnHmmHGnHnnnHGmHGmmnnmGHnHHmHmmHGmHnGHmmmGmGGmG:1 => "GHmn"
JxxJxcJccJcJJcccJJJJxJJxccJcJJJJJcxxcccxJJxJJxxcJx:2 => "Jcx"
nGGnnmnmmGGnHGnGmmGmmmHHmGmHHnHHHmHmmmnnnGGGHmHmHG:3 => "GHmn"
yTyyttTtttyyyyyyytyytTyyTtyttyytytTyytyTTyytTyyTtT:4 => "Tty"
nHHHnnnGHmmmGnGGHGnHHHnnGnmGmmHnmHGGHHnnmHnmmHHmnG:6 => "GHmn"
NaNsaNsaNNaNNsNNNNNsNaNNNsNNsaaaNNNaNNNsNsNaaNasaN:7 => "Nas"
BdVdVddVVdBddBdVVBBBVBdBBddVdVVddBdddVddBdBVdddVdd:8 => "BVd"
NNssNNsNsNNNNaNaNaNsNsNNNNsasNaNNsaaNasNsaNNasaNaN:9 => "Nas"
JJcxccJxJxxxJJxJxJJccxcxxJcJxcxcxJcxxxJcJJcJJcJcJx:12 => "Jcx"
bVBVdVddBVdzSAASllzWQpQWWWppghXhhXgCasNaaNaNscxxJc:13 => "ABCJNQSVWXabcdghlpsxz"
uHZbBlQXNJuLdlpXaJiGZDdSpgsxHkvdSQNinLDdQgNJRGLDdp:14 => "BDGHJLNQRSXZabdgiklnpsuvx"
TyTyyyyytyTyttytytyyyyyttTTytyTtTyyTTtyTtyyytTyyyT:15 => "Tty"
xccJcJxJJcxxJcJcJJJcxJJxJJJJJcJJccJcJccccxJJxcxJJx:18 => "Jcx"
TTytyytyTyyyttTTttttyyyTTyyyyyTyyyytTyTyTytyTTTtyy:19 => "Tty"
mnmHmnnmGnGGnGnnGmHmGmnnHnnHmGmGGnmnmHHGmnGGmHmHnG:21 => "GHmn"
HnnGnHnnnHnHGmmHmnnHGHmmnnmmmmmHHnHmnHGHmGmGmHHHmm:23 => "GHmn"

3.It's showed that each single character in the group LZk represents a same symbol (number or character or whatever). There are 11 groups : GHmn, LZk, DFbv, BVd, ASlz, QWp, ghXC, Nas, Jcx, ERui and Tty. Try with different number of albums. We will see the patterns at position 15,14,13... tend to vary in size as we increase the number of albums in ascendant order. EX: result of 50000x24 matrix

0 => "LZk"
1 => "GHmn"
2 => "Jcx"
3 => "GHmn"
4 => "Tty"
5 => "LZk"
6 => "GHmn"
7 => "Nas"
8 => "BVd"
9 => "Nas"
10 => "ACEJNQRSWXacghilpsuxz"
11 => "ABCDEFGHJLNQRSVWXZabcdghiklmnpsuvxz"
12 => "ABCDEFGHJLNQRSVWXZabcdghiklmnpsuvxz"
13 => "ABCDEFGHJLNQRSVWXZabcdghiklmnpsuvxz"
14 => "ABCDEFGHJLNQRSVWXZabcdghiklmnpsuvxz"
15 => "Tty"
16 => "LZk"
17 => "DFbv"
18 => "Jcx"
19 => "Tty"
20 => "DFbv"
21 => "GHmn"
22 => "LZk"
23 => "GHmn"

4.We see that if the 14th pattern reaches to 35-character length, it gonna stay the same, the the 13th continue to vary until it reached its limit. The same thing applies to 13th pattern. So the question is which position it gonna stop. We find out 10 groups from GHmn to ERui has total characters of 35. They equal the limit of 14th pattern.Moreover, the group Tty does not exist in the 14th pattern. Therefore we can assume it can be served as a delimiter or something else. 10 groups maybe represent base ten, so the boundary can be assumed from 4th to 15th. Next step, we observe the length from 5th to 14th is equal to 10. It is coincident to the length of aid (album_id showed in number) (EX: 1381585030). So our assumption is perhaps correct. The problem now is to find a mapping of each group to single digit in base 10. Find two consecutive albums and look at the change in the 14th position of aid in the albums, hence we have the example hash table:

1381585330 => "LnJmyknNdNSvZBHTkDJTvHkn" : 14th position is "H"
1381585331 => "kmJmTLHsdalFLVLyLDJTbGZG" : 14th position is "L"
1381585339 => "kncmTkHsdsAvkduyLFJyDnLG" : 14th position is "u"

5.We come to an order of 10 groups as GHmn<LZk<DFbv<BVd<ASlz<QWp<ghXC<Nas<Jcx<ERui. They are equivalent to the digits from 0,1,2 to 9. EX: we test with the string LnJmyknNdNSvZBHTkDJTvHkn(1381585330). At firstly remove the trivial positions from 0 to 4, 15 to 23 as the group Tty is the delimiter to get knNdNSvZBH and convert it into nummerical system. We have 1073742130. The difference between the result and the original number is 307843200.

6.It is almost complete. Now given a real album_id, ex: 1382365302 . We subtract by 307843200 and generate from the calculated result to get string which each digit is equivalent to each group. Finally it is end up with ZGJGTknazpbbknbTZDJTDGLG

encryptId = (id) ->
    = "GHmn|LZk|DFbv|BVd|ASlz|QWp|ghXC|Nas|Jcx|ERui|Tty".split("|") 

EX: Run encryptId(1381585458) -> ZGJGykHsVNSDvQJtkDcTbHkH

term is artist or song in database

  • Scan whole albums in artist profile

Step 1: Get album-xml:

Step 2: Get static, constant links. For instance:

It'll redirect to a new temporary location

Step 3: Get temp link (being expired in 6h)

Notice link like this

only available in 6hours due to the consistency between the hash 4ce95480fb0b141aba6d059d0591fa3c and the timestamp 5108a15e => timestamping

the encrypted links

This link will be regenerated in every 6h.
At first, the webserver will rewrite the URL to new location .
Secondly, it actually loads balancing among the hosts: where subdomain channelz1 is in [1,2,7,8,9]

Lyric has supported many verions

~421984 songs, ~42677 albums, ~10695 artists, ~29366 videos on Feb 7

ONES = ['A','E','I','M','Q','U','Y','c','g','k']
TENS = ['MD','MT','Mj','Mz','ND','NT','Nj','Nz','OD','OT']
HUNDREDS = ['w','x','y','z','0','1','2','3','4','5']
THOUSANDS = ['A','E','I','M','Q','U','Y','c','g','k']
TENSOFTHOUSANDS = ['MD','MT','Mj','Mz','ND','NT','Nj','Nz','OD','OT']
HUNDREDSOFTHOUSANDS = ['','MC0x','MC0y','MC0z','MC00','MC01','MC02','MC03','MC04']

Note: ----->

  • Get A Chunk of A Video

Get File :

Get link :

Get content like : AAAAAA9zGyVZeG9VTVhzdUlCazZBbEJ0SWk5UVN5NE1FVHR5ZUZwSW.....

Decode it :


Get a chunk of video:

  • Scan artist profile link gonna expire in 12h

Check duplicated albums in database. EX: albumid I1umglqa8dMM has 2 performers. Check it out and correct later!

ALBUMS means both videos and songs

Changing resolution of an image: add _640 before the file extension

STATS ~251797 songs, ~26853 albums, ~ 21057+119647 videos on feb 10

Notice: the pair (songid,albumid) gonna be duplicated while updating new albums. Be careful when use it

values={"format":"timed","keyword_id":"615596","clip_id":"67319","artist_name":"Backstreet Boys","song_title":"Backstreet Boys - As Long As You Love Me","page_title":"Backstreet Boys - As Long As You Love Me - YouTube","clip_url":"","request_id":"m2rvh01xuu40a4i_698","duration_ms":219000,"view_count":14100406,"upload_date":"May 25, 2011","extension_version":"1.0.23"}
  • Notice the version value "extension_version":"1.0.23"

  • Get singer list
    METHOD = POST (singer started with 'g')
    LINK =
    FORM = APIKey=23fdffd9fd764cb&ElementID=ArtistsBodyContent&KeywordID=0&ClipID=0&StartingLetter=g& ResultsLimit=0&PlaylistID=21

  • Get artist image
    615354.jpg from artist list

  • Get clip in Artist File
    METHOD = POST // test with GET method
    LINK =
    FORM = APIKey=23fdffd9fd764cb&ElementID=ClipBodyContent&KeywordID=615354&ClipID=0&StartingLetter=&ResultsLimit=-1

Search on google

    url: '',
    data: {
      q: ' ' + title + ' -"Page Ranking Information"'
    dataType: 'jsonp',
    type: 'GET',
    successfunction(googleDatastatus){  //do something  } 

Result example :

Get lyric from file

deviceid : 'chrome_extension'

  • Get mp4 movie
rtmpdump -r "rtmpe://\850.mp4" -W "" -p "" -o film.mp4
rtmpdump -r "rtmpe://\850.mp4" -o film.mp4

first10mPlayed = function(){}


loadVideo function in

SECRET_KEY:String = "secrete123!@#"; MD5.hash((_local3 + this.SECRET_KEY)); for example 217secrete123!@#

  • Get files

1.Decrypt files using RC4 func
2.Get source :
3.If the para lucdebug=true is disable then decrypt the file whose password is HDVN@T@oanL@c
4.Decrypt the m3u8 file using hdviet123#@! EX:


5.Decrypt the files at different resolutions. Ex:


6.Change the relative urls to absolute ones. EX 1280/Deadwood_S02_E001_1280_0.ts to

Note server'll load balances between
7.Play m3u8 file
8.Decode VNese subtiltes using the pass 6e28cec025af4ff790c8337d5190184e

  • Get files

1.use user-agent to fool the server

curl "" --user-agent "Mozilla/5.0 (iPhone; U; CPU iPhone"
curl "" --user-agent "Mozilla/5.0 (iPhone; U; CPU iPhone" --cookie "OAID=db6333b40159517a1a4fbaac928396ab; x_sessionid=fb835813c3b2224da2ea56ebda6ab7ac;"
  1. get eval(function(p,a,c,k,e,d){...} in the script and decode the dean edwards packer
  2. get m3u8 file


Type in CLI, change the directory which contains these files, default is ~/Box Documents/Sites/nodejs

  • To create tables : node createAlbumTable.js add
  • To delete tables : node createAlbumTable.js delete
  • To get all albums from id 1 to id 2: node fetchdatafromNS.js No1 No2
    where No1 is the first Id and No2 is the last EX: node fetchdatafromNS.js 500000 502000 <- can run parallelly 3 programs


Install the couchbase nosql database

Run bin/elasticsearch -f , install plugin on [github>

curl -XPUT 'localhost:9200/_river/ns_song/_meta' -d '{
    "type" : "jdbc",
    "jdbc" : {
        "driver" : "com.mysql.jdbc.Driver",
        "url" : "jdbc:mysql://localhost:8889/anbinh",
        "user" : "root",
        "password" : "root",
        "sql" : "select * from ns_song"
    "index" : {
        "index" : "jdbc",
        "type" : "jdbc"

Notice: ns_song, choose localhost:8889, database anbinh , username root, password root, select all from table ns_song, choose index jdbc and type jdbci