【问题标题】:Getting Started... Youtube API via Javascript to give most recent upload video, title and description开始... Youtube API 通过 Javascript 提供最新的上传视频、标题和描述
【发布时间】:2013-09-06 18:36:30
【问题描述】:

在 jlmcdonald 一些明智的意见后,我重新写了这篇文章

最终目标是使用 YouTube API 做一些有趣的事情。今天的目标是让它发挥作用。

我在这里学习了 youtube dev java-scrip API 教程:

https://developers.google.com/youtube/v3/code_samples/javascript#my_uploads

但是我没有单独的文档,而是做了一个大的,并根据需要调整了脚本标签。

无法让它发挥作用....有想法吗?

这是我来自 Google 的 API 代码图片(如果需要)http://d.pr/i/Ybcx

<!doctype html>
<html>
  <head>
    <title>My Uploads</title>
    <link rel="stylesheet" href="my_uploads.css" />
    <style>
      .paging-button {
        visibility: hidden;
      }

      .video-content {
        width: 200px;
        height: 200px;
        background-position: center;
        background-repeat: no-repeat;
        float: left;
        position: relative;
        margin: 5px;
      }

      .video-title {
        width: 100%;
        text-align: center;
        background-color: rgba(0, 0, 0, .5);
        color: white;
        top: 50%;
        left: 50%;
        position: absolute;
        -moz-transform: translate(-50%, -50%);
        -webkit-transform: translate(-50%, -50%);
        transform: translate(-50%, -50%);
      }

      .video-content:nth-child(3n+1) {
        clear: both;
      }

      .button-container {
        clear: both;
      }
      </style>
      <script>
        //This is the Authorization by Client ID http://d.pr/i/mEmY
        // The client id is obtained from the Google APIs Console at https://code.google.com/apis/console
        // If you run access this code from a server other than http://localhost, you need to register
        // your own client id.
        var OAUTH2_CLIENT_ID = '367567738093.apps.googleusercontent.com';
        var OAUTH2_SCOPES = [
          'https://www.googleapis.com/auth/youtube'
        ];

        // This callback is invoked by the Google APIs JS client automatically when it is loaded.
        googleApiClientReady = function() {
          gapi.auth.init(function() {
            window.setTimeout(checkAuth, 1);
          });
        }

        // Attempt the immediate OAuth 2 client flow as soon as the page is loaded.
        // If the currently logged in Google Account has previously authorized OAUTH2_CLIENT_ID, then
        // it will succeed with no user intervention. Otherwise, it will fail and the user interface
        // to prompt for authorization needs to be displayed.
        function checkAuth() {
          gapi.auth.authorize({
            client_id: OAUTH2_CLIENT_ID,
            scope: OAUTH2_SCOPES,
            immediate: true
          }, handleAuthResult);
        }

        // Handles the result of a gapi.auth.authorize() call.
        function handleAuthResult(authResult) {
          if (authResult) {
            // Auth was successful; hide the things related to prompting for auth and show the things
            // that should be visible after auth succeeds.
            $('.pre-auth').hide();
            loadAPIClientInterfaces();
          } else {
            // Make the #login-link clickable, and attempt a non-immediate OAuth 2 client flow.
            // The current function will be called when that flow is complete.
            $('#login-link').click(function() {
              gapi.auth.authorize({
                client_id: OAUTH2_CLIENT_ID,
                scope: OAUTH2_SCOPES,
                immediate: false
                }, handleAuthResult);
            });
          }
        }

        // Loads the client interface for the YouTube Analytics and Data APIs.
        // This is required before using the Google APIs JS client; more info is available at
        // http://code.google.com/p/google-api-javascript-client/wiki/GettingStarted#Loading_the_Client
        function loadAPIClientInterfaces() {
          gapi.client.load('youtube', 'v3', function() {
            handleAPILoaded();
          });
        }



      //This is the uploads script
      // Some variables to remember state.
      var playlistId, nextPageToken, prevPageToken;

      // Once the api loads call a function to get the uploads playlist id.
      function handleAPILoaded() {
        requestUserUploadsPlaylistId();
      }

      //Retrieve the uploads playlist id.
      function requestUserUploadsPlaylistId() {
        // https://developers.google.com/youtube/v3/docs/channels/list
        var request = gapi.client.youtube.channels.list({
          // mine: '' indicates that we want to retrieve the channel for the authenticated user.
          mine: '',
          part: 'contentDetails'
        });
        request.execute(function(response) {
          playlistId = response.result.items[0].contentDetails.uploads;
          requestVideoPlaylist(playlistId);
        });
      }

      // Retrieve a playist of videos.
      function requestVideoPlaylist(playlistId, pageToken) {
        $('#video-container').html('');
        var requestOptions = {
          playlistId: playlistId,
          part: 'snippet',
          maxResults: 9
        };
        if (pageToken) {
          requestOptions.pageToken = pageToken;
        }
        var request = gapi.client.youtube.playlistItems.list(requestOptions);
        request.execute(function(response) {
          // Only show the page buttons if there's a next or previous page.
          nextPageToken = response.result.nextPageToken;
          var nextVis = nextPageToken ? 'visible' : 'hidden';
          $('#next-button').css('visibility', nextVis);
          prevPageToken = response.result.prevPageToken
          var prevVis = prevPageToken ? 'visible' : 'hidden';
          $('#prev-button').css('visibility', prevVis);

          var playlistItems = response.result.items;
          if (playlistItems) {
            // For each result lets show a thumbnail.
            jQuery.each(playlistItems, function(index, item) {
              createDisplayThumbnail(item.snippet);
            });
          } else {
            $('#video-container').html('Sorry you have no uploaded videos');
          }
        });
      }


      // Create a thumbnail for a video snippet.
      function createDisplayThumbnail(videoSnippet) {
        var titleEl = $('<h3>');
        titleEl.addClass('video-title');
        $(titleEl).html(videoSnippet.title);
        var thumbnailUrl = videoSnippet.thumbnails.medium.url;

        var div = $('<div>');
        div.addClass('video-content');
        div.css('backgroundImage', 'url("' + thumbnailUrl + '")');
        div.append(titleEl);
        $('#video-container').append(div);
      }

      // Retrieve the next page of videos.
      function nextPage() {
        requestVideoPlaylist(playlistId, nextPageToken);
      }

      // Retrieve the previous page of videos.
      function previousPage() {
        requestVideoPlaylist(playlistId, prevPageToken);
      }
    </script>
  </head>
  <body>
    <div id="login-container" class="pre-auth">This application requires access to your YouTube account.
      Please <a href="#" id="login-link">authorize</a> to continue.
    </div>
    <div id="video-container">
    </div>
    <div class="button-container">
      <button id="prev-button" class="paging-button" onclick="previousPage();">Previous Page</button>
      <button id="next-button" class="paging-button" onclick="nextPage();">Next Page</button>
    </div>
    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    <script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
  </body>
</html>

【问题讨论】:

  • 抱歉,超级空洞,超级​​新人……我正在努力
  • 不确定我是否了解您想要做什么,但如果尚未完成,可能会是有用的阅读:developers.google.com/youtube/2.0/…
  • @ChaseWestlye,你不应该把你的钥匙给别人看。

标签: javascript jquery html youtube-api


【解决方案1】:

由于您的问题主要是关于“入门”的,我将向您指出一些方向,希望这足以让您到达您想去的地方。首先,有几种不同的 YouTube API——有 data API,用于检索有关提要、活动、视频等的信息,还有 player API ,用于嵌入视频并对其进行控制。 (还有一个分析 API 和一个直播 API,但这在这里并不重要。)如果您的唯一目标是获取有关您最近上传的信息(您提到标题和描述),那么您'将只需要数据 API。如果您还希望将视频本身嵌入到 iFrame 中(首选方式),那么您将需要两者……您将首先使用数据 API,然后使用您从您的元数据包。

还有一点需要指出的是,生产中的数据 API 有两个版本; v2 和 v3。 v2 有时称为 gdata API(因为它使用较旧的 gdata XML 模式)。我建议使用数据 API 的 v3,因为它更容易使用,完全符合 REST 和 CORS,布局更合理,等等。话虽如此,v3 中还没有一些东西(例如评论检索),所以如果你最终需要 v3 没有提供的东西,你将不得不暂时绕过它。

因此,要从数据 API 检索您最近上传的内容,一般策略是调用 REST 端点,该端点为您提供上传提要的 ID,然后调用 REST 端点,为您提供属于该提要的视频。幸运的是,数据 API v3 的文档为您提供了确切的示例:

https://developers.google.com/youtube/v3/code_samples/javascript#my_uploads

(请注意,该示例使用 javascript gapi 客户端,主要用于处理您需要的 OAuth2 身份验证。每当您向需要身份验证的数据 API 发出请求时,使用 gapi 客户端可能非常有用,因此您不必必须自己处理所有传递的令牌。在 javascript、python、php、go 等中有 gapi 客户端。但是如果你得到的数据你只需要读取,并且不需要在后面授权墙,您可以获取 API 密钥并直接调用端点。)

获得最新上传的数据后,您可以将标题和说明放在 HTML 中的任意位置,然后获取视频 ID(也通过数据 API 调用返回)并在播放器 API 中使用。您在上面发布的代码就是一个很好的例子。

当您开始进行此操作时,您可以发布有关您可能遇到的特定问题的新问题。

【讨论】:

    【解决方案2】:

    参考:https://developers.google.com/youtube/v3/docs/

    不要忘记更新代码行:var OAUTH2_CLIENT_ID = 'Put Your-Client-Id Here';

    将您当前的代码更改为:

    <!doctype html>
    <html>
      <head>
        <title>My Uploads</title>
        <link rel="stylesheet" href="my_uploads.css" />
        <style>
          .paging-button {
            visibility: hidden;
          }
    
          .video-content {
            width: 200px;
            height: 200px;
            background-position: center;
            background-repeat: no-repeat;
            float: left;
            position: relative;
            margin: 5px;
          }
    
          .video-title {
            width: 100%;
            text-align: center;
            background-color: rgba(0, 0, 0, .5);
            color: white;
            top: 50%;
            left: 50%;
            position: absolute;
            -moz-transform: translate(-50%, -50%);
            -webkit-transform: translate(-50%, -50%);
            transform: translate(-50%, -50%);
          }
    
          .video-content:nth-child(3n+1) {
            clear: both;
          }
    
          .button-container {
            clear: both;
          }
          </style>
    
    
        <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
    
    
          <script>
            //This is the Authorization by Client ID http://d.pr/i/mEmY
            // The client id is obtained from the Google APIs Console at https://code.google.com/apis/console
            // If you run access this code from a server other than http://localhost, you need to register
            // your own client id.
            var OAUTH2_CLIENT_ID = 'Put Your-Client-Id Here';  // <==============================
            var OAUTH2_SCOPES = [
              'https://www.googleapis.com/auth/youtube'
            ];
    
            // This callback is invoked by the Google APIs JS client automatically when it is loaded.
            googleApiClientReady = function() {
              gapi.auth.init(function() {
                window.setTimeout(checkAuth, 1);
              });
            }
    
            // Attempt the immediate OAuth 2 client flow as soon as the page is loaded.
            // If the currently logged in Google Account has previously authorized OAUTH2_CLIENT_ID, then
            // it will succeed with no user intervention. Otherwise, it will fail and the user interface
            // to prompt for authorization needs to be displayed.
            function checkAuth() {
              gapi.auth.authorize({
                client_id: OAUTH2_CLIENT_ID,
                scope: OAUTH2_SCOPES,
                immediate: true
              }, handleAuthResult);
            }
    
            // Handles the result of a gapi.auth.authorize() call.
            function handleAuthResult(authResult) {
              if (authResult) {
                // Auth was successful; hide the things related to prompting for auth and show the things
                // that should be visible after auth succeeds.
                $('.pre-auth').hide();
                loadAPIClientInterfaces();
              } else {
                // Make the #login-link clickable, and attempt a non-immediate OAuth 2 client flow.
                // The current function will be called when that flow is complete.
                $('#login-link').click(function() {
                  gapi.auth.authorize({
                    client_id: OAUTH2_CLIENT_ID,
                    scope: OAUTH2_SCOPES,
                    immediate: false
                    }, handleAuthResult);
                });
              }
            }
    
            // Loads the client interface for the YouTube Analytics and Data APIs.
            // This is required before using the Google APIs JS client; more info is available at
            // http://code.google.com/p/google-api-javascript-client/wiki/GettingStarted#Loading_the_Client
            function loadAPIClientInterfaces() {
              gapi.client.load('youtube', 'v3', function() {
                handleAPILoaded();
              });
            }
    
    
    
          //This is the uploads script
          // Some variables to remember state.
          var playlistId, nextPageToken, prevPageToken;
    
          // Once the api loads call a function to get the uploads playlist id.
          function handleAPILoaded() {
            requestUserUploadsPlaylistId();
          }
    
          //Retrieve the uploads playlist id.
          function requestUserUploadsPlaylistId() {
            // https://developers.google.com/youtube/v3/docs/channels/list
            var request = gapi.client.youtube.channels.list({
              // mine: '' indicates that we want to retrieve the channel for the authenticated user.
              mine: true,
              part: 'contentDetails'
            });
            request.execute(function(response) {
              playlistId = response.result.items[0].contentDetails.relatedPlaylists.uploads;
              requestVideoPlaylist(playlistId);
            });
          }
    
          // Retrieve a playist of videos.
          function requestVideoPlaylist(playlistId, pageToken) {
            $('#video-container').html('');
            var requestOptions = {
              playlistId: playlistId,
              part: 'snippet',
              maxResults: 9
            };
            if (pageToken) {
              requestOptions.pageToken = pageToken;
            }
            var request = gapi.client.youtube.playlistItems.list(requestOptions);
            request.execute(function(response) {
              // Only show the page buttons if there's a next or previous page.
              nextPageToken = response.result.nextPageToken;
              var nextVis = nextPageToken ? 'visible' : 'hidden';
              $('#next-button').css('visibility', nextVis);
              prevPageToken = response.result.prevPageToken
              var prevVis = prevPageToken ? 'visible' : 'hidden';
              $('#prev-button').css('visibility', prevVis);
    
              var playlistItems = response.result.items;
              if (playlistItems) {
                // For each result lets show a thumbnail.
                jQuery.each(playlistItems, function(index, item) {
                  createDisplayThumbnail(item.snippet);
                });
              } else {
                $('#video-container').html('Sorry you have no uploaded videos');
              }
            });
          }
    
    
          // Create a thumbnail for a video snippet.
          function createDisplayThumbnail(videoSnippet) {
            var titleEl = $('<h3>');
            titleEl.addClass('video-title');
            $(titleEl).html(videoSnippet.title);
            var thumbnailUrl = videoSnippet.thumbnails.medium.url;
    
            var div = $('<div>');
            div.addClass('video-content');
            div.css('backgroundImage', 'url("' + thumbnailUrl + '")');
            div.append(titleEl);
            $('#video-container').append(div);
          }
    
          // Retrieve the next page of videos.
          function nextPage() {
            requestVideoPlaylist(playlistId, nextPageToken);
          }
    
          // Retrieve the previous page of videos.
          function previousPage() {
            requestVideoPlaylist(playlistId, prevPageToken);
          }
        </script>
    
    
        <script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
      </head>
      <body>
        <div id="login-container" class="pre-auth">This application requires access to your YouTube account.
          Please <a href="#" id="login-link">authorize</a> to continue.
        </div>
        <div id="video-container">
        </div>
        <div class="button-container">
          <button id="prev-button" class="paging-button" onclick="previousPage();">Previous Page</button>
          <button id="next-button" class="paging-button" onclick="nextPage();">Next Page</button>
        </div>
      </body>
    </html>
    

    【讨论】:

    • 谢谢,在我的一个朋友的帮助下,我最终走向了不同的方向。看看下面的代码。
    【解决方案3】:

    所以我设置了一个额外的部分来创建一个 cookie 来存储用户名。 CSS也在外部文档中。除此之外...检查一下:

    <!DOCTYPE HTML>
    <html>
        <head>
            <title>My Sandbox</title>
            <link rel="stylesheet" type="text/css" href="CSS/Style.CSS">
            <script src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.10.2.min.js">
            </script>   
            <script>
                jQuery(function($){
                  $("#video-container").on('click', '.video_select', function(e){
                    console.log(e);
                    var buttonSource = $(this).data('video');
                    var embededVideo = $('#youTube_video');
                        embededVideo.attr('src', buttonSource);
                        return false;
                  });
                });
    
    
                function getCookie(c_name)
                    {
                    var c_value = document.cookie;
                    var c_start = c_value.indexOf(" " + c_name + "=");
                        if (c_start == -1){
                            c_start = c_value.indexOf(c_name + "=");
                        }
                        if (c_start == -1){
                            c_value = null;
                        }
                        else{
                            c_start = c_value.indexOf("=", c_start) + 1;
                    var c_end = c_value.indexOf(";", c_start);
                        if (c_end == -1){
                            c_end = c_value.length;
                        }
                            c_value = unescape(c_value.substring(c_start,c_end));
                        }
                        return c_value;
                        }
    
                function setCookie(c_name,value,exdays){
                    var exdate=new Date();
                        exdate.setDate(exdate.getDate() + exdays);
                    var c_value=escape(value) + ((exdays==null) ? "" : "; expires="+exdate.toUTCString());
                        document.cookie=c_name + "=" + c_value;
                        }
    
                function checkCookie(){
                    var username=getCookie("username");
                        if (username!=null && username!=""){
                            alert("Welcome back " + username);
                            document.getElementById("title_script").innerHTML="Welcome "+username+" to my sandbox";
                            }
                        else{
                            username=prompt("Please enter your name:","");
                            if (username!=null && username!=""){
                            setCookie("username",username,365);
                            document.getElementById("title_script").innerHTML="Welcome "+username+" to my sandbox";
                            }
                        }
                }
    
    
    
    
    
                    </script>
    
    
    
                      <script>
            //This is the Authorization by Client ID http://d.pr/i/mEmY
            // The client id is obtained from the Google APIs Console at https://code.google.com/apis/console
            // If you run access this code from a server other than http://localhost, you need to register
            // your own client id.
            var OAUTH2_CLIENT_ID = '367567738093.apps.googleusercontent.com';
            var OAUTH2_SCOPES = [
              'https://www.googleapis.com/auth/youtube'
            ];
    
            // This callback is invoked by the Google APIs JS client automatically when it is loaded.
            googleApiClientReady = function() {
              gapi.auth.init(function() {
                window.setTimeout(checkAuth, 1);
              });
            }
    
            // Attempt the immediate OAuth 2 client flow as soon as the page is loaded.
            // If the currently logged in Google Account has previously authorized OAUTH2_CLIENT_ID, then
            // it will succeed with no user intervention. Otherwise, it will fail and the user interface
            // to prompt for authorization needs to be displayed.
            function checkAuth() {
              gapi.auth.authorize({
                client_id: OAUTH2_CLIENT_ID,
                scope: OAUTH2_SCOPES,
                immediate: true
              }, handleAuthResult);
            }
    
            // Handles the result of a gapi.auth.authorize() call.
            function handleAuthResult(authResult) {
              if (authResult) {
                // Auth was successful; hide the things related to prompting for auth and show the things
                // that should be visible after auth succeeds.
                $('.pre-auth').hide();
                loadAPIClientInterfaces();
              } else {
                // Make the #login-link clickable, and attempt a non-immediate OAuth 2 client flow.
                // The current function will be called when that flow is complete.
                $('#login-link').click(function() {
                  gapi.auth.authorize({
                    client_id: OAUTH2_CLIENT_ID,
                    scope: OAUTH2_SCOPES,
                    immediate: false
                    }, handleAuthResult);
                });
              }
            }
    
            // Loads the client interface for the YouTube Analytics and Data APIs.
            // This is required before using the Google APIs JS client; more info is available at
            // http://code.google.com/p/google-api-javascript-client/wiki/GettingStarted#Loading_the_Client
            function loadAPIClientInterfaces() {
              gapi.client.load('youtube', 'v3', function() {
                handleAPILoaded();
              });
            }
    
    
    
          //This is the uploads script
          // Some variables to remember state.
          var playlistId, nextPageToken, prevPageToken;
    
          // Once the api loads call a function to get the uploads playlist id.
          function handleAPILoaded() {
            requestUserUploadsPlaylistId();
          }
    
          //Retrieve the uploads playlist id.
          function requestUserUploadsPlaylistId() {
            // https://developers.google.com/youtube/v3/docs/channels/list
            var request = gapi.client.youtube.channels.list({
              // mine: '' indicates that we want to retrieve the channel for the authenticated user.
              // mine: false,
              id: 'UCziks4y-RixDhWljY_es-tA',
              part: 'contentDetails'
            });
            request.execute(function(response) {
              console.log(response);
              playlistId = response.result.items[0].contentDetails.relatedPlaylists.uploads;
              requestVideoPlaylist(playlistId);
            });
          }
    
          // Retrieve a playist of videos.
          function requestVideoPlaylist(playlistId, pageToken) {
            $('#video-container').html('');
            var requestOptions = {
              playlistId: playlistId,
              part: 'snippet',
              maxResults: 9
            };
            if (pageToken) {
              requestOptions.pageToken = pageToken;
            }
            var request = gapi.client.youtube.playlistItems.list(requestOptions);
            request.execute(function(response) {
              // Only show the page buttons if there's a next or previous page.
              console.log (response);
              nextPageToken = response.result.nextPageToken;
              var nextVis = nextPageToken ? 'visible' : 'hidden';
              $('#next-button').css('visibility', nextVis);
              prevPageToken = response.result.prevPageToken
              var prevVis = prevPageToken ? 'visible' : 'hidden';
              $('#prev-button').css('visibility', prevVis);
    
              var playlistItems = response.result.items;
              if (playlistItems) {
                // For each result lets show a thumbnail.
                jQuery.each(playlistItems, function(index, item) {
                  createDisplayThumbnail(item.snippet);
                });
              } else {
                $('#video-container').html('Sorry you have no uploaded videos');
              }
            });
          }
    
    
          // Create a thumbnail for a video snippet.
          function createDisplayThumbnail(videoSnippet) {
            console.log(videoSnippet);
            var titleEl = $('<h3>');
            titleEl.addClass('video-title');
            $(titleEl).html(videoSnippet.title);
            var thumbnailUrl = videoSnippet.thumbnails.medium.url;
            var videoLink=$('<a>');
            videoLink.attr('data-video','http://www.youtube.com/embed/'+videoSnippet.resourceId.videoId);
            videoLink.append(div)
            videoLink.addClass('video_select')
    
            var div = $('<div>');
            div.addClass('video-content');
            div.css('backgroundImage', 'url("' + thumbnailUrl + '")');
            div.append(titleEl);
            videoLink.append(div)
            $('#video-container').append(videoLink);
    
          }
    
          // Retrieve the next page of videos.
          function nextPage() {
            requestVideoPlaylist(playlistId, nextPageToken);
          }
    
          // Retrieve the previous page of videos.
          function previousPage() {
            requestVideoPlaylist(playlistId, prevPageToken);
          }
        </script>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    
            </script>
        </head>
    <body onload="checkCookie()" class="background_color">
    <div class="wrap">
        <iframe id='youTube_video' width="560" height="315" src="//www.youtube.com/embed/io78hmjAWHw" frameborder="0" allowfullscreen></iframe>
        <h1 class="title" id="title_script">Welcome to my Sandbox</h1>
    </div>
    
    
    
    
    
    
    <div id="login-container" class="pre-auth">This application requires access to your YouTube account.
      Please <a href="#" id="login-link">authorize</a> to continue.
    </div>
    <div id="video-container">
    </div>
    <div class="button-container">
      <button id="prev-button" class="paging-button" onclick="previousPage();">Previous Page</button>
      <button id="next-button" class="paging-button" onclick="nextPage();">Next Page</button>
    </div>
    <script src="https://apis.google.com/js/client.js?onload=googleApiClientReady"></script>
    
    
    
    
    
    
    
    
    
    
    
    
    
    
    </body>
    </html>
    

    【讨论】:

      猜你喜欢
      • 2014-02-09
      • 2011-09-19
      • 1970-01-01
      • 2016-03-05
      • 2012-02-08
      • 2013-05-13
      • 2014-09-27
      • 2021-05-28
      • 2023-02-21
      相关资源
      最近更新 更多