Browse Source

Integrated media in results + Deezer Engine

New "embedded" item for the results, allow to give an iframe to display the media directly in the results.
Note that the attributes src of the iframes are not set, but instead data-src is set, allowing to only load the iframe when clicked.

Deezer engine based on public API (no key).
Cqoicebordel 10 years ago
parent
commit
4a195e0b28

+ 11
- 4
searx/engines/dailymotion.py View File

6
 # @using-api   yes
6
 # @using-api   yes
7
 # @results     JSON
7
 # @results     JSON
8
 # @stable      yes
8
 # @stable      yes
9
-# @parse       url, title, thumbnail
9
+# @parse       url, title, thumbnail, publishedDate, embedded
10
 #
10
 #
11
 # @todo        set content-parameter with correct data
11
 # @todo        set content-parameter with correct data
12
 
12
 
13
 from urllib import urlencode
13
 from urllib import urlencode
14
 from json import loads
14
 from json import loads
15
+from cgi import escape
16
+from datetime import datetime
15
 
17
 
16
 # engine dependent config
18
 # engine dependent config
17
 categories = ['videos']
19
 categories = ['videos']
20
 
22
 
21
 # search-url
23
 # search-url
22
 # see http://www.dailymotion.com/doc/api/obj-video.html
24
 # see http://www.dailymotion.com/doc/api/obj-video.html
23
-search_url = 'https://api.dailymotion.com/videos?fields=title,description,duration,url,thumbnail_360_url&sort=relevance&limit=5&page={pageno}&{query}'  # noqa
25
+search_url = 'https://api.dailymotion.com/videos?fields=created_time,title,description,duration,url,thumbnail_360_url,id&sort=relevance&limit=5&page={pageno}&{query}'  # noqa
26
+embedded_url = '<iframe frameborder="0" width="540" height="304" ' +\
27
+    'data-src="//www.dailymotion.com/embed/video/{videoid}" allowfullscreen></iframe>'
24
 
28
 
25
 
29
 
26
 # do search-request
30
 # do search-request
51
     for res in search_res['list']:
55
     for res in search_res['list']:
52
         title = res['title']
56
         title = res['title']
53
         url = res['url']
57
         url = res['url']
54
-        #content = res['description']
55
-        content = ''
58
+        content = escape(res['description'])
56
         thumbnail = res['thumbnail_360_url']
59
         thumbnail = res['thumbnail_360_url']
60
+        publishedDate = datetime.fromtimestamp(res['created_time'], None)
61
+        embedded = embedded_url.format(videoid=res['id'])
57
 
62
 
58
         results.append({'template': 'videos.html',
63
         results.append({'template': 'videos.html',
59
                         'url': url,
64
                         'url': url,
60
                         'title': title,
65
                         'title': title,
61
                         'content': content,
66
                         'content': content,
67
+                        'publishedDate': publishedDate,
68
+                        'embedded': embedded,
62
                         'thumbnail': thumbnail})
69
                         'thumbnail': thumbnail})
63
 
70
 
64
     # return results
71
     # return results

+ 62
- 0
searx/engines/deezer.py View File

1
+## Deezer (Music)
2
+#
3
+# @website     https://deezer.com
4
+# @provide-api yes (http://developers.deezer.com/api/)
5
+#
6
+# @using-api   yes
7
+# @results     JSON
8
+# @stable      yes
9
+# @parse       url, title, content, embedded
10
+
11
+from json import loads
12
+from urllib import urlencode
13
+
14
+# engine dependent config
15
+categories = ['music']
16
+paging = True
17
+
18
+# search-url
19
+url = 'http://api.deezer.com/'
20
+search_url = url + 'search?{query}&index={offset}'
21
+
22
+embedded_url = '<iframe scrolling="no" frameborder="0" allowTransparency="true" ' +\
23
+    'data-src="http://www.deezer.com/plugins/player?type=tracks&id={audioid}" ' +\
24
+    'width="540" height="80"></iframe>'
25
+
26
+
27
+# do search-request
28
+def request(query, params):
29
+    offset = (params['pageno'] - 1) * 25
30
+
31
+    params['url'] = search_url.format(query=urlencode({'q': query}),
32
+                                      offset=offset)
33
+
34
+    return params
35
+
36
+
37
+# get response from search-request
38
+def response(resp):
39
+    results = []
40
+
41
+    search_res = loads(resp.text)
42
+
43
+    # parse results
44
+    for result in search_res.get('data', []):
45
+        if result['type'] == 'track':
46
+            print result
47
+            title = result['title']
48
+            url = result['link']
49
+            content = result['artist']['name'] +\
50
+                " &bull; " +\
51
+                result['album']['title'] +\
52
+                " &bull; " + result['title']
53
+            embedded = embedded_url.format(audioid=result['id'])
54
+
55
+            # append result
56
+            results.append({'url': url,
57
+                            'title': title,
58
+                            'embedded': embedded,
59
+                            'content': content})
60
+
61
+    # return results
62
+    return results

+ 12
- 2
searx/engines/soundcloud.py View File

6
 # @using-api   yes
6
 # @using-api   yes
7
 # @results     JSON
7
 # @results     JSON
8
 # @stable      yes
8
 # @stable      yes
9
-# @parse       url, title, content
9
+# @parse       url, title, content, publishedDate, embedded
10
 
10
 
11
 from json import loads
11
 from json import loads
12
-from urllib import urlencode
12
+from urllib import urlencode, quote_plus
13
+from dateutil import parser
13
 
14
 
14
 # engine dependent config
15
 # engine dependent config
15
 categories = ['music']
16
 categories = ['music']
27
                          '&linked_partitioning=1'\
28
                          '&linked_partitioning=1'\
28
                          '&client_id={client_id}'   # noqa
29
                          '&client_id={client_id}'   # noqa
29
 
30
 
31
+embedded_url = '<iframe width="100%" height="166" ' +\
32
+    'scrolling="no" frameborder="no" ' +\
33
+    'data-src="https://w.soundcloud.com/player/?url={uri}"></iframe>'
34
+
30
 
35
 
31
 # do search-request
36
 # do search-request
32
 def request(query, params):
37
 def request(query, params):
50
         if result['kind'] in ('track', 'playlist'):
55
         if result['kind'] in ('track', 'playlist'):
51
             title = result['title']
56
             title = result['title']
52
             content = result['description']
57
             content = result['description']
58
+            publishedDate = parser.parse(result['last_modified'])
59
+            uri = quote_plus(result['uri'])
60
+            embedded = embedded_url.format(uri=uri)
53
 
61
 
54
             # append result
62
             # append result
55
             results.append({'url': result['permalink_url'],
63
             results.append({'url': result['permalink_url'],
56
                             'title': title,
64
                             'title': title,
65
+                            'publishedDate': publishedDate,
66
+                            'embedded': embedded,
57
                             'content': content})
67
                             'content': content})
58
 
68
 
59
     # return results
69
     # return results

+ 9
- 2
searx/engines/vimeo.py View File

7
 # @using-api   no (TODO, rewrite to api)
7
 # @using-api   no (TODO, rewrite to api)
8
 # @results     HTML (using search portal)
8
 # @results     HTML (using search portal)
9
 # @stable      no (HTML can change)
9
 # @stable      no (HTML can change)
10
-# @parse       url, title, publishedDate,  thumbnail
10
+# @parse       url, title, publishedDate,  thumbnail, embedded
11
 #
11
 #
12
 # @todo        rewrite to api
12
 # @todo        rewrite to api
13
 # @todo        set content-parameter with correct data
13
 # @todo        set content-parameter with correct data
33
 results_xpath = '//div[@id="browse_content"]/ol/li'
33
 results_xpath = '//div[@id="browse_content"]/ol/li'
34
 publishedDate_xpath = './/p[@class="meta"]//attribute::datetime'
34
 publishedDate_xpath = './/p[@class="meta"]//attribute::datetime'
35
 
35
 
36
+embedded_url = '<iframe data-src="//player.vimeo.com/video{videoid}" ' +\
37
+    'width="540" height="304" frameborder="0" ' +\
38
+    'webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'
39
+
36
 
40
 
37
 # do search-request
41
 # do search-request
38
 def request(query, params):
42
 def request(query, params):
56
 
60
 
57
     # parse results
61
     # parse results
58
     for result in dom.xpath(results_xpath):
62
     for result in dom.xpath(results_xpath):
59
-        url = base_url + result.xpath(url_xpath)[0]
63
+        videoid = result.xpath(url_xpath)[0]
64
+        url = base_url + videoid
60
         title = p.unescape(extract_text(result.xpath(title_xpath)))
65
         title = p.unescape(extract_text(result.xpath(title_xpath)))
61
         thumbnail = extract_text(result.xpath(content_xpath)[0])
66
         thumbnail = extract_text(result.xpath(content_xpath)[0])
62
         publishedDate = parser.parse(extract_text(
67
         publishedDate = parser.parse(extract_text(
63
             result.xpath(publishedDate_xpath)[0]))
68
             result.xpath(publishedDate_xpath)[0]))
69
+        embedded = embedded_url.format(videoid=videoid)
64
 
70
 
65
         # append result
71
         # append result
66
         results.append({'url': url,
72
         results.append({'url': url,
68
                         'content': '',
74
                         'content': '',
69
                         'template': 'videos.html',
75
                         'template': 'videos.html',
70
                         'publishedDate': publishedDate,
76
                         'publishedDate': publishedDate,
77
+                        'embedded': embedded,
71
                         'thumbnail': thumbnail})
78
                         'thumbnail': thumbnail})
72
 
79
 
73
     # return results
80
     # return results

+ 11
- 2
searx/engines/youtube.py View File

6
 # @using-api   yes
6
 # @using-api   yes
7
 # @results     JSON
7
 # @results     JSON
8
 # @stable      yes
8
 # @stable      yes
9
-# @parse       url, title, content, publishedDate, thumbnail
9
+# @parse       url, title, content, publishedDate, thumbnail, embedded
10
 
10
 
11
 from json import loads
11
 from json import loads
12
 from urllib import urlencode
12
 from urllib import urlencode
19
 
19
 
20
 # search-url
20
 # search-url
21
 base_url = 'https://gdata.youtube.com/feeds/api/videos'
21
 base_url = 'https://gdata.youtube.com/feeds/api/videos'
22
-search_url = base_url + '?alt=json&{query}&start-index={index}&max-results=5'  # noqa
22
+search_url = base_url + '?alt=json&{query}&start-index={index}&max-results=5'
23
+
24
+embedded_url = '<iframe width="540" height="304" ' +\
25
+    'data-src="//www.youtube-nocookie.com/embed/{videoid}" ' +\
26
+    'frameborder="0" allowfullscreen></iframe>'
23
 
27
 
24
 
28
 
25
 # do search-request
29
 # do search-request
60
         if url.endswith('&'):
64
         if url.endswith('&'):
61
             url = url[:-1]
65
             url = url[:-1]
62
 
66
 
67
+        videoid = url[32:]
68
+
63
         title = result['title']['$t']
69
         title = result['title']['$t']
64
         content = ''
70
         content = ''
65
         thumbnail = ''
71
         thumbnail = ''
72
 
78
 
73
         content = result['content']['$t']
79
         content = result['content']['$t']
74
 
80
 
81
+        embedded = embedded_url.format(videoid=videoid)
82
+
75
         # append result
83
         # append result
76
         results.append({'url': url,
84
         results.append({'url': url,
77
                         'title': title,
85
                         'title': title,
78
                         'content': content,
86
                         'content': content,
79
                         'template': 'videos.html',
87
                         'template': 'videos.html',
80
                         'publishedDate': publishedDate,
88
                         'publishedDate': publishedDate,
89
+                        'embedded': embedded,
81
                         'thumbnail': thumbnail})
90
                         'thumbnail': thumbnail})
82
 
91
 
83
     # return results
92
     # return results

+ 4
- 0
searx/settings.yml View File

35
     engine : currency_convert
35
     engine : currency_convert
36
     categories : general
36
     categories : general
37
     shortcut : cc
37
     shortcut : cc
38
+    
39
+  - name : deezer
40
+    engine : deezer
41
+    shortcut : dz
38
 
42
 
39
   - name : deviantart
43
   - name : deviantart
40
     engine : deviantart
44
     engine : deviantart

+ 2
- 2
searx/static/themes/oscar/js/searx.min.js
File diff suppressed because it is too large
View File


+ 12
- 0
searx/static/themes/oscar/js/searx_src/element_modifiers.js View File

63
         $(this).toggleClass(btnClass);
63
         $(this).toggleClass(btnClass);
64
         $(this).toggleClass('btn-default');
64
         $(this).toggleClass('btn-default');
65
     });
65
     });
66
+	
67
+	/**
68
+     * change text during btn-toggle click if possible
69
+     */
70
+    $('.media-loader').click(function() {
71
+        var target = $(this).data('target');
72
+        var iframe_load = $(target + ' > iframe');
73
+		var srctest = iframe_load.attr('src');
74
+		if(srctest === undefined || srctest === false){
75
+            iframe_load.attr('src', iframe_load.data('src'));
76
+		}
77
+    });
66
     
78
     
67
     /**
79
     /**
68
      * Select or deselect every categories on double clic
80
      * Select or deselect every categories on double clic

+ 12
- 0
searx/templates/oscar/result_templates/default.html View File

5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
6
 <small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
6
 <small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
7
 
7
 
8
+{% if result.embedded %}
9
+    <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader" data-toggle="collapse" data-target="#result-media-{{ index }}" data-btn-text-collapsed="{{ _('show media') }}" data-btn-text-not-collapsed="{{ _('hide media') }}">{{ icon('music') }} {{ _('show media') }}</a></small>
10
+{% endif %}
11
+
8
 {% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
12
 {% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
9
 
13
 
14
+{% if result.embedded %}
15
+<div id="result-media-{{ index }}" class="collapse">
16
+{% autoescape false %}
17
+   {{ result.embedded }}
18
+{% endautoescape %}
19
+</div>
20
+{% endif %}
21
+
10
 <div class="clearfix"></div>
22
 <div class="clearfix"></div>
11
 
23
 
12
 <span class="label label-default pull-right">{{ result.engine }}</span>
24
 <span class="label label-default pull-right">{{ result.engine }}</span>

+ 12
- 0
searx/templates/oscar/result_templates/videos.html View File

5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
6
 <small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
6
 <small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
7
 
7
 
8
+{% if result.embedded %}
9
+    <small> &bull; <a class="text-info btn-collapse collapsed cursor-pointer media-loader" data-toggle="collapse" data-target="#result-video-{{ index }}" data-btn-text-collapsed="{{ _('show video') }}" data-btn-text-not-collapsed="{{ _('hide video') }}">{{ icon('film') }} {{ _('show video') }}</a></small>
10
+{% endif %}
11
+
8
 <div class="container-fluid">
12
 <div class="container-fluid">
9
     <div class="row">
13
     <div class="row">
10
         <a href="{{ result.url }}"><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ result.thumbnail|safe }}" alt="{{ result.title|striptags }} {{ result.engine }}" /></a>
14
         <a href="{{ result.url }}"><img class="thumbnail col-xs-6 col-sm-4 col-md-4 result-content" src="{{ result.thumbnail|safe }}" alt="{{ result.title|striptags }} {{ result.engine }}" /></a>
12
     </div>
16
     </div>
13
 </div>
17
 </div>
14
 
18
 
19
+{% if result.embedded %}
20
+<div id="result-video-{{ index }}" class="collapse">
21
+{% autoescape false %}
22
+   {{ result.embedded }}
23
+{% endautoescape %}
24
+</div>
25
+{% endif %}
26
+
15
 <div class="clearfix"></div>
27
 <div class="clearfix"></div>
16
 
28
 
17
 <span class="label label-default pull-right">{{ result.engine }}</span>
29
 <span class="label label-default pull-right">{{ result.engine }}</span>