forked from zaclys/searxng
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).
This commit is contained in:
parent
7b531c6fce
commit
4a195e0b28
@ -6,12 +6,14 @@
|
||||
# @using-api yes
|
||||
# @results JSON
|
||||
# @stable yes
|
||||
# @parse url, title, thumbnail
|
||||
# @parse url, title, thumbnail, publishedDate, embedded
|
||||
#
|
||||
# @todo set content-parameter with correct data
|
||||
|
||||
from urllib import urlencode
|
||||
from json import loads
|
||||
from cgi import escape
|
||||
from datetime import datetime
|
||||
|
||||
# engine dependent config
|
||||
categories = ['videos']
|
||||
@ -20,7 +22,9 @@ language_support = True
|
||||
|
||||
# search-url
|
||||
# see http://www.dailymotion.com/doc/api/obj-video.html
|
||||
search_url = 'https://api.dailymotion.com/videos?fields=title,description,duration,url,thumbnail_360_url&sort=relevance&limit=5&page={pageno}&{query}' # noqa
|
||||
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
|
||||
embedded_url = '<iframe frameborder="0" width="540" height="304" ' +\
|
||||
'data-src="//www.dailymotion.com/embed/video/{videoid}" allowfullscreen></iframe>'
|
||||
|
||||
|
||||
# do search-request
|
||||
@ -51,14 +55,17 @@ def response(resp):
|
||||
for res in search_res['list']:
|
||||
title = res['title']
|
||||
url = res['url']
|
||||
#content = res['description']
|
||||
content = ''
|
||||
content = escape(res['description'])
|
||||
thumbnail = res['thumbnail_360_url']
|
||||
publishedDate = datetime.fromtimestamp(res['created_time'], None)
|
||||
embedded = embedded_url.format(videoid=res['id'])
|
||||
|
||||
results.append({'template': 'videos.html',
|
||||
'url': url,
|
||||
'title': title,
|
||||
'content': content,
|
||||
'publishedDate': publishedDate,
|
||||
'embedded': embedded,
|
||||
'thumbnail': thumbnail})
|
||||
|
||||
# return results
|
||||
|
62
searx/engines/deezer.py
Normal file
62
searx/engines/deezer.py
Normal file
@ -0,0 +1,62 @@
|
||||
## Deezer (Music)
|
||||
#
|
||||
# @website https://deezer.com
|
||||
# @provide-api yes (http://developers.deezer.com/api/)
|
||||
#
|
||||
# @using-api yes
|
||||
# @results JSON
|
||||
# @stable yes
|
||||
# @parse url, title, content, embedded
|
||||
|
||||
from json import loads
|
||||
from urllib import urlencode
|
||||
|
||||
# engine dependent config
|
||||
categories = ['music']
|
||||
paging = True
|
||||
|
||||
# search-url
|
||||
url = 'http://api.deezer.com/'
|
||||
search_url = url + 'search?{query}&index={offset}'
|
||||
|
||||
embedded_url = '<iframe scrolling="no" frameborder="0" allowTransparency="true" ' +\
|
||||
'data-src="http://www.deezer.com/plugins/player?type=tracks&id={audioid}" ' +\
|
||||
'width="540" height="80"></iframe>'
|
||||
|
||||
|
||||
# do search-request
|
||||
def request(query, params):
|
||||
offset = (params['pageno'] - 1) * 25
|
||||
|
||||
params['url'] = search_url.format(query=urlencode({'q': query}),
|
||||
offset=offset)
|
||||
|
||||
return params
|
||||
|
||||
|
||||
# get response from search-request
|
||||
def response(resp):
|
||||
results = []
|
||||
|
||||
search_res = loads(resp.text)
|
||||
|
||||
# parse results
|
||||
for result in search_res.get('data', []):
|
||||
if result['type'] == 'track':
|
||||
print result
|
||||
title = result['title']
|
||||
url = result['link']
|
||||
content = result['artist']['name'] +\
|
||||
" • " +\
|
||||
result['album']['title'] +\
|
||||
" • " + result['title']
|
||||
embedded = embedded_url.format(audioid=result['id'])
|
||||
|
||||
# append result
|
||||
results.append({'url': url,
|
||||
'title': title,
|
||||
'embedded': embedded,
|
||||
'content': content})
|
||||
|
||||
# return results
|
||||
return results
|
@ -6,10 +6,11 @@
|
||||
# @using-api yes
|
||||
# @results JSON
|
||||
# @stable yes
|
||||
# @parse url, title, content
|
||||
# @parse url, title, content, publishedDate, embedded
|
||||
|
||||
from json import loads
|
||||
from urllib import urlencode
|
||||
from urllib import urlencode, quote_plus
|
||||
from dateutil import parser
|
||||
|
||||
# engine dependent config
|
||||
categories = ['music']
|
||||
@ -27,6 +28,10 @@ search_url = url + 'search?{query}'\
|
||||
'&linked_partitioning=1'\
|
||||
'&client_id={client_id}' # noqa
|
||||
|
||||
embedded_url = '<iframe width="100%" height="166" ' +\
|
||||
'scrolling="no" frameborder="no" ' +\
|
||||
'data-src="https://w.soundcloud.com/player/?url={uri}"></iframe>'
|
||||
|
||||
|
||||
# do search-request
|
||||
def request(query, params):
|
||||
@ -50,10 +55,15 @@ def response(resp):
|
||||
if result['kind'] in ('track', 'playlist'):
|
||||
title = result['title']
|
||||
content = result['description']
|
||||
publishedDate = parser.parse(result['last_modified'])
|
||||
uri = quote_plus(result['uri'])
|
||||
embedded = embedded_url.format(uri=uri)
|
||||
|
||||
# append result
|
||||
results.append({'url': result['permalink_url'],
|
||||
'title': title,
|
||||
'publishedDate': publishedDate,
|
||||
'embedded': embedded,
|
||||
'content': content})
|
||||
|
||||
# return results
|
||||
|
@ -7,7 +7,7 @@
|
||||
# @using-api no (TODO, rewrite to api)
|
||||
# @results HTML (using search portal)
|
||||
# @stable no (HTML can change)
|
||||
# @parse url, title, publishedDate, thumbnail
|
||||
# @parse url, title, publishedDate, thumbnail, embedded
|
||||
#
|
||||
# @todo rewrite to api
|
||||
# @todo set content-parameter with correct data
|
||||
@ -33,6 +33,10 @@ title_xpath = './a/div[@class="data"]/p[@class="title"]/text()'
|
||||
results_xpath = '//div[@id="browse_content"]/ol/li'
|
||||
publishedDate_xpath = './/p[@class="meta"]//attribute::datetime'
|
||||
|
||||
embedded_url = '<iframe data-src="//player.vimeo.com/video{videoid}" ' +\
|
||||
'width="540" height="304" frameborder="0" ' +\
|
||||
'webkitallowfullscreen mozallowfullscreen allowfullscreen></iframe>'
|
||||
|
||||
|
||||
# do search-request
|
||||
def request(query, params):
|
||||
@ -56,11 +60,13 @@ def response(resp):
|
||||
|
||||
# parse results
|
||||
for result in dom.xpath(results_xpath):
|
||||
url = base_url + result.xpath(url_xpath)[0]
|
||||
videoid = result.xpath(url_xpath)[0]
|
||||
url = base_url + videoid
|
||||
title = p.unescape(extract_text(result.xpath(title_xpath)))
|
||||
thumbnail = extract_text(result.xpath(content_xpath)[0])
|
||||
publishedDate = parser.parse(extract_text(
|
||||
result.xpath(publishedDate_xpath)[0]))
|
||||
embedded = embedded_url.format(videoid=videoid)
|
||||
|
||||
# append result
|
||||
results.append({'url': url,
|
||||
@ -68,6 +74,7 @@ def response(resp):
|
||||
'content': '',
|
||||
'template': 'videos.html',
|
||||
'publishedDate': publishedDate,
|
||||
'embedded': embedded,
|
||||
'thumbnail': thumbnail})
|
||||
|
||||
# return results
|
||||
|
@ -6,7 +6,7 @@
|
||||
# @using-api yes
|
||||
# @results JSON
|
||||
# @stable yes
|
||||
# @parse url, title, content, publishedDate, thumbnail
|
||||
# @parse url, title, content, publishedDate, thumbnail, embedded
|
||||
|
||||
from json import loads
|
||||
from urllib import urlencode
|
||||
@ -19,7 +19,11 @@ language_support = True
|
||||
|
||||
# search-url
|
||||
base_url = 'https://gdata.youtube.com/feeds/api/videos'
|
||||
search_url = base_url + '?alt=json&{query}&start-index={index}&max-results=5' # noqa
|
||||
search_url = base_url + '?alt=json&{query}&start-index={index}&max-results=5'
|
||||
|
||||
embedded_url = '<iframe width="540" height="304" ' +\
|
||||
'data-src="//www.youtube-nocookie.com/embed/{videoid}" ' +\
|
||||
'frameborder="0" allowfullscreen></iframe>'
|
||||
|
||||
|
||||
# do search-request
|
||||
@ -60,6 +64,8 @@ def response(resp):
|
||||
if url.endswith('&'):
|
||||
url = url[:-1]
|
||||
|
||||
videoid = url[32:]
|
||||
|
||||
title = result['title']['$t']
|
||||
content = ''
|
||||
thumbnail = ''
|
||||
@ -72,12 +78,15 @@ def response(resp):
|
||||
|
||||
content = result['content']['$t']
|
||||
|
||||
embedded = embedded_url.format(videoid=videoid)
|
||||
|
||||
# append result
|
||||
results.append({'url': url,
|
||||
'title': title,
|
||||
'content': content,
|
||||
'template': 'videos.html',
|
||||
'publishedDate': publishedDate,
|
||||
'embedded': embedded,
|
||||
'thumbnail': thumbnail})
|
||||
|
||||
# return results
|
||||
|
@ -35,6 +35,10 @@ engines:
|
||||
engine : currency_convert
|
||||
categories : general
|
||||
shortcut : cc
|
||||
|
||||
- name : deezer
|
||||
engine : deezer
|
||||
shortcut : dz
|
||||
|
||||
- name : deviantart
|
||||
engine : deviantart
|
||||
|
4
searx/static/themes/oscar/js/searx.min.js
vendored
4
searx/static/themes/oscar/js/searx.min.js
vendored
File diff suppressed because one or more lines are too long
@ -63,6 +63,18 @@ $(document).ready(function(){
|
||||
$(this).toggleClass(btnClass);
|
||||
$(this).toggleClass('btn-default');
|
||||
});
|
||||
|
||||
/**
|
||||
* change text during btn-toggle click if possible
|
||||
*/
|
||||
$('.media-loader').click(function() {
|
||||
var target = $(this).data('target');
|
||||
var iframe_load = $(target + ' > iframe');
|
||||
var srctest = iframe_load.attr('src');
|
||||
if(srctest === undefined || srctest === false){
|
||||
iframe_load.attr('src', iframe_load.data('src'));
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* Select or deselect every categories on double clic
|
||||
|
@ -5,8 +5,20 @@
|
||||
{% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
|
||||
<small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
|
||||
|
||||
{% if result.embedded %}
|
||||
<small> • <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>
|
||||
{% endif %}
|
||||
|
||||
{% if result.content %}<p class="result-content">{{ result.content|safe }}</p>{% endif %}
|
||||
|
||||
{% if result.embedded %}
|
||||
<div id="result-media-{{ index }}" class="collapse">
|
||||
{% autoescape false %}
|
||||
{{ result.embedded }}
|
||||
{% endautoescape %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<span class="label label-default pull-right">{{ result.engine }}</span>
|
||||
|
@ -5,6 +5,10 @@
|
||||
{% if result.publishedDate %}<time class="text-muted" datetime="{{ result.pubdate }}" >{{ result.publishedDate }}</time>{% endif %}
|
||||
<small><a class="text-info" href="https://web.archive.org/web/{{ result.url }}">{{ icon('link') }} {{ _('cached') }}</a></small>
|
||||
|
||||
{% if result.embedded %}
|
||||
<small> • <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>
|
||||
{% endif %}
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row">
|
||||
<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 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% if result.embedded %}
|
||||
<div id="result-video-{{ index }}" class="collapse">
|
||||
{% autoescape false %}
|
||||
{{ result.embedded }}
|
||||
{% endautoescape %}
|
||||
</div>
|
||||
{% endif %}
|
||||
|
||||
<div class="clearfix"></div>
|
||||
|
||||
<span class="label label-default pull-right">{{ result.engine }}</span>
|
||||
|
Loading…
Reference in New Issue
Block a user