summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-03 04:14:42 +0900
committerTheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com>2025-11-03 04:14:42 +0900
commite924090e00636ab2aa5ab66fea6f8d6ee1a2ca7c (patch)
tree25278da861ae5035546e0e95a4e47c2480711642
parent5070b67dd7d8ec15f541dd17c108b1b334afabae (diff)
modified plugins/ssh.lua, modified plugins/ssh.lua, modified shell/aliasrc, modified bin/ylog
-rw-r--r--ar/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua283
-rw-r--r--mac/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua283
-rw-r--r--mac/.config/shell/aliasrc2
-rwxr-xr-xmac/.local/bin/ylog169
4 files changed, 525 insertions, 212 deletions
diff --git a/ar/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua b/ar/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
index b42a588..e9788e0 100644
--- a/ar/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
+++ b/ar/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
@@ -1,118 +1,199 @@
return {
- "amitds1997/remote-nvim.nvim",
- version = "*",
- dependencies = {
- "nvim-lua/plenary.nvim",
- "MunifTanjim/nui.nvim",
- "nvim-telescope/telescope.nvim",
- },
- config = true,
- init = function()
- local ok, wk = pcall(require, "which-key")
- if ok then
- wk.add({ { "<localleader>r", group = "SSH Remote" } })
- end
- end,
- keys = {
- { "<localleader>rs", "<cmd>RemoteStart<CR>", desc = "Start/Connect", mode = "n", silent = true },
- { "<localleader>rx", "<cmd>RemoteStop<CR>", desc = "Stop/Close", mode = "n", silent = true },
- { "<localleader>ri", "<cmd>RemoteInfo<CR>", desc = "Info/Progress Viewer", mode = "n", silent = true },
- { "<localleader>rc", "<cmd>RemoteCleanup<CR>", desc = "Cleanup workspace", mode = "n", silent = true },
+ {
+ "amitds1997/remote-nvim.nvim",
+ version = "*",
+ dependencies = {
+ "nvim-lua/plenary.nvim",
+ "MunifTanjim/nui.nvim",
+ "nvim-telescope/telescope.nvim",
+ },
+ config = true,
+ init = function()
+ local ok, wk = pcall(require, "which-key")
+ if ok then
+ wk.add({ { "<localleader>r", group = "SSH Remote" } })
+ end
+ end,
+ keys = {
+ { "<localleader>rs", "<cmd>RemoteStart<CR>", desc = "Start/Connect", mode = "n", silent = true },
+ { "<localleader>rx", "<cmd>RemoteStop<CR>", desc = "Stop/Close", mode = "n", silent = true },
+ { "<localleader>ri", "<cmd>RemoteInfo<CR>", desc = "Info/Progress Viewer", mode = "n", silent = true },
+ { "<localleader>rC", "<cmd>RemoteCleanup<CR>", desc = "Cleanup workspace", mode = "n", silent = true },
- -- Delete saved config: show a list, allow multi-select, then run :RemoteConfigDel <name>
- {
- "<localleader>rd",
- function()
- local function get_names()
- -- use command-line completion if the command supports it
- local list = vim.fn.getcompletion("RemoteConfigDel ", "cmdline") or {}
- return list
- end
+ -- Delete saved config: show a list, allow multi-select, then run :RemoteConfigDel <name>
+ {
+ "<localleader>rd",
+ function()
+ local function get_names()
+ -- use command-line completion if the command supports it
+ local list = vim.fn.getcompletion("RemoteConfigDel ", "cmdline") or {}
+ return list
+ end
- local names = get_names()
- if #names == 0 then
- return vim.notify(
- "No saved remote configs found (completion empty)",
- vim.log.levels.INFO,
- { title = "Remote" }
- )
- end
+ local names = get_names()
+ if #names == 0 then
+ return vim.notify(
+ "No saved remote configs found (completion empty)",
+ vim.log.levels.INFO,
+ { title = "Remote" }
+ )
+ end
- -- Prefer Telescope if present
- local ok_picker, pickers = pcall(require, "telescope.pickers")
- if ok_picker then
- local finders = require("telescope.finders")
- local conf = require("telescope.config").values
- local actions = require("telescope.actions")
- local state = require("telescope.actions.state")
+ -- Prefer Telescope if present
+ local ok_picker, pickers = pcall(require, "telescope.pickers")
+ if ok_picker then
+ local finders = require("telescope.finders")
+ local conf = require("telescope.config").values
+ local actions = require("telescope.actions")
+ local state = require("telescope.actions.state")
- pickers
- .new({}, {
- prompt_title = "Delete Remote Config(s)",
- finder = finders.new_table(names),
- sorter = conf.generic_sorter({}),
- attach_mappings = function(_, map)
- local function run_delete(prompt_bufnr, picked)
- local function del(name)
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
- end
- if picked and #picked > 0 then
- for _, entry in ipairs(picked) do
- del(entry.value or entry[1] or entry.text)
+ pickers
+ .new({}, {
+ prompt_title = "Delete Remote Config(s)",
+ finder = finders.new_table(names),
+ sorter = conf.generic_sorter({}),
+ attach_mappings = function(_, map)
+ local function run_delete(prompt_bufnr, picked)
+ local function del(name)
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
end
- else
- local entry = state.get_selected_entry()
- if entry then
- del(entry.value or entry[1] or entry.text)
+ if picked and #picked > 0 then
+ for _, entry in ipairs(picked) do
+ del(entry.value or entry[1] or entry.text)
+ end
+ else
+ local entry = state.get_selected_entry()
+ if entry then
+ del(entry.value or entry[1] or entry.text)
+ end
end
+ actions.close(prompt_bufnr)
end
- actions.close(prompt_bufnr)
- end
- actions.select_default:replace(function(bufnr)
- local picker = state.get_current_picker(bufnr)
- local multi = picker:get_multi_selection()
- run_delete(bufnr, multi)
- end)
+ actions.select_default:replace(function(bufnr)
+ local picker = state.get_current_picker(bufnr)
+ local multi = picker:get_multi_selection()
+ run_delete(bufnr, multi)
+ end)
- -- quality of life: <C-d> also deletes without closing (optional)
- map("i", "<C-d>", function(bufnr)
- local picker = state.get_current_picker(bufnr)
- local multi = picker:get_multi_selection()
- local function del(name)
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
- end
- if multi and #multi > 0 then
- for _, e in ipairs(multi) do
- del(e.value or e[1] or e.text)
+ -- quality of life: <C-d> also deletes without closing (optional)
+ map("i", "<C-d>", function(bufnr)
+ local picker = state.get_current_picker(bufnr)
+ local multi = picker:get_multi_selection()
+ local function del(name)
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
end
- else
- local e = state.get_selected_entry()
- if e then
- del(e.value or e[1] or e.text)
+ if multi and #multi > 0 then
+ for _, e in ipairs(multi) do
+ del(e.value or e[1] or e.text)
+ end
+ else
+ local e = state.get_selected_entry()
+ if e then
+ del(e.value or e[1] or e.text)
+ end
end
- end
- -- keep picker open
- end)
+ -- keep picker open
+ end)
- return true
- end,
- })
- :find()
- else
- -- Fallback: vim.ui.select (single delete)
- vim.ui.select(names, { prompt = "Select remote config to delete" }, function(choice)
- if choice and choice ~= "" then
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { choice } }, {})
- end
- end)
- end
- end,
- desc = "Delete saved config (pick from list)",
- mode = "n",
- silent = true,
+ return true
+ end,
+ })
+ :find()
+ else
+ -- Fallback: vim.ui.select (single delete)
+ vim.ui.select(names, { prompt = "Select remote config to delete" }, function(choice)
+ if choice and choice ~= "" then
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { choice } }, {})
+ end
+ end)
+ end
+ end,
+ desc = "Delete saved config (pick from list)",
+ mode = "n",
+ silent = true,
+ },
+
+ { "<localleader>rl", "<cmd>RemoteLog<CR>", desc = "Open log", mode = "n", silent = true },
+ },
+ },
+ {
+ "nosduco/remote-sshfs.nvim",
+ dependencies = { "nvim-telescope/telescope.nvim", "nvim-lua/plenary.nvim" },
+ opts = {
+ -- Refer to the configuration section below
+ -- or leave empty for defaults
},
+ config = function()
+ require("remote-sshfs").setup({
+ connections = {
+ ssh_configs = { -- which ssh configs to parse for hosts list
+ vim.fn.expand("$HOME") .. "/.ssh/config",
+ "/etc/ssh/ssh_config",
+ -- "/path/to/custom/ssh_config"
+ },
+ ssh_known_hosts = vim.fn.expand("$HOME") .. "/.ssh/known_hosts",
+ -- NOTE: Can define ssh_configs similarly to include all configs in a folder
+ -- ssh_configs = vim.split(vim.fn.globpath(vim.fn.expand "$HOME" .. "/.ssh/configs", "*"), "\n")
+ sshfs_args = { -- arguments to pass to the sshfs command
+ "-o reconnect",
+ "-o ConnectTimeout=5",
+ },
+ },
+ mounts = {
+ base_dir = vim.fn.expand("$HOME") .. "/.sshfs/", -- base directory for mount points
+ unmount_on_exit = true, -- run sshfs as foreground, will unmount on vim exit
+ },
+ handlers = {
+ on_connect = {
+ change_dir = true, -- when connected change vim working directory to mount point
+ },
+ on_disconnect = {
+ clean_mount_folders = false, -- remove mount point folder on disconnect/unmount
+ },
+ on_edit = {}, -- not yet implemented
+ },
+ ui = {
+ select_prompts = false, -- not yet implemented
+ confirm = {
+ connect = true, -- prompt y/n when host is selected to connect to
+ change_dir = false, -- prompt y/n to change working directory on connection (only applicable if handlers.on_connect.change_dir is enabled)
+ },
+ },
+ log = {
+ enabled = false, -- enable logging
+ truncate = false, -- truncate logs
+ types = { -- enabled log types
+ all = false,
+ util = false,
+ handler = false,
+ sshfs = false,
+ },
+ },
+ })
+ local api = require("remote-sshfs.api")
+ vim.keymap.set("n", "<localleader>rc", api.connect, { desc = "Connect SSH" })
+ vim.keymap.set("n", "<localleader>rd", api.disconnect, { desc = "Disconnect SSH" })
+ vim.keymap.set("n", "<localleader>re", api.edit, { desc = "Edit SSH" })
- { "<localleader>rl", "<cmd>RemoteLog<CR>", desc = "Open log", mode = "n", silent = true },
+ -- (optional) Override telescope find_files and live_grep to make dynamic based on if connected to host
+ local builtin = require("telescope.builtin")
+ local connections = require("remote-sshfs.connections")
+ vim.keymap.set("n", "<localleader>rf", function()
+ if connections.is_connected() then
+ api.find_files()
+ else
+ builtin.find_files()
+ end
+ end, { desc = "Find SSH files" })
+ vim.keymap.set("n", "<localleader>rg", function()
+ if connections.is_connected() then
+ api.live_grep()
+ else
+ builtin.live_grep()
+ end
+ end, { desc = "Live SSH grep" })
+ require("telescope").load_extension("remote-sshfs")
+ end,
},
}
diff --git a/mac/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua b/mac/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
index b42a588..e9788e0 100644
--- a/mac/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
+++ b/mac/.config/TheSiahxyz/lua/TheSiahxyz/plugins/ssh.lua
@@ -1,118 +1,199 @@
return {
- "amitds1997/remote-nvim.nvim",
- version = "*",
- dependencies = {
- "nvim-lua/plenary.nvim",
- "MunifTanjim/nui.nvim",
- "nvim-telescope/telescope.nvim",
- },
- config = true,
- init = function()
- local ok, wk = pcall(require, "which-key")
- if ok then
- wk.add({ { "<localleader>r", group = "SSH Remote" } })
- end
- end,
- keys = {
- { "<localleader>rs", "<cmd>RemoteStart<CR>", desc = "Start/Connect", mode = "n", silent = true },
- { "<localleader>rx", "<cmd>RemoteStop<CR>", desc = "Stop/Close", mode = "n", silent = true },
- { "<localleader>ri", "<cmd>RemoteInfo<CR>", desc = "Info/Progress Viewer", mode = "n", silent = true },
- { "<localleader>rc", "<cmd>RemoteCleanup<CR>", desc = "Cleanup workspace", mode = "n", silent = true },
+ {
+ "amitds1997/remote-nvim.nvim",
+ version = "*",
+ dependencies = {
+ "nvim-lua/plenary.nvim",
+ "MunifTanjim/nui.nvim",
+ "nvim-telescope/telescope.nvim",
+ },
+ config = true,
+ init = function()
+ local ok, wk = pcall(require, "which-key")
+ if ok then
+ wk.add({ { "<localleader>r", group = "SSH Remote" } })
+ end
+ end,
+ keys = {
+ { "<localleader>rs", "<cmd>RemoteStart<CR>", desc = "Start/Connect", mode = "n", silent = true },
+ { "<localleader>rx", "<cmd>RemoteStop<CR>", desc = "Stop/Close", mode = "n", silent = true },
+ { "<localleader>ri", "<cmd>RemoteInfo<CR>", desc = "Info/Progress Viewer", mode = "n", silent = true },
+ { "<localleader>rC", "<cmd>RemoteCleanup<CR>", desc = "Cleanup workspace", mode = "n", silent = true },
- -- Delete saved config: show a list, allow multi-select, then run :RemoteConfigDel <name>
- {
- "<localleader>rd",
- function()
- local function get_names()
- -- use command-line completion if the command supports it
- local list = vim.fn.getcompletion("RemoteConfigDel ", "cmdline") or {}
- return list
- end
+ -- Delete saved config: show a list, allow multi-select, then run :RemoteConfigDel <name>
+ {
+ "<localleader>rd",
+ function()
+ local function get_names()
+ -- use command-line completion if the command supports it
+ local list = vim.fn.getcompletion("RemoteConfigDel ", "cmdline") or {}
+ return list
+ end
- local names = get_names()
- if #names == 0 then
- return vim.notify(
- "No saved remote configs found (completion empty)",
- vim.log.levels.INFO,
- { title = "Remote" }
- )
- end
+ local names = get_names()
+ if #names == 0 then
+ return vim.notify(
+ "No saved remote configs found (completion empty)",
+ vim.log.levels.INFO,
+ { title = "Remote" }
+ )
+ end
- -- Prefer Telescope if present
- local ok_picker, pickers = pcall(require, "telescope.pickers")
- if ok_picker then
- local finders = require("telescope.finders")
- local conf = require("telescope.config").values
- local actions = require("telescope.actions")
- local state = require("telescope.actions.state")
+ -- Prefer Telescope if present
+ local ok_picker, pickers = pcall(require, "telescope.pickers")
+ if ok_picker then
+ local finders = require("telescope.finders")
+ local conf = require("telescope.config").values
+ local actions = require("telescope.actions")
+ local state = require("telescope.actions.state")
- pickers
- .new({}, {
- prompt_title = "Delete Remote Config(s)",
- finder = finders.new_table(names),
- sorter = conf.generic_sorter({}),
- attach_mappings = function(_, map)
- local function run_delete(prompt_bufnr, picked)
- local function del(name)
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
- end
- if picked and #picked > 0 then
- for _, entry in ipairs(picked) do
- del(entry.value or entry[1] or entry.text)
+ pickers
+ .new({}, {
+ prompt_title = "Delete Remote Config(s)",
+ finder = finders.new_table(names),
+ sorter = conf.generic_sorter({}),
+ attach_mappings = function(_, map)
+ local function run_delete(prompt_bufnr, picked)
+ local function del(name)
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
end
- else
- local entry = state.get_selected_entry()
- if entry then
- del(entry.value or entry[1] or entry.text)
+ if picked and #picked > 0 then
+ for _, entry in ipairs(picked) do
+ del(entry.value or entry[1] or entry.text)
+ end
+ else
+ local entry = state.get_selected_entry()
+ if entry then
+ del(entry.value or entry[1] or entry.text)
+ end
end
+ actions.close(prompt_bufnr)
end
- actions.close(prompt_bufnr)
- end
- actions.select_default:replace(function(bufnr)
- local picker = state.get_current_picker(bufnr)
- local multi = picker:get_multi_selection()
- run_delete(bufnr, multi)
- end)
+ actions.select_default:replace(function(bufnr)
+ local picker = state.get_current_picker(bufnr)
+ local multi = picker:get_multi_selection()
+ run_delete(bufnr, multi)
+ end)
- -- quality of life: <C-d> also deletes without closing (optional)
- map("i", "<C-d>", function(bufnr)
- local picker = state.get_current_picker(bufnr)
- local multi = picker:get_multi_selection()
- local function del(name)
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
- end
- if multi and #multi > 0 then
- for _, e in ipairs(multi) do
- del(e.value or e[1] or e.text)
+ -- quality of life: <C-d> also deletes without closing (optional)
+ map("i", "<C-d>", function(bufnr)
+ local picker = state.get_current_picker(bufnr)
+ local multi = picker:get_multi_selection()
+ local function del(name)
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { name } }, {})
end
- else
- local e = state.get_selected_entry()
- if e then
- del(e.value or e[1] or e.text)
+ if multi and #multi > 0 then
+ for _, e in ipairs(multi) do
+ del(e.value or e[1] or e.text)
+ end
+ else
+ local e = state.get_selected_entry()
+ if e then
+ del(e.value or e[1] or e.text)
+ end
end
- end
- -- keep picker open
- end)
+ -- keep picker open
+ end)
- return true
- end,
- })
- :find()
- else
- -- Fallback: vim.ui.select (single delete)
- vim.ui.select(names, { prompt = "Select remote config to delete" }, function(choice)
- if choice and choice ~= "" then
- vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { choice } }, {})
- end
- end)
- end
- end,
- desc = "Delete saved config (pick from list)",
- mode = "n",
- silent = true,
+ return true
+ end,
+ })
+ :find()
+ else
+ -- Fallback: vim.ui.select (single delete)
+ vim.ui.select(names, { prompt = "Select remote config to delete" }, function(choice)
+ if choice and choice ~= "" then
+ vim.api.nvim_cmd({ cmd = "RemoteConfigDel", args = { choice } }, {})
+ end
+ end)
+ end
+ end,
+ desc = "Delete saved config (pick from list)",
+ mode = "n",
+ silent = true,
+ },
+
+ { "<localleader>rl", "<cmd>RemoteLog<CR>", desc = "Open log", mode = "n", silent = true },
+ },
+ },
+ {
+ "nosduco/remote-sshfs.nvim",
+ dependencies = { "nvim-telescope/telescope.nvim", "nvim-lua/plenary.nvim" },
+ opts = {
+ -- Refer to the configuration section below
+ -- or leave empty for defaults
},
+ config = function()
+ require("remote-sshfs").setup({
+ connections = {
+ ssh_configs = { -- which ssh configs to parse for hosts list
+ vim.fn.expand("$HOME") .. "/.ssh/config",
+ "/etc/ssh/ssh_config",
+ -- "/path/to/custom/ssh_config"
+ },
+ ssh_known_hosts = vim.fn.expand("$HOME") .. "/.ssh/known_hosts",
+ -- NOTE: Can define ssh_configs similarly to include all configs in a folder
+ -- ssh_configs = vim.split(vim.fn.globpath(vim.fn.expand "$HOME" .. "/.ssh/configs", "*"), "\n")
+ sshfs_args = { -- arguments to pass to the sshfs command
+ "-o reconnect",
+ "-o ConnectTimeout=5",
+ },
+ },
+ mounts = {
+ base_dir = vim.fn.expand("$HOME") .. "/.sshfs/", -- base directory for mount points
+ unmount_on_exit = true, -- run sshfs as foreground, will unmount on vim exit
+ },
+ handlers = {
+ on_connect = {
+ change_dir = true, -- when connected change vim working directory to mount point
+ },
+ on_disconnect = {
+ clean_mount_folders = false, -- remove mount point folder on disconnect/unmount
+ },
+ on_edit = {}, -- not yet implemented
+ },
+ ui = {
+ select_prompts = false, -- not yet implemented
+ confirm = {
+ connect = true, -- prompt y/n when host is selected to connect to
+ change_dir = false, -- prompt y/n to change working directory on connection (only applicable if handlers.on_connect.change_dir is enabled)
+ },
+ },
+ log = {
+ enabled = false, -- enable logging
+ truncate = false, -- truncate logs
+ types = { -- enabled log types
+ all = false,
+ util = false,
+ handler = false,
+ sshfs = false,
+ },
+ },
+ })
+ local api = require("remote-sshfs.api")
+ vim.keymap.set("n", "<localleader>rc", api.connect, { desc = "Connect SSH" })
+ vim.keymap.set("n", "<localleader>rd", api.disconnect, { desc = "Disconnect SSH" })
+ vim.keymap.set("n", "<localleader>re", api.edit, { desc = "Edit SSH" })
- { "<localleader>rl", "<cmd>RemoteLog<CR>", desc = "Open log", mode = "n", silent = true },
+ -- (optional) Override telescope find_files and live_grep to make dynamic based on if connected to host
+ local builtin = require("telescope.builtin")
+ local connections = require("remote-sshfs.connections")
+ vim.keymap.set("n", "<localleader>rf", function()
+ if connections.is_connected() then
+ api.find_files()
+ else
+ builtin.find_files()
+ end
+ end, { desc = "Find SSH files" })
+ vim.keymap.set("n", "<localleader>rg", function()
+ if connections.is_connected() then
+ api.live_grep()
+ else
+ builtin.live_grep()
+ end
+ end, { desc = "Live SSH grep" })
+ require("telescope").load_extension("remote-sshfs")
+ end,
},
}
diff --git a/mac/.config/shell/aliasrc b/mac/.config/shell/aliasrc
index 9fc3aab..d1fe206 100644
--- a/mac/.config/shell/aliasrc
+++ b/mac/.config/shell/aliasrc
@@ -500,5 +500,7 @@ alias szs="source ${XDG_CONFIG_HOME:-${HOME}/.config}/zsh/.zshrc"
alias ylogu='ylog -s recordings -c us'
+alias ylogh='ylog -s hidden -c us | grep $(LC_TIME=C date +%d/%b)'
+alias ylogi='ylog -s hidden -c us | grep $(LC_TIME=C date -v-1d +%d/%b)'
alias ylogt='ylog -s recordings -c us | grep $(LC_TIME=C date +%d/%b)'
alias ylogy='ylog -s recordings -c us | grep $(LC_TIME=C date -v-1d +%d/%b)'
diff --git a/mac/.local/bin/ylog b/mac/.local/bin/ylog
index f15fb3b..d147eb8 100755
--- a/mac/.local/bin/ylog
+++ b/mac/.local/bin/ylog
@@ -9,7 +9,8 @@ SCOPE="all" # all|access|recordings
EXCL_FIREFOX=1 # 1 = exclude Firefox lines by default
EXCLUDES="59.19.56.8" # default exclude pattern
ADD_EXCLUDES=""
-LINE_LIMIT=30 # default number of lines when TARGET=all
+LINE_LIMIT=100 # default number of lines when TARGET=all
+DATE_FILTER="" # date filter: "2" = 2 days ago, "~2" = last 2 days to today
usage() {
cat <<'EOF'
@@ -40,6 +41,11 @@ Options:
Only applies when TARGET=all
e.g. -l 50 → show last 50 lines per file
+ -d DATE Filter by date
+ e.g. -d 2 → logs from 2 days ago only
+ e.g. -d 1 → logs from 1 day ago only
+ e.g. -d ~2 → logs from 2 days ago to today
+
-h Show this help
Examples:
@@ -47,11 +53,13 @@ Examples:
ylog -s recordings # Recordings logs only, last 10 lines each
ylog -c kr -t 1.2.3.4 # Search specific IP in Korean logs
ylog -t all -l 50 # All logs, last 50 lines each
+ ylog -d 1 # Logs from 1 day ago only
+ ylog -d ~2 # Logs from 2 days ago to today
EOF
exit 0
}
-while getopts "t:c:s:nx:l:h" opt; do
+while getopts "t:c:s:nx:l:d:h" opt; do
case "$opt" in
t) TARGET="$OPTARG" ;;
c) COUNTRY="$OPTARG" ;;
@@ -60,6 +68,7 @@ while getopts "t:c:s:nx:l:h" opt; do
x) ADD_EXCLUDES="${ADD_EXCLUDES}
$OPTARG" ;;
l) LINE_LIMIT="$OPTARG" ;;
+ d) DATE_FILTER="$OPTARG" ;;
h) usage ;;
*) usage ;;
esac
@@ -78,6 +87,7 @@ TARGET="'"$TARGET"'"
ESC_TARGET="'"$esc_target"'"
EXCL_FIREFOX='"$EXCL_FIREFOX"'
LINE_LIMIT='"$LINE_LIMIT"'
+DATE_FILTER="'"$DATE_FILTER"'"
# collect files
pick_files() {
@@ -104,6 +114,11 @@ pick_files() {
[ -e "$q" ] && printf "%s\n" "$q"
done
fi
+ if [ "$SCOPE" = "hidden" ] || [ "$SCOPE" = "all" ]; then
+ for q in "$LOG_DIR/hidden.access.log" "$LOG_DIR/hidden.access.log".*; do
+ [ -e "$q" ] && printf "%s\n" "$q"
+ done
+ fi
}
# build exclude regex
@@ -137,12 +152,19 @@ if [ ! -s "$FILES_TMP" ]; then
exit 0
fi
-echo "[SCAN] Target: \"$TARGET\" Country: $COUNTRY Scope: $SCOPE"
+if [ -n "$DATE_FILTER" ]; then
+ echo "[SCAN] Target: \"$TARGET\" Country: $COUNTRY Scope: $SCOPE Date: $DATE_FILTER"
+else
+ echo "[SCAN] Target: \"$TARGET\" Country: $COUNTRY Scope: $SCOPE"
+fi
echo "[FILES]"
cat "$FILES_TMP"
EXRE="$(build_exre || true)"
+RESULTS_TMP="/tmp/.ylog_results_$$"
+rm -f "$RESULTS_TMP"
+
found=0
for f in $(cat "$FILES_TMP"); do
[ -e "$f" ] || continue
@@ -160,17 +182,144 @@ for f in $(cat "$FILES_TMP"); do
[ "$EXCL_FIREFOX" -eq 1 ] && cmd="$cmd | grep -vi firefox"
if [ "$TARGET" = "all" ]; then
- if sh -c "$cmd | tail -n $LINE_LIMIT"; then
- found=1
- fi
+ sh -c "$cmd | tail -n $LINE_LIMIT" >> "$RESULTS_TMP" 2>/dev/null && found=1
else
- if sh -c "$cmd"; then
- found=1
- fi
+ sh -c "$cmd" >> "$RESULTS_TMP" 2>/dev/null && found=1
fi
done
-rm -f "$FILES_TMP"
+# Deduplicate: keep only the latest log for same IP+URI within same minute
+# Format: IP - user [datetime] "METHOD URI PROTOCOL" status bytes ...
+if [ -f "$RESULTS_TMP" ] && [ -s "$RESULTS_TMP" ]; then
+ # Date filtering: calculate target dates
+ TARGET_DATE=""
+ START_DATE=""
+ if [ -n "$DATE_FILTER" ]; then
+ if [ "$(printf '%s' "$DATE_FILTER" | cut -c1)" = "~" ]; then
+ # Range mode: ~N means last N days to today
+ DAYS=$(printf '%s' "$DATE_FILTER" | sed 's/^~//')
+ if [ -n "$DAYS" ] && [ "$DAYS" -gt 0 ] 2>/dev/null; then
+ START_DATE=$(date -d "$DAYS days ago" +%d/%b/%Y 2>/dev/null || date -v-${DAYS}d +%d/%b/%Y 2>/dev/null || echo "")
+ [ -z "$START_DATE" ] && START_DATE=""
+ fi
+ else
+ # Single date mode: N means N days ago only
+ DAYS="$DATE_FILTER"
+ if [ -n "$DAYS" ] && [ "$DAYS" -ge 0 ] 2>/dev/null; then
+ TARGET_DATE=$(date -d "$DAYS days ago" +%d/%b/%Y 2>/dev/null || date -v-${DAYS}d +%d/%b/%Y 2>/dev/null || echo "")
+ [ -z "$TARGET_DATE" ] && TARGET_DATE=""
+ fi
+ fi
+ fi
+
+ awk -v date_filter="${DATE_FILTER:-}" -v target_date="${TARGET_DATE:-}" -v start_date="${START_DATE:-}" "
+ function parse_date(date_str, parts, month_num) {
+ # date_str format: \"DD/MMM/YYYY\"
+ split(date_str, parts, \"/\")
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, parts[2])
+ month_num = (month_num + 2) / 3 # Convert to 1-12
+ # Return YYYYMMDD for easy comparison
+ return sprintf(\"%04d%02d%02d\", parts[3], month_num, parts[1])
+ }
+
+ BEGIN {
+ today = strftime(\"%Y%m%d\")
+ filter_target = \"\"
+ date_range_start = \"\"
+ date_range_end = \"\"
+
+ if (date_filter != \"\" && date_filter ~ /^~/) {
+ # Range mode: extract days
+ if (start_date != \"\" && split(start_date, sd_parts, \"/\") == 3) {
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, sd_parts[2])
+ if (month_num > 0) {
+ month_num = (month_num + 2) / 3
+ start_date_num = sprintf(\"%04d%02d%02d\", sd_parts[3], month_num, sd_parts[1])
+ date_range_start = start_date_num
+ date_range_end = today
+ }
+ }
+ } else if (date_filter != \"\" && target_date != \"\") {
+ # Single date mode
+ if (split(target_date, td_parts, \"/\") == 3) {
+ month_names = \"JanFebMarAprMayJunJulAugSepOctNovDec\"
+ month_num = index(month_names, td_parts[2])
+ if (month_num > 0) {
+ month_num = (month_num + 2) / 3
+ target_date_num = sprintf(\"%04d%02d%02d\", td_parts[3], month_num, td_parts[1])
+ filter_target = target_date_num
+ }
+ }
+ }
+ }
+ {
+ line = \$0
+
+ # Extract datetime [DD/MMM/YYYY:HH:MM:SS
+ datetime = \"\"
+ minute_part = \"\"
+ pos = match(line, /\\[[0-9]{2}\\/[A-Z][a-z]{2}\\/[0-9]{4}:[0-9]{2}:[0-9]{2}:[0-9]{2}/)
+ if (pos > 0) {
+ datetime = substr(line, pos + 1, 20)
+ date_part = substr(datetime, 1, 11) # DD/MMM/YYYY
+ minute_part = substr(datetime, 1, 17) # DD/MMM/YYYY:HH:MM
+
+ # Date filtering
+ if (filter_target != \"\" || date_range_start != \"\") {
+ line_date_num = parse_date(date_part)
+ if (filter_target != \"\" && line_date_num != filter_target) {
+ next # Skip if not matching target date
+ }
+ if (date_range_start != \"\" && (line_date_num < date_range_start || line_date_num > date_range_end)) {
+ next # Skip if outside date range
+ }
+ }
+ }
+
+ # Extract IP (first field before \" - \")
+ ip = \"\"
+ pos = match(line, /^[0-9a-fA-F:.]+/)
+ if (pos > 0) {
+ ip = substr(line, pos, RLENGTH)
+ }
+
+ # Extract URI (between quotes after method)
+ uri = \"\"
+ # Find the quoted request part: \"METHOD URI PROTOCOL\"
+ # Use split on quotes to find the request section
+ split(line, parts, \"\\\"\")
+ if (length(parts) >= 2) {
+ # parts[2] should be \"METHOD URI PROTOCOL\"
+ n = split(parts[2], req_parts, \" \")
+ if (n >= 2) {
+ uri = req_parts[2]
+ }
+ }
+
+ # Create key: IP + minute + URI
+ key = ip \"|\" minute_part \"|\" uri
+
+ # Store latest line for each key (compare by full line for latest)
+ if (!(key in latest) || line > latest[key]) {
+ latest[key] = line
+ timestamp[key] = datetime
+ }
+ }
+ END {
+ # Output: simple approach - print all unique entries
+ # Since we want chronological order, we need to sort by timestamp
+ # For simplicity, just print the unique entries
+ for (key in latest) {
+ print latest[key]
+ }
+ }
+ " "$RESULTS_TMP" | sort
+ found=1
+fi
+
+rm -f "$FILES_TMP" "$RESULTS_TMP"
if [ "$TARGET" != "all" ] && [ "$found" -eq 0 ]; then
echo "[INFO] No matches found (or filtered out)." >&2