diff --git a/src/public/search.php b/src/public/search.php
new file mode 100644
index 0000000..ea1590c
--- /dev/null
+++ b/src/public/search.php
@@ -0,0 +1,436 @@
+ false,
+ 'page' => 1,
+];
+
+// Prepare request
+$request->query = isset($_GET['query']) ? urldecode((string) $_GET['query']) : '';
+$request->page = isset($_GET['page']) && $_GET['page'] > 0 ? (int) $_GET['page'] : 1;
+
+// Define response
+$response = (object)
+[
+ 'success' => true,
+ 'message' => false,
+ 'magnets' => [],
+];
+
+// Yggdrasil connections only
+if (!Valid::host($_SERVER['REMOTE_ADDR']))
+{
+ $response->success = false;
+ $response->message = _('Yggdrasil connection required to enable resource features');
+}
+
+// Init session
+else if (!$userId = $db->initUserId($_SERVER['REMOTE_ADDR'], USER_DEFAULT_APPROVED, time()))
+{
+ $response->success = false;
+ $response->message = _('Could not init user session');
+}
+
+// Get user
+else if (!$user = $db->getUser($userId))
+{
+ $response->success = false;
+ $response->message = _('Could not init user info');
+}
+
+// On first visit, redirect user to the welcome page with access level question
+else if (is_null($user->public) && !isset($_GET['rss']))
+{
+ header(
+ sprintf('Location: %s/welcome.php', WEBSITE_URL)
+ );
+}
+
+// Request valid
+else
+{
+ // Query is magnet link
+ if ($magnet = Yggverse\Parser\Magnet::is($request->query))
+ {
+ header(
+ sprintf('Location: %s/action.php?target=magnet&toggle=new&magnet=%s', WEBSITE_URL, urlencode($request->query))
+ );
+ }
+
+ // Get index
+ $response->total = $sphinx->searchMagnetsTotal($request->query);
+ $results = $sphinx->searchMagnets(
+ $request->query,
+ $request->page * WEBSITE_PAGINATION_LIMIT - WEBSITE_PAGINATION_LIMIT,
+ WEBSITE_PAGINATION_LIMIT,
+ $response->total
+ );
+
+ foreach ($results as $result)
+ {
+ if ($magnet = $db->getMagnet($result->magnetid))
+ {
+ // Get access info
+ $accessRead = ($user->address == $db->getUser($magnet->userId)->address || in_array($user->address, MODERATOR_IP_LIST) || ($magnet->public && $magnet->approved));
+ $accessEdit = ($user->address == $db->getUser($magnet->userId)->address || in_array($user->address, MODERATOR_IP_LIST));
+
+ // Keywords
+ $keywords = [];
+
+ foreach ($db->findKeywordTopicByMagnetId($magnet->magnetId) as $keyword)
+ {
+ $keywords[] = $db->getKeywordTopic($keyword->keywordTopicId)->value;
+ }
+
+ $response->magnets[] = (object)
+ [
+ 'magnetId' => $magnet->magnetId,
+ 'title' => $magnet->title ? htmlentities($magnet->title) : ($magnet->dn ? htmlentities($magnet->dn): false),
+ 'preview' => $magnet->preview ? nl2br(
+ htmlentities(
+ $magnet->preview
+ )
+ ) : false,
+ 'approved' => (bool) $magnet->approved,
+ 'public' => (bool) $magnet->public,
+ 'sensitive' => (bool) $magnet->sensitive,
+ 'comments' => (bool) $magnet->comments,
+ 'timeAdded' => $magnet->timeAdded ? Time::ago((int) $magnet->timeAdded) : false,
+ 'timeUpdated' => $magnet->timeUpdated ? Time::ago((int) $magnet->timeUpdated) : false,
+ 'keywords' => $keywords,
+ 'comment' => (object)
+ [
+ 'total' => $db->findMagnetCommentsTotalByMagnetId($magnet->magnetId),
+ 'status' => $db->findMagnetCommentsTotal($magnet->magnetId, $userId),
+ ],
+ 'download' => (object)
+ [
+ 'total' => $db->findMagnetDownloadsTotalByMagnetId($magnet->magnetId),
+ 'status' => $db->findMagnetDownloadsTotal($magnet->magnetId, $userId),
+ ],
+ 'star' => (object)
+ [
+ 'total' => $db->findMagnetStarsTotalByMagnetId($magnet->magnetId, true),
+ 'status' => $db->findLastMagnetStarValue($magnet->magnetId, $userId),
+ ],
+ 'access' => (object)
+ [
+ 'read' => $accessRead,
+ 'edit' => $accessEdit,
+ ],
+ 'seeders' => $db->getMagnetToAddressTrackerSeedersSumByMagnetId($magnet->magnetId),
+ 'completed' => $db->getMagnetToAddressTrackerCompletedSumByMagnetId($magnet->magnetId),
+ 'leechers' => $db->getMagnetToAddressTrackerLeechersSumByMagnetId($magnet->magnetId),
+ 'directs' => $db->getMagnetToAcceptableSourceTotalByMagnetId($magnet->magnetId)
+ ];
+ }
+ }
+}
+
+if (isset($_GET['rss']) && $response->success) { ?>' . PHP_EOL ?>
+