mirror of
https://github.com/nmasur/dotfiles
synced 2026-02-14 21:39:46 +00:00
Compare commits
7 Commits
10eecfa136
...
be6d6b0d35
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
be6d6b0d35 | ||
|
|
0239a9925c | ||
|
|
49e35403b6 | ||
|
|
430b522c61 | ||
|
|
a64488093c | ||
|
|
54d2376437 | ||
|
|
cd0a5d5de0 |
5
overlays/firefox.nix
Normal file
5
overlays/firefox.nix
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
inputs: final: prev: {
|
||||||
|
|
||||||
|
firefox-unwrapped = final.stable.firefox-unwrapped;
|
||||||
|
|
||||||
|
}
|
||||||
41
pkgs/firefox-history-exporter/background.js
Normal file
41
pkgs/firefox-history-exporter/background.js
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
|
||||||
|
function exportHistory() {
|
||||||
|
const now = new Date();
|
||||||
|
const startTime = new Date(now.getFullYear(), now.getMonth(), now.getDate(), 0, 0, 0, 0); // Beginning of today
|
||||||
|
|
||||||
|
browser.history.search({
|
||||||
|
text: '',
|
||||||
|
startTime: startTime,
|
||||||
|
endTime: now,
|
||||||
|
maxResults: 10000
|
||||||
|
}).then(historyItems => {
|
||||||
|
const historyData = JSON.stringify(historyItems, null, 2);
|
||||||
|
const blob = new Blob([historyData], {type: 'application/json'});
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const date = now.toISOString().slice(0, 10); // YYYY-MM-DD
|
||||||
|
const filename = `firefox-history/history-${date}.json`;
|
||||||
|
|
||||||
|
browser.downloads.download({
|
||||||
|
url: url,
|
||||||
|
filename: filename,
|
||||||
|
conflictAction: 'overwrite',
|
||||||
|
saveAs: false
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
browser.alarms.create('daily-export', {
|
||||||
|
periodInMinutes: 60 // every 1 hour
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.alarms.onAlarm.addListener(alarm => {
|
||||||
|
if (alarm.name === 'daily-export') {
|
||||||
|
exportHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
browser.runtime.onMessage.addListener((message, sender, sendResponse) => {
|
||||||
|
if (message.command === "exportHistory") {
|
||||||
|
exportHistory();
|
||||||
|
}
|
||||||
|
});
|
||||||
25
pkgs/firefox-history-exporter/manifest.json
Normal file
25
pkgs/firefox-history-exporter/manifest.json
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"manifest_version": 3,
|
||||||
|
"name": "History Exporter",
|
||||||
|
"version": "1.0",
|
||||||
|
"description": "Automatically exports today's browsing history.",
|
||||||
|
"permissions": [
|
||||||
|
"history",
|
||||||
|
"downloads",
|
||||||
|
"alarms"
|
||||||
|
],
|
||||||
|
"background": {
|
||||||
|
"scripts": ["background.js"]
|
||||||
|
},
|
||||||
|
"action": {
|
||||||
|
"default_popup": "popup.html"
|
||||||
|
},
|
||||||
|
"browser_specific_settings": {
|
||||||
|
"gecko": {
|
||||||
|
"id": "firefox-history-exporter@nmasur.com",
|
||||||
|
"data_collection_permissions": {
|
||||||
|
"required": ["none"]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
26
pkgs/firefox-history-exporter/package.nix
Normal file
26
pkgs/firefox-history-exporter/package.nix
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
{ pkgs, ... }:
|
||||||
|
|
||||||
|
pkgs.stdenv.mkDerivation rec {
|
||||||
|
pname = "firefox-history-exporter";
|
||||||
|
version = "1.0";
|
||||||
|
src = ./.;
|
||||||
|
|
||||||
|
nativeBuildInputs = [ pkgs.zip ];
|
||||||
|
|
||||||
|
dontUnpack = true;
|
||||||
|
|
||||||
|
installPhase = ''
|
||||||
|
dst="$out/share/mozilla/extensions/{ec8030f7-c20a-464f-9b0e-13a3a9e97384}"
|
||||||
|
mkdir -p "$dst"
|
||||||
|
zip -j "$dst/firefox-history-exporter@nmasur.com.xpi" \
|
||||||
|
"${src}/manifest.json" \
|
||||||
|
"${src}/background.js" \
|
||||||
|
"${src}/popup.html" \
|
||||||
|
"${src}/popup.js"
|
||||||
|
'';
|
||||||
|
|
||||||
|
meta = with pkgs.lib; {
|
||||||
|
description = "Automatically exports today's browsing history.";
|
||||||
|
license = licenses.mit;
|
||||||
|
};
|
||||||
|
}
|
||||||
25
pkgs/firefox-history-exporter/popup.html
Normal file
25
pkgs/firefox-history-exporter/popup.html
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>History Exporter</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
width: 200px;
|
||||||
|
text-align: center;
|
||||||
|
font-family: sans-serif;
|
||||||
|
}
|
||||||
|
button {
|
||||||
|
margin-top: 10px;
|
||||||
|
padding: 10px;
|
||||||
|
font-size: 16px;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>History Exporter</h1>
|
||||||
|
<button id="export-button">Export Now</button>
|
||||||
|
<p id="status"></p>
|
||||||
|
<script src="popup.js"></script>
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
9
pkgs/firefox-history-exporter/popup.js
Normal file
9
pkgs/firefox-history-exporter/popup.js
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
document.getElementById('export-button').addEventListener('click', () => {
|
||||||
|
browser.runtime.sendMessage({command: "exportHistory"});
|
||||||
|
|
||||||
|
const statusElement = document.getElementById('status');
|
||||||
|
statusElement.textContent = 'Exporting...';
|
||||||
|
setTimeout(() => {
|
||||||
|
statusElement.textContent = 'Export complete!';
|
||||||
|
}, 2000);
|
||||||
|
});
|
||||||
@@ -46,6 +46,8 @@ in
|
|||||||
ublacklist
|
ublacklist
|
||||||
vimium
|
vimium
|
||||||
wappalyzer # TODO: only for work profile
|
wappalyzer # TODO: only for work profile
|
||||||
|
pkgs.nmasur.firefox-history-exporter
|
||||||
|
# copy-as-markdown
|
||||||
# saml-tracer
|
# saml-tracer
|
||||||
# text-fragment
|
# text-fragment
|
||||||
];
|
];
|
||||||
@@ -61,6 +63,7 @@ in
|
|||||||
"trailhead.firstrun.didSeeAboutWelcome" = true; # Disable welcome splash
|
"trailhead.firstrun.didSeeAboutWelcome" = true; # Disable welcome splash
|
||||||
"dom.forms.autocomplete.formautofill" = false; # Disable autofill
|
"dom.forms.autocomplete.formautofill" = false; # Disable autofill
|
||||||
"extensions.formautofill.creditCards.enabled" = false; # Disable credit cards
|
"extensions.formautofill.creditCards.enabled" = false; # Disable credit cards
|
||||||
|
"extensions.autoDisableScopes" = false; # Enable extensions automatically
|
||||||
"dom.payments.defaults.saveAddress" = false; # Disable address save
|
"dom.payments.defaults.saveAddress" = false; # Disable address save
|
||||||
"general.autoScroll" = true; # Drag middle-mouse to scroll
|
"general.autoScroll" = true; # Drag middle-mouse to scroll
|
||||||
"services.sync.prefs.sync.general.autoScroll" = false; # Prevent disabling autoscroll
|
"services.sync.prefs.sync.general.autoScroll" = false; # Prevent disabling autoscroll
|
||||||
@@ -187,7 +190,7 @@ in
|
|||||||
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.isLinux {
|
xsession.windowManager.i3.config.keybindings = lib.mkIf pkgs.stdenv.isLinux {
|
||||||
"${config.xsession.windowManager.i3.config.modifier}+Shift+b" = "exec ${
|
"${config.xsession.windowManager.i3.config.modifier}+Shift+b" = "exec ${
|
||||||
# Don't name the script `firefox` or it will affect grep
|
# Don't name the script `firefox` or it will affect grep
|
||||||
builtins.toString (
|
toString (
|
||||||
pkgs.writeShellScript "focus-ff.sh" ''
|
pkgs.writeShellScript "focus-ff.sh" ''
|
||||||
count=$(ps aux | grep -c firefox)
|
count=$(ps aux | grep -c firefox)
|
||||||
if [ "$count" -eq 1 ]; then
|
if [ "$count" -eq 1 ]; then
|
||||||
|
|||||||
@@ -22,7 +22,6 @@ in
|
|||||||
extensions = [
|
extensions = [
|
||||||
pkgs.nmasur.gh-collaborators
|
pkgs.nmasur.gh-collaborators
|
||||||
pkgs.gh-dash
|
pkgs.gh-dash
|
||||||
pkgs.gh-copilot
|
|
||||||
];
|
];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -347,7 +347,7 @@ in
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
themes."${config.programs.helix.settings.theme}" = {
|
themes.base16 = {
|
||||||
"attributes" = config.theme.colors.base09;
|
"attributes" = config.theme.colors.base09;
|
||||||
"comment" = {
|
"comment" = {
|
||||||
fg = config.theme.colors.base03;
|
fg = config.theme.colors.base03;
|
||||||
@@ -527,6 +527,197 @@ in
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
themes.alabaster-style = {
|
||||||
|
"attribute" = config.theme.colors.base05;
|
||||||
|
"comment" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
# modifiers = [ "italic" ];
|
||||||
|
};
|
||||||
|
"constant" = config.theme.colors.base0E;
|
||||||
|
"constant.numeric" = config.theme.colors.base0E;
|
||||||
|
"constant.builtin" = config.theme.colors.base0E;
|
||||||
|
"constant.character" = config.theme.colors.base0E;
|
||||||
|
"constant.character.escape" = config.theme.colors.base0C;
|
||||||
|
"constructor" = config.theme.colors.base0D;
|
||||||
|
"debug" = config.theme.colors.base03;
|
||||||
|
"diagnostic" = {
|
||||||
|
modifiers = [ "underlined" ];
|
||||||
|
};
|
||||||
|
"diff.delta" = config.theme.colors.base09;
|
||||||
|
"diff.minus" = config.theme.colors.base08;
|
||||||
|
"diff.plus" = config.theme.colors.base0B;
|
||||||
|
"error" = config.theme.colors.base08;
|
||||||
|
"function" = config.theme.colors.base0D;
|
||||||
|
"hint" = config.theme.colors.base03;
|
||||||
|
"info" = config.theme.colors.base0D;
|
||||||
|
"keyword" = config.theme.colors.base05;
|
||||||
|
"keyword.control" = config.theme.colors.base05;
|
||||||
|
"keyword.operator" = config.theme.colors.base05;
|
||||||
|
"label" = config.theme.colors.base0E;
|
||||||
|
"namespace" = config.theme.colors.base0E;
|
||||||
|
"operator" = config.theme.colors.base05;
|
||||||
|
"punctuation" = config.theme.colors.base04;
|
||||||
|
"punctuation.bracket" = config.theme.colors.base04;
|
||||||
|
"punctuation.delimiter" = config.theme.colors.base04;
|
||||||
|
"special" = config.theme.colors.base0D;
|
||||||
|
"string" = config.theme.colors.base0B;
|
||||||
|
"string.regexp" = config.theme.colors.base0B;
|
||||||
|
"string.special" = config.theme.colors.base0C;
|
||||||
|
"type" = config.theme.colors.base0A;
|
||||||
|
"variable" = config.theme.colors.base05;
|
||||||
|
"variable.parameter" = config.theme.colors.base05;
|
||||||
|
"variable.builtin" = config.theme.colors.base05;
|
||||||
|
"variable.other.member" = config.theme.colors.base05;
|
||||||
|
"warning" = config.theme.colors.base09;
|
||||||
|
"markup.bold" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"markup.heading" = config.theme.colors.base0D;
|
||||||
|
"markup.italic" = {
|
||||||
|
fg = config.theme.colors.base0E;
|
||||||
|
modifiers = [ "italic" ];
|
||||||
|
};
|
||||||
|
"markup.link.text" = config.theme.colors.base08;
|
||||||
|
"markup.link.url" = {
|
||||||
|
fg = config.theme.colors.base09;
|
||||||
|
modifiers = [ "underlined" ];
|
||||||
|
};
|
||||||
|
"markup.list" = config.theme.colors.base08;
|
||||||
|
"markup.quote" = config.theme.colors.base0C;
|
||||||
|
"markup.raw" = config.theme.colors.base0B;
|
||||||
|
"markup.strikethrough" = {
|
||||||
|
modifiers = [ "crossed_out" ];
|
||||||
|
};
|
||||||
|
"diagnostic.hint" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.info" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.warning" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"diagnostic.error" = {
|
||||||
|
underline = {
|
||||||
|
style = "curl";
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"ui.background" = {
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.bufferline.active" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base03;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.bufferline" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.cursor" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursor.insert" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursorline.primary" = {
|
||||||
|
fg = config.theme.colors.base05;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.cursor.match" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.cursor.select" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
modifiers = [ "reversed" ];
|
||||||
|
};
|
||||||
|
"ui.gutter" = {
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.help" = {
|
||||||
|
fg = config.theme.colors.base06;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.linenr" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
bg = config.theme.colors.base00;
|
||||||
|
};
|
||||||
|
"ui.linenr.selected" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.menu" = {
|
||||||
|
fg = config.theme.colors.base05;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.menu.scroll" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.menu.selected" = {
|
||||||
|
fg = config.theme.colors.base01;
|
||||||
|
bg = config.theme.colors.base04;
|
||||||
|
};
|
||||||
|
"ui.popup" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.selection" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.selection.primary" = {
|
||||||
|
bg = config.theme.colors.base02;
|
||||||
|
};
|
||||||
|
"ui.statusline" = {
|
||||||
|
fg = config.theme.colors.base04;
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.statusline.inactive" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.statusline.insert" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base0B;
|
||||||
|
};
|
||||||
|
"ui.statusline.normal" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.statusline.select" = {
|
||||||
|
fg = config.theme.colors.base00;
|
||||||
|
bg = config.theme.colors.base0F;
|
||||||
|
};
|
||||||
|
"ui.text" = config.theme.colors.base05;
|
||||||
|
"ui.text.focus" = config.theme.colors.base05;
|
||||||
|
"ui.virtual.indent-guide" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.virtual.inlay-hint" = {
|
||||||
|
fg = config.theme.colors.base03;
|
||||||
|
};
|
||||||
|
"ui.virtual.ruler" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
"ui.virtual.jump-label" = {
|
||||||
|
fg = config.theme.colors.base0A;
|
||||||
|
modifiers = [ "bold" ];
|
||||||
|
};
|
||||||
|
"ui.window" = {
|
||||||
|
bg = config.theme.colors.base01;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
# Create a desktop option for launching Helix from a file manager
|
# Create a desktop option for launching Helix from a file manager
|
||||||
|
|||||||
@@ -128,7 +128,7 @@ in
|
|||||||
if pkgs.stdenv.isDarwin then
|
if pkgs.stdenv.isDarwin then
|
||||||
[
|
[
|
||||||
"env"
|
"env"
|
||||||
"PATH=${config.home.homeDirectory}/.nix-profile/bin:/usr/bin:/bin"
|
"PATH=/nix/var/nix/profiles/default/bin:/run/current-system/sw/bin:/usr/bin:/bin"
|
||||||
(lib.getExe zellij-switch-to-last)
|
(lib.getExe zellij-switch-to-last)
|
||||||
]
|
]
|
||||||
else
|
else
|
||||||
@@ -271,6 +271,16 @@ in
|
|||||||
_args = [ "Left" ];
|
_args = [ "Left" ];
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
"bind \"Alt j\"" = {
|
||||||
|
MoveFocus = {
|
||||||
|
_args = [ "Down" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
|
"bind \"Alt k\"" = {
|
||||||
|
MoveFocus = {
|
||||||
|
_args = [ "Up" ];
|
||||||
|
};
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -0,0 +1,70 @@
|
|||||||
|
{
|
||||||
|
config,
|
||||||
|
pkgs,
|
||||||
|
lib,
|
||||||
|
...
|
||||||
|
}:
|
||||||
|
|
||||||
|
let
|
||||||
|
inherit (config.nmasur.settings) username;
|
||||||
|
cfg = config.nmasur.presets.services.daily-summary;
|
||||||
|
|
||||||
|
# Remove process urls in favor of using extention
|
||||||
|
# process_urls = pkgs.writers.writePython3Bin "process-urls" {
|
||||||
|
# libraries = [
|
||||||
|
# pkgs.python3Packages.requests
|
||||||
|
# pkgs.python3Packages.beautifulsoup4
|
||||||
|
# ];
|
||||||
|
# } (builtins.readFile ./process-urls.py);
|
||||||
|
# prompt = "Based on my browser usage for today from the markdown file located in /Users/${username}/Downloads/Sidebery/todays_urls.md, create or update a daily summary markdown file in the generated notes directory located in /Users/${username}/dev/personal/notes/generated/ with the filename format 'YYYY-MM-DD Daily Summary.md'. The resulting markdown file should use /Users/${username}/dev/personal/notes/templates/generated-summary.md as a format template, and it should summarize where I have spent my time today and highlight any notable links that I have visited. Please create markdown links to other relevant notes in /Users/${username}/dev/personal/notes/. If there is an existing markdown file for today, update it to include the newest information.";
|
||||||
|
prompt = "Based on my browser usage for today from the JSON file located in /Users/${username}/Downloads/firefox-history/history-YYYY-MM-DD.json, create or update a daily summary markdown file in the generated notes directory located in /Users/${username}/dev/personal/notes/generated/ with the filename format 'YYYY-MM-DD Daily Summary.md'. The resulting markdown file should use /Users/${username}/dev/personal/notes/templates/generated-summary.md as a format template, and it should summarize where I have spent my time today and highlight any notable pages that I have visited, using the titles of each URL in the JSON file for markdown links. Please create markdown links to other relevant notes in /Users/${username}/dev/personal/notes/ and explain why they are being referenced. If there is an existing markdown file for today, update it to include the newest information.";
|
||||||
|
in
|
||||||
|
|
||||||
|
{
|
||||||
|
|
||||||
|
options.nmasur.presets.services.daily-summary.enable = lib.mkEnableOption "Daily work summary";
|
||||||
|
|
||||||
|
config = lib.mkIf cfg.enable {
|
||||||
|
launchd.user.agents.daily-summary = {
|
||||||
|
# This replaces program and args entirely
|
||||||
|
# script = ''
|
||||||
|
# ${process_urls}/bin/process-urls /Users/${username}/Downloads/Sidebery/
|
||||||
|
# GEMINI_API_KEY=$(cat /Users/${username}/.config/gemini/.gemini_api_key) ${pkgs.gemini-cli}/bin/gemini --allowed-tools all --yolo --include-directories /Users/${username}/Downloads/Sidebery/ --include-directories /Users/${username}/dev/personal/notes/ "${prompt}"
|
||||||
|
# '';
|
||||||
|
script = ''
|
||||||
|
GEMINI_API_KEY=$(cat /Users/${username}/.config/gemini/.gemini_api_key) ${pkgs.gemini-cli}/bin/gemini --allowed-tools all --yolo --include-directories /Users/${username}/Downloads/firefox-history/ --include-directories /Users/${username}/dev/personal/notes/ "${prompt}"
|
||||||
|
'';
|
||||||
|
|
||||||
|
path = [
|
||||||
|
pkgs.bash
|
||||||
|
pkgs.coreutils
|
||||||
|
];
|
||||||
|
|
||||||
|
serviceConfig = {
|
||||||
|
Label = "com.example.daily-summary";
|
||||||
|
# Runs the script through /bin/sh automatically
|
||||||
|
# RunAtLoad = true;
|
||||||
|
StartCalendarInterval = [
|
||||||
|
{
|
||||||
|
Hour = 4;
|
||||||
|
Minute = 45;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Hour = 6;
|
||||||
|
Minute = 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Hour = 9;
|
||||||
|
Minute = 0;
|
||||||
|
}
|
||||||
|
{
|
||||||
|
Hour = 11;
|
||||||
|
Minute = 0;
|
||||||
|
}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,115 @@
|
|||||||
|
# Temporarily disabled in favor of using an extension to save history
|
||||||
|
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from bs4 import BeautifulSoup
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import sys
|
||||||
|
from datetime import datetime
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
|
||||||
|
def find_urls(data):
|
||||||
|
urls = []
|
||||||
|
if isinstance(data, dict):
|
||||||
|
for key, value in data.items():
|
||||||
|
if key == 'url' and isinstance(value, str):
|
||||||
|
urls.append(value)
|
||||||
|
else:
|
||||||
|
urls.extend(find_urls(value))
|
||||||
|
elif isinstance(data, list):
|
||||||
|
for item in data:
|
||||||
|
urls.extend(find_urls(item))
|
||||||
|
return urls
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
if len(sys.argv) > 1:
|
||||||
|
base_dir = sys.argv[1]
|
||||||
|
if not os.path.isdir(base_dir):
|
||||||
|
print(f"Error: Directory '{base_dir}' not found.")
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
base_dir = '.'
|
||||||
|
|
||||||
|
today = datetime.now().strftime('%Y.%m.%d')
|
||||||
|
output_filename = 'todays_urls.md'
|
||||||
|
output_filepath = os.path.join(base_dir, output_filename)
|
||||||
|
url_titles = {}
|
||||||
|
|
||||||
|
print(f"Searching for files in '{base_dir}' "
|
||||||
|
f"starting with 'snapshot-{today}-'")
|
||||||
|
|
||||||
|
with open(output_filepath, 'w') as md_file:
|
||||||
|
md_file.write(f'# URLs from Sidebery Snapshots for '
|
||||||
|
f'{today.replace(".", "-")}\n\n')
|
||||||
|
|
||||||
|
files_processed = 0
|
||||||
|
for filename in sorted(os.listdir(base_dir)):
|
||||||
|
# Debugging print removed
|
||||||
|
if (filename.startswith(f'snapshot-{today}-')
|
||||||
|
and filename.endswith('.json')):
|
||||||
|
files_processed += 1
|
||||||
|
print(f"Processing file: "
|
||||||
|
f"{os.path.join(base_dir, filename)}")
|
||||||
|
|
||||||
|
# Extract and format date and time from filename
|
||||||
|
# Example: snapshot-2026.01.25-13.19.29.json
|
||||||
|
clean_filename = (filename.replace('snapshot-', '')
|
||||||
|
.replace('.json', ''))
|
||||||
|
date_time_parts = clean_filename.split('-', 1)
|
||||||
|
|
||||||
|
formatted_date = date_time_parts[0].replace('.', '-')
|
||||||
|
formatted_time = date_time_parts[1].replace('.', ':')
|
||||||
|
|
||||||
|
datetime_str = f"{formatted_date} {formatted_time}"
|
||||||
|
|
||||||
|
md_file.write(f'## {datetime_str}\n\n')
|
||||||
|
|
||||||
|
with open(os.path.join(base_dir, filename), 'r') as json_file:
|
||||||
|
try:
|
||||||
|
data = json.load(json_file)
|
||||||
|
urls = find_urls(data)
|
||||||
|
print(f" Found {len(urls)} URLs")
|
||||||
|
for url in urls:
|
||||||
|
if url not in url_titles:
|
||||||
|
try:
|
||||||
|
# Get title of URL
|
||||||
|
res = requests.get(
|
||||||
|
url,
|
||||||
|
timeout=10,
|
||||||
|
allow_redirects=True
|
||||||
|
)
|
||||||
|
soup = BeautifulSoup(
|
||||||
|
res.text,
|
||||||
|
'html.parser'
|
||||||
|
)
|
||||||
|
if soup.title and soup.title.string:
|
||||||
|
title = soup.title.string.strip()
|
||||||
|
else:
|
||||||
|
domain = urlparse(url).netloc
|
||||||
|
title = domain if domain else url
|
||||||
|
url_titles[url] = title
|
||||||
|
except requests.exceptions.InvalidSchema:
|
||||||
|
continue
|
||||||
|
except Exception:
|
||||||
|
domain = urlparse(url).netloc
|
||||||
|
title = domain if domain else url
|
||||||
|
url_titles[url] = title
|
||||||
|
if url in url_titles:
|
||||||
|
title = url_titles[url]
|
||||||
|
md_file.write(f'- [{title}]({url})\n')
|
||||||
|
md_file.write('\n')
|
||||||
|
except json.JSONDecodeError:
|
||||||
|
print(f" Error decoding JSON in {filename}")
|
||||||
|
md_file.write('- Error decoding JSON\n\n')
|
||||||
|
|
||||||
|
if files_processed == 0:
|
||||||
|
print("No files found for today.")
|
||||||
|
|
||||||
|
print(f"Processing complete. Output written to {output_filepath}")
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
@@ -22,6 +22,7 @@ in
|
|||||||
homebrew.enable = lib.mkDefault true;
|
homebrew.enable = lib.mkDefault true;
|
||||||
};
|
};
|
||||||
services = {
|
services = {
|
||||||
|
daily-summary.enable = lib.mkDefault true;
|
||||||
dock.enable = lib.mkDefault true;
|
dock.enable = lib.mkDefault true;
|
||||||
finder.enable = lib.mkDefault true;
|
finder.enable = lib.mkDefault true;
|
||||||
hammerspoon.enable = lib.mkDefault true;
|
hammerspoon.enable = lib.mkDefault true;
|
||||||
|
|||||||
Reference in New Issue
Block a user