diff --git a/app/controllers/oer/market.php b/app/controllers/oer/market.php
index f9d203c0dbe1cf685464e11ece10ce98c6229bb1..23782a44e2a995f1266e0615b369331653847ef7 100755
--- a/app/controllers/oer/market.php
+++ b/app/controllers/oer/market.php
@@ -62,6 +62,12 @@ class Oer_MarketController extends StudipController
             $tags = $this->tag_history = Request::getArray("tags");
             $this->without_tags = [];
             $tag_to_search_for = array_pop($tags);
+
+            OERMaterial::fetchRemoteSearch(
+                null,
+                $tag_to_search_for
+            );
+
             foreach (OERTag::findBest($tag_matrix_entries_number, true) as $related_tag) {
                 if ($related_tag['tag_hash'] !== $this->tag_history[0]) {
                     $this->without_tags[] = $related_tag['tag_hash'];
@@ -203,7 +209,12 @@ class Oer_MarketController extends StudipController
         if (Navigation::hasItem("/oer/market")) {
             Navigation::activateItem("/oer/market");
         }
-        $this->material = new OERMaterial($material_id);
+        $this->material = OERMaterial::find($material_id);
+        if (!$this->material) {
+            PageLayout::postError(_('Lernmaterial existiert nicht mehr.'));
+            $this->redirect('oer/market');
+            return;
+        }
 
         //OpenGraph tags:
         PageLayout::addHeadElement("meta", ['og:title' => $this->material['name']]);
diff --git a/app/views/oer/embed/standard.php b/app/views/oer/embed/standard.php
index 3060b716faa456f96865a84ac96f43b7beed168e..4374c376fab9b0a0aa7902a1f33cb5fee9bf3df1 100644
--- a/app/views/oer/embed/standard.php
+++ b/app/views/oer/embed/standard.php
@@ -1,4 +1,8 @@
-<a href="<?= htmlReady($url) ?>">
-    <?= Icon::create("service", Icon::ROLE_CLICKABLE)->asImg(16, ['class' => "text-bottom"]) ?>
+<? if ($url) : ?>
+    <a href="<?= htmlReady($url) ?>">
+<? else : ?>
+    <a href="<?= htmlReady($source_url) ?>" target="_blank">
+<? endif ?>
+    <?= Icon::create('oer-campus')->asImg(['class' => 'text-bottom']) ?>
     <?= htmlReady($material['name']) ?>
 </a>
diff --git a/app/views/oer/market/_searchform.php b/app/views/oer/market/_searchform.php
index c731ac8d01bfc60470f4f726617ae310895114ed..995eb9cbec29cd035da81166ce330cfa77cb3f82 100644
--- a/app/views/oer/market/_searchform.php
+++ b/app/views/oer/market/_searchform.php
@@ -169,7 +169,7 @@
                                      role="clickable"
                                      size="20"
                                      class="text-bottom"></studip-icon>
-                        {{ result.name }}
+                        {{ shortenName(result.name) }}
                     </h1>
                 </header>
                 <div class="image" :style="'background-image: url(' + result.logo_url + ');' + (!result.front_image_content_type ? ' background-size: 60% auto;': '')"></div>
diff --git a/app/views/oer/market/details.php b/app/views/oer/market/details.php
index 2c84011c11b8c9dbc31affdb06247658d220c48e..a42114f36c1bbd18344fed52270f49b4670c2202 100755
--- a/app/views/oer/market/details.php
+++ b/app/views/oer/market/details.php
@@ -1,6 +1,6 @@
 <?= $contentbar ?>
 
-<? $url = $material['host_id'] ? $material->host->url."download/".$material['foreign_material_id'] : $controller->link_for("oer/endpoints/download/".$material->getId()) ?>
+<? $url = $material->getDownloadUrl() ?>
 
 <? if ($material['player_url']) : ?>
     <iframe src="<?= htmlReady($material['player_url']) ?>"
@@ -9,7 +9,7 @@
 <? elseif ($material->isVideo()) : ?>
     <video controls
         <?= $material['front_image_content_type'] ? 'poster="'.htmlReady($material->getLogoURL()).'"' : "" ?>
-           crossorigin="anonymous"
+           crossorigin="use-credentials"
            src="<?= htmlReady($url) ?>"
            class="lernmarktplatz_player"></video>
 <? elseif ($material->isAudio()) : ?>
@@ -40,9 +40,9 @@
     </ol>
 <? endif ?>
 
-<? if (($url && $material['filename'] || (!$material['host_id'] && ($material->isMine() || $GLOBALS['perm']->have_perm("root"))))) : ?>
+<? if (($url && $material['filename']) || $material['source_url'] || (!$material['host_id'] && ($material->isMine() || $GLOBALS['perm']->have_perm("root")))) : ?>
     <div class="center bordered" style="margin-top: 20px; margin-bottom: 20px;">
-        <? if ($url && $material['filename']) : ?>
+        <? if ($url) : ?>
             <a class="button"
                href="<?= htmlReady($url) ?>" title="<?= _('Herunterladen') ?>"
                download="<?= htmlReady($material['filename']) ?>">
@@ -50,6 +50,14 @@
             </a>
         <? endif ?>
 
+        <? if ($material['source_url']) : ?>
+            <a class="button"
+               target="_blank"
+               href="<?= htmlReady($material['source_url']) ?>">
+                <?= _('Webseite') ?>
+            </a>
+        <? endif ?>
+
         <? if ($GLOBALS['perm']->have_perm("autor")) : ?>
             <a class="button"
                href="<?= $controller->link_for( "oer/market/add_to_course/" . $material->getId()) ?>"
@@ -142,170 +150,151 @@
             <?= formatReady($material['description']) ?>
         </div>
 
-        <h2><?= _('Zum Autor') ?></h2>
-        <ul class="author_information clean">
-            <? foreach ($material->users as $materialuser) : ?>
-                <li>
-                    <? if ($materialuser['external_contact']) : ?>
-                        <? $user = $materialuser['oeruser'] ?>
-                        <? $image = $user['avatar_url'] ?>
-                        <? $host = OERHost::find($user['host_id']) ?>
-                        <div class="avatar" style="background-image: url('<?= $image ?>');"></div>
-                        <div>
-                            <div class="author_name">
-                                <a href="<?= $controller->link_for("oer/market/profile/".$user->getId()) ?>">
-                                    <?= htmlReady($user['name']) ?>
-                                </a>
-                            </div>
-                            <div class="author_host">(<?= htmlReady($host->name) ?>)</div>
-                            <div class="description"><?= formatReady($user['data']['description']) ?></div>
-                        </div>
-                    <? else : ?>
-                        <? $user = User::find($materialuser['user_id']) ?>
-                        <? $image = Avatar::getAvatar($materialuser['user_id'])->getURL(Avatar::MEDIUM) ?>
-                        <div class="avatar" style="background-image: url('<?= $image ?>');"></div>
+        <? $authors = $material->getAuthors() ?>
+        <? if (count($authors)) : ?>
+            <h2><?= _('Zum Autor') ?></h2>
+            <ul class="author_information clean">
+                <? foreach ($material->getAuthors() as $authordata) : ?>
+                    <li>
+                        <div class="avatar" style="background-image: url('<?= htmlReady($authordata['avatar'] ?: Avatar::getNobody()->getURL(Avatar::MEDIUM)) ?>');"></div>
                         <div>
                             <div class="author_name">
-                                <a href="<?= URLHelper::getLink("dispatch.php/profile", ['username' => $user['username']]) ?>">
-                                    <?= htmlReady($user ? $user->getFullName() : _('unbekannt')) ?>
+                                <? if ($authordata['link']) : ?>
+                                <a href="<?= htmlReady($authordata['link']) ?>">
+                                <? endif ?>
+                                    <?= htmlReady($authordata['name']) ?>
+                                <? if ($authordata['link']) : ?>
                                 </a>
-                            </div>
-                            <div class="author_host">(<?= htmlReady(Config::get()->UNI_NAME_CLEAN) ?>)</div>
-                            <div class="description">
-                                <? if ($user['oercampus_description']) : ?>
-                                <?= htmlReady($user['oercampus_description']) ?>
-                                <? elseif ($materialuser['user_id'] === $GLOBALS['user']->id) : ?>
-                                    <em>
-                                        <?= sprintf(_('Noch keine Beschreibung für den %s vorhanden.'), Config::get()->OER_TITLE) ?>
-                                        <a href="<?= URLHelper::getLink("dispatch.php/settings/details") ?>">
-                                            <?= _('Jetzt eine eingeben.') ?>
-                                        </a>
-                                    </em>
                                 <? endif ?>
                             </div>
+                            <div class="author_host">(<?= htmlReady($authordata['hostname']) ?>)</div>
+                            <? if ($authordata['description']) : ?>
+                            <div class="description"><?= formatReady($authordata['description']) ?></div>
+                            <? endif ?>
                         </div>
-                    <? endif ?>
-                </li>
-            <? endforeach ?>
-        </ul>
+                    </li>
+                <? endforeach ?>
+            </ul>
+        <? endif ?>
     </div>
 </div>
 
-<? $allowed_to_review = !$material->isMine() && $GLOBALS['perm']->have_perm("autor") ?>
-<? if (!$material->isMine() || count($material->reviews)) : ?>
-    <article class="studip bordered">
-        <div class="center">
-            <? if ($material['rating'] === null) : ?>
-                <? if ($allowed_to_review) : ?>
-                    <a style="opacity: 0.3;"
-                    title="<?= $GLOBALS['perm']->have_perm("autor") ? _('Geben Sie die erste Bewertung ab.') : _('Noch keine Bewertung abgegeben.') ?>"
-                    href="<?= $controller->link_for('oer/market/review/' . $material->getId()) ?>" data-dialog>
-                <? endif ?>
-                <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
-                <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
-                <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
-                <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
-                <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
-                <? if ($allowed_to_review) : ?>
-                    </a>
-                <? endif ?>
-            <? else : ?>
-                <? if ($allowed_to_review) : ?>
-                    <a href="<?= $controller->link_for('oer/market/review/' . $material->getId()) ?>" data-dialog title="<?= sprintf(_('%s von 5 Sternen'), round($material['rating'] / 2, 1)) ?>">
-                <? endif ?>
-                <? $material['rating'] = round($material['rating'], 1) / 2 ?>
-                <? $v = $material['rating'] >= 0.75 ? "" : ($material['rating'] >= 0.25 ? "-halffull" : "-empty") ?>
-                <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
-                <? $v = $material['rating'] >= 1.75 ? "" : ($material['rating'] >= 1.25 ? "-halffull" : "-empty") ?>
-                <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
-                <? $v = $material['rating'] >= 2.75 ? "" : ($material['rating'] >= 2.25 ? "-halffull" : "-empty") ?>
-                <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
-                <? $v = $material['rating'] >= 3.75 ? "" : ($material['rating'] >= 3.25 ? "-halffull" : "-empty") ?>
-                <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
-                <? $v = $material['rating'] >= 4.75 ? "" : ($material['rating'] >= 4.25 ? "-halffull" : "-empty") ?>
-                <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
-                <? if ($allowed_to_review) : ?>
-                    </a>
+<? if ($material->host && $material->host->isReviewable()) : ?>
+    <? $allowed_to_review = !$material->isMine() && $GLOBALS['perm']->have_perm("autor") ?>
+    <? if (!$material->isMine() || count($material->reviews)) : ?>
+        <article class="studip bordered">
+            <div class="center">
+                <? if ($material['rating'] === null) : ?>
+                    <? if ($allowed_to_review) : ?>
+                        <a style="opacity: 0.3;"
+                        title="<?= $GLOBALS['perm']->have_perm("autor") ? _('Geben Sie die erste Bewertung ab.') : _('Noch keine Bewertung abgegeben.') ?>"
+                        href="<?= $controller->link_for('oer/market/review/' . $material->getId()) ?>" data-dialog>
+                    <? endif ?>
+                    <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
+                    <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
+                    <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
+                    <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
+                    <?= Icon::create("star", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INACTIVE)->asImg(50) ?>
+                    <? if ($allowed_to_review) : ?>
+                        </a>
+                    <? endif ?>
+                <? else : ?>
+                    <? if ($allowed_to_review) : ?>
+                        <a href="<?= $controller->link_for('oer/market/review/' . $material->getId()) ?>" data-dialog title="<?= sprintf(_('%s von 5 Sternen'), round($material['rating'] / 2, 1)) ?>">
+                    <? endif ?>
+                    <? $material['rating'] = round($material['rating'], 1) / 2 ?>
+                    <? $v = $material['rating'] >= 0.75 ? "" : ($material['rating'] >= 0.25 ? "-halffull" : "-empty") ?>
+                    <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
+                    <? $v = $material['rating'] >= 1.75 ? "" : ($material['rating'] >= 1.25 ? "-halffull" : "-empty") ?>
+                    <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
+                    <? $v = $material['rating'] >= 2.75 ? "" : ($material['rating'] >= 2.25 ? "-halffull" : "-empty") ?>
+                    <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
+                    <? $v = $material['rating'] >= 3.75 ? "" : ($material['rating'] >= 3.25 ? "-halffull" : "-empty") ?>
+                    <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
+                    <? $v = $material['rating'] >= 4.75 ? "" : ($material['rating'] >= 4.25 ? "-halffull" : "-empty") ?>
+                    <?= Icon::create("star$v", $allowed_to_review ? Icon::ROLE_CLICKABLE : Icon::ROLE_INFO)->asImg(50) ?>
+                    <? if ($allowed_to_review) : ?>
+                        </a>
+                    <? endif ?>
                 <? endif ?>
-            <? endif ?>
-        </div>
+            </div>
 
-        <ul class="reviews">
-            <? foreach ($material->reviews as $review) : ?>
-                <li id="review_<?= $review->getId() ?>" class="review">
-                    <div class="avatar">
-                        <img width="50px" height="50px" src="<?= htmlReady($review['metadata']['host_id']
-                            ? ExternalUser::find($review['user_id'])->avatar_url
-                            : Avatar::getAvatar($review['user_id'])->getURL(Avatar::MEDIUM)) ?>">
-                    </div>
-                    <div class="content">
-                        <div class="timestamp">
-                            <?= date("j.n.Y G:i", $review['chdate']) ?>
-                        </div>
-                        <strong>
-                            <? if ($review['metadata']['host_id']) : ?>
-                                <? $user = ExternalUser::find($review['user_id']) ?>
-                                <a href="<?= $controller->link_for("oer/market/profile/".$user->getId()) ?>">
-                                    <?= htmlReady($user->name) ?>
-                                </a>
-                            <? else : ?>
-                                <? $user = new User($review['user_id']) ?>
-                                <a href="<?= URLHelper::getLink("dispatch.php/profile", ['username' => $user['username']]) ?>">
-                                    <?= htmlReady($user->getFullName()) ?>
-                                </a>
-                            <? endif ?>
-                        </strong>
-                        <span class="origin">(<?= htmlReady($review['metadata']['host_id'] ? $review->host['name'] : Config::get()->UNI_NAME_CLEAN) ?>)</span>
-                        <div class="review_text">
-                            <?= formatReady($review['content']) ?>
+            <ul class="reviews">
+                <? foreach ($material->reviews as $review) : ?>
+                    <li id="review_<?= $review->getId() ?>" class="review">
+                        <div class="avatar">
+                            <img width="50px" height="50px" src="<?= htmlReady($review['metadata']['host_id']
+                                ? ExternalUser::find($review['user_id'])->avatar_url
+                                : Avatar::getAvatar($review['user_id'])->getURL(Avatar::MEDIUM)) ?>">
                         </div>
-                        <div class="stars">
-                            <? $rating = round($review['metadata']['rating'], 1) ?>
-                            <? $v = $rating >= 0.75 ? "" : ($rating >= 0.25 ? "-halffull" : "-empty") ?>
-                            <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
-                            <? $v = $rating >= 1.75 ? "" : ($rating >= 1.25 ? "-halffull" : "-empty") ?>
-                            <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
-                            <? $v = $rating >= 2.75 ? "" : ($rating >= 2.25 ? "-halffull" : "-empty") ?>
-                            <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
-                            <? $v = $rating >= 3.75 ? "" : ($rating >= 3.25 ? "-halffull" : "-empty") ?>
-                            <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
-                            <? $v = $rating >= 4.75 ? "" : ($rating >= 4.25 ? "-halffull" : "-empty") ?>
-                            <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
+                        <div class="content">
+                            <div class="timestamp">
+                                <?= date("j.n.Y G:i", $review['chdate']) ?>
+                            </div>
+                            <strong>
+                                <? if ($review['metadata']['host_id']) : ?>
+                                    <? $user = ExternalUser::find($review['user_id']) ?>
+                                    <a href="<?= $controller->link_for("oer/market/profile/".$user->getId()) ?>">
+                                        <?= htmlReady($user->name) ?>
+                                    </a>
+                                <? else : ?>
+                                    <? $user = new User($review['user_id']) ?>
+                                    <a href="<?= URLHelper::getLink("dispatch.php/profile", ['username' => $user['username']]) ?>">
+                                        <?= htmlReady($user->getFullName()) ?>
+                                    </a>
+                                <? endif ?>
+                            </strong>
+                            <span class="origin">(<?= htmlReady($review['metadata']['host_id'] ? $review->host['name'] : Config::get()->UNI_NAME_CLEAN) ?>)</span>
+                            <div class="review_text">
+                                <?= formatReady($review['content']) ?>
+                            </div>
+                            <div class="stars">
+                                <? $rating = round($review['metadata']['rating'], 1) ?>
+                                <? $v = $rating >= 0.75 ? "" : ($rating >= 0.25 ? "-halffull" : "-empty") ?>
+                                <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
+                                <? $v = $rating >= 1.75 ? "" : ($rating >= 1.25 ? "-halffull" : "-empty") ?>
+                                <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
+                                <? $v = $rating >= 2.75 ? "" : ($rating >= 2.25 ? "-halffull" : "-empty") ?>
+                                <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
+                                <? $v = $rating >= 3.75 ? "" : ($rating >= 3.25 ? "-halffull" : "-empty") ?>
+                                <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
+                                <? $v = $rating >= 4.75 ? "" : ($rating >= 4.25 ? "-halffull" : "-empty") ?>
+                                <?= Icon::create("star$v", Icon::ROLE_INFO)->asImg(16) ?>
 
-                            <? if ($GLOBALS['perm']->have_perm("autor") && !count($review->comments)) : ?>
-                                <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>" style="font-size: 0.8em;">
-                                    <?= _('Darauf antworten') ?>
-                                </a>
-                            <? endif ?>
-                        </div>
-                        <div class="comments center">
-                            <? if (count($review->comments)) : ?>
-                                <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>">
-                                    <?= Icon::create("comment", Icon::ROLE_CLICKABLE)->asImg(16, ['class' => "text-bottom"]) ?>
-                                    <?= sprintf(_('%s Kommentare dazu'), count($review->comments)) ?>
-                                </a>
-                            <? elseif ($material->isMine()) : ?>
-                                <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>">
-                                    <?= Icon::create("comment", Icon::ROLE_CLICKABLE)->asImg(16, ['class' => "text-bottom"]) ?>
-                                    <?= _('Dazu einen Kommentar schreiben') ?>
-                                </a>
-                            <? endif ?>
+                                <? if ($GLOBALS['perm']->have_perm("autor") && !count($review->comments)) : ?>
+                                    <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>" style="font-size: 0.8em;">
+                                        <?= _('Darauf antworten') ?>
+                                    </a>
+                                <? endif ?>
+                            </div>
+                            <div class="comments center">
+                                <? if (count($review->comments)) : ?>
+                                    <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>">
+                                        <?= Icon::create("comment", Icon::ROLE_CLICKABLE)->asImg(16, ['class' => "text-bottom"]) ?>
+                                        <?= sprintf(_('%s Kommentare dazu'), count($review->comments)) ?>
+                                    </a>
+                                <? elseif ($material->isMine()) : ?>
+                                    <a href="<?= $controller->link_for("oer/market/discussion/".$review->getId()) ?>">
+                                        <?= Icon::create("comment", Icon::ROLE_CLICKABLE)->asImg(16, ['class' => "text-bottom"]) ?>
+                                        <?= _('Dazu einen Kommentar schreiben') ?>
+                                    </a>
+                                <? endif ?>
+                            </div>
                         </div>
-                    </div>
-                </li>
-            <? endforeach ?>
-        </ul>
+                    </li>
+                <? endforeach ?>
+            </ul>
 
-        <div class="center">
-            <? if (!$material->isMine() && $GLOBALS['perm']->have_perm("autor")) : ?>
-                <?= \Studip\LinkButton::create(_('Review schreiben'), $controller->url_for('oer/market/review/' . $material->getId()), ['data-dialog' => 1]) ?>
-            <? endif ?>
-        </div>
-    </article>
+            <div class="center">
+                <? if (!$material->isMine() && $GLOBALS['perm']->have_perm("autor")) : ?>
+                    <?= \Studip\LinkButton::create(_('Review schreiben'), $controller->url_for('oer/market/review/' . $material->getId()), ['data-dialog' => 1]) ?>
+                <? endif ?>
+            </div>
+        </article>
+    <? endif ?>
 <? endif ?>
 
 
-
 <?
 $actions = new ActionsWidget();
 $GLOBALS['perm']->have_perm(Config::get()->OER_PUBLIC_STATUS);
diff --git a/db/migrations/5.2.9_add_oersi.php b/db/migrations/5.2.9_add_oersi.php
new file mode 100644
index 0000000000000000000000000000000000000000..1b15d9ab2d2a6a969b3f5065ba3569a696014997
--- /dev/null
+++ b/db/migrations/5.2.9_add_oersi.php
@@ -0,0 +1,73 @@
+<?php
+
+class AddOersi extends Migration
+{
+    public function description ()
+    {
+        return 'Adds the OER-search-index OERSI to OER Campus.';
+    }
+
+    public function up()
+    {
+        DBManager::get()->exec("
+            ALTER TABLE `oer_hosts`
+            ADD COLUMN `sorm_class` varchar(50) DEFAULT 'OERHost' NOT NULL AFTER `host_id`
+        ");
+        DBManager::get()->exec("
+            INSERT IGNORE INTO `oer_hosts`
+            SET `host_id` = MD5('oersi'),
+                `name` = 'OERSI',
+                `sorm_class` = 'OERHostOERSI',
+                `url` = 'https://oersi.de',
+                `public_key` = '',
+                `private_key` = '',
+                `active` = '1',
+                `index_server` = '1',
+                `allowed_as_index_server` = '1',
+                `last_updated` = UNIX_TIMESTAMP(),
+                `chdate` = UNIX_TIMESTAMP(),
+                `mkdate` = UNIX_TIMESTAMP()
+        ");
+        DBManager::get()->exec("
+            ALTER TABLE `oer_material`
+            ADD COLUMN `source_url` varchar(256) DEFAULT NULL AFTER `published_id_on_twillo`,
+            ADD COLUMN `data` TEXT DEFAULT NULL AFTER `source_url`
+        ");
+        DBManager::get()->exec(
+            "INSERT IGNORE INTO `config`
+            (`field`, `value`, `type`, `range`,
+            `section`,
+            `mkdate`, `chdate`,
+            `description`)
+            VALUES
+            ('OER_OERSI_ONLY_DOWNLOADABLE', '1', 'boolean', 'global',
+            'OERCampus', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(),
+            'Should the search in OERSI only find downloadable OERs?')"
+        );
+    }
+
+    public function down()
+    {
+        DBManager::get()->exec("
+            ALTER TABLE `oer_hosts`
+            DROP COLUMN `sorm_class`
+        ");
+        DBManager::get()->exec("
+            DELETE FROM `oer_hosts`
+            WHERE `host_id` = MD5('oersi')
+        ");
+        DBManager::get()->exec("
+            ALTER TABLE `oer_material`
+            DROP COLUMN `source_url`,
+            DROP COLUMN `data`
+        ");
+        DBManager::get()->exec(
+            "DELETE FROM `config`
+            WHERE `field` = 'OER_OERSI_ONLY_DOWNLOADABLE'"
+        );
+        DBManager::get()->exec(
+            "DELETE FROM `config_values`
+            WHERE `field` = 'OER_OERSI_ONLY_DOWNLOADABLE'"
+        );
+    }
+}
diff --git a/lib/models/OERHost.php b/lib/models/OERHost.php
index 187e49f6f6c6fc3d4e7312cb1567191e3697004d..bba555d1e76e494747a1df86188930e8e847fca7 100755
--- a/lib/models/OERHost.php
+++ b/lib/models/OERHost.php
@@ -13,7 +13,7 @@ class OERHost extends OERIdentity
      */
     public static function thisOne()
     {
-        $host = self::findOneBySQL("private_key IS NOT NULL LIMIT 1");
+        $host = self::findOneBySQL("`private_key` IS NOT NULL AND `sorm_class` = 'OERHost' LIMIT 1");
         if ($host) {
             $host['url'] = $GLOBALS['oer_PREFERRED_URI'] ?: $GLOBALS['ABSOLUTE_URI_STUDIP']."dispatch.php/oer/endpoints/";
             if ($host->isFieldDirty("url")) {
@@ -39,6 +39,38 @@ class OERHost extends OERIdentity
         return self::findBySQL("1=1 ORDER BY name ASC");
     }
 
+    public static function URIExists($uri)
+    {
+        return (bool) OERMaterial::findOneBySQL("LEFT JOIN `oer_hosts` USING (`host_id`) WHERE (`oer_hosts`.`sorm_class` = 'OERHost' OR `oer_hosts`.`sorm_class` IS NULL) AND `uri_hash` = ?", [
+            md5($uri)
+        ]);
+    }
+
+    public static function findBySQL($sql, $params = [])
+    {
+        $hosts = parent::findBySQL($sql, $params);
+        foreach ($hosts as $key => $host) {
+            $class = $host['sorm_class'];
+            if ($class && ($class !== 'OERHost') && is_subclass_of($class, 'OERHost')) {
+                $data = $host->toRawArray();
+                $host = $class::buildExisting($data);
+                $hosts[$key] = $host;
+            }
+        }
+        return $hosts;
+    }
+
+    public static function find($id)
+    {
+        $host = parent::find($id);
+        $class = $host['sorm_class'];
+        if ($class && ($class !== 'OERHost') && is_subclass_of($class, 'OERHost')) {
+            $data = $host->toRawArray();
+            $host = $class::buildExisting($data);
+        }
+        return $host;
+    }
+
     /**
      * configures this class
      * @param array $config
@@ -111,7 +143,7 @@ class OERHost extends OERIdentity
 
     /**
      * Executes a search request on the host.
-     * @param string|null $text : the serach string
+     * @param string|null $text : the search string
      * @param string|null $tag : a tag to search for
      */
     public function fetchRemoteSearch($text = null, $tag = null)
@@ -203,9 +235,9 @@ class OERHost extends OERIdentity
      * @param string $foreign_material_id : foreign id of that oer-material
      * @return array|null : data of that material or null on error.
      */
-    public function fetchItemData($foreign_material_id)
+    public function fetchItemData(OERMaterial $material)
     {
-        $endpoint_url = $this['url']."get_item_data/".urlencode($foreign_material_id);
+        $endpoint_url = $this['url']."get_item_data/".urlencode($material['foreign_material_id']);
         $output = @file_get_contents($endpoint_url);
         if ($output) {
             $output = json_decode($output, true);
@@ -214,4 +246,55 @@ class OERHost extends OERIdentity
             }
         }
     }
+
+    public function getFrontImageURL(OERMaterial $material)
+    {
+        return $this['url']."download_front_image/".$material['foreign_material_id'];
+    }
+
+    public function isReviewable()
+    {
+        return true;
+    }
+
+    public function getAuthorsForMaterial(OERMaterial $material)
+    {
+        $users = [];
+        foreach ($material->users as $materialdata) {
+            if ($materialdata['external_contact']) {
+                $user = $materialdata['oeruser'];
+                $users[] = [
+                    'user_id' => $user['foreign_user_id'],
+                    'name' => $user['name'],
+                    'avatar' => $user['avatar'],
+                    'description' => $user['description'],
+                    'host_url' => $user->host['url'],
+                    'link' => URLHelper::getURL('dispatch.php/oer/market/profile/' . $user->getId()),
+                    'hostname' => $this['name']
+                ];
+            } else {
+                $user = User::find($materialdata['user_id']);
+                $users[] = [
+                    'user_id' => $user['user_id'],
+                    'name' => $user ? $user->getFullName() : _('unbekannt'),
+                    'avatar' => Avatar::getAvatar($user['user_id'])->getURL(Avatar::NORMAL),
+                    'description' => $user ? $user['oercampus_description'] : '',
+                    'host_url' => OERHost::thisOne()->url,
+                    'link' => URLHelper::getURL('dispatch.php/profile', ['username' => $user['username']]),
+                    'hostname' => $this['name']
+                ];
+            }
+        }
+        return $users;
+    }
+
+    public function getDownloadURLForMaterial(OERMaterial $material)
+    {
+        $base = URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
+        $url = $material['host_id']
+            ? $this->url . 'download/' . $material['foreign_material_id']
+            : URLHelper::getURL('dispatch.php/oer/endpoints/download/' . $material->getId());
+        URLHelper::setBaseURL($base);
+        return $url;
+    }
 }
diff --git a/lib/models/OERHostOERSI.php b/lib/models/OERHostOERSI.php
new file mode 100755
index 0000000000000000000000000000000000000000..3ceb23c4eeaf9a2e57afb70f0c9e21448588d3ad
--- /dev/null
+++ b/lib/models/OERHostOERSI.php
@@ -0,0 +1,173 @@
+<?php
+
+class OERHostOERSI extends OERHost
+{
+
+    /**
+     * Executes a search request on the host.
+     * @param string|null $text : the search string
+     * @param string|null $tag : a tag to search for
+     */
+    public function fetchRemoteSearch($text = null, $tag = null)
+    {
+        $endpoint_url = 'https://oersi.de/resources/api-internal/search/oer_data/_search';
+        $appendix = Config::get()->OER_OERSI_ONLY_DOWNLOADABLE ? ' AND _exists_:encoding.contentUrl' : '';
+        if ($tag) {
+            $endpoint_url .= '?q=' . urlencode("keywords:" . $tag . $appendix);
+        } else {
+            $endpoint_url .= '?q=' . urlencode($text . $appendix);
+        }
+        $output = @file_get_contents($endpoint_url);
+        if ($output) {
+            $output = json_decode($output, true);
+            foreach ((array) $output['hits']['hits'] as $material_data) {
+                //check if material already in database from this or another OER Campus host
+                if (OERHost::URIExists($material_data['_source']['id'])) {
+                    continue;
+                }
+
+                $material = OERMaterial::findOneBySQL('foreign_material_id = ? AND host_id = ?', [
+                    md5($material_data['_source']['id']),
+                    $this->getId()
+                ]);
+                if (!$material) {
+                    $material = new OERMaterial();
+                    $material['foreign_material_id'] = md5($material_data['_source']['id']);
+                    $material['host_id'] = $this->getId();
+                }
+                $material['name'] = mb_substr($material_data['_source']['name'], 0, 64);
+                $material['draft'] = '0';
+                $material['filename'] = '';
+                $material['short_description'] = '';
+                $material['description'] = $material_data['_source']['description'] ?: '';
+                $material['difficulty_start'] = 0;
+                $material['difficulty_start'] = 12;
+                $material['uri'] = $material_data['_source']['id'];
+                $material['source_url'] = $material_data['_source']['id'];
+                $material['content_type'] = $material_data['_source']['encoding'][0]['encodingFormat'] ?: '';
+                $material['license_identifier'] = $this->getLicenseID($material_data['_source']['license']['id']) ?: '';
+                if (!$material['category']) {
+                    $material['category'] = $material->autoDetectCategory();
+                }
+                $material['front_image_content_type'] = $material_data['_source']['image'] ? 'image/jpg' : null;
+                $material['data'] = [
+                    'front_image_url' => $material_data['_source']['image'],
+                    'download' => $material_data['_source']['encoding'][0]['contentUrl'] ?: '',
+                    'id' => $material_data['_id'],
+                    'authors' => $material_data['_source']['creator'],
+                    'organization' => $material_data['_source']['sourceOrganization'][0]['name'] ?: $material_data['_source']['publisher'][0]['name']
+                ];
+                $material->store();
+
+                //set topics:
+                //$material->setUsers([]);
+
+                //set topics:
+                $material->setTopics($material_data['_source']['keywords']);
+
+            }
+        }
+    }
+
+    /**
+     * Pushes some data to the foreign OERHost.
+     * @param string $endpoint : part behind the host-url like "push_data"
+     * @param array $data : the data to be pushed as an associative array
+     * @return bool|CurlHandle|resource
+     */
+    public function pushDataToEndpoint($endpoint, $data)
+    {
+        //nothing to do
+    }
+
+    /**
+     * Fetches all information of an item from that host. This is a request.
+     * @param string $foreign_material_id : foreign id of that oer-material
+     * @return array|null : data of that material or null on error.
+     */
+    public function fetchItemData(OERMaterial $material)
+    {
+        $endpoint_url = 'https://oersi.de/resources/' . urlencode($material['data']['id']) . '?format=json';
+        $output = @file_get_contents($endpoint_url);
+        if ($output) {
+            $output = json_decode($output, true);
+            if ($output) {
+                $data = [];
+                $data['name'] = mb_substr($output['name'], 0, 64);
+                $data['draft'] = '0';
+                $data['filename'] = '';
+                $data['short_description'] = '';
+                $data['description'] = $output['description'] ?: '';
+                $data['difficulty_start'] = 0;
+                $data['difficulty_start'] = 12;
+                $data['uri'] = $output['encoding'][0]['contentUrl'] ?: '';
+                $data['source_url'] = $output['id'];
+                $data['content_type'] = $output['encoding'][0]['encodingFormat'] ?: '';
+                $data['license_identifier'] = $this->getLicenseID($output['license']['id']) ?: '';
+                if (!$data['category']) {
+                    $data['category'] = $material->autoDetectCategory();
+                }
+                $data['front_image_content_type'] = $output['image'] ? 'image/jpg' : null;
+                $data['data'] = $material['data']->getArrayCopy();
+                $data['data']['download'] = $output['encoding'][0]['contentUrl'] ?: '';
+                $data['data']['front_image_url'] = $output['image'];
+                $data['data']['authors'] = $output['creator'];
+                $data['data']['organization'] = $output['sourceOrganization'][0]['name'] ?: $output['publisher'][0]['name'];
+                $data = [
+                    'data' => $data,
+                    'topics' => $output['keywords']
+                ];
+                return $data;
+            }
+        } else {
+            return ['deleted' => 1];
+        }
+    }
+
+    public function getFrontImageURL(OERMaterial $material)
+    {
+        return $material['data'] ? $material['data']['front_image_url'] : null;
+    }
+
+    /**
+     * Tries to match the CC-license URL from OERSI to an spdx-identifier, which is used in Stud.IP
+     * @param $license : an URL
+     * @return string|null
+     */
+    protected function getLicenseID($license)
+    {
+        preg_match("^https:\/\/creativecommons.org\/licenses\/([\w\d\-\.]+)\/([\w\d\-\.]+)^", $license, $matches);
+        if ($matches[0]) {
+            $spdx_id = 'CC-' . strtoupper($matches[1]) . '-' . strtoupper($matches[2]);
+            if (License::find($spdx_id)) {
+                return $spdx_id;
+            }
+        }
+        return null;
+    }
+
+    public function isReviewable()
+    {
+        return false;
+    }
+
+    public function getAuthorsForMaterial(OERMaterial $material)
+    {
+        $users = [];
+        $data = $material->data->getArrayCopy();
+        foreach ((array) $data['authors'] as $author) {
+            $users[] = [
+                'name' => $author['name'],
+                'hostname' => $data['organization'] ?: $this['name']
+            ];
+        }
+        return $users;
+    }
+
+    public function getDownloadURLForMaterial(OERMaterial $material)
+    {
+        return $material['uri'];
+    }
+
+
+}
diff --git a/lib/models/OERMaterial.php b/lib/models/OERMaterial.php
index d718d60ebbb070b43eca5631882de7d421fd9f2f..7612f70f9853ad411cc6cb40333ea58016f8865e 100755
--- a/lib/models/OERMaterial.php
+++ b/lib/models/OERMaterial.php
@@ -23,6 +23,7 @@ class OERMaterial extends SimpleORMap
             'foreign_key' => 'license_identifier'
         ];
         $config['serialized_fields']['structure'] = 'JSONArrayObject';
+        $config['serialized_fields']['data'] = 'JSONArrayObject';
         $config['registered_callbacks']['before_store'][] = "cbHashURI";
         $config['registered_callbacks']['before_delete'][] = "cbDeleteFile";
         parent::configure($config);
@@ -145,9 +146,11 @@ class OERMaterial extends SimpleORMap
         $id = $matches[1];
         $material = OERMaterial::find($id);
 
-        $url = $material['host_id']
-            ? $material->host->url."download/".$material['foreign_material_id']
-            : URLHelper::getURL("dispatch.php/oer/endpoints/download/".$material->getId());
+        if (!$material) {
+            return _('OER Material nicht vorhanden.');
+        }
+
+        $url = $material->getDownloadUrl();
 
         if ($material['player_url'] || $material->isPDF()) {
             if ($material['player_url']) {
@@ -171,6 +174,7 @@ class OERMaterial extends SimpleORMap
             $template = $tf->open("oer/embed/standard");
         }
         $template->url = $url;
+        $template->source_url = $material['source_url'];
         $template->material = $material;
         $template->id = $id;
         return $template->render();
@@ -184,7 +188,16 @@ class OERMaterial extends SimpleORMap
 
     public function cbHashURI()
     {
-        $this['uri_hash'] = md5($this['uri']);
+        $this['uri_hash'] = $this['uri'] ? md5($this['uri']) : '';
+    }
+
+    public function getAuthors()
+    {
+        if ($this->host) {
+            return $this->host->getAuthorsForMaterial($this);
+        } else {
+            return OERHost::thisOne()->getAuthorsForMaterial($this);
+        }
     }
 
     public function getTopics()
@@ -217,7 +230,7 @@ class OERMaterial extends SimpleORMap
             SET tag_hash = MD5(:tag),
                 material_id = :material_id
         ");
-        foreach ($tags as $tag) {
+        foreach ((array) $tags as $tag) {
             $insert_tag->execute([
                 'tag' => $tag
             ]);
@@ -238,11 +251,15 @@ class OERMaterial extends SimpleORMap
 
     public function getDownloadUrl()
     {
-        $base = URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
-        $url = $this['host_id']
-            ? $this->host->url."download/".$this['foreign_material_id']
-            : URLHelper::getURL("dispatch.php/oer/endpoints/download/".$this->getId());
-        URLHelper::setBaseURL($base);
+        if (!$this['host_id']) {
+            $base = URLHelper::setBaseURL($GLOBALS['ABSOLUTE_URI_STUDIP']);
+            $url = $this['host_id']
+                ? $this->host->url . 'download/' . $this['foreign_material_id']
+                : URLHelper::getURL('dispatch.php/oer/endpoints/download/' . $this->getId());
+            URLHelper::setBaseURL($base);
+        } else {
+            $url = $this->host->getDownloadURLForMaterial($this);
+        }
         return $url;
     }
 
@@ -261,7 +278,7 @@ class OERMaterial extends SimpleORMap
     {
         if ($this['front_image_content_type']) {
             if ($this['host_id']) {
-                return $this->host['url']."download_front_image/".$this['foreign_material_id'];
+                return $this->host->getFrontImageURL($this);
             } else {
                 return URLHelper::getURL("dispatch.php/oer/endpoints/download_front_image/".$this->getId());
             }
@@ -357,10 +374,7 @@ class OERMaterial extends SimpleORMap
         unset($data['data']['id']);
         unset($data['data']['user_id']);
         unset($data['data']['host_id']);
-        $data['users'] = [];
-        foreach ($this->users as $materialuser) {
-            $data['users'][] = $materialuser->getJSON();
-        }
+        $data['users'] = $myHost->getAuthorsForMaterial($this);
         $data['topics'] = [];
         foreach ($this->getTopics() as $tag) {
             if ($tag['name']) {
@@ -400,93 +414,90 @@ class OERMaterial extends SimpleORMap
 
     public function fetchData()
     {
-        if ($this['host_id']) {
-            $host = new OERHost($this['host_id']);
-            if ($host) {
-                $data = $host->fetchItemData($this['foreign_material_id']);
+        if ($this['host_id'] && $this->host) {
+            $data = $this->host->fetchItemData($this);
 
-                if (!$data) {
-                    return false;
-                }
+            if (!$data) {
+                return false;
+            }
 
-                if ($data['deleted']) {
-                    return "deleted";
-                }
+            if ($data['deleted']) {
+                return "deleted";
+            }
 
-                //material:
-                $material_data = $data['data'];
-                unset($material_data['material_id']);
-                unset($material_data['mkdate']);
-                $this->setData($material_data);
-                $this->store();
-
-                //topics:
-                $this->setTopics($data['topics']);
-
-                //user:
-                $this->setUsers($data['users']);
-
-                foreach ((array) $data['reviews'] as $review_data) {
-                    $currenthost = OERHost::findOneByUrl(trim($review_data['host']['url']));
-                    if (!$currenthost) {
-                        $currenthost = new OERHost();
-                        $currenthost['url'] = trim($review_data['host']['url']);
-                        $currenthost['last_updated'] = time();
-                        $currenthost->fetchPublicKey();
-                        if ($currenthost['public_key']) {
-                            $currenthost->store();
-                        }
+            //material:
+            $material_data = $data['data'];
+            unset($material_data['material_id']);
+            unset($material_data['mkdate']);
+            $this->setData($material_data);
+            $this->store();
+
+            //topics:
+            $this->setTopics($data['topics']);
+
+            //user:
+            $this->setUsers($data['users']);
+
+            foreach ((array) $data['reviews'] as $review_data) {
+                $currenthost = OERHost::findOneByUrl(trim($review_data['host']['url']));
+                if (!$currenthost) {
+                    $currenthost = new OERHost();
+                    $currenthost['url'] = trim($review_data['host']['url']);
+                    $currenthost['last_updated'] = time();
+                    $currenthost->fetchPublicKey();
+                    if ($currenthost['public_key']) {
+                        $currenthost->store();
+                    }
+                }
+                if ($currenthost && $currenthost['public_key'] && !$currenthost->isMe()) {
+                    $review = OERReview::findOneBySQL("
+                            context_id = :context_id
+                            AND `metadata` LIKE :foreign_review_id
+                            AND `metadata` LIKE :host_id", [
+                        'context_id' => $this->getId(),
+                        'foreign_review_id' => "%".$review_data['foreign_review_id']."%",
+                        'host_id' => "%".$currenthost->getId()."%"
+                    ]);
+                    if (!$review) {
+                        $review = new OERReview();
+                        $review['context_id'] = $this->getId();
+                        $review['context_type'] = "public";
+                        $review['display_class'] = "OERReview";
+                        $review['visible_in_stream'] = 0;
+                        $review['commentable'] = 1;
+                    }
+                    $review['content'] = $review_data['review'];
+                    $review['metadata'] = [
+                        'host_id' => $currenthost->getId(),
+                        'foreign_review_id' => $review_data['foreign_review_id'],
+                        'rating' => $review_data['rating']
+                    ];
+                    if ($review_data['chdate']) {
+                        $review['chdate'] = $review_data['chdate'];
                     }
-                    if ($currenthost && $currenthost['public_key'] && !$currenthost->isMe()) {
-                        $review = OERReview::findOneBySQL("
-                                context_id = :context_id
-                                AND `metadata` LIKE :foreign_review_id
-                                AND `metadata` LIKE :host_id", [
-                            'context_id' => $this->getId(),
-                            'foreign_review_id' => "%".$review_data['foreign_review_id']."%",
-                            'host_id' => "%".$currenthost->getId()."%"
-                        ]);
-                        if (!$review) {
-                            $review = new OERReview();
-                            $review['context_id'] = $this->getId();
-                            $review['context_type'] = "public";
-                            $review['display_class'] = "OERReview";
-                            $review['visible_in_stream'] = 0;
-                            $review['commentable'] = 1;
-                        }
-                        $review['content'] = $review_data['review'];
-                        $review['metadata'] = [
-                            'host_id' => $currenthost->getId(),
-                            'foreign_review_id' => $review_data['foreign_review_id'],
-                            'rating' => $review_data['rating']
-                        ];
-                        if ($review_data['chdate']) {
-                            $review['chdate'] = $review_data['chdate'];
-                        }
-                        if ($review_data['mkdate']) {
-                            $review['mkdate'] = $review_data['mkdate'];
-                        }
-
-                        $user = ExternalUser::findOneBySQL("foreign_id = :foreign_id AND host_id = :host_id", [
-                            'foreign_id' => $review_data['user']['user_id'],
-                            'host_id' => $currenthost->getId()
-                        ]);
-
-                        if (!$user) {
-                            $user = new ExternalUser();
-                            $user['foreign_id'] = $review_data['user']['user_id'];
-                            $user['host_id'] = $currenthost->getId();
-                        }
-                        $user['contact_type'] = "oercampus";
-                        $user['name'] = $review_data['user']['name'];
-                        $user['avatar_url'] = $review_data['user']['avatar'] ?: null;
-                        $user['data']['description'] = $review_data['user']['description'] ?: null;
-                        $user->store();
-
-                        $review['user_id'] = $user->getId();
-
-                        $review->store();
+                    if ($review_data['mkdate']) {
+                        $review['mkdate'] = $review_data['mkdate'];
                     }
+
+                    $user = ExternalUser::findOneBySQL("foreign_id = :foreign_id AND host_id = :host_id", [
+                        'foreign_id' => $review_data['user']['user_id'],
+                        'host_id' => $currenthost->getId()
+                    ]);
+
+                    if (!$user) {
+                        $user = new ExternalUser();
+                        $user['foreign_id'] = $review_data['user']['user_id'];
+                        $user['host_id'] = $currenthost->getId();
+                    }
+                    $user['contact_type'] = "oercampus";
+                    $user['name'] = $review_data['user']['name'];
+                    $user['avatar_url'] = $review_data['user']['avatar'] ?: null;
+                    $user['data']['description'] = $review_data['user']['description'] ?: null;
+                    $user->store();
+
+                    $review['user_id'] = $user->getId();
+
+                    $review->store();
                 }
             }
         }
diff --git a/lib/models/OERMaterialUser.php b/lib/models/OERMaterialUser.php
index 1e6babe4e2f2f1406ba1ea80b04608e2818e3b0e..9b4e1aa2829e11b58dd7d1952e7e92d46f0e3198 100755
--- a/lib/models/OERMaterialUser.php
+++ b/lib/models/OERMaterialUser.php
@@ -11,29 +11,10 @@ class OERMaterialUser extends SimpleORMap
             'foreign_key' => 'user_id'
         ];
 
+        $config['belongs_to']['material'] = [
+            'class_name' => OERMaterial::class,
+            'foreign_key' => 'material_id'
+        ];
         parent::configure($config);
     }
-
-    public function getJSON()
-    {
-        if ($this['external_contact']) {
-            $user = $this['oeruser'];
-            return [
-                'user_id' => $user['foreign_user_id'],
-                'name' => $user['name'],
-                'avatar' => $user['avatar'],
-                'description' => $user['description'],
-                'host_url' => $user->host['url']
-            ];
-        } else {
-            $user = User::find($this['user_id']);
-            return [
-                'user_id' => $user['user_id'],
-                'name' => $user ? $user->getFullName() : _("unbekannt"),
-                'avatar' => Avatar::getAvatar($user['user_id'])->getURL(Avatar::NORMAL),
-                'description' => $user ? $user['oercampus_description'] : "",
-                'host_url' => OERHost::thisOne()->url
-            ];
-        }
-    }
 }
diff --git a/lib/modules/CoreDocuments.class.php b/lib/modules/CoreDocuments.class.php
index 28fcae5cce7322d58d039227133e8bc008ccfb71..c7aff2dc05e855800a82649c527c147933154573 100644
--- a/lib/modules/CoreDocuments.class.php
+++ b/lib/modules/CoreDocuments.class.php
@@ -50,19 +50,30 @@ class CoreDocuments extends CorePlugin implements StudipModule, OERModule
             'content_terms_of_use_id' => "FREE_LICENSE",
             'description' => $material['description']
         ];
-        if ($material['host_id']) {
-            $tmp_name = $GLOBALS['TMP_PATH']."/oer_".$material->getId();
-            file_put_contents($tmp_name, file_get_contents($material->getDownloadUrl()));
-            $uploaded_file['tmp_name'] = $tmp_name;
-            $uploaded_file['type'] = filesize($tmp_name);
-        } else {
-            $uploaded_file['tmp_name'] = $material->getFilePath();
-            $uploaded_file['size'] = filesize($material->getFilePath());
-        }
+        $url = $material->getDownloadUrl();
+        if ($url) {
+            if ($material['host_id']) {
+                $tmp_name = $GLOBALS['TMP_PATH'] . '/oer_' . $material->getId();
+                file_put_contents($tmp_name, file_get_contents($url));
+                $uploaded_file['tmp_name'] = $tmp_name;
+                $uploaded_file['type'] = filesize($tmp_name);
+            } else {
+                $uploaded_file['tmp_name'] = $material->getFilePath();
+                $uploaded_file['size'] = filesize($material->getFilePath());
+            }
 
-        $standardfile = StandardFile::create($uploaded_file);
+            $standardfile = StandardFile::create($uploaded_file);
+        } elseif($material['source_url']) {
+            $standardfile = URLFile::create([
+                'url' => $material['source_url'],
+                'name' => $material['name'],
+                'author_name' => implode(', ', array_map(function ($a) { return $a['name']; }, $material)),
+                'description' => $material['description'],
+                'content_terms_of_use_id' => "FREE_LICENSE"
+            ]);
+        }
 
-        if ($standardfile->getSize()) {
+        if ($standardfile->getSize() || is_a($standardfile, 'URLFile')) {
             $error = $folder->validateUpload($standardfile, User::findCurrent()->id);
             if ($error && is_string($error)) {
                 if ($tmp_name) {
diff --git a/resources/assets/javascripts/lib/oer.js b/resources/assets/javascripts/lib/oer.js
index 701a37b90a2af89f1108e71723fa70ae795e95da..dac19ec56ad17cf652330bb68851b8ed7d753741 100755
--- a/resources/assets/javascripts/lib/oer.js
+++ b/resources/assets/javascripts/lib/oer.js
@@ -186,6 +186,13 @@ const OER = {
                     },
                     getMaterialURL: function (material_id) {
                         return this.material_select_url_template.replace("__material_id__", material_id);
+                    },
+                    shortenName: function (name) {
+                        if (name.length > 55) {
+                            return name.substring(0, 50) + ' ...';
+                        } else {
+                            return name;
+                        }
                     }
                 },
                 mounted: function () {
diff --git a/resources/assets/stylesheets/scss/oer.scss b/resources/assets/stylesheets/scss/oer.scss
index 5e2df197e0e843503906d9dac8f24e5f3780dddf..6af5b26b1b161b79246b3a6a62c892fdddb85e0f 100755
--- a/resources/assets/stylesheets/scss/oer.scss
+++ b/resources/assets/stylesheets/scss/oer.scss
@@ -373,10 +373,6 @@ ul.reviews, ol.reviews {
         display: none !important;
     }
 
-    article.contentbox {
-        animation: oer-material-appears 200ms ease-out;
-    }
-
     .browser {
         margin-top: 15px;
         padding: 10px;
@@ -462,18 +458,6 @@ ul.reviews, ol.reviews {
     }
 }
 
-@keyframes oer-material-appears {
-    from {
-        opacity: 0;
-        max-width: 0px;
-        overflow: hidden;
-    }
-    to {
-        overflow: hidden;
-        max-width: 270px;
-        opacity: 1;
-    }
-}
 
 @keyframes oer-tag-appears {
     from {