Updated extensions.
This commit is contained in:
80
README.md
80
README.md
@ -1 +1,79 @@
|
||||
Placeholder
|
||||
# TTYverse Extensions
|
||||
|
||||
This directory contains bundled extensions for TTYverse, the command-line fediverse client.
|
||||
|
||||
## Extension Loading
|
||||
|
||||
TTYverse uses a simple XDG-compliant extension system. Extensions are only loaded from:
|
||||
|
||||
**`~/.local/share/ttyverse/extensions/`** (XDG_DATA_HOME/ttyverse/extensions)
|
||||
|
||||
Extensions are loaded with the `-exts` flag:
|
||||
```bash
|
||||
perl ttyverse.pl -exts=soundpack
|
||||
perl ttyverse.pl -exts=extension1,extension2
|
||||
```
|
||||
|
||||
## Managing Extensions
|
||||
|
||||
Use the included management script to enable/disable bundled extensions:
|
||||
|
||||
```bash
|
||||
# Show available and enabled extensions
|
||||
./extensions/manage-extensions.sh list
|
||||
|
||||
# Enable an extension (creates symlink in XDG directory)
|
||||
./extensions/manage-extensions.sh enable soundpack
|
||||
|
||||
# Disable an extension (removes from XDG directory)
|
||||
./extensions/manage-extensions.sh disable soundpack
|
||||
|
||||
# Check extension status
|
||||
./extensions/manage-extensions.sh status soundpack
|
||||
```
|
||||
|
||||
## Available Extensions
|
||||
|
||||
### soundpack.pl
|
||||
Plays notification sounds for different types of posts (timeline, replies, DMs, mentions, search results).
|
||||
|
||||
**Configuration options** (add to `~/.config/ttyverse/ttyverse.rc`):
|
||||
```
|
||||
extpref_sound_command=paplay # Sound player (paplay, play, ogg123, etc.)
|
||||
extpref_soundpack=default # Sound pack name
|
||||
```
|
||||
|
||||
**Sound files location**: `~/.local/share/ttyverse/sounds/default/`
|
||||
- `default.ogg` - Regular timeline posts
|
||||
- `mention.ogg` - Mentions of your username
|
||||
- `dm.ogg` - Direct messages
|
||||
- `me.ogg` - Your own posts
|
||||
- `follow.ogg` - New followers
|
||||
- `boost.ogg` - Your posts boosted
|
||||
- `favourite.ogg` - Your posts favourited
|
||||
- `poll.ogg` - Poll notifications
|
||||
- `announcement.ogg` - Server announcements
|
||||
|
||||
## Installing Custom Extensions
|
||||
|
||||
1. Copy your extension `.pl` file to `~/.local/share/ttyverse/extensions/`
|
||||
2. Load it with `-exts=yourextension`
|
||||
|
||||
## Extension Development
|
||||
|
||||
Extensions are Perl modules that hook into TTYverse's event system. Key variables:
|
||||
|
||||
- `$data` - XDG data directory (`~/.local/share/ttyverse`)
|
||||
- `$config` - XDG config directory (`~/.config/ttyverse`)
|
||||
- `$store` - Extension workspace (persistent storage)
|
||||
- `$silent` - Silent mode flag
|
||||
- `$stdout` - Output filehandle
|
||||
|
||||
Extensions can define these functions:
|
||||
- `$notifier` - Called for new posts
|
||||
- `$heartbeat` - Called periodically
|
||||
- `$handle` - Called for user commands
|
||||
- `$prepost` - Called before posting
|
||||
- `$postpost` - Called after posting
|
||||
|
||||
Set `$store->{'loaded'} = 1;` at the end of your extension.
|
70
libnotifyperl.pl
Normal file
70
libnotifyperl.pl
Normal file
@ -0,0 +1,70 @@
|
||||
# TTYverse Desktop Notifications Extension (libnotify-perl)
|
||||
# Adapted from original TTYtter extension
|
||||
# Provides desktop notifications using GTK Gtk2::Notify
|
||||
# Published under the Floodgap Free Software License: http://www.floodgap.com/software/ffsl/
|
||||
|
||||
# What is it?
|
||||
# This extension enables desktop notifications for TTYverse using the
|
||||
# libnotify system on Linux/Unix with GUI environments.
|
||||
|
||||
# Requirements:
|
||||
# - Gtk2::Notify Perl module
|
||||
# - GUI environment with DISPLAY set
|
||||
# - libnotify system installed
|
||||
|
||||
# Installation:
|
||||
# Install dependency: cpan Gtk2::Notify
|
||||
# Or on Debian/Ubuntu: sudo apt install libgtk2-notify-perl
|
||||
# Or on Fedora/RHEL: sudo dnf install perl-Gtk2-Notify
|
||||
# Or on Arch: sudo pacman -S perl-gtk2-notify
|
||||
|
||||
eval { require Gtk2::Notify };
|
||||
if($@){
|
||||
print "-- TTYverse notification extension requires Gtk2::Notify\n";
|
||||
print "-- Install with: cpan Gtk2::Notify\n";
|
||||
print "-- Or on Debian/Ubuntu: sudo apt install libgtk2-notify-perl\n";
|
||||
print "-- Or on Fedora/RHEL: sudo dnf install perl-Gtk2-Notify\n";
|
||||
print "-- Or on Arch: sudo pacman -S perl-gtk2-notify\n";
|
||||
die();
|
||||
}
|
||||
|
||||
sub notifier_libnotifyperl {
|
||||
# Skip notifications if no GUI display available
|
||||
return 1 if(!$ENV{'DISPLAY'});
|
||||
|
||||
my $class = shift;
|
||||
my $text = shift;
|
||||
my $ref = shift; # Post reference data (unused in this version)
|
||||
|
||||
# Handle initialization
|
||||
if (!defined($class) || !defined($notify_send_path)) {
|
||||
if (!defined($class)) {
|
||||
return 1 if ($script); # Skip in script mode
|
||||
$class = 'TTYverse Desktop Notifications';
|
||||
$text = 'Desktop notifications are now active for TTYverse.';
|
||||
Gtk2::Notify->init('ttyverse');
|
||||
print $streamout "-- $text\n" if (!$silent);
|
||||
}
|
||||
}
|
||||
|
||||
# Show notification if system is properly initialized
|
||||
if (Gtk2::Notify->is_initted()) {
|
||||
my $notification = Gtk2::Notify->new(
|
||||
"TTYverse: $class",
|
||||
$text
|
||||
);
|
||||
|
||||
# Set reasonable timeout (5 seconds)
|
||||
$notification->set_timeout(5_000);
|
||||
|
||||
if($notification->show()) {
|
||||
# Debug output (optional)
|
||||
# print $streamout "-- Notification shown: $class\n" if ($debug);
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Make sure the module loads properly
|
||||
1;
|
287
manage-extensions.sh
Executable file
287
manage-extensions.sh
Executable file
@ -0,0 +1,287 @@
|
||||
#!/usr/bin/env bash
|
||||
#
|
||||
# TTYverse Extension Manager
|
||||
# Simple XDG-compliant extension management for ~/.local/share/ttyverse/extensions/
|
||||
#
|
||||
|
||||
# XDG data directory for TTYverse
|
||||
DATA_DIR="${XDG_DATA_HOME:-$HOME/.local/share}/ttyverse"
|
||||
EXT_DIR="$DATA_DIR/extensions"
|
||||
BUNDLED_DIR="$(dirname "$0")"
|
||||
|
||||
# Colors for output (only if stdout is a terminal)
|
||||
if [[ -t 1 ]]; then
|
||||
GREEN='\033[0;32m'
|
||||
YELLOW='\033[1;33m'
|
||||
RED='\033[0;31m'
|
||||
NC='\033[0m'
|
||||
else
|
||||
GREEN=''
|
||||
YELLOW=''
|
||||
RED=''
|
||||
NC=''
|
||||
fi
|
||||
|
||||
# Ensure extension directory exists
|
||||
mkdir -p "$EXT_DIR"
|
||||
|
||||
show_help() {
|
||||
cat << EOF
|
||||
TTYverse Extension Manager
|
||||
|
||||
Usage: $0 <command> [extension_name]
|
||||
|
||||
Commands:
|
||||
list Show available and enabled extensions
|
||||
enable <ext> Enable an extension (symlink to XDG extensions directory)
|
||||
disable <ext> Disable an extension (remove from XDG extensions directory)
|
||||
status <ext> Show status of specific extension
|
||||
help Show this help
|
||||
|
||||
Examples:
|
||||
$0 list # Show all extensions
|
||||
$0 enable soundpack # Enable soundpack extension
|
||||
$0 disable soundpack # Disable soundpack extension
|
||||
$0 status soundpack # Check if soundpack is enabled
|
||||
|
||||
XDG Extensions Directory: $EXT_DIR
|
||||
Bundled Extensions: $BUNDLED_DIR
|
||||
|
||||
Note: TTYverse only loads extensions from the XDG directory.
|
||||
Use this script to enable/disable bundled extensions or install your own.
|
||||
EOF
|
||||
}
|
||||
|
||||
list_extensions() {
|
||||
echo -e "${GREEN}Available Extensions:${NC}"
|
||||
for ext in "$BUNDLED_DIR"/*.pl; do
|
||||
if [[ -f "$ext" ]]; then
|
||||
basename="${ext##*/}"
|
||||
name="${basename%.pl}"
|
||||
if [[ -L "$EXT_DIR/$basename" || -f "$EXT_DIR/$basename" ]]; then
|
||||
echo -e " ${GREEN}✓${NC} $name (enabled)"
|
||||
else
|
||||
echo -e " ${YELLOW}○${NC} $name (available)"
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
echo -e "\n${GREEN}User Extensions:${NC}"
|
||||
for ext in "$EXT_DIR"/*.pl; do
|
||||
if [[ -f "$ext" && ! -L "$ext" ]]; then
|
||||
basename="${ext##*/}"
|
||||
name="${basename%.pl}"
|
||||
echo -e " ${GREEN}●${NC} $name (user-installed)"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
enable_extension() {
|
||||
local name="$1"
|
||||
local ext_file="$name.pl"
|
||||
local bundled_path="$BUNDLED_DIR/$ext_file"
|
||||
local user_path="$EXT_DIR/$ext_file"
|
||||
|
||||
if [[ ! -f "$bundled_path" ]]; then
|
||||
echo -e "${RED}Error:${NC} Extension '$name' not found in bundled extensions"
|
||||
echo "Available extensions:"
|
||||
for ext in "$BUNDLED_DIR"/*.pl; do
|
||||
if [[ -f "$ext" ]]; then
|
||||
basename="${ext##*/}"
|
||||
echo " ${basename%.pl}"
|
||||
fi
|
||||
done
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -L "$user_path" ]]; then
|
||||
echo -e "${YELLOW}Warning:${NC} Extension '$name' is already enabled"
|
||||
return 0
|
||||
elif [[ -f "$user_path" ]]; then
|
||||
echo -e "${YELLOW}Warning:${NC} User-installed extension '$name' already exists"
|
||||
return 0
|
||||
fi
|
||||
|
||||
ln -s "$(realpath "$bundled_path")" "$user_path"
|
||||
echo -e "${GREEN}✓${NC} Enabled extension: $name"
|
||||
echo " Linked: $bundled_path -> $user_path"
|
||||
|
||||
# Special handling for soundpack extension - copy default sounds and configure RC
|
||||
if [[ "$name" == "soundpack" ]]; then
|
||||
local sounds_src="$BUNDLED_DIR/sounds"
|
||||
local sounds_dst="$DATA_DIR/sounds"
|
||||
local config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/ttyverse"
|
||||
local rc_file="$config_dir/ttyverserc"
|
||||
|
||||
# Copy sound files
|
||||
if [[ -d "$sounds_src" ]]; then
|
||||
echo " Copying bundled sound files..."
|
||||
cp -r "$sounds_src"/* "$sounds_dst/" 2>/dev/null || true
|
||||
echo -e "${GREEN}✓${NC} Copied default sound pack to $sounds_dst/"
|
||||
fi
|
||||
|
||||
# Auto-configure RC file
|
||||
mkdir -p "$config_dir"
|
||||
local needs_config=false
|
||||
|
||||
# Check if soundpack extension is already configured
|
||||
# Need to check for exts, notifytype, and notifies all being properly set
|
||||
local has_exts=false
|
||||
local has_notifytype=false
|
||||
local has_notifies=false
|
||||
|
||||
if [[ -f "$rc_file" ]]; then
|
||||
grep -q "^exts.*soundpack" "$rc_file" 2>/dev/null && has_exts=true
|
||||
grep -q "^notifytype=.*soundpack" "$rc_file" 2>/dev/null && has_notifytype=true
|
||||
grep -q "^notifies=.*mention.*boost.*favourite" "$rc_file" 2>/dev/null && has_notifies=true
|
||||
fi
|
||||
|
||||
if [[ "$has_exts" == "false" ]] || [[ "$has_notifytype" == "false" ]] || [[ "$has_notifies" == "false" ]]; then
|
||||
needs_config=true
|
||||
fi
|
||||
|
||||
if [[ "$needs_config" == "true" ]]; then
|
||||
echo " Configuring TTYverse for sound notifications..."
|
||||
|
||||
# Create backup if RC file exists
|
||||
[[ -f "$rc_file" ]] && cp "$rc_file" "$rc_file.backup.$(date +%s)"
|
||||
|
||||
# Update or create exts line
|
||||
if [[ -f "$rc_file" ]] && grep -q "^exts=" "$rc_file"; then
|
||||
# Check if soundpack is already in exts line
|
||||
if ! grep -q "^exts=.*soundpack" "$rc_file"; then
|
||||
sed -i 's/^exts=\(.*\)/exts=\1,soundpack/' "$rc_file"
|
||||
echo " Added soundpack to existing exts line"
|
||||
fi
|
||||
else
|
||||
# Add new exts line
|
||||
echo "exts=soundpack" >> "$rc_file"
|
||||
echo " Added exts=soundpack"
|
||||
fi
|
||||
|
||||
# Add or update notifytype
|
||||
if [[ -f "$rc_file" ]] && grep -q "^notifytype=" "$rc_file"; then
|
||||
sed -i 's/^notifytype=.*/notifytype=soundpack/' "$rc_file"
|
||||
echo " Updated notifytype to soundpack"
|
||||
else
|
||||
echo "notifytype=soundpack" >> "$rc_file"
|
||||
echo " Added notifytype=soundpack"
|
||||
fi
|
||||
|
||||
# Add or update notifies parameter for sound events
|
||||
if [[ -f "$rc_file" ]] && grep -q "^notifies=" "$rc_file"; then
|
||||
# Update existing notifies line to include fediverse sound types
|
||||
sed -i 's/^notifies=.*/notifies=default,mention,dm,me,follow,boost,favourite/' "$rc_file"
|
||||
echo " Updated existing notifies configuration"
|
||||
else
|
||||
# Add new notifies line
|
||||
echo "notifies=default,mention,dm,me,follow,boost,favourite" >> "$rc_file"
|
||||
echo " Added notifies configuration"
|
||||
fi
|
||||
|
||||
# Add extension preferences
|
||||
{
|
||||
echo ""
|
||||
echo "# Sound notifications (added by extension manager)"
|
||||
echo "extpref_sound_command=paplay"
|
||||
echo "extpref_soundpack=default"
|
||||
echo ""
|
||||
echo "# Fediverse sound types: default, mention, dm, me, follow, boost, favourite, poll, announcement"
|
||||
} >> "$rc_file"
|
||||
|
||||
echo -e "${GREEN}✓${NC} Configured TTYverse RC file for sound notifications"
|
||||
echo " Restart TTYverse to enable sounds automatically"
|
||||
else
|
||||
echo -e "${YELLOW}Note:${NC} Soundpack already configured in RC file"
|
||||
fi
|
||||
fi
|
||||
}
|
||||
|
||||
disable_extension() {
|
||||
local name="$1"
|
||||
local ext_file="$name.pl"
|
||||
local user_path="$EXT_DIR/$ext_file"
|
||||
|
||||
if [[ ! -e "$user_path" ]]; then
|
||||
echo -e "${YELLOW}Warning:${NC} Extension '$name' is not enabled"
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ -L "$user_path" ]]; then
|
||||
rm "$user_path"
|
||||
echo -e "${GREEN}✓${NC} Disabled extension: $name"
|
||||
|
||||
# Special handling for soundpack - offer to remove from RC file
|
||||
if [[ "$name" == "soundpack" ]]; then
|
||||
local config_dir="${XDG_CONFIG_HOME:-$HOME/.config}/ttyverse"
|
||||
local rc_file="$config_dir/ttyverserc"
|
||||
|
||||
if [[ -f "$rc_file" ]] && grep -q "soundpack" "$rc_file"; then
|
||||
echo -e "${YELLOW}Note:${NC} Soundpack is still configured in $rc_file"
|
||||
echo " You may want to remove the soundpack lines to fully disable"
|
||||
echo " Or run TTYverse without -exts=soundpack to override"
|
||||
fi
|
||||
fi
|
||||
elif [[ -f "$user_path" ]]; then
|
||||
echo -e "${YELLOW}Warning:${NC} '$name' is a user-installed extension (not a symlink)"
|
||||
echo "Remove manually if needed: $user_path"
|
||||
fi
|
||||
}
|
||||
|
||||
show_status() {
|
||||
local name="$1"
|
||||
local ext_file="$name.pl"
|
||||
local bundled_path="$BUNDLED_DIR/$ext_file"
|
||||
local user_path="$EXT_DIR/$ext_file"
|
||||
|
||||
echo "Extension: $name"
|
||||
echo "Bundled: $([[ -f "$bundled_path" ]] && echo "Available" || echo "Not found")"
|
||||
|
||||
if [[ -L "$user_path" ]]; then
|
||||
echo -e "Status: ${GREEN}Enabled${NC} (symlinked)"
|
||||
echo "Target: $(readlink "$user_path")"
|
||||
elif [[ -f "$user_path" ]]; then
|
||||
echo -e "Status: ${GREEN}Enabled${NC} (user-installed)"
|
||||
else
|
||||
echo -e "Status: ${YELLOW}Disabled${NC}"
|
||||
fi
|
||||
}
|
||||
|
||||
# Main command handling
|
||||
case "${1:-help}" in
|
||||
list|ls)
|
||||
list_extensions
|
||||
;;
|
||||
enable)
|
||||
if [[ -z "$2" ]]; then
|
||||
echo -e "${RED}Error:${NC} Extension name required"
|
||||
echo "Usage: $0 enable <extension_name>"
|
||||
exit 1
|
||||
fi
|
||||
enable_extension "$2"
|
||||
;;
|
||||
disable)
|
||||
if [[ -z "$2" ]]; then
|
||||
echo -e "${RED}Error:${NC} Extension name required"
|
||||
echo "Usage: $0 disable <extension_name>"
|
||||
exit 1
|
||||
fi
|
||||
disable_extension "$2"
|
||||
;;
|
||||
status)
|
||||
if [[ -z "$2" ]]; then
|
||||
echo -e "${RED}Error:${NC} Extension name required"
|
||||
echo "Usage: $0 status <extension_name>"
|
||||
exit 1
|
||||
fi
|
||||
show_status "$2"
|
||||
;;
|
||||
help|--help|-h)
|
||||
show_help
|
||||
;;
|
||||
*)
|
||||
echo -e "${RED}Error:${NC} Unknown command: $1"
|
||||
echo "Run '$0 help' for usage information"
|
||||
exit 1
|
||||
;;
|
||||
esac
|
76
soundpack.pl
Normal file
76
soundpack.pl
Normal file
@ -0,0 +1,76 @@
|
||||
# TTYverse Sound Pack Extension
|
||||
# Adapted from the original TTYtter soundpack by Storm Dragon: https://stormux.org/
|
||||
# Support Storm Dragon's work: https://patreon.com/stormux
|
||||
# Published under the Floodgap Free Software License: http://www.floodgap.com/software/ffsl/
|
||||
|
||||
# Plays sounds for different fediverse activities:
|
||||
# Core: default, mention, dm, me
|
||||
# Fediverse: follow, boost, favourite, poll, announcement
|
||||
#
|
||||
# Configure in RC file with:
|
||||
# extpref_sound_command=paplay # Sound command (paplay, play, ogg123, etc.)
|
||||
# extpref_soundpack=default # Sound pack name
|
||||
# notifytype=soundpack # Enable sound notifications
|
||||
# notifies=default,mention,dm,me,follow,boost,favourite
|
||||
|
||||
sub notifier_soundpack {
|
||||
my $class = shift;
|
||||
my $text = shift;
|
||||
my $ref = shift;
|
||||
|
||||
# Debug output
|
||||
print $stdout "-- DEBUG: soundpack notifier called with class='$class'\n" if (defined($class) && $verbose);
|
||||
|
||||
# Determine sound command (default to paplay for modern Linux)
|
||||
my $sound_command;
|
||||
if (!$extpref_sound_command) {
|
||||
$sound_command = "paplay"; # Modern default for PulseAudio
|
||||
} else {
|
||||
$sound_command = $extpref_sound_command;
|
||||
}
|
||||
|
||||
# Determine sound pack name
|
||||
my $sound_pack;
|
||||
if (!$extpref_soundpack) {
|
||||
$sound_pack = "default";
|
||||
} else {
|
||||
$sound_pack = $extpref_soundpack;
|
||||
}
|
||||
|
||||
# Skip if silent mode enabled
|
||||
return 1 if ($silent);
|
||||
|
||||
if (!defined($class)) {
|
||||
# Initialize - show loaded message
|
||||
print $stdout "-- TTYverse sound pack loaded: $sound_pack\n";
|
||||
print $stdout "-- Supported sounds: default, mention, dm, me, follow, boost, favourite, poll, announcement\n" if (!$silent);
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Build sound file path using XDG data directory
|
||||
my $data_dir = "$ENV{'HOME'}/.local/share/ttyverse";
|
||||
my $sound_file = "$data_dir/sounds/$sound_pack/" . lc($class) . ".ogg";
|
||||
|
||||
if (!-f $sound_file) {
|
||||
# Only warn once per session per class
|
||||
my $warn_key = "warned_missing_sound_$class";
|
||||
if (!$store->{$warn_key}) {
|
||||
print $stdout "-- Warning: Sound file '$class.ogg' not found in pack '$sound_pack'\n";
|
||||
print $stdout "-- Place sound files in $data_dir/sounds/$sound_pack/\n";
|
||||
$store->{$warn_key} = 1;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Play the sound in background (suppress output)
|
||||
print $stdout "-- DEBUG: Playing sound: $sound_command \"$sound_file\"\n" if ($verbose);
|
||||
system("$sound_command \"$sound_file\" >/dev/null 2>&1 &");
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
# Mark extension as successfully loaded
|
||||
$store->{'loaded'} = 1;
|
||||
|
||||
# Extension loaded successfully
|
||||
1;
|
4
sounds/.gitattributes
vendored
Normal file
4
sounds/.gitattributes
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
*.wav filter=lfs diff=lfs merge=lfs -text
|
||||
*.mp3 filter=lfs diff=lfs merge=lfs -text
|
||||
*.opus filter=lfs diff=lfs merge=lfs -text
|
||||
*.ogg filter=lfs diff=lfs merge=lfs -text
|
119
sounds/README.md
Normal file
119
sounds/README.md
Normal file
@ -0,0 +1,119 @@
|
||||
# TTYverse Sound Packs
|
||||
|
||||
TTYverse supports audio notifications for different types of fediverse activity. Sound packs are collections of audio files that play when specific events occur.
|
||||
|
||||
## Quick Start
|
||||
|
||||
1. **Enable sounds**: Use the extension manager to enable the soundpack extension:
|
||||
```bash
|
||||
./extensions/manage-extensions.sh enable soundpack
|
||||
```
|
||||
|
||||
2. **Configure TTYverse**: Add to your `~/.config/ttyverse/ttyverserc`:
|
||||
```
|
||||
notifytype=soundpack
|
||||
notifies=default,mention,dm,me,search,follow,boost,favourite
|
||||
extpref_soundpack=default
|
||||
extpref_sound_command=paplay
|
||||
```
|
||||
|
||||
3. **Test**: Start TTYverse and you should hear sounds for different activities!
|
||||
|
||||
## Sound Pack Structure
|
||||
|
||||
Sound packs are stored in `~/.local/share/ttyverse/sounds/` with this structure:
|
||||
```
|
||||
sounds/
|
||||
├── default/ # Default sound pack (included)
|
||||
│ ├── default.ogg # Regular posts
|
||||
│ ├── mention.ogg # @mentions of you
|
||||
│ ├── dm.ogg # Direct messages
|
||||
│ ├── me.ogg # Your own posts
|
||||
│ ├── follow.ogg # New followers
|
||||
│ ├── boost.ogg # Your posts boosted
|
||||
│ ├── favourite.ogg # Your posts favourited
|
||||
│ ├── poll.ogg # Poll notifications
|
||||
│ └── announcement.ogg # Server announcements
|
||||
├── custom/ # Your custom sound pack
|
||||
│ └── *.ogg
|
||||
└── README.md # This file
|
||||
```
|
||||
|
||||
## Required Sound Files
|
||||
|
||||
### Core Sounds (Essential)
|
||||
- **`default.ogg`** - Regular timeline posts
|
||||
- **`mention.ogg`** - When someone @mentions you
|
||||
- **`dm.ogg`** - Direct messages received
|
||||
- **`me.ogg`** - Your own posts (optional feedback)
|
||||
|
||||
### Fediverse Interaction Sounds
|
||||
- **`follow.ogg`** - Someone follows you
|
||||
- **`boost.ogg`** - Someone boosts (shares) your post
|
||||
- **`favourite.ogg`** - Someone favourites (likes) your post
|
||||
- **`poll.ogg`** - Poll results or poll you voted in ends
|
||||
- **`announcement.ogg`** - Server announcements
|
||||
|
||||
## Creating Custom Sound Packs
|
||||
|
||||
1. **Create directory**: Make a new directory under `sounds/` with your pack name:
|
||||
```bash
|
||||
mkdir -p ~/.local/share/ttyverse/sounds/mystyle
|
||||
```
|
||||
|
||||
2. **Add sound files**: Place `.ogg` files with the required names. All files should be:
|
||||
- **Format**: OGG Vorbis (most compatible)
|
||||
- **Length**: 1-3 seconds recommended (short and sweet)
|
||||
- **Volume**: Normalized to prevent startling users
|
||||
- **Sample Rate**: 44.1kHz or 48kHz
|
||||
|
||||
3. **Configure TTYverse**: Update your config to use the new pack:
|
||||
```
|
||||
extpref_soundpack=mystyle
|
||||
```
|
||||
|
||||
4. **Test**: Restart TTYverse to load the new sounds
|
||||
|
||||
## Audio Format Support
|
||||
|
||||
TTYverse uses your system's audio command for playback. Supported formats depend on your audio player:
|
||||
|
||||
- **paplay** (PulseAudio default): OGG, WAV, FLAC
|
||||
- **play** (SoX): Most formats including MP3, OGG, WAV
|
||||
- **ogg123**: OGG Vorbis only
|
||||
- **mpv**: Most formats including MP3, OGG, WAV, FLAC
|
||||
|
||||
Configure your preferred player with:
|
||||
```
|
||||
extpref_sound_command=paplay # or play, ogg123, mpv, etc.
|
||||
```
|
||||
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### No Sound
|
||||
1. Check audio command: `paplay /usr/share/sounds/alsa/Front_Left.wav`
|
||||
2. Verify sound pack path: `ls ~/.local/share/ttyverse/sounds/`
|
||||
3. Check TTYverse config: `grep -E "(notifytype|soundpack)" ~/.config/ttyverse/ttyverserc`
|
||||
4. Test with verbose mode: TTYverse will show warnings for missing sounds
|
||||
|
||||
### Wrong Sounds Playing
|
||||
- Verify file names exactly match the required names (case-sensitive)
|
||||
- Check that you're using the correct sound pack name in config
|
||||
- Restart TTYverse after changing sound files
|
||||
|
||||
### Performance Issues
|
||||
- Use compressed formats like OGG instead of WAV
|
||||
- Keep sound files under 3 seconds
|
||||
- Use `&` in sound command for background playback (already handled by extension)
|
||||
|
||||
## Example Sound Pack Themes
|
||||
|
||||
### **Retro Gaming**
|
||||
Use classic 8-bit style beeps and boops for different actions
|
||||
|
||||
### **Natural Sounds**
|
||||
Bird calls, water drops, wind chimes for a calming experience
|
||||
|
||||
### **Minimal**
|
||||
Simple tones with different pitches for each notification type
|
BIN
sounds/default/announcement.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/announcement.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/boost.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/boost.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/default.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/default.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/dm.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/dm.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/favourite.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/favourite.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/follow.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/follow.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/me.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/me.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/mention.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/mention.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
BIN
sounds/default/poll.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/default/poll.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
60
timestamp.pl
Normal file
60
timestamp.pl
Normal file
@ -0,0 +1,60 @@
|
||||
# TTYverse Timestamp Extension
|
||||
# Modified by Storm Dragon: https://stormux.org/
|
||||
# Support Storm Dragon's work: https://patreon.com/stormux
|
||||
# Original concept from kosertech.com (see ttyverse.wiki/Extension-Development.md for development guide)
|
||||
# Published under the Floodgap Free Software License: http://www.floodgap.com/software/ffsl/
|
||||
|
||||
# What is it?
|
||||
# This extension adds timestamps before posts when 5 minutes or more have passed
|
||||
# between timeline updates, helping organize the flow of your fediverse timeline.
|
||||
|
||||
# Usage:
|
||||
# This extension works automatically. Load it when you start TTYverse or add it
|
||||
# to your configuration. The timestamp format is: -- HH:MMAM/PM --
|
||||
|
||||
$handle = sub {
|
||||
my $delayInSeconds = 60 * 5; # 5 minutes default
|
||||
my ($nsec,$nmin,$nhour,$nday,$nmon,$nyear) = localtime(time);
|
||||
|
||||
# Initialize timestamp tracking on first run
|
||||
if(!$Lib_firstrun){
|
||||
$Lib_firstrun = 1;
|
||||
print "-- TTYverse timestamp extension loaded\n" if (!$silent);
|
||||
$Lib_past = time;
|
||||
}
|
||||
|
||||
# Print timestamp if enough time has elapsed
|
||||
if($Lib_past < (time - $delayInSeconds)){
|
||||
$Lib_past = time;
|
||||
my $timeString = "-- ";
|
||||
my $timeOfDay = "AM";
|
||||
|
||||
# Convert to 12-hour format
|
||||
if ($nhour >= 12) {
|
||||
if ($nhour > 12) {
|
||||
$nhour = $nhour - 12;
|
||||
}
|
||||
$timeOfDay = "PM";
|
||||
}
|
||||
if (($nhour < 10) && ($nhour != 0)) {
|
||||
$timeString .= "0";
|
||||
}
|
||||
if ($nhour == 0) {
|
||||
$nhour = 12;
|
||||
$timeOfDay = "AM";
|
||||
}
|
||||
|
||||
$timeString .= "$nhour:";
|
||||
if ($nmin < 10) {
|
||||
$timeString .= "0";
|
||||
}
|
||||
$timeString .= "$nmin$timeOfDay";
|
||||
print $streamout "$timeString --\n" if (!$silent);
|
||||
}
|
||||
|
||||
# Allow TTYverse to handle displaying the post normally
|
||||
my $ref = shift;
|
||||
&defaulthandle($ref);
|
||||
|
||||
return 1;
|
||||
};
|
153
tts.pl
Normal file
153
tts.pl
Normal file
@ -0,0 +1,153 @@
|
||||
# TTYverse Text-to-Speech Extension
|
||||
# By Storm Dragon: https://stormux.org/
|
||||
# Support Storm Dragon's work: https://patreon.com/stormux
|
||||
# Published under the Floodgap Free Software License: http://www.floodgap.com/software/ffsl/
|
||||
|
||||
# What is it?
|
||||
# This extension uses text-to-speech to read incoming fediverse posts.
|
||||
# Multiple synthesizer engines are supported for accessibility.
|
||||
|
||||
# Usage:
|
||||
# Toggle TTS on/off: /tts
|
||||
# Get help: /tts help
|
||||
# Load extension when starting TTYverse or add to configuration
|
||||
|
||||
$addaction = sub {
|
||||
my $command = shift;
|
||||
my $speak = "";
|
||||
|
||||
# Get current TTS state from config
|
||||
my $tts_config = "$ENV{'HOME'}/.config/ttyverse/tts_enabled";
|
||||
if (-e $tts_config) {
|
||||
open TTSSETTINGS, $tts_config;
|
||||
$speak = <TTSSETTINGS>;
|
||||
close TTSSETTINGS;
|
||||
chomp($speak) if defined($speak);
|
||||
} else {
|
||||
$speak = 0;
|
||||
}
|
||||
|
||||
if ($command eq '/tts') {
|
||||
if ((!defined($speak)) || ($speak eq 1)) {
|
||||
$speak = 0;
|
||||
print $streamout "-- Text-to-speech disabled\n";
|
||||
} else {
|
||||
$speak = 1;
|
||||
print $streamout "-- Text-to-speech enabled\n";
|
||||
}
|
||||
|
||||
# Save new state
|
||||
open TTSSETTINGS, ">$tts_config";
|
||||
print TTSSETTINGS "$speak";
|
||||
close TTSSETTINGS;
|
||||
return 1;
|
||||
}
|
||||
|
||||
if ($command eq "/tts help") {
|
||||
my $ttsHelp = "TTYverse Text-to-Speech Extension\n\n" .
|
||||
"Commands:\n" .
|
||||
" /tts - Toggle speech on/off\n" .
|
||||
" /tts help - Show this help\n\n" .
|
||||
"Configuration (add to TTYverse config):\n\n" .
|
||||
"extpref_tts_synthesizer=synthName\n" .
|
||||
" Available: espeak (default), festival, pico, cepstral, mac\n\n" .
|
||||
"extpref_tts_language=languageCode\n" .
|
||||
" Default: en-US (supported by espeak and pico)\n\n" .
|
||||
"extpref_tts_rate=number\n" .
|
||||
" Speech rate, default: 175 (espeak only)\n\n" .
|
||||
"extpref_tts_variant=name\n" .
|
||||
" Voice variant/name (espeak variants, cepstral/mac voices)\n";
|
||||
print $streamout "$ttsHelp";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
$handle = sub {
|
||||
my $ref = shift;
|
||||
my $class = shift;
|
||||
|
||||
# Skip TTS during initial timeline load
|
||||
if ($last_id eq 0) {
|
||||
&defaulthandle($ref);
|
||||
return 1;
|
||||
}
|
||||
|
||||
my $speak = "";
|
||||
# Get TTS state from config
|
||||
my $tts_config = "$ENV{'HOME'}/.config/ttyverse/tts_enabled";
|
||||
if (-e $tts_config) {
|
||||
open TTSSETTINGS, $tts_config;
|
||||
$speak = <TTSSETTINGS>;
|
||||
close TTSSETTINGS;
|
||||
chomp($speak) if defined($speak);
|
||||
} else {
|
||||
$speak = 0;
|
||||
}
|
||||
|
||||
# Initialize TTS configuration
|
||||
my $soundCommand = "paplay"; # Default for modern Linux/PulseAudio
|
||||
my $synthesizer = $extpref_tts_synthesizer || "espeak";
|
||||
my $language = $extpref_tts_language || "en-US";
|
||||
my $variant = $extpref_tts_variant || "";
|
||||
my $rate = $extpref_tts_rate || "";
|
||||
|
||||
# Override sound command if configured
|
||||
if ($extpref_sound_command) {
|
||||
$soundCommand = $extpref_sound_command;
|
||||
}
|
||||
|
||||
# Extract post content for TTS
|
||||
my $postText = &descape($ref->{'account'}->{'display_name'} || $ref->{'account'}->{'username'}) .
|
||||
" posted: " . &descape($ref->{'content'});
|
||||
|
||||
# Make speech more accessible
|
||||
$postText =~ s/\"/ /g; # Remove quotes
|
||||
$postText =~ s/ \#/ hashtag /g; # Make hashtags readable
|
||||
$postText =~ s/https?:\/\/\S+/ link /g; # Simplify links
|
||||
$postText =~ s/www\./ /g; # Remove www
|
||||
$postText =~ s/\// forward slash /g; # Make slashes readable
|
||||
$postText =~ s/\\/ back slash /g; # Make backslashes readable
|
||||
$postText =~ s/\blol\b/ laughs out loud /gi; # Expand common abbreviations
|
||||
$postText =~ s/\brofl\b/ rolling on the floor laughing /gi;
|
||||
$postText =~ s/<[^>]*>//g; # Remove any remaining HTML
|
||||
|
||||
my $speechCommand = "";
|
||||
|
||||
# Configure synthesizer command
|
||||
if ($synthesizer eq "cepstral") {
|
||||
$speechCommand = "aoss swift ";
|
||||
if ($variant ne "") {
|
||||
$speechCommand .= "-n $variant ";
|
||||
}
|
||||
$speechCommand .= "\"$postText\"";
|
||||
} elsif ($synthesizer eq "espeak") {
|
||||
if ($rate eq "") {
|
||||
$rate = "175";
|
||||
}
|
||||
$speechCommand = "$synthesizer -v " . lc($language);
|
||||
if ($variant ne "") {
|
||||
$speechCommand .= "+$variant";
|
||||
}
|
||||
$speechCommand .= " -s $rate \"$postText\"";
|
||||
} elsif ($synthesizer eq "festival") {
|
||||
$speechCommand = "echo \"$postText\" | festival --tts";
|
||||
} elsif ($synthesizer eq "mac") {
|
||||
$speechCommand = "say ";
|
||||
if ($variant ne "") {
|
||||
$speechCommand .= "-v $variant ";
|
||||
}
|
||||
$speechCommand .= "\"$postText\"";
|
||||
} elsif ($synthesizer eq "pico") {
|
||||
$speechCommand = "pico2wave -l $language -w /tmp/ttyverse.wav \"$postText\" && $soundCommand /tmp/ttyverse.wav";
|
||||
}
|
||||
|
||||
# Speak the post if TTS is enabled
|
||||
if ($speak eq 1) {
|
||||
system("$speechCommand");
|
||||
}
|
||||
|
||||
# Allow TTYverse to display the post normally
|
||||
&defaulthandle($ref);
|
||||
return 1;
|
||||
};
|
Reference in New Issue
Block a user