diff --git a/modules/okc/backend.py b/modules/okc/backend.py index 6f18fde6..e5c3339d 100644 --- a/modules/okc/backend.py +++ b/modules/okc/backend.py @@ -30,14 +30,13 @@ from dateutil.parser import parse as _parse_dt from weboob.capabilities.base import NotLoaded from weboob.capabilities.messages import ICapMessages, ICapMessagesPost, Message, Thread #from weboob.capabilities.dating import ICapDating, OptimizationNotFound, Event -#from weboob.capabilities.contact import ICapContact, ContactPhoto, Query, QueryError +from weboob.capabilities.contact import ICapContact, ContactPhoto, Query, QueryError from weboob.tools.backend import BaseBackend, BackendConfig from weboob.tools.browser import BrowserUnavailable from weboob.tools.value import Value, ValuesDict, ValueBool, ValueBackendPassword from weboob.tools.log import getLogger from weboob.tools.misc import local2utc -#from .contact import Contact from .browser import OkCBrowser @@ -63,7 +62,7 @@ def parse_dt(s): d = _parse_dt(s) return local2utc(d) -class OkCBackend(BaseBackend, ICapMessages): +class OkCBackend(BaseBackend, ICapMessages, ICapContact): #, ICapMessagesPost, ICapContact): NAME = 'okc' MAINTAINER = 'Roger Philibert' @@ -133,9 +132,6 @@ class OkCBackend(BaseBackend, ICapMessages): if not thread.title: thread.title = u'Discussion with %s' % mails['member']['pseudo'] - #self.storage.set('sluts', thread.id, 'status', mails['status']) - #self.storage.save() - for mail in mails['messages']: flags = Message.IS_HTML if parse_dt(mail['date']) > slut['lastmsg'] and mail['id_from'] != self.browser.get_my_name(): @@ -233,18 +229,18 @@ class OkCBackend(BaseBackend, ICapMessages): # ---- ICapContact methods --------------------- - #def fill_contact(self, contact, fields): - # if 'profile' in fields: - # contact = self.get_contact(contact) - # if contact and 'photos' in fields: - # for name, photo in contact.photos.iteritems(): - # with self.browser: - # if photo.url and not photo.data: - # data = self.browser.openurl(photo.url).read() - # contact.set_photo(name, data=data) - # if photo.thumbnail_url and not photo.thumbnail_data: - # data = self.browser.openurl(photo.thumbnail_url).read() - # contact.set_photo(name, thumbnail_data=data) + def fill_contact(self, contact, fields): + if 'profile' in fields: + contact = self.get_contact(contact) + if contact and 'photos' in fields: + for name, photo in contact.photos.iteritems(): + with self.browser: + if photo.url and not photo.data: + data = self.browser.openurl(photo.url).read() + contact.set_photo(name, data=data) + if photo.thumbnail_url and not photo.thumbnail_data: + data = self.browser.openurl(photo.thumbnail_url).read() + contact.set_photo(name, thumbnail_data=data) #def fill_photo(self, photo, fields): # with self.browser: @@ -254,29 +250,37 @@ class OkCBackend(BaseBackend, ICapMessages): # photo.thumbnail_data = self.browser.readurl(photo.thumbnail_url) # return photo - #def get_contact(self, contact): - # with self.browser: - # if isinstance(contact, Contact): - # _id = contact.id - # elif isinstance(contact, (int,long,basestring)): - # _id = contact - # else: - # raise TypeError("The parameter 'contact' isn't a contact nor a int/long/str/unicode: %s" % contact) + def get_contact(self, contact): + with self.browser: + if isinstance(contact, Contact): + _id = contact.id + elif isinstance(contact, (int,long,basestring)): + _id = contact + else: + raise TypeError("The parameter 'contact' isn't a contact nor a int/long/str/unicode: %s" % contact) - # profile = self.browser.get_profile(_id) - # if not profile: - # return None + profile = self.browser.get_profile(_id) + if not profile: + return None - # _id = profile['id'] + _id = profile['id'] - # if isinstance(contact, Contact): - # contact.id = _id - # contact.name = profile['pseudo'] - # else: - # contact = Contact(_id, profile['pseudo'], Contact.STATUS_ONLINE) - # contact.url = self.browser.id2url(_id) - # contact.parse_profile(profile, self.browser.get_consts()) - # return contact + if isinstance(contact, Contact): + contact.id = _id + contact.name = profile['id'] + else: + contact = Contact(_id, profile['id'], Contact.STATUS_OFFLINE) + contact.url = 'http://%s/profile/%s' % (self.browser.DOMAIN, _id) + contact.profile = profile['data'] + contact.summary = profile['summary'] + + if contact.profile['details']['last_online'].value == 'Online now!': + contact.status = Contact.STATUS_ONLINE + else: + contact.status = Contact.STATUS_OFFLINE + contact.status_msg = contact.profile['details']['last_online'].value + + return contact #def _get_partial_contact(self, contact): # if contact.get('isBan', contact.get('dead', False)): @@ -290,7 +294,7 @@ class OkCBackend(BaseBackend, ICapMessages): # else: # s = Contact.STATUS_OFFLINE - # c = Contact(contact['id'], contact['pseudo'], s) + # c = Contact(contact['id'], contact['id'], s) # c.url = self.browser.id2url(contact['id']) # if 'birthday' in contact: # birthday = _parse_dt(contact['birthday']) @@ -306,14 +310,14 @@ class OkCBackend(BaseBackend, ICapMessages): # thumbnail_url=url % {'type': 'thumb0_'}) # return c - #def iter_contacts(self, status=Contact.STATUS_ALL, ids=None): - # with self.browser: - # threads = self.browser.get_threads_list(count=100) + def iter_contacts(self, status=Contact.STATUS_ALL, ids=None): + with self.browser: + threads = self.browser.get_threads_list(count=100) - # for thread in threads: - # c = self._get_partial_contact(thread['member']) - # if c and (c.status & status) and (not ids or c.id in ids): - # yield c + for thread in threads: + c = self._get_partial_contact(thread['member']) + if c and (c.status & status) and (not ids or c.id in ids): + yield c #def send_query(self, id): # if isinstance(id, Contact): @@ -350,6 +354,6 @@ class OkCBackend(BaseBackend, ICapMessages): # self.storage.save() OBJECTS = {Thread: fill_thread, - #Contact: fill_contact, + Contact: fill_contact, #ContactPhoto: fill_photo } diff --git a/modules/okc/browser.py b/modules/okc/browser.py index 3b0e6d5c..1b99585e 100644 --- a/modules/okc/browser.py +++ b/modules/okc/browser.py @@ -32,7 +32,7 @@ except ImportError: from weboob.tools.browser import BaseBrowser, BrowserIncorrectPassword, BrowserUnavailable from weboob.tools.ordereddict import OrderedDict -from .pages import LoginPage, ThreadPage, MessagesPage +from .pages import LoginPage, ThreadPage, MessagesPage, ProfilePage __all__ = ['OkCBrowser'] @@ -48,6 +48,7 @@ class OkCBrowser(BaseBrowser): ('https://%s/login.*' % DOMAIN, LoginPage), ('http://%s/messages' % DOMAIN, ThreadPage), ('http://%s/messages\?.*' % DOMAIN, MessagesPage), + ('http://%s/profile/.*' % DOMAIN, ProfilePage), )) @@ -71,7 +72,8 @@ class OkCBrowser(BaseBrowser): return func(self, *args, **kwargs) return inner - #def get_consts(self): + def get_consts(self): + return { 'conts' : 'blah' } # if self.consts is not None: # return self.consts @@ -197,39 +199,10 @@ class OkCBrowser(BaseBrowser): # ids = [s['id'] for s in r['result']['search']] # return set(ids) - #@url2id - #def get_profile(self, id, with_pics=True): - # r = self.api_request('member', 'view', data={'id': id}) - # if not 'result' in r: - # print r - # profile = r['result']['member'] - - - # # Calculate distance in km. - # profile['dist'] = 0.0 - # if 'lat' in profile and 'lng' in profile: - # coords = (float(profile['lat']), float(profile['lng'])) - - # R = 6371 - # lat1 = math.radians(self.my_coords[0]) - # lat2 = math.radians(coords[0]) - # lon1 = math.radians(self.my_coords[1]) - # lon2 = math.radians(coords[1]) - # dLat = lat2 - lat1 - # dLong = lon2 - lon1 - # a= pow(math.sin(dLat/2), 2) + math.cos(lat1) * math.cos(lat2) * pow(math.sin(dLong/2), 2) - # c= 2 * math.atan2(math.sqrt(a), math.sqrt(1-a)) - # profile['dist'] = R * c - - # if with_pics: - # r = self.api_request('member', 'pictures', data={'id': id}) - # profile['pictures'] = [] - # for pic in r['result']['pictures']: - # d = {'hidden': False} - # d.update(pic) - # profile['pictures'].append(d) - - # return profile + @check_login + def get_profile(self, id, with_pics=True): + self.location(self.absurl('/profile/%s' % id)) + return self.page.get_profile() #def _get_chat_infos(self): # try: diff --git a/modules/okc/pages.py b/modules/okc/pages.py index 2a7eca68..4be4e4ae 100644 --- a/modules/okc/pages.py +++ b/modules/okc/pages.py @@ -19,6 +19,9 @@ from weboob.tools.browser import BasePage, BrokenPageError +from weboob.tools.ordereddict import OrderedDict +from weboob.tools.misc import html2text +from weboob.capabilities.contact import ProfileNode class LoginPage(BasePage): def login(self, username, password): @@ -64,3 +67,65 @@ class MessagesPage(BasePage): }) return mails + +class ProfilePage(BasePage): + def get_profile(self): + title = self.parser.select(self.document.getroot(), 'title', 1) + if title.text == 'OkCupid: Account Not Found': + return None + + profile = {} + profile['id'] = title.text[len('OkCupid: '):] + profile['data'] = OrderedDict() + + profile_p = self.parser.select(self.document.getroot(), "//div[@id='page_content']//p", method='xpath') + + profile['data']['infos'] = ProfileNode('infos', 'Informations', OrderedDict(), flags=ProfileNode.SECTION) + + info = { + 'age' : profile_p[1].text.split(' / ')[0], + 'sex' : profile_p[1].text.split(' / ')[1], + 'orientation' : profile_p[1].text.split(' / ')[2], + 'relationship' : profile_p[1].text.split(' / ')[3], + } + + for key, val in info.iteritems(): + profile['data']['infos'].value[key] = ProfileNode(key, key.capitalize(), val) + + div_essays = self.parser.select(self.document.getroot(), "//div[@class='essay']", method='xpath') + h3_essays = self.parser.select(self.document.getroot(), "//div[@id='page_content']//h3", method='xpath') + essays = dict(zip(h3_essays, div_essays)) + + profile['summary'] = div_essays[0].text.strip() + + profile['data']['essays'] = ProfileNode('essays', 'Essays', OrderedDict(), flags=ProfileNode.SECTION) + + for label, val in essays.iteritems(): + label = unicode(label.text).strip() + val = unicode(val.text).strip() + key = label.replace(' ', '_') + profile['data']['essays'].value[key] = ProfileNode(key, label, val) + #profile['data']['look_for'].value['orientation'] = ProfileNode('orientation', 'Orientation', div_essays[9].getchildren()[0].getchildren()[0].text.strip()) + #profile['data']['look_for'].value['location'] = ProfileNode('location', 'Location', div_essays[9].getchildren()[0].getchildren()[2].text.strip()) + #profile['data']['look_for'].value['relationship'] = ProfileNode('relationship', 'Relationship', div_essays[9].getchildren()[0].getchildren()[3].text.strip()) + #profile['data']['look_for'].value['what_for'] = ProfileNode('what_for', 'What for', div_essays[9].getchildren()[0].getchildren()[4].text.split('\n')[1].strip().split(', ')) + + #age = div_essays[9].getchildren()[0].getchildren()[1].text[5:].strip().split(u'–') + #profile['data']['look_for'].value['age_min'] = ProfileNode('age_min', 'Age min', int(age[0])) + #profile['data']['look_for'].value['age_max'] = ProfileNode('age_max', 'Age max', int(age[1])) + + #div_essays = div_essays[1:-1] + #h3_essays = h3_essays[1:-1] + + #for i, title in enumerate(h3_essays): + # profile['data']['essays'].value['essay_%i' % i] = ProfileNode('essay_%i' % i, title.text, div_essays[i].text.strip()) + + details_div = self.parser.select(self.document.getroot(), "//div[@id='details']//li", method='xpath') + profile['data']['details'] = ProfileNode('details', 'Details', OrderedDict(), flags=ProfileNode.SECTION) + for elem in details_div: + label = elem.getchildren()[0].text.strip() + key = label.lower().replace(' ', '_') + val = elem.getchildren()[1].text.strip() + profile['data']['details'].value[key] = ProfileNode(key, label, val) + + return profile