Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Opds Parser Laravel Package

bookeenweb/opds-parser

PHP library for parsing OPDS-compliant catalog feeds. Fetch and parse feeds from a local file or URL, and extract OpenSearch search endpoints from opensearchdescription XML to help build catalog search features.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation Run composer require bookeenweb/opds-parser in your Laravel project directory. Ensure your composer.json includes the package under require.

  2. Basic Setup Import the parser class in your service or controller:

    use OpdsBundle\Business\OpdsParserBusiness;
    
  3. First Use Case Parse an OPDS feed from a URL:

    $parser = new OpdsParserBusiness();
    $feed = $parser->parseURL('https://framabookin.org/b/opds/');
    

    Parse an OPDS file locally:

    $feed = $parser->parseFile(__DIR__ . '/path/to/feed.atom');
    
  4. Where to Look First

    • Documentation: The README provides basic usage, but explore the source code for deeper insights.
    • Examples: Test with the provided feed examples (e.g., http://www.feedbooks.com/catalog.atom) to validate functionality.
    • Output Structure: Inspect the parsed feed structure (likely an array/object) to understand how to extract entries, metadata, or links.

Implementation Patterns

Usage Patterns

  1. Parsing Feeds in Controllers Use the parser in a controller to fetch and display OPDS feeds:

    public function showFeed(Request $request, OpdsParserBusiness $parser) {
        $feed = $parser->parseURL($request->input('feed_url'));
        return view('opds.feed', ['feed' => $feed]);
    }
    
  2. Service Layer Integration Create a dedicated service class to encapsulate OPDS logic:

    class OpdsService {
        protected $parser;
    
        public function __construct(OpdsParserBusiness $parser) {
            $this->parser = $parser;
        }
    
        public function fetchAndProcessFeed(string $url) {
            $feed = $this->parser->parseURL($url);
            // Process feed (e.g., extract entries, validate metadata)
            return $this->transformFeed($feed);
        }
    }
    
  3. Handling Search Feeds Parse OpenSearch description feeds to extract search URLs:

    $searchUrls = $parser->parseSearchUrl('https://example.com/opensearch.xml');
    
  4. Caching Responses Cache parsed feeds to avoid repeated network requests:

    $cacheKey = 'opds_feed_' . md5($url);
    $feed = Cache::remember($cacheKey, now()->addHours(1), function() use ($parser, $url) {
        return $parser->parseURL($url);
    });
    

Workflows

  1. Fetch and Display Feed Entries Iterate over parsed entries to display books or resources:

    foreach ($feed['entries'] as $entry) {
        echo $entry['title'] . ' - ' . $entry['author'] . '<br>';
    }
    
  2. Extract Metadata for Storage Store parsed metadata (e.g., titles, authors, links) in a database:

    foreach ($feed['entries'] as $entry) {
        Book::create([
            'title' => $entry['title'],
            'author' => $entry['author'],
            'source_url' => $entry['id'],
            'cover_url' => $entry['thumbnail'] ?? null,
        ]);
    }
    
  3. Validate Feed Structure Check for required fields (e.g., id, title, updated) before processing:

    if (!isset($feed['id']) || !isset($feed['title'])) {
        throw new \InvalidArgumentException('Invalid OPDS feed structure');
    }
    

Integration Tips

  1. Laravel Service Provider Bind the parser to the container for dependency injection:

    // In AppServiceProvider
    $this->app->bind(OpdsParserBusiness::class, function () {
        return new OpdsParserBusiness();
    });
    
  2. Queue Long-Running Parses Offload heavy parsing tasks to a queue (e.g., Laravel Queues):

    ParseOpdsFeedJob::dispatch($url)->onQueue('opds');
    
  3. Error Handling Wrap parser calls in try-catch blocks to handle network/parse errors:

    try {
        $feed = $parser->parseURL($url);
    } catch (\Exception $e) {
        Log::error("Failed to parse OPDS feed: " . $e->getMessage());
        return response()->view('errors.feed', [], 500);
    }
    
  4. Testing Mock the parser in unit tests:

    $mockParser = Mockery::mock(OpdsParserBusiness::class);
    $mockParser->shouldReceive('parseURL')->once()->andReturn($mockFeed);
    

Gotchas and Tips

Pitfalls

  1. Deprecated Package

    • The package hasn’t been updated since 2018 and has 0 stars/dependents. Assess whether its OPDS compliance aligns with your needs (e.g., modern OPDS 2.0 features may not be supported).
    • Consider alternatives like spatie/feed (for Atom/RSS) or custom XML parsing if this package lacks critical features.
  2. No Laravel-Specific Features

    • The package is not a Laravel bundle (despite the name OpdsBundle). It’s a standalone PHP library. Avoid expecting Laravel-specific conveniences (e.g., service providers, config files).
    • Manual dependency injection is required (e.g., no auto-wiring without binding).
  3. XML Parsing Quirks

    • Malformed XML: Some OPDS feeds may have invalid XML. The parser might throw exceptions or return incomplete data. Validate feeds before parsing:
      $xml = file_get_contents($url);
      if (!@simplexml_load_string($xml)) {
          throw new \RuntimeException('Invalid XML in OPDS feed');
      }
      
    • Namespaces: OPDS feeds often use XML namespaces (e.g., atom, opds). The parser may not handle them explicitly. Inspect the output structure to map namespaced fields.
  4. Performance

    • Parsing large feeds (e.g., thousands of entries) may consume memory. Stream or paginate results if needed:
      $entries = array_chunk($feed['entries'], 100); // Process in batches
      
  5. Search URL Limitations

    • parseSearchUrl may only extract basic OpenSearch metadata. Custom logic might be needed to handle complex search endpoints.

Debugging

  1. Inspect Raw Output Dump the parsed feed to understand its structure:

    dd($parser->parseURL($url));
    
    • Look for keys like entries, links, title, updated, or author.
  2. Validate Against Examples Compare output with the provided feed examples to ensure expected fields are present.

  3. Check for Deprecation Warnings Enable PHP error reporting to catch deprecated methods or warnings:

    error_reporting(E_ALL);
    ini_set('display_errors', 1);
    

Tips

  1. Extend the Parser Create a decorator class to add Laravel-specific logic:

    class LaravelOpdsParser {
        protected $parser;
    
        public function __construct(OpdsParserBusiness $parser) {
            $this->parser = $parser;
        }
    
        public function parseWithCache(string $url) {
            // Add caching, logging, or validation
            return $this->parser->parseURL($url);
        }
    }
    
  2. Handle Relative URLs OPDS feeds often contain relative links (e.g., /path/to/resource). Resolve them using the base URL:

    $baseUrl = parse_url($feedUrl, PHP_URL_SCHEME) . '://' . parse_url($feedUrl, PHP_URL_HOST);
    $absoluteUrl = $baseUrl . ltrim($relativeLink, '/');
    
  3. Normalize Data Standardize parsed data before storage (e.g., trim strings, convert dates):

    $normalized = array_map(function ($entry) {
        return [
            'title' => trim($entry['title']),
            'published_at' => Carbon::parse($entry['updated'])->format('Y-m-d'),
        ];
    }, $feed['entries']);
    
  4. Monitor Feed Updates Track the updated field in feeds to detect changes:

    if ($feed['updated'] > Cache::get('last_opds_update')) {
        Cache::put('last_opds_update', $feed['updated']);
        // Trigger update logic (e.g., re-fetch entries)
    }
    
  5. Fallback for Missing Fields Provide defaults for optional fields (e.g., `thumbnail

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
directorytree/privacy-filter-classifier
directorytree/privacy-filter
datacore/hub-sdk
develia/commons
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
develia/geo-bundle
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle
agtp/agtp-php
agtp/mod-php
splash/sonata-admin
splash/metadata
splash/openapi
splash/scopes
splash/toolkit
testo/output-teamcity
testo/bridge-symfony
spatie/flare-daemon-runtime