三无青年

热爱生活,重新开始

跟风利用FreshRSS实现朋友圈

文章目录[隐藏]

前言

最开始我用的是阿锋的朋友圈插件,这是我第一次见把友链整合到RSS订阅把它展现出来,那会儿很好奇,就使用了阿锋的晨风自定义插件。后面看到了hexo-circle-of-friends,网上找了半天没看到WordPress上面实现的方法。后面才看到了若志的这篇文章,索性就搞了起来。

实现步骤

首先要搭建FreshRSS,这个教程很多,我使用的是服务器搭建,纯宝塔操作,简单不复杂。

1、添加站点,注意:需要确认已经安装了 PHP 扩展 fileinfo(我的默认安装了)。接下来在宝塔面板创建新站点,设置好数据库与 PHP 版本。数据库我选择的是mysql,PHP版本是0。然后,删去网站根目录下默认添加创建的所有文件,确保文件夹全部清空。打开站点根目录,把 FreshRSS 源代码上传到网站根目录,域名访问开始安装。

2、安装完成后进入设置-账户-API 管理,填写api密码提交。

3、进入设置-认证,勾选允许 API 访问 (用于手机应用),提交。

4、添加你的友链feed地址,我试了一下,直接输入友链域名大部分的rss地址可以自动获取,少部分不知道rss地址的可以安装浏览器插件查看或者问博主本人。

5、不知道是不是我安装的有问题,点击添加的友链管理,会弹出502 Bad Gateway nginx。不过双击还是就进去了,可以进行删除修改等操作,凑合着用吧。

6、在自己站点根目录下创建一个php文件,用于放FreshRSS api调用函数,例如:rss.php。访问https://你的博客域名/rss.php,显示数据已保存到JSON文件中。

<?php
/**
 * 获取最新订阅文章并生成JSON文件
 */
function getAllSubscribedArticlesAndSaveToJson($user, $password)
{
    $apiUrl = 'https://你部署FreshRSS的域名/p/api/greader.php';
    $loginUrl = $apiUrl . '/accounts/ClientLogin?Email=' . urlencode($user) . '&Passwd=' . urlencode($password);
    $loginResponse = curlRequest($loginUrl);
    if (strpos($loginResponse, 'Auth=') !== false) {
        $authToken = substr($loginResponse, strpos($loginResponse, 'Auth=') + 5);
        $articlesUrl = $apiUrl . '/reader/api/0/stream/contents/reading-list?&n=1000';
        $articlesResponse = curlRequest($articlesUrl, $authToken);
        $articles = json_decode($articlesResponse, true);
        if (isset($articles['items'])) {
            usort($articles['items'], function ($a, $b) {
                return $b['published'] - $a['published'];
            });
            $subscriptionsUrl = $apiUrl . '/reader/api/0/subscription/list?output=json';
            $subscriptionsResponse = curlRequest($subscriptionsUrl, $authToken);
            $subscriptions = json_decode($subscriptionsResponse, true);
            if (isset($subscriptions['subscriptions'])) {
                $subscriptionMap = array();
                foreach ($subscriptions['subscriptions'] as $subscription) {
                    $subscriptionMap[$subscription['id']] = $subscription;
                }
                $formattedArticles = array();
                foreach ($articles['items'] as $article) {
                    $desc_length = mb_strlen(strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8')), 'UTF-8');
                    if ($desc_length > 20) {
                        $short_desc = mb_substr(strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8')), 0, 99, 'UTF-8') . '...';
                    } else {
                        $short_desc = strip_tags(html_entity_decode($article['summary']['content'], ENT_QUOTES, 'UTF-8'));
                    }
                    
                    $formattedArticle = array(
                        'site_name' => $article['origin']['title'],
                        'title' => $article['title'],
                        'link' => $article['alternate'][0]['href'],
                        'time' => date('Y-m-d H:i', $article['published']),
                        'description' => $short_desc,
                    );

                    $subscriptionId = $article['origin']['streamId'];
                    if (isset($subscriptionMap[$subscriptionId])) {
                        $subscription = $subscriptionMap[$subscriptionId];
                        $iconUrl = $subscription['iconUrl'];
                        $filename = 'https://你部署FreshRSS的域名/p/'.substr($iconUrl, strrpos($iconUrl, '/') + 1);
                        $formattedArticle['icon'] = $filename;
                    }

                    $formattedArticles[] = $formattedArticle;
                }

                saveToJsonFile($formattedArticles);
                return $formattedArticles;
            } else {
                echo 'Error retrieving articles.';
            }
        } else {
            echo 'Error retrieving articles.';
        }
    } else {
        echo 'Login failed.';
    }
    return null;
}
function curlRequest($url, $authToken = null)
{
    $ch = curl_init($url);
    if ($authToken) {
        $headers = array(
            'Authorization: GoogleLogin auth=' . $authToken,
        );
        curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    }
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $response = curl_exec($ch);
    curl_close($ch);
    return $response;
}
/**
 * 将数据保存到JSON文件中
 */
function saveToJsonFile($data)
{
    $json = json_encode($data, JSON_PRETTY_PRINT | JSON_UNESCAPED_UNICODE);
    file_put_contents('output.json', $json);
    echo '数据已保存到JSON文件中';
}

// 调用函数并提供用户名和密码
getAllSubscribedArticlesAndSaveToJson('这里是FreshRSS的用户名', '这里是第3步设置的api密码');

注意:'https://你部署FreshRSS的域名/p/,没证书是http(最好带上证书,不然图标获取不到),还有后面的/p/. 新建页面,在正文里面输入简码:

7、我是用的是添加页面使用简码将其显示出来,在子主题的funtions.php里添加以下代码:

// 在 functions.php 中添加 shortcode 函数
function display_articles_shortcode() {
    // 获取JSON数据
    $jsonData = file_get_contents('./output.json');
    // 将JSON数据解析为PHP数组
    $articles = json_decode($jsonData, true);
    // 对文章按时间排序(最新的排在前面)
    usort($articles, function ($a, $b) {
        return strtotime($b['time']) - strtotime($a['time']);
    });
    // 设置每页显示的文章数量
    $itemsPerPage = 30;

    // 生成文章列表
    ob_start(); // 开始缓存输出
    foreach (array_slice($articles, 0, $itemsPerPage) as $article) {
    ?>
        <div class="article">
            <h3>
                <img src="<?php echo htmlspecialchars($article['icon']); ?>" alt="Icon" class="icon">
                <a href="<?php echo htmlspecialchars($article['link']); ?>" target="_blank"><?php echo htmlspecialchars($article['title']); ?></a>
            </h3>
            <p>作者:<?php echo htmlspecialchars($article['site_name']); ?></p>
            <p><?php echo htmlspecialchars($article['description']); ?></p>
            <time><?php echo htmlspecialchars($article['time']); ?></time>
        </div>
    <?php
    }
    return ob_get_clean(); // 返回缓存的输出并清除缓存
}

// 注册简码
add_shortcode('display_articles', 'display_articles_shortcode');

8、可以自定义css样式让其精致的显示,这是我的css代码:

/* Article container */
.article {
    border: 1px solid #ccc;
    border-radius: 5px;
    padding: 15px;
    margin-bottom: 20px;
}

/* Article title */
.article h3 {
    margin-top: 0;
}

/* Article icon */
.icon {
    width: 50px;
    height: 50px;
    margin-right: 10px;
    border-radius: 50%;
}

/* Article metadata */
.article p, .article time {
    margin: 5px 0;
}

/* Article time */
.article time {
    font-style: italic;
}

/* Hover effect on article */
.article:hover {
    box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
    transition: box-shadow 0.3s ease;
}
/* Article icon */
.icon {
    width: 1.5em; /* 使用 em 单位可以根据标题字体大小调整图标大小 */
    height: auto; /* 自动调整高度以保持宽高比 */
    margin-right: 10px;
    vertical-align: middle; /* 垂直居中对齐 */
    border-radius: 50%;
}

9、在宝塔添加一个计划任务,定时访问执行第6步创建的php文件,以更新订阅数据。官网里说的那个自动刷新订阅源的方法,我按照官网设置了每隔30分钟刷新,不知道咋回事儿不管用,每次都要自己刷新后才更新订阅源。

结语

自己部署rss订阅源是一件非常有成就感的事儿,过程也是艰辛,尤其是我这种不会代码的,更是辛苦,一步一步地查看错误,幸好有GPT,帮我可以查找问题,解决问题,不至于求人。

评论

《 “跟风利用FreshRSS实现朋友圈” 》 有 37 条评论

  1. 从良未遂 的头像

    你好,咨询两个问题:
    1.我复制的rss代码里没有/p/,域名是https的,但是获取不到图片,需要加上/p/吗?
    2.如果文章较多,也只是显示一页,怎么分页呢?

    1. 段先森 的头像

      /p/是必须加上的。文章较多之前也遇到过,研究半天没研究明白,就再没研究过 😀

  2. Pipu 的头像

    我在你的基础上新增了两个功能,哈哈哈哈,欢迎体验:https://pipuwong.com/friend-link-to-moments

    1. 段先森 的头像

      可以呀,非常nice

  3. Pipu 的头像

    问了GPT,等博主更新代码。

    GPT:
    根据您提供的主题的 functions.php 文件内容,错误信息指出问题出现在 usort() 函数的第一个参数必须是数组,但实际传入的是 null。这可能是因为从 output.json 文件中读取的数据为空或无法解析为有效的数组,导致在排序时出现问题。

    为了解决这个问题,您可以按照以下步骤进行操作:

    检查 output.json 文件:

    确保 output.json 文件存在于正确的路径,并且包含有效的 JSON 数据。
    检查文件路径是否正确,并且 PHP 有权限读取该文件。
    处理 JSON 数据:

    在读取和解析 JSON 数据之前,最好添加一些错误处理代码,以确保数据有效性。
    您可以使用 json_last_error() 和 json_last_error_msg() 函数来检查 JSON 解析过程中是否发生了错误,并根据需要进行处理。
    处理空数据情况:

    如果 output.json 中的数据为空,或者无法解析为有效的数组,您可能需要添加适当的错误处理代码来处理这种情况。
    可以在解析数据之后检查数组是否为空,避免将空数组传递给 usort() 函数。
    调试排序逻辑:

    您可以添加一些调试语句来输出读取的 JSON 数据以及排序后的数组,以便更好地了解问题所在。
    可以在 usort() 函数调用之前输出 $articles 数组,以确保它包含有效的数据。
    备份并测试修改:

    在对 functions.php 文件进行任何更改之前,请确保先备份文件。
    对修改后的代码进行测试,确保问题得到解决,并且没有引入新的错误。
    通过以上步骤,您应该能够解决 Caards Child 主题中 usort() 函数导致的错误问题。

  4. Pipu 的头像

    插入主题functions.php以后,是可以显示好友文案饿了,但是一点击编辑页面,就出现错误哦:此站点遇到了致命错误,请查看您站点管理员电子邮箱中收到的邮件来获得指引。

    错误提示位置在 :

    // 对文章按时间排序(最新的排在前面)
    usort($articles, function ($a, $b) {
    return strtotime($b['time']) - strtotime($a['time']);
    });

    请问如何解决哦?

    1. 段先森 的头像

      我的好像没遇到过,我研究研究

  5. Pipu 的头像

    你好,搭建完了。但是有一个问题,左边的图片出不来,请问是什么情况?
    https://img.gugu.ovh/i/2024/04/17/132903.webp

    1. 段先森 的头像

      调用的图标没出来,是没开启ssl嘛

      1. Pipu 的头像

        已经可以了。要去地址栏 输入域名/rss.php

        1. 从良未遂 的头像

          你好,这句话是什么意思:要去地址栏。。。我也是不显示图片

  6. 段先森 的头像

    要不是张老师提醒,我都不知道,这篇文章缺少部分代码,现已更新

  7. 大雄 的头像

    是个什么高端的操作.

  8. 大峰 的头像

    这个很方便啊,我都是一个个打开网站去看的~

  9. 格子老师 的头像

    另外,我看大家目前都是直接读取api 没考虑把api的数据记录到数据库,然后就可以实现分页展示历史文章了。前台再增加代码检测网址可用性 不可用的,前台也就不展示了。

    1. 格子老师 的头像

      另外,跳转链接 没设置成新窗口打开,不便于自己页面的留存。

    2. 格子老师 的头像

      保存到自己数据库后,还可以前台使用代码读取对应文章ID 然后通过读取到的ID 获取文章链接 这个操作的同时,还能记录该篇文章的点击次数,这样又可以实现本地的点击排行 或者阅读排行什么的。 也算是增加功能了,反正是折腾。

  10. 粽叶加米 的头像

    真不错,FreshRSS有api功能,之前很多博友安利过,我就本地安装试了一下,很方便实用。

    1. 段先森 的头像

      确实呀,我也是这两天才看到,大佬还是厉害

  11. 格子老师 的头像

    这个模板 看着不错啊

    1. 段先森 的头像

      哈哈,格子老师,你的博客咋样了,还是没好嘛

      1. 格子老师 的头像

        还是有端口号 但一直正常运行着呢 没有关闭

  12. maqingxi 的头像

    这个功能看着就特别帅,如果能读取缩略图就更完美了。

    1. 段先森 的头像

      缩略图那个我不知道哪里出问题,出不来所以取消了,完了再试试

  13. 老张博客 的头像

    这也是我想折腾的事。

    1. 段先森 的头像

      张老师再完美一下 😳

    2. 格子老师 的头像

      缩略图 好像有一个网站能通过网址自动生成 我之前记着的没找到 但是百度搜索 有好多

  14. HWL 的头像

    不错!以前也找过类似解决方案,找不到放弃了

    1. 段先森 的头像

      那就再尝试尝试呗

  15. 梦不见的梦 的头像

    我的订阅不知道为啥总是出现些莫名其妙的问题,就是别人网站更新了我订阅获取不到 :zhuakuang:

    1. 段先森 的头像

      我一般都是自己更新订阅源,我看了一下,慢慢的就全了,

  16. obaby 的头像

    哦吼,又一个朋友圈~~

    1. 段先森 的头像

      我看了一下你的,好复杂,不会弄,哈哈

  17. 林羽凡 的头像

    你正在朝大佬的路上靠近,哈哈哈

    1. 段先森 的头像

      哈哈,瞎折腾了 😳

回复 大峰 取消回复

您的邮箱地址不会被公开。 必填项已用 * 标注