IT博客汇
  • 首页
  • 精华
  • 技术
  • 设计
  • 资讯
  • 扯淡
  • 权利声明
  • 登录 注册

    我和 ChatGPT4 把友情链接改成了“朋友圈“

    pipu发表于 2024-04-17 17:43:08
    love 0

    今天看到了 段先生 的文章,他用Freshrss的API在个人网站上面,实现了“朋友圈”。
    我也想弄一个,说干就干,我和ChatGPT4在他的基础上新增了一些功能:

    • 新增加载更多 按钮:默认显示 10 篇最新的文章,每次点击“加载更多”按钮时,都会通过 AJAX 请求加载更多文章,并在当前文章列表后追加新加载的文章。同时,如果还有更多文章可加载,新的“加载更多”按钮也会被添加到页面上。
    • 避免网站SEO权重分散:我在每个文章链接(<a> 标签)都被添加了 rel="nofollow" 属性。这样,当搜索引擎蜘蛛爬取这些页面时,知道不跟随这些链接,这有助于管理网站的SEO链接权重分配。

    效果展示:https://pipuwong.com/friends

    甚至,我们还做了 2 个版本:
    版本一:手动加载,手动点击加载更多 按钮

    版本 2:自动加载,滑到底部加载更多最新文章,就像跟刷朋友圈一样地爽

    大家可选择不同的版本进行使用,Enjoy ! ☀

    实现思路

    通过 FreshRSS 的 API 获取订阅源的文章,并在 WordPress 中展示这些文章。

    流程

    安装Freshrss —— 设置Freshrss API访问权限和密码 —— 添加rss.php —— 编辑主题funtions.php文件 —— 添加自定义CSS —— 添加自动加载按钮 —— 订阅好友的 RSS

    具体步骤

    通过Docker 安装部署 Freshrss

    新建docker compose.yml文件,并且输入以下代码
    因为新版的docker已经去掉了version: “3”,所以在此也去掉了

    # ~/freshrss/docker-compose.yml
    
    services:
    
    freshrss-db:
    
    image: postgres:latest
    
    container_name: freshrss-db
    
    hostname: freshrss-db
    
    restart: unless-stopped
    
    volumes:
    
    - ./freshrss-db:/var/lib/postgresql/data
    
    environment:
    
    POSTGRES_USER: freshrss
    
    POSTGRES_PASSWORD: df6Qi5SnPQUdScsagzB
    
    POSTGRES_DB: freshrss
    
    freshrss-app:
    
    image: freshrss/freshrss:latest
    
    container_name: freshrss-app
    
    hostname: freshrss-app
    
    restart: unless-stopped
    
    ports:
    
    - 34211:80
    
    depends_on:
    
    - freshrss-db
    
    volumes:
    
    - ./data:/var/www/FreshRSS/data
    
    - ./extensions:/var/www/FreshRSS/extensions
    
    environment:
    
    CRON_MIN: "*/45"
    
    TZ: Asia/Shanghai
    
    volumes:
    
    freshrss-db: null

    cd 到 yml 文件目录,输入安装命令docker compose up -d 即可安装成功

    Freshrss 设置

    允许api访问

    按需设置清理策略、自动刷新间隔(可选,你也可保持默认)

    设置 api密码

    访问api地址

    api 地址如下

    一般常用的,都是用htps://xxx/api/greader.php 这个api地址,记住它!
    到此,Freshrss的安装和设置相关工作已经结束了!

    新建rss.php

    在网站根目录新建rss.php文件,并且填入以下代码,按需修改成自己的域名。
    *标记红色的都是需要你自己改

    <?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的用户名', '这里输入Freshrss的api密码');

    请先检测是否成功:地址栏输入 https://你的域名/rss.php,假如看到“数据已保存到JSON文件中”,就意味着成功,可进行下一步。

    编辑funtions.php

    在子主题的funtions.php里添加以下代码
    (建议用子主题,因为当主题更新时,不怕丢失funtions.php里面的自定义代码)
    (这里的代码无修修改,找funtions的自定义代码区域,粘贴进去)

    function display_articles_shortcode($atts) {
        $attributes = shortcode_atts(array('offset' => 0), $atts);
        $offset = intval($attributes['offset']);
    
        $jsonFilePath = ABSPATH . 'output.json';
        $jsonData = file_get_contents($jsonFilePath);
        if ($jsonData === false) {
            return '<div class="error">Failed to load data from ' . htmlspecialchars($jsonFilePath) . '</div>';
        }
    
        $articles = json_decode($jsonData, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return '<div class="error">Error decoding JSON data: ' . htmlspecialchars(json_last_error_msg()) . '</div>';
        }
    
        if (empty($articles)) {
            return '<div class="error">No articles to display.</div>';
        }
    
        usort($articles, function ($a, $b) {
            return strtotime($b['time']) - strtotime($a['time']);
        });
    
        $itemsPerPage = 10;
        $articlesToShow = array_slice($articles, $offset, $itemsPerPage);
    
        ob_start();
        foreach ($articlesToShow as $article) {
            ?>
            <div class="article">
                <h3>
                    <img src="<?php echo htmlspecialchars($article['icon']); ?>" alt="Icon" class="icon">
                    <a href="<?php echo htmlspecialchars($article['link']); ?>" rel="nofollow" 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
        }
        // Check if there are more articles to load
        if ($offset + $itemsPerPage < count($articles)) {
            echo '<button id="load-more" data-offset="' . ($offset + $itemsPerPage) . '">加载更多</button>';
        } else {
            echo '<div id="all-loaded">加载完毕</div>';
        }
        return ob_get_clean();
    }
    
    add_shortcode('display_articles', 'display_articles_shortcode');
    
    
    
    function enqueue_custom_scripts() {
        wp_enqueue_script('custom-js', get_template_directory_uri() . '/js/custom.js', array('jquery'), null, true);
        wp_localize_script('custom-js', 'ajax_params', array('ajax_url' => admin_url('admin-ajax.php')));
    }
    add_action('wp_enqueue_scripts', 'enqueue_custom_scripts');
    
    function load_more_articles() {
        $offset = isset($_POST['offset']) ? intval($_POST['offset']) : 0;
        echo display_articles_shortcode(array('offset' => $offset));
        wp_die();
    }
    add_action('wp_ajax_load_more_articles', 'load_more_articles');
    add_action('wp_ajax_nopriv_load_more_articles', 'load_more_articles');

    新建js文件

    在主主题,是主主题,不是子主题,在主主题的根目录新建 js 文件夹,在 js 里面新增 custom.js,并且把下面代码粘贴进去
    (也就是:/wp-content/themes/主主题/js/custom.js)

    版本一:手动加载

    custom.js

    jQuery(document).ready(function($) {
    $(document).on('click', '#load-more', function() {
    var button = $(this);
    var offset = button.data('offset');
    $.ajax({
    url: ajax_params.ajax_url,
    type: 'POST',
    data: {
    'action': 'load_more_articles',
    'offset': offset
    },
    success: function(response) {
    button.replaceWith(response);
    }
    });
    });
    });

    版本二:底部自动加载,就像刷朋友圈那么爽!

    custom.js

    jQuery(document).ready(function($) {
        // 函数用于检查是否滚动到页面底部
        function isScrolledToBottom() {
            return $(window).scrollTop() + $(window).height() >= $(document).height() - 100; // 100px提前量
        }
    
        // 函数用于加载更多文章
        function loadMoreArticles() {
            var button = $('#load-more');
            if (button.length) {
                var offset = button.data('offset');
                $.ajax({
                    url: ajax_params.ajax_url,
                    type: 'POST',
                    data: {
                        'action': 'load_more_articles',
                        'offset': offset
                    },
                    beforeSend: function() {
                        button.text('加载中...'); // 可选:在加载时更改按钮文本
                    },
                    success: function(response) {
                        button.replaceWith(response);
                    }
                });
            }
        }
    
        // 绑定滚动事件
        $(window).scroll(function() {
            if (isScrolledToBottom()) {
                loadMoreArticles(); // 当滚动到底部时,调用加载更多文章的函数
            }
        });
    
        // 也保留点击加载更多的功能
        $(document).on('click', '#load-more', function() {
            loadMoreArticles();
        });
    });

    自定义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%;
    }

    输入简码

    在需要的地方输入 简码 即可

    [display_articles]

    定时刷新

    定时访问刚开始创建的php文件,以更新订阅数据
    以1panel为例,宝塔面板同理

    用Freshrss订阅好友

    用Freshrss订阅好友非常方便

    See You~

    参考资料:
    若志:用FreshRSS 实现友圈rss订阅
    段先生:跟风利用FreshRSS实现朋友圈



沪ICP备19023445号-2号
友情链接