summaryrefslogtreecommitdiff
path: root/mpv/scripts/youtube-serarch.lua
blob: dfe04c6998864aeaf4b87335eff10e3e2b29e1c5 (plain)
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)