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.
Installation
Run composer require bookeenweb/opds-parser in your Laravel project directory.
Ensure your composer.json includes the package under require.
Basic Setup Import the parser class in your service or controller:
use OpdsBundle\Business\OpdsParserBusiness;
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');
Where to Look First
http://www.feedbooks.com/catalog.atom) to validate functionality.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]);
}
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);
}
}
Handling Search Feeds Parse OpenSearch description feeds to extract search URLs:
$searchUrls = $parser->parseSearchUrl('https://example.com/opensearch.xml');
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);
});
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>';
}
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,
]);
}
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');
}
Laravel Service Provider Bind the parser to the container for dependency injection:
// In AppServiceProvider
$this->app->bind(OpdsParserBusiness::class, function () {
return new OpdsParserBusiness();
});
Queue Long-Running Parses Offload heavy parsing tasks to a queue (e.g., Laravel Queues):
ParseOpdsFeedJob::dispatch($url)->onQueue('opds');
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);
}
Testing Mock the parser in unit tests:
$mockParser = Mockery::mock(OpdsParserBusiness::class);
$mockParser->shouldReceive('parseURL')->once()->andReturn($mockFeed);
Deprecated Package
spatie/feed (for Atom/RSS) or custom XML parsing if this package lacks critical features.No Laravel-Specific Features
OpdsBundle). It’s a standalone PHP library. Avoid expecting Laravel-specific conveniences (e.g., service providers, config files).XML Parsing Quirks
$xml = file_get_contents($url);
if (!@simplexml_load_string($xml)) {
throw new \RuntimeException('Invalid XML in OPDS feed');
}
atom, opds). The parser may not handle them explicitly. Inspect the output structure to map namespaced fields.Performance
$entries = array_chunk($feed['entries'], 100); // Process in batches
Search URL Limitations
parseSearchUrl may only extract basic OpenSearch metadata. Custom logic might be needed to handle complex search endpoints.Inspect Raw Output Dump the parsed feed to understand its structure:
dd($parser->parseURL($url));
entries, links, title, updated, or author.Validate Against Examples Compare output with the provided feed examples to ensure expected fields are present.
Check for Deprecation Warnings Enable PHP error reporting to catch deprecated methods or warnings:
error_reporting(E_ALL);
ini_set('display_errors', 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);
}
}
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, '/');
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']);
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)
}
Fallback for Missing Fields Provide defaults for optional fields (e.g., `thumbnail
How can I help you explore Laravel packages today?