javascript - 带有 youtube 数据 api 的 Chrome 扩展程序无法验证/登录
问题描述
我正在尝试使用操纵用户播放列表的 Youtube 数据 api(在 javascript 中)创建一个 chrome 扩展。我的代码使用了大量来自 youtube api 网站的示例代码。链接到将视频添加到播放列表的文档:( https://developers.google.com/youtube/v3/docs/playlistItems/insert )。
示例代码中的身份验证和加载客户端函数在提供的所有 youtube api 函数中都重复使用,但我不太了解它们。我在身份验证函数中遇到此行错误:
.signIn({scope: "https://www.googleapis.com/auth/youtube.force-ssl"})
TypeError:无法读取 null 的属性“signIn”
问题是我什至不知道登录功能是否真的有必要,我只是在使用它,因为它在示例代码中使用,我不希望用户必须重新登录谷歌使用扩展程序时。
这是有问题的功能:
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/youtube.force-ssl"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
这是上下文的完整代码:
gapi.auth2.init({client_id: "759121533570-dqpfg5rksm7n0j1a2jmi4fv542u1ik1f.apps.googleusercontent.com" });
});
function authenticateList() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/youtube.readonly"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function authenticate() {
return gapi.auth2.getAuthInstance()
.signIn({scope: "https://www.googleapis.com/auth/youtube.force-ssl"})
.then(function() { console.log("Sign-in successful"); },
function(err) { console.error("Error signing in", err); });
}
function loadClient() {
gapi.client.setApiKey(...);
return gapi.client.load("https://www.googleapis.com/discovery/v1/apis/youtube/v3/rest")
.then(function() { console.log("GAPI client loaded for API"); },
function(err) { console.error("Error loading GAPI client for API", err); });
}
// Make sure the client is loaded and sign-in is complete before calling this method.
//Lists current playlists
function listPlaylists() {
return gapi.client.youtube.playlists.list({
"part": "snippet",
"maxResults": 50,
"mine": true
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
let length = response.result.items.length
for(let i=0; i<length; i++){
if(response.result.items[i].snippet.title == "Queue"){
chrome.storage.sync.set({'playlistId': response.result.items[i].id});
return;
}
}
insertQueuePlaylist();
},
function(err) { console.error("Execute error", err); });
}
//Lists videos in Queue playlist
function listVideos() {
return gapi.client.youtube.playlistItems.list({
"part": "snippet",
"maxResults": 50,
"playlistId": chrome.storage.sync.get(['playlistId'])
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
return response.result.pageInfo.totalResults;
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
//Inserts video to playlist
function insertVideo(videoId) {
return gapi.client.youtube.playlistItems.insert({
"part": "snippet",
"resource": {
"snippet": {
"playlistId": chrome.storage.sync.get(['playlistId']),
"position": 0,
"resourceId": {
"kind": "youtube#video",
"videoId": videoId
}
}
}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
//Delete video from playlist
function deleteVideo(videoId) {
return gapi.client.youtube.playlistItems.delete({
"id": videoId
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
},
function(err) { console.error("Execute error", err); });
}
//Inserts the playlist
function insertQueuePlaylist() {
return gapi.client.youtube.playlists.insert({
"part": "snippet",
"resource": {
"snippet": {
"title": "Queue",
"description": "The videos queued to play next"
}
}
})
.then(function(response) {
// Handle the results here (response.result has the parsed body).
console.log("Response", response);
chrome.storage.sync.set({'playlistId': response.result.id});
},
function(err) { console.error("Execute error", err); });
}
//add queue link
chrome.runtime.onInstalled.addListener(function() {
authenticate().then(loadClient);
insertQueuePlaylist();
chrome.contextMenus.create({
"id": "queueContextMenu",
"title": "Add to Queue",
"contexts": ["links"]
});
});
chrome.contextMenus.onClicked.addListener(function(info) {
if (info.menuItemId == "queueContextMenu") {
chrome.storage.sync.get(['playlistId'],function(data){
if(data.playlistId==='undefined'){
authenticateList().then(loadClient);
listPlaylists();
}
});
authenticate().then(loadClient);
let url = new URL(info.linkUrl);
insertVideo(url.searchParams.get("v"));
}
})
chrome.webNavigation.onBeforeNavigate.addListener(function(details){
//before Navigate, get the id of the queue playlist if you don't already have it
console.log(details.url);
chrome.storage.sync.get(['playlistId'],function(data){
if(data.playlistId==='undefined'){
authenticateList().then(loadClient);
listPlaylists();
}
});
//get the number of videos in the queue
let numVideos = listVideos();
if (numVideos!=0){
authenticate().then(loadClient);
//if there are videos in the queue, add the current video to the begining of the queue,
let url = new URL(details.url);
let videoId = url.searchParams.get("v");
insertVideo(vidoId);
//and enter the playlists
window.location.search = "?v=" + videoId + "&list=" + chrome.storage.sync.get(['playlistId']);
}
},{url: [{urlContains : '.youtube.com/watch'}]});
chrome.webNavigation.onHistoryStateUpdated.addListener(function(details){
console.log(details.url);
},{url: [{urlContains : '.youtube.com/watch'}]});
chrome.webNavigation.onCompleted.addListener(function(details){
authenticate().then(loadClient)
let url = new URL(details.url);
let videoId = url.searchParams.get("v");
deleteVideo(videoId);
},{url: [{queryContains: 'list=' + chrome.storage.sync.get(['playlistId'],function(result) {
console.log('Value currently is ' + result.key);
})}]});
我还在文件顶部添加了“ https://apis.google.com/js/api.js ”。我真的很感激任何帮助!
解决方案
推荐阅读
- sql - 即使没有返回行也显示一个值
- django - 如何在用户按下搜索按钮时自动生成 csv 文件
- php - 如何在 PHP 中生成随机数集数组?
- node.js - Vue Js Form 将问题发布到服务器
- unity3d - 逻辑问题通过 Photon 同步翻转游戏对象子项
- javascript - 如何将中缩放库与惰性大小一起使用?
- sql - 2个资源关系-为每条记录选择每条记录-即使pivot没有定义它
- ldap - 将 LexikJWTAuthenticationBundle 与 LDAP 提供程序一起使用
- sql - 仅当另一列具有特定值时才允许 Null
- swiftui - SwiftUI 错误:无法推断通用参数“标签”显式指定通用参数以解决此问题`