https://github.com/markus1189/hocket
Hocket the Haskell pocket client
https://github.com/markus1189/hocket
Last synced: 12 months ago
JSON representation
Hocket the Haskell pocket client
- Host: GitHub
- URL: https://github.com/markus1189/hocket
- Owner: markus1189
- License: bsd-3-clause
- Created: 2014-12-21T09:33:14.000Z (over 11 years ago)
- Default Branch: master
- Last Pushed: 2024-10-30T03:37:12.000Z (over 1 year ago)
- Last Synced: 2024-10-30T06:25:00.130Z (over 1 year ago)
- Language: Haskell
- Size: 677 KB
- Stars: 2
- Watchers: 5
- Forks: 2
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Hocket
A minimalistic terminal user interface for [Raindrop.io](https://raindrop.io/) written in Haskell.
## Overview
Hocket provides a keyboard-driven terminal interface for efficiently managing your Raindrop.io bookmarks. It's designed for users who prefer command-line tools and want to quickly process their bookmark collection without leaving the terminal.

## Features
### Core Functionality
- **Single-pane interface with action flags** - View all items with visual indicators for pending actions
- **Real-time synchronization** - Fetch latest bookmarks from Raindrop.io
- **Batch operations** - Archive multiple items and manage reminders at once
- **Smart reminder management** - Set and remove reminders with intelligent toggling
- **Smart updates** - Only fetch items modified since last sync
- **Favorite indicators** - Visual markers (★) for favorite bookmarks
- **Rich item display** - Shows dates, titles, URLs, notes, excerpts, and reminder dates
### Command Line Interface
- **Add bookmarks from CLI** - Add bookmarks directly from terminal
- **Automatic metadata extraction** - Raindrop.io parses title and description automatically
- **Collection targeting** - Specify which collection to add bookmarks to
- **Tag support** - Add multiple tags when creating bookmarks
- **Robust error handling** - Automatic retries with exponential backoff
### Workflow Support
- **Browser integration** - Open bookmarks in your default browser
- **Archive management** - Move items to a designated archive collection
- **Reminder scheduling** - Set reminders for next day at 7:00 AM in your local timezone
- **Keyboard navigation** - Efficient Vi-style navigation
- **Status tracking** - Visual feedback for all operations
## Installation
### Using Nix (Recommended)
```bash
# Build the project
nix build
# Run directly
nix run -- tui
# Install to your profile
nix profile install
```
### Using Cabal
```bash
# Clone the repository
git clone https://github.com/markus1189/hocket.git
cd hocket
# Build and install
cabal build
cabal install
```
## Configuration
### XDG Base Directory Support
Hocket follows the XDG Base Directory Specification for configuration files:
**Current config location**: `~/.config/hocket/config.dhall`
Create your configuration file:
```dhall
{
_raindropToken = "your-raindrop-test-token-here",
_archiveCollectionId = 12345
}
: ./schema.dhall
```
### Legacy Support
For backward compatibility, Hocket will still use `./config.dhall` if it exists in your working directory. However, you'll see a warning message encouraging migration to the XDG location.
### Migration from Legacy Config
If you have an existing `config.dhall` in your working directory:
1. Create the XDG config directory: `mkdir -p ~/.config/hocket`
2. Move your config: `mv ./config.dhall ~/.config/hocket/config.dhall`
3. Move the schema: `mv ./schema.dhall ~/.config/hocket/schema.dhall`
The application will automatically create the schema file if it doesn't exist.
### Getting Your Raindrop.io Token
1. Visit [Raindrop.io Settings → Integrations](https://app.raindrop.io/settings/integrations)
2. Click **"+ Create new app"**
3. Name your app (e.g., "Hocket")
4. Click **"Create"**
5. Click on your new app
6. Copy the **"Test token"**
### Finding Your Archive Collection ID
1. Go to [Raindrop.io](https://app.raindrop.io)
2. Create or navigate to your desired archive collection
3. Note the collection ID from the URL (e.g., `app.raindrop.io/my/12345`)
**Security Note:** Keep your token secure and never commit it to version control.
## Usage
### Commands
#### Terminal User Interface
```bash
# Run the interactive TUI (config is loaded from ~/.config/hocket/config.dhall)
hocket tui
```
#### Add Bookmarks from Command Line
```bash
# Add a bookmark to the unsorted collection
hocket add https://example.com
# Add a bookmark to a specific collection
hocket add https://example.com --collection 12345
# Add a bookmark with tags
hocket add https://example.com --tag programming --tag tutorial
# Add a bookmark with collection and tags
hocket add https://example.com --collection 12345 --tag rust --tag cli
```
**Add Command Features:**
- **Automatic metadata extraction** - Title, description, and other metadata are fetched automatically
- **Default collection** - Uses unsorted collection (-1) if not specified
- **Multiple tags** - Add multiple `--tag` flags for multiple tags
- **Retry logic** - Automatically retries failed requests with exponential backoff
- **Error handling** - Clear error messages for configuration and API issues
### Keyboard Controls
#### Navigation
- `↑/↓` or `j/k` - Move up/down in the list
- `J/K` - Jump to next/previous flagged item (skip unflagged items)
- `q` - Quit application
#### Item Actions
- `Space` - Open selected item in browser
- `Enter` - Open item in browser AND mark for archiving
- `a` - Flag selected item for archiving
- `s` - Smart reminder toggle: flag for reminder setting (unscheduled items) or removal (scheduled items)
- `u` - Remove flags from selected item (archive, reminder, or removal flags)
#### Bulk Operations
- `r` - Refresh/fetch latest items from Raindrop.io
- `U` - Clear all flags from all items
- `X` - Execute all flagged operations (archive items, set reminders, remove reminders)
- `S` - Toggle showing/hiding items with future reminders
### Interface Layout
```
┌─ Hocket: (15|2|1|1) (3) ───────────────────────────────────────────┐
│ 2025-01-15: ★ Important Article Title reddit.com/r/... │
│ 2025-01-14: Regular Bookmark github.com/... │
│ A 2025-01-13: Item flagged for archive example.com/... │
│ R 2025-01-12: Item flagged for reminder example.com/... │
│ r 2025-01-11: Item flagged to remove reminder news.ycombinator...│
│ 2025-01-10: Item with existing reminder stackoverflow.com/│
├──────────────────────────────────────────────────────────────────┤
└─ REMINDER 2025-01-12 EXCERPT: This is a sample excerpt ──────────┘
│ Last: 14:32:18 │
│ Status: setting reminders │
└────────────────────────────────────────────────────────────────────┘
```
#### Visual Elements
- **A** - Flag indicating item is pending archive action
- **R** - Flag indicating item is pending reminder setting (blue color)
- **r** - Flag indicating item is pending reminder removal (red color)
- **★** - Indicates favorite bookmarks
- **Header counts** - `(normal|archive|remind_set|remind_remove) (existing_reminders)`
- **Date** - When the bookmark was created (shows reminder date when present)
- **Title** - Bookmark title or URL if no title available
- **Domain** - Truncated URL showing the domain and path
- **Bottom section** - Shows notes, reminder dates, and excerpts for the selected item
- **Status bar** - Last update time and current operation status
## Reminder Management
### Smart Reminder Toggle
The `s` key provides intelligent reminder management based on the item's current state:
- **Unscheduled items**: Press `s` to flag for reminder setting (shows blue "R ")
- **Items with existing reminders**: Press `s` to flag for reminder removal (shows red "r ")
### Reminder Scheduling
- **Default time**: All reminders are set for the next day at 7:00 AM in your local timezone
- **Automatic conversion**: Times are converted to UTC for API storage
- **Visual feedback**: Items with reminders show the reminder date instead of creation date
### Workflow Example
```bash
# Set reminders for important items
1. Navigate to an unscheduled item
2. Press 's' - item shows blue "R " flag
3. Repeat for other items
4. Press 'X' - executes all flagged operations
# Remove unwanted reminders
1. Navigate to an item with existing reminder
2. Press 's' - item shows red "r " flag
3. Press 'X' - removes the reminder
# Mixed operations
1. Flag some items for archive with 'a'
2. Flag some items for reminders with 's'
3. Flag some existing reminders for removal with 's'
4. Press 'X' - executes all operations at once
```
### Display Features
- **Color coding**: Blue for setting reminders, red for removing them
- **Status tracking**: Real-time count of flagged operations in header
- **Jump navigation**: `J/K` keys jump between all flagged items (archive and reminder)
- **Toggle visibility**: `S` key shows/hides items with future reminders
## Technical Details
### Architecture
- **Language**: Haskell (GHC 9.6+)
- **UI Framework**: [Brick](https://github.com/jtdaugherty/brick) (terminal UI library)
- **HTTP Client**: [Wreq](http://www.serpentine.com/wreq/) for API communication
- **Configuration**: [Dhall](https://dhall-lang.org/) functional configuration language
- **Concurrency**: Async operations for non-blocking UI
### API Integration
- **Raindrop.io REST API v1** - Full integration with bookmark and reminder management
- **Individual reminder operations** - Each reminder uses separate API calls as required by Raindrop.io
- **Smart pagination** - Efficiently handles large bookmark collections
- **Rate limiting** - Respects API limits with exponential backoff retry logic
- **Error handling** - Graceful degradation on network issues
- **Automatic metadata parsing** - Uses Raindrop's `pleaseParse` feature for rich bookmark data
### Data Management
- **Local state** - In-memory bookmark cache with smart updates
- **Conflict resolution** - Handles concurrent modifications
- **Performance** - Optimized for collections with thousands of items
## Development
### Building from Source
```bash
# Install dependencies
cabal update
# Build the project
cabal build
# Run tests
cabal test
# Development build with warnings
cabal build --ghc-options="-Wall -Werror"
```
### Project Structure
```
hocket/
├── main/ # Main application
│ ├── hocket.hs # Entry point and UI logic
│ └── Events.hs # Event system definitions
├── src/Network/
│ ├── Raindrop.hs # API client implementation
│ └── Bookmark/
│ ├── Types.hs # Data types and JSON instances
│ └── Ui/
│ ├── State.hs # Application state management
│ └── Widgets.hs # UI helper functions
└── test/ # Test suite
```
### Contributing
Contributions are welcome! Please:
1. Follow the existing code style (see `CONVENTIONS.md`)
2. Add tests for new functionality
3. Update documentation as needed
4. Ensure `cabal test` passes
#### Code Style Guidelines
- Use `lens` for record access (avoid `_` prefixed accessors)
- Prefer `wreq` for HTTP operations
- Use `tasty` for testing
- Follow Brick patterns for UI components
## Limitations
Current limitations that may be addressed in future versions:
- **Single collection focus** - Primarily works with unsorted bookmarks
- **Browser dependency** - Requires external browser for opening links
- **Terminal only** - No GUI version available
- **Limited search** - No built-in search functionality
## Troubleshooting
### Common Issues
**"Authentication failed"**
- Verify your Raindrop.io token in `~/.config/hocket/config.dhall`
- Ensure the token has not expired
- Check your internet connection
**"Collection not found"**
- Verify the `archiveCollectionId` in your config
- Ensure the collection exists and is accessible
**"Items not appearing"**
- Press `r` to refresh/fetch latest items
- Check that items exist in your Raindrop.io unsorted collection
- Verify your account has bookmarks
**"Reminders not working"**
- Ensure you have proper permissions to modify bookmarks
- Check that the reminder time (next day 7:00 AM) is in the future
- Verify your system timezone is configured correctly
- Press `r` to refresh and see updated reminder states
**"Reminder flags showing incorrectly"**
- Press `S` to toggle reminder visibility and refresh the display
- Use `r` to refresh from Raindrop.io to sync latest reminder states
### Getting Help
- Check existing [GitHub Issues](https://github.com/markus1189/hocket/issues)
- Review the `CONVENTIONS.md` file for development guidelines
- Consult the [Brick documentation](https://github.com/jtdaugherty/brick/blob/master/docs/guide.rst) for UI-related questions
## License
BSD3 - See [LICENSE](LICENSE) file for details.
## Acknowledgments
- [Raindrop.io](https://raindrop.io/) for providing an excellent bookmark service with a great API
- [Brick](https://github.com/jtdaugherty/brick) for making terminal UI development in Haskell approachable
- The Haskell community for excellent libraries and tooling