Skip to content

Commit

Permalink
Merge branch 'master' into stable
Browse files Browse the repository at this point in the history
  • Loading branch information
oczkers committed Dec 28, 2016
2 parents ccc0f0a + 83c02dc commit cca9d12
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 37 deletions.
4 changes: 4 additions & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Changelog
---------


0.2.5 (2016-12-28)
++++++++++++++++++
* add timeout (#226)

0.2.4 (2016-12-15)
++++++++++++++++++
* proper(?) page_size and start values correction (thanks to rafaelget #220)
Expand Down
2 changes: 1 addition & 1 deletion fut/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
"""

__title__ = 'fut'
__version__ = '0.2.4'
__version__ = '0.2.5'
__author__ = 'Piotr Staroszczyk'
__author_email__ = 'piotr.staroszczyk@get24.org'
__license__ = 'GNU GPL v3'
Expand Down
5 changes: 3 additions & 2 deletions fut/config.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# chrome 53 @ win10
headers = {
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.71 Safari/537.36',
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/54.0.2840.99 Safari/537.36',
'Accept': 'text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8',
'Accept-Encoding': 'gzip,deflate,sdch',
'Accept-Language': 'en-US,en;q=0.8',
Expand Down Expand Up @@ -36,6 +36,7 @@
# 'X-Requested-With': 'com.ea.fifaultimate_row', # ultimate app identifier?
}

flash_agent = 'ShockwaveFlash/23.0.0.205'
flash_agent = 'ShockwaveFlash/24.0.0.186'

cookies_file = 'cookies.txt'
timeout = 15 # defaulf global timeout
58 changes: 28 additions & 30 deletions fut/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@
except ImportError:
import json

from .config import headers, headers_and, headers_ios, flash_agent, cookies_file
from .config import headers, headers_and, headers_ios, flash_agent, cookies_file, timeout
from .log import logger
from .urls import urls
from .exceptions import (FutError, ExpiredSession, InternalServerError,
Expand Down Expand Up @@ -110,43 +110,43 @@ def cardInfo(resource_id):
"""Return card info."""
# TODO: add referer to headers (futweb)
url = '{0}{1}.json'.format(self.urls['card_info'], baseId(resource_id))
return requests.get(url).json()
return requests.get(url, timeout=timeout).json()
'''


# TODO: optimize messages, xml parser might be faster
def nations():
def nations(timeout=timeout):
"""Return all nations in dict {id0: nation0, id1: nation1}.
:params year: Year.
"""
rc = requests.get(urls('pc')['messages']).text
rc = requests.get(urls('pc')['messages'], timeout=timeout).text
data = re.findall('<trans-unit resname="search.nationName.nation([0-9]+)">\n <source>(.+)</source>', rc)
nations = {}
for i in data:
nations[int(i[0])] = i[1]
return nations


def leagues(year=2017):
def leagues(year=2017, timeout=timeout):
"""Return all leagues in dict {id0: league0, id1: legaue1}.
:params year: Year.
"""
rc = requests.get(urls('pc')['messages']).text
rc = requests.get(urls('pc')['messages'], timeout=timeout).text
data = re.findall('<trans-unit resname="global.leagueFull.%s.league([0-9]+)">\n <source>(.+)</source>' % year, rc)
leagues = {}
for i in data:
leagues[int(i[0])] = i[1]
return leagues


def teams(year=2017):
def teams(year=2017, timeout=timeout):
"""Return all teams in dict {id0: team0, id1: team1}.
:params year: Year.
"""
rc = requests.get(urls('pc')['messages']).text
rc = requests.get(urls('pc')['messages'], timeout=timeout).text
data = re.findall('<trans-unit resname="global.teamFull.%s.team([0-9]+)">\n <source>(.+)</source>' % year, rc)
teams = {}
for i in data:
Expand All @@ -155,9 +155,10 @@ def teams(year=2017):


class Core(object):
def __init__(self, email, passwd, secret_answer, platform='pc', code=None, emulate=None, debug=False, cookies=cookies_file):
def __init__(self, email, passwd, secret_answer, platform='pc', code=None, emulate=None, debug=False, cookies=cookies_file, timeout=timeout):
self.credits = 0
self.cookies_file = cookies # TODO: map self.cookies to requests.Session.cookies?
self.timeout = timeout
if debug: # save full log to file (fut.log)
self.logger = logger(save=True)
else: # NullHandler
Expand All @@ -178,7 +179,6 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
# TODO: split into smaller methods
# TODO: check first if login is needed (https://www.easports.com/fifa/api/isUserLoggedIn)
# TODO: get gamesku, url from shards !!
print("INFO: Two more issues has been found and fixed (#219, #220). Please report all bans to help protect others https://github.com/oczkers/fut/issues/216")
self.emulate = emulate
secret_answer_hash = EAHashingAlgorithm().EAHash(secret_answer)
# create session
Expand Down Expand Up @@ -212,7 +212,7 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
platform = 'ps3' # ps4 not available?
else:
raise FutError(reason='Wrong platform. (Valid ones are pc/xbox/xbox360/ps3/ps4)')
# if self.r.get(self.urls['main_site']+'/fifa/api/isUserLoggedIn').json()['isLoggedIn']:
# if self.r.get(self.urls['main_site']+'/fifa/api/isUserLoggedIn', timeout=timeout).json()['isLoggedIn']:
# return True # no need to log in again
# emulate
if emulate == 'ios':
Expand All @@ -237,22 +237,22 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
else:
raise FutError(reason='Invalid emulate parameter. (Valid ones are and/ios).') # pc/ps3/xbox/
# === login
self.urls['login'] = self.r.get(self.urls['fut_home']).url
self.urls['login'] = self.r.get(self.urls['fut_home'], timeout=timeout).url
self.r.headers['Referer'] = self.urls['login'] # prepare headers
data = {'email': email,
'password': passwd,
'_rememberMe': 'on',
'rememberMe': 'on',
'_eventId': 'submit'}
rc = self.r.post(self.urls['login'], data=data)
rc = self.r.post(self.urls['login'], data=data, timeout=self.timeout)
self.logger.debug(rc.content)

''' # pops out only on first launch
if 'FIFA Ultimate Team</strong> needs to update your Account to help protect your gameplay experience.' in rc.text: # request email/sms code
self.r.headers['Referer'] = rc.url # s2
rc = self.r.post(rc.url.replace('s2', 's3'), {'_eventId': 'submit'}).content
rc = self.r.post(rc.url.replace('s2', 's3'), {'_eventId': 'submit'}, timeout=self.timeout).content
self.r.headers['Referer'] = rc.url # s3
rc = self.r.post(rc.url, {'twofactorType': 'EMAIL', 'country': 0, 'phoneNumber': '', '_eventId': 'submit'}
rc = self.r.post(rc.url, {'twofactorType': 'EMAIL', 'country': 0, 'phoneNumber': '', '_eventId': 'submit'}, timeout=self.timeout)
'''
if 'We sent a security code to your' in rc.text or 'Your security code was sent to' in rc.text or 'Enter the 6-digit verification code' in rc.text: # post code
# TODO: 'We sent a security code to your email' / 'We sent a security code to your ?'
Expand All @@ -263,23 +263,23 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
self.r.headers['Referer'] = url = rc.url
# self.r.headers['Upgrade-Insecure-Requests'] = 1 # ?
# self.r.headers['Origin'] = 'https://signin.ea.com'
rc = self.r.post(url, {'twofactorCode': code, '_trustThisDevice': 'on', 'trustThisDevice': 'on', '_eventId': 'submit'}).text
rc = self.r.post(url, {'twofactorCode': code, '_trustThisDevice': 'on', 'trustThisDevice': 'on', '_eventId': 'submit'}, timeout=self.timeout).text
if 'Incorrect code entered' in rc or 'Please enter a valid security code' in rc:
raise FutError(reason='Error during login process - provided code is incorrect.')
self.logger.debug(rc)
if 'Set Up an App Authenticator' in rc:
rc = self.r.post(url.replace('s2', 's3'), {'_eventId': 'cancel', 'appDevice': 'IPHONE'}).text
rc = self.r.post(url.replace('s2', 's3'), {'_eventId': 'cancel', 'appDevice': 'IPHONE'}, timeout=self.timeout).text
self.logger.debug(rc)

self.r.headers['Referer'] = self.urls['login']
if self.r.get(self.urls['main_site'] + '/fifa/api/isUserLoggedIn').json()['isLoggedIn'] is not True: # TODO: parse error?
if self.r.get(self.urls['main_site'] + '/fifa/api/isUserLoggedIn', timeout=self.timeout).json()['isLoggedIn'] is not True: # TODO: parse error?
raise FutError(reason='Error during login process (probably invalid email, password or code).')
# TODO: catch invalid data exception
# self.nucleus_id = re.search('userid : "([0-9]+)"', rc.text).group(1) # we'll get it later

# === lanuch futweb
self.r.headers['Referer'] = self.urls['fut_home'] # prepare headers
rc = self.r.get(self.urls['futweb'])
rc = self.r.get(self.urls['futweb'], timeout=self.timeout)
self.logger.debug(rc.content)
rc = rc.text
# if 'EASW_ID' not in rc:
Expand All @@ -301,7 +301,7 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
'X-UT-Route': self.urls['fut_host'],
'Referer': self.urls['futweb'],
})
rc = self.r.get(self.urls['acc_info'], params={'_': int(time() * 1000)})
rc = self.r.get(self.urls['acc_info'], params={'_': int(time() * 1000)}, timeout=self.timeout)
self.logger.debug(rc.content)
# pick persona (first valid for given game_sku)
personas = rc.json()['userAccountInfo']['personas']
Expand Down Expand Up @@ -332,7 +332,7 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
'method': 'authcode',
'priorityLevel': 4,
'identification': {'AuthCode': ''}}
rc = self.r.post(self.urls['fut']['authentication'], data=json.dumps(data))
rc = self.r.post(self.urls['fut']['authentication'], data=json.dumps(data), timeout=self.timeout)
self.logger.debug(rc.content)
if rc.status_code == 500:
raise InternalServerError('Servers are probably temporary down.')
Expand All @@ -351,14 +351,14 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
# validate (secret question)
self.r.headers['Accept'] = 'text/json' # prepare headers
del self.r.headers['Origin']
rc = self.r.get(self.urls['fut_question'], params={'_': int(time() * 1000)})
rc = self.r.get(self.urls['fut_question'], params={'_': int(time() * 1000)}, timeout=self.timeout)
self.logger.debug(rc.content)
rc = rc.json()
if rc.get('string') != 'Already answered question.':
# answer question
data = {'answer': secret_answer_hash}
self.r.headers['Content-Type'] = 'application/x-www-form-urlencoded' # requests bug?
rc = self.r.post(self.urls['fut_validate'], data=data)
rc = self.r.post(self.urls['fut_validate'], data=data, timeout=self.timeout)
self.logger.debug(rc.content)
rc = rc.json()
if rc['string'] != 'OK': # we've got error
Expand Down Expand Up @@ -396,7 +396,7 @@ def __login__(self, email, passwd, secret_answer, platform='pc', code=None, emul
# """Returns shards info."""
# # TODO: headers
# self.r.headers['X-UT-Route'] = self.urls['fut_base']
# return self.r.get(self.urls['shards'], params={'_': int(time()*1000)}).json()
# return self.r.get(self.urls['shards'], params={'_': int(time()*1000)}, timeout=self.timeout).json()
# # self.r.headers['X-UT-Route'] = self.urls['fut_pc']

def __request__(self, method, url, *args, **kwargs):
Expand All @@ -408,7 +408,7 @@ def __request__(self, method, url, *args, **kwargs):
# TODO: update credtis?
self.r.headers['X-HTTP-Method-Override'] = method.upper()
self.logger.debug("request: {0} args={1}; kwargs={2}".format(url, args, kwargs))
rc = self.r.post(url, *args, **kwargs)
rc = self.r.post(url, timeout=self.timeout, *args, **kwargs)
self.logger.debug("response: {0}".format(rc.content))
if not rc.ok: # status != 200
raise UnknownError(rc.content)
Expand All @@ -433,7 +433,7 @@ def __request__(self, method, url, *args, **kwargs):
elif err_code == '461' or err_string == 'Permission Denied':
raise PermissionDenied(err_code, err_reason, err_string)
elif err_code == '459' or err_string == 'Captcha Triggered':
# img = self.r.get(self.urls['fut_captcha_img'], params={'_': int(time()*1000), 'token': captcha_token}).content # doesnt work - check headers
# img = self.r.get(self.urls['fut_captcha_img'], params={'_': int(time()*1000), 'token': captcha_token}, timeout=self.timeout).content # doesnt work - check headers
img = None
raise Captcha(err_code, err_reason, err_string, captcha_token, img)
elif err_code == '409' or err_string == 'Conflict':
Expand Down Expand Up @@ -493,7 +493,7 @@ def logout(self, save=True):
:params save: False if You don't want to save cookies.
"""
self.r.get('https://www.easports.com/fifa/logout')
self.r.get('https://www.easports.com/fifa/logout', timeout=self.timeout)
if save:
self.saveSession()
return True
Expand Down Expand Up @@ -539,7 +539,7 @@ def cardInfo(self, resource_id):
"""
# TODO: add referer to headers (futweb)
url = '{0}{1}.json'.format(self.urls['card_info'], baseId(resource_id))
return requests.get(url).json()
return requests.get(url, timeout=self.timeout).json()

def searchDefinition(self, asset_id, start=0, count=35):
"""Return variations of the given asset id, e.g. IF cards.
Expand Down Expand Up @@ -845,5 +845,3 @@ def messageDelete(self, message_id):
"""
url = '{0}/{1}'.format(self.urls['fut']['ActiveMessage'], message_id)
self.__delete__(url)

print("INFO: Two more issues has been found and fixed (#219, #220). Please report all bans to help protect others https://github.com/oczkers/fut/issues/216")
9 changes: 8 additions & 1 deletion fut/exceptions.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,10 @@ class UnknownError(FutError):
https://github.com/oczkers/fut/issues/24"""


class Timeout(FutError):
"""Request timeout, looks like ea servers are down."""


class ExpiredSession(FutError):
"""Session has expired,
you should send at least one request every ~10 minutes."""
Expand Down Expand Up @@ -56,7 +60,10 @@ class PermissionDenied(FutError):

class Captcha(FutError):
"""[459] Captcha Triggered."""
def __init__(self, token=None, img=None):
def __init__(self, code=None, reason=None, string=None, token=None, img=None):
self.code = code
self.reason = reason
self.string = string
self.token = token
self.img = img

Expand Down
5 changes: 3 additions & 2 deletions fut/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,14 @@
import requests
import xmltodict

from .config import timeout
from .exceptions import FutError


def __updateUrls__(urls, cl):
"""Get services urls."""
urls['fut_config'] = '%s?cl=%s' % (urls['fut_config'], cl)
rc = xmltodict.parse(requests.get(urls['fut_config']).content)
rc = xmltodict.parse(requests.get(urls['fut_config'], timeout=timeout).content)
services = rc['main']['services']['prod']
path = '{0}{1}game/fifa17/'.format(urls['fut_host'], rc['main']['directHttpServiceDestination'])
path_auth = '{0}/iframe/fut17{1}'.format(urls['main_site'], rc['main']['httpServiceDestination'])
Expand Down Expand Up @@ -47,7 +48,7 @@ def urls(platform, cl=None):
'card_info': 'https://fifa17.content.easports.com/fifa/fltOnlineAssets/CC8267B6-0817-4842-BB6A-A20F88B05418/2017/fut/items/web/',
'messages': 'https://www.easports.com/iframe/fut17/bundles/futweb/web/flash/xml/localization/messages.en_US.xml', # add cl
}
# urls['login'] = requests.get(urls['fut_home']).url
# urls['login'] = requests.get(urls['fut_home'], timeout=timeout).url

if platform in urls['fut_host']:
urls['fut_host'] = urls['fut_host'][platform]
Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@


__title__ = 'fut'
__version__ = '0.2.4'
__version__ = '0.2.5'
__author__ = 'Piotr Staroszczyk'
__author_email__ = 'piotr.staroszczyk@get24.org'
__license__ = 'GNU GPL v3'
Expand Down

0 comments on commit cca9d12

Please sign in to comment.