505
									
								
								.config/mpv/scripts/iptv.lua
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										505
									
								
								.config/mpv/scripts/iptv.lua
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,505 @@ | ||||
| --redefine keybindings here if needed; multiple bindings are possible | ||||
| keybinds = { | ||||
|             activate = {'\\', 'MOUSE_BTN2'}, | ||||
|             plsup = {'UP', 'MOUSE_BTN3'}, | ||||
|             plsdown = {'DOWN', 'MOUSE_BTN4'}, | ||||
|             plsenter = {'ENTER', 'MOUSE_BTN0'} | ||||
|         } | ||||
| --hide playlist after specified number of seconds | ||||
| osd_time=10 | ||||
| --show only specified number of playlist entries | ||||
| window=7 | ||||
| --fade video when showing playlist | ||||
| fade=false | ||||
| --if fade=true; -100 — black, 0 — normal | ||||
| plsbrightness=-70 | ||||
| --favorites get promotion to the top of the pls | ||||
| favorites = {} | ||||
| -- END OF CONFIGURABLE VARIABLES | ||||
|  | ||||
| -- put your settings in (SCRIPTS DIR)/_iptvconf.lua | ||||
| pcall(require, "_iptvconf") | ||||
|  | ||||
| local timer | ||||
| --local plscount | ||||
| local pattern="" | ||||
| local is_active | ||||
| local is_playlist_loaded | ||||
|  | ||||
| -- UTF-8 lower/upper conversion | ||||
| local utf8_lc_uc = { | ||||
|   ["a"] = "A", | ||||
|   ["b"] = "B", | ||||
|   ["c"] = "C", | ||||
|   ["d"] = "D", | ||||
|   ["e"] = "E", | ||||
|   ["f"] = "F", | ||||
|   ["g"] = "G", | ||||
|   ["h"] = "H", | ||||
|   ["i"] = "I", | ||||
|   ["j"] = "J", | ||||
|   ["k"] = "K", | ||||
|   ["l"] = "L", | ||||
|   ["m"] = "M", | ||||
|   ["n"] = "N", | ||||
|   ["o"] = "O", | ||||
|   ["p"] = "P", | ||||
|   ["q"] = "Q", | ||||
|   ["r"] = "R", | ||||
|   ["s"] = "S", | ||||
|   ["t"] = "T", | ||||
|   ["u"] = "U", | ||||
|   ["v"] = "V", | ||||
|   ["w"] = "W", | ||||
|   ["x"] = "X", | ||||
|   ["y"] = "Y", | ||||
|   ["z"] = "Z", | ||||
|   ["а"] = "А", | ||||
|   ["б"] = "Б", | ||||
|   ["в"] = "В", | ||||
|   ["г"] = "Г", | ||||
|   ["д"] = "Д", | ||||
|   ["е"] = "Е", | ||||
|   ["ж"] = "Ж", | ||||
|   ["з"] = "З", | ||||
|   ["и"] = "И", | ||||
|   ["й"] = "Й", | ||||
|   ["к"] = "К", | ||||
|   ["л"] = "Л", | ||||
|   ["м"] = "М", | ||||
|   ["н"] = "Н", | ||||
|   ["о"] = "О", | ||||
|   ["п"] = "П", | ||||
|   ["р"] = "Р", | ||||
|   ["с"] = "С", | ||||
|   ["т"] = "Т", | ||||
|   ["у"] = "У", | ||||
|   ["ф"] = "Ф", | ||||
|   ["х"] = "Х", | ||||
|   ["ц"] = "Ц", | ||||
|   ["ч"] = "Ч", | ||||
|   ["ш"] = "Ш", | ||||
|   ["щ"] = "Щ", | ||||
|   ["ъ"] = "Ъ", | ||||
|   ["ы"] = "Ы", | ||||
|   ["ь"] = "Ь", | ||||
|   ["э"] = "Э", | ||||
|   ["ю"] = "Ю", | ||||
|   ["я"] = "Я", | ||||
|   ["ё"] = "Ё" | ||||
| } | ||||
|  | ||||
| local utf8_uc_lc = { | ||||
|   ["A"] = "a", | ||||
|   ["B"] = "b", | ||||
|   ["C"] = "c", | ||||
|   ["D"] = "d", | ||||
|   ["E"] = "e", | ||||
|   ["F"] = "f", | ||||
|   ["G"] = "g", | ||||
|   ["H"] = "h", | ||||
|   ["I"] = "i", | ||||
|   ["J"] = "j", | ||||
|   ["K"] = "k", | ||||
|   ["L"] = "l", | ||||
|   ["M"] = "m", | ||||
|   ["N"] = "n", | ||||
|   ["O"] = "o", | ||||
|   ["P"] = "p", | ||||
|   ["Q"] = "q", | ||||
|   ["R"] = "r", | ||||
|   ["S"] = "s", | ||||
|   ["T"] = "t", | ||||
|   ["U"] = "u", | ||||
|   ["V"] = "v", | ||||
|   ["W"] = "w", | ||||
|   ["X"] = "x", | ||||
|   ["Y"] = "y", | ||||
|   ["Z"] = "z", | ||||
|   ["А"] = "а", | ||||
|   ["Б"] = "б", | ||||
|   ["В"] = "в", | ||||
|   ["Г"] = "г", | ||||
|   ["Д"] = "д", | ||||
|   ["Е"] = "е", | ||||
|   ["Ж"] = "ж", | ||||
|   ["З"] = "з", | ||||
|   ["И"] = "и", | ||||
|   ["Й"] = "й", | ||||
|   ["К"] = "к", | ||||
|   ["Л"] = "л", | ||||
|   ["М"] = "м", | ||||
|   ["Н"] = "н", | ||||
|   ["О"] = "о", | ||||
|   ["П"] = "п", | ||||
|   ["Р"] = "р", | ||||
|   ["С"] = "с", | ||||
|   ["Т"] = "т", | ||||
|   ["У"] = "у", | ||||
|   ["Ф"] = "ф", | ||||
|   ["Х"] = "х", | ||||
|   ["Ц"] = "ц", | ||||
|   ["Ч"] = "ч", | ||||
|   ["Ш"] = "ш", | ||||
|   ["Щ"] = "щ", | ||||
|   ["Ъ"] = "ъ", | ||||
|   ["Ы"] = "ы", | ||||
|   ["Ь"] = "ь", | ||||
|   ["Э"] = "э", | ||||
|   ["Ю"] = "ю", | ||||
|   ["Я"] = "я", | ||||
|   ["Ё"] = "ё" | ||||
| } | ||||
|  | ||||
| --utf8 char pattern | ||||
| local utf8_char="[\1-\127\192-\223][\128-\191]*" | ||||
|  | ||||
| local cyr_chars={'а','б','в','г','д','е','ё','ж','з','и','й','к','л','м','н','о','п','р','с','т','у','ф','х','ц','ч','ш','щ','ъ','ы','ь','э','ю','я'} | ||||
|  | ||||
| -- символы, которые возможно вводить для поиска | ||||
| local chars={} | ||||
| for i=string.byte('a'),string.byte('z') do | ||||
|   table.insert(chars,i) | ||||
| end | ||||
| for i=string.byte('A'),string.byte('Z') do | ||||
|   table.insert(chars,i) | ||||
| end | ||||
| for i=string.byte('0'),string.byte('9') do | ||||
|   table.insert(chars,i) | ||||
| end | ||||
| for _,v in ipairs({',','^','$','(',')','%','.','[',']','*','+','-','?','`',"'",";"}) do | ||||
|   table.insert(chars,string.byte(v)) | ||||
| end | ||||
|  | ||||
| local keybinder = {  | ||||
|   remove = function(action) | ||||
|     for i,_ in ipairs(keybinds[action]) do | ||||
|       mp.remove_key_binding(action..tostring(i)) | ||||
|     end | ||||
|   end, | ||||
|   add = function(action, func, repeatable) | ||||
|     for i,key in ipairs(keybinds[action]) do | ||||
|       assert(type(func)=="function", "not a function") | ||||
|       if repeatable then | ||||
|         mp.add_forced_key_binding(key, action..tostring(i), func, "repeatable") | ||||
|       else | ||||
|         mp.add_forced_key_binding(key, action..tostring(i), func) | ||||
|       end | ||||
|     end | ||||
|   end | ||||
| } | ||||
|  | ||||
| local fader = { | ||||
|   saved_brtns, | ||||
|   on = function(self) | ||||
|     if fade and not self.saved_brtns then | ||||
|         self.saved_brtns = mp.get_property("brightness") | ||||
|         mp.set_property("brightness", plsbrightness) | ||||
|     end | ||||
|   end, | ||||
|   off = function(self) | ||||
|     if fade and self.saved_brtns then | ||||
|       mp.set_property("brightness", self.saved_brtns) | ||||
|       self.saved_brtns=nil | ||||
|     end | ||||
|   end | ||||
| } | ||||
|  | ||||
| local playlister = { | ||||
| -- pls — список элементов плейлиста | ||||
|   pls, | ||||
| -- plsfiltered — список индексов выбранных фильтром элементов плейлиста | ||||
|   plsfiltered, | ||||
|   plspos, | ||||
|   wndstart, | ||||
|   wndend, | ||||
|   cursor, | ||||
|  | ||||
|   init = function(self) | ||||
|     if not self.pls then | ||||
|       self.pls = mp.get_property_native("playlist") | ||||
|     end | ||||
|     mp.commandv("stop") | ||||
|     --need to mark first entry non-current (mpv bug?) | ||||
|     if self.pls[1] then | ||||
|       self.pls[1].current = false | ||||
|     end | ||||
|     if favorites and #favorites>0 then | ||||
|       self:sortfavs() | ||||
|     end | ||||
|     pattern = "" | ||||
|     self.plsfiltered = tablekeys(self.pls) | ||||
|   end, | ||||
|  | ||||
|   show = function(self) | ||||
|     local i | ||||
|     local newpos | ||||
|     local msg | ||||
|     --media-title | ||||
|     --playlist t[2].title | ||||
|  | ||||
|     if not self.plsfiltered then | ||||
|       return | ||||
|     end | ||||
|     if not self.plspos then | ||||
|       self.plspos=mp.get_property_native("playlist-pos-1") | ||||
|       --plscount=mp.get_property_native("playlist-count") | ||||
|     end | ||||
|     if not self.wndstart or not self.cursor then | ||||
|       self.wndstart=1 | ||||
|       self.cursor=0 | ||||
|     end | ||||
|    | ||||
|     msg="" | ||||
|     i = self.wndstart | ||||
|     local prefix | ||||
|     while self.plsfiltered[i] and i<=self.wndstart+window-1 do | ||||
|       if self.pls[self.plsfiltered[i]].current then | ||||
|         prefix="*" | ||||
|       elseif i==self.wndstart+self.cursor then | ||||
|         prefix=">" | ||||
|       else | ||||
|         prefix="  " | ||||
|       end | ||||
|       msg = msg..prefix..(self.pls[self.plsfiltered[i]].title or "").."\n" | ||||
|       i=i+1 | ||||
|     end | ||||
|     if self.wndstart>1 then | ||||
|       msg = "...\n"..msg | ||||
|     else | ||||
|       msg = " \n"..msg | ||||
|     end | ||||
|     if self.wndstart+window-1<#self.plsfiltered then | ||||
|       msg = msg.."..." | ||||
|     end | ||||
|     msg="/"..pattern.."\n"..msg | ||||
|     mp.osd_message(msg, osd_time) | ||||
|   end, | ||||
|  | ||||
|   sortfavs = function(self) | ||||
|     --favorites bubbles to the top | ||||
|     local favs={} | ||||
|     local nonfavs={} | ||||
|     for _,v in ipairs(self.pls) do | ||||
|       if in_array(favorites,v.title) then | ||||
|         favs[#favs+1] = v | ||||
|       else | ||||
|         nonfavs[#nonfavs+1] = v | ||||
|       end | ||||
|     end | ||||
|     for i=1,#nonfavs do | ||||
|       favs[#favs+1] = nonfavs[i] | ||||
|     end | ||||
|     self.pls = favs | ||||
|   end, | ||||
|  | ||||
|   filter = function(self) | ||||
|     self.plsfiltered={} | ||||
|     for i,v in ipairs(self.pls) do | ||||
|       if string.match(mylower(v.title),'.*'..prepat(pattern)..'.*') then | ||||
|         table.insert(self.plsfiltered,i) | ||||
|       end | ||||
|     end | ||||
|     self.wndstart=1 | ||||
|     self.cursor=0 | ||||
|   end, | ||||
|  | ||||
|   down = function(self) | ||||
|     if self.cursor >= #self.plsfiltered-1 then return end | ||||
|     if self.cursor<window-1 then | ||||
|       self.cursor=self.cursor+1 | ||||
|     else | ||||
|       if self.wndstart<#self.plsfiltered-window+1 then | ||||
|         self.wndstart=self.wndstart+1 | ||||
|       end | ||||
|     end | ||||
|     self.show(self) | ||||
|   end, | ||||
|   up = function(self) | ||||
|     if self.cursor>0 then | ||||
|       self.cursor=self.cursor-1 | ||||
|       self.show(self) | ||||
|     else | ||||
|       if self.wndstart>1 then | ||||
|         self.wndstart=self.wndstart-1 | ||||
|         self.show(self) | ||||
|       end | ||||
|     end | ||||
|   end, | ||||
|  | ||||
|   play = function(self) | ||||
|     mp.commandv("loadfile",self.pls[self.plsfiltered[self.wndstart+self.cursor]].filename) | ||||
|     if self.plspos then | ||||
|       self.pls[self.plspos].current=false | ||||
|     end | ||||
|     self.plspos=self.plsfiltered[self.wndstart+self.cursor] | ||||
|     self.pls[self.plspos].current=true | ||||
|   end | ||||
| } | ||||
|  | ||||
| function add_bindings() | ||||
|   keybinder.add("plsup", up, true) | ||||
|   keybinder.add("plsdown", down, true) | ||||
|   for i,v in ipairs(chars) do | ||||
|     c=string.char(v) | ||||
|     mp.add_forced_key_binding(c, 'search'..v, typing(c),"repeatable") | ||||
|   end | ||||
|   mp.add_forced_key_binding('SPACE', 'search32', typing(' '),"repeatable") | ||||
|      | ||||
| --[[    mp.add_key_binding('а', 'search1000', typing('а'),"repeatable") | ||||
|     mp.add_key_binding('с', 'search1001', typing('с'),"repeatable")]] | ||||
|  | ||||
|   mp.add_forced_key_binding('BS', 'searchbs', backspace,"repeatable") | ||||
|   keybinder.add("plsenter", play) | ||||
|   for i,v in ipairs(cyr_chars) do | ||||
|     mp.add_forced_key_binding(v, 'search'..i+1000, typing(v),"repeatable") | ||||
|   end | ||||
| end | ||||
|  | ||||
| function remove_bindings() | ||||
|   keybinder.remove('plsup') | ||||
|   keybinder.remove('plsdown') | ||||
|   keybinder.remove('plsenter') | ||||
|   for i,v in ipairs(chars) do | ||||
|     c=string.char(v) | ||||
|     mp.remove_key_binding('search'..v) | ||||
|   end | ||||
|   mp.remove_key_binding('search32') | ||||
|   mp.remove_key_binding('searchbs') | ||||
|   for i,v in ipairs(cyr_chars) do | ||||
|     mp.remove_key_binding('search'..i+1000) | ||||
|   end | ||||
| end | ||||
|  | ||||
| function activate() | ||||
|   if is_active then | ||||
|     shutdown() | ||||
|     return | ||||
|   else | ||||
|     is_active=true | ||||
|     fader:on() | ||||
|     playlister:show() | ||||
|     add_bindings() | ||||
|     if not timer then | ||||
|       timer=mp.add_periodic_timer(osd_time, shutdown) | ||||
|       timer.oneshot=true | ||||
|     else | ||||
|       resumetimer() | ||||
|     end | ||||
|   end | ||||
| end | ||||
|  | ||||
| function tablekeys(t) | ||||
|   local result={} | ||||
|   for i,v in ipairs(t) do | ||||
|     table.insert(result,i) | ||||
|   end | ||||
|   return result | ||||
| end | ||||
|  | ||||
| function in_array(array, value) | ||||
|   for _,v in ipairs(array) do | ||||
|     if v==value then | ||||
|       return true | ||||
|     end | ||||
|   end | ||||
|   return false | ||||
| end | ||||
|  | ||||
| function mylower(s) | ||||
|   local res,n =  string.gsub(s,utf8_char,function (c)  | ||||
|                                     return utf8_uc_lc[c] | ||||
|                                  end) | ||||
|   return res | ||||
| end | ||||
|  | ||||
| function myupper(s) | ||||
|   local res,n =  string.gsub(s,utf8_char,function (c)  | ||||
|                                     return utf8_lc_uc[c] | ||||
|                                  end) | ||||
|   return res | ||||
| end | ||||
|  | ||||
| function prepat(s) | ||||
| --prepare nocase and magic chars | ||||
|   s = string.gsub(s, "[%^%$%(%)%%%.%[%]%*%+%-%?]",function (c) | ||||
|         return '%'..c | ||||
|       end) | ||||
| --[[  s = string.gsub(s, utf8_char, function (c) | ||||
|         return string.format("[%s%s]", utf8_uc_lc[c] or c, utf8_lc_uc[c] or c) | ||||
|       end)]] | ||||
|   return s | ||||
| end | ||||
|  | ||||
| function resumetimer() | ||||
|   timer:kill() | ||||
|   timer:resume() | ||||
| end | ||||
|  | ||||
| function typing(char) | ||||
|   return function() | ||||
|            local c=string.lower(char) | ||||
|            pattern = pattern..c | ||||
|            playlister:filter() | ||||
|            playlister:show() | ||||
|            resumetimer() | ||||
|          end | ||||
| end | ||||
|  | ||||
| function backspace() | ||||
|   if string.len(pattern)>0 then | ||||
| --    pattern = string.sub(pattern,1,-2) | ||||
| -- for unicode | ||||
|     pattern = string.match(pattern,"(.*)"..utf8_char.."$") | ||||
|     playlister:filter() | ||||
|     playlister:show() | ||||
|     resumetimer() | ||||
|   end | ||||
| end | ||||
|  | ||||
| function play() | ||||
| --  mp.commandv("playlist-move", wndstart+cursor, 1) | ||||
| --  mp.commandv("playlist-clear") | ||||
| --  mp.commandv("playlist-next") | ||||
|   fader:off() | ||||
|   playlister:play() | ||||
|   playlister:show() | ||||
|   resumetimer() | ||||
| end | ||||
|  | ||||
| function shutdown() | ||||
|   fader:off() | ||||
|   remove_bindings() | ||||
|   is_active=false | ||||
|   mp.osd_message("", 1) | ||||
| end | ||||
|  | ||||
| function down() | ||||
|   fader:on() | ||||
|   playlister:down() | ||||
|   resumetimer() | ||||
| end | ||||
|  | ||||
| function up() | ||||
|   fader:on() | ||||
|   playlister:up() | ||||
|   resumetimer() | ||||
| end | ||||
|  | ||||
| function on_start_file() | ||||
|   if is_playlist_loaded then | ||||
|     playlister:init() | ||||
|     mp.unregister_event(on_start_file) | ||||
|     activate() | ||||
|   else | ||||
|     is_playlist_loaded = true | ||||
|   end | ||||
| end | ||||
|  | ||||
| if mp.get_opt("iptv") then | ||||
|   mp.set_property_bool("idle", true) | ||||
|   mp.set_property_bool("force-window", true) | ||||
|   mp.register_event("start-file", on_start_file) | ||||
|   keybinder.add("activate", activate) | ||||
| end | ||||
|  | ||||
		Reference in New Issue
	
	Block a user