· 10 years ago · Apr 07, 2016, 01:15 PM
1import base64
2import csv
3import hashlib
4import json
5import lxml.html
6import random
7import requests
8import time
9import os.path
10
11
12class MusicallyFame:
13 phone_profiles = [
14 "lava",
15 "samsung",
16 "oneplusone",
17 "htc",
18 "nexus"
19 ]
20 phone_details = {
21 "lava": {
22 "os": "android 4.1.2",
23 "User-Agent": "Musical.ly/2016020601 (Android; LAVA LAVA 4.1.2;rv:16)",
24 "build": "2016020601",
25 "mobile": "LAVA Iris 501",
26 "model": "SM-G730V",
27 "sdk": "19"
28 },
29 "samsung": {
30 "os": "android 5.1.1",
31 "User-Agent": "Musical.ly/2016040101 (Android; Samsung Galaxy J3 5.1.1;rv:22)",
32 "build": "2016040101",
33 "mobile": "Samsung Galaxy J3 SM-J320Y",
34 "model": "SM-J320Y",
35 "sdk": "22"
36 },
37 "oneplusone": {
38 "os": "android 5.1.1",
39 "User-Agent": "Musical.ly/2016040101 (Android; OnePlus A0001 5.1.1;rv:22)",
40 "build": "2016040101",
41 "mobile": "OnePlus A0001",
42 "model": "A0001",
43 "sdk": "22"
44 },
45 "nexus": {
46 "os": "android 6.0.1",
47 "User-Agent": "Musical.ly/2016040101 (Android; LGE Nexus 5 6.0.1;rv:23)",
48 "build": "2016040101",
49 "mobile": "LGE Nexus 5",
50 "model": "Nexus 5",
51 "sdk": "22"
52 },
53 "htc": {
54 "os": "android 5.1.1",
55 "User-Agent": "Musical.ly/2016040101 (Android; HTC One A9 5.1.1;rv:22)",
56 "build": "2016040101",
57 "mobile": "HTC One A9",
58 "model": "A9",
59 "sdk": "22"
60 },
61 }
62
63 def __init__(self, input_file):
64 """
65 Constructor of the class
66 :param input_file:
67 """
68 self.proxies = self.proxy_list()
69 self.input_file = input_file
70 self.common_header = {
71 "os": "android 4.1.2",
72 "User-Agent": "Musical.ly/2016020601 (Android; LAVA LAVA 4.1.2;rv:16)",
73 "build": "2016020601",
74 "mobile": "LAVA Iris 501",
75 "version": "4.7.5",
76 "X-Requested-With": "XMLHttpRequest",
77 "language": "en_US",
78 "Connection": "close",
79 "network": "WiFi",
80 "Host": "www.musical.ly",
81 "Accept-Encoding": "gzip",
82 "MIME-Version": "1.0"
83 }
84 self.signing_server = "http://45.55.203.163:8888/sign"
85 self.signature_data = {
86 "app": {
87 "-r": "Gvt1",
88 "os": "android 4.1.2",
89 "version": "4.7.5"
90 },
91 "ostype": "and",
92 "imei": "51a4454f",
93 "mac": "4C:3C:16:82:EE:F3",
94 "model": "SM-G730V",
95 "sdk": "19",
96 }
97 self.session = requests.Session()
98
99 def proxy_list(self):
100 """
101 :return: List of Proxies
102 """
103 content = requests.get("http://free-proxy-list.net").text
104 doc = lxml.html.document_fromstring(content)
105 lines = doc.cssselect('table.fpltable tr')
106 temp_proxies = []
107 for line in lines:
108 tds = line.cssselect('td')
109 if not tds:
110 continue
111 anonymity = tds[4].text
112 if anonymity == 'elite proxy' and len(tds) > 7:
113 temp_proxies.append({
114 'ip_address': tds[0].text,
115 'port': tds[1].text,
116 'country_code': tds[2].text,
117 })
118 print len(temp_proxies)
119
120 return temp_proxies
121
122 def alter_handle(self, handle, alter_option=random.choice((1, 2, 3))):
123 """
124 :param handle:
125 :param alter_option:
126 :return: Altered Handle
127 """
128 if alter_option == 1:
129 handle += random.choice([str(n) for n in range(10)])
130 elif alter_option == 2:
131 _, __ = handle[-1], handle[-2]
132 handle = handle[:-3] + _ + __
133 else:
134 handle = handle[:-1]
135
136 return handle
137
138 def generate_user(self):
139 """
140 :return: Generator for User
141 """
142 mail_servers = ["@newmail.com", "@gmail.com", "@hotmail.com", "@yahoo.com", "@outlook.com"]
143 with open(self.input_file, "rb") as csvfile:
144 reader = csv.reader(csvfile)
145 reader.next() # Skip the header row
146 for row in reader:
147 scraped_data = dict()
148 scraped_data["country"] = row[0].decode('string-escape').decode("utf-8")
149 scraped_data["nick_name"] = row[2].decode('string-escape').decode("utf-8")
150 scraped_data["photo"] = "./photos"+row[3]+".jpg"
151
152 handle = row[3].decode('string-escape').decode("utf-8")
153 scraped_data["handle"] = self.alter_handle(handle)
154 scraped_data["bio"] = row[4].decode('string-escape').decode("utf-8")
155 if scraped_data["bio"] == "n/a":
156 scraped_data["bio"] = "live with passion, live musical.ly"
157 scraped_data["email"] = scraped_data["handle"]+random.choice(mail_servers)
158 scraped_data["password"] = scraped_data["handle"][::-1]+random.choice(["1", "2", "3", "4", "5"])
159 yield scraped_data
160
161 def get_likes(self, account, like_counts):
162 return
163
164 def get_follows(self, account, follow_counts):
165 return
166
167 def set_phone(self, phone):
168 """
169 :param phone:
170 """
171 # Random value for imei and mac no
172 imei = ''.join(random.choice('0123456789abcdef') for i in range(8))
173 val = ''.join(random.choice('0123456789ABCDEF') for i in range(12))
174 mac = ':'.join(val[i:i+2] for i in xrange(0, 12, 2))
175 self.signature_data["imei"] = imei
176 self.signature_data["mac"] = mac
177
178 if phone in self.phone_profiles:
179 self.common_header["os"] = self.phone_details[phone]["os"]
180 self.common_header["User-Agent"] = self.phone_details[phone]["User-Agent"]
181 self.common_header["build"] = self.phone_details[phone]["build"]
182 self.common_header["mobile"] = self.phone_details[phone]["mobile"]
183
184 self.signature_data["app"]["os"] = self.phone_details[phone]["os"]
185 self.signature_data["model"] = self.phone_details[phone]["model"]
186 self.signature_data["sdk"] = self.phone_details[phone]["sdk"]
187
188 def get_proxy(self, country):
189 """
190 :param country:
191 :return: Proxy or False
192 """
193 if not self.proxies:
194 self.proxies = self.proxy_list()
195
196 temp_proxies = list(self.proxies)
197 retries = 0
198
199 for proxy in temp_proxies:
200 if proxy['country_code'] == country:
201 address = "%s:%s" % (proxy['ip_address'], proxy['port'])
202 self.proxies.remove(proxy)
203 try:
204 _proxy = {"http": "http://"+address, "https": "https://"+address, "ftp":"ftp://"+address}
205 response = self.session.get("http://ipecho.net/plain", proxies=_proxy)
206 if address.split(':')[0] == response.text:
207 return _proxy
208
209 raise Exception()
210 except:
211 print 'get error, when checking proxy, try to get next proxy'
212 retries += 1
213 if retries == 5:
214 self.proxy_list()
215
216 if retries == 10:
217 break
218
219 return False
220
221 def unset_proxy(self):
222 self.session.proxies = None
223
224 def get_signature(self):
225 """
226 :return: Signature
227 """
228 payload = {"data": json.dumps(self.signature_data)}
229 response = self.session.get(self.signing_server, data=payload)
230 try:
231 return str(json.loads(response.text)["signature"])
232 except ValueError:
233 return "signature not received"
234
235 def get_unique_id(self):
236 """
237 Id Generator
238 :return: id
239 """
240 request_id = hashlib.md5(str(random.random())).hexdigest()
241 request_id = request_id[:8]+"-"+request_id[8:12]+"-"+request_id[12:16]+"-"+request_id[16:20]+"-"+request_id[20:]
242 return request_id
243
244 def get_time_stamp(self):
245 """
246 :return: time stamp
247 """
248 a = time.time()*1000
249 return "%.0f" % a
250
251 def prepare_header(self, url, method):
252 """
253 :param url:
254 :param method:
255 """
256 request_id = self.get_unique_id()
257 timestamp = self.get_time_stamp()
258 self.session.headers.clear()
259 self.session.headers = dict(self.common_header)
260 self.session.headers["X-Request-ID"] = request_id
261 if "register" in url or "login.do" in url:
262 self.signature_data["app"].pop("slider-show-cookie", None)
263 self.signature_data["app"]["-r"] = ''.join(random.choice('0123456789abcdefGHIJSTUVW') for i in range(4))
264 self.signature_data["app"]["X-Request-ID"] = request_id
265 self.signature_data["serviceTime"] = timestamp
266 self.signature_data["app"]["method"] = method
267 self.signature_data["app"]["url"] = url
268 request_signature = self.get_signature()
269 self.session.headers["X-Request-Sign2"] = request_signature
270
271 def prepare_registration_data(self, handle, email, password):
272 """
273 :param handle:
274 :param email:
275 :param password:
276 :return: registration data
277 """
278 user = str({
279 "handle": handle,
280 "email": email,
281 "password": password
282 })
283 boundary = "27c8b11a-9b7e-4849-a665-7f1a04edf2b7"
284 data = (
285 """
286--%(boundary)s
287Content-Disposition: form-data; name="user"
288Content-Type: application/json; charset=utf-8
289Content-Length: %(content_length)s
290\r\n%(user)s
291--%(boundary)s--
292 """ % {
293 "boundary": boundary,
294 "content_length": len(user),
295 "user": user
296 }).replace("\n", "\r\n") # HTTP uses DOS-style line endings.
297
298 # update current headers
299 self.session.headers["Content-Type"] = "multipart/mixed; boundary=\"%s\"" % boundary
300 return data
301
302 def prepare_profile_data(self, user_setting_dto, bio, gender, handle, nick_name, user_id):
303 """
304 :param user_setting_dto:
305 :param bio:
306 :param gender:
307 :return: registration data
308 """
309 user = str({
310 "userSettingDTO": user_setting_dto,
311 "instagramID": handle,
312 "userDesc": bio,
313 "gender": gender,
314 "handle": handle,
315 "nickName": nick_name,
316 "userId": user_id
317 })
318 data = (
319 """
320--2b8a2224-07c6-4463-bb4b-364576e556ad
321Content-Disposition: form-data; name="user"
322Content-Type: application/json; charset=utf-8
323Content-Length: %(content_length)s
324\r\n%(user)s
325--2b8a2224-07c6-4463-bb4b-364576e556ad--
326 """ % {
327 "content_length": len(user),
328 "user": user
329 }).replace("\n", "\r\n")
330 self.session.headers["Content-Type"] = '''multipart/mixed; boundary="2b8a2224-07c6-4463-bb4b-364576e556ad"'''
331 return data
332
333 def register_accounts(self, count):
334 # output_fp = open('success.csv', 'w')
335 # output_writer = csv.writer(output_fp, delimiter=',')
336
337 all_users = self.generate_user()
338 for i in xrange(count):
339 user_data = all_users.next()
340 self.set_phone(random.choice(self.phone_profiles))
341 country = user_data["country"]
342 proxy = self.get_proxy(country)
343 if not proxy:
344 proxy = self.get_proxy("US")
345
346 if not proxy:
347 continue
348
349 # method = "POST"
350 # url = "https://www.musical.ly/rest/v2/users/register"
351 # self.prepare_header(url, method)
352 # handle = user_data["handle"]
353 # email = user_data["email"]
354 # password = user_data["password"]
355 # data = self.prepare_registration_data(handle, email, password)
356
357 try:
358 # self.session.proxies = proxy
359 # response = self.session.post(url, data=data, proxies=proxy, headers=self.session.headers)
360 # print response.content
361 # print response.status_code
362 # profile edit
363 # if response.status_code == 200:
364 if True:
365 # response_status = response.json().get('success', False)
366 # if response_status:
367 if True:
368 # output_writer.writerow([handle, password, email])
369 # handle, password = 'test20krishna', 'notsaying'
370 handle, password = 'nerearosa', 'asoraeren1'
371 args = {
372 "username": "@"+handle,
373 "password": password,
374 "remember_me": "on"
375 }
376 login_url = "https://www.musical.ly/v2/login.do"
377 self.prepare_header(login_url, "POST")
378 self.session.proxies = proxy
379 response = self.session.post(login_url, params=args, headers=self.session.headers, proxies=proxy)
380 print response.content
381 print response.status_code
382 if response.status_code == 200:
383 response_status = response.json().get('success', False)
384 if response_status:
385 self.signature_data["app"].pop("-r",None)
386 self.signature_data["app"]["slider-show-cookie"] = self.session.cookies["SLIDER_SHOW_COOKIE"]
387 user_setting_dto = json.dumps(response.json()["result"]["userSettingDTO"])
388 gender = response.json()["result"]["gender"]
389 user_id = response.json()["result"]["userId"]
390 bio = user_data["bio"]
391 nick_name = user_data["nick_name"].decode('string-escape').decode("utf-8")
392 edit_url = "https://www.musical.ly/rest/v2/users/edit"
393 self.prepare_header(edit_url, "POST")
394 data = self.prepare_profile_data(user_setting_dto, bio, gender, handle, nick_name, user_id)
395 self.session.proxies = proxy
396 response = self.session.post(edit_url, headers=self.session.headers, data=data, proxies=proxy)
397 if response.status_code == 200:
398 response_status = response.json().get('success', False)
399 if response_status:
400 # Upload Photo
401 photo = user_data["photo"]
402 photo_data = open(photo, 'rb').read()
403 if not os.path(photo):
404 continue
405 post_photo_url = "https://www.musical.ly/rest/v2/users/signIcon"
406 payload = {
407 "endpoint": None,
408 "headers": None,
409 "length": len(photo_data),
410 "md5": base64.b64decode(hashlib.md5(photo_data.digest())),
411 "method": None,
412 "parameters": None,
413 "presignedUrl": None,
414 "resourcePath": None
415 }
416
417 self.prepare_header(post_photo_url, "POST")
418 self.session.headers["Content-Type"] = "application/json; charset=utf-8"
419 response = self.session.post(post_photo_url, data=json.dumps(payload))
420 if response.status_code == 200:
421 response_status = response.json().get('success', False)
422 if response_status:
423 put_photo_url = response.json()["result"]["endpoint"] + "/" + response.json()["result"]["resourcePath"]
424 self.prepare_header(put_photo_url, "PUT")
425 self.session.headers = response.json()["result"]["headers"]
426 with open(photo, "rb") as image_file:
427 encoded_string = base64.b64encode(image_file.read())
428 response = self.session.put(put_photo_url, data = encoded_string, proxies = proxy)
429 change_photo_url = "https://www.musical.ly/rest/v2/users/changeIcon"
430 prepare_header(change_photo_url, "POST")
431 payload = {"icon": put_photo_url}
432 response = session.post(change_photo_url, data = payload)
433
434
435 except Exception, e:
436 print proxy
437 print self.session.proxies
438 print e
439 self.session.cookies.clear()
440 self.unset_proxy()
441 pass
442
443 self.session.cookies.clear()
444 self.unset_proxy()
445
446 # output_fp.close()
447
448
449if __name__ == '__main__':
450 magic_obj = MusicallyFame('L760pSXT.txt')
451 magic_obj.register_accounts(1)