rm old
This commit is contained in:
@@ -1,57 +0,0 @@
|
|||||||
# https://github.com/NixOS/nixpkgs/issues/126590#issuecomment-3194531220
|
|
||||||
{
|
|
||||||
config,
|
|
||||||
pkgs,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
nixpkgs.overlays = lib.singleton (final: prev: {
|
|
||||||
kdePackages =
|
|
||||||
prev.kdePackages
|
|
||||||
// {
|
|
||||||
plasma-workspace = let
|
|
||||||
# the package we want to override
|
|
||||||
basePkg = prev.kdePackages.plasma-workspace;
|
|
||||||
|
|
||||||
# a helper package that merges all the XDG_DATA_DIRS into a single directory
|
|
||||||
xdgdataPkg = pkgs.stdenv.mkDerivation {
|
|
||||||
name = "${basePkg.name}-xdgdata";
|
|
||||||
buildInputs = [basePkg];
|
|
||||||
dontUnpack = true;
|
|
||||||
dontFixup = true;
|
|
||||||
dontWrapQtApps = true;
|
|
||||||
installPhase = ''
|
|
||||||
mkdir -p $out/share
|
|
||||||
( IFS=:
|
|
||||||
for DIR in $XDG_DATA_DIRS; do
|
|
||||||
if [[ -d "$DIR" ]]; then
|
|
||||||
cp -r $DIR/. $out/share/
|
|
||||||
chmod -R u+w $out/share
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
)
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
|
|
||||||
# undo the XDG_DATA_DIRS injection that is usually done in the qt wrapper
|
|
||||||
# script and instead inject the path of the above helper package
|
|
||||||
derivedPkg = basePkg.overrideAttrs {
|
|
||||||
preFixup = ''
|
|
||||||
for index in "''${!qtWrapperArgs[@]}"; do
|
|
||||||
if [[ ''${qtWrapperArgs[$((index+0))]} == "--prefix" ]] && [[ ''${qtWrapperArgs[$((index+1))]} == "XDG_DATA_DIRS" ]]; then
|
|
||||||
unset -v "qtWrapperArgs[$((index+0))]"
|
|
||||||
unset -v "qtWrapperArgs[$((index+1))]"
|
|
||||||
unset -v "qtWrapperArgs[$((index+2))]"
|
|
||||||
unset -v "qtWrapperArgs[$((index+3))]"
|
|
||||||
fi
|
|
||||||
done
|
|
||||||
qtWrapperArgs=("''${qtWrapperArgs[@]}")
|
|
||||||
qtWrapperArgs+=(--prefix XDG_DATA_DIRS : "${xdgdataPkg}/share")
|
|
||||||
qtWrapperArgs+=(--prefix XDG_DATA_DIRS : "$out/share")
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
in
|
|
||||||
derivedPkg;
|
|
||||||
};
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@@ -1,51 +0,0 @@
|
|||||||
{lib, ...}: {
|
|
||||||
# Home Manager needs a bit of information about you and the paths it should
|
|
||||||
# manage.
|
|
||||||
home.username = "admin-jroeger";
|
|
||||||
home.homeDirectory = "/home/admin-jroeger";
|
|
||||||
|
|
||||||
# hive modules
|
|
||||||
hive.kitty.enable = true;
|
|
||||||
hive.ranger.enable = true;
|
|
||||||
hive.yubikey.enable = true;
|
|
||||||
hive.yubikey.pinentry = "gnome3";
|
|
||||||
hive.nix-scripts.enable = true;
|
|
||||||
hive.zsh.enable = true;
|
|
||||||
hive.doom.enable = true;
|
|
||||||
hive.doom.asDefaultEditor = true;
|
|
||||||
hive.doom.enableCopilot = true;
|
|
||||||
hive.doom.withNixPkgs = true;
|
|
||||||
hive.doom.withShellPkgs = true;
|
|
||||||
hive.doom.withCXXPkgs = true;
|
|
||||||
hive.doom.withPythonPkgs = true;
|
|
||||||
hive.jj.enable = true;
|
|
||||||
|
|
||||||
# This value determines the Home Manager release that your configuration is
|
|
||||||
# compatible with. This helps avoid breakage when a new Home Manager release
|
|
||||||
# introduces backwards incompatible changes.
|
|
||||||
#
|
|
||||||
# You should not change this value, even if you update Home Manager. If you do
|
|
||||||
# want to update the value, then make sure to first check the Home Manager
|
|
||||||
# release notes.
|
|
||||||
home.stateVersion = "24.11"; # Please read the comment before changing.
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
EDITOR = lib.mkDefault "vim";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Let Home Manager install and manage itself.
|
|
||||||
programs.home-manager.enable = true;
|
|
||||||
|
|
||||||
# Git
|
|
||||||
programs.difftastic.enable = true;
|
|
||||||
programs.difftastic.git.enable = true;
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
settings.user.name = "Jonas Röger";
|
|
||||||
settings.user.email = "jonas.kieran.roeger@iml.fraunhofer.de";
|
|
||||||
signing = {
|
|
||||||
signByDefault = true;
|
|
||||||
key = "4000EB35E1AE0F07";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
imports = [
|
|
||||||
(./. + "/jonas@comfy-station/" + /borg.nix)
|
|
||||||
];
|
|
||||||
|
|
||||||
# Home Manager needs a bit of information about you and the paths it should
|
|
||||||
# manage.
|
|
||||||
home.username = "jonas";
|
|
||||||
home.homeDirectory = "/home/jonas";
|
|
||||||
|
|
||||||
sops = {
|
|
||||||
age.keyFile = "${config.home.homeDirectory}/.config/sops/age/keys.txt";
|
|
||||||
};
|
|
||||||
|
|
||||||
# hive modules
|
|
||||||
hive.themes.layan.enable = true;
|
|
||||||
hive.themes.layan.pkgsInHome = true;
|
|
||||||
hive.hyprland.enable = true;
|
|
||||||
hive.swaync.enable = true;
|
|
||||||
hive.waybar.enable = true;
|
|
||||||
hive.wlogout.enable = true;
|
|
||||||
hive.wofi.enable = true;
|
|
||||||
hive.kitty.enable = true;
|
|
||||||
hive.nextcloud.enable = true;
|
|
||||||
hive.firefox = {
|
|
||||||
enable = true;
|
|
||||||
plasmaIntegration = true;
|
|
||||||
passFF = true;
|
|
||||||
};
|
|
||||||
hive.kdeconnect.enable = true;
|
|
||||||
hive.ranger.enable = true;
|
|
||||||
hive.ssh = {
|
|
||||||
enable = true;
|
|
||||||
sopsFile = ../secrets/jonas/ssh.yaml;
|
|
||||||
keys = ["borg" "passgit"];
|
|
||||||
};
|
|
||||||
hive.yubikey.enable = true;
|
|
||||||
hive.yubikey.withCCID = false;
|
|
||||||
hive.zsh.enable = true;
|
|
||||||
hive.nix-scripts.enable = true;
|
|
||||||
hive.doom.enable = true;
|
|
||||||
hive.doom.asDefaultEditor = true;
|
|
||||||
hive.doom.enableCopilot = true;
|
|
||||||
hive.doom.withNixPkgs = true;
|
|
||||||
hive.doom.withShellPkgs = true;
|
|
||||||
hive.doom.withPythonPkgs = true;
|
|
||||||
hive.jj.enable = true;
|
|
||||||
|
|
||||||
# Make session variables available in systemd units
|
|
||||||
# SEE: https://github.com/nix-community/home-manager/pull/5543
|
|
||||||
# systemd.user.settings.Manager.DefaultEnvironment =
|
|
||||||
# lib.mapAttrs (_: lib.mkDefault) config.home.sessionVariables;
|
|
||||||
|
|
||||||
xdg.mimeApps = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
defaultApplications = {
|
|
||||||
"text/html" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/http" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/https" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/about" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/unknown" = "firefox.desktop";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
xdg.userDirs.enable = true;
|
|
||||||
xdg.userDirs.createDirectories = true;
|
|
||||||
xdg.userDirs.extraConfig = {
|
|
||||||
XDG_WORKSPACES_DIR = "${config.home.homeDirectory}/Workspaces";
|
|
||||||
XDG_NEXTCLOUD_DIR = "${config.home.homeDirectory}/Nextcloud";
|
|
||||||
XDG_NOTES_DIR = "${config.home.homeDirectory}/Notes";
|
|
||||||
};
|
|
||||||
|
|
||||||
# This value determines the Home Manager release that your configuration is
|
|
||||||
# compatible with. This helps avoid breakage when a new Home Manager release
|
|
||||||
# introduces backwards incompatible changes.
|
|
||||||
#
|
|
||||||
# You should not change this value, even if you update Home Manager. If you do
|
|
||||||
# want to update the value, then make sure to first check the Home Manager
|
|
||||||
# release notes.
|
|
||||||
home.stateVersion = "24.11"; # Please read the comment before changing.
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
EDITOR = lib.mkDefault "vim";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Let Home Manager install and manage itself.
|
|
||||||
programs.home-manager.enable = true;
|
|
||||||
|
|
||||||
# Git
|
|
||||||
programs.difftastic.enable = true;
|
|
||||||
programs.difftastic.git.enable = true;
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
settings.user.name = "Jonas Röger";
|
|
||||||
settings.user.email = "jonas.roeger@tu-dortmund.de";
|
|
||||||
signing = {
|
|
||||||
signByDefault = true;
|
|
||||||
key = "4000EB35E1AE0F07";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,131 +0,0 @@
|
|||||||
{config, ...}: let
|
|
||||||
defaultChecks = [
|
|
||||||
{
|
|
||||||
name = "repository";
|
|
||||||
frequency = "2 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "archives";
|
|
||||||
frequency = "4 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "data";
|
|
||||||
frequency = "6 weeks";
|
|
||||||
}
|
|
||||||
{
|
|
||||||
name = "extract";
|
|
||||||
frequency = "6 weeks";
|
|
||||||
}
|
|
||||||
];
|
|
||||||
passwordFile = "${config.home.homeDirectory}/.config/borg/password";
|
|
||||||
encCmd = ''cat ${passwordFile}'';
|
|
||||||
repo = "ssh://borg.jroeger.de/./comfy-station";
|
|
||||||
in {
|
|
||||||
sops.secrets = {
|
|
||||||
"borg/password" = {
|
|
||||||
sopsFile = ../../secrets/jonas/borg.yaml;
|
|
||||||
key = "password";
|
|
||||||
path = passwordFile;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
services.borgmatic.enable = true;
|
|
||||||
services.borgmatic.frequency = "hourly";
|
|
||||||
|
|
||||||
programs.borgmatic.enable = true;
|
|
||||||
programs.borgmatic.backups = {
|
|
||||||
workspaces = {
|
|
||||||
location = {
|
|
||||||
sourceDirectories = ["${config.xdg.userDirs.extraConfig.XDG_WORKSPACES_DIR}"];
|
|
||||||
repositories = [repo];
|
|
||||||
excludeHomeManagerSymlinks = true;
|
|
||||||
extraConfig = {
|
|
||||||
archive_name_format = "{hostname}-workspaces-{now}";
|
|
||||||
exclude_patterns = [
|
|
||||||
"*/.venv"
|
|
||||||
"__pycache__"
|
|
||||||
];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
retention = {
|
|
||||||
keepDaily = 7;
|
|
||||||
keepHourly = 12;
|
|
||||||
keepWeekly = 4;
|
|
||||||
keepMonthly = 6;
|
|
||||||
};
|
|
||||||
storage = {
|
|
||||||
encryptionPasscommand = encCmd;
|
|
||||||
};
|
|
||||||
consistency.checks = defaultChecks;
|
|
||||||
};
|
|
||||||
media = {
|
|
||||||
location = {
|
|
||||||
sourceDirectories = [
|
|
||||||
"${config.xdg.userDirs.documents}"
|
|
||||||
"${config.xdg.userDirs.music}"
|
|
||||||
"${config.home.homeDirectory}/org"
|
|
||||||
"${config.home.homeDirectory}/Obsidian"
|
|
||||||
"${config.home.homeDirectory}/Zotero"
|
|
||||||
];
|
|
||||||
repositories = [repo];
|
|
||||||
excludeHomeManagerSymlinks = true;
|
|
||||||
extraConfig = {
|
|
||||||
archive_name_format = "{hostname}-media-{now}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
retention = {
|
|
||||||
keepDaily = 7;
|
|
||||||
keepWeekly = 2;
|
|
||||||
keepMonthly = 6;
|
|
||||||
};
|
|
||||||
storage = {
|
|
||||||
encryptionPasscommand = encCmd;
|
|
||||||
};
|
|
||||||
consistency.checks = defaultChecks;
|
|
||||||
};
|
|
||||||
sec = {
|
|
||||||
location = {
|
|
||||||
sourceDirectories = [
|
|
||||||
"${config.xdg.configHome}/sops"
|
|
||||||
"${config.home.homeDirectory}/Stuff/sec"
|
|
||||||
"${config.home.homeDirectory}/.password-store"
|
|
||||||
];
|
|
||||||
repositories = [repo];
|
|
||||||
excludeHomeManagerSymlinks = true;
|
|
||||||
extraConfig = {
|
|
||||||
archive_name_format = "{hostname}-sec-{now}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
retention = {
|
|
||||||
keepDaily = 7;
|
|
||||||
keepWeekly = 2;
|
|
||||||
keepMonthly = 6;
|
|
||||||
};
|
|
||||||
storage = {
|
|
||||||
encryptionPasscommand = encCmd;
|
|
||||||
};
|
|
||||||
consistency.checks = defaultChecks;
|
|
||||||
};
|
|
||||||
var = {
|
|
||||||
location = {
|
|
||||||
sourceDirectories = [
|
|
||||||
"${config.xdg.userDirs.desktop}"
|
|
||||||
];
|
|
||||||
repositories = [repo];
|
|
||||||
excludeHomeManagerSymlinks = true;
|
|
||||||
extraConfig = {
|
|
||||||
archive_name_format = "{hostname}-var-{now}";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
retention = {
|
|
||||||
keepDaily = 7;
|
|
||||||
keepWeekly = 2;
|
|
||||||
keepMonthly = 6;
|
|
||||||
};
|
|
||||||
storage = {
|
|
||||||
encryptionPasscommand = encCmd;
|
|
||||||
};
|
|
||||||
consistency.checks = defaultChecks;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
{lib, ...}: {
|
|
||||||
# Home Manager needs a bit of information about you and the paths it should
|
|
||||||
# manage.
|
|
||||||
home.username = "jonas";
|
|
||||||
home.homeDirectory = "/home/jonas";
|
|
||||||
|
|
||||||
# hive modules
|
|
||||||
hive.zsh.enable = true;
|
|
||||||
hive.nix-scripts.enable = true;
|
|
||||||
hive.ranger.enable = true;
|
|
||||||
hive.doom.enable = true;
|
|
||||||
hive.doom.asDefaultEditor = true;
|
|
||||||
hive.doom.withNixPkgs = true;
|
|
||||||
hive.doom.withShellPkgs = true;
|
|
||||||
|
|
||||||
# This value determines the Home Manager release that your configuration is
|
|
||||||
# compatible with. This helps avoid breakage when a new Home Manager release
|
|
||||||
# introduces backwards incompatible changes.
|
|
||||||
#
|
|
||||||
# You should not change this value, even if you update Home Manager. If you do
|
|
||||||
# want to update the value, then make sure to first check the Home Manager
|
|
||||||
# release notes.
|
|
||||||
home.stateVersion = "24.11"; # Please read the comment before changing.
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
EDITOR = lib.mkDefault "vim";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Let Home Manager install and manage itself.
|
|
||||||
programs.home-manager.enable = true;
|
|
||||||
|
|
||||||
# Git
|
|
||||||
programs.difftastic.enable = true;
|
|
||||||
programs.difftastic.git.enable = true;
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
settings.user.name = "Jonas Röger";
|
|
||||||
settings.user.email = "jonas.roeger@tu-dortmund.de";
|
|
||||||
signing = {
|
|
||||||
signByDefault = true;
|
|
||||||
key = "4000EB35E1AE0F07";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,105 +0,0 @@
|
|||||||
{
|
|
||||||
config,
|
|
||||||
lib,
|
|
||||||
...
|
|
||||||
}: rec {
|
|
||||||
# Home Manager needs a bit of information about you and the paths it should
|
|
||||||
# manage.
|
|
||||||
home.username = "jonas";
|
|
||||||
home.homeDirectory = "/home/jonas";
|
|
||||||
|
|
||||||
sops = {
|
|
||||||
age.keyFile = "${home.homeDirectory}/.config/sops/age/keys.txt";
|
|
||||||
};
|
|
||||||
sops.secrets.gotifyDaemonToken = {
|
|
||||||
sopsFile = ../secrets/jonas/gotify.yaml;
|
|
||||||
key = "monolithDesktopToken";
|
|
||||||
};
|
|
||||||
sops.secrets.gotifyCLIToken = {
|
|
||||||
sopsFile = ../secrets/jonas/gotify.yaml;
|
|
||||||
key = "cliToken";
|
|
||||||
};
|
|
||||||
|
|
||||||
# hive moduless
|
|
||||||
hive.doom.enable = true;
|
|
||||||
hive.doom.asDefaultEditor = true;
|
|
||||||
hive.doom.enableCopilot = false;
|
|
||||||
hive.doom.enableTidal = false;
|
|
||||||
hive.doom.withNixPkgs = true;
|
|
||||||
hive.doom.withShellPkgs = true;
|
|
||||||
hive.doom.withPythonPkgs = true;
|
|
||||||
hive.firefox = {
|
|
||||||
enable = true;
|
|
||||||
plasmaIntegration = false;
|
|
||||||
passFF = true;
|
|
||||||
};
|
|
||||||
hive.kdeconnect.enable = false;
|
|
||||||
hive.kdeconnect.indicatorOnly = false;
|
|
||||||
hive.nextcloud.enable = false; # kwallet bug
|
|
||||||
hive.nix-scripts.enable = true;
|
|
||||||
hive.ranger.enable = true;
|
|
||||||
hive.themes.layan.enable = true;
|
|
||||||
hive.yubikey.enable = true;
|
|
||||||
hive.zsh.enable = true;
|
|
||||||
hive.jj.enable = true;
|
|
||||||
hive.gotify = {
|
|
||||||
cli.enable = true;
|
|
||||||
daemon.enable = true;
|
|
||||||
cli.tokenSopsKey = config.sops.secrets.gotifyCLIToken.name;
|
|
||||||
daemon.tokenSopsKey = config.sops.secrets.gotifyDaemonToken.name;
|
|
||||||
host = "gotify.jroeger.de";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Make session variables available in systemd units
|
|
||||||
# SEE: https://github.com/nix-community/home-manager/pull/5543
|
|
||||||
# systemd.user.settings.Manager.DefaultEnvironment =
|
|
||||||
# lib.mapAttrs (_: lib.mkDefault) config.home.sessionVariables;
|
|
||||||
|
|
||||||
xdg.mimeApps = {
|
|
||||||
enable = true;
|
|
||||||
|
|
||||||
defaultApplications = {
|
|
||||||
"text/html" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/http" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/https" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/about" = "firefox.desktop";
|
|
||||||
"x-scheme-handler/unknown" = "firefox.desktop";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
xdg.userDirs.enable = true;
|
|
||||||
xdg.userDirs.createDirectories = true;
|
|
||||||
xdg.userDirs.extraConfig = {
|
|
||||||
XDG_WORKSPACES_DIR = "${config.home.homeDirectory}/Workspaces";
|
|
||||||
XDG_NEXTCLOUD_DIR = "${config.home.homeDirectory}/Nextcloud";
|
|
||||||
XDG_NOTES_DIR = "${config.home.homeDirectory}/Notes";
|
|
||||||
};
|
|
||||||
|
|
||||||
# This value determines the Home Manager release that your configuration is
|
|
||||||
# compatible with. This helps avoid breakage when a new Home Manager release
|
|
||||||
# introduces backwards incompatible changes.
|
|
||||||
#
|
|
||||||
# You should not change this value, even if you update Home Manager. If you do
|
|
||||||
# want to update the value, then make sure to first check the Home Manager
|
|
||||||
# release notes.
|
|
||||||
home.stateVersion = "24.11"; # Please read the comment before changing.
|
|
||||||
|
|
||||||
home.sessionVariables = {
|
|
||||||
EDITOR = lib.mkDefault "vim";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Let Home Manager install and manage itself.
|
|
||||||
programs.home-manager.enable = true;
|
|
||||||
|
|
||||||
# Git
|
|
||||||
programs.difftastic.enable = true;
|
|
||||||
programs.difftastic.git.enable = true;
|
|
||||||
programs.git = {
|
|
||||||
enable = true;
|
|
||||||
settings.user.name = "Jonas Röger";
|
|
||||||
settings.user.email = "jonas.roeger@tu-dortmund.de";
|
|
||||||
signing = {
|
|
||||||
signByDefault = true;
|
|
||||||
key = "4000EB35E1AE0F07";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
{inputs, ...}: {
|
|
||||||
flake.overlays.unstable = final: prev: {
|
|
||||||
unstable = import inputs.nixpkgs-unstable {
|
|
||||||
system = prev.system;
|
|
||||||
config.allowUnfree = true;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
use flake ../../#bulk-transcode --show-trace
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
declare -rA presets=(
|
|
||||||
[davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le"
|
|
||||||
[instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
|
|
||||||
[insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
|
|
||||||
[storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy"
|
|
||||||
[storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
|
|
||||||
[storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
|
|
||||||
[storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy"
|
|
||||||
[network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
|
|
||||||
[network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
|
|
||||||
[whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -rA containers=(
|
|
||||||
[davinci-resolve]="mov"
|
|
||||||
[instagram]="mp4"
|
|
||||||
[insta-4k]="mp4"
|
|
||||||
[storage-hevc]="mkv"
|
|
||||||
[storage-av1]="mkv"
|
|
||||||
[storage-av1-1080p]="mkv"
|
|
||||||
[storage-av1-nvenc]="mkv"
|
|
||||||
[network]="mp4"
|
|
||||||
[network-1080p]="mp4"
|
|
||||||
[whatsapp]="mp4"
|
|
||||||
)
|
|
||||||
|
|
||||||
where="${1:-.}"
|
|
||||||
dest="${2:-$where}"
|
|
||||||
|
|
||||||
selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap)
|
|
||||||
|
|
||||||
preset=$(
|
|
||||||
printf '%s\n' "${!presets[@]}" | \
|
|
||||||
fzf --multi --prompt "Select a preset"
|
|
||||||
)
|
|
||||||
flags="${presets[$preset]}"
|
|
||||||
container="${containers[$preset]}"
|
|
||||||
|
|
||||||
output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ")
|
|
||||||
|
|
||||||
if gum confirm "Flatten the directory structure?";
|
|
||||||
then
|
|
||||||
flatten=true
|
|
||||||
else
|
|
||||||
flatten=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
function transcode_job {
|
|
||||||
local ifile="$1"
|
|
||||||
local output_dir="$2"
|
|
||||||
local flatten="$3"
|
|
||||||
local where="$4"
|
|
||||||
local flags="$5"
|
|
||||||
local container="$6"
|
|
||||||
local fname=$(basename "$ifile")
|
|
||||||
local segment=$(realpath --relative-to="$where" "$ifile")
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$flatten" = true ]; then
|
|
||||||
output_file="$output_dir/$fname.$container"
|
|
||||||
else
|
|
||||||
output_file="$output_dir/$segment.$container"
|
|
||||||
fi
|
|
||||||
|
|
||||||
tmp_file=$(mktemp)
|
|
||||||
|
|
||||||
echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file"
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$output_file")"
|
|
||||||
|
|
||||||
if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file";
|
|
||||||
then
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
else
|
|
||||||
# gum log "Failed to transcode $ifile. Check ./error.log for details."
|
|
||||||
cat "$tmp_file" >> error.log
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
export -f transcode_job
|
|
||||||
|
|
||||||
mapfile -t files <<< "$selection"
|
|
||||||
len=${#files[@]}
|
|
||||||
i=1
|
|
||||||
for file in "${files[@]}"; do
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\""
|
|
||||||
else
|
|
||||||
echo "Skipping invalid file: $file" >&2
|
|
||||||
fi
|
|
||||||
((i++))
|
|
||||||
done
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{
|
|
||||||
flake.overlays.bulk-transcode = final: prev: {
|
|
||||||
bulk-transcode = import ./overlay.nix {inherit final prev;};
|
|
||||||
};
|
|
||||||
perSystem = {pkgs, ...}: {
|
|
||||||
packages.bulk-transcode = pkgs.callPackage ./derivation.nix {};
|
|
||||||
devShells.bulk-transcode = import ./shell.nix {inherit pkgs;};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
bash,
|
|
||||||
coreutils,
|
|
||||||
ffmpeg,
|
|
||||||
findutils,
|
|
||||||
fzf,
|
|
||||||
gum,
|
|
||||||
lib,
|
|
||||||
makeWrapper,
|
|
||||||
stdenv,
|
|
||||||
tree,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation (finalAttrs: {
|
|
||||||
name = "bulk-transcode";
|
|
||||||
src = ./.;
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
bash
|
|
||||||
coreutils
|
|
||||||
ffmpeg
|
|
||||||
findutils
|
|
||||||
fzf
|
|
||||||
gum
|
|
||||||
makeWrapper
|
|
||||||
tree
|
|
||||||
];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
install -Dm755 bulk-transcode.sh $out/bin/bulk-transcode
|
|
||||||
|
|
||||||
wrapProgram $out/bin/bulk-transcode \
|
|
||||||
--set PATH "${lib.makeBinPath finalAttrs.buildInputs}"
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}: let
|
|
||||||
bin = pkgs.callPackage ./derivation.nix {};
|
|
||||||
in
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "bulk-transcode";
|
|
||||||
inputsFrom = [bin];
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
appimageTools,
|
|
||||||
fetchurl,
|
|
||||||
makeWrapper,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
pname = "crossover";
|
|
||||||
version = "3.1.5";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "https://github.com/lacymorrow/crossover/releases/download/v${version}/CrossOver-${version}-x86_64.AppImage";
|
|
||||||
sha256 = "sha256-64RPal8n1PJh1LB+CTyNFt04Pw1lVgcsyc63S8yQ/DA=";
|
|
||||||
};
|
|
||||||
appimageContents = appimageTools.extract {
|
|
||||||
inherit pname version src;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
appimageTools.wrapType2 {
|
|
||||||
inherit pname version src;
|
|
||||||
|
|
||||||
nativeBuildInputs = [makeWrapper];
|
|
||||||
extraInstallCommands = ''
|
|
||||||
wrapProgram $out/bin/${pname} --add-flags "--no-sandbox"
|
|
||||||
|
|
||||||
# Create a minimal .desktop file manually
|
|
||||||
mkdir -p $out/share/applications
|
|
||||||
cat > $out/share/applications/${pname}.desktop <<EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=${pname}
|
|
||||||
Exec=${pname} %U
|
|
||||||
Icon=${pname}
|
|
||||||
Type=Application
|
|
||||||
Categories=Utility;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Optionally extract icon from AppImage (if available)
|
|
||||||
# You can also manually install an icon here:
|
|
||||||
mkdir -p $out/share/icons/hicolor/0x0/apps
|
|
||||||
cp ${appimageContents}/usr/share/icons/hicolor/0x0/apps/${pname}.png $out/share/icons/hicolor/0x0/apps/${pname}.png || true
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
final: _: {
|
|
||||||
hive = {
|
|
||||||
crossover = final.callPackage ./crossover.nix {};
|
|
||||||
bulk-transcode = final.callPackage ./bulk-transcode {};
|
|
||||||
spotify-shortcuts = final.callPackage ./spotify-shortcuts/derivation.nix {};
|
|
||||||
layan-qt6 = final.kdePackages.callPackage ./layan-qt6.nix {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{
|
|
||||||
stdenv,
|
|
||||||
lib,
|
|
||||||
fetchFromGitHub,
|
|
||||||
gitUpdater,
|
|
||||||
kdeclarative,
|
|
||||||
libplasma,
|
|
||||||
plasma-workspace,
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
pname = "layan-kde-qt6";
|
|
||||||
version = "2025-02-13";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "vinceliuice";
|
|
||||||
repo = "Layan-kde";
|
|
||||||
rev = "ace0b1d93e5f08c650630c146b2d637e1e2e6cd1";
|
|
||||||
hash = "sha256-T69bGjfZeOsJLmOZKps9N2wMv5VKYeo1ipGEsLAS+Sg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Propagate sddm theme dependencies to user env otherwise sddm does
|
|
||||||
# not find them. Putting them in buildInputs is not enough.
|
|
||||||
propagatedUserEnvPkgs = [
|
|
||||||
kdeclarative
|
|
||||||
libplasma
|
|
||||||
plasma-workspace
|
|
||||||
];
|
|
||||||
|
|
||||||
postPatch = ''
|
|
||||||
patchShebangs install.sh
|
|
||||||
|
|
||||||
substituteInPlace install.sh \
|
|
||||||
--replace '$HOME/.local' $out \
|
|
||||||
--replace '$HOME/.config' $out/share
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
name= ./install.sh --dest $out/share/themes
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.updateScript = gitUpdater {};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Flat Design theme for KDE Plasma desktop";
|
|
||||||
homepage = "https://github.com/vinceliuice/Layan-kde";
|
|
||||||
license = licenses.gpl3Only;
|
|
||||||
platforms = platforms.all;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
use flake ../../#spotify-shortcuts --show-trace
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}:
|
|
||||||
pkgs.callPackage ./derivation.nix {}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{python3Packages}:
|
|
||||||
with python3Packages;
|
|
||||||
buildPythonApplication {
|
|
||||||
name = "spotify-shortcuts";
|
|
||||||
propagatedBuildInputs = [spotipy pyxdg desktop-notifier];
|
|
||||||
pyproject = true;
|
|
||||||
build-system = [setuptools];
|
|
||||||
src = ./.;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="spotify_shortcuts",
|
|
||||||
version="1.0",
|
|
||||||
packages=find_packages(),
|
|
||||||
entry_points={
|
|
||||||
"console_scripts": [
|
|
||||||
"spotisc=spotify_shortcuts.run:main",
|
|
||||||
"spotify-like=spotify_shortcuts.spotify_like:main",
|
|
||||||
"spotify-pl-add=spotify_shortcuts.spotify_pl_add:main",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}: let
|
|
||||||
drv = pkgs.callPackage ./derivation.nix {};
|
|
||||||
in
|
|
||||||
pkgs.mkShell {
|
|
||||||
packages = [
|
|
||||||
pkgs.pyright
|
|
||||||
pkgs.black
|
|
||||||
];
|
|
||||||
|
|
||||||
inputsFrom = [drv];
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
export PYTHONPATH="$PYTHONPATH:$(pwd)"
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
from spotify_shortcuts.run import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
from typing import List
|
|
||||||
from os import getenv
|
|
||||||
from sys import argv
|
|
||||||
from xdg.BaseDirectory import xdg_cache_home
|
|
||||||
from json import loads
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Config:
|
|
||||||
cache_file: Path = Path(xdg_cache_home) / Path("spotify-shortcuts.json")
|
|
||||||
client_id: str | None = None
|
|
||||||
client_secret: str | None = None
|
|
||||||
notifications: bool = True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_file(path: Path):
|
|
||||||
if not path.exists():
|
|
||||||
raise FileNotFoundError(f"Configuration file {path} does not exist.")
|
|
||||||
with open(path, "r") as f:
|
|
||||||
data = loads(f.read())
|
|
||||||
|
|
||||||
return Config(
|
|
||||||
cache_file=Path(data.get("cacheFile", Config.cache_file)),
|
|
||||||
client_id=data.get("clientId", Config.client_id),
|
|
||||||
client_secret=data.get("clientSecret", Config.client_secret),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(args: List[str] = argv[1:]) -> Config:
|
|
||||||
parser = ArgumentParser(description="Spotify CLI Tool")
|
|
||||||
parser.add_argument(
|
|
||||||
"--cache-file",
|
|
||||||
type=Path,
|
|
||||||
default=Config.cache_file,
|
|
||||||
help="Path to the cache file for Spotify authentication",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--client-id",
|
|
||||||
type=str,
|
|
||||||
default=Config.client_id,
|
|
||||||
help="Spotify API Client ID",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--client-secret",
|
|
||||||
type=str,
|
|
||||||
default=Config.client_secret,
|
|
||||||
help="Spotify API Client Secret",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--config-file",
|
|
||||||
type=str,
|
|
||||||
help="Path to a json configuration file with keys clientId and clientSecret",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--no-notifications",
|
|
||||||
action="store_true",
|
|
||||||
help="Disable desktop notifications",
|
|
||||||
)
|
|
||||||
|
|
||||||
ns = parser.parse_args(args)
|
|
||||||
|
|
||||||
cfg = Config()
|
|
||||||
if (cfg_file := ns.config_file or getenv("SPOTIFY_SHORTCUTS_CONFIG", None)) != None:
|
|
||||||
cfg = Config.from_file(Path(cfg_file))
|
|
||||||
|
|
||||||
return Config(
|
|
||||||
cache_file=ns.cache_file or cfg.cache_file,
|
|
||||||
client_id=ns.client_id or cfg.client_id,
|
|
||||||
client_secret=ns.client_secret or cfg.client_secret,
|
|
||||||
notifications=not ns.no_notifications or cfg.notifications,
|
|
||||||
)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
from spotify_shortcuts.spotify_like import SpotifyLike
|
|
||||||
from spotify_shortcuts.spotify_pl_add import SpotifyPlAdd
|
|
||||||
|
|
||||||
SHORTCUT_REGISTRY = {
|
|
||||||
"like": SpotifyLike(),
|
|
||||||
"pl_add": SpotifyPlAdd(),
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
from spotify_shortcuts.config import Config, load_config
|
|
||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.spotify_auth import authenticated_session
|
|
||||||
from itertools import chain
|
|
||||||
|
|
||||||
|
|
||||||
def all_scopes() -> list[str]:
|
|
||||||
from spotify_shortcuts.registry import SHORTCUT_REGISTRY
|
|
||||||
|
|
||||||
return list(
|
|
||||||
set(
|
|
||||||
chain.from_iterable(
|
|
||||||
shortcut.get_scopes() for shortcut in SHORTCUT_REGISTRY.values()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_shortcut(shortcut: Shortcut, config: Config):
|
|
||||||
client = authenticated_session(
|
|
||||||
config, scopes=all_scopes() # use all scopes to avoid re-authentication
|
|
||||||
)
|
|
||||||
|
|
||||||
shortcut.execute(client, config)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
from spotify_shortcuts.registry import SHORTCUT_REGISTRY
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print(f"Usage: {sys.argv[0]} <shortcut_name>")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
shortcut_name = sys.argv[1]
|
|
||||||
if shortcut_name not in SHORTCUT_REGISTRY:
|
|
||||||
print(f"Shortcut '{shortcut_name}' not found.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
shortcut = SHORTCUT_REGISTRY[shortcut_name]
|
|
||||||
config = load_config(args=sys.argv[2:])
|
|
||||||
|
|
||||||
run_shortcut(shortcut, config)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
from spotify_shortcuts.config import Config
|
|
||||||
from spotipy import Spotify
|
|
||||||
|
|
||||||
|
|
||||||
class Shortcut(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def execute(self, client: Spotify, config: Config):
|
|
||||||
"""Execute the shortcut action."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_help(self) -> str:
|
|
||||||
"""Return a description of the shortcut."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
"""Return the spotify API scopes required for the shortcut."""
|
|
||||||
pass
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from spotipy.oauth2 import SpotifyOAuth
|
|
||||||
from spotipy import Spotify
|
|
||||||
from spotify_shortcuts.config import Config
|
|
||||||
|
|
||||||
CALLBACK_URI = "http://127.0.0.1:45632/callback"
|
|
||||||
|
|
||||||
|
|
||||||
def authenticated_session(cfg: Config, scopes: list[str]) -> Spotify:
|
|
||||||
assert cfg.client_id, "Spotify client ID is required"
|
|
||||||
assert cfg.client_secret, "Spotify client secret is required"
|
|
||||||
|
|
||||||
return Spotify(
|
|
||||||
auth_manager=SpotifyOAuth(
|
|
||||||
client_id=cfg.client_id,
|
|
||||||
client_secret=cfg.client_secret,
|
|
||||||
redirect_uri=CALLBACK_URI,
|
|
||||||
scope=" ".join(scopes),
|
|
||||||
cache_path=cfg.cache_file,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
from spotify_shortcuts.run import run_shortcut
|
|
||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.config import load_config
|
|
||||||
from desktop_notifier import DesktopNotifierSync
|
|
||||||
|
|
||||||
SCOPES = [
|
|
||||||
"user-library-read",
|
|
||||||
"user-library-modify",
|
|
||||||
"user-read-playback-state",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyLike(Shortcut):
|
|
||||||
def execute(self, client, config):
|
|
||||||
if (playback := client.current_playback()) is None:
|
|
||||||
print("No current playback found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (uri := playback.get("item", {}).get("uri", None)) is None:
|
|
||||||
print("No track URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
client.current_user_saved_tracks_add(tracks=[uri])
|
|
||||||
|
|
||||||
if config.notifications:
|
|
||||||
dn = DesktopNotifierSync()
|
|
||||||
dn.send(
|
|
||||||
title="Track Liked",
|
|
||||||
message=f"Track \"{playback.get('item', {}).get('name', '<no-name>')}\" by \"{
|
|
||||||
", ".join(a.get('name', '<no-name>') for a in playback.get('item', {}).get('artists', []))
|
|
||||||
}\" has been liked.",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help(self) -> str:
|
|
||||||
return "Like the currently playing track."
|
|
||||||
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
return SCOPES
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
run_shortcut(SpotifyLike(), load_config())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.config import load_config
|
|
||||||
from desktop_notifier import DesktopNotifierSync
|
|
||||||
from spotify_shortcuts.run import run_shortcut
|
|
||||||
|
|
||||||
SCOPES = [
|
|
||||||
"playlist-modify-public",
|
|
||||||
"playlist-modify-private",
|
|
||||||
"user-read-playback-state",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyPlAdd(Shortcut):
|
|
||||||
def execute(self, client, config):
|
|
||||||
if (playback := client.current_playback()) is None:
|
|
||||||
print("No current playback found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (track_uri := playback.get("item", {}).get("uri", None)) is None:
|
|
||||||
print("No track URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (context_uri := playback.get("context", {}).get("uri", None)) is None:
|
|
||||||
print("No context URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
client.playlist_add_items(context_uri, items=[track_uri])
|
|
||||||
|
|
||||||
if config.notifications:
|
|
||||||
track_name = playback.get("item", {}).get("name", "<no-name>")
|
|
||||||
artists = ", ".join(
|
|
||||||
a.get("name", "<no-name>")
|
|
||||||
for a in playback.get("item", {}).get("artists", [])
|
|
||||||
)
|
|
||||||
playlist_name = (client.playlist(context_uri) or {}).get(
|
|
||||||
"name", "<no-name>"
|
|
||||||
)
|
|
||||||
|
|
||||||
dn = DesktopNotifierSync()
|
|
||||||
dn.send(
|
|
||||||
title="Track Added to Playlist",
|
|
||||||
message=f'Track "{track_name}" by "{artists}" has been added to {playlist_name}.',
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help(self) -> str:
|
|
||||||
return "Add the currently playing track to the current playlist."
|
|
||||||
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
return SCOPES
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
run_shortcut(SpotifyPlAdd(), load_config())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
use flake ../../#bulk-transcode --show-trace
|
|
||||||
@@ -1,96 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
|
|
||||||
declare -rA presets=(
|
|
||||||
[davinci-resolve]="-c:v dnxhd -profile:v dnxhr_hq -pix_fmt yuv422p -c:a pcm_s16le"
|
|
||||||
[instagram]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)':flags=lanczos -r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
|
|
||||||
[insta-4k]="-r 30 -c:v libx264 -profile:v high -level 4.1 -pix_fmt yuv420p -preset slow -crf 18 -bf 2 -g 15 -keyint_min 15 -x264-params \"open-gop=0:cabac=1:b-pyramid=none\" -movflags +faststart -c:a aac -b:a 96k"
|
|
||||||
[storage-hevc]="-c:v libx265 -preset slower -crf 18 -pix_fmt yuv420p10le -x265-params aq-mode=3:aq-strength=1.0:psy-rd=1.8:psy-rdoq=1.0 -c:a copy"
|
|
||||||
[storage-av1]="-c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
|
|
||||||
[storage-av1-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libsvtav1 -preset 6 -crf 28 -pix_fmt yuv420p -g 240 -svtav1-params tune=0:aq-mode=2 -c:a copy"
|
|
||||||
[storage-av1-nvenc]="-c:v av1_nvenc -cq 28 -preset slow -pix_fmt yuv420p10le -c:a copy"
|
|
||||||
[network]="-c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
|
|
||||||
[network-1080p]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 22 -pix_fmt yuv420p -c:a aac -b:a 128k"
|
|
||||||
[whatsapp]="-vf scale='if(gte(iw/ih,1),1920,-1)':'if(gte(iw/ih,1),-1,1920)' -c:v libx264 -preset slow -crf 30 -profile:v baseline -level 3.0 -pix_fmt yuv420p -r 25 -g 50 -c:a aac -b:a 160k -r:a 44100"
|
|
||||||
)
|
|
||||||
|
|
||||||
declare -rA containers=(
|
|
||||||
[davinci-resolve]="mov"
|
|
||||||
[instagram]="mp4"
|
|
||||||
[insta-4k]="mp4"
|
|
||||||
[storage-hevc]="mkv"
|
|
||||||
[storage-av1]="mkv"
|
|
||||||
[storage-av1-1080p]="mkv"
|
|
||||||
[storage-av1-nvenc]="mkv"
|
|
||||||
[network]="mp4"
|
|
||||||
[network-1080p]="mp4"
|
|
||||||
[whatsapp]="mp4"
|
|
||||||
)
|
|
||||||
|
|
||||||
where="${1:-.}"
|
|
||||||
dest="${2:-$where}"
|
|
||||||
|
|
||||||
selection=$(find "$where" -type f | fzf --multi --preview 'ffprobe -v error -show_format -show_streams {}' --preview-window=up:wrap)
|
|
||||||
|
|
||||||
preset=$(
|
|
||||||
printf '%s\n' "${!presets[@]}" | \
|
|
||||||
fzf --multi --prompt "Select a preset"
|
|
||||||
)
|
|
||||||
flags="${presets[$preset]}"
|
|
||||||
container="${containers[$preset]}"
|
|
||||||
|
|
||||||
output_dir=$(find "$dest" -type d ! -name '.*' ! -path '*/.*/*' | fzf --preview 'tree -C {}' --preview-window=up:wrap --prompt "Select output directory: ")
|
|
||||||
|
|
||||||
if gum confirm "Flatten the directory structure?";
|
|
||||||
then
|
|
||||||
flatten=true
|
|
||||||
else
|
|
||||||
flatten=false
|
|
||||||
fi
|
|
||||||
|
|
||||||
|
|
||||||
function transcode_job {
|
|
||||||
local ifile="$1"
|
|
||||||
local output_dir="$2"
|
|
||||||
local flatten="$3"
|
|
||||||
local where="$4"
|
|
||||||
local flags="$5"
|
|
||||||
local container="$6"
|
|
||||||
local fname=$(basename "$ifile")
|
|
||||||
local segment=$(realpath --relative-to="$where" "$ifile")
|
|
||||||
|
|
||||||
|
|
||||||
if [ "$flatten" = true ]; then
|
|
||||||
output_file="$output_dir/$fname.$container"
|
|
||||||
else
|
|
||||||
output_file="$output_dir/$segment.$container"
|
|
||||||
fi
|
|
||||||
|
|
||||||
tmp_file=$(mktemp)
|
|
||||||
|
|
||||||
echo "Running Command: ffmpeg -y -i $ifile $flags $output_file" >> "$tmp_file"
|
|
||||||
|
|
||||||
mkdir -p "$(dirname "$output_file")"
|
|
||||||
|
|
||||||
if ffmpeg -y -i "$ifile" $(echo -n "$flags") "$output_file" 2>> "$tmp_file";
|
|
||||||
then
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
else
|
|
||||||
# gum log "Failed to transcode $ifile. Check ./error.log for details."
|
|
||||||
cat "$tmp_file" >> error.log
|
|
||||||
rm -f "$tmp_file"
|
|
||||||
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
export -f transcode_job
|
|
||||||
|
|
||||||
mapfile -t files <<< "$selection"
|
|
||||||
len=${#files[@]}
|
|
||||||
i=1
|
|
||||||
for file in "${files[@]}"; do
|
|
||||||
if [[ -f "$file" ]]; then
|
|
||||||
gum spin --spinner dot --title "[$i/$len] Transcoding $file" -- bash -c "source <(declare -f transcode_job); transcode_job \"$file\" \"$output_dir\" \"$flatten\" \"$where\" \"$flags\" \"$container\""
|
|
||||||
else
|
|
||||||
echo "Skipping invalid file: $file" >&2
|
|
||||||
fi
|
|
||||||
((i++))
|
|
||||||
done
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
{
|
|
||||||
bash,
|
|
||||||
coreutils,
|
|
||||||
ffmpeg,
|
|
||||||
findutils,
|
|
||||||
fzf,
|
|
||||||
gum,
|
|
||||||
lib,
|
|
||||||
makeWrapper,
|
|
||||||
stdenv,
|
|
||||||
tree,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation (finalAttrs: {
|
|
||||||
name = "bulk-transcode";
|
|
||||||
src = ./.;
|
|
||||||
|
|
||||||
buildInputs = [
|
|
||||||
bash
|
|
||||||
coreutils
|
|
||||||
ffmpeg
|
|
||||||
findutils
|
|
||||||
fzf
|
|
||||||
gum
|
|
||||||
makeWrapper
|
|
||||||
tree
|
|
||||||
];
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
install -Dm755 bulk-transcode.sh $out/bin/bulk-transcode
|
|
||||||
|
|
||||||
wrapProgram $out/bin/bulk-transcode \
|
|
||||||
--set PATH "${lib.makeBinPath finalAttrs.buildInputs}"
|
|
||||||
'';
|
|
||||||
})
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}: let
|
|
||||||
bin = pkgs.callPackage ./default.nix {};
|
|
||||||
in
|
|
||||||
pkgs.mkShell {
|
|
||||||
name = "bulk-transcode";
|
|
||||||
inputsFrom = [bin];
|
|
||||||
}
|
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
{
|
|
||||||
appimageTools,
|
|
||||||
fetchurl,
|
|
||||||
makeWrapper,
|
|
||||||
...
|
|
||||||
}: let
|
|
||||||
pname = "crossover";
|
|
||||||
version = "3.1.5";
|
|
||||||
src = fetchurl {
|
|
||||||
url = "https://github.com/lacymorrow/crossover/releases/download/v${version}/CrossOver-${version}-x86_64.AppImage";
|
|
||||||
sha256 = "sha256-64RPal8n1PJh1LB+CTyNFt04Pw1lVgcsyc63S8yQ/DA=";
|
|
||||||
};
|
|
||||||
appimageContents = appimageTools.extract {
|
|
||||||
inherit pname version src;
|
|
||||||
};
|
|
||||||
in
|
|
||||||
appimageTools.wrapType2 {
|
|
||||||
inherit pname version src;
|
|
||||||
|
|
||||||
nativeBuildInputs = [makeWrapper];
|
|
||||||
extraInstallCommands = ''
|
|
||||||
wrapProgram $out/bin/${pname} --add-flags "--no-sandbox"
|
|
||||||
|
|
||||||
# Create a minimal .desktop file manually
|
|
||||||
mkdir -p $out/share/applications
|
|
||||||
cat > $out/share/applications/${pname}.desktop <<EOF
|
|
||||||
[Desktop Entry]
|
|
||||||
Name=${pname}
|
|
||||||
Exec=${pname} %U
|
|
||||||
Icon=${pname}
|
|
||||||
Type=Application
|
|
||||||
Categories=Utility;
|
|
||||||
EOF
|
|
||||||
|
|
||||||
# Optionally extract icon from AppImage (if available)
|
|
||||||
# You can also manually install an icon here:
|
|
||||||
mkdir -p $out/share/icons/hicolor/0x0/apps
|
|
||||||
cp ${appimageContents}/usr/share/icons/hicolor/0x0/apps/${pname}.png $out/share/icons/hicolor/0x0/apps/${pname}.png || true
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
final: _: {
|
|
||||||
hive = {
|
|
||||||
crossover = final.callPackage ./crossover.nix {};
|
|
||||||
bulk-transcode = final.callPackage ./bulk-transcode {};
|
|
||||||
spotify-shortcuts = final.callPackage ./spotify-shortcuts/derivation.nix {};
|
|
||||||
layan-qt6 = final.kdePackages.callPackage ./layan-qt6.nix {};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
{
|
|
||||||
stdenv,
|
|
||||||
lib,
|
|
||||||
fetchFromGitHub,
|
|
||||||
gitUpdater,
|
|
||||||
kdeclarative,
|
|
||||||
libplasma,
|
|
||||||
plasma-workspace,
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation {
|
|
||||||
pname = "layan-kde-qt6";
|
|
||||||
version = "2025-02-13";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "vinceliuice";
|
|
||||||
repo = "Layan-kde";
|
|
||||||
rev = "ace0b1d93e5f08c650630c146b2d637e1e2e6cd1";
|
|
||||||
hash = "sha256-T69bGjfZeOsJLmOZKps9N2wMv5VKYeo1ipGEsLAS+Sg=";
|
|
||||||
};
|
|
||||||
|
|
||||||
# Propagate sddm theme dependencies to user env otherwise sddm does
|
|
||||||
# not find them. Putting them in buildInputs is not enough.
|
|
||||||
propagatedUserEnvPkgs = [
|
|
||||||
kdeclarative
|
|
||||||
libplasma
|
|
||||||
plasma-workspace
|
|
||||||
];
|
|
||||||
|
|
||||||
postPatch = ''
|
|
||||||
patchShebangs install.sh
|
|
||||||
|
|
||||||
substituteInPlace install.sh \
|
|
||||||
--replace '$HOME/.local' $out \
|
|
||||||
--replace '$HOME/.config' $out/share
|
|
||||||
'';
|
|
||||||
|
|
||||||
installPhase = ''
|
|
||||||
runHook preInstall
|
|
||||||
|
|
||||||
name= ./install.sh --dest $out/share/themes
|
|
||||||
|
|
||||||
runHook postInstall
|
|
||||||
'';
|
|
||||||
|
|
||||||
passthru.updateScript = gitUpdater {};
|
|
||||||
|
|
||||||
meta = with lib; {
|
|
||||||
description = "Flat Design theme for KDE Plasma desktop";
|
|
||||||
homepage = "https://github.com/vinceliuice/Layan-kde";
|
|
||||||
license = licenses.gpl3Only;
|
|
||||||
platforms = platforms.all;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
use flake ../../#spotify-shortcuts --show-trace
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}:
|
|
||||||
pkgs.callPackage ./derivation.nix {}
|
|
||||||
@@ -1,9 +0,0 @@
|
|||||||
{python3Packages}:
|
|
||||||
with python3Packages;
|
|
||||||
buildPythonApplication {
|
|
||||||
name = "spotify-shortcuts";
|
|
||||||
propagatedBuildInputs = [spotipy pyxdg desktop-notifier];
|
|
||||||
pyproject = true;
|
|
||||||
build-system = [setuptools];
|
|
||||||
src = ./.;
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
#!/usr/bin/env python
|
|
||||||
|
|
||||||
from setuptools import setup, find_packages
|
|
||||||
|
|
||||||
setup(
|
|
||||||
name="spotify_shortcuts",
|
|
||||||
version="1.0",
|
|
||||||
packages=find_packages(),
|
|
||||||
entry_points={
|
|
||||||
"console_scripts": [
|
|
||||||
"spotisc=spotify_shortcuts.run:main",
|
|
||||||
"spotify-like=spotify_shortcuts.spotify_like:main",
|
|
||||||
"spotify-pl-add=spotify_shortcuts.spotify_pl_add:main",
|
|
||||||
],
|
|
||||||
},
|
|
||||||
)
|
|
||||||
@@ -1,15 +0,0 @@
|
|||||||
{pkgs ? import <nixpkgs> {}}: let
|
|
||||||
drv = pkgs.callPackage ./derivation.nix {};
|
|
||||||
in
|
|
||||||
pkgs.mkShell {
|
|
||||||
packages = [
|
|
||||||
pkgs.pyright
|
|
||||||
pkgs.black
|
|
||||||
];
|
|
||||||
|
|
||||||
inputsFrom = [drv];
|
|
||||||
|
|
||||||
shellHook = ''
|
|
||||||
export PYTHONPATH="$PYTHONPATH:$(pwd)"
|
|
||||||
'';
|
|
||||||
}
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
from spotify_shortcuts.run import main
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
from pathlib import Path
|
|
||||||
from dataclasses import dataclass
|
|
||||||
from argparse import ArgumentParser
|
|
||||||
from typing import List
|
|
||||||
from os import getenv
|
|
||||||
from sys import argv
|
|
||||||
from xdg.BaseDirectory import xdg_cache_home
|
|
||||||
from json import loads
|
|
||||||
|
|
||||||
|
|
||||||
@dataclass
|
|
||||||
class Config:
|
|
||||||
cache_file: Path = Path(xdg_cache_home) / Path("spotify-shortcuts.json")
|
|
||||||
client_id: str | None = None
|
|
||||||
client_secret: str | None = None
|
|
||||||
notifications: bool = True
|
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def from_file(path: Path):
|
|
||||||
if not path.exists():
|
|
||||||
raise FileNotFoundError(f"Configuration file {path} does not exist.")
|
|
||||||
with open(path, "r") as f:
|
|
||||||
data = loads(f.read())
|
|
||||||
|
|
||||||
return Config(
|
|
||||||
cache_file=Path(data.get("cacheFile", Config.cache_file)),
|
|
||||||
client_id=data.get("clientId", Config.client_id),
|
|
||||||
client_secret=data.get("clientSecret", Config.client_secret),
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def load_config(args: List[str] = argv[1:]) -> Config:
|
|
||||||
parser = ArgumentParser(description="Spotify CLI Tool")
|
|
||||||
parser.add_argument(
|
|
||||||
"--cache-file",
|
|
||||||
type=Path,
|
|
||||||
default=Config.cache_file,
|
|
||||||
help="Path to the cache file for Spotify authentication",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--client-id",
|
|
||||||
type=str,
|
|
||||||
default=Config.client_id,
|
|
||||||
help="Spotify API Client ID",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--client-secret",
|
|
||||||
type=str,
|
|
||||||
default=Config.client_secret,
|
|
||||||
help="Spotify API Client Secret",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--config-file",
|
|
||||||
type=str,
|
|
||||||
help="Path to a json configuration file with keys clientId and clientSecret",
|
|
||||||
)
|
|
||||||
parser.add_argument(
|
|
||||||
"--no-notifications",
|
|
||||||
action="store_true",
|
|
||||||
help="Disable desktop notifications",
|
|
||||||
)
|
|
||||||
|
|
||||||
ns = parser.parse_args(args)
|
|
||||||
|
|
||||||
cfg = Config()
|
|
||||||
if (cfg_file := ns.config_file or getenv("SPOTIFY_SHORTCUTS_CONFIG", None)) != None:
|
|
||||||
cfg = Config.from_file(Path(cfg_file))
|
|
||||||
|
|
||||||
return Config(
|
|
||||||
cache_file=ns.cache_file or cfg.cache_file,
|
|
||||||
client_id=ns.client_id or cfg.client_id,
|
|
||||||
client_secret=ns.client_secret or cfg.client_secret,
|
|
||||||
notifications=not ns.no_notifications or cfg.notifications,
|
|
||||||
)
|
|
||||||
@@ -1,7 +0,0 @@
|
|||||||
from spotify_shortcuts.spotify_like import SpotifyLike
|
|
||||||
from spotify_shortcuts.spotify_pl_add import SpotifyPlAdd
|
|
||||||
|
|
||||||
SHORTCUT_REGISTRY = {
|
|
||||||
"like": SpotifyLike(),
|
|
||||||
"pl_add": SpotifyPlAdd(),
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
from spotify_shortcuts.config import Config, load_config
|
|
||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.spotify_auth import authenticated_session
|
|
||||||
from itertools import chain
|
|
||||||
|
|
||||||
|
|
||||||
def all_scopes() -> list[str]:
|
|
||||||
from spotify_shortcuts.registry import SHORTCUT_REGISTRY
|
|
||||||
|
|
||||||
return list(
|
|
||||||
set(
|
|
||||||
chain.from_iterable(
|
|
||||||
shortcut.get_scopes() for shortcut in SHORTCUT_REGISTRY.values()
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
def run_shortcut(shortcut: Shortcut, config: Config):
|
|
||||||
client = authenticated_session(
|
|
||||||
config, scopes=all_scopes() # use all scopes to avoid re-authentication
|
|
||||||
)
|
|
||||||
|
|
||||||
shortcut.execute(client, config)
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
from spotify_shortcuts.registry import SHORTCUT_REGISTRY
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) < 2:
|
|
||||||
print(f"Usage: {sys.argv[0]} <shortcut_name>")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
shortcut_name = sys.argv[1]
|
|
||||||
if shortcut_name not in SHORTCUT_REGISTRY:
|
|
||||||
print(f"Shortcut '{shortcut_name}' not found.")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
shortcut = SHORTCUT_REGISTRY[shortcut_name]
|
|
||||||
config = load_config(args=sys.argv[2:])
|
|
||||||
|
|
||||||
run_shortcut(shortcut, config)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,21 +0,0 @@
|
|||||||
from abc import ABC, abstractmethod
|
|
||||||
|
|
||||||
from spotify_shortcuts.config import Config
|
|
||||||
from spotipy import Spotify
|
|
||||||
|
|
||||||
|
|
||||||
class Shortcut(ABC):
|
|
||||||
@abstractmethod
|
|
||||||
def execute(self, client: Spotify, config: Config):
|
|
||||||
"""Execute the shortcut action."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_help(self) -> str:
|
|
||||||
"""Return a description of the shortcut."""
|
|
||||||
pass
|
|
||||||
|
|
||||||
@abstractmethod
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
"""Return the spotify API scopes required for the shortcut."""
|
|
||||||
pass
|
|
||||||
@@ -1,20 +0,0 @@
|
|||||||
from spotipy.oauth2 import SpotifyOAuth
|
|
||||||
from spotipy import Spotify
|
|
||||||
from spotify_shortcuts.config import Config
|
|
||||||
|
|
||||||
CALLBACK_URI = "http://127.0.0.1:45632/callback"
|
|
||||||
|
|
||||||
|
|
||||||
def authenticated_session(cfg: Config, scopes: list[str]) -> Spotify:
|
|
||||||
assert cfg.client_id, "Spotify client ID is required"
|
|
||||||
assert cfg.client_secret, "Spotify client secret is required"
|
|
||||||
|
|
||||||
return Spotify(
|
|
||||||
auth_manager=SpotifyOAuth(
|
|
||||||
client_id=cfg.client_id,
|
|
||||||
client_secret=cfg.client_secret,
|
|
||||||
redirect_uri=CALLBACK_URI,
|
|
||||||
scope=" ".join(scopes),
|
|
||||||
cache_path=cfg.cache_file,
|
|
||||||
)
|
|
||||||
)
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
from spotify_shortcuts.run import run_shortcut
|
|
||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.config import load_config
|
|
||||||
from desktop_notifier import DesktopNotifierSync
|
|
||||||
|
|
||||||
SCOPES = [
|
|
||||||
"user-library-read",
|
|
||||||
"user-library-modify",
|
|
||||||
"user-read-playback-state",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyLike(Shortcut):
|
|
||||||
def execute(self, client, config):
|
|
||||||
if (playback := client.current_playback()) is None:
|
|
||||||
print("No current playback found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (uri := playback.get("item", {}).get("uri", None)) is None:
|
|
||||||
print("No track URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
client.current_user_saved_tracks_add(tracks=[uri])
|
|
||||||
|
|
||||||
if config.notifications:
|
|
||||||
dn = DesktopNotifierSync()
|
|
||||||
dn.send(
|
|
||||||
title="Track Liked",
|
|
||||||
message=f"Track \"{playback.get('item', {}).get('name', '<no-name>')}\" by \"{
|
|
||||||
", ".join(a.get('name', '<no-name>') for a in playback.get('item', {}).get('artists', []))
|
|
||||||
}\" has been liked.",
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help(self) -> str:
|
|
||||||
return "Like the currently playing track."
|
|
||||||
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
return SCOPES
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
run_shortcut(SpotifyLike(), load_config())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
from spotify_shortcuts.shortcut import Shortcut
|
|
||||||
from spotify_shortcuts.config import load_config
|
|
||||||
from desktop_notifier import DesktopNotifierSync
|
|
||||||
from spotify_shortcuts.run import run_shortcut
|
|
||||||
|
|
||||||
SCOPES = [
|
|
||||||
"playlist-modify-public",
|
|
||||||
"playlist-modify-private",
|
|
||||||
"user-read-playback-state",
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
class SpotifyPlAdd(Shortcut):
|
|
||||||
def execute(self, client, config):
|
|
||||||
if (playback := client.current_playback()) is None:
|
|
||||||
print("No current playback found.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (track_uri := playback.get("item", {}).get("uri", None)) is None:
|
|
||||||
print("No track URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
if (context_uri := playback.get("context", {}).get("uri", None)) is None:
|
|
||||||
print("No context URI found in current playback.")
|
|
||||||
return
|
|
||||||
|
|
||||||
client.playlist_add_items(context_uri, items=[track_uri])
|
|
||||||
|
|
||||||
if config.notifications:
|
|
||||||
track_name = playback.get("item", {}).get("name", "<no-name>")
|
|
||||||
artists = ", ".join(
|
|
||||||
a.get("name", "<no-name>")
|
|
||||||
for a in playback.get("item", {}).get("artists", [])
|
|
||||||
)
|
|
||||||
playlist_name = (client.playlist(context_uri) or {}).get(
|
|
||||||
"name", "<no-name>"
|
|
||||||
)
|
|
||||||
|
|
||||||
dn = DesktopNotifierSync()
|
|
||||||
dn.send(
|
|
||||||
title="Track Added to Playlist",
|
|
||||||
message=f'Track "{track_name}" by "{artists}" has been added to {playlist_name}.',
|
|
||||||
)
|
|
||||||
|
|
||||||
def get_help(self) -> str:
|
|
||||||
return "Add the currently playing track to the current playlist."
|
|
||||||
|
|
||||||
def get_scopes(self) -> list[str]:
|
|
||||||
return SCOPES
|
|
||||||
|
|
||||||
|
|
||||||
def main():
|
|
||||||
run_shortcut(SpotifyPlAdd(), load_config())
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
main()
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAILNYmQ4HspLsunLyryI/ZbX4tTuRI6cRv0n/ai6+DNCc borg@jroeger.de
|
|
||||||
@@ -1,448 +0,0 @@
|
|||||||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
|
||||||
Comment: Hostname:
|
|
||||||
Version: Hockeypuck 2.1.1-10-gec3b0e7
|
|
||||||
|
|
||||||
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
|
|
||||||
=JVtR
|
|
||||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIBodNTvEGT2J+w6qpJNvmwZuHCshzq2nwU92+VqRcyn4 jonas@comfy-station
|
|
||||||
Binary file not shown.
|
Before Width: | Height: | Size: 41 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 642 KiB |
1
templates/cmake-c/.gitignore
vendored
1
templates/cmake-c/.gitignore
vendored
@@ -1 +0,0 @@
|
|||||||
build
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
cmake_minimum_required(VERSION 3.15)
|
|
||||||
|
|
||||||
project(Hello
|
|
||||||
DESCRIPTION "Hello World"
|
|
||||||
LANGUAGES C
|
|
||||||
)
|
|
||||||
|
|
||||||
add_executable(hello src/main.c)
|
|
||||||
|
|
||||||
install(TARGETS hello)
|
|
||||||
@@ -1,56 +0,0 @@
|
|||||||
{
|
|
||||||
description = "Cmake C Flake";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:nixos/nixpkgs/nixos-unstable";
|
|
||||||
flake-parts.url = "github:hercules-ci/flake-parts";
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = inputs @ {
|
|
||||||
self,
|
|
||||||
flake-parts,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
flake-parts.lib.mkFlake {inherit inputs;} (
|
|
||||||
top: {
|
|
||||||
imports = [];
|
|
||||||
|
|
||||||
flake = {
|
|
||||||
overlays.default = final: prev: {
|
|
||||||
my-derivation = final.callPackage ./nix/derivation.nix {};
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
systems = [
|
|
||||||
"x86_64-linux"
|
|
||||||
];
|
|
||||||
|
|
||||||
perSystem = {
|
|
||||||
self',
|
|
||||||
pkgs,
|
|
||||||
system,
|
|
||||||
...
|
|
||||||
}: {
|
|
||||||
_module.args.pkgs = import inputs.nixpkgs {
|
|
||||||
inherit system;
|
|
||||||
overlays = [self.overlays.default];
|
|
||||||
};
|
|
||||||
|
|
||||||
packages.default = pkgs.my-derivation;
|
|
||||||
|
|
||||||
devShells.default = pkgs.mkShell {
|
|
||||||
packages = [
|
|
||||||
pkgs.cmake-language-server
|
|
||||||
pkgs.cmake-format
|
|
||||||
pkgs.clang-tools
|
|
||||||
pkgs.gdb
|
|
||||||
];
|
|
||||||
inputsFrom = [self'.packages.default];
|
|
||||||
shellHook = ''
|
|
||||||
export CMAKE_EXPORT_COMPILE_COMMANDS=ON
|
|
||||||
'';
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
{
|
|
||||||
cmake,
|
|
||||||
stdenv,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
stdenv.mkDerivation (finalAttrs: {
|
|
||||||
pname = "my-derivation";
|
|
||||||
version = "0.1.0";
|
|
||||||
src = ../.;
|
|
||||||
nativeBuildInputs = [cmake];
|
|
||||||
buildInputs = [];
|
|
||||||
|
|
||||||
meta = {
|
|
||||||
description = "Hello World Binary";
|
|
||||||
mainProgram = "hello";
|
|
||||||
};
|
|
||||||
})
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
int main() {
|
|
||||||
puts("Hello, Flake!");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
# ^ make editor happy
|
|
||||||
|
|
||||||
#
|
|
||||||
# Use https://direnv.net/ to automatically load the dev shell.
|
|
||||||
#
|
|
||||||
|
|
||||||
if ! has nix_direnv_version || ! nix_direnv_version 3.0.4; then
|
|
||||||
source_url "https://raw.githubusercontent.com/nix-community/nix-direnv/3.0.4/direnvrc" "sha256-DzlYZ33mWF/Gs8DDeyjr8mnVmQGx7ASYqA5WlxwvBG4="
|
|
||||||
fi
|
|
||||||
|
|
||||||
watch_file nix/**
|
|
||||||
watch_file -- **/*.nix
|
|
||||||
# Adding files to git includes them in a flake
|
|
||||||
# But it is also a bit much reloading.
|
|
||||||
# watch_file .git/index .git/HEAD
|
|
||||||
use flake . --show-trace
|
|
||||||
3
templates/rust/.gitignore
vendored
3
templates/rust/.gitignore
vendored
@@ -1,3 +0,0 @@
|
|||||||
.direnv/
|
|
||||||
target/
|
|
||||||
result/
|
|
||||||
@@ -1,11 +0,0 @@
|
|||||||
[package]
|
|
||||||
name = "hello"
|
|
||||||
description = "A test rust binary"
|
|
||||||
publish = false
|
|
||||||
version = "0.1.0"
|
|
||||||
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[[bin]]
|
|
||||||
name = "hello"
|
|
||||||
path = "src/main.rs"
|
|
||||||
@@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
description = "Rust-Hello";
|
|
||||||
|
|
||||||
inputs = {
|
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
|
|
||||||
rust-overlay = {
|
|
||||||
url = "github:oxalica/rust-overlay";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
flake-utils.url = "github:numtide/flake-utils";
|
|
||||||
crate2nix = {
|
|
||||||
url = "github:nix-community/crate2nix";
|
|
||||||
inputs.nixpkgs.follows = "nixpkgs";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
outputs = inputs @ {
|
|
||||||
crate2nix,
|
|
||||||
flake-utils,
|
|
||||||
nixpkgs,
|
|
||||||
rust-overlay,
|
|
||||||
...
|
|
||||||
}:
|
|
||||||
flake-utils.lib.eachDefaultSystem (
|
|
||||||
system: let
|
|
||||||
# Overlay pkgs with rust-bin
|
|
||||||
overlays = [(import rust-overlay)];
|
|
||||||
pkgs = import nixpkgs {
|
|
||||||
inherit system overlays;
|
|
||||||
};
|
|
||||||
|
|
||||||
# Use rust-bin to generate the toolchain from rust-toolchain.toml
|
|
||||||
rust-toolchain = pkgs.rust-bin.fromRustupToolchainFile ./rust-toolchain.toml;
|
|
||||||
|
|
||||||
buildRustCrateForPkgs = _:
|
|
||||||
pkgs.buildRustCrate.override {
|
|
||||||
rustc = rust-toolchain; # Use rustc from toolchain
|
|
||||||
cargo = rust-toolchain; # Use cargo from toolchain
|
|
||||||
};
|
|
||||||
|
|
||||||
# Cargo.nix for IFD
|
|
||||||
generatedCargoNix = crate2nix.tools.${system}.generatedCargoNix {
|
|
||||||
name = "rustnix";
|
|
||||||
src = ./.;
|
|
||||||
};
|
|
||||||
|
|
||||||
cargoNix = import generatedCargoNix {
|
|
||||||
inherit pkgs buildRustCrateForPkgs;
|
|
||||||
};
|
|
||||||
in {
|
|
||||||
packages = rec {
|
|
||||||
hello = cargoNix.rootCrate.build;
|
|
||||||
default = hello;
|
|
||||||
};
|
|
||||||
|
|
||||||
devShell = pkgs.mkShell {
|
|
||||||
buildInputs = [rust-toolchain];
|
|
||||||
};
|
|
||||||
}
|
|
||||||
);
|
|
||||||
}
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
[toolchain]
|
|
||||||
channel = "1.85.0"
|
|
||||||
components = [ "rustfmt", "rustc-dev", "rust-analyzer", "rust-src"]
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
fn main() {
|
|
||||||
println!("{}", "Hello, world!");
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user