-
Notifications
You must be signed in to change notification settings - Fork 46
/
Copy pathbackground.js
132 lines (118 loc) · 3.65 KB
/
background.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
const ORIGIN = 'https://devwebfeed.appspot.com';
function authUser() {
return new Promise((resolve, reject) => {
// Note: getAuthToken caches token, so it's safe to call repeatedly.
chrome.identity.getAuthToken({interactive: true}, async token => {
if (chrome.runtime.lastError) {
console.error(chrome.runtime.lastError.message);
return reject(token);
}
// TODO: consider caching profile response.
const resp = await fetch(`https://www.googleapis.com/oauth2/v2/userinfo?alt=json&access_token=${token}`);
const json = await resp.json();
if (json.error) {
console.error(json.error.message);
return reject(token);
}
resolve(json);
});
});
}
chrome.browserAction.onClicked.addListener(async tab => {
try {
const userInfo = await authUser();
chrome.identity.getProfileUserInfo(async profileInfo => {
const user = Object.assign(userInfo, profileInfo);
const json = await sendPageInfo(user, tab);
chrome.browserAction.setBadgeText({text: 'OK'});
setTimeout(() => chrome.browserAction.setBadgeText({text: ''}), 3000);
});
} catch (err) {
// Revoke token. User needs to click button again.
chrome.identity.removeCachedAuthToken({token}, () => {
console.info('Cached token revoked');
});
}
});
function getCanonicalLink(tab) {
return new Promise(resolve => {
const code = `
var canonical = document.querySelector('link[rel=canonical]');
canonical && canonical.href;
`;
chrome.tabs.executeScript(tab.id, {code}, results => resolve(results[0] || tab.url));
});
}
function getPageTitle(tab) {
return new Promise(resolve => {
const code = `
var metaTwitterTitle = document.querySelector('meta[name="twitter:title"]');
document.title || (metaTwitterTitle && metaTwitterTitle.content) || null;
`;
chrome.tabs.executeScript(tab.id, {code}, result => {
let title = result[0];
// Cleanup Twitter titles.
const m = title.match(/^.*on Twitter: "(.*)"/i);
if (m) {
title = m[1];
}
resolve(title);
});
});
}
function getAuthor(tab) {
const code = `
function getAuthor() {
const metaAuthor = document.querySelector('meta[property=author], meta[name=author]');
if (metaAuthor) {
return metaAuthor.content;
}
const relAuthorLink = document.querySelector('link[rel=author]');
if (relAuthorLink) {
return relAuthorLink.href;
}
const itemPropAuthor = document.querySelector('[itemprop="author"]');
const name = itemPropAuthor ? itemPropAuthor.querySelector('[itemprop="name"]') || itemPropAuthor : null;
if (name) {
return name.textContent.split(/\\s/).filter(item => item).join(' ');
}
}
getAuthor();
`;
return new Promise(resolve => {
chrome.tabs.executeScript(tab.id, {code}, result => {
resolve(result[0] || null)
});
});
}
async function sendPageInfo(submitter, tab) {
const url = await getCanonicalLink(tab);
const data = {
title: await getPageTitle(tab),
url,
domain: new URL(url).host,
submitted: (new Date()).toJSON(),
submitter: {
name: submitter.name,
email: submitter.email,
picture: submitter.picture,
bot: false,
},
author: await getAuthor(tab),
};
console.log(data);
try {
const resp = await fetch(`${ORIGIN}/posts`, {
method: 'POST',
body: JSON.stringify(data),
headers: {'Content-Type': 'application/json'}
});
const json = await resp.text();
if (!resp.ok || json.error) {
throw Error(json.error);
}
return json;
} catch (err) {
throw err;
}
}