ames icon indicating copy to clipboard operation
ames copied to clipboard

Is there a way to make it work in NixOS?

Open chrollorifat opened this issue 8 months ago • 6 comments

chrollorifat avatar May 21 '25 17:05 chrollorifat

Both @eshrh and I use nixos, but neither of us really actively use ames anymore, unfortunately. Of course the arch AUR package and Makefile will not work on nixos, but the general installation should still work as long as you have the requirements, which should be installable using the standard means.

Is there anything specific you can't get working?

stephen-huan avatar May 22 '25 10:05 stephen-huan

@stephen-huan since you also use Nixos, may I ask what setup you are using for japanese immersion?

chrollorifat avatar May 23 '25 10:05 chrollorifat

As someone who uses NixOS and ames, I can confirm it is fully functional (although I've never tested it without the wayland config). If you're having trouble running it, you're likely missing dependencies or trying to run it on wayland without the config in contrib/wayland. Make sure you have the dependencies installed with home-manager or environment.systemPackages, and you have the wayland config in $XDG_CONFIG_DIR/ames/config (and its dependencies) if you're on a wlroots-based compositor (or hyprland/KDE? YMMV). I'm also looking into making a package for my own flake for portability sake, I might post that here later if I can figure that out.

WaddlesPlays avatar May 24 '25 18:05 WaddlesPlays

@WaddlesPlays thanks for chiming in.

@stephen-huan since you also use Nixos, may I ask what setup you are using for japanese immersion?

Unfortunately the time I was learning Japanese is completely disjoint with my time on nixos, and the same is true for eshrh.

stephen-huan avatar May 24 '25 19:05 stephen-huan

Managed to write a package and even a home-manager module for ames, feel free to give it a shot! Simply overlay the package (and optionally override the optionals), import the module into your home-manager, use the options to set the card fields (you shouldn't have to if you use lapis or JPMN), and everything should work (please let me know if it doesn't)!

Here's the package:
# A package for ames, or "Anki Media Extractor Script".
# Known issues:
# - -w only works on x11 and sway

{ stdenvNoCC
, lib
, fetchFromGitHub
, bash
, libnotify # notify-send
, pulseaudio # pactl
, ffmpeg
, maim
, xdotool
, xclip
, grim
, slurp
, wl-clipboard # wl-copy, wl-paste
, pipewire # pw-record
, makeWrapper
, wlSupport ? true # wayland support
, pwSupport ? true # pw-record instead of ffmpeg/pactl, see ames#15 and ames#14
}:

let
  wlDeps = [
    grim
    slurp
    wl-clipboard
  ];

  x11Deps = [
    maim
    xdotool
    xclip
  ];

  pwDeps = [
    pipewire
  ];

  ffmpegDeps = [
    ffmpeg
    pulseaudio
  ];

  # resolve optionals
  wmDeps = if wlSupport then wlDeps else x11Deps;
  audioDeps = if pwSupport then pwDeps else ffmpegDeps;

  # final dependency list
  finalDeps = [
    bash
    libnotify
  ] ++ wmDeps ++ audioDeps;
in

stdenvNoCC.mkDerivation {
  pname = "ames";
  version = "138ebe7";

  src = fetchFromGitHub {
    owner = "eshrh";
    repo = "ames";
    rev = "138ebe7db91afcba10ad3f0b99207cd14021da09";
    hash = "sha256-watyBmREXKCR3VN8I+lyOnDmgTOFyhMUTEjejWqAQdI=";
  };

  buildInputs = finalDeps;
  nativeBuildInputs = [ makeWrapper ];

  installPhase = ''
    mkdir -p $out/bin
    cp ames.sh $out/bin/ames
    wrapProgram $out/bin/ames \
    --prefix PATH : ${lib.makeBinPath finalDeps}
  '';

  # access for home-manager modules to appropriately configure ames
  passthru = {
    inherit wlSupport pwSupport;
  };
}
Here's the module:
# A module for ames, to generate a config based on the package options
{
  config,
  lib,
  pkgs,
  ...
}:
let
  inherit (lib) mkOption types;
in
{
  options.programs.ames = {
    enable = lib.mkEnableOption "ames, the Anki Media Extractor Script";

    package = lib.mkPackageOption pkgs "ames" { nullable = true; };

    audioField = mkOption {
      type = types.str;
      default = "SentenceAudio";
      description = "Card field to insert audio recorded with -r into.";
    };

    picField = mkOption {
      type = types.str;
      default = "Picture";
      description = "Card field to insert screenshots into.";
    };
  };

  config =
    let
      cfg = config.programs.ames;
    in
    lib.mkIf cfg.enable {
      home.packages = lib.mkIf (cfg.package != null) [ cfg.package ];

    # Generate config for ames
    xdg.configFile."ames/config".text =
    let
      wlConfig = ''
        get_selection() {
            # get a region of the screen for future screenshotting.
            slurp
        }

        take_screenshot_region() {
            # function to take a screenshot of a given screen region.
            # $1 is the geometry of the region from get_selection().
            # $2 is the output file name.
            local -r geom="$1"
            local -r path="$2"
            grim -g "$geom" "$path"
        }

        take_screenshot_window() {
            # function to take a screenshot of the current window.
            # $1 is the output file name.
            local -r path="$1"
            swaymsg -t get_tree | jq -r '.. | select(.pid? and .visible?) | .rect | "\(.x),\(.y) \(.width)x\(.height)"' | grim -g - "$path"
        }

        copied_text() {
            # get the contents of the clipboard.
            wl-paste
        }

      '';

      pwConfig = ''
        record_function() {
            local -r audio_file="$1"
            pw-record -P '{ stream.capture.sink=true }' "$audio_file" 1> /dev/null &
        }

        record_start() {
            # begin recording audio.
            local -r audio_file="$(mktemp \
                                       "/tmp/pipewire-recording.XXXXXX.$AUDIO_FORMAT")"
            echo "$audio_file" > "$recording_toggle"

            record_function "$audio_file"
            echo "$!" >> "$recording_toggle"

            current_time >> "$recording_toggle"

            notify_record_start
        }

        record_end() {
            # end recording.
            local -r audio_file="$(sed -n "1p" "$recording_toggle")"
            local -r pid="$(sed -n "2p" "$recording_toggle")"
            local -r start_time="$(sed -n "3p" "$recording_toggle")"
            local -r duration="$(($(current_time) - start_time))"

            if [ "$duration" -le "$MINIMUM_DURATION" ]; then
                sleep "$((MINIMUM_DURATION - duration))e-3"
            fi

            rm "$recording_toggle"
            kill -15 "$pid"

            while [ "$(du "$audio_file" | awk '{ print $1 }')" -eq 0 ]; do
                true
            done

            store_file ''${audio_file}
            update_sound "$(basename -- "$audio_file")"

            notify_record_stop
        }
      '';
    in
    ''
      #!/usr/bin/env bash

      AUDIO_FIELD="${cfg.audioField}"
      SCREENSHOT_FIELD="${cfg.picField}"
      ${if pkgs.ames.passthru.wlSupport then wlConfig else ""}
      ${if pkgs.ames.passthru.pwSupport then pwConfig else ""}
    '';
  };
}

I haven't tested setting either of the optionals (wlSupport and pwSupport), but they should build fine. Maybe whenever I do I'll upstream it somewhere :^)

WaddlesPlays avatar May 25 '25 02:05 WaddlesPlays

I'd be happy to help/review if you submitted a PR to nixpkgs/home-manager, feel free to ping me. There's even precedent for this, cf. one of eshrh's other projects inori (https://github.com/NixOS/nixpkgs/pull/371762, https://github.com/nix-community/home-manager/pull/6289).

stephen-huan avatar May 25 '25 03:05 stephen-huan