Skip to content

Commit 5dd6bc4

Browse files
committed
initial
0 parents  commit 5dd6bc4

File tree

13 files changed

+20282
-0
lines changed

13 files changed

+20282
-0
lines changed

assets/icons/48x48_bw.png

3.8 KB
Loading

assets/js/background.js

Lines changed: 104 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
const subsAlarmName = 'check-subscriptions';
2+
const defaultUpdateTimeout = 1.0;
3+
4+
const app = {
5+
6+
init: async () => {
7+
8+
self.importScripts('/assets/js/fetch.js');
9+
self.importScripts('/assets/js/storage.js');
10+
11+
chrome.action.setBadgeBackgroundColor({ color: "#ff6600" });
12+
chrome.action.setBadgeTextColor({ color: "#ffffff" });
13+
14+
app.actions();
15+
16+
if(await app.updateBadgeFromStorage())
17+
app.setSubsUpdateAlarm();
18+
},
19+
20+
isAlarmSet: async () => {
21+
return (await chrome.alarms.get(subsAlarmName)) !== undefined;
22+
},
23+
24+
setSubsUpdateAlarm: (mins = defaultUpdateTimeout) => {
25+
chrome.alarms.create(subsAlarmName, {
26+
delayInMinutes: mins,
27+
periodInMinutes: 15 // emergency timeout
28+
});
29+
},
30+
31+
stopSubsUpdateAlarm: () => {
32+
chrome.alarms.clear(subsAlarmName);
33+
},
34+
35+
updateBadgeFromStorage: async () => {
36+
const isSubsStored = subscriptions.isSubsStored();
37+
38+
let unreadNum = await subscriptions.getUnreadCount();
39+
40+
chrome.action.setBadgeText({
41+
text: unreadNum > 0 ? unreadNum.toString() : ""
42+
});
43+
44+
return isSubsStored;
45+
},
46+
47+
actions: () => {
48+
49+
chrome.alarms.onAlarm.addListener( async(a) => {
50+
const page_ids = (await subscriptions.bySub())
51+
.map((a) => a.page_id);
52+
53+
const stats = await requester.request(
54+
{ action: 'getStats' },
55+
{
56+
"page_ids": page_ids
57+
}
58+
);
59+
60+
// Set next update timepoint
61+
app.setSubsUpdateAlarm(
62+
defaultUpdateTimeout * stats.update_timeout_factor
63+
);
64+
65+
stats.latest_actions.forEach(async(e) =>
66+
await subscriptions.setActivityCounterIfSubscribed(e.page_id, e.latest_activity_id)
67+
);
68+
69+
const found = stats.latest_actions
70+
.map((e) => e.page_id);
71+
72+
// not found:
73+
subscriptions.bySub().then((r) => {
74+
r.forEach((a) => {
75+
if(found.includes(a.page_id) == false)
76+
subscriptions.setRemoved(a.page_id);
77+
});
78+
});
79+
});
80+
81+
chrome.storage.onChanged.addListener(async(changes, namespace) => {
82+
const haveSubs = await app.updateBadgeFromStorage();
83+
84+
if(haveSubs)
85+
{
86+
if(!(await app.isAlarmSet()))
87+
app.setSubsUpdateAlarm();
88+
}
89+
else
90+
app.stopSubsUpdateAlarm();
91+
});
92+
93+
},
94+
95+
getLocalStorage: ( key ) => {
96+
return new Promise(resolve => {
97+
chrome.storage.local.get(key, data => {
98+
resolve( data[ key ] );
99+
});
100+
});
101+
}
102+
};
103+
104+
app.init();

assets/js/fetch.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
const requester = {
2+
api: 'https://jbchan.mooo.com:8351',
3+
4+
request: async ( args, post_args ) => {
5+
let res;
6+
7+
if( Object.keys( args ).length ){
8+
const params = new URLSearchParams();
9+
10+
params.append('api', '1.0');
11+
12+
for( const key in args ){
13+
if( args.hasOwnProperty( key ) )
14+
params.append(key, args[ key ] );
15+
}
16+
const query = params.toString();
17+
18+
let url = requester.api +'?'+ query;
19+
20+
if( Object.keys( post_args ).length == 0 ){
21+
res = await fetch(
22+
url,
23+
{
24+
credentials: "include"
25+
}
26+
);
27+
}
28+
else{
29+
res = await fetch(
30+
url,
31+
{
32+
method: "POST",
33+
headers: {
34+
"Content-type": "application/json; charset=UTF-8",
35+
"Accept": "application/json; charset=UTF-8"
36+
},
37+
credentials: "include",
38+
body: JSON.stringify(
39+
Object.assign(post_args)
40+
)
41+
}
42+
);
43+
}
44+
}
45+
46+
if( ! res.ok )
47+
throw new Error('Request error: '+ res.status );
48+
49+
return await res.json();
50+
}
51+
}

assets/js/storage.js

Lines changed: 204 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,204 @@
1+
class SubscriptionsStorage {
2+
async #getSubsArray() {
3+
const key = "subscriptions_list";
4+
5+
const r = await chrome.storage.local.get(key).then((r) => r?.[key]);
6+
7+
return r === undefined ? [] : r;
8+
}
9+
10+
async #insertToSubsArray(page_id) {
11+
const key = "subscriptions_list";
12+
13+
let r = await this.#getSubsArray();
14+
15+
r.push(page_id);
16+
17+
chrome.storage.local.set({[key]: r});
18+
}
19+
20+
async #removeListFromSubsArray(page_ids) {
21+
let r = await this.#getSubsArray();
22+
23+
if(r === undefined)
24+
return;
25+
26+
r = r.filter((e) => e.includes(page_ids) == false);
27+
28+
const key = "subscriptions_list";
29+
30+
chrome.storage.local.set({[key]: r});
31+
}
32+
33+
#getKey(page_id) { return "subscription:" + page_id; }
34+
35+
async #getByPageId(page_id) {
36+
const key = this.#getKey(page_id);
37+
38+
const j = await chrome.storage.local.get(key);
39+
40+
return j?.[key];
41+
}
42+
43+
#setByPageId(page_id, v) {
44+
const key = this.#getKey(page_id);
45+
46+
return chrome.storage.local.set({ [key]: v });
47+
}
48+
49+
async bySub() {
50+
const r = await this.#getSubsArray();
51+
52+
return await Promise.all(
53+
r.map(async(id) => await this.#getByPageId(id))
54+
);
55+
}
56+
57+
async upsertSubscription(page_id, url, title, latest_activity_counter) {
58+
let r = await this.#getByPageId(page_id);
59+
60+
if(r === undefined)
61+
{
62+
r = {
63+
"page_id": page_id,
64+
"url": url,
65+
"title": title,
66+
"added": Date.now(),
67+
"curr_activity_counter": latest_activity_counter,
68+
"latest_activity_counter": latest_activity_counter,
69+
"isRemoved": false
70+
};
71+
72+
this.#insertToSubsArray(page_id);
73+
}
74+
else
75+
{
76+
r["url"] = url;
77+
r["title"] = title;
78+
r["latest_activity_counter"] = latest_activity_counter;
79+
}
80+
81+
this.#setByPageId(page_id, r);
82+
}
83+
84+
async isSubscribed(page_id) {
85+
const v = await this.#getByPageId(page_id);
86+
87+
return v !== undefined;
88+
}
89+
90+
async markAsReadIfSubscribed(page_id, latest_activity_counter) {
91+
const r = await this.#getByPageId(page_id);
92+
93+
if(r !== undefined)
94+
{
95+
r.curr_activity_counter = latest_activity_counter;
96+
r.latest_activity_counter = latest_activity_counter;
97+
}
98+
99+
await this.#setByPageId(page_id, r);
100+
}
101+
102+
async setActivityCounterIfSubscribed(page_id, latest_activity_counter) {
103+
const r = await this.#getByPageId(page_id);
104+
105+
if(r !== undefined)
106+
r.latest_activity_counter = latest_activity_counter;
107+
108+
await this.#setByPageId(page_id, r);
109+
}
110+
111+
async setRemoved(page_id) {
112+
const r = await this.#getByPageId(page_id);
113+
114+
if(r !== undefined)
115+
r.isRemoved = true;
116+
117+
await this.#setByPageId(page_id, r);
118+
}
119+
120+
async getSortedSubscriptions() {
121+
const key = "subscriptions_list";
122+
123+
const r = await this.bySub();
124+
125+
const sorted = r
126+
.sort((a, b) => a.added - b.added);
127+
128+
return sorted;
129+
}
130+
131+
async deleteSubscription(page_id) {
132+
const e = [page_id];
133+
await this.#removeListFromSubsArray(e);
134+
135+
const key = this.#getKey(page_id);
136+
await chrome.storage.local.remove(key);
137+
}
138+
139+
async isSubsStored() {
140+
const r = await this.#getSubsArray();
141+
142+
return r.length > 0;
143+
}
144+
145+
async getUnreadCount() {
146+
const unreadSubsFlags = (await this.bySub())
147+
.map((e) => e.curr_activity_counter < e.latest_activity_counter);
148+
149+
const unreadNum = unreadSubsFlags
150+
.map((isUnread) => isUnread ? 1 : 0)
151+
.reduce((ret, i) => ret + i, 0);
152+
153+
return unreadNum;
154+
}
155+
}
156+
157+
const subscriptions = new SubscriptionsStorage();
158+
159+
const own_key = "pages";
160+
161+
const own_comments = {
162+
upsertComment: async(page_id, msg_id, secret) => {
163+
await chrome.storage.local.get(own_key).then((aa) => {
164+
let r = aa[own_key];
165+
166+
if(r === undefined)
167+
r = {};
168+
169+
if(r[page_id] === undefined)
170+
r[page_id] = {
171+
"page_id": page_id,
172+
"own_messages": {}
173+
};
174+
175+
r[page_id].own_messages[msg_id] = {
176+
"msg_id": msg_id,
177+
"secret": secret,
178+
"added": Date.now(),
179+
};
180+
181+
return r;
182+
}).then(
183+
async (r) => await chrome.storage.local.set({[own_key]: r})
184+
);
185+
},
186+
187+
getCommentBelongings: (page_id, msg_id) => {
188+
return chrome.storage.local.get(own_key).then(
189+
(r) => r?.[own_key]?.[page_id]?.own_messages?.[msg_id]
190+
);
191+
},
192+
193+
isCommentModifiable: async(page_id, msg_id) => {
194+
const timeout = 1000 * 60 * 60 * 24 * 2; // 2 days
195+
196+
return await own_comments.getCommentBelongings(page_id, msg_id).
197+
then((r) => {
198+
if(r?.added === undefined)
199+
return false;
200+
else
201+
return (Date.now() - r.added) < timeout;
202+
});
203+
}
204+
}

0 commit comments

Comments
 (0)