소스 검색

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 년 전
부모
커밋
4a195e0b28

+ 11
- 4
searx/engines/dailymotion.py 파일 보기

@@ -6,12 +6,14 @@
6 6
 # @using-api   yes
7 7
 # @results     JSON
8 8
 # @stable      yes
9
-# @parse       url, title, thumbnail
9
+# @parse       url, title, thumbnail, publishedDate, embedded
10 10
 #
11 11
 # @todo        set content-parameter with correct data
12 12
 
13 13
 from urllib import urlencode
14 14
 from json import loads
15
+from cgi import escape
16
+from datetime import datetime
15 17
 
16 18
 # engine dependent config
17 19
 categories = ['videos']
@@ -20,7 +22,9 @@ language_support = True
20 22
 
21 23
 # search-url
22 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 30
 # do search-request
@@ -51,14 +55,17 @@ def response(resp):
51 55
     for res in search_res['list']:
52 56
         title = res['title']
53 57
         url = res['url']
54
-        #content = res['description']
55
-        content = ''
58
+        content = escape(res['description'])
56 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 63
         results.append({'template': 'videos.html',
59 64
                         'url': url,
60 65
                         'title': title,
61 66
                         'content': content,
67
+                        'publishedDate': publishedDate,
68
+                        'embedded': embedded,
62 69
                         'thumbnail': thumbnail})
63 70
 
64 71
     # return results

+ 62
- 0
searx/engines/deezer.py 파일 보기

@@ -0,0 +1,62 @@
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 파일 보기

@@ -6,10 +6,11 @@
6 6
 # @using-api   yes
7 7
 # @results     JSON
8 8
 # @stable      yes
9
-# @parse       url, title, content
9
+# @parse       url, title, content, publishedDate, embedded
10 10
 
11 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 15
 # engine dependent config
15 16
 categories = ['music']
@@ -27,6 +28,10 @@ search_url = url + 'search?{query}'\
27 28
                          '&linked_partitioning=1'\
28 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 36
 # do search-request
32 37
 def request(query, params):
@@ -50,10 +55,15 @@ def response(resp):
50 55
         if result['kind'] in ('track', 'playlist'):
51 56
             title = result['title']
52 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 62
             # append result
55 63
             results.append({'url': result['permalink_url'],
56 64
                             'title': title,
65
+                            'publishedDate': publishedDate,
66
+                            'embedded': embedded,
57 67
                             'content': content})
58 68
 
59 69
     # return results

+ 9
- 2
searx/engines/vimeo.py 파일 보기

@@ -7,7 +7,7 @@
7 7
 # @using-api   no (TODO, rewrite to api)
8 8
 # @results     HTML (using search portal)
9 9
 # @stable      no (HTML can change)
10
-# @parse       url, title, publishedDate,  thumbnail
10
+# @parse       url, title, publishedDate,  thumbnail, embedded
11 11
 #
12 12
 # @todo        rewrite to api
13 13
 # @todo        set content-parameter with correct data
@@ -33,6 +33,10 @@ title_xpath = './a/div[@class="data"]/p[@class="title"]/text()'
33 33
 results_xpath = '//div[@id="browse_content"]/ol/li'
34 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 41
 # do search-request
38 42
 def request(query, params):
@@ -56,11 +60,13 @@ def response(resp):
56 60
 
57 61
     # parse results
58 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 65
         title = p.unescape(extract_text(result.xpath(title_xpath)))
61 66
         thumbnail = extract_text(result.xpath(content_xpath)[0])
62 67
         publishedDate = parser.parse(extract_text(
63 68
             result.xpath(publishedDate_xpath)[0]))
69
+        embedded = embedded_url.format(videoid=videoid)
64 70
 
65 71
         # append result
66 72
         results.append({'url': url,
@@ -68,6 +74,7 @@ def response(resp):
68 74
                         'content': '',
69 75
                         'template': 'videos.html',
70 76
                         'publishedDate': publishedDate,
77
+                        'embedded': embedded,
71 78
                         'thumbnail': thumbnail})
72 79
 
73 80
     # return results

+ 11
- 2
searx/engines/youtube.py 파일 보기

@@ -6,7 +6,7 @@
6 6
 # @using-api   yes
7 7
 # @results     JSON
8 8
 # @stable      yes
9
-# @parse       url, title, content, publishedDate, thumbnail
9
+# @parse       url, title, content, publishedDate, thumbnail, embedded
10 10
 
11 11
 from json import loads
12 12
 from urllib import urlencode
@@ -19,7 +19,11 @@ language_support = True
19 19
 
20 20
 # search-url
21 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 29
 # do search-request
@@ -60,6 +64,8 @@ def response(resp):
60 64
         if url.endswith('&'):
61 65
             url = url[:-1]
62 66
 
67
+        videoid = url[32:]
68
+
63 69
         title = result['title']['$t']
64 70
         content = ''
65 71
         thumbnail = ''
@@ -72,12 +78,15 @@ def response(resp):
72 78
 
73 79
         content = result['content']['$t']
74 80
 
81
+        embedded = embedded_url.format(videoid=videoid)
82
+
75 83
         # append result
76 84
         results.append({'url': url,
77 85
                         'title': title,
78 86
                         'content': content,
79 87
                         'template': 'videos.html',
80 88
                         'publishedDate': publishedDate,
89
+                        'embedded': embedded,
81 90
                         'thumbnail': thumbnail})
82 91
 
83 92
     # return results

+ 4
- 0
searx/settings.yml 파일 보기

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

+ 2
- 2
searx/static/themes/oscar/js/searx.min.js
파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
파일 보기


+ 12
- 0
searx/static/themes/oscar/js/searx_src/element_modifiers.js 파일 보기

@@ -63,6 +63,18 @@ $(document).ready(function(){
63 63
         $(this).toggleClass(btnClass);
64 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 80
      * Select or deselect every categories on double clic

+ 12
- 0
searx/templates/oscar/result_templates/default.html 파일 보기

@@ -5,8 +5,20 @@
5 5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
6 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 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 22
 <div class="clearfix"></div>
11 23
 
12 24
 <span class="label label-default pull-right">{{ result.engine }}</span>

+ 12
- 0
searx/templates/oscar/result_templates/videos.html 파일 보기

@@ -5,6 +5,10 @@
5 5
 {% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
6 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 12
 <div class="container-fluid">
9 13
     <div class="row">
10 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,6 +16,14 @@
12 16
     </div>
13 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 27
 <div class="clearfix"></div>
16 28
 
17 29
 <span class="label label-default pull-right">{{ result.engine }}</span>