├── LICENSE ├── README.md ├── app.js ├── hn.png ├── index.html └── style.css /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Karan Goel 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | scInstant 2 | ========= 3 | 4 | SoundCloud Instant Search. 5 | 6 | 7 | 8 | *A Saturday morning hack.* 9 | 10 | ### Built with 11 | 12 | - [SoundCloud JS SDK](http://developers.soundcloud.com/docs/api/sdks#javascript) 13 | - [jQuery](http://jquery.com/) 14 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | $(function(){ 2 | 3 | $(document).height($(window).height()); 4 | 5 | // SC api key 6 | var client_id = '7182630dc6a6fc8aa606657648545826'; 7 | 8 | // store all tracks after a search query 9 | var all_tracks = []; 10 | 11 | // timer to search only after a while 12 | var timer; 13 | 14 | // iframe that stores the SC player 15 | var iframe = $("#widget")[0]; 16 | 17 | // the SC Widget object 18 | var widget; 19 | 20 | // initialize the soundcloud app 21 | SC.initialize({ 22 | client_id: client_id 23 | }); 24 | 25 | // on page load, start with a single song 26 | iframe.src = "http://w.soundcloud.com/player/?url=https://soundcloud.com/withlovexavier/drake-medley"; 27 | widget = SC.Widget(iframe); 28 | 29 | // keyboard shortcut bindings 30 | $(document).keydown(function(e) { 31 | // this won't work if search field is focussed 32 | if (!$("#searchterm").is(':focus')) { 33 | if (e.keyCode == 39) { 34 | // right arrow key pressed, play next 35 | next(); 36 | } else if (e.keyCode == 32) { 37 | // space key to toggle playback 38 | toggle(); 39 | } else if (e.shiftKey && e.keyCode == 38) { 40 | // shift up 41 | volumeUp(); 42 | } else if (e.shiftKey && e.keyCode == 40) { 43 | // shift down 44 | volumeDown(); 45 | } 46 | } 47 | }); 48 | 49 | // bind events to the widget 50 | widget.bind(SC.Widget.Events.READY, function() { 51 | // when the track finishes, play the next one 52 | widget.bind(SC.Widget.Events.FINISH, function(e) { 53 | next(); 54 | }); 55 | }); 56 | 57 | // main function that handles searching 58 | $('#searchterm').keyup(function(event) { 59 | 60 | event.preventDefault(); 61 | 62 | // google analytics 63 | ga('send', 'event', 'input', 'search'); 64 | 65 | var q = $("#searchterm").val(); 66 | 67 | // validate query 68 | if (q == '' || q == undefined) { 69 | return; 70 | } 71 | 72 | if (event.keyCode == 17 || event.keyCode == 18 || event.keyCode == 91 || 73 | event.keyCode == 9 || event.keyCode == 16) { 74 | // control, option, command, tab, shift 75 | return; 76 | } 77 | 78 | clearTimeout(timer); 79 | 80 | timer = setTimeout(function() { 81 | instaSearch(q); 82 | }, 200); // wait for 200ms after search query 83 | 84 | }); 85 | 86 | // searches and plays a track 87 | function instaSearch(q) { 88 | SC.get('/tracks', { q: q, limit: 10 }, function(tracks) { 89 | if (tracks.length == 0) { 90 | cleanUpSpace(); 91 | $('#error').append('No tracks found'); 92 | } else { 93 | all_tracks = tracks; 94 | var track = all_tracks.splice(0, 1)[0]; 95 | playTrack(track); 96 | } 97 | }); 98 | } 99 | 100 | // takes a track from SoundCloud and plays it. 101 | function playTrack(track) { 102 | ga('send', 'event', 'play', 'songPla'); 103 | cleanUpSpace(); 104 | // console.log(track.uri); 105 | // update the iframe source 106 | widget.load(track.uri, { 107 | auto_play: true, 108 | buying: false, 109 | sharing: false, 110 | show_playcount: false, 111 | show_comments: false 112 | }); 113 | 114 | // set the title of the track 115 | $('#trackname').text(track.title); 116 | 117 | // console.log("loaded " + track.title); 118 | } 119 | 120 | // toggle play and paused state of audio player 121 | var toggle = function() { 122 | widget.toggle(); 123 | } 124 | 125 | // play the next song in queue and remove the track that 126 | // is to be played. 127 | var next = function() { 128 | if (all_tracks.length != 0) { 129 | var track = all_tracks.splice(0, 1)[0]; 130 | playTrack(track); 131 | } else { 132 | cleanUpSpace(); 133 | $('#error').append('No more songs. Try searching.'); 134 | $('#searchterm').focus(); 135 | } 136 | } 137 | 138 | var volumeUp = function() { 139 | widget.getVolume(function(volume) { 140 | widget.setVolume(Math.min(100, volume + 5)); 141 | }); 142 | } 143 | 144 | var volumeDown = function() { 145 | widget.getVolume(function(volume) { 146 | widget.setVolume(Math.max(0, volume - 5)); 147 | }); 148 | } 149 | 150 | var cleanUpSpace = function() { 151 | $('#widget').empty(); 152 | $('#error').empty(); 153 | } 154 | 155 | }); 156 | 157 | 158 | -------------------------------------------------------------------------------- /hn.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/karan/scInstant/81c442f1a23d99dfc16740e8786a362aa3936eea/hn.png -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SoundCloud Instant Search 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | Fork me on GitHub 19 | 20 |
21 | 22 | 33 | 34 | 37 | 38 |
39 |
40 | 41 |
42 | 43 |
44 |

space - play/pause, right arrow - next song, shift up/down - volume

45 |

46 |

Open source project by Karan Goel (@TheKaranGoel).

47 |

Get notified when I make something really cool.

48 |
49 |
50 | 51 | 52 | 53 | 62 | 63 | 64 | 65 | 72 | 73 | 74 | -------------------------------------------------------------------------------- /style.css: -------------------------------------------------------------------------------- 1 | html,body { height: 100%; margin: 0px; padding: 0px; } 2 | 3 | body { 4 | background-color: #ffffff; 5 | font-family: avenir, 'avenir next', helvetica, arial, sans-serif; 6 | text-align: center; 7 | } 8 | 9 | *::-webkit-input-placeholder { 10 | color: #aaa; 11 | } 12 | *:-moz-placeholder { 13 | color: #aaa; 14 | } 15 | *::-moz-placeholder { 16 | color: #aaa; 17 | } 18 | *:-ms-input-placeholder { 19 | color: #aaa; 20 | } 21 | 22 | a { 23 | color: #FF6600; 24 | } 25 | 26 | #container { 27 | margin-left: 10%; 28 | margin-right: 10%; 29 | padding: 0% 5%; 30 | /*background-color: #DDD;*/ 31 | height: 100%; 32 | } 33 | 34 | #header { 35 | margin-bottom: 30px; 36 | } 37 | 38 | #logo:before { 39 | content: "scInstant"; 40 | font-size: 3.5em; 41 | } 42 | 43 | #logo { 44 | font-weight: 100; 45 | color: #FF6600; 46 | } 47 | 48 | #sharing { 49 | /*width: 50%;*/ 50 | display: inline-block; 51 | } 52 | 53 | #sharing iframe { 54 | vertical-align: middle; 55 | } 56 | 57 | .twitter-share-button { 58 | float: left; 59 | } 60 | 61 | .fb-like { 62 | float: right; 63 | } 64 | 65 | #search { 66 | margin-top: 30px; 67 | } 68 | 69 | #app { 70 | margin: 5% 10%; 71 | } 72 | 73 | #searchterm { 74 | width: 80%; 75 | max-width: 400px; 76 | height: 20px; 77 | font-size: 18px; 78 | margin-top: 1px; 79 | border-radius: 8px; 80 | border: 0; 81 | color: #111; 82 | background: rgba(0,0,0,.1); 83 | padding: 10px; 84 | outline: 0px; 85 | box-shadow: 0 1px 0 rgba(255,255,255,.15), 86 | 0 2px 4px rgba(0,0,0,.2) inset, 87 | 0 0 12px rgba(255,255,255,.1); 88 | } 89 | 90 | #widget { 91 | margin-top: 1em; 92 | display:block; 93 | border:0; 94 | } 95 | 96 | #error { 97 | color: #FF4136; 98 | font-weight: 600; 99 | margin: 20px; 100 | } 101 | --------------------------------------------------------------------------------