Compare commits

..

10 Commits

11 changed files with 269 additions and 37 deletions

View File

@ -70,7 +70,7 @@
};
users.users.${user} = {
isNormalUser = true;
extraGroups = ["wheel"]; # Enable sudo for the user.
extraGroups = ["wheel" "video"]; # Enable sudo for the user.
openssh.authorizedKeys.keys = [
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIKAa3tMzSCRuprEACrBsKI0F/o73o6J9L1qR3TaZn/N8 user@Kell"
"ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIByLwLAdJbmoDV5sx4hg5NbzKbOh1GmWEhDOUJ1GQBhK user@Riva"

View File

@ -26,7 +26,9 @@ in {
rclone
opencode
# zed-editor
uv
google-cloud-sdk
awscli2
distrobox
gnome-disk-utility
moonlight-qt

View File

@ -47,6 +47,7 @@ in {
Status = "locked";
};
"privacy.trackingprotection.enabled" = true;
"media.webrtc.camera.allow-pipewire" = true;
};
};
};

View File

@ -4,8 +4,8 @@
pname = "Helium";
version = "0.4.7.1";
src = pkgs.fetchurl {
url = "https://github.com/imputnet/helium-linux/releases/download/0.8.5.1/helium-0.8.5.1-x86_64.AppImage";
sha256 = "sha256-jFSLLDsHB/NiJqFmn8S+JpdM8iCy3Zgyq+8l4RkBecM=";
url = "https://github.com/imputnet/helium-linux/releases/download/0.9.4.1/helium-0.9.4.1-x86_64.AppImage";
sha256 = "sha256-N5gdWuxOrIudJx/4nYo4/SKSxakpTFvL4zzByv6Cnug=";
};
})
];

View File

@ -116,7 +116,7 @@ in {
"uwsm app -- hyprpaper"
"uwsm app -- foot --server"
"uwsm app -- hyprctl dispatch exec ags run"
"uwsm app -- ${pkgs.mate.mate-polkit}/bin/polkit-mate"
"uwsm app -- ${pkgs.mate-polkit}/bin/polkit-mate"
];
env = [
"WLR_NO_HARDWARE_CURSORS,1"
@ -290,7 +290,8 @@ in {
in [
"$mainMod, ${ws}, ${workspace_command_prefix}workspace, ${toString (x + 1)}"
"$mainMod SHIFT, ${ws}, ${workspace_command_prefix}movetoworkspace, ${toString (x + 1)}"
]) 10)
])
10)
);
};
};

View File

@ -0,0 +1,180 @@
-- frame-seek.lua
-- Allows seeking to a specific frame number or timestamp
local input = require("mp.input")
local jump_mode = nil -- "frame" or "time"
local relative = false
local minus = false
local fps = 0
function parse_timestamp(input_str)
-- Formats:
-- HH:MM:SS.ms
-- MM:SS.ms
-- SS.ms
-- .ms
-- More than 60 minutes or seconds can be entered - it will seek any amount accurately
-- First try to match HH:MM:SS.ms
local hours, minutes, seconds = input_str:match("^(%d+):(%d+):(%d+%.?%d*)$")
if hours and minutes and seconds then
return tonumber(hours) * 3600 + tonumber(minutes) * 60 + tonumber(seconds)
end
-- Try to match MM:SS.ms
local minutes, seconds = input_str:match("^(%d+):(%d+%.?%d*)$")
if minutes and seconds then
return tonumber(minutes) * 60 + tonumber(seconds)
end
-- Try to match just seconds (with or without decimal)
local seconds = input_str:match("^(%d+%.?%d*)$")
if seconds then
return tonumber(seconds)
end
local milliseconds = input_str:match("^%.(%d+)$")
if milliseconds ~= nil then
return tonumber("0." .. milliseconds)
end
return nil
end
function seek_to_frame(frame_num)
fps = mp.get_property_number("estimated-vf-fps")
if not fps or fps <= 0 then
mp.osd_message("Error: Cannot determine framerate")
return
end
local timestamp = frame_num / fps
seek_to_timestamp(timestamp)
end
function seek_to_timestamp(timestamp)
if minus then timestamp = -timestamp end
local cur_time = mp.get_property_number("time-pos")
if not cur_time then return end
if relative then
if timestamp == 0 then return end
if math.abs(timestamp) < 10 then
mp.commandv("seek", timestamp, "exact")
else
-- Only show OSD if seek >10s
mp.command("seek " .. timestamp .. " exact")
end
else
-- Handle imprecise float
if math.abs(timestamp - cur_time) < 1e-7 then return end
mp.command("seek " .. timestamp .. " absolute+exact")
end
mp.observe_property("time-pos", "number", display_osd_message)
end
function display_osd_message(_, timestamp)
if timestamp == nil then return end
mp.unobserve_property(display_osd_message)
-- Format the display nicely
local hours = math.floor(timestamp / 3600)
local minutes = math.floor((timestamp % 3600) / 60)
local seconds = math.floor(timestamp % 60)
local milliseconds = math.floor((timestamp % 1) * 1000 + 0.5)
local display_time = string.format("%02d:%02d", minutes, seconds)
if hours ~= 0 then
display_time = string.format("%d:", hours) .. display_time
end
if milliseconds ~= 0 or jump_mode == "frame" then
display_time = display_time .. string.format(".%03d", milliseconds)
end
if jump_mode == "frame" and fps and fps > 0 then
local frame_num = math.floor(timestamp * fps + 0.5)
mp.osd_message(string.format("Seeking to frame %d (%s)", frame_num, display_time))
else
mp.osd_message(string.format("Seeking to %s", display_time))
end
end
function jump_submit(input)
if not input or input == "" then
reset()
return
end
-- Handle relative marker
if input:sub(1, 1) == "r" then
relative = true
input = input:sub(2)
end
-- Handle negative input
minus = false
if input:sub(1, 1) == "-" then
minus = true
input = input:sub(2)
end
if jump_mode == "frame" then
local frame_num = tonumber(input)
if frame_num then
seek_to_frame(math.floor(frame_num))
else
mp.osd_message("Invalid frame number")
end
elseif jump_mode == "time" then
local timestamp = parse_timestamp(input)
if timestamp then
seek_to_timestamp(timestamp)
else
mp.osd_message("Invalid timestamp format")
end
end
end
function reset()
jump_mode = nil
relative = false
minus = false
end
function run_script(mode, prompt, relative_flag)
if mp.get_property("path") == nil then return end
reset()
jump_mode = mode
relative = relative_flag
input.get({
prompt = prompt,
submit = jump_submit,
})
end
-- Register key bindings
mp.add_key_binding("ctrl+t", "seek-timestamp", function()
run_script("time", "Seek to time:", false)
end)
mp.add_key_binding("ctrl+T", "seek-frame", function()
run_script("frame", "Seek to frame:", false)
end)
mp.add_key_binding(nil, "seek-timestamp-relative", function()
run_script("time", "Seek forward by time:", true)
end)
mp.add_key_binding(nil, "seek-frame-relative", function()
run_script("frame", "Seek forward by frame:", true)
end)

View File

@ -1,6 +1,6 @@
vim.keymap.set("i", "jj", "<Esc>", {})
vim.keymap.set({ "n", "v" }, "k", "v:count == 0 ? 'gk' : 'k'", { expr = true })
vim.keymap.set({ "n", "v" }, "j", "v:count == 0 ? 'gj' : 'j'", { expr = true })
vim.keymap.set({ "n", "v" }, "k", "v:count == 0 ? 'gk' : 'k'", { expr = true, silent = true })
vim.keymap.set({ "n", "v" }, "j", "v:count == 0 ? 'gj' : 'j'", { expr = true, silent = true })
vim.keymap.set("n", "<S-k>", "<Nop>", {})
vim.keymap.set("t", "jj", "<C-\\><C-n>", { noremap = true, silent = true })
vim.keymap.set("n", "<Backspace>", ":q<cr>", { noremap = true, silent = true })
@ -15,15 +15,16 @@ vim.keymap.set("n", "<C-I>", "<C-I>", { noremap = true, silent = true })
vim.keymap.set("n", "n", "nzz", { noremap = true })
vim.keymap.set("n", "N", "Nzz", { noremap = true })
vim.keymap.set("x", "<leader>p", [["_dP]], { noremap = true })
vim.keymap.set({"n", "v"}, "<leader>y", [["+y]])
vim.keymap.set({"n", "v"}, "<leader>Y", [["+Y]])
vim.keymap.set({ "n", "v" }, "<leader>y", [["+y]])
vim.keymap.set({ "n", "v" }, "<leader>Y", [["+Y]])
vim.keymap.set("n", "<Tab>", "<Nop>", { noremap = true })
vim.keymap.set("n", "<leader><space>", ":noh<cr>", { noremap = true, silent = true })
vim.keymap.set("n", "gn", ":n<cr>", { noremap = true, silent = true })
-- vim.keymap.set("n", "gi", ":ClangdSwitchSourceHeader<cr>", { noremap = true, silent = true })
vim.keymap.set("n", "-", function () require("oil").open() end, { desc = "Open parent directory" })
vim.keymap.set("n", "<leader>-", function () require("oil").open() end, { desc = "Open parent directory" })
vim.keymap.set("n", "<leader>g", function () require("neogit").open({kind="replace"}) end, { noremap = true, silent = true })
vim.keymap.set("n", "-", function() require("oil").open() end, { desc = "Open parent directory" })
vim.keymap.set("n", "<leader>-", function() require("oil").open() end, { desc = "Open parent directory" })
vim.keymap.set("n", "<leader>g", function() require("neogit").open({ kind = "replace" }) end,
{ noremap = true, silent = true })
vim.keymap.set("x", "<leader>a", "<C-A>", { noremap = true, silent = true })
vim.keymap.set("x", "<leader>x", "<C-X>", { noremap = true, silent = true })
vim.keymap.set("x", "<leader>ga", "g<C-A>", { noremap = true, silent = true })

View File

@ -22,7 +22,15 @@
home.packages = with pkgs; [
spotify
slack
(pkgs.symlinkJoin {
name = "slack-pipewire";
paths = [pkgs.slack];
buildInputs = [pkgs.makeWrapper];
postBuild = ''
wrapProgram $out/bin/slack \
--add-flags "--enable-features=WebRTCPipeWireCamera"
'';
})
eid-mw
onlyoffice-desktopeditors
libreoffice

View File

@ -175,9 +175,15 @@ in {
};
services.usbmuxd.enable = true;
environment.systemPackages = with pkgs; [
libcamera
ifuse
libimobiledevice
scrcpy
v4l-utils
];
boot.kernel.sysctl = {
"net.ipv6.conf.all.disable_ipv6" = 1;
"net.ipv6.conf.default.disable_ipv6" = 1;
"net.ipv6.conf.lo.disable_ipv6" = 1;
};
}

View File

@ -14,13 +14,14 @@
boot.initrd.availableKernelModules = ["xhci_pci" "thunderbolt" "nvme" "usb_storage" "sd_mod"];
boot.initrd.kernelModules = [];
boot.kernelModules = ["kvm-intel" "v4l2loopback"];
boot.extraModulePackages = with config.boot.kernelPackages; [v4l2loopback tp_smapi];
boot.kernelModules = ["kvm-intel" "v4l2loopback" "intel_vsc" "intel_vsc_csi" "intel_vsc_vbus"];
boot.extraModulePackages = with config.boot.kernelPackages; [v4l2loopback tp_smapi ipu6-drivers];
boot.extraModprobeConfig = ''
options thinkpad_acpi fan_control=1
options v4l2loopback exclusive_caps=1 card_label="Android Virtual Camera"
options v4l2loopback exclusive_caps=1 video_nr=42 card_label="IPU6 Virtual Camera"
'';
boot.kernelParams = ["ipv6.disable=1"];
# boot.kernelParams = ["ipv6.disable=1"];
fileSystems."/" = {
device = "rpool/root";
@ -52,24 +53,48 @@
hardware.trackpoint.enable = lib.mkDefault true;
hardware.trackpoint.emulateWheel = lib.mkDefault config.hardware.trackpoint.enable;
hardware.trackpoint.device = "TPPS/2 Synaptics TrackPoint";
hardware.ipu6.enable = true;
hardware.ipu6.platform = "ipu6ep";
nixpkgs.config.packageOverrides = pkgs: {
zfs = pkgs.zfs_unstable;
};
# boot.kernelPackages = pkgs.linuxPackages_latest;
# boot.kernelPackages = pkgs.linuxPackages_latest.extend ( self: super: {
# ipu6-drivers = super.ipu6-drivers.overrideAttrs (
# final: previous: rec {
# src = builtins.fetchGit {
# url = "https://github.com/intel/ipu6-drivers.git";
# ref = "master";
# rev = "4bb5b4d8128fbf7f4730cd364a8f7fc13a0ef65b";
# };
# patches = [
# "${src}/patches/0001-v6.10-IPU6-headers-used-by-PSYS.patch"
# ] ;
# }
# );
# } );
boot.kernelPackages = pkgs.linuxPackages_latest;
hardware.firmware = with pkgs; [
ipu6-camera-bins
ivsc-firmware
];
services.udev.extraRules = ''
SUBSYSTEM=="intel-ipu6-psys", MODE="0660", GROUP="video"
'';
systemd.services.ipu6-v4l2-proxy = {
description = "IPU6 Libcamera to V4L2Loopback Proxy";
# wantedBy = ["multi-user.target"];
after = ["systemd-udev-settle.service"];
serviceConfig = {
ExecStart = let
gstPluginPath = pkgs.lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" (with pkgs.gst_all_1;
[
gstreamer
gst-plugins-base
gst-plugins-good
gst-plugins-bad
]
++ [pkgs.libcamera]);
in ''
${pkgs.gst_all_1.gstreamer}/bin/gst-launch-1.0 \
--gst-plugin-path=${gstPluginPath} \
libcamerasrc \
! video/x-raw \
! vapostproc contrast=1.3 saturation=1.4 brightness=-0.15 \
! video/x-raw,width=1280,height=720 \
! videoconvert \
! gamma gamma=0.7 \
! videoconvert \
! video/x-raw,format=YUY2 \
! v4l2sink device=/dev/video42
'';
Restart = "always";
RestartSec = "3";
};
};
}

View File

@ -48,12 +48,20 @@
services.gnome.sushi.enable = true;
services.pipewire = {
wireplumber.enable = true;
enable = true;
alsa.enable = true;
alsa.support32Bit = true;
pulse.enable = true;
jack.enable = true;
};
services.pipewire.wireplumber.extraConfig = {
"99-libcamera" = {
"wireplumber.settings" = {
"camera.use-libcamera" = true;
};
};
};
hardware.bluetooth = {
enable = true;