diff --git a/dotfiles/hypr/.luarc.json b/dotfiles/hypr/.luarc.json index 16541f8..7a500f3 120000 --- a/dotfiles/hypr/.luarc.json +++ b/dotfiles/hypr/.luarc.json @@ -1 +1 @@ -/nix/store/yaksysd8kvxqwyv04sd4g97la1sh762c-home-manager-files/.config/hypr/.luarc.json \ No newline at end of file +/nix/store/yrapqnp1lddhxv9d4hc00b4gcnlxa7fk-home-manager-files/.config/hypr/.luarc.json \ No newline at end of file diff --git a/dotfiles/hypr/hyprland.lua b/dotfiles/hypr/hyprland.lua index afe63b4..8a3bdb5 120000 --- a/dotfiles/hypr/hyprland.lua +++ b/dotfiles/hypr/hyprland.lua @@ -1 +1 @@ -/nix/store/yaksysd8kvxqwyv04sd4g97la1sh762c-home-manager-files/.config/hypr/hyprland.lua \ No newline at end of file +/nix/store/yrapqnp1lddhxv9d4hc00b4gcnlxa7fk-home-manager-files/.config/hypr/hyprland.lua \ No newline at end of file diff --git a/dotfiles/inkscape/palettes b/dotfiles/inkscape/palettes index ce3edd8..ad21020 120000 --- a/dotfiles/inkscape/palettes +++ b/dotfiles/inkscape/palettes @@ -1 +1 @@ -/nix/store/yaksysd8kvxqwyv04sd4g97la1sh762c-home-manager-files/.config/inkscape/palettes \ No newline at end of file +/nix/store/yrapqnp1lddhxv9d4hc00b4gcnlxa7fk-home-manager-files/.config/inkscape/palettes \ No newline at end of file diff --git a/dotfiles/inkscape/templates b/dotfiles/inkscape/templates index 24055d5..e3b98c5 120000 --- a/dotfiles/inkscape/templates +++ b/dotfiles/inkscape/templates @@ -1 +1 @@ -/nix/store/yaksysd8kvxqwyv04sd4g97la1sh762c-home-manager-files/.config/inkscape/templates \ No newline at end of file +/nix/store/yrapqnp1lddhxv9d4hc00b4gcnlxa7fk-home-manager-files/.config/inkscape/templates \ No newline at end of file diff --git a/dotfiles/kitty/kitty.conf b/dotfiles/kitty/kitty.conf index 46dc004..0f6cc92 120000 --- a/dotfiles/kitty/kitty.conf +++ b/dotfiles/kitty/kitty.conf @@ -1 +1 @@ -/nix/store/yaksysd8kvxqwyv04sd4g97la1sh762c-home-manager-files/.config/kitty/kitty.conf \ No newline at end of file +/nix/store/yrapqnp1lddhxv9d4hc00b4gcnlxa7fk-home-manager-files/.config/kitty/kitty.conf \ No newline at end of file diff --git a/dotfiles/mpv/feeds.lua b/dotfiles/mpv/feeds.lua new file mode 100644 index 0000000..8d820b4 --- /dev/null +++ b/dotfiles/mpv/feeds.lua @@ -0,0 +1,487 @@ +--[[ +feeds.lua — menu "Abonnements YouTube / Twitch" pour mpv, rendu via uosc. + +Lit deux CSV : + - le subscriptions.csv de Google Takeout + (col. 1 = ID de chaîne, col. 3 = nom de la chaîne) + - un twitch.csv maison (col. 1 = login Twitch, col. 2 = libellé, optionnelle) + +Trois sources : + - Abonnements YouTube : dernières vidéos, via les flux RSS publics (curl) + - Parcourir une chaîne : catalogue d'une chaîne, via yt-dlp + - Twitch : chaînes suivies, lecture via streamlink + +Aucune clé API n'est nécessaire. +Dépendances : uosc, curl, yt-dlp, streamlink. +Raccourci par défaut : alt+h +--]] + +local utils = require("mp.utils") +local options = require("mp.options") +local msg = require("mp.msg") + +local o = { + youtube_csv = "~/nixos-config/dotfiles/mpv/youtube.csv", + twitch_csv = "~/nixos-config/dotfiles/mpv/twitch.csv", + key = "alt+h", + per_channel = 3, -- nb max de vidéos gardées par chaîne (flux RSS) + max_videos = 150, -- taille max de la liste des abonnements + channel_videos = 1000, -- nb de vidéos chargées en parcourant une chaîne + twitch_live_check = true, -- détection "en direct" (best-effort, sans clé API) +} +options.read_options(o, "feeds") + +local cache = { youtube = nil, twitch = nil, channels = {} } + +local function expand(path) + return mp.command_native({ "expand-path", path }) +end + +local function unescape(s) + if not s then + return "" + end + s = s:gsub("<", "<"):gsub(">", ">"):gsub(""", '"') + s = s:gsub("'", "'"):gsub("'", "'"):gsub("&", "&") + return s +end + +local function trim(s) + return (s or ""):gsub("^%s+", ""):gsub("%s+$", "") +end + +local function format_duration(sec) + if type(sec) ~= "number" or sec <= 0 then + return "" + end + sec = math.floor(sec) + local h = math.floor(sec / 3600) + local m = math.floor((sec % 3600) / 60) + local s = sec % 60 + if h > 0 then + return string.format("%d:%02d:%02d", h, m, s) + end + return string.format("%d:%02d", m, s) +end + +local function open_menu(m) + mp.commandv("script-message-to", "uosc", "open-menu", utils.format_json(m)) +end + +local function update_menu(m) + mp.commandv("script-message-to", "uosc", "update-menu", utils.format_json(m)) +end + +local function loading_menu(type_, title) + open_menu({ + type = type_, + title = title, + items = { { title = "Chargement…", icon = "spinner", selectable = false, keep_open = true } }, + }) +end + +-- Renvoie les lignes du fichier, débarrassées d'un éventuel \r final (les +-- exports Takeout peuvent être en CRLF). +local function read_lines(path) + local lines = {} + local full = expand(path) + local f = io.open(full, "r") + if not f then + msg.warn("CSV illisible : " .. tostring(full)) + return lines + end + for line in f:lines() do + lines[#lines + 1] = (line:gsub("\r$", "")) + end + f:close() + return lines +end + +--------------------------------------------------- Lecture + +mp.register_script_message("feeds-play", function(url) + mp.commandv("loadfile", url, "replace") +end) + +mp.register_script_message("feeds-twitch", function(login) + mp.osd_message("Ouverture de " .. login .. " via streamlink…", 3) + mp.command_native_async({ + name = "subprocess", + args = { "streamlink", "--player=mpv", "--twitch-low-latency", "twitch.tv/" .. login, "best" }, + detach = true, + -- sans ceci, mpv tue le processus dès qu'aucune vidéo n'est en lecture + playback_only = false, + }, function() end) +end) + +--------------------------------------------------- CSV YouTube + +-- Format Takeout : ID,URL,Titre — l'URL ne contient jamais de virgule, donc +-- tout ce qui suit la 2e virgule est le titre (éventuellement entre +-- guillemets s'il contient lui-même une virgule). +local function read_youtube_channels() + local channels = {} + for _, line in ipairs(read_lines(o.youtube_csv)) do + local id = line:match("^([%w_-]+)") + if id and id:match("^UC") then -- écarte l'en-tête du CSV + local title = line:match("^[^,]*,[^,]*,(.*)$") or "" + title = trim(title) + local inner = title:match('^"(.*)"$') + if inner then + title = inner:gsub('""', '"') + end + if title == "" then + title = id + end + channels[#channels + 1] = { id = id, title = title } + end + end + table.sort(channels, function(a, b) + return a.title:lower() < b.title:lower() + end) + return channels +end + +--------------------------------------------------- Abonnements (RSS) + +local function youtube_menu_data(videos) + local items = {} + for _, v in ipairs(videos) do + items[#items + 1] = { + title = v.author .. " — " .. v.title, + hint = v.published:sub(1, 10), + value = { "script-message", "feeds-play", v.url }, + } + end + if #items == 0 then + items = { + { + title = "Aucune vidéo récupérée — voir les logs (--msg-level=feeds=info)", + selectable = false, + }, + } + end + return { type = "yt_feed", title = "Abonnements YouTube", items = items } +end + +local function parse_feeds(blob) + local videos, seen_count = {}, {} + for entry in blob:gmatch("(.-)") do + local id = entry:match("(.-)") + local title = entry:match("(.-)") + local author = entry:match(".-(.-)") + local published = entry:match("(.-)") + if id and title and published then + videos[#videos + 1] = { + url = "https://www.youtube.com/watch?v=" .. id, + title = unescape(title), + author = unescape(author or "?"), + published = published, + } + end + end + + -- les dates ISO 8601 se trient correctement comme de simples chaînes + table.sort(videos, function(a, b) + return a.published > b.published + end) + + local kept = {} + for _, v in ipairs(videos) do + local n = (seen_count[v.author] or 0) + if n < o.per_channel then + seen_count[v.author] = n + 1 + kept[#kept + 1] = v + if #kept >= o.max_videos then + break + end + end + end + return kept +end + +local function youtube_menu(force) + if cache.youtube and not force then + open_menu(youtube_menu_data(cache.youtube)) + return + end + + local channels = read_youtube_channels() + local args = { "curl", "-s", "--parallel", "--parallel-max", "16", "-m", "25" } + for _, c in ipairs(channels) do + args[#args + 1] = "https://www.youtube.com/feeds/videos.xml?channel_id=" .. c.id + end + + if #channels == 0 then + open_menu({ + type = "yt_feed", + title = "Abonnements YouTube", + items = { { title = "Aucune chaîne lue dans " .. o.youtube_csv, selectable = false } }, + }) + return + end + + msg.info(#channels .. " chaînes à interroger") + loading_menu("yt_feed", "Abonnements YouTube") + + mp.command_native_async({ + name = "subprocess", + args = args, + capture_stdout = true, + playback_only = false, + }, function(_, res) + local videos = {} + if res and res.stdout and #res.stdout > 0 then + videos = parse_feeds(res.stdout) + end + msg.info( + string.format( + "curl status=%s, %d octets, %d vidéos", + tostring(res and res.status), + res and res.stdout and #res.stdout or 0, + #videos + ) + ) + cache.youtube = videos + update_menu(youtube_menu_data(videos)) + end) +end + +--------------------------------------------------- Parcourir une chaîne + +local function channel_videos_menu_data(name, videos) + local items = {} + for _, v in ipairs(videos) do + items[#items + 1] = { + title = v.title, + hint = v.duration, + value = { "script-message", "feeds-play", v.url }, + } + end + if #items == 0 then + items = { { title = "Rien récupéré — voir les logs (--msg-level=feeds=info)", selectable = false } } + end + return { type = "yt_channel", title = name, items = items } +end + +local function channel_videos_menu(id, name) + if cache.channels[id] then + open_menu(channel_videos_menu_data(name, cache.channels[id])) + return + end + + loading_menu("yt_channel", name) + + mp.command_native_async({ + name = "subprocess", + args = { + "yt-dlp", + "--flat-playlist", + "--dump-single-json", + "--no-warnings", + "--playlist-items", + "1:" .. tostring(o.channel_videos), + "https://www.youtube.com/channel/" .. id .. "/videos", + }, + capture_stdout = true, + playback_only = false, + }, function(_, res) + local videos = {} + if res and res.stdout and #res.stdout > 0 then + local ok, data = pcall(utils.parse_json, res.stdout) + if ok and data and data.entries then + for _, e in ipairs(data.entries) do + if e.id then + videos[#videos + 1] = { + title = e.title or e.id, + duration = format_duration(e.duration), + url = "https://www.youtube.com/watch?v=" .. e.id, + } + end + end + end + end + msg.info( + string.format( + "yt-dlp status=%s, %d octets, %d vidéos (%s)", + tostring(res and res.status), + res and res.stdout and #res.stdout or 0, + #videos, + name + ) + ) + cache.channels[id] = videos + update_menu(channel_videos_menu_data(name, videos)) + end) +end + +mp.register_script_message("feeds-channel", function(id, name) + channel_videos_menu(id, name) +end) + +local function channels_menu() + local channels = read_youtube_channels() + local items = {} + for _, c in ipairs(channels) do + items[#items + 1] = { + title = c.title, + value = { "script-message", "feeds-channel", c.id, c.title }, + } + end + if #items == 0 then + items = { { title = "Aucune chaîne lue dans " .. o.youtube_csv, selectable = false } } + end + -- tape simplement quelques lettres pour filtrer la liste + open_menu({ type = "yt_channels", title = "Parcourir une chaîne", items = items }) +end + +--------------------------------------------------- Twitch + +local function twitch_menu_data(channels) + local items = {} + for _, c in ipairs(channels) do + local mark = "" + if c.live == true then + mark = "🔴 " + elseif c.live == false then + mark = "· " + end + items[#items + 1] = { + title = mark .. (c.label ~= "" and c.label or c.login), + hint = c.live == true and "en direct" or nil, + value = { "script-message", "feeds-twitch", c.login }, + } + end + if #items == 0 then + items = { { title = "Aucune chaîne lue dans " .. o.twitch_csv, selectable = false } } + end + return { type = "twitch_feed", title = "Twitch", items = items } +end + +local function twitch_menu(force) + if cache.twitch and not force then + open_menu(twitch_menu_data(cache.twitch)) + return + end + + local channels = {} + for _, line in ipairs(read_lines(o.twitch_csv)) do + local login = line:match("^([%w_][%w_]*)") + if login and login:lower() ~= "login" then -- ignore l'en-tête éventuel + local label = trim(line:match("^[^,]*,(.*)$") or "") + channels[#channels + 1] = { login = login, label = label, live = nil } + end + end + + if #channels == 0 or not o.twitch_live_check then + cache.twitch = channels + open_menu(twitch_menu_data(channels)) + return + end + + loading_menu("twitch_feed", "Twitch") + + local logins = {} + for _, c in ipairs(channels) do + logins[#logins + 1] = c.login + end + + local script = [[ +for c in ]] .. table.concat(logins, " ") .. [[; do + ( if curl -sL -m 8 "https://www.twitch.tv/$c" | grep -q '"isLiveBroadcast":true'; then + echo "$c live" + else + echo "$c off" + fi ) & +done +wait +]] + + mp.command_native_async({ + name = "subprocess", + args = { "sh", "-c", script }, + capture_stdout = true, + playback_only = false, + }, function(_, res) + local nb_live = 0 + if res and res.stdout and #res.stdout > 0 then + local status = {} + for login, state in res.stdout:gmatch("(%S+)%s+(%S+)") do + status[login] = (state == "live") + end + for _, c in ipairs(channels) do + if status[c.login] ~= nil then + c.live = status[c.login] + if c.live then + nb_live = nb_live + 1 + end + end + end + table.sort(channels, function(a, b) + if a.live ~= b.live then + return a.live == true + end + return a.login < b.login + end) + end + msg.info( + string.format( + "twitch status=%s, %d chaînes, %d en direct", + tostring(res and res.status), + #channels, + nb_live + ) + ) + cache.twitch = channels + update_menu(twitch_menu_data(channels)) + end) +end + +--------------------------------------------------- Menu racine + +mp.register_script_message("feeds-open", function(which, force) + local refresh = (force == "refresh") + if which == "youtube" then + youtube_menu(refresh) + elseif which == "channels" then + channels_menu() + elseif which == "twitch" then + twitch_menu(refresh) + end +end) + +mp.add_key_binding(o.key, "feeds-menu", function() + open_menu({ + type = "feeds", + title = "Chaînes", + items = { + { + title = "Abonnements YouTube", + icon = "subscriptions", + value = { "script-message", "feeds-open", "youtube" }, + }, + { + title = "Parcourir une chaîne", + icon = "video_library", + value = { "script-message", "feeds-open", "channels" }, + }, + { + title = "Twitch", + icon = "live_tv", + value = { "script-message", "feeds-open", "twitch" }, + }, + { + title = "Rafraîchir YouTube", + icon = "refresh", + muted = true, + value = { "script-message", "feeds-open", "youtube", "refresh" }, + }, + { + title = "Rafraîchir Twitch", + icon = "refresh", + muted = true, + value = { "script-message", "feeds-open", "twitch", "refresh" }, + }, + }, + }) +end) diff --git a/dotfiles/mpv/twitch.csv b/dotfiles/mpv/twitch.csv new file mode 100644 index 0000000..17bd2c0 --- /dev/null +++ b/dotfiles/mpv/twitch.csv @@ -0,0 +1,13 @@ +Wissam_Xelka +HasanAbi +Zawa_Prod +Cass_Andre +Ostpolitik +dofla +LeMawakast +ParolesDHonneur_ +lives2leo +MOuffette_ +KaLeeVision +Bamwempan +RiboDansLaSauce diff --git a/dotfiles/mpv/youtube.csv b/dotfiles/mpv/youtube.csv new file mode 100644 index 0000000..5836bdd --- /dev/null +++ b/dotfiles/mpv/youtube.csv @@ -0,0 +1,101 @@ +ID des chaînes,URL des chaînes,Titres des chaînes +UC0HxyEc_ojRJ1oJXS5K6oaA,http://www.youtube.com/channel/UC0HxyEc_ojRJ1oJXS5K6oaA,Politikon +UC0Miwa4YsGduqJFYmpCSXeg,http://www.youtube.com/channel/UC0Miwa4YsGduqJFYmpCSXeg,taoqan +UC0fDG3byEcMtbOqPMymDNbw,http://www.youtube.com/channel/UC0fDG3byEcMtbOqPMymDNbw,/noclip +UC0yPCUmdMZIGtnxSnx5_ifA,http://www.youtube.com/channel/UC0yPCUmdMZIGtnxSnx5_ifA,Tzitzimitl - Esprit Critique +UC1ObD9AuLfxiqRkrY7A_kgA,http://www.youtube.com/channel/UC1ObD9AuLfxiqRkrY7A_kgA,Les vidéos de Léo +UC1eBAh5DIkn9N_5XzMS0wFg,http://www.youtube.com/channel/UC1eBAh5DIkn9N_5XzMS0wFg,Les Amoureuses +UC1zVvHsRsvxInUMX4dfIyAQ,http://www.youtube.com/channel/UC1zVvHsRsvxInUMX4dfIyAQ,The Sciencoder +UC2qlgiYCCtaYpn2_blX01xg,http://www.youtube.com/channel/UC2qlgiYCCtaYpn2_blX01xg,Antoine Goya +UC2rpRj3VqEMaT7vgtiBnQoQ,http://www.youtube.com/channel/UC2rpRj3VqEMaT7vgtiBnQoQ,Veridis Project +UC3A_TG1leX0eQEJD1Ew6Ftw,http://www.youtube.com/channel/UC3A_TG1leX0eQEJD1Ew6Ftw,Game Of Hearth +UC476clcLNhTKwjdulsfvHLw,http://www.youtube.com/channel/UC476clcLNhTKwjdulsfvHLw,imranepresents +UC4vfXTvb9fysmiGab_cdJXg,http://www.youtube.com/channel/UC4vfXTvb9fysmiGab_cdJXg,Legendes Musique +UC5AA57FT52rBCyGc9UT1DDg,http://www.youtube.com/channel/UC5AA57FT52rBCyGc9UT1DDg,Emmodem VOD +UC5eOLQO5VUEFJukNg9cl5jg,http://www.youtube.com/channel/UC5eOLQO5VUEFJukNg9cl5jg,Dave Sheik +UC6zC37ITu2dNx3GimE8UV2A,http://www.youtube.com/channel/UC6zC37ITu2dNx3GimE8UV2A,Mathys Aurand +UC7sXGI8p8PvKosLWagkK9wQ,http://www.youtube.com/channel/UC7sXGI8p8PvKosLWagkK9wQ,Heu?reka +UC85YiwWx6BC6SYR7wuMyG8A,http://www.youtube.com/channel/UC85YiwWx6BC6SYR7wuMyG8A,SLICE Histoire +UC8cQpBzgnpkHPMkEpnoWWcQ,http://www.youtube.com/channel/UC8cQpBzgnpkHPMkEpnoWWcQ,Three Hours Later +UC9_qAALb4xSC4cWyuzECs5g,http://www.youtube.com/channel/UC9_qAALb4xSC4cWyuzECs5g,Saturne +UC9lWSxp7TdohmRwnvSR2Gvw,http://www.youtube.com/channel/UC9lWSxp7TdohmRwnvSR2Gvw,RiboDansLaSauce +UC9mes7ZXbrZ_UXn0jzBt21A,http://www.youtube.com/channel/UC9mes7ZXbrZ_UXn0jzBt21A,Bon Pote +UC9r6ydGn4TA8PexLQlgWSmQ,http://www.youtube.com/channel/UC9r6ydGn4TA8PexLQlgWSmQ,Réflexions Basses +UC9w4KQLmoOOBhhFwcKnK7UA,http://www.youtube.com/channel/UC9w4KQLmoOOBhhFwcKnK7UA,Max Atger +UCAJta1-T5V_RB7YDfp7GQag,http://www.youtube.com/channel/UCAJta1-T5V_RB7YDfp7GQag,Headlundas +UCAbFIrKZCYdKucQYnhxWnrA,http://www.youtube.com/channel/UCAbFIrKZCYdKucQYnhxWnrA,LIMIT +UCBm4zCKYn0Iirik1j5yRTfg,http://www.youtube.com/channel/UCBm4zCKYn0Iirik1j5yRTfg,Satellisés +UCCTbruTofQHTMkmG8cEJ4fQ,http://www.youtube.com/channel/UCCTbruTofQHTMkmG8cEJ4fQ,Jack Couscous +UCCTuFofVWD9uORhQqgn-d7Q,http://www.youtube.com/channel/UCCTuFofVWD9uORhQqgn-d7Q,INA Société +UCCauEjHzPXxGer8af3u4x5g,http://www.youtube.com/channel/UCCauEjHzPXxGer8af3u4x5g,Envoyé Spécial +UCDanmCiN4kaOO_tOOv81s6g,http://www.youtube.com/channel/UCDanmCiN4kaOO_tOOv81s6g,Emmodem Vod +UCEFGCs68E9Vr5te5qZuJsbg,http://www.youtube.com/channel/UCEFGCs68E9Vr5te5qZuJsbg,Off Investigation +UCEfpbmshpf-G90fGLla73kA,http://www.youtube.com/channel/UCEfpbmshpf-G90fGLla73kA,Bolchegeek +UCEsShazY9frY_x51rknY2dw,http://www.youtube.com/channel/UCEsShazY9frY_x51rknY2dw,Dandee +UCF8wHRQmuBpOuvQvsfSFMnQ,http://www.youtube.com/channel/UCF8wHRQmuBpOuvQvsfSFMnQ,Faustin Sullivan +UCGjKwjEvPA0ms2wOyBwdMPQ,http://www.youtube.com/channel/UCGjKwjEvPA0ms2wOyBwdMPQ,Parlons Cyber +UCHOtlkL8XEHbL6KHIHYRGSw,http://www.youtube.com/channel/UCHOtlkL8XEHbL6KHIHYRGSw,Franck Lepage +UCHiwtz2tCEfS17N9A-WoSSw,http://www.youtube.com/channel/UCHiwtz2tCEfS17N9A-WoSSw,Pop Culture Detective +UCI_FnSJPNGd3Y3IL0PwD-NQ,http://www.youtube.com/channel/UCI_FnSJPNGd3Y3IL0PwD-NQ,Diable Positif +UCIlNSCHPwun7060OYU5thrw,http://www.youtube.com/channel/UCIlNSCHPwun7060OYU5thrw,Barap +UCJ9kIKgFuAB23GkEko1hHDg,http://www.youtube.com/channel/UCJ9kIKgFuAB23GkEko1hHDg,Mycéliums +UCJT6bmaCnlJDq5Yh1EfoSQw,http://www.youtube.com/channel/UCJT6bmaCnlJDq5Yh1EfoSQw,Grünt +UCJd1AFjN9vIgVDDB6UE2UQg,http://www.youtube.com/channel/UCJd1AFjN9vIgVDDB6UE2UQg,Marouchka de Qu'est-ce qu'on lit ? +UCJpIF-QIOk1YOjSqD5eqyqQ,http://www.youtube.com/channel/UCJpIF-QIOk1YOjSqD5eqyqQ,Elyne Simon +UCLXDNUOO3EQ80VmD9nQBHPg,http://www.youtube.com/channel/UCLXDNUOO3EQ80VmD9nQBHPg,Fouloscopie +UCLdmnkqdcTPHvVZ8aNdbf5A,http://www.youtube.com/channel/UCLdmnkqdcTPHvVZ8aNdbf5A,Spline LND +UCNxe55xhsqp_w6k6GEor8Uw,http://www.youtube.com/channel/UCNxe55xhsqp_w6k6GEor8Uw,Papy fait de la Resistance +UCP46_MXP_WG_auH88FnfS1A,http://www.youtube.com/channel/UCP46_MXP_WG_auH88FnfS1A,Nota Bene +UCPTlw9-dflN3_Sw9AfQs3vw,http://www.youtube.com/channel/UCPTlw9-dflN3_Sw9AfQs3vw,Faune Cool +UCPVS8efBdhXGGYs4JW2IJcQ,http://www.youtube.com/channel/UCPVS8efBdhXGGYs4JW2IJcQ,Kiffe ta race +UCPZIJMFJBoyG7t7nsUQ3UcA,http://www.youtube.com/channel/UCPZIJMFJBoyG7t7nsUQ3UcA,Nedrac +UCPo1nFSGNkyzrA9yvtkEvIw,http://www.youtube.com/channel/UCPo1nFSGNkyzrA9yvtkEvIw,Eliott Meunier +UCQHX6ViZmPsWiYSFAyS0a3Q,http://www.youtube.com/channel/UCQHX6ViZmPsWiYSFAyS0a3Q,GothamChess +UCQcas4dulTzVUrAo0fMfWWg,http://www.youtube.com/channel/UCQcas4dulTzVUrAo0fMfWWg,Clément Viktorovitch +UCRoQyGLLPd9lwPUJtUwD2yw,http://www.youtube.com/channel/UCRoQyGLLPd9lwPUJtUwD2yw,Samora | Le Mwakast +UCT67YOMntJxfRnO_9bXDpvw,http://www.youtube.com/channel/UCT67YOMntJxfRnO_9bXDpvw,Le Média +UCTth6-5ZiCD_CUJ6xOMug_w,http://www.youtube.com/channel/UCTth6-5ZiCD_CUJ6xOMug_w,Paroles D'Honneur +UCUc-m8A95mE9zLlNvVtLfFQ,http://www.youtube.com/channel/UCUc-m8A95mE9zLlNvVtLfFQ,Orange Trio Music +UCVeMw72tepFl1Zt5fvf9QKQ,http://www.youtube.com/channel/UCVeMw72tepFl1Zt5fvf9QKQ,Osons Causer +UCVuMMUfqEI448VKbkpuNPHQ,http://www.youtube.com/channel/UCVuMMUfqEI448VKbkpuNPHQ,Histoires Crépues +UCWGsN59FON3vOtXCozQPsZQ,http://www.youtube.com/channel/UCWGsN59FON3vOtXCozQPsZQ,Canard Réfractaire +UCXHWT_QoQSsdGXbqF0hAMtg,http://www.youtube.com/channel/UCXHWT_QoQSsdGXbqF0hAMtg,Arrêt sur images +UCYpRDnhk5H8h16jpS84uqsA,http://www.youtube.com/channel/UCYpRDnhk5H8h16jpS84uqsA,Le Monde +UC_-hYjoNe4PJNFa9iZ4lraA,http://www.youtube.com/channel/UC_-hYjoNe4PJNFa9iZ4lraA,Good Work +UC_2-ii_May8L-lx25YJhSew,http://www.youtube.com/channel/UC_2-ii_May8L-lx25YJhSew,Fracas +UC_NukSq2ve_AHVAz_9ikTDg,http://www.youtube.com/channel/UC_NukSq2ve_AHVAz_9ikTDg,Usul +UC__xRB5L4toU9yYawt_lIKg,http://www.youtube.com/channel/UC__xRB5L4toU9yYawt_lIKg,"BLAST, Le souffle de l'info" +UCaU9xFZi08_meRCb9Uzr_Ew,http://www.youtube.com/channel/UCaU9xFZi08_meRCb9Uzr_Ew,L'Argumentarium +UCafxR2HWJRmMfSdyZXvZMTw,http://www.youtube.com/channel/UCafxR2HWJRmMfSdyZXvZMTw,LOOK MUM NO COMPUTER +UCar0yo-PpeMk51m116826pQ,http://www.youtube.com/channel/UCar0yo-PpeMk51m116826pQ,Journal l'Humanité +UCd5DKToXYTKAQ6khzewww2g,http://www.youtube.com/channel/UCd5DKToXYTKAQ6khzewww2g,France Culture +UCdKTlsmvczkdvGjiLinQwmw,http://www.youtube.com/channel/UCdKTlsmvczkdvGjiLinQwmw,Philoxime +UCdnaDhU-LDQrIEEmSIfq0-Q,http://www.youtube.com/channel/UCdnaDhU-LDQrIEEmSIfq0-Q,Mediapart +UCe6iUNw4s5VxGnWi63JRU3g,http://www.youtube.com/channel/UCe6iUNw4s5VxGnWi63JRU3g,Bamwempan +UCeQRERCvEY3-ZeQONwnx0zw,http://www.youtube.com/channel/UCeQRERCvEY3-ZeQONwnx0zw,Zawa Prod +UCebfFtcRXJWGgAHi0h8n2JA,http://www.youtube.com/channel/UCebfFtcRXJWGgAHi0h8n2JA,Sismique +UCeovElJP0n0i8ADaPsRSd8g,http://www.youtube.com/channel/UCeovElJP0n0i8ADaPsRSd8g,HAINBACH +UCg5OUM5Y5UWJHJgFCjXcfkA,http://www.youtube.com/channel/UCg5OUM5Y5UWJHJgFCjXcfkA,Way Back 2 Afrika +UChG8nxeVTk6jQJyH-_TG7xw,http://www.youtube.com/channel/UChG8nxeVTk6jQJyH-_TG7xw,InPower Podcast +UChYdEwKt1QyP27OwzmVObnA,http://www.youtube.com/channel/UChYdEwKt1QyP27OwzmVObnA,Blast2 +UChaI6XKLJJHZu70_QJFQjKA,http://www.youtube.com/channel/UChaI6XKLJJHZu70_QJFQjKA,Gael Berlinger +UCi1h68Fys0apnhLaJ-ijQOw,http://www.youtube.com/channel/UCi1h68Fys0apnhLaJ-ijQOw,INA Politique +UCkgO4A3Fzm5D9Xu1Y_4vCKQ,http://www.youtube.com/channel/UCkgO4A3Fzm5D9Xu1Y_4vCKQ,ÉLUCID +UCn1eIYIqfPOhj-KhDmbG8KA,http://www.youtube.com/channel/UCn1eIYIqfPOhj-KhDmbG8KA,AMI | INSA Lyon +UCnP7HeJGVy8EL1L-1gTDm8w,http://www.youtube.com/channel/UCnP7HeJGVy8EL1L-1gTDm8w,STUPMEDIA +UCoobqoKhnrJhgP8v2bx3ZnA,http://www.youtube.com/channel/UCoobqoKhnrJhgP8v2bx3ZnA,SOCIOLOGIK +UCp9cUr3zrGguWsm5oIa2VAQ,http://www.youtube.com/channel/UCp9cUr3zrGguWsm5oIa2VAQ,Bignou Collectif +UCqt99sKYNTxqlHtzV9weUYA,http://www.youtube.com/channel/UCqt99sKYNTxqlHtzV9weUYA,VU FranceTV +UCrzwP_TnWL_FA-PjIZ9qaZg,http://www.youtube.com/channel/UCrzwP_TnWL_FA-PjIZ9qaZg,Cass Andre +UCt3XYjlua5RtcHyEKUkUKOQ,http://www.youtube.com/channel/UCt3XYjlua5RtcHyEKUkUKOQ,Kong DIRTY BOXING +UCvW-hY30MCw1qrxAN2HeeZg,http://www.youtube.com/channel/UCvW-hY30MCw1qrxAN2HeeZg,À L'Assaut du Ciel +UCwI-JbGNsojunnHbFAc0M4Q,http://www.youtube.com/channel/UCwI-JbGNsojunnHbFAc0M4Q,ARTE +UCwU7Gq3vG5kL1eknXIZvMag,http://www.youtube.com/channel/UCwU7Gq3vG5kL1eknXIZvMag,Wissam Xelka +UCwaliuWsJWhdhk-KUfQHlYA,http://www.youtube.com/channel/UCwaliuWsJWhdhk-KUfQHlYA,Metabolism of Cities +UCweCc7bSMX5J4jEH7HFImng,http://www.youtube.com/channel/UCweCc7bSMX5J4jEH7HFImng,GMHikaru +UCxJka_qnTVquoIL-PQV5POg,http://www.youtube.com/channel/UCxJka_qnTVquoIL-PQV5POg,DanyCaligula +UCy4CtZFhDCSkNnr6GUypacw,http://www.youtube.com/channel/UCy4CtZFhDCSkNnr6GUypacw,Síomha +UCyJDHgrsUKuWLe05GvC2lng,http://www.youtube.com/channel/UCyJDHgrsUKuWLe05GvC2lng,Stupid Economics +UCyjXo7RjhDQ1oX7Q7CPUUIQ,http://www.youtube.com/channel/UCyjXo7RjhDQ1oX7Q7CPUUIQ,Avant l'orage +UCzB5vMdtF0qAf84nV3HrD2A,http://www.youtube.com/channel/UCzB5vMdtF0qAf84nV3HrD2A,Thomas Babord + diff --git a/flake.lock b/flake.lock index 3c6c14b..ec4d38e 100644 --- a/flake.lock +++ b/flake.lock @@ -147,11 +147,11 @@ ] }, "locked": { - "lastModified": 1786031233, - "narHash": "sha256-TIDlLTLI1/pB7IqgjzcKQjpODQsZE2oII4XGG9B6KjI=", + "lastModified": 1786286733, + "narHash": "sha256-7dN93WKkEERgutPtTjK7SY3ZarO2LAU33A1+vKu+7cc=", "owner": "nix-community", "repo": "home-manager", - "rev": "7834e82588860aaf780cec1366524456a70898d7", + "rev": "367f7ef80856d18438953d54dda235d42a46ba31", "type": "github" }, "original": { @@ -267,11 +267,11 @@ }, "nixpkgs_2": { "locked": { - "lastModified": 1785967620, - "narHash": "sha256-IItrdb7Puk05RqOBWZYFC5X6Wl1sJmCfh5MWVHw5iMM=", + "lastModified": 1786106723, + "narHash": "sha256-zDSUbpoeo/9ZmD2+wXnzxoo1+uhL8vxc0b8yuYMKYq0=", "owner": "nixos", "repo": "nixpkgs", - "rev": "b7c2ada94fe99c15b0dbcf4d11fd7850b957a436", + "rev": "f13ff45afd1bb73e640eaa08a7066dbed07e3238", "type": "github" }, "original": { @@ -336,11 +336,11 @@ "tinted-zed": "tinted-zed" }, "locked": { - "lastModified": 1786144742, - "narHash": "sha256-ROqWcNC1qYU2p0EY1d9BHnZbcl0ZDaCmXtojENSqL18=", + "lastModified": 1786216702, + "narHash": "sha256-fOOmw9tUYeqWVnK2w2NiuMTmGIbluj8xiBFTTFDCcEE=", "owner": "danth", "repo": "stylix", - "rev": "d18ba6834c7f1141429b6d4cf148fff6c8c41139", + "rev": "b67debfd2db1eb1f0fd8740b950f598bbaf74b8f", "type": "github" }, "original": { @@ -472,11 +472,11 @@ ] }, "locked": { - "lastModified": 1786171986, - "narHash": "sha256-kvmCZLYbByuE+zskqtf5+UPGrFI8e8KspB8jVey0nj0=", + "lastModified": 1786290296, + "narHash": "sha256-V5WOJhCGsuSRkz60K8TcALKMiMVCNubfJquMJqoCow0=", "owner": "0xc000022070", "repo": "zen-browser-flake", - "rev": "f3a721857afb4c34f687390213e0bc034d8e4999", + "rev": "a1f244256e643fe7bd3f811e75b4267fd180cd7c", "type": "github" }, "original": { diff --git a/home/afoucaultc/packages/mpv.nix b/home/afoucaultc/packages/mpv.nix index 372d23a..976aeda 100644 --- a/home/afoucaultc/packages/mpv.nix +++ b/home/afoucaultc/packages/mpv.nix @@ -1,6 +1,32 @@ -{ ... }: +{ pkgs, ... }: { + home.packages = with pkgs; [ + yt-dlp + streamlink + curl + ]; + programs.mpv = { enable = true; + scripts = with pkgs.mpvScripts; [ + uosc + thumbfast + sponsorblock + ]; + config = { + osc = false; + border = false; + ytdl-format = "bestvideo[height<=?1080]+bestaudio/best"; + save-position-on-quit = true; + }; + scriptOpts.feeds = { + youtube_csv = "~/nixos-config/dotfiles/mpv/youtube.csv"; + twitch_csv = "~/nixos-config/dotfiles/mpv/twitch.csv"; + key = "ctrl+h"; + # twitch_live_check = "no"; + }; }; + + # destination = relative à ~/.config ; source = ./feeds.lua dans ton dépôt + xdg.configFile."mpv/scripts/feeds.lua".source = ../../../dotfiles/mpv/feeds.lua; } diff --git a/home/afoucaultc/packages/niri/conf/misc.nix b/home/afoucaultc/packages/niri/conf/misc.nix index 5db8427..792eb20 100644 --- a/home/afoucaultc/packages/niri/conf/misc.nix +++ b/home/afoucaultc/packages/niri/conf/misc.nix @@ -31,7 +31,7 @@ }; clipboard.disable-primary = false; - hotkey-overlay.skip-at-startup = false; + hotkey-overlay.skip-at-startup = true; overview.zoom = 0.5; }; } diff --git a/home/afoucaultc/packages/niri/conf/window-rules.nix b/home/afoucaultc/packages/niri/conf/window-rules.nix index 4716895..eae72e2 100644 --- a/home/afoucaultc/packages/niri/conf/window-rules.nix +++ b/home/afoucaultc/packages/niri/conf/window-rules.nix @@ -25,5 +25,9 @@ opacity = 0.95; clip-to-geometry = true; } + { + matches = [ { app-id = "^mpv$"; } ]; + open-fullscreen = true; + } ]; }