initial commit

This commit is contained in:
sid 2026-02-23 20:50:47 +01:00
commit c094b5770c
113 changed files with 6879 additions and 0 deletions

16
pkgs/default.nix Normal file
View file

@ -0,0 +1,16 @@
{
pkgs ? import <nixpkgs>,
...
}:
{
gitingest = pkgs.python3Packages.callPackage ./gitingest { };
open-webui-desktop = pkgs.callPackage ./open-webui-desktop { };
otp = pkgs.callPackage ./otp { };
pdf2printable = pkgs.callPackage ./pdf2printable { };
transcribe = pkgs.callPackage ./transcribe { };
udiskie-dmenu = pkgs.callPackage ./udiskie-dmenu { };
yt2rss = pkgs.callPackage ./yt2rss { };
# spotify-to-tidal = pkgs.callPackage ./spotify-to-tidal { }; # FIXME
}

100
pkgs/gitingest/default.nix Normal file
View file

@ -0,0 +1,100 @@
{
lib,
buildPythonPackage,
fetchFromGitHub,
# Dependencies
setuptools,
click,
fastapi,
pathspec,
pydantic,
python-dotenv,
slowapi,
starlette,
tiktoken,
tomli,
uvicorn,
loguru,
# Tests
httpx,
jinja2,
gitMinimal,
pytest-asyncio,
pytest-mock,
pytestCheckHook,
python-multipart,
}:
buildPythonPackage rec {
pname = "gitingest";
version = "0.3.1";
pyproject = true;
src = fetchFromGitHub {
owner = "cyclotruc";
repo = "gitingest";
tag = "v${version}";
hash = "sha256-drsncGneZyOCC2GJbrDM+bf4QGI2luacxMhrmdk03l4=";
};
build-system = [
setuptools
];
dependencies = [
click
fastapi
pathspec
pydantic
python-dotenv
slowapi
starlette
tiktoken
tomli
uvicorn
httpx
loguru
];
pythonImportsCheck = [
"gitingest"
];
nativeCheckInputs = [
httpx
jinja2
gitMinimal
pytest-asyncio
pytest-mock
pytestCheckHook
python-multipart
];
doCheck = false;
disabledTests = [
# Tests require network
"test_cli_with_default_options"
"test_cli_with_options"
"test_cli_with_stdout_output"
"test_cli_writes_file"
"test_clone_specific_branch"
"test_include_ignore_patterns"
"test_ingest_with_gitignore"
"test_parse_query_with_branch"
"test_parse_query_without_host"
"test_run_ingest_query"
];
meta = {
changelog = "https://github.com/cyclotruc/gitingest/releases/tag/${src.tag}";
description = "Replace 'hub' with 'ingest' in any github url to get a prompt-friendly extract of a codebase";
homepage = "https://github.com/cyclotruc/gitingest";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ ];
mainProgram = "gitingest";
};
}

View file

@ -0,0 +1,68 @@
{
lib,
python3,
fetchFromGitHub,
}:
python3.pkgs.buildPythonApplication rec {
pname = "gitingest";
version = "0.3.1";
pyproject = true;
src = fetchFromGitHub {
owner = "coderamp-labs";
repo = "gitingest";
rev = "v${version}";
hash = "sha256-drsncGneZyOCC2GJbrDM+bf4QGI2luacxMhrmdk03l4=";
};
build-system = [
python3.pkgs.setuptools
python3.pkgs.wheel
];
dependencies = with python3.pkgs; [
click
httpx
loguru
pathspec
pydantic
python-dotenv
starlette
strenum
tiktoken
typing-extensions
];
optional-dependencies = with python3.pkgs; {
dev = [
eval-type-backport
pre-commit
pytest
pytest-asyncio
pytest-cov
pytest-mock
];
server = [
boto3
fastapi
prometheus-client
sentry-sdk
slowapi
uvicorn
];
};
pythonImportsCheck = [
"gitingest"
];
meta = {
description = "Replace 'hub' with 'ingest' in any GitHub URL to get a prompt-friendly extract of a codebase";
homepage = "https://github.com/coderamp-labs/gitingest";
changelog = "https://github.com/coderamp-labs/gitingest/blob/${src.rev}/CHANGELOG.md";
license = lib.licenses.mit;
maintainers = with lib.maintainers; [ ];
mainProgram = "gitingest";
};
}

View file

@ -0,0 +1,60 @@
{
lib,
buildNpmPackage,
fetchFromGitHub,
electron,
}:
buildNpmPackage rec {
pname = "open-webui-desktop";
version = "7e54042";
src = fetchFromGitHub {
owner = "open-webui";
repo = "desktop";
rev = "build-e${version}";
hash = "sha256-eW3B8CS2T46Z91JRAlZJ3rNxAru4p7eJwyxn6P20pnA=";
};
npmDepsHash = "sha256-HdkgbcLzY/9T26hpw6Jej8sUWlcIIn1FkJ7IVvG3P4o=";
makeCacheWritable = true;
# Create .npmrc to prevent scripts from running during install
postPatch = ''
cat >> .npmrc << 'EOF'
ignore-scripts=true
EOF
'';
preInstall = ''
sed -i '/postinstall/d' package.json
'';
npmRebuild = false;
buildPhase = ''
export ELECTRON_SKIP_BINARY_DOWNLOAD=1
npm run build
'';
installPhase = ''
mkdir -p $out/opt/${pname}
cp -r out $out/opt/${pname}/
cp -r resources $out/opt/${pname}/
cp -r node_modules $out/opt/${pname}/
mkdir -p $out/bin
makeWrapper ${electron}/bin/electron $out/bin/${pname} \
--add-flags "$out/opt/${pname}/out/main/index.js" \
--run "cd $out/opt/${pname}"
'';
meta = {
description = "Open WebUI Desktop 🌐 (Alpha)";
homepage = "https://github.com/open-webui/desktop";
# license = lib.licenses.TODO;
mainProgram = "open-webui-desktop";
platforms = lib.platforms.linux;
};
}

15
pkgs/otp/default.nix Normal file
View file

@ -0,0 +1,15 @@
{
writeShellScriptBin,
symlinkJoin,
...
}:
let
wrapped = writeShellScriptBin "otp" (builtins.readFile ./otp.sh);
in
symlinkJoin {
name = "otp";
paths = [
wrapped
];
}

25
pkgs/otp/otp.sh Normal file
View file

@ -0,0 +1,25 @@
#!/usr/bin/env bash
DMENU="bemenu"
OPTIONS="github\nth-koeln"
CHOICE=$(echo -e "$OPTIONS" | "$DMENU" -p "OTP:")
get_pass() {
pass otp -c "$1" 2>/dev/null
}
case "$CHOICE" in
"github")
get_pass "www/github.com"
;;
"th-koeln")
get_pass "www/login.th-koeln.de"
;;
*)
echo "Error: Unknown option '$CHOICE'"
exit 1
;;
esac
exit 0

View file

@ -0,0 +1,39 @@
{
writeShellScriptBin,
pdftk,
texlivePackages,
}:
let
_pdfjam = "${texlivePackages.pdfjam}/bin/pdfjam";
_pdftk = "${pdftk}/bin/pdftk";
in
writeShellScriptBin "pdf2printable" ''
if [ "$#" -ne 2 ]; then
echo "Usage: $0 input.pdf output.pdf"
exit 1
fi
input_pdf="$1"
output_pdf="$2"
even_pdf="even.pdf"
even_rotated_pdf="even_rotated.pdf"
landscape_pdf="landscape.pdf"
odd_pdf="odd.pdf"
# Convert the PDF to landscape
${_pdfjam} --landscape --nup 2x1 "$input_pdf" -o "$landscape_pdf"
# Split the PDF into odd and even pages
${_pdftk} "$landscape_pdf" cat odd output "$odd_pdf"
${_pdftk} "$landscape_pdf" cat even output "$even_pdf"
# Rotate the even pages by 180 degrees
${_pdfjam} --landscape "$even_pdf" --angle 180 --outfile "$even_rotated_pdf"
# Merge the odd and rotated even pages
${_pdftk} A="$odd_pdf" B="$even_rotated_pdf" shuffle A B output "$output_pdf"
rm "$odd_pdf" "$even_pdf" "$landscape_pdf" "$even_rotated_pdf"
''

View file

@ -0,0 +1,44 @@
{
lib,
python3,
fetchFromGitHub,
}:
python3.pkgs.buildPythonApplication rec {
pname = "spotify-to-tidal";
version = "1.0.4";
pyproject = true;
src = fetchFromGitHub {
owner = "spotify2tidal";
repo = "spotify_to_tidal";
rev = "v${version}";
hash = "sha256-NexwO4Qwv1P58QAgBHPfCf4Q/mhTicWHaRubh8En9AE=";
};
build-system = [
python3.pkgs.setuptools
python3.pkgs.wheel
];
dependencies = with python3.pkgs; [
pytest
pytest-mock
pyyaml
spotipy
sqlalchemy
tidalapi
tqdm
];
pythonImportsCheck = [
"spotify_to_tidal"
];
meta = {
description = "A command line tool for importing your Spotify playlists into Tidal";
homepage = "https://github.com/spotify2tidal/spotify_to_tidal";
license = lib.licenses.agpl3Only;
mainProgram = "spotify-to-tidal";
};
}

View file

@ -0,0 +1,22 @@
{
python3Packages,
...
}:
python3Packages.buildPythonApplication {
pname = "transcribe";
version = "1.0.0";
src = ./.;
pyproject = true;
build-system = [ python3Packages.setuptools ];
propagatedBuildInputs = [ python3Packages.openai ];
doCheck = false;
meta = {
description = "Transcribe a given audio file using the OpenAI API.";
};
}

7
pkgs/transcribe/setup.py Normal file
View file

@ -0,0 +1,7 @@
from setuptools import setup
setup(
name='transcribe',
version='1.0.0',
scripts=['transcribe'],
)

View file

@ -0,0 +1,47 @@
#!/usr/bin/env python3
import sys
import os
from openai import OpenAI
def transcribe_audio(file_path):
"""Transcribe the given audio file using OpenAI API."""
if not os.environ.get("OPENAI_API_KEY"):
print("Error: OPENAI_API_KEY environment variable is not set.")
return None
if not os.path.exists(file_path):
print(f"Error: File '{file_path}' not found.")
return None
try:
client = OpenAI()
with open(file_path, "rb") as audio_file:
transcription = client.audio.transcriptions.create(
# model="gpt-4o-transcribe",
model="whisper-1",
file=audio_file,
response_format="text"
)
return transcription
except Exception as e:
print(f"Error occurred during transcription: {e}")
return None
def main():
if len(sys.argv) != 2:
print("Usage: transcribe <audio_file_path>")
sys.exit(1)
audio_file_path = sys.argv[1]
transcription = transcribe_audio(audio_file_path)
if transcription:
print(transcription)
if __name__ == "__main__":
main()

1241
pkgs/udiskie-dmenu/Cargo.lock generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,9 @@
[package]
name = "udiskie-dmenu"
version = "0.1.0"
edition = "2021"
[dependencies]
notify-rust = "4.5.0"
serde = { version = "1.0", features = ["derive"] }
serde_json = "1.0"

View file

@ -0,0 +1,13 @@
{
lib,
rustPlatform,
...
}:
rustPlatform.buildRustPackage {
pname = "udiskie-dmenu";
version = "0.1.0";
cargoLock.lockFile = ./Cargo.lock;
src = lib.cleanSource ./.;
}

View file

@ -0,0 +1,190 @@
use notify_rust::Notification;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::io::{self, Write};
use std::process::{Command, Stdio};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct DeviceInfo {
label: Option<String>,
isLuks: Option<bool>,
mountPath: Option<String>,
devPath: String,
}
fn main() {
match run_udiskie_info() {
Ok(block_devices) => {
let options = parse_udiskie_info(&block_devices);
if options.is_empty() {
notify_if_err("Nothing to unmount / mount".to_string());
std::process::exit(0);
}
match get_selection(pretty_print(&options)) {
Ok(Some(selected)) => {
let parsed_selection = parse_selection(&selected, &options);
for device in parsed_selection {
process_device(&device);
}
}
Ok(None) => {} // User cancelled input, do nothing
Err(err) => notify_if_err(err),
}
}
Err(err) => notify_if_err(err),
}
}
fn run_udiskie_info() -> Result<Vec<DeviceInfo>, String> {
let output = Command::new("udiskie-info")
.args(&["-C", "-a", "-o", r#""label":"{ui_label}", "isLuks":"{is_luks}", "mountPath": "{mount_path}""#])
.output()
.map_err(|e| e.to_string())?;
if !output.status.success() {
return Err(format!(
"Error running `udiskie-info`: {}",
String::from_utf8_lossy(&output.stderr)
));
}
let stdout = String::from_utf8_lossy(&output.stdout);
parse_udiskie_json(&stdout)
}
fn parse_udiskie_json(json_lines: &str) -> Result<Vec<DeviceInfo>, String> {
json_lines
.lines()
.filter(|line| !line.is_empty())
.map(|line| {
let wrapped_line = format!("{{{}}}", line);
serde_json::from_str(&wrapped_line).map_err(|e| format!("JSON parsing error: {}", e))
})
.collect()
}
fn parse_udiskie_info(devices: &[DeviceInfo]) -> HashMap<String, DeviceInfo> {
let mut options: HashMap<String, DeviceInfo> = HashMap::new();
for device in devices {
if device.devPath.starts_with("/dev/loop") {
// Skip snap packages
continue;
}
let key = device.devPath.clone();
if let Some(existing) = options.get(&key) {
if existing.mountPath.is_some() && device.mountPath.is_none() {
continue;
}
if existing.isLuks.unwrap_or(false) && !device.isLuks.unwrap_or(false) {
continue;
}
}
options.insert(key, device.clone());
}
options
}
fn pretty_print(parsed_info: &HashMap<String, DeviceInfo>) -> String {
let mut output = String::new();
for (dev_path, device) in parsed_info {
let dev_path_padded = format!("{: <9}", dev_path);
let label_or_mount_path = device
.mountPath
.clone()
.or_else(|| device.label.clone())
.unwrap_or_else(|| "<unknown>".to_string());
output.push_str(&format!("{}: {}\n", dev_path_padded, label_or_mount_path));
}
output
}
fn get_selection(options: String) -> Result<Option<String>, String> {
let launcher = std::env::var("UDISKIE_DMENU_LAUNCHER").unwrap_or_else(|_| "dmenu".to_string());
let mut child = Command::new(launcher)
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.map_err(|e| e.to_string())?;
if let Some(stdin) = child.stdin.as_mut() {
stdin
.write_all(options.as_bytes())
.map_err(|e| e.to_string())?;
}
let output = child
.wait_with_output()
.map_err(|e| e.to_string())?;
match output.status.code() {
Some(0) | Some(10) => {
let selection = String::from_utf8_lossy(&output.stdout).to_string();
Ok(Some(selection))
}
Some(_) | None => Ok(None),
}
}
fn parse_selection(selection: &str, options: &HashMap<String, DeviceInfo>) -> Vec<DeviceInfo> {
let mut devices = Vec::new();
for line in selection.lines() {
if let Some((dev_path, _label_or_mount)) = line.split_once(":") {
let trimmed_path = dev_path.trim();
if let Some(device) = options.get(trimmed_path) {
devices.push(device.clone());
}
}
}
devices
}
fn notify_if_err(err: String) {
Notification::new()
.summary("Error")
.body(&err)
.show()
.ok();
eprintln!("{}", err);
}
fn process_device(device: &DeviceInfo) {
let udiskie_opt = if device.isLuks.unwrap_or(false) {
"--force"
} else {
""
};
if let Some(mount_path) = &device.mountPath {
run_command(
&format!("udiskie-umount {} \"{}\"", udiskie_opt, mount_path),
Some("Failed to unmount device"),
);
} else if let Some(label) = &device.label {
run_command(
&format!("udiskie-mount {} \"{}\"", udiskie_opt, device.devPath),
Some(&format!("Failed to mount device: {}", label)),
);
} else {
notify_if_err("Unknown device - aborting".to_string());
}
}
fn run_command(command: &str, error_msg: Option<&str>) {
let status = Command::new("sh")
.arg("-c")
.arg(command)
.status()
.unwrap_or_else(|e| panic!("Failed to execute command: {}", e));
if !status.success() {
if let Some(msg) = error_msg {
notify_if_err(msg.to_string());
}
}
}

15
pkgs/yt2rss/default.nix Normal file
View file

@ -0,0 +1,15 @@
{
writeShellScriptBin,
symlinkJoin,
...
}:
let
wrapped = writeShellScriptBin "yt2rss" (builtins.readFile ./yt2rss.sh);
in
symlinkJoin {
name = "create";
paths = [
wrapped
];
}

21
pkgs/yt2rss/yt2rss.sh Normal file
View file

@ -0,0 +1,21 @@
if [ $# -eq 0 ]; then
echo "Usage: $0 <url>"
exit 1
fi
url=$1
# Check if input URL is a playlist URL
if [[ "$url" == *"playlist"* ]]; then
playlist_id=$(echo "$url" | grep -o 'list=[A-Za-z0-9_-]*' | cut -d'=' -f2)
if [ -n "$playlist_id" ]; then
echo "https://www.youtube.com/feeds/videos.xml?playlist_id=$playlist_id"
else
echo "Could not extract playlist ID from URL."
fi
else
curl -s "$url" | grep -o 'https://www.youtube.com/feeds/videos.xml?channel_id=[A-Za-z0-9_-]*' | sort | uniq
fi
exit 0