~vincent-vandevyvre/qarte/trunk

« back to all changes in this revision

Viewing changes to parsers.py

  • Committer: Vincent Vande Vyvre
  • Date: 2015-11-01 06:27:59 UTC
  • Revision ID: vincent.vandevyvre@oqapy.eu-20151101062759-bm7f19uavuoxisv2
Update the parsing

Show diffs side-by-side

added added

removed removed

Lines of Context:
86
86
        """Get www.arte.tv/ page and run parsing.
87
87
 
88
88
        """
89
 
        dtc={}
90
 
        for u in self.URL_ALL:
91
 
            jsn = self.parseurl(u)
92
 
            if jsn is not None:
93
 
                dct = self.parse_videos(jsn, dtc)
94
 
        
95
 
        ordv = self.sort_videos(dct)
96
 
        for k, v in ordv.items():
97
 
            video = VideoPlusItem(k, v)
 
89
        videos = {}
 
90
        for idx, url in enumerate(self.URL_ALL):
 
91
            url = url.replace('fr', self.lang)
 
92
            page, error = self.get_page_content(url)
 
93
            if page is None or not page:
 
94
                logger.info(u"Read Error: {0}".format(error))
 
95
                continue
 
96
 
 
97
            json = self.extract_json(page)
 
98
            if not json:
 
99
                continue
 
100
 
 
101
            if not idx:
 
102
                # First page
 
103
                json = self.prepare_json(json)
 
104
 
 
105
            else:
 
106
                # all other pages, not the same json!
 
107
                json = self.sanitize_json(json)
 
108
 
 
109
            dct = self.read_json(json)
 
110
            if not dct:
 
111
                continue
 
112
 
 
113
            if not idx:
 
114
                self.get_recent_videos(dct, videos)
 
115
 
 
116
            else:
 
117
                self.get_video_items(dct["videos"], videos)
 
118
 
 
119
        if not videos:
 
120
            logger.warning(u'No video items found')
 
121
            self.parsingFinished.emit(['error', 'Stage 1', 'No videos found'])
 
122
            return
 
123
 
 
124
        for k in sorted(videos.keys()):
 
125
            video = VideoPlusItem(k, videos[k])
98
126
            self.videos.insert(0, video)
99
127
 
100
128
        logger.info(u'Parsed %s videos' % len(self.videos))
101
129
        self.parsingFinished.emit([None])
102
130
 
103
 
    def parseurl(self,urlallitem):              
104
 
        # Stage 1
105
 
        url = urlallitem.replace('fr', self.lang)
106
 
        logger.info(u"Run arte+7 parser: {0}".format(current_thread()))
107
 
        logger.info(u"Get page: {0}".format(url))
108
 
        content, err = self.get_page_content(url)
109
 
 
110
 
        if content is None:
111
 
            logger.info(u"Read Error: {0}".format(err))
112
 
            self.parsingFinished.emit(['error', 'Stage 1', err])
113
 
            return
114
 
 
115
 
        if not len(content):
116
 
            logger.info(u"Read Error: 'Page empty'")
117
 
            self.parsingFinished.emit(['error', 'Stage 1', 'Page empty'])
118
 
            return
119
 
 
120
 
        # Stage 2
121
 
        videos = self.ALL_VIDEOS.search(content)
122
 
        if videos is not None:
123
 
            txt = self.sanitize_json(videos.group(0))
124
 
            jsn = self.read_json(txt)
125
 
            if not jsn:
126
 
                self.parsingFinished.emit(['error', 'Stage 1', 'json unreadable'])
127
 
                return
128
 
 
129
 
        else:
130
 
            logger.info(u"Read Error: 'No videos found'")
131
 
            self.parsingFinished.emit(['error', 'Stage 1', 'No videos found'])
132
 
            return
133
 
 
134
 
        logger.info(u"json loaded")
135
 
        return jsn
136
 
 
137
 
 
138
131
    def get_page_content(self, url):
139
132
        """Fetch a html or xml page.
140
133
 
144
137
        Returns:
145
138
        page as text or None if fail
146
139
        """
 
140
        logger.info(u'Fetch page: %s' % url)
147
141
        try:
148
142
            content = urllib2.urlopen(url).read()
149
143
        except IOError as why:
152
146
 
153
147
        return content, None
154
148
 
 
149
    def extract_json(self, text):
 
150
        logger.info(u'Extract json code')
 
151
        videos = self.ALL_VIDEOS.search(text)
 
152
        if videos is not None:
 
153
            return videos.group(0)
 
154
 
 
155
        logger.info(u'Regex ALL_VIDEOS failed')
 
156
        return False
 
157
 
 
158
    def prepare_json(self, jsn):
 
159
        for item in ['highlightedVideos', 'currentLive', 
 
160
                     'dailyMostViewedVideos', 'mostViewedVideos', 
 
161
                     'latestVideos', 'nextExpiringVideos',
 
162
                     'categoriesVideos', 'videoSet','clusters']:
 
163
            jsn = jsn.replace(item, '"%s"' % item)
 
164
        jsn = jsn.rstrip(',;) \n')
 
165
        return jsn
 
166
 
 
167
    def sanitize_json(self, jsn):
 
168
        jsn = jsn.split('videoSet:')[1].lstrip()
 
169
        jsn = jsn.split('}]}')[0] + '}]}'
 
170
        return jsn
 
171
 
155
172
    def read_json(self, text):
156
173
        try:
157
 
            #logger.info(u'%s' % text)
158
174
            return json.loads(text.decode('utf8', 'ignore'))
159
175
        except Exception as why:
160
 
            logger.info(u'%s' % text)
161
176
            logger.warning(u'json read error: %s' % why)
162
 
            
163
177
            return False
164
178
 
165
 
    def sanitize_json(self, js):
166
 
        js = js.rstrip(',); \n')
167
 
        try:
168
 
            # Remove some bad formated part of the text
169
 
            idx = js.index('videoSet')
170
 
        except ValueError:
171
 
            pass
172
 
        else:
173
 
            try:
174
 
                # Remove unneeded elements
175
 
                idx2 = js.index('clusters')
176
 
            except ValueError:
177
 
                pass
178
 
            else:
179
 
                js = '{' + js[idx:idx2]
180
 
                js = js.rstrip(',); \n')
181
 
                js += '}'
182
 
        
183
 
        for item in ['highlightedVideos', 'currentLive', 'dailyMostViewedVideos', 
184
 
                 'mostViewedVideos', 'latestVideos', 'nextExpiringVideos',
185
 
                 'categoriesVideos', 'videoSet','clusters', 'sort','returnURL']:
186
 
            js = js.replace(item, '"%s"' % item)
187
 
 
188
 
        js = js.replace('"returnURL": \'http://www.arte.tv/guide/fr/plus7/\',','')
189
 
        js = js.replace('"returnURL": \'/guide/fr/plus7/\',','')
190
 
        js = js.replace('"sort"ir','sortir')
191
 
        js = js.replace('"returnURL": \'http://www.arte.tv/guide/de/plus7/\',','')
192
 
        js = js.replace('"returnURL": \'/guide/de/plus7/\',','')
193
 
 
194
 
        return js
195
 
 
196
 
    def parse_videos(self, jsn, dic_):
197
 
        for itemkey in ['highlightedVideos', 
198
 
                 'mostViewedVideos', 'latestVideos',
199
 
                 'videoSet']:
200
 
            if itemkey in jsn:
201
 
                logger.info("%s found" % itemkey)
202
 
                for item in jsn[itemkey]["videos"]:
203
 
                    dic_[item['id']] = {}
204
 
                    self.build_item(dic_[item['id']], item)
205
 
        #for itemkey in ['categoriesVideos']:
206
 
            #if itemkey in jsn:
207
 
                #logger.info("%s found" % itemkey)
208
 
                #for cat in jsn[itemkey]:
209
 
                    #videos = cat['videos']
210
 
                    #for item in videos:
211
 
                        #if not item['id'] in dic_:
212
 
                            #dic_[item['id']] = {}
213
 
                            #self.build_item(dic_[item['id']], item)
214
 
##        for item in jsn['highlightedVideos']["videos"]:
215
 
##            dic_[item['id']] = {}
216
 
##            self.build_item(dic_[item['id']], item)
217
 
##        for item in jsn['mostViewedVideos']["videos"]:
218
 
##            if not item['id'] in dic_:
219
 
##                dic_[item['id']] = {}
220
 
##                self.build_item(dic_[item['id']], item)
221
 
##        for item in jsn['latestVideos']["videos"]:
222
 
##            if not item['id'] in dic_:
223
 
##                dic_[item['id']] = {}
224
 
##                self.build_item(dic_[item['id']], item)
225
 
        if 'categoriesVideos' in jsn:
226
 
            for cat in jsn['categoriesVideos']:
227
 
                videos = cat['videos']
228
 
                for item in videos:
229
 
                    if not item['id'] in dic_:
230
 
                        dic_[item['id']] = {}
231
 
                        self.build_item(dic_[item['id']], item)
232
 
 
233
 
        return dic_
234
 
 
235
 
    def build_item(self, v, item):
236
 
        v['title'] = item['title']
237
 
        v['duration'] = item['duration']
238
 
        v['date'] = item['scheduled_on']
239
 
        v['expire'] = item['rights_end']
240
 
        v['thumbnail'] = item['thumbnail_url']
241
 
        v['url'] = item['url']
242
 
        v['pitch'] = item['teaser']
243
 
 
244
 
    def sort_videos(self, videos):
245
 
        for v in sorted(videos.keys()):
246
 
            date = videos[v]['date'].split('-')
247
 
            exp = videos[v]['expire'].split('T')[1].rstrip('Z').split(':')
248
 
            date.extend(exp)
249
 
            y, m, d, h, n, s = [int(i) for i in date]
250
 
            videos[v]['date'] = datetime.datetime(y, m, d, h, n, s)
251
 
        return OrderedDict(sorted(videos.items(), key=lambda v: v[1]['date']))
252
 
 
253
 
    def normalise_date(self, value):
 
179
    def get_recent_videos(self, dct, videos):
 
180
        for itemkey in ['highlightedVideos', 'mostViewedVideos', 'latestVideos',
 
181
                        'videoSet']:
 
182
            if itemkey in dct:
 
183
                self.get_video_items(dct[itemkey]["videos"], videos)
 
184
 
 
185
        if 'categoriesVideos' in dct:
 
186
            for cat in dct['categoriesVideos']:
 
187
                self.get_video_items(cat["videos"], videos)
 
188
 
 
189
    def get_video_items(self, lst, videos):
 
190
        for v in lst:
 
191
            key, date = self.build_video_key(v['scheduled_on'], v['rights_end'])
 
192
            v['date'] = date
 
193
            videos[key] = v
 
194
 
 
195
    def build_video_key(self, date, expire):
 
196
        """Returns the identifiant and the complete date of a video.
 
197
 
 
198
        "scheduled_on":"2015-10-30" "rights_end":"2015-11-07T23:52:21Z"
 
199
        >>> "2015-10-30-23-52-21", "2015-10-30 23:52:21"
 
200
 
 
201
        Args:
 
202
        date -- value of key "scheduled_on"
 
203
        expire -- value of key "rights_end"
 
204
        """
 
205
        hour = expire.split('T')[1].rstrip('Z')
 
206
        id_ = '%s-%s' %(date, hour.replace(':', '-'))
 
207
        orig = '%s %s' %(date, hour)
 
208
        return id_, orig
 
209
 
 
210
 
 
211
    def normalise_date2(self, value):
 
212
        # FIXME obsolete?
254
213
        td = datetime.date.today()
255
214
        ldate = value.split()
256
215
        mnt = m = ldate[2]
298
257
                try:
299
258
                    summ = self.summaries[video.date][0]
300
259
                except IndexError:
301
 
                     summ = ''
 
260
                    summ = ''
302
261
 
303
262
                if not summ:
304
263
                    try:
1021
980
 
1022
981
        return ele
1023
982
 
 
983
    def build_item(self, v, item):
 
984
        v['title'] = item['title']
 
985
        v['duration'] = item['duration']
 
986
        v['date'] = item['scheduled_on']
 
987
        v['expire'] = item['rights_end']
 
988
        v['thumbnail'] = item['thumbnail_url']
 
989
        v['url'] = item['url']
 
990
        v['pitch'] = item['teaser']
1024
991
 
1025
992
class VideoPlusItem(object):
1026
993
    def __init__(self, idx, data):
1028
995
 
1029
996
        Args:
1030
997
        data -- values provided by the parser
1031
 
        ['title', 'long date', 'duration', 'url', 'image_url', 'desc', 'date']
1032
998
        """
1033
 
        d = dict(title = data['title'],
1034
 
                ldate = data['date'].strftime('%Y %m %d, %Hh%M'),
 
999
        d = dict(idx = idx,
 
1000
                title = data['title'],
 
1001
                ldate = data['date'],
1035
1002
                duration = data['duration'],
1036
1003
                link = data['url'],
1037
 
                pix = data['thumbnail'],
1038
 
                pitch = data['pitch'],
1039
 
                date = data['date'].strftime('%Y %m %d, %Hh%M'),
 
1004
                pix = data['thumbnail_url'],
 
1005
                pitch = data['teaser'],
 
1006
                date = data['date'],
1040
1007
                HD = None,
1041
1008
                SD = None,
1042
1009
                outfile = None,
1043
1010
                preview = None,
1044
 
                summary = None,
 
1011
                summary = data['teaser'],
1045
1012
                orig = None,
1046
1013
                streams = None,
1047
1014
                stream = None)
1048
1015
 
1049
1016
        for key, value in d.iteritems():
1050
1017
            setattr(self, key, value)
1051
 
 
 
1018
    
 
1019
        seconds = self.duration
 
1020
        m, s = divmod(seconds, 60)
 
1021
        h, m = divmod(m, 60)
 
1022
        t = ""
 
1023
        if h:
 
1024
            t += '%sh ' % h
 
1025
        t += '%sm %ss' %(m, s)
 
1026
        self.duration = '(%s)' % t
1052
1027
 
1053
1028
class VideoItem(object):
1054
1029
    def __init__(self, cat, item):