├── plugin └── soundcloud.vim ├── README.md └── autoload └── ctrlp └── soundcloud.vim /plugin/soundcloud.vim: -------------------------------------------------------------------------------- 1 | command! -nargs=? -complete=customlist,ctrlp#soundcloud#genres Soundcloud call ctrlp#soundcloud#start() 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vim-soundcloud 2 | 3 | Soundcloud player for Vim 4 | 5 | ![](http://go-gyazo.appspot.com/63314f2b3a439476.png) 6 | 7 | ## Usage 8 | 9 | ``` 10 | :Soundcloud 11 | ``` 12 | 13 | or 14 | 15 | ``` 16 | :Soundcloud [genre] 17 | ``` 18 | 19 | ## Requirements 20 | 21 | [CtrlP](https://github.com/ctrlpvim/ctrlp.vim) 22 | 23 | [webapi-vim](https://github.com/mattn/webapi-vim) 24 | 25 | ## License 26 | 27 | MIT 28 | 29 | ## Author 30 | 31 | Yasuhiro Matsumoto (a.k.a mattn) 32 | -------------------------------------------------------------------------------- /autoload/ctrlp/soundcloud.vim: -------------------------------------------------------------------------------- 1 | if exists('g:loaded_ctrlp_soundcloud') && g:loaded_ctrlp_soundcloud 2 | "finish 3 | endif 4 | let g:loaded_ctrlp_soundcloud = 1 5 | 6 | let s:config_file = get(g:, 'ctrlp_soundcloud_file', '~/.ctrlp-soundcloud') 7 | 8 | let s:soundcloud_var = { 9 | \ 'init': 'ctrlp#soundcloud#init()', 10 | \ 'exit': 'ctrlp#soundcloud#exit()', 11 | \ 'accept': 'ctrlp#soundcloud#accept', 12 | \ 'lname': 'soundcloud', 13 | \ 'sname': 'soundcloud', 14 | \ 'type': 'path', 15 | \ 'sort': 0, 16 | \ 'nolim': 1, 17 | \} 18 | 19 | if exists('g:ctrlp_ext_vars') && !empty(g:ctrlp_ext_vars) 20 | let g:ctrlp_ext_vars = add(g:ctrlp_ext_vars, s:soundcloud_var) 21 | else 22 | let g:ctrlp_ext_vars = [s:soundcloud_var] 23 | endif 24 | 25 | let s:vim_soundcloud_client_id = 'e58dfd1cec88ed21d2b1329902464cfb' 26 | let s:vim_soundcloud_client_secret = '39b4d7d9404bfbbfcf1b45e5e1f8f021' 27 | 28 | function! ctrlp#soundcloud#genres(arglead, cmdline, curpos) 29 | return filter(copy(['all-music', 'all-audio', 'alternativerock', 'ambient', 'classical', 'country', 'danceedm', 'dancehall', 'deephouse', 'disco', 'drumbass', 'dubstep', 'electronic', 'folksingersongwriter', 'hiphoprap', 'house', 'indie', 'jazzblues', 'latin', 'metal', 'piano', 'pop', 'rbsoul', 'reggae', 'reggaeton', 'rock', 'soundtrack', 'techno', 'trance', 'trap', 'triphop', 'world', 'audiobooks', 'business', 'comedy', 'entertainment', 'learning', 'newspolitics', 'religionspirituality', 'science', 'sports', 'storytelling', 'technology']), 'stridx(v:val, a:arglead) == 0') 30 | endfunction 31 | 32 | function! s:authenticate(...) 33 | let refresh_token = get(a:000, 0, '') 34 | 35 | if !empty(refresh_token) 36 | let res = webapi#http#post('https://api.soundcloud.com/oauth2/token', { 37 | \ 'client_id': s:vim_soundcloud_client_id, 38 | \ 'client_secret': s:vim_soundcloud_client_secret, 39 | \ 'grant_type': 'refresh_token', 40 | \ 'refresh_token': refresh_token, 41 | \}) 42 | call writefile([res.content], expand('~/.vim-soundcloud')) 43 | return webapi#json#decode(res.content) 44 | endif 45 | 46 | if filereadable(expand('~/.vim-soundcloud')) 47 | return webapi#json#decode(join(readfile(expand('~/.vim-soundcloud')), "\n")) 48 | endif 49 | 50 | let username = input('username: ') 51 | let password = inputsecret('password: ') 52 | let res = webapi#http#post('https://api.soundcloud.com/oauth2/token', { 53 | \ 'client_id': s:vim_soundcloud_client_id, 54 | \ 'client_secret': s:vim_soundcloud_client_secret, 55 | \ 'grant_type': 'password', 56 | \ 'username': username, 57 | \ 'password': password, 58 | \}) 59 | echomsg string(res) 60 | if res.status == 200 61 | call writefile([res.content], expand('~/.vim-soundcloud')) 62 | endif 63 | return webapi#json#decode(res.content) 64 | endfunction 65 | 66 | function! ctrlp#soundcloud#init() 67 | let ai = {} 68 | try 69 | let ai = s:authenticate() 70 | let res = webapi#http#get('https://api.soundcloud.com/tracks.json', { 71 | \ 'oauth_token': ai.access_token, 72 | \ 'genre': s:genre, 73 | \}) 74 | if res.status == 401 75 | throw "failed" 76 | endif 77 | catch 78 | if empty(ai) || !has_key(ai, 'refresh_token') 79 | echohl ErrorMsg | echom 'failed to authenticate: ' . v:exception | echohl None 80 | sleep 2 81 | return 82 | endif 83 | let ai = s:authenticate(ai.refresh_token) 84 | let res = webapi#http#get('https://api.soundcloud.com/tracks.json', { 85 | \ 'oauth_token': ai.access_token, 86 | \ 'genre': s:genre, 87 | \}) 88 | if res.status == 401 89 | call delete(expand('~/.vim-soundcloud')) 90 | echohl ErrorMsg | echom 'failed to authenticate. try again' | echohl None 91 | sleep 2 92 | return 93 | endif 94 | endtry 95 | let s:list = webapi#json#decode(res.content) 96 | return map(copy(s:list), 'v:val.title . " - " . v:val.user.username') 97 | endfunc 98 | 99 | function! ctrlp#soundcloud#accept(mode, str) 100 | let lines = filter(copy(s:list), 'a:str == v:val.title . " - " . v:val.user.username') 101 | call ctrlp#exit() 102 | redraw! 103 | if len(lines) > 0 && len(lines[0]) > 1 104 | if exists('s:job') && job_status(s:job) != 'stop' 105 | call job_stop(s:job) 106 | endif 107 | let ai = s:authenticate() 108 | if executable('ffplay') 109 | let s:job = job_start(['ffplay', '-autoexit', '-nodisp', lines[0].stream_url . '?oauth_token=' . ai.access_token]) 110 | elseif executable('avplay') 111 | let s:job = job_start(['avplay', '-autoexit', '-nodisp', lines[0].stream_url . '?oauth_token=' . ai.access_token]) 112 | elseif executable('avplay') 113 | let s:job = job_start(['mplayer', lines[0].stream_url . '?oauth_token=' . ai.access_token]) 114 | endif 115 | endif 116 | endfunction 117 | 118 | function! ctrlp#soundcloud#exit() 119 | if exists('s:list') 120 | unlet! s:list 121 | endif 122 | endfunction 123 | 124 | function! ctrlp#soundcloud#start(...) 125 | let s:genre = get(a:000, 0, '') 126 | call ctrlp#init(ctrlp#soundcloud#id()) 127 | endfunction 128 | 129 | let s:id = g:ctrlp_builtins + len(g:ctrlp_ext_vars) 130 | function! ctrlp#soundcloud#id() 131 | return s:id 132 | endfunction 133 | --------------------------------------------------------------------------------