1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
|
--[[
This script allows users to search and open youtube results from within mpv.
Available at: https://github.com/CogentRedTester/mpv-scripts
Users can open the search page with Y, and use Y again to open a search.
Alternatively, Ctrl+y can be used at any time to open a search.
Esc can be used to close the page.
Enter will open the selected item, Shift+Enter will append the item to the playlist.
This script requires that my other scripts `scroll-list` and `user-input` be installed.
scroll-list.lua and user-input-module.lua must be in the ~~/script-modules/ directory,
while user-input.lua should be loaded by mpv normally.
https://github.com/CogentRedTester/mpv-scroll-list
https://github.com/CogentRedTester/mpv-user-input
This script also requires a youtube API key to be entered.
The API key must be passed to the `API_key` script-opt.
A personal API key is free and can be created from:
https://console.developers.google.com/apis/api/youtube.googleapis.com/
The script also requires that curl be in the system path.
]]--
local mp = require "mp"
local msg = require "mp.msg"
local utils = require "mp.utils"
local opts = require "mp.options"
package.path = mp.command_native({"expand-path", "~~/lua-modules/?.lua;"}) .. package.path
local ui = require "user-input-module"
local list = require "scroll-list"
list.header = "Youtube Search Results\\N-----------------------------"
list.num_entries = 18
list.list_style = [[{\fs10}\N{\q2\fs25\c&Hffffff&}]]
local o = {
API_key = "AIzaSyB3IuyFp8C5SYEgJ0BSGgKZZjfUtuVGl44",
num_results = 40
}
opts.read_options(o)
local ass_escape = list.ass_escape
--taken from: https://gist.github.com/liukun/f9ce7d6d14fa45fe9b924a3eed5c3d99
local function urlencode(url)
if type(url) ~= "string" then return url end
url = url:gsub("\n", "\r\n")
url = url:gsub("([^%w ])", function (c) string.format("%%%02X", string.byte(c)) end)
url = url:gsub(" ", "+")
return url
end
--sends an API request
local function send_request(type, queries)
local url = "https://www.googleapis.com/youtube/v3/"..type
url = url.."?key="..o.API_key
for key, value in pairs(queries) do
url = url.."&"..key.."="..urlencode(value)
end
local request = mp.command_native({
name = "subprocess",
capture_stdout = true,
capture_stderr = true,
playback_only = false,
args = {"curl", url}
})
local response = utils.parse_json(request.stdout)
if request.status ~= 0 then msg.error(request.stderr) ; return nil end
return response
end
local function insert_video(item)
list:insert({
ass = ("%s {\\c&aaaaaa&}%s"):format(ass_escape(item.snippet.title), ass_escape(item.snippet.channelTitle)),
url = "https://www.youtube.com/watch?v="..item.id.videoId
})
end
local function insert_playlist(item)
list:insert({
ass = ("🖿 %s {\\c&aaaaaa&}%s"):format(ass_escape(item.snippet.title), ass_escape(item.snippet.channelTitle)),
url = "https://www.youtube.com/playlist?list="..item.id.playlistId
})
end
local function insert_channel(item)
list:insert({
ass = ("👤 %s"):format(ass_escape(item.snippet.title)),
url = "https://www.youtube.com/channel/"..item.id.channelId
})
end
local function reset_list()
list.selected = 1
list:clear()
end
local function search(query)
local response = send_request("search", {
q = query,
part = "id,snippet",
maxResults = o.num_results
})
if not response then return end
reset_list()
for _, item in ipairs(response.items) do
if item.id.kind == "youtube#video" then
insert_video(item)
elseif item.id.kind == "youtube#playlist" then
insert_playlist(item)
elseif item.id.kind == "youtube#channel" then
insert_channel(item)
end
end
list.header = "Youtube Search: "..ass_escape(query).."\\N-------------------------------------------------"
list:update()
list:open()
end
local function play_result(flag)
if not list[list.selected] then return end
if flag == "new_window" then mp.commandv("run", "mpv", list[list.selected].url) ; return end
mp.commandv("loadfile", list[list.selected].url, flag)
if flag == "replace" then list:close() end
end
table.insert(list.keybinds, {"ENTER", "play", function() play_result("replace") end, {}})
table.insert(list.keybinds, {"Shift+ENTER", "play_append", function() play_result("append-play") end, {}})
table.insert(list.keybinds, {"Ctrl+ENTER", "play_new_window", function() play_result("new_window") end, {}})
local function open_search_input()
ui.get_user_input(function(input)
if not input then return end
search( input )
end)
end
mp.add_key_binding("Ctrl+y", "yt", open_search_input)
mp.add_key_binding("Y", "youtube-search", function()
if not list.hidden then open_search_input()
else list:open() end
end)
|