Updated extensions information.
576
Extension-Development.md
Normal file
576
Extension-Development.md
Normal file
@ -0,0 +1,576 @@
|
|||||||
|
# Extension Development
|
||||||
|
|
||||||
|
TTYverse extensions are Perl scripts that integrate with TTYverse's event system to add custom functionality. This guide covers creating, testing, and deploying custom extensions.
|
||||||
|
|
||||||
|
## Extension Architecture
|
||||||
|
|
||||||
|
Extensions hook into TTYverse's multi-process architecture through defined callback functions:
|
||||||
|
|
||||||
|
- **`$handle`** - Called for each incoming post (main processing hook)
|
||||||
|
- **`$addaction`** - Called for user commands (adds new slash commands)
|
||||||
|
- **`$prepost`** - Called before sending posts
|
||||||
|
- **`$postpost`** - Called after sending posts
|
||||||
|
- **`$heartbeat`** - Called periodically for background tasks
|
||||||
|
- **`$notifier`** - Called for notification events (sounds, desktop alerts, etc.)
|
||||||
|
|
||||||
|
## Available Variables
|
||||||
|
|
||||||
|
Extensions have access to these TTYverse variables:
|
||||||
|
|
||||||
|
### Core Variables
|
||||||
|
- **`$whoami`** - Current user's username
|
||||||
|
- **`$silent`** - Silent mode flag (suppress output when true)
|
||||||
|
- **`$verbose`** - Verbose mode flag (show debug info when true)
|
||||||
|
- **`$stdout`** - Output filehandle for user messages
|
||||||
|
- **`$streamout`** - Output filehandle for timeline content
|
||||||
|
|
||||||
|
### File Paths
|
||||||
|
- **`$data`** - XDG data directory (`~/.local/share/ttyverse`)
|
||||||
|
- **`$config`** - XDG config directory (`~/.config/ttyverse`)
|
||||||
|
- **`$store`** - Extension persistent storage hash
|
||||||
|
|
||||||
|
### Post Processing
|
||||||
|
- **`&defaulthandle($ref)`** - Default post display function
|
||||||
|
- **`&standardpost($ref, $text_only)`** - Format post for notifications
|
||||||
|
- **`&findtarget($code)`** - Find post by menu code (a1, b3, etc.)
|
||||||
|
- **`&descape($text)`** - Decode HTML entities and escape sequences safely
|
||||||
|
- **`&common_split_post($text, $reply_to, $media)`** - Send posts via TTYverse
|
||||||
|
|
||||||
|
### Timeline State
|
||||||
|
- **`$last_id`** - Current timeline position (0 during initial load)
|
||||||
|
- **`$initial_load_in_progress`** - True during startup timeline fetch
|
||||||
|
|
||||||
|
### Environment Access
|
||||||
|
- **`$ENV{'HOME'}`** - User's home directory
|
||||||
|
- **`$ENV{'DISPLAY'}`** - X11 display (for GUI detection)
|
||||||
|
- **`$ENV{'XDG_DATA_HOME'}`** - XDG data directory override
|
||||||
|
- **`$ENV{'XDG_CONFIG_HOME'}`** - XDG config directory override
|
||||||
|
|
||||||
|
## Extension Types
|
||||||
|
|
||||||
|
### 1. Post Processing Extensions
|
||||||
|
|
||||||
|
Handle incoming posts and modify display:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
$handle = sub {
|
||||||
|
my $post_ref = shift;
|
||||||
|
my $class = shift; # Notification class (default, mention, dm, etc.)
|
||||||
|
|
||||||
|
# Your custom processing here
|
||||||
|
# Access post data: $post_ref->{'content'}, $post_ref->{'account'}->{'username'}
|
||||||
|
|
||||||
|
# Always call default handler to display the post
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Command Extensions
|
||||||
|
|
||||||
|
Add new slash commands:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
$addaction = sub {
|
||||||
|
my $command_line = $_; # Full command line input
|
||||||
|
|
||||||
|
if ($command_line =~ /^\/mycommand\s+(.*)$/) {
|
||||||
|
my $args = $1;
|
||||||
|
|
||||||
|
# Process your command
|
||||||
|
print $streamout "-- My command executed with: $args\n";
|
||||||
|
return 1; # Command handled
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; # Not our command, let TTYverse handle it
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Notification Extensions
|
||||||
|
|
||||||
|
Handle sound, visual, or other notifications:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
sub notifier_mynotifier {
|
||||||
|
my $class = shift; # Notification type (dm, mention, boost, etc.)
|
||||||
|
my $text = shift; # Formatted notification text
|
||||||
|
my $post_ref = shift; # Original post data
|
||||||
|
|
||||||
|
# Handle initialization (called with no $class)
|
||||||
|
if (!defined($class)) {
|
||||||
|
print $stdout "-- My notifier loaded\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Process notification based on class
|
||||||
|
if ($class eq 'dm') {
|
||||||
|
# Handle direct messages with higher priority
|
||||||
|
} elsif ($class eq 'mention') {
|
||||||
|
# Handle mentions
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Register the notifier (must be done globally)
|
||||||
|
# TTYverse automatically finds functions named notifier_*
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Time-based Extensions
|
||||||
|
|
||||||
|
Extensions that perform actions based on time intervals:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Extension global variables for state tracking
|
||||||
|
my $last_action_time = 0;
|
||||||
|
my $first_run = 0;
|
||||||
|
|
||||||
|
$handle = sub {
|
||||||
|
my $post_ref = shift;
|
||||||
|
|
||||||
|
# Initialize on first run
|
||||||
|
if (!$first_run) {
|
||||||
|
$first_run = 1;
|
||||||
|
$last_action_time = time;
|
||||||
|
print $stdout "-- Time-based extension loaded\n" if (!$silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check if enough time has passed (5 minutes = 300 seconds)
|
||||||
|
my $current_time = time;
|
||||||
|
if ($current_time - $last_action_time >= 300) {
|
||||||
|
$last_action_time = $current_time;
|
||||||
|
|
||||||
|
# Perform periodic action
|
||||||
|
my ($sec,$min,$hour,$day,$mon,$year) = localtime($current_time);
|
||||||
|
my $timestamp = sprintf("%02d:%02d", $hour, $min);
|
||||||
|
print $streamout "-- $timestamp --\n" if (!$silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Always call default handler
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Configuration and State Management
|
||||||
|
|
||||||
|
### RC File Configuration
|
||||||
|
|
||||||
|
Extensions can use configuration variables from the user's RC file:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# In user's ~/.config/ttyverse/ttyverserc:
|
||||||
|
# extpref_myext_setting=value
|
||||||
|
# extpref_myext_enabled=1
|
||||||
|
|
||||||
|
# In your extension:
|
||||||
|
my $setting = $extpref_myext_setting || "default_value";
|
||||||
|
my $enabled = $extpref_myext_enabled || 0;
|
||||||
|
```
|
||||||
|
|
||||||
|
### File-based Configuration Storage
|
||||||
|
|
||||||
|
For settings that change during runtime, use separate config files:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Read extension-specific config file
|
||||||
|
my $config_file = "$ENV{'HOME'}/.config/ttyverse/myext_settings";
|
||||||
|
my $setting_value;
|
||||||
|
|
||||||
|
if (-e $config_file) {
|
||||||
|
open my $fh, '<', $config_file or die "Cannot read config: $!";
|
||||||
|
$setting_value = <$fh>;
|
||||||
|
close $fh;
|
||||||
|
chomp($setting_value) if defined($setting_value);
|
||||||
|
} else {
|
||||||
|
$setting_value = "default";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Write extension-specific config file
|
||||||
|
sub save_setting {
|
||||||
|
my $value = shift;
|
||||||
|
my $config_file = "$ENV{'HOME'}/.config/ttyverse/myext_settings";
|
||||||
|
|
||||||
|
open my $fh, '>', $config_file or die "Cannot write config: $!";
|
||||||
|
print $fh $value;
|
||||||
|
close $fh;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### XDG Directory Handling
|
||||||
|
|
||||||
|
Use XDG standards for cross-platform compatibility:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Get XDG-compliant data directory
|
||||||
|
my $data_dir = $ENV{'XDG_DATA_HOME'} || "$ENV{'HOME'}/.local/share";
|
||||||
|
my $ext_data_dir = "$data_dir/ttyverse";
|
||||||
|
|
||||||
|
# Get XDG-compliant config directory
|
||||||
|
my $config_dir = $ENV{'XDG_CONFIG_HOME'} || "$ENV{'HOME'}/.config";
|
||||||
|
my $ext_config_dir = "$config_dir/ttyverse";
|
||||||
|
|
||||||
|
# Create directories if needed
|
||||||
|
mkdir $ext_data_dir unless -d $ext_data_dir;
|
||||||
|
mkdir $ext_config_dir unless -d $ext_config_dir;
|
||||||
|
```
|
||||||
|
|
||||||
|
### Persistent Storage with $store
|
||||||
|
|
||||||
|
Use the `$store` hash for data that persists during the TTYverse session:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Store data (survives between function calls)
|
||||||
|
$store->{'my_counter'} = 0;
|
||||||
|
$store->{'user_preferences'} = { volume => 50, enabled => 1 };
|
||||||
|
|
||||||
|
# Access stored data
|
||||||
|
my $count = $store->{'my_counter'} || 0;
|
||||||
|
$count++;
|
||||||
|
$store->{'my_counter'} = $count;
|
||||||
|
|
||||||
|
# Complex data structures
|
||||||
|
my $prefs = $store->{'user_preferences'} || {};
|
||||||
|
$prefs->{'last_used'} = time;
|
||||||
|
$store->{'user_preferences'} = $prefs;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Post Data Structure
|
||||||
|
|
||||||
|
Post references contain Mastodon API data:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
$post_ref = {
|
||||||
|
'id' => '12345',
|
||||||
|
'content' => 'Post text with <em>HTML</em>',
|
||||||
|
'account' => {
|
||||||
|
'username' => 'user',
|
||||||
|
'acct' => 'user@domain.com',
|
||||||
|
'display_name' => 'Display Name'
|
||||||
|
},
|
||||||
|
'mentions' => [
|
||||||
|
{
|
||||||
|
'username' => 'mentioned_user',
|
||||||
|
'acct' => 'mentioned_user@domain.com'
|
||||||
|
}
|
||||||
|
],
|
||||||
|
'created_at' => '2024-01-01T12:00:00Z',
|
||||||
|
'visibility' => 'public'
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## Notification Classes
|
||||||
|
|
||||||
|
TTYverse uses these notification classes:
|
||||||
|
|
||||||
|
- **`default`** - Regular timeline posts
|
||||||
|
- **`mention`** - Posts that mention your username
|
||||||
|
- **`dm`** - Direct messages (highest priority)
|
||||||
|
- **`me`** - Your own posts
|
||||||
|
- **`follow`** - New followers
|
||||||
|
- **`boost`** - Your posts were boosted/shared
|
||||||
|
- **`favourite`** - Your posts were favourited/liked
|
||||||
|
- **`poll`** - Poll notifications
|
||||||
|
- **`announcement`** - Server announcements
|
||||||
|
|
||||||
|
## Example: Complete Extension
|
||||||
|
|
||||||
|
Here's a comprehensive example extension that demonstrates multiple patterns:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Advanced Custom Extension
|
||||||
|
# Adds /greet command and tracks greeting statistics
|
||||||
|
# Demonstrates configuration, state management, and safe text processing
|
||||||
|
|
||||||
|
# Extension configuration with defaults
|
||||||
|
my $enabled = $extpref_greet_enabled || 1;
|
||||||
|
my $greeting_style = $extpref_greet_style || "friendly";
|
||||||
|
|
||||||
|
# Initialize extension state
|
||||||
|
if (!$store->{'greet_loaded'}) {
|
||||||
|
$store->{'greet_loaded'} = 1;
|
||||||
|
$store->{'greet_count'} = 0;
|
||||||
|
print $stdout "-- Greeting extension loaded (style: $greeting_style)\n" if (!$silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Command handler
|
||||||
|
$addaction = sub {
|
||||||
|
my $command = $_;
|
||||||
|
|
||||||
|
# Toggle extension on/off
|
||||||
|
if ($command eq '/greet toggle') {
|
||||||
|
my $config_file = "$ENV{'HOME'}/.config/ttyverse/greet_enabled";
|
||||||
|
my $new_state = $enabled ? 0 : 1;
|
||||||
|
|
||||||
|
open my $fh, '>', $config_file or die "Cannot save config: $!";
|
||||||
|
print $fh $new_state;
|
||||||
|
close $fh;
|
||||||
|
|
||||||
|
$enabled = $new_state;
|
||||||
|
my $status = $enabled ? "enabled" : "disabled";
|
||||||
|
print $streamout "-- Greeting extension $status\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Show greeting statistics
|
||||||
|
if ($command eq '/greet stats') {
|
||||||
|
my $count = $store->{'greet_count'} || 0;
|
||||||
|
print $streamout "-- Total greetings sent: $count\n";
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send greeting
|
||||||
|
if ($command =~ /^\/greet\s+(\S+)\s*(.*)$/) {
|
||||||
|
return 0 unless $enabled; # Respect user preference
|
||||||
|
|
||||||
|
my $username = $1;
|
||||||
|
my $custom_message = $2;
|
||||||
|
|
||||||
|
# Clean and validate username
|
||||||
|
$username = &descape($username);
|
||||||
|
$username =~ s/^@//; # Remove @ if user included it
|
||||||
|
|
||||||
|
# Choose greeting based on style and custom message
|
||||||
|
my $greeting;
|
||||||
|
if ($custom_message) {
|
||||||
|
$greeting = &descape($custom_message);
|
||||||
|
} elsif ($greeting_style eq "formal") {
|
||||||
|
$greeting = "Good day!";
|
||||||
|
} elsif ($greeting_style eq "casual") {
|
||||||
|
$greeting = "Hey there! 😊";
|
||||||
|
} else { # friendly (default)
|
||||||
|
$greeting = "Hello! 👋";
|
||||||
|
}
|
||||||
|
|
||||||
|
# Send the greeting
|
||||||
|
my $post_text = "\@$username $greeting";
|
||||||
|
my $result = &common_split_post($post_text, undef, undef);
|
||||||
|
|
||||||
|
# Update statistics on success
|
||||||
|
if ($result) {
|
||||||
|
$store->{'greet_count'}++;
|
||||||
|
print $stdout "-- Greeting sent to $username (total: $store->{'greet_count'})\n" if ($verbose);
|
||||||
|
}
|
||||||
|
|
||||||
|
return $result;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0; # Not our command
|
||||||
|
};
|
||||||
|
|
||||||
|
# Post handler (optional - could add auto-greeting detection)
|
||||||
|
$handle = sub {
|
||||||
|
my $post_ref = shift;
|
||||||
|
my $class = shift;
|
||||||
|
|
||||||
|
# Skip during initial load
|
||||||
|
if ($last_id eq 0) {
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Could add logic here to detect greetings and respond
|
||||||
|
# For now, just process normally
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
# Extension successfully loaded
|
||||||
|
$store->{'loaded'} = 1;
|
||||||
|
|
||||||
|
# Required return value
|
||||||
|
1;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extension Development Workflow
|
||||||
|
|
||||||
|
### 1. Create Extension File
|
||||||
|
```bash
|
||||||
|
# Create extension in the extensions directory
|
||||||
|
~/.local/share/ttyverse/extensions/myextension.pl
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Test Extension
|
||||||
|
```bash
|
||||||
|
# Test Perl syntax
|
||||||
|
perl -c ~/.local/share/ttyverse/extensions/myextension.pl
|
||||||
|
|
||||||
|
# Load extension with TTYverse
|
||||||
|
./ttyverse.pl -exts=myextension -verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Debug Extension
|
||||||
|
Use verbose mode to see debug output:
|
||||||
|
```bash
|
||||||
|
./ttyverse.pl -exts=myextension -verbose
|
||||||
|
```
|
||||||
|
|
||||||
|
Add debug output in your extension:
|
||||||
|
```perl
|
||||||
|
print $stdout "-- DEBUG: My extension called\n" if ($verbose);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Advanced Extension Patterns
|
||||||
|
|
||||||
|
### Handling Initial Timeline Load
|
||||||
|
|
||||||
|
Prevent extension spam during startup by checking timeline state:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
$handle = sub {
|
||||||
|
my $post_ref = shift;
|
||||||
|
my $class = shift;
|
||||||
|
|
||||||
|
# Skip processing during initial timeline load
|
||||||
|
if ($last_id eq 0) {
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Or use the more explicit flag
|
||||||
|
if ($initial_load_in_progress) {
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Your extension logic here...
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Safe Text Processing
|
||||||
|
|
||||||
|
Always use `&descape()` when processing post content:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Extract and clean post text
|
||||||
|
my $author = &descape($post_ref->{'account'}->{'display_name'} ||
|
||||||
|
$post_ref->{'account'}->{'username'});
|
||||||
|
my $content = &descape($post_ref->{'content'});
|
||||||
|
|
||||||
|
# Additional cleaning for text-to-speech or notifications
|
||||||
|
$content =~ s/<[^>]*>//g; # Remove HTML tags
|
||||||
|
$content =~ s/&[a-zA-Z0-9]+;//g; # Remove remaining entities
|
||||||
|
$content =~ s/https?:\/\/\S+/ link /g; # Replace URLs
|
||||||
|
$content =~ s/#(\w+)/ hashtag $1 /g; # Make hashtags readable
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Detection
|
||||||
|
|
||||||
|
Check system capabilities before using features:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Check for GUI environment
|
||||||
|
if (!$ENV{'DISPLAY'}) {
|
||||||
|
print $stdout "-- Warning: No GUI display available\n" if (!$silent);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check for required commands
|
||||||
|
sub command_exists {
|
||||||
|
my $cmd = shift;
|
||||||
|
return system("which $cmd >/dev/null 2>&1") == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!command_exists('paplay')) {
|
||||||
|
print $stdout "-- Warning: paplay not found, trying alternative\n" if (!$silent);
|
||||||
|
# Try alternative commands...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Notification Function Registration
|
||||||
|
|
||||||
|
Proper naming convention for notification handlers:
|
||||||
|
|
||||||
|
```perl
|
||||||
|
# Function name must be: notifier_extensionname
|
||||||
|
sub notifier_soundpack {
|
||||||
|
my $class = shift;
|
||||||
|
my $text = shift;
|
||||||
|
my $post_ref = shift;
|
||||||
|
|
||||||
|
# TTYverse automatically discovers and calls functions matching this pattern
|
||||||
|
# No explicit registration needed
|
||||||
|
}
|
||||||
|
|
||||||
|
# Multiple notifiers can exist - TTYverse calls all of them
|
||||||
|
sub notifier_myother {
|
||||||
|
# Another notification handler
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
### Error Handling
|
||||||
|
```perl
|
||||||
|
$handle = sub {
|
||||||
|
my $post_ref = shift;
|
||||||
|
|
||||||
|
eval {
|
||||||
|
# Your processing code here
|
||||||
|
# ...
|
||||||
|
};
|
||||||
|
|
||||||
|
if ($@) {
|
||||||
|
print $stdout "-- Extension error: $@\n" if (!$silent);
|
||||||
|
}
|
||||||
|
|
||||||
|
# Always call default handler
|
||||||
|
&defaulthandle($post_ref);
|
||||||
|
return 1;
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### Persistent Storage
|
||||||
|
```perl
|
||||||
|
# Store data between sessions
|
||||||
|
$store->{'my_data'} = "persistent value";
|
||||||
|
|
||||||
|
# Access stored data
|
||||||
|
my $saved_value = $store->{'my_data'} || "default";
|
||||||
|
```
|
||||||
|
|
||||||
|
### Respecting User Preferences
|
||||||
|
```perl
|
||||||
|
# Check if user wants your extension to be quiet
|
||||||
|
return 1 if ($silent);
|
||||||
|
|
||||||
|
# Only show messages in verbose mode
|
||||||
|
print $stdout "-- Extension info\n" if ($verbose && !$silent);
|
||||||
|
```
|
||||||
|
|
||||||
|
## Extension Loading
|
||||||
|
|
||||||
|
Extensions must end with:
|
||||||
|
```perl
|
||||||
|
# Mark extension as successfully loaded
|
||||||
|
$store->{'loaded'} = 1;
|
||||||
|
|
||||||
|
# Required Perl module return value
|
||||||
|
1;
|
||||||
|
```
|
||||||
|
|
||||||
|
## Testing Your Extension
|
||||||
|
|
||||||
|
1. **Syntax Check**: `perl -c yourextension.pl`
|
||||||
|
2. **Load Test**: `./ttyverse.pl -exts=yourextension -verbose`
|
||||||
|
3. **Function Test**: Try your commands/hooks with real data
|
||||||
|
4. **Error Test**: Test with invalid inputs and network failures
|
||||||
|
|
||||||
|
## Distribution
|
||||||
|
|
||||||
|
To share your extension:
|
||||||
|
|
||||||
|
1. Add clear documentation header with license
|
||||||
|
2. List any dependencies
|
||||||
|
3. Provide configuration examples
|
||||||
|
4. Test on different systems
|
||||||
|
|
||||||
|
See existing extensions in `~/.local/share/ttyverse/extensions/` for examples.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
**See also:** [Extensions](Extensions) | [Configuration](Configuration) | [Commands Reference](Commands-Reference)
|
||||||
|
|
||||||
|
*Last updated: 2025-07-29*
|
181
Extensions.md
181
Extensions.md
@ -1,98 +1,177 @@
|
|||||||
# Extensions
|
# Extensions
|
||||||
|
|
||||||
TTYverse supports extensions that add functionality like sound notifications, text-to-speech, and desktop integration. Extensions are Perl scripts that integrate with TTYverse's multi-process architecture.
|
TTYverse supports extensions that add functionality like sound notifications, text-to-speech, and desktop integration. Extensions enhance your fediverse experience with customizable features.
|
||||||
|
|
||||||
## Available Extensions
|
## Available Extensions
|
||||||
|
|
||||||
TTYverse includes several extensions that enhance the user experience:
|
TTYverse includes several built-in extensions:
|
||||||
|
|
||||||
- **Sound Pack** - Audio notifications for different types of posts and events
|
### Sound Pack Extension
|
||||||
- **Text-to-Speech** - Speak posts and notifications aloud
|
- **Purpose**: Audio notifications for different types of posts and events
|
||||||
- **Desktop Notifications** - Visual notification bubbles
|
- **Sounds**: Default timeline, mentions, DMs, boosts, follows, polls, announcements
|
||||||
- **Timestamp Enhancement** - Enhanced timestamp display options
|
- **Configuration**: Customizable sound packs and audio commands
|
||||||
|
|
||||||
Extensions are included with TTYverse but not enabled by default.
|
### Text-to-Speech Extension
|
||||||
|
- **Purpose**: Speak posts and notifications aloud for accessibility
|
||||||
|
- **Engines**: espeak, festival, pico, cepstral, macOS say
|
||||||
|
- **Features**: Configurable voice, speed, and language settings
|
||||||
|
|
||||||
## Extension Installation
|
### Desktop Notifications Extension
|
||||||
|
- **Purpose**: Visual notification bubbles on Linux/Unix desktops
|
||||||
|
- **Requirements**: libnotify and Gtk2::Notify Perl module
|
||||||
|
- **Integration**: Works with GNOME, KDE, and other desktop environments
|
||||||
|
|
||||||
### Extension Availability
|
### Timestamp Extension
|
||||||
TTYverse includes core extensions in the installation:
|
- **Purpose**: Enhanced timestamp display with time gaps
|
||||||
|
- **Features**: Shows timestamps when 5+ minutes pass between posts
|
||||||
|
|
||||||
|
## Installing Extensions
|
||||||
|
|
||||||
|
### Using the Extension Manager
|
||||||
|
|
||||||
|
TTYverse includes a management script for easy extension control:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
** attempting to load extensions
|
# Show available extensions
|
||||||
** loading /home/user/.local/share/ttyverse/extensions/extensionname.pl
|
./extensions/manage-extensions.sh list
|
||||||
** loaded extensions: extensionname
|
|
||||||
|
# Enable an extension
|
||||||
|
./extensions/manage-extensions.sh enable soundpack
|
||||||
|
|
||||||
|
# Disable an extension
|
||||||
|
./extensions/manage-extensions.sh disable soundpack
|
||||||
|
|
||||||
|
# Check extension status
|
||||||
|
./extensions/manage-extensions.sh status soundpack
|
||||||
```
|
```
|
||||||
|
|
||||||
### Extension Location
|
### Manual Installation
|
||||||
Extensions are stored in:
|
|
||||||
|
Extensions are stored in the XDG data directory:
|
||||||
```
|
```
|
||||||
~/.local/share/ttyverse/extensions/
|
~/.local/share/ttyverse/extensions/
|
||||||
```
|
```
|
||||||
|
|
||||||
|
Load extensions when starting TTYverse:
|
||||||
|
```bash
|
||||||
|
./ttyverse.pl -exts=soundpack,tts,libnotifyperl
|
||||||
|
```
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
Extensions are configured through TTYverse settings:
|
### Extension Settings
|
||||||
|
Configure extensions in your TTYverse RC file (`~/.config/ttyverse/ttyverserc`):
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
# View extension-related settings
|
# Load extensions automatically
|
||||||
/get sound_enabled
|
exts=soundpack,tts
|
||||||
/get tts_enabled
|
|
||||||
|
|
||||||
# Enable/disable extensions
|
# Enable sound notifications
|
||||||
/set sound_enabled 1
|
notifytype=soundpack
|
||||||
/set extension_name 0
|
notifies=default,mention,dm,me,follow,boost,favourite
|
||||||
|
|
||||||
|
# Sound pack settings
|
||||||
|
extpref_sound_command=paplay
|
||||||
|
extpref_soundpack=default
|
||||||
|
|
||||||
|
# Text-to-speech settings
|
||||||
|
extpref_tts_synthesizer=espeak
|
||||||
|
extpref_tts_language=en-US
|
||||||
|
extpref_tts_rate=175
|
||||||
```
|
```
|
||||||
|
|
||||||
Configuration can also be edited directly in:
|
### Runtime Configuration
|
||||||
```
|
Some settings can be changed while TTYverse is running:
|
||||||
~/.config/ttyverse/ttyverse_rc
|
|
||||||
|
```bash
|
||||||
|
# Toggle text-to-speech
|
||||||
|
/tts
|
||||||
|
|
||||||
|
# Get TTS help
|
||||||
|
/tts help
|
||||||
```
|
```
|
||||||
|
|
||||||
## Extension Dependencies
|
## Extension Dependencies
|
||||||
|
|
||||||
Some extensions may require additional system packages. Check the documentation for your specific distribution to install:
|
### Sound Pack Extension
|
||||||
|
- **Audio system**: PulseAudio (paplay), ALSA (aplay), or similar
|
||||||
|
- **Sound files**: OGG Vorbis format recommended
|
||||||
|
- **Commands**: `paplay`, `play` (SoX), `ogg123`, or `mpv`
|
||||||
|
|
||||||
- **Audio support** - PulseAudio or similar audio system
|
### Text-to-Speech Extension
|
||||||
- **Text-to-speech** - TTS engines like espeak or festival
|
- **Synthesizers**: `espeak` (recommended), `festival`, `pico2wave`
|
||||||
- **Desktop notifications** - libnotify and related Perl modules
|
- **Commercial**: Cepstral Swift (Linux), macOS `say` command
|
||||||
|
- **Languages**: Depends on synthesizer (espeak supports many)
|
||||||
|
|
||||||
## Custom Extensions
|
### Desktop Notifications Extension
|
||||||
|
- **Perl module**: `Gtk2::Notify`
|
||||||
|
- **System**: libnotify (`libnotify-dev` or similar package)
|
||||||
|
- **Desktop**: GUI environment with `DISPLAY` variable set
|
||||||
|
|
||||||
### Creating Extensions
|
Install dependencies on common distributions:
|
||||||
Extensions are Perl scripts that follow TTYverse conventions. They can:
|
|
||||||
|
|
||||||
- Hook into post processing
|
```bash
|
||||||
- React to different notification types
|
# Debian/Ubuntu
|
||||||
- Add new commands
|
sudo apt install libgtk2-notify-perl espeak pulseaudio-utils
|
||||||
- Integrate with system features
|
|
||||||
|
|
||||||
### Extension Development
|
# Fedora/RHEL
|
||||||
See the existing extensions in `~/.local/share/ttyverse/extensions/` for examples of how to create custom functionality.
|
sudo dnf install perl-Gtk2-Notify espeak pulseaudio-utils
|
||||||
|
|
||||||
|
# Arch Linux
|
||||||
|
sudo pacman -S perl-gtk2-notify espeak pulseaudio
|
||||||
|
```
|
||||||
|
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
### Extension Issues
|
### Extension Loading Issues
|
||||||
```bash
|
```bash
|
||||||
# Check if extensions are loading
|
# Check if extensions are loading properly
|
||||||
./ttyverse.pl -verbose
|
./ttyverse.pl -exts=soundpack -verbose
|
||||||
|
|
||||||
# Test extension files manually
|
# Test extension syntax
|
||||||
perl ~/.local/share/ttyverse/extensions/extensionname.pl
|
perl -c ~/.local/share/ttyverse/extensions/soundpack.pl
|
||||||
|
|
||||||
# Fix permissions if needed
|
# Check extension manager status
|
||||||
chmod +x ~/.local/share/ttyverse/extensions/*.pl
|
./extensions/manage-extensions.sh list
|
||||||
```
|
```
|
||||||
|
|
||||||
### Common Problems
|
### Common Problems
|
||||||
- **Permission denied** - Make extension files executable
|
|
||||||
- **Missing dependencies** - Install required system packages
|
|
||||||
- **Configuration errors** - Check settings in ttyverse_rc
|
|
||||||
|
|
||||||
For specific extension issues, check the [Troubleshooting](Troubleshooting) guide.
|
**Extension not loading**
|
||||||
|
- Check that the extension file exists in `~/.local/share/ttyverse/extensions/`
|
||||||
|
- Verify the extension is enabled: `./extensions/manage-extensions.sh status extensionname`
|
||||||
|
- Look for Perl syntax errors: `perl -c extensionname.pl`
|
||||||
|
|
||||||
|
**No sound notifications**
|
||||||
|
- Test audio system: `paplay /usr/share/sounds/alsa/Front_Left.wav`
|
||||||
|
- Check sound pack configuration in RC file
|
||||||
|
- Verify sound files exist in `~/.local/share/ttyverse/sounds/default/`
|
||||||
|
|
||||||
|
**Text-to-speech not working**
|
||||||
|
- Test synthesizer: `espeak "test message"`
|
||||||
|
- Check TTS configuration: `/tts help`
|
||||||
|
- Install required TTS engine packages
|
||||||
|
|
||||||
|
**Desktop notifications not appearing**
|
||||||
|
- Verify GUI environment: `echo $DISPLAY`
|
||||||
|
- Test notification system: `notify-send "Test"`
|
||||||
|
- Install libnotify Perl module
|
||||||
|
|
||||||
|
### Getting Help
|
||||||
|
|
||||||
|
For specific extension issues, check the [Troubleshooting](Troubleshooting) guide or examine the extension source code for configuration examples.
|
||||||
|
|
||||||
|
## Creating Custom Extensions
|
||||||
|
|
||||||
|
Want to create your own extensions? See the [Extension Development](Extension-Development) guide for detailed information on:
|
||||||
|
|
||||||
|
- Extension architecture and hooks
|
||||||
|
- Available functions and variables
|
||||||
|
- Code examples and best practices
|
||||||
|
- Testing and distribution
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
**See also:** [Configuration](Configuration) | [Troubleshooting](Troubleshooting) | [Installation](Installation)
|
**See also:** [Extension Development](Extension-Development) | [Configuration](Configuration) | [Troubleshooting](Troubleshooting)
|
||||||
|
|
||||||
*Last updated: 2025-07-28*
|
*Last updated: 2025-07-29*
|
Reference in New Issue
Block a user