mirror of
				https://github.com/searxng/searxng
				synced 2024-01-01 19:24:07 +01:00 
			
		
		
		
	
						commit
						98aa70cd41
					
				
					 7 changed files with 207 additions and 29 deletions
				
			
		
							
								
								
									
										60
									
								
								searx/engines/spotify.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								searx/engines/spotify.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,60 @@ | ||||||
|  | ## Spotify (Music) | ||||||
|  | # | ||||||
|  | # @website     https://spotify.com | ||||||
|  | # @provide-api yes (https://developer.spotify.com/web-api/search-item/) | ||||||
|  | # | ||||||
|  | # @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 = 'https://api.spotify.com/' | ||||||
|  | search_url = url + 'v1/search?{query}&type=track&offset={offset}' | ||||||
|  | 
 | ||||||
|  | embedded_url = '<iframe data-src="https://embed.spotify.com/?uri=spotify:track:{audioid}"\ | ||||||
|  |      width="300" height="80" frameborder="0" allowtransparency="true"></iframe>' | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | # do search-request | ||||||
|  | def request(query, params): | ||||||
|  |     offset = (params['pageno'] - 1) * 20 | ||||||
|  | 
 | ||||||
|  |     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('tracks', {}).get('items', {}): | ||||||
|  |         if result['type'] == 'track': | ||||||
|  |             title = result['name'] | ||||||
|  |             url = result['external_urls']['spotify'] | ||||||
|  |             content = result['artists'][0]['name'] +\ | ||||||
|  |                 " • " +\ | ||||||
|  |                 result['album']['name'] +\ | ||||||
|  |                 " • " + result['name'] | ||||||
|  |             embedded = embedded_url.format(audioid=result['id']) | ||||||
|  | 
 | ||||||
|  |             # append result | ||||||
|  |             results.append({'url': url, | ||||||
|  |                             'title': title, | ||||||
|  |                             'embedded': embedded, | ||||||
|  |                             'content': content}) | ||||||
|  | 
 | ||||||
|  |     # return results | ||||||
|  |     return results | ||||||
|  | @ -84,12 +84,6 @@ engines: | ||||||
| #    shortcut : fa | #    shortcut : fa | ||||||
| #    api_key : 'apikey' # required! | #    api_key : 'apikey' # required! | ||||||
| 
 | 
 | ||||||
| # down - website is under criminal investigation by the UK |  | ||||||
| #  - name : filecrop |  | ||||||
| #    engine : filecrop |  | ||||||
| #    categories : files |  | ||||||
| #    shortcut : fc |  | ||||||
| 
 |  | ||||||
|   - name : 500px |   - name : 500px | ||||||
|     engine : www500px |     engine : www500px | ||||||
|     shortcut : px |     shortcut : px | ||||||
|  | @ -109,11 +103,6 @@ engines: | ||||||
| # Or you can use the html non-stable engine, activated by default | # Or you can use the html non-stable engine, activated by default | ||||||
|     engine : flickr_noapi |     engine : flickr_noapi | ||||||
| 
 | 
 | ||||||
|   - name : general-file |  | ||||||
|     engine : generalfile |  | ||||||
|     shortcut : gf |  | ||||||
|     disabled : True |  | ||||||
| 
 |  | ||||||
|   - name : gigablast |   - name : gigablast | ||||||
|     engine : gigablast |     engine : gigablast | ||||||
|     shortcut : gb |     shortcut : gb | ||||||
|  | @ -201,6 +190,10 @@ engines: | ||||||
|     shortcut : scc |     shortcut : scc | ||||||
|     disabled : True |     disabled : True | ||||||
| 
 | 
 | ||||||
|  |   - name : spotify | ||||||
|  |     engine : spotify | ||||||
|  |     shortcut : stf | ||||||
|  | 
 | ||||||
|   - name : subtitleseeker |   - name : subtitleseeker | ||||||
|     engine : subtitleseeker |     engine : subtitleseeker | ||||||
|     shortcut : ss |     shortcut : ss | ||||||
|  |  | ||||||
|  | @ -12,9 +12,14 @@ class TestBlekkoImagesEngine(SearxTestCase): | ||||||
|         dicto['pageno'] = 0 |         dicto['pageno'] = 0 | ||||||
|         dicto['safesearch'] = 1 |         dicto['safesearch'] = 1 | ||||||
|         params = blekko_images.request(query, dicto) |         params = blekko_images.request(query, dicto) | ||||||
|         self.assertTrue('url' in params) |         self.assertIn('url', params) | ||||||
|         self.assertTrue(query in params['url']) |         self.assertIn(query, params['url']) | ||||||
|         self.assertTrue('blekko.com' in params['url']) |         self.assertIn('blekko.com', params['url']) | ||||||
|  |         self.assertIn('page', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['pageno'] = 1 | ||||||
|  |         params = blekko_images.request(query, dicto) | ||||||
|  |         self.assertNotIn('page', params['url']) | ||||||
| 
 | 
 | ||||||
|     def test_response(self): |     def test_response(self): | ||||||
|         self.assertRaises(AttributeError, blekko_images.response, None) |         self.assertRaises(AttributeError, blekko_images.response, None) | ||||||
|  |  | ||||||
|  | @ -11,9 +11,14 @@ class TestGoogleImagesEngine(SearxTestCase): | ||||||
|         dicto = defaultdict(dict) |         dicto = defaultdict(dict) | ||||||
|         dicto['pageno'] = 1 |         dicto['pageno'] = 1 | ||||||
|         params = google_images.request(query, dicto) |         params = google_images.request(query, dicto) | ||||||
|         self.assertTrue('url' in params) |         self.assertIn('url', params) | ||||||
|         self.assertTrue(query in params['url']) |         self.assertIn(query, params['url']) | ||||||
|         self.assertTrue('googleapis.com' in params['url']) |         self.assertIn('googleapis.com', params['url']) | ||||||
|  |         self.assertIn('safe=on', params['url']) | ||||||
|  | 
 | ||||||
|  |         dicto['safesearch'] = 0 | ||||||
|  |         params = google_images.request(query, dicto) | ||||||
|  |         self.assertIn('safe=off', params['url']) | ||||||
| 
 | 
 | ||||||
|     def test_response(self): |     def test_response(self): | ||||||
|         self.assertRaises(AttributeError, google_images.response, None) |         self.assertRaises(AttributeError, google_images.response, None) | ||||||
|  |  | ||||||
							
								
								
									
										124
									
								
								searx/tests/engines/test_spotify.py
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										124
									
								
								searx/tests/engines/test_spotify.py
									
										
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,124 @@ | ||||||
|  | from collections import defaultdict | ||||||
|  | import mock | ||||||
|  | from searx.engines import spotify | ||||||
|  | from searx.testing import SearxTestCase | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
|  | class TestSpotifyEngine(SearxTestCase): | ||||||
|  | 
 | ||||||
|  |     def test_request(self): | ||||||
|  |         query = 'test_query' | ||||||
|  |         dicto = defaultdict(dict) | ||||||
|  |         dicto['pageno'] = 0 | ||||||
|  |         params = spotify.request(query, dicto) | ||||||
|  |         self.assertIn('url', params) | ||||||
|  |         self.assertIn(query, params['url']) | ||||||
|  |         self.assertIn('spotify.com', params['url']) | ||||||
|  | 
 | ||||||
|  |     def test_response(self): | ||||||
|  |         self.assertRaises(AttributeError, spotify.response, None) | ||||||
|  |         self.assertRaises(AttributeError, spotify.response, []) | ||||||
|  |         self.assertRaises(AttributeError, spotify.response, '') | ||||||
|  |         self.assertRaises(AttributeError, spotify.response, '[]') | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{}') | ||||||
|  |         self.assertEqual(spotify.response(response), []) | ||||||
|  | 
 | ||||||
|  |         response = mock.Mock(text='{"data": []}') | ||||||
|  |         self.assertEqual(spotify.response(response), []) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |           "tracks": { | ||||||
|  |             "href": "https://api.spotify.com/v1/search?query=nosfell&offset=0&limit=20&type=track", | ||||||
|  |             "items": [ | ||||||
|  |               { | ||||||
|  |                 "album": { | ||||||
|  |                   "album_type": "album", | ||||||
|  |                   "external_urls": { | ||||||
|  |                     "spotify": "https://open.spotify.com/album/5c9ap1PBkSGLxT3J73toxA" | ||||||
|  |                   }, | ||||||
|  |                   "href": "https://api.spotify.com/v1/albums/5c9ap1PBkSGLxT3J73toxA", | ||||||
|  |                   "id": "5c9ap1PBkSGLxT3J73toxA", | ||||||
|  |                   "name": "Album Title", | ||||||
|  |                   "type": "album", | ||||||
|  |                   "uri": "spotify:album:5c9ap1PBkSGLxT3J73toxA" | ||||||
|  |                 }, | ||||||
|  |                 "artists": [ | ||||||
|  |                   { | ||||||
|  |                     "external_urls": { | ||||||
|  |                       "spotify": "https://open.spotify.com/artist/0bMc6b75FfZEpQHG1jifKu" | ||||||
|  |                     }, | ||||||
|  |                     "href": "https://api.spotify.com/v1/artists/0bMc6b75FfZEpQHG1jifKu", | ||||||
|  |                     "id": "0bMc6b75FfZEpQHG1jifKu", | ||||||
|  |                     "name": "Artist Name", | ||||||
|  |                     "type": "artist", | ||||||
|  |                     "uri": "spotify:artist:0bMc6b75FfZEpQHG1jifKu" | ||||||
|  |                   } | ||||||
|  |                 ], | ||||||
|  |                 "disc_number": 1, | ||||||
|  |                 "duration_ms": 202386, | ||||||
|  |                 "explicit": false, | ||||||
|  |                 "external_ids": { | ||||||
|  |                   "isrc": "FRV640600067" | ||||||
|  |                 }, | ||||||
|  |                 "external_urls": { | ||||||
|  |                   "spotify": "https://open.spotify.com/track/2GzvFiedqW8hgqUpWcASZa" | ||||||
|  |                 }, | ||||||
|  |                 "href": "https://api.spotify.com/v1/tracks/2GzvFiedqW8hgqUpWcASZa", | ||||||
|  |                 "id": "1000", | ||||||
|  |                 "is_playable": true, | ||||||
|  |                 "name": "Title of track", | ||||||
|  |                 "popularity": 6, | ||||||
|  |                 "preview_url": "https://p.scdn.co/mp3-preview/7b8ecda580965a066b768c2647f877e43f7b1a0a", | ||||||
|  |                 "track_number": 3, | ||||||
|  |                 "type": "track", | ||||||
|  |                 "uri": "spotify:track:2GzvFiedqW8hgqUpWcASZa" | ||||||
|  |               } | ||||||
|  |             ], | ||||||
|  |             "limit": 20, | ||||||
|  |             "next": "https://api.spotify.com/v1/search?query=nosfell&offset=20&limit=20&type=track", | ||||||
|  |             "offset": 0, | ||||||
|  |             "previous": null, | ||||||
|  |             "total": 107 | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = spotify.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 1) | ||||||
|  |         self.assertEqual(results[0]['title'], 'Title of track') | ||||||
|  |         self.assertEqual(results[0]['url'], 'https://open.spotify.com/track/2GzvFiedqW8hgqUpWcASZa') | ||||||
|  |         self.assertEqual(results[0]['content'], 'Artist Name • Album Title • Title of track') | ||||||
|  |         self.assertIn('1000', results[0]['embedded']) | ||||||
|  | 
 | ||||||
|  |         json = """ | ||||||
|  |         { | ||||||
|  |           "tracks": { | ||||||
|  |             "href": "https://api.spotify.com/v1/search?query=nosfell&offset=0&limit=20&type=track", | ||||||
|  |             "items": [ | ||||||
|  |               { | ||||||
|  |                 "href": "https://api.spotify.com/v1/tracks/2GzvFiedqW8hgqUpWcASZa", | ||||||
|  |                 "id": "1000", | ||||||
|  |                 "is_playable": true, | ||||||
|  |                 "name": "Title of track", | ||||||
|  |                 "popularity": 6, | ||||||
|  |                 "preview_url": "https://p.scdn.co/mp3-preview/7b8ecda580965a066b768c2647f877e43f7b1a0a", | ||||||
|  |                 "track_number": 3, | ||||||
|  |                 "type": "album", | ||||||
|  |                 "uri": "spotify:track:2GzvFiedqW8hgqUpWcASZa" | ||||||
|  |               } | ||||||
|  |             ], | ||||||
|  |             "limit": 20, | ||||||
|  |             "next": "https://api.spotify.com/v1/search?query=nosfell&offset=20&limit=20&type=track", | ||||||
|  |             "offset": 0, | ||||||
|  |             "previous": null, | ||||||
|  |             "total": 107 | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |         """ | ||||||
|  |         response = mock.Mock(text=json) | ||||||
|  |         results = spotify.response(response) | ||||||
|  |         self.assertEqual(type(results), list) | ||||||
|  |         self.assertEqual(len(results), 0) | ||||||
|  | @ -75,12 +75,6 @@ class TestYahooEngine(SearxTestCase): | ||||||
|     <li> |     <li> | ||||||
|         <div class="dd algo lst Sr"> |         <div class="dd algo lst Sr"> | ||||||
|             <div class="compTitle"> |             <div class="compTitle"> | ||||||
|                 <h3 class="title"><a class=" td-u" href="http://r.search.yahoo.com/_ylt=AwrBT7zgEudUW.wAe2ZXNyoA; |  | ||||||
|                      _ylu=X3oDMTBybGY3bmpvBGNvbG8DYmYxBHBvcwMyBHZ0aWQDBHNlYwNzcg--/RV=2\/RE=1424458593/RO=10 |  | ||||||
|                      /RU=https%3a%2f%2fthis.is.the.second.url%2f/RK=0/RS=jIctjj_cBH1Efj88GCgHKp3__Qk-" |  | ||||||
|                      target="_blank" data-bid="54e712e136926"> |  | ||||||
|                      This is the second <b><b>title</b></b></a> |  | ||||||
|                 </h3> |  | ||||||
|             </div> |             </div> | ||||||
|             <div class="compText aAbs"> |             <div class="compText aAbs"> | ||||||
|                 <p class="lh-18">This is the second content</p> |                 <p class="lh-18">This is the second content</p> | ||||||
|  | @ -102,16 +96,12 @@ class TestYahooEngine(SearxTestCase): | ||||||
|         """ |         """ | ||||||
|         response = mock.Mock(text=html) |         response = mock.Mock(text=html) | ||||||
|         results = yahoo.response(response) |         results = yahoo.response(response) | ||||||
|         print results |  | ||||||
|         self.assertEqual(type(results), list) |         self.assertEqual(type(results), list) | ||||||
|         self.assertEqual(len(results), 3) |         self.assertEqual(len(results), 2) | ||||||
|         self.assertEqual(results[0]['title'], 'This is the title') |         self.assertEqual(results[0]['title'], 'This is the title') | ||||||
|         self.assertEqual(results[0]['url'], 'https://this.is.the.url/') |         self.assertEqual(results[0]['url'], 'https://this.is.the.url/') | ||||||
|         self.assertEqual(results[0]['content'], 'This is the content') |         self.assertEqual(results[0]['content'], 'This is the content') | ||||||
|         self.assertEqual(results[1]['title'], 'This is the second title') |         self.assertEqual(results[1]['suggestion'], 'This is the suggestion') | ||||||
|         self.assertEqual(results[1]['url'], 'https://this.is.the.second.url/') |  | ||||||
|         self.assertEqual(results[1]['content'], 'This is the second content') |  | ||||||
|         self.assertEqual(results[2]['suggestion'], 'This is the suggestion') |  | ||||||
| 
 | 
 | ||||||
|         html = """ |         html = """ | ||||||
| <ol class="reg mb-15 searchCenterMiddle"> | <ol class="reg mb-15 searchCenterMiddle"> | ||||||
|  |  | ||||||
|  | @ -28,6 +28,7 @@ from searx.tests.engines.test_piratebay import *  # noqa | ||||||
| from searx.tests.engines.test_searchcode_code import *  # noqa | from searx.tests.engines.test_searchcode_code import *  # noqa | ||||||
| from searx.tests.engines.test_searchcode_doc import *  # noqa | from searx.tests.engines.test_searchcode_doc import *  # noqa | ||||||
| from searx.tests.engines.test_soundcloud import *  # noqa | from searx.tests.engines.test_soundcloud import *  # noqa | ||||||
|  | from searx.tests.engines.test_spotify import *  # noqa | ||||||
| from searx.tests.engines.test_stackoverflow import *  # noqa | from searx.tests.engines.test_stackoverflow import *  # noqa | ||||||
| from searx.tests.engines.test_startpage import *  # noqa | from searx.tests.engines.test_startpage import *  # noqa | ||||||
| from searx.tests.engines.test_subtitleseeker import *  # noqa | from searx.tests.engines.test_subtitleseeker import *  # noqa | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		
		Reference in a new issue
	
	 Adam Tauber
						Adam Tauber