友链的朋友圈 RSS的聚合页 (Typecho->handsome主题篇)

本文代码基于Typecho构建,handsome主题测试,其他主题理论上不通用

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版)请参考如下文章:

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版) 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版) 本文代码基于WordPress构建,PIX主题测试,其他主题理论上通用。 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)请参考如下文章: [pix_po... 时间:2023/12/26 分类:技术相关

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版)请参考如下文章:

友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版) 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&本地解析版) 本文适用于友链网站内容频繁更新的情况 友链的朋友圈 RSS的聚合页 (WordPress->PIX主题篇&在线解析版)请参考如下文章: [pix_post ids=561] 之所以又出了一个本... 时间:2024/1/9 分类:技术相关

WordPress的RSS朋友圈发布后,感觉应该也可以为Typecho出一个,但是去做了,却发现不是那么回事儿,主要是对Typecho太不熟悉了,最后比葫芦画瓢,基于很受欢迎的handsome主题堆出来一个聚合页。

加入了异步加载机制,并支持缓存,默认8小时。

重要提示:假如以下代码文件在handsome文件夹下,使用缓存时,在handsome文件夹下建立rsscache目录,总之此文件和rsscache目录必须在同一个目录下。

第一次刷新获取,所有友链将缓存存储在rsscache目录下,8小时内刷新页面直接取cache文件显示。8小时后,重新访问这些feed地址并解析计算MD5值,如果MD5值没有变化说明友链网站未更新,则xml不变,如果MD5值变化,则重新获取该站的xml文件并存储在rsscache目录下文件,同域名下的旧xml文件自动删除。如果需要强制更新,删除rsscache目录下所有文件并重新刷新页面即可。

本地演示如下:

友链的朋友圈 RSS的聚合页 (Typecho->handsome主题篇)-似水流年

代码如下:

[reply]

<?php
/**
 * RSS朋友圈
 *
 * @package custom
 */
if (!defined('__TYPECHO_ROOT_DIR__')) exit;
$this->need('component/header.php');
?>
<?php $this->need('component/aside.php'); ?>

<style>.avatar{width:60px;height:60px;border-radius:50%;transition:transform 1s ease-in-out;margin:0 auto}.avatar:hover{transform:rotate(360deg)}.post-content{display:flex;flex-wrap:wrap;justify-content:flex-start;align-items:stretch}.post-content-item{flex-basis:100%;display:flex;border:1px dashed #ccc;margin-bottom:20px}.post-content-left{flex-basis:20%;display:flex;flex-direction:column;justify-content:space-around;padding:10px;box-sizing:border-box}.post-content-right{flex-basis:80%;display:flex;flex-direction:column;justify-content:space-between;padding:10px;box-sizing:border-box}.site-name{text-align:center;cursor:pointer}.post-title{cursor:pointer;font-size:1.8rem}.post-content-description{margin-bottom:10px}.author-info{text-align:right}</style>

<main class="app-content-body" <?php Content::returnPageAnimateClass($this); ?>>
    <div class="hbox hbox-auto-xs hbox-auto-sm">
        <div class="content">
            <article class="post">
                <div class="post-content" id="post-content">
                    <?php
                    $rssFeeds = [];

                    // 获取Typecho的链接信息
                    $links = Typecho_Db::get()->fetchAll(Typecho_Db::get()->select()->from('table.links'));

                    foreach ($links as $link) {
                        $url = rtrim($link['url'], '/');
                        $domain = parse_url($url, PHP_URL_HOST);

                        if (!preg_match('#^https?://#i', $url)) {
                            $url = 'http://' . $url;
                        }

                        if (substr($url, -1) === '/') {
                            $url .= 'feed';
                        } else {
                            $url .= '/feed';
                        }

                        $feedMd5 = md5($url);
                        $cacheFile = __DIR__ . '/rsscache/' . $domain . '.' . $feedMd5 . '.xml';

                        $rssContent = '';

                        if (file_exists($cacheFile) && filemtime($cacheFile) > time() - 28800) {
                            $rssContent = file_get_contents($cacheFile);
                        } else {
                            $context = stream_context_create([
                                'ssl' => [
                                    'verify_peer' => false,
                                    'verify_peer_name' => false
                                ]
                            ]);
                            $rssContent = file_get_contents($url, false, $context);

                            if ($rssContent !== false) {
                                // 删除旧的缓存文件
                                $oldFiles = glob(__DIR__ . '/rsscache/' . $domain . '.*.xml');
                                foreach ($oldFiles as $file) {
                                    if ($file !== $cacheFile) {
                                        unlink($file);
                                    }
                                }
                                
                                // 将新的内容写入新的缓存文件
                                file_put_contents($cacheFile, $rssContent);
                            }
                        }

                        if ($rssContent === false) {
                            echo '获取 ' . $domain . ' 的 RSS 内容失败';
                            continue;
                        }

                        $rss = simplexml_load_string($rssContent, 'SimpleXMLElement', LIBXML_NOCDATA);

                        if ($rss === false) {
                            echo '解析 ' . $domain . ' 的 RSS 内容失败';
                            continue;
                        }

                        $siteLink = (string) $rss->channel->link;
                        $items = $rss->channel->item;

                        foreach ($items as $item) {
                            $description = (string) $item->description;

                            if (empty($description)) {
                                $description = mb_substr(strip_tags((string) $item->content), 0, 80, 'utf-8');
                            } else {
                                $description = mb_substr(strip_tags($description), 0, 80, 'utf-8');
                            }

                            if (mb_strlen(strip_tags($description), 'utf-8') > 80) {
                                $description = rtrim($description);
                                $description = mb_substr($description, 0, mb_strrpos($description, ' ', 0, 'utf-8'), 'utf-8') . '...';
                            }

                            $description = html_entity_decode($description, ENT_QUOTES, 'utf-8');

                            $rssFeeds[] = [
                                'title' => (string) $item->title,
                                'link' => (string) $item->link,
                                'pubDate' => strtotime((string) $item->pubDate),
                                'name' => htmlspecialchars($link['name']),
                                'image' => htmlspecialchars($link['image']),
                                'description' => htmlspecialchars($description),
                                'author' => (string) $item->children('dc', true)->creator,
                                'siteLink' => htmlspecialchars($siteLink)
                            ];
                        }
                    }

                    usort($rssFeeds, function ($a, $b) {
                        return $b['pubDate'] - $a['pubDate'];
                    });

                    // 默认显示友链网站的最新50条内容
                    $rssFeeds = array_slice($rssFeeds, 0, 50);

                    foreach ($rssFeeds as $rssFeed) {
                        echo '<div class="post-content-item">';
                        echo '<div class="post-content-left">';
                        echo '<img class="avatar" src="' . $rssFeed['image'] . '" alt="站标">';
                        echo '<p class="site-name" onclick="window.open(\'' . $rssFeed['siteLink'] . '\', \'_blank\')">' . $rssFeed['name'] . '</p>';
                        echo '</div>';
                        echo '<div class="post-content-right">';
                        echo '<h4 class="post-title" onclick="window.open(\'' . $rssFeed['link'] . '\', \'_blank\')">' . $rssFeed['title'] . '</h4>';
                        echo '<p class="post-content-description">' . $rssFeed['description'] . '</p>';
                        echo '<p class="author-info">作者:' . $rssFeed['author'] . ' | 更新时间:' . date('Y-m-d H:i:s', $rssFeed['pubDate']) . '</p>';
                        echo '</div>';
                        echo '</div>';
                    }
                    ?>
                </div>
            </article>
        </div>

        <?php echo WidgetContent::returnRightTriggerHtml() ?>
        <?php $this->need('component/sidebar.php'); ?>
    </div>
</main>

<script>
    window.addEventListener('DOMContentLoaded', function () {
        var postContent = document.getElementById('post-content');
        var page = 2;

        function loadMoreContent() {
            var xhr = new XMLHttpRequest();
            xhr.open('GET', '<?php echo $this->options->siteUrl; ?>/page/' + page, true);

            xhr.onload = function () {
                if (xhr.status === 200) {
                    var response = xhr.responseText;
                    var temp = document.createElement('div');
                    temp.innerHTML = response;

                    var newContent = temp.querySelector('#post-content');
                    if (newContent) {
                        postContent.innerHTML += newContent.innerHTML;
                        page++;
                    }
                }
            };

            xhr.send();
        }

        window.addEventListener('scroll', function () {
            var scrollTop = window.pageYOffset || document.documentElement.scrollTop;
            var windowHeight = window.innerHeight || document.documentElement.clientHeight;
            var documentHeight = document.documentElement.scrollHeight;

            if (scrollTop + windowHeight >= documentHeight - 100) {
                loadMoreContent();
            }
        });
    });
</script>

<?php $this->need('component/footer.php'); ?>

[/reply]

大功告成!

Comments | 13 条评论
  • ymz316

    Firefox 128 Firefox 128 GNU/Linux GNU/Linux 1中国 中国电信 ip address 240e:381:dad8:b400:*:*

    向大佬学习,看能不能给自己的网站加上这个功能。

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国 中国联通 ip address 2408:8220:6112:e330:*:*

      欢迎👏

  • 酷酷

    Microsoft Edge 131 Microsoft Edge 131 Windows 10 Windows 10 1中国–新疆–乌鲁木齐 电信 ip address 49.112.*.*

    看看吧

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南–漯河 电信 ip address 222.89.*.*

      这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。

  • Booky

    IBrowse r IBrowse r Android 12 Android 12 1中国 中国联通 ip address 2408:8463:1430:487d:*:*

    学习一下

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南–漯河 电信 ip address 222.89.*.*

      这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。

  • 一只小白菜

    Google Chrome 116 Google Chrome 116 Android 13 Android 13 1中国–江苏–无锡 联通 ip address 122.193.*.*

    看看,确实不错

    • 似水流年

      IBrowse r IBrowse r Android 12 Android 12 1中国–河南–漯河 电信 ip address 222.89.*.*

      这个慎用,因为我对typecho不太了解。我本地调试没有错误,但是听朋友说传到网站上不行。

  • obaby

    Google Chrome 120 Google Chrome 120 Windows 10 Windows 10 1中国–山东–临沂 联通 ip address 39.65.*.*

    竟然还有广告?abp 屏蔽了~~

    • 网友小宋

      Microsoft Edge 119 Microsoft Edge 119 Android 10 Android 10 1中国–河南–驻马店 移动 ip address 39.163.*.*

      就是谷歌那种色色广告,要嘛就是梯子广告。

    • 似水流年

      Google Chrome 99 Google Chrome 99 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 182.126.*.*

      我荣耀浏览器自带屏蔽。😂

  • 网友小宋

    Microsoft Edge 119 Microsoft Edge 119 Android 10 Android 10 1中国–河南–南阳 移动 ip address 117.136.*.*

    这个在线精品,无需等待的广告,给我整得不知道该怎么回了。

    • 似水流年

      Microsoft Edge 120 Microsoft Edge 120 Windows 10 Windows 10 1中国–河南–漯河 联通 ip address 182.126.*.*

      😂插入的谷歌广告。

消息盒子
# 您需要首次评论以获取消息 #
# 您需要首次评论以获取消息 #

只显示最新10条未读和已读信息