bloggerize 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,193 @@
1
+ //////////////////////////////////////////////////
2
+ //
3
+ globalThis.standardLongTags = 'iframe,repdiv,table,font,span,div,img,a';
4
+ globalThis.standardShortTags = 'blockquote,strike,tbody,pre,sub,sup,hr,li,ol,td,tr,ul,p,u';
5
+ globalThis.imgAllowedFormats = '(jpeg|jpg|gif|png|bmp|webp|avif)';
6
+ globalThis.tagForbiddenAttributes = 'onclick,ondblclick,onmouseover,onmouseout,onmousedown,onmouseup,onmousemove,onmouseenter,onmouseleave,onload,onerror,oncontextmenu,sandbox,allow,allowfullscreen';
7
+ globalThis.tagAllowedAttributes = {
8
+ font: 'color,face,style',
9
+ span: 'style,lang,title',
10
+ div: 'style,align,title',
11
+ img: 'src,width,height,style',
12
+ a: 'href,target,title',
13
+ b: 'value,fixed',
14
+ }
15
+ globalThis.tagStyleLimitedProperties = {
16
+ span: 'width,height',
17
+ div: 'width,height',
18
+ img: 'width,height',
19
+ }
20
+ globalThis.regimg = function(scope='i', formats=imgAllowedFormats){return new RegExp(`\\.${formats}$`, scope)}
21
+ globalThis.regtag = function(tag, scope='gi'){return new RegExp(`<${tag}\\s*([^>]*)>([\\w\\W]*?)<\\/${tag}>`, scope)}
22
+ globalThis.regimgtag = function(scope='gi'){return new RegExp(`<img\\b[^>]*src\\s*=\\s*["']([^"']*)["'][^>]*>`, scope)}
23
+ globalThis.reglonetag = function(tag, scope='gi'){return new RegExp(`<${tag}\\s*([^>]*)/>`, scope)}
24
+ globalThis.reglonetag2 = function(tag, scope='gi'){return new RegExp(`<${tag}\\s*([^>]*)>`, scope)}
25
+ globalThis.regp = function(scope='gi'){return new RegExp(`<p(\\s+(style|align|class)\\s*=\\s*["']([^"']*)["'][^>]*)>([\\w\\W]*?)<\\/p>`, scope)}
26
+ String.prototype.reptag = function(oldtag, newtag, omark='[', cmark=']'){return this.replace(regtag(oldtag), `${omark}${newtag}${cmark}$2${omark}/${newtag}${cmark}`)}
27
+ String.prototype.reptagex = function(oldtag, newtag, omark='[', cmark=']'){return this.replace(regtag(oldtag), `${omark}${newtag} $1${cmark}$2${omark}/${newtag}${cmark}`)}
28
+ String.prototype.repimgtag = function(){return this.replace(regimgtag(), `[img=$1]`)}
29
+ String.prototype.replonetag = function(oldtag, newtag, omark='[', cmark=']'){rep=function(text,func){return(text.replace(func(oldtag),`${omark}${newtag} $1${cmark}${omark}/${newtag}${cmark}`))};return(rep(rep(this,reglonetag),reglonetag2))}
30
+ String.prototype.nicetag = function(){return this.replace(/<[^>]+>/g,function(tag){return(tag.replace(/(\s+[a-zA-Z-]+)=([^\s"'>]+)/g,'$1="$2"').replace(/(\s+[a-zA-Z-]+)='([^']*)'/g,'$1="$2"').replace(/\&quot;/gi,"'"))})}
31
+ String.prototype.nicea = function(){const temp=document.createElement('div');temp.innerHTML=this;temp.querySelectorAll('a[href]').forEach(link=>{const href=link.getAttribute('href');if(href&&href.toLowerCase().startsWith('javascript:')){link.removeAttribute('href')}});return(temp.innerHTML)}
32
+ String.prototype.nicep = function(){return this.replace(regp(), '<div$1>$4</div>')}
33
+ String.prototype.longreptag = function(oldtag, newtag){return this.repimgtag().reptagex(oldtag,newtag).replonetag(oldtag,newtag)}
34
+ String.prototype.shortreptag = function(oldtag, newtag){return this.repimgtag().reptag(oldtag,newtag).replonetag(oldtag,newtag)}
35
+ globalThis.regrev = function(tag, spec='', scope='gi', omark='\\[', cmark='\\]'){return new RegExp(`${omark}${tag}${spec}\\s*([^${cmark}]*)${cmark}([\\w\\W]*?)${omark}\\/${tag}${cmark}`, scope)}
36
+ globalThis.regsrev = function(tag, scope='gi', omark='\\[', cmark='\\]'){return new RegExp(`${omark}${tag}\\s*${cmark}([\\w\\W]*?)${omark}\\/${tag}${cmark}`, scope)}
37
+ globalThis.regsxrev = function(tag, spec='', scope='gi', omark='\\[', cmark='\\]'){return new RegExp(`${omark}${tag}${spec}\\s*([^${cmark}]*)${cmark}`, scope)}
38
+ String.prototype.revtag = function(oldtag, newtag, omark='<', cmark='>'){return this.replace(regrev(oldtag), `${omark}${newtag}${cmark}$2${omark}/${newtag}${cmark}`)}
39
+ String.prototype.srevtag = function(oldtag, newtag, omark='<', cmark='>'){return this.replace(regsrev(oldtag), `${omark}${newtag}${cmark}$1${omark}/${newtag}${cmark}`)}
40
+ String.prototype.revtagex = function(oldtag, newtag, omark='<', cmark='>'){return this.replace(regrev(oldtag), `${omark}${newtag} $1${cmark}$2${omark}/${newtag}${cmark}`)}
41
+ String.prototype.xrevtag = function(oldtag, newopen, newclose){return this.replace(regsrev(oldtag), `${newopen}$1${newclose}`)}
42
+ String.prototype.exrevtag = function(oldtag, spec, newopen, newclose, cmark='>'){return this.replace(regrev(oldtag, spec), `${newopen}$1${cmark}$2${newclose}`)}
43
+ String.prototype.exrevtagcolon = function(oldtag, newopen, newclose){return this.exrevtag(oldtag, '\\:', newopen, newclose)}
44
+ String.prototype.exrevtagequal = function(oldtag, newopen, newclose){return this.exrevtag(oldtag, '\\=', newopen, newclose)}
45
+ String.prototype.sxrevtag = function(oldtag, spec, newopen, newclose){return this.replace(regsxrev(oldtag, spec), `${newopen}$1${newclose}`)}
46
+ String.prototype.sxrevtagcolon = function(oldtag, newopen, newclose){return this.sxrevtag(oldtag, '\\:', newopen, newclose)}
47
+ String.prototype.sxrevtagequal = function(oldtag, newopen, newclose){return this.sxrevtag(oldtag, '\\=', newopen, newclose)}
48
+ String.prototype.clearcode = function(){return this.replace(/\[[^\]]*\]/g,' ').replace(/(\s){2,}/g,' ').trim()}
49
+ String.prototype.escapebreaks = function(){return(this.replace(/<\/?p>/gi,'\n').replace(/<br\s*\/?>/gi,'\n').replace(/(\r?\n|\r){3,}/g,'\n\n'))}
50
+ String.prototype.cleanbrtags = function(){return(this.trim().replace(/(\r?<br>|<br\/>){3,}/gi,'<br><br>').replace(/^\s*(?:<br\s*\/?>\s*)+|(?:<br\s*\/?>\s*)+$/gi,''))}
51
+ String.prototype.cleanrepptags = function(){return(this.replace(/&nbsp;/gi,' ').replace(/<p>\s*<\/p>/gi,''))}
52
+ String.prototype.cleanrepbrtags = function(){return(this.replace(/(<br>|<br\/>)(<br>|<br\/>)/i,''))}
53
+ //
54
+ //////////////////////////////////////////////////
55
+ //
56
+ globalThis.resourcesLocation = 'https://cdn.jsdelivr.net/gh/antonroch/blogger';
57
+ globalThis.iconImageLocation = `${resourcesLocation}/img`;
58
+ //
59
+ //////////////////////////////////////////////////
60
+ //
61
+ globalThis.DEF_IMG_WIDTH = 480;
62
+ globalThis.DEF_IMG_HEIGHT = 270;
63
+ globalThis.DEF_STYLE = 'width="100%" height="auto"';
64
+ //
65
+ globalThis.CommentsCounter = 0;
66
+ globalThis.numCommentPerPage = 200;
67
+ globalThis.sDefAllowedTagList = "<br><b><i><a>";
68
+ globalThis.sMoreAllowedTagList = "<p><img><font><span><div><u><li><ol><ul><sup><sub><blockquote><hr><pre><h1><h2><h3><h4><h5><h6><table><tbody><tr><td><iframe><strike><repdiv>";
69
+ globalThis.autoResizeCommentFont = true;
70
+ globalThis.nFontSizeMax = 6;
71
+ globalThis.nFontSizeMin = 3;
72
+ //
73
+ globalThis.numIndexVip1 = 20;
74
+ globalThis.numIndexVip2 = 50;
75
+ globalThis.urlVip1Avatar = `${iconImageLocation}/is_vip02.jpg`;
76
+ globalThis.urlVip2Avatar = `${iconImageLocation}/is_vip03.jpg`;
77
+ globalThis.urlVip3Avatar = `${iconImageLocation}/is_vip04.gif`;
78
+ //
79
+ // Ext-pages-defines:
80
+ globalThis.exPageCmntPages = {};
81
+ globalThis.exPageNames = [];
82
+ //
83
+ // Paginating:
84
+ globalThis.numEntryComment = 0; //Data-post
85
+ globalThis.numEntryCommentFeed = 0; //JSON-Feeder
86
+ globalThis.numEntryCommentRecount = 0; //Onfly-count
87
+ globalThis.numCommentPage = 1;
88
+ globalThis.strPagination = '';
89
+ globalThis.strEntryURL = '';
90
+ globalThis.strPostURL = '';
91
+ globalThis.strPostID = '';
92
+ globalThis.strBlogID = '';
93
+ //
94
+ // Comment-authors:
95
+ globalThis.urlIdAvatars = {};
96
+ globalThis.iCommentSmileys = {};
97
+ //
98
+ // Comment-containers:
99
+ globalThis.dataFullComments = {};
100
+ globalThis.idTextareaCommentPost = 'comment-body';
101
+ //
102
+ // Comment-format:
103
+ globalThis.UserBLs = [];
104
+ globalThis.UserVIPs = [];
105
+ globalThis.isVipAuthor = false;
106
+ globalThis.isBLAuthor = false;
107
+ globalThis.rsBLAuthor = false;
108
+ globalThis.isStyleItalic = false;
109
+ globalThis.isStyleBold = false;
110
+ globalThis.isStyleBGC = false;
111
+ //
112
+ // Comment-consts:
113
+ globalThis.numRecentComments = 25;
114
+ globalThis.maxCommentChars = 175;
115
+ globalThis.useAvatar = false;
116
+ globalThis.urlAnoAvatar = `${iconImageLocation}/noava.jpg`;
117
+ globalThis.urlIconPostA = `${iconImageLocation}/im_star3.gif`;
118
+ globalThis.urlIconPostB = `${iconImageLocation}/im_star2.gif`;
119
+ globalThis.urlIconPostC = `${iconImageLocation}/im_star1.gif`;
120
+ //
121
+ // Stamps-n-cards:
122
+ urlIdAvatars['00'] = [`${iconImageLocation}/i_quanbua2.gif`, 'L&#227;nht&#7909; t&#224;nb&#7841;o manh&#273;&#7897;ng'];
123
+ urlIdAvatars['th'] = [`${iconImageLocation}/i_tinhhoa.gif`, 'Tinhhoa phongnh&#227; baola'];
124
+ urlIdAvatars['vs'] = [`${iconImageLocation}/i_vangson.gif`, 'V&#224;ngson m&#7855;t s&#7855;c m&#244;ng to &#273;&#249;i tr&#242;n'];
125
+ urlIdAvatars['bn'] = [`${iconImageLocation}/i_bannong.gif`, 'B&#7847;nn&#244;ng m&#7891;m &#273;&#7887; c&#7855;n nhanh'];
126
+ urlIdAvatars['jh'] = [`${iconImageLocation}/i_jahoi.gif`, 'C&#225;cm&#225;c gi&#224;h&#243;i, c&#7845;m th&#7857;ng m&#224;y tr&#234;u'];
127
+ urlIdAvatars['tt'] = [`${iconImageLocation}/i_tintin.gif`, 'Tintin ch&#432;a m&#7845;t trinh &#273;&#226;u'];
128
+ urlIdAvatars['db'] = [`${iconImageLocation}/i_daibang.gif`, '&#272;&#7841;ib&#224;ng b&#7909;ng c&#243;c d&#225;i m&#232;o tai d&#417;i'];
129
+ urlIdAvatars['mt'] = [`${iconImageLocation}/i_momthoi.gif`, 'M&#245;m th&#7889;i, bam su&#7889;t b&#7843;y ng&#224;y'];
130
+ urlIdAvatars['oq'] = [`${iconImageLocation}/i_ocquat.gif`, '&#211;c qu&#7845;t, kh&#244;n nh&#7845;t Qu&#225;n n&#224;y con &#417;i'];
131
+ urlIdAvatars['ld'] = [`${iconImageLocation}/i_liudan.gif`, 'L&#7921;u&#273;&#7841;n gi&#7853;t ch&#7889;t qu&#259;ng ngay'];
132
+ urlIdAvatars['td'] = [`${iconImageLocation}/i_thandit.gif`, 'Th&#7847;n &#273;&#7883;t, ch&#417;i kh&#233;o, v&#259;n hay, c&#7863;c d&#224;i'];
133
+ urlIdAvatars['vc'] = [`${iconImageLocation}/i_daubo.gif`, '&#272;&#7847;u b&#242;, b&#7843;oth&#7911; thi&#234;nt&#224;i'];
134
+ urlIdAvatars['sl'] = [`${iconImageLocation}/i_salong.gif`, 'Sal&#244;ng th&#225;nh g&#250;c mi&#7879;tm&#224;i l&#224; &#273;&#226;y'];
135
+ urlIdAvatars['lx'] = [`${iconImageLocation}/i_loxo.gif`, 'L&#242;xo b&#7853;t m&#227;i kh&#244;ng ngu&#244;i'];
136
+ urlIdAvatars['eo'] = [`${iconImageLocation}/i_echop.gif`, '&#7870;ch ng&#7891;i &#273;&#225;y gi&#7871;ng, bi&#7871;t &#273;&#7901;i n&#224;o ngon'];
137
+ urlIdAvatars['cs'] = [`${iconImageLocation}/i_casau.gif`, 'C&#225;s&#7845;u m&#7863;t x&#7845;u v&#227;i l&#7891;n'];
138
+ urlIdAvatars['xl'] = [`${iconImageLocation}/i_xilip.gif`, 'Xil&#237;p h&#7891;ng t&#237;m cho ch&#224;ng hai-phai'];
139
+ urlIdAvatars['oc'] = [`${iconImageLocation}/i_ongcu.gif`, 'Anh C&#7909; r&#259;ng b&#7921;a r&#226;u th&#432;a'];
140
+ urlIdAvatars['ol'] = [`${iconImageLocation}/i_ongle.gif`, 'Anh Le ph&#225;tx&#237;t r&#226;u nh&#432; qu&#7843; m&#236;n'];
141
+ urlIdAvatars['om'] = [`${iconImageLocation}/i_ongmao.gif`, 'Anh Mao r&#226;u c&#7841;o s&#7841;ch tr&#417;n'];
142
+ urlIdAvatars['on'] = [`${iconImageLocation}/i_ongnin.gif`, 'Anh Nin r&#226;u m&#7885;c tr&#249;m quanh quai h&#224;m'];
143
+ urlIdAvatars['bc'] = [`${iconImageLocation}/i_boncau.gif`, 'X&#237; b&#7879;t, n&#244;n kh&#7841;c khai m&#249;'];
144
+ urlIdAvatars['cd'] = [`${iconImageLocation}/i_chuidit.gif`, 'Gi&#7845;y l&#244;, nh&#245;n &#273;&#225;m ph&#242; qu&#234; m&#7899;i d&#249;ng'];
145
+ urlIdAvatars['tb'] = [`${iconImageLocation}/i_taobon.gif`, 'T&#225;ob&#243;n t&#7915; s&#225;ng t&#7899;i &#273;&#234;m'];
146
+ urlIdAvatars['tv'] = [`${iconImageLocation}/i_tinvit.gif`, 'Chuy&#234;n tung tin v&#7883;t, &#7843;o h&#417;n loa ph&#432;&#7901;ng'];
147
+ urlIdAvatars['tz'] = [`${iconImageLocation}/i_tongzat.gif`, 'Em to&#7885;c: M&#7865;o, M&#225;n, T&#224;y, M&#432;&#7901;ng'];
148
+ urlIdAvatars['dance'] = [`${iconImageLocation}/dance.gif`, 'Guerrilla: Zuk&#237;ch Chim B&#432;&#417;ng'];
149
+ urlIdAvatars['fun'] = [`${iconImageLocation}/fun.gif`, 'Actress: V&#361; C&#244;ng V&#250; B&#7921;'];
150
+ urlIdAvatars['hit'] = [`${iconImageLocation}/hit.gif`, 'Policeman: Daoph&#7911; C&#7843;nhbinh'];
151
+ urlIdAvatars['hug'] = [`${iconImageLocation}/hug.gif`, 'Teacher: Gi&#225;o Gi&#7843;ng Tr&#432;&#7901;ng L&#224;ng'];
152
+ urlIdAvatars['kiss'] = [`${iconImageLocation}/kiss.gif`, 'Capitalist: T&#432;b&#7843;n S&#224;ilang'];
153
+ urlIdAvatars['laugh'] = [`${iconImageLocation}/laugh.gif`, 'Communist: D&#7843;ngvi&#234;n Ho&#224;nt&#7909;c'];
154
+ urlIdAvatars['think'] = [`${iconImageLocation}/think.gif`, 'Wanking Netizen: Trai T&#226;n S&#243;c L&#7885;'];
155
+ urlIdAvatars['ship'] = [`${iconImageLocation}/ship.gif`, 'Shipping Biker: Ch&#7841;y Ch&#7907; Xe &#212;m'];
156
+ urlIdAvatars['show'] = [`${iconImageLocation}/show.gif`, 'Fucking Bastard: S&#7871;p Nh&#7899;n H&#7871;t X&#232;ng'];
157
+ urlIdAvatars['ride'] = [`${iconImageLocation}/ride.gif`, 'Homeless Wanderer: Langthang Kh&#244;ng Nh&#224; Kh&#244;ng C&#7917;a'];
158
+ //
159
+ // Comment-href:
160
+ exPageNames[0] = ['ban-hang', 'Mua-ban', 'Bookstore'];
161
+ exPageNames[1] = ['tu-van-kinh-doanh', 'Tuvan kinhdoanh', 'Business Consulting'];
162
+ exPageNames[2] = ['tu-van-cong-nghe', 'Tuvan congnghe', 'Technology Consulting'];
163
+ exPageNames[3] = ['tu-van-giao-duc', 'Tuvan giaoduc', 'Education Consulting'];
164
+ exPageNames[4] = ['tu-van-phap-ly', 'Tuvan phaply', 'Law Consulting'];
165
+ exPageNames[5] = ['tu-van-van-xa', 'Tuvan vanxa', 'Culture Consulting'];
166
+ exPageNames[6] = ['tu-van-suc-khoe', 'Tuvan suckhoe', 'Health Consulting'];
167
+ exPageNames[7] = ['tu-van-gia-inh', 'Tuvan giadinh', 'Life Consulting'];
168
+ exPageNames[8] = ['tu-van-tam-linh', 'Tuvan tamlinh', 'Spirit Consulting'];
169
+ exPageNames[9] = ['tu-van-choi', 'Tuvan anchoi', 'Entertainment Consulting'];
170
+ exPageNames[10] = ['index-mucluc', 'Mucluc Bua', 'Shit Index'];
171
+ exPageNames[11] = ['resources', 'Tainguyen Bua', 'Shit Resources'];
172
+ exPageNames[12] = ['comment-archive', 'Luutru Bua', 'Shit Archive'];
173
+ exPageNames[13] = ['thamgia-paid-box', 'Thamgia Paibox', 'Join Paibox'];
174
+ exPageNames[14] = ['thamgia-fast-mba', 'Thamgia Fast MBA', 'Join Fast MBA'];
175
+ exPageNames[15] = ['thamgia-fast-flp', 'Thamgia Fast FLP', 'Join Fast FLP'];
176
+ exPageNames[16] = ['meo-comment', 'Meo comment', 'Comment Tricks'];
177
+ exPageNames[17] = ['bam-box', 'Bam', 'Bam Box'];
178
+ exPageNames[18] = ['web-games', 'Game', 'Web Games'];
179
+ exPageNames[19] = ['comments-quickview', 'CommentView & Chat', 'CommentView & Chat'];
180
+ //
181
+ // Comment-smiley:
182
+ iCommentSmileys['*dance*'] = [`<img src="${iconImageLocation}/dance.gif" border="0"/>`];
183
+ iCommentSmileys['*fun*'] = [`<img src="${iconImageLocation}/fun.gif" border="0"/>`];
184
+ iCommentSmileys['*hit*'] = [`<img src="${iconImageLocation}/hit.gif" border="0"/>`];
185
+ iCommentSmileys['*hug*'] = [`<img src="${iconImageLocation}/hug.gif" border="0"/>`];
186
+ iCommentSmileys['*kiss*'] = [`<img src="${iconImageLocation}/kiss.gif" border="0"/>`];
187
+ iCommentSmileys['*laugh*'] = [`<img src="${iconImageLocation}/laugh.gif" border="0"/>`];
188
+ iCommentSmileys['*think*'] = [`<img src="${iconImageLocation}/think.gif" border="0"/>`];
189
+ iCommentSmileys['*ship*'] = [`<img src="${iconImageLocation}/ship.gif" border="0"/>`];
190
+ iCommentSmileys['*show*'] = [`<img src="${iconImageLocation}/show.gif" border="0"/>`];
191
+ iCommentSmileys['*ride*'] = [`<img src="${iconImageLocation}/ride.gif" border="0"/>`];
192
+ //
193
+ //////////////////////////////////////////////////
package/buasc.js ADDED
@@ -0,0 +1,81 @@
1
+ // CLI Version
2
+
3
+ const jd = require('jsdom-global')();
4
+
5
+ const urlJsonData1 = 'https://cdn.jsdelivr.net/gh/asinerum/project/team/buas.json';
6
+ const urlJsonData2 = 'https://asinerum.github.io/project/team/buas.json';
7
+
8
+ const LOADED = 'Config loaded';
9
+
10
+ let ACTIVE_JSON_URL = urlJsonData1;
11
+
12
+ globalThis.members;
13
+
14
+ globalThis.loadMembers = function (cbf=console.log, url=ACTIVE_JSON_URL) {
15
+ // Require <xmlhttprequest> installed
16
+ // or just got from JSDOM-GLOBAL
17
+ let xhr = new XMLHttpRequest();
18
+ xhr.open('GET', url, true);
19
+ xhr.responseType = 'json';
20
+ xhr.onload = function () {
21
+ var status = xhr.status;
22
+ if (status === 200) {
23
+ cbf(null, xhr.response.members);
24
+ } else {
25
+ cbf(status, null);
26
+ }
27
+ }
28
+ xhr.send();
29
+ }
30
+
31
+ globalThis.loadMembersSync = function (url=ACTIVE_JSON_URL) {
32
+ // Require <xmlhttprequest> installed
33
+ // or just got from JSDOM-GLOBAL
34
+ let xhr = new XMLHttpRequest();
35
+ try {
36
+ xhr.open('GET', url, false);
37
+ xhr.send(null);
38
+ if (xhr.status === 200) {
39
+ console.log(LOADED);
40
+ return JSON.parse(xhr.responseText).members;
41
+ }
42
+ } catch(err) {
43
+ console.error(`ERROR: ${err}`);
44
+ }
45
+ }
46
+
47
+ async function fetchData(url) {
48
+ try {
49
+ const response = await fetch(url);
50
+ if (!response.ok) {
51
+ throw new Error(`HTTP: ${response.status}`);
52
+ }
53
+ const data = await response.json();
54
+ return data;
55
+ } catch (err) {
56
+ throw err;
57
+ }
58
+ }
59
+
60
+ globalThis.loadMembersAsync = function (url=ACTIVE_JSON_URL) {
61
+ (async () => {
62
+ try {
63
+ const data = await fetchData(url);
64
+ members = data.members;
65
+ syncMembers(members);
66
+ console.log(LOADED);
67
+ } catch(err) {
68
+ console.error(`ERROR: ${err}`);
69
+ }
70
+ })();
71
+ }
72
+
73
+ function syncMembers (mbr) {
74
+ globalThis.numIndexVip1 = mbr.numIndexVip1;
75
+ globalThis.numIndexVip2 = mbr.numIndexVip2;
76
+ globalThis.UserVIPs = mbr.UserVIPs;
77
+ globalThis.UserBLs = mbr.UserBLs;
78
+ }
79
+
80
+ members = loadMembersSync();
81
+ syncMembers(members);
package/download.js ADDED
@@ -0,0 +1,182 @@
1
+ import {} from './loadlib.js';
2
+
3
+ export const BLOG_URL = 'https://an-hoang-trung-tuong-2014.blogspot.com';
4
+ export const BLOG_URL_ALT = 'https://an-hoang-trung-tuong.blogspot.com';
5
+
6
+ export const ARCHIVE_URL = 'https://comment-archive.blogspot.com';
7
+ export const ARCHIVE_BLOG_ID = '8254806400148362373';
8
+
9
+ export let teamMembers;
10
+
11
+ export const COMMENTS_PER_PAGE = 200;
12
+
13
+ // This differs from loadlib.loadJson(url)
14
+ const loadjson = async function (filepath) {
15
+ try {
16
+ const { default: data } = await import (filepath, {
17
+ with: { type: 'json' }
18
+ });
19
+ return data;
20
+ } catch (err) {
21
+ console.error('Error loading JSON file:', err.message);
22
+ process.exit(0);
23
+ }
24
+ }
25
+
26
+ const nodefetch = async function (url) { // Not native fetch
27
+ const node_fetch = (await import('node-fetch')).default;
28
+ const data = await node_fetch(url);
29
+ return data;
30
+ }
31
+
32
+ export async function getPage (url) {
33
+ return await nodefetch(url);
34
+ }
35
+
36
+ export async function getMembers (url) {
37
+ const team = await loadJson(url);
38
+ if (team) {
39
+ teamMembers = team.members;
40
+ return teamMembers;
41
+ }
42
+ return {};
43
+ }
44
+
45
+ // Get Blogspot blog ID information by its URL
46
+ export async function getBlogId (url=BLOG_URL, getid=true) {
47
+ const feedUrl = `${url}/feeds/posts/summary?alt=json&max-results=1&start-index=1`;
48
+ const res = await nodefetch(feedUrl);
49
+ if (!res.ok) throw new Error(`Failed to fetch blog ID: ${res.statusText}`);
50
+ const data = await res.json();
51
+ if (getid) return data.feed.id.$t.split('-').pop();
52
+ data.feed;
53
+ }
54
+
55
+ // Get posts between date range
56
+ export async function getPosts (fromdate, {todate=null, url=BLOG_URL}={}) {
57
+ todate = (todate||fromdate).convertDate() + 'T23:59:59Z';
58
+ fromdate = fromdate.convertDate() + 'T00:00:00Z';
59
+ const feedUrl = `${url}/feeds/posts/summary?alt=json&redirect=false&max-results=200&start-index=1&published-min=${fromdate}&published-max=${todate}`;
60
+ const res = await nodefetch(feedUrl);
61
+ if (!res.ok) throw new Error(`Failed to fetch posts: ${res.statusText}`);
62
+ const data = await res.json();
63
+ const entries = data.feed.entry || [];
64
+ const posts = [];
65
+ for (const entry of entries) {
66
+ const res = await nodefetch(entry.link.findObject('rel', 'self').href + '?alt=json');
67
+ if (!res.ok) throw new Error(`Failed to fetch post content: ${res.statusText}`);
68
+ const data = await res.json();
69
+ const content = data.entry.content.$t;
70
+ posts.push({
71
+ id: entry.id.$t.split('-').pop(),
72
+ title: entry.title.$t,
73
+ label: entry.category?.at(0).term || '',
74
+ entry: entry.link.findObject('rel', 'alternate').href,
75
+ stamp: entry.published.$t.split('.')[0].replace(/t/i, ' '),
76
+ author: entry.author[0].name.$t,
77
+ summary: entry.summary.$t,
78
+ total: entry.thr$total.$t,
79
+ pages: 0,
80
+ pageno: 0,
81
+ comments: [],
82
+ compage: '',
83
+ comlink: '',
84
+ content,
85
+ });
86
+ }
87
+ return posts;
88
+ }
89
+
90
+ // Get comments for a post: getComments(post[i], {})
91
+ export async function getComments (post={}, {frompage=1, pages=1, url=BLOG_URL, limit=COMMENTS_PER_PAGE, newest=false}={}) {
92
+ const total = Number(post.total);
93
+ const tpages = Math.ceil(total / limit);
94
+ if (!total || (frompage < 1) || (limit * (frompage - 1) >= total)) return [];
95
+ if (pages < 1 || frompage + pages - 1 > tpages) pages = tpages - frompage + 1;
96
+ const comments = [];
97
+ for (let page = frompage; page < frompage+pages; page++) {
98
+ const commentindex = page * limit;
99
+ const index = newest ? commentindex : Math.max((total - commentindex + 1), 1);
100
+ const commentsPerLoad = (page >= tpages) ? (total - (limit * (page - 1))) : limit;
101
+ const feedUrl = `${url}/feeds/${post.id}/comments/default?alt=json&start-index=${index}&max-results=${commentsPerLoad}`;
102
+ const res = await nodefetch(feedUrl);
103
+ if (!res.ok) {
104
+ console.log('Failed to fetch comments for page #', page);
105
+ continue;
106
+ }
107
+ let id, count, author, profile, timestamp;
108
+ const data = await res.json();
109
+ const entries = data.feed?.entry || [];
110
+ if (!newest) entries.reverse();
111
+ const pagecomments = entries.map((comment, i) => ({
112
+ id: (id = comment.id.$t.split('-').pop()),
113
+ count: (count = commentindex - limit + i + 1),
114
+ link: `${post.entry}?commentPage=${page}#c${id}`,
115
+ author: (author = comment.author[0].name?.$t || ''),
116
+ profile: (profile = comment.author[0].uri?.$t || ''),
117
+ avatar: comment.author[0].gd$image.src.convertAvatarUrl(),
118
+ timestamp: (timestamp = comment.published.$t), // To check blacklisting
119
+ dated: comment.gd$extendedProperty.findObject('name', 'blogger.displayTime').value,
120
+ content: getStyledComment(profile, author, timestamp, comment.content.$t, false),
121
+ info: showVIP(profile, 1, 24, '&nbsp;', 1, count, id, post.entry),
122
+ }));
123
+ comments.push({page, tpages, pagecomments});
124
+ }
125
+ return comments;
126
+ }
127
+
128
+ // Combine getPosts and getComments
129
+ export async function loadBlog (fromdate, frompage=1, {todate=null, pages=1, url=BLOG_URL, limit=COMMENTS_PER_PAGE, newest=false}={}) {
130
+ try {
131
+ const posts = await getPosts(fromdate, {todate, url});
132
+ const results = [];
133
+ for (const post of posts) {
134
+ const comments = await getComments(post, {frompage, pages, url, limit, newest});
135
+ results.push({post, comments});
136
+ }
137
+ return results;
138
+ } catch (err) {
139
+ console.error('Error:', err.message);
140
+ return [];
141
+ }
142
+ }
143
+
144
+ // Make text/html to save as independent html page
145
+ export async function extractBlog (fromdate, frompage=1, {todate=null, pages=1, url=BLOG_URL, limit=COMMENTS_PER_PAGE, newest=false, texthtml=true, pteindex=0}={}) {
146
+ const entries = await loadBlog(fromdate, frompage, {todate, pages, url, limit, newest});
147
+ if (entries.length === 0) return {}; // OBJECT
148
+ const htmls = [];
149
+ for (const entry of entries) {
150
+ const commentpages = entry.comments;
151
+ for (const commentpage of commentpages) {
152
+ const html = cloneObject(entry.post);
153
+ html.pageno = commentpage.page;
154
+ html.pages = commentpage.tpages;
155
+ html.compage = `${html.entry}?commentPage=${commentpage.page}#comments`;
156
+ html.file = `${html.stamp.split(' ')[0]}.${html.entry.split('/').pop().replace(/\.(?=[^.]*$)/, '.CP'+commentpage.page+'.')}`;
157
+ if (commentpage.page > 1) html.content = html.summary + `\n(<a href="${html.compage}">read more</a>)`;
158
+ if (pteindex > 0) {
159
+ const ptecore = UserVIPs[pteindex-1][0] || pteindex;
160
+ html.comments = commentpage.pagecomments.filter(item => ptecore.ireg().test(item.profile));
161
+ } else {
162
+ html.comments = commentpage.pagecomments;
163
+ }
164
+ html.vol = html.comments.length;
165
+ htmls.push(html);
166
+ }
167
+ }
168
+ if (!texthtml) return htmls; // ARRAY
169
+ const texts = [];
170
+ for (const html of htmls) {
171
+ html.comments = html.comments.map(item => item.content.generateComment(cloneObject(item))).join('')+'\n';
172
+ texts.push({
173
+ vol: html.vol,
174
+ file: html.file,
175
+ page: html.pageno,
176
+ title: html.title,
177
+ label: html.label,
178
+ html: html.content.generatePost(cloneObject(html)).generateHtml()
179
+ });
180
+ }
181
+ return texts;
182
+ }
@@ -0,0 +1 @@
1
+ {"key":"google_project_api_key"}
File without changes
@@ -0,0 +1,29 @@
1
+ let args = process.argv[2];
2
+
3
+ if (!args) {
4
+ console.log(`Syntax: node delete.js "from:<DD/MM/YYYY>, to:<DD/MM/YYYY>, blog:[BLOG_ID]"`);
5
+ process.exit(0);
6
+ }
7
+
8
+ require('bloggerize/blogger.format.gd3');
9
+
10
+ args = args.extractInput();
11
+
12
+ let fromdate = args.from || '';
13
+ let todate = args.to || fromdate;
14
+
15
+ if (!fromdate || !todate) {
16
+ console.log(`Invalid date range provided`);
17
+ process.exit(0);
18
+ }
19
+
20
+ const upload = require('bloggerize/upload');
21
+ const BLOG_ID = '8254806400148362373';
22
+
23
+ let blog_id = args.blog || BLOG_ID;
24
+ let maxResults = args.max || 500;
25
+
26
+ todate = (todate || fromdate).convertDate() + 'T23:59:59Z';
27
+ fromdate = fromdate.convertDate() + 'T00:00:00Z';
28
+
29
+ upload.deletePosts(fromdate, todate, {blog_id, maxResults});
@@ -0,0 +1,63 @@
1
+ const fs = require('fs');
2
+
3
+ let args = process.argv[2];
4
+
5
+ if (!args) {
6
+ console.log(`
7
+ Mandatory argument is missing
8
+ Usage syntax:
9
+ node download.js "from:<FromDate>, to:[ToDate], page:[FromPage], pages:[Pages], dir:[ArchiveFolder], pte:[PrivateIndex], pdir:[PrivateArchiveFolder], url:[BlogURL]"
10
+ `);
11
+ process.exit(0);
12
+ }
13
+
14
+ require('bloggerize/loadlib');
15
+
16
+ const { extractBlog, COMMENTS_PER_PAGE } = require('bloggerize/download');
17
+
18
+ const BLOG_URL = 'https://an-hoang-trung-tuong-2014.blogspot.com';
19
+
20
+ const PUBLIC_FOLDER = 'comment-archive';
21
+ const PRIVATE_FOLDER = 'comment-archive.pte';
22
+
23
+ args = args.extractInput();
24
+
25
+ const fromdate = args.from || '';
26
+ const frompage = Number(args.page) || 1;
27
+ const todate = args.to || fromdate;
28
+ const pages = Number(args.pages) || 1;
29
+ const pteindex = Number(args.pte) || 0;
30
+ const url = args.url || BLOG_URL;
31
+ const limit = Number(args.lim) || COMMENTS_PER_PAGE;
32
+ const newest = args.filo || false;
33
+ const folder = args.dir || PUBLIC_FOLDER;
34
+ const ptefolder = args.pdir || PRIVATE_FOLDER;
35
+
36
+ folder.createFolder();
37
+ ptefolder.createFolder();
38
+
39
+ async function main () {
40
+ const entries = await extractBlog(fromdate, frompage, {todate, pages, url, limit, newest, pteindex});
41
+ if (!Array.isArray(entries)) {
42
+ console.log(`
43
+ No valid posts found, program stopped
44
+ `);
45
+ process.exit(0);
46
+ }
47
+ for (const entry of entries) {
48
+ const file = (pteindex == 1) ? `${ptefolder}/${entry.file}` : `${folder}/${entry.file}`;
49
+ try {
50
+ if (entry.vol > 0) {
51
+ fs.writeFileSync(file, entry.html);
52
+ console.log(entry.file, '..done');
53
+ } else {
54
+ console.log(entry.file, '..ignored');
55
+ }
56
+ } catch (err) {
57
+ console.log(entry.file, '..failed read/write');
58
+ }
59
+ }
60
+ console.log('All done');
61
+ }
62
+
63
+ main();
@@ -0,0 +1,23 @@
1
+ /**
2
+
3
+ This tiny script creates Google Access Token for you to launch Blogger API tasks.
4
+ You have to do the following steps at Google Cloud Console:
5
+ 1. Create new project, pick it when done, or pick another existing project;
6
+ 2. Enable Blogger API V3 service for the project;
7
+ 3. Go to IAM tab on Project Settings menu. Review all project's users;
8
+ 4. Add new user for the project, pick it, or pick any existing user;
9
+ 5. Create and download Credentials JSON file of the picked user;
10
+ Then do these steps at your home machine:
11
+ 1. Save the downloaded file "credentials.json" in your working folder;
12
+ 2. Run this script. Follow its prompts;
13
+ 3. Wait for the file named "token.json" being created;
14
+ 4. Two files "credentials.json" and "token.json" must be kept safely.
15
+
16
+ */
17
+
18
+ const blogger = require('bloggerize/upload');
19
+
20
+ blogger.authorizeThru((res) => {
21
+ if (res) console.log('Done');
22
+ else { console.log('An error has occured'); }
23
+ });
File without changes
@@ -0,0 +1,72 @@
1
+ const fs = require('fs');
2
+
3
+ const blogger = require('bloggerize/upload');
4
+
5
+ const ARCHIVE_URL = 'https://comment-archive.blogspot.com';
6
+ const ARCHIVE_BLOG_ID = '8254806400148362373';
7
+
8
+ const PTE_ARCHIVE_URL = '';
9
+ const PTE_ARCHIVE_BLOG_ID = '';
10
+
11
+ const publicUploadList = './list.upload.txt';
12
+ const privateUploadList = './list.upload.pte.txt';
13
+
14
+ const pathPublicHtml = './comment-archive';
15
+ const pathPrivateHtml = './comment-archive.pte';
16
+
17
+ function filesBeUploaded (list=publicUploadList) {
18
+ try {
19
+ const files = fs.readFileSync(list, 'utf8');
20
+ return files.trim().split('\n').map(item => item.trim()).filter(item => item);
21
+ } catch (err) {
22
+ console.log('File Error:', err.message);
23
+ process.exit(0);
24
+ }
25
+ }
26
+
27
+ async function run (pte=false, draft=false, blog_id=ARCHIVE_BLOG_ID) {
28
+ const publicBeUploaded = filesBeUploaded(publicUploadList);
29
+ const privateBeUploaded = filesBeUploaded(privateUploadList);
30
+ if ((pte && privateBeUploaded.length === 0) ||
31
+ (!pte && publicBeUploaded.length === 0)) {
32
+ console.log('No posts to be uploaded');
33
+ } else {
34
+ console.log('Starting to upload posts..');
35
+ if (pte) await upload(privateBeUploaded, pathPrivateHtml, draft, blog_id);
36
+ else { await upload(publicBeUploaded, pathPublicHtml, draft, blog_id); }
37
+ }
38
+ }
39
+
40
+ async function upload (filelist, frompath, draft=false, blog_id=ARCHIVE_BLOG_ID) {
41
+ filelist = filelist.map(item => `${frompath}/${item}`);
42
+ if (filelist.length === 0) return console.log('No files to post');
43
+ await blogger.insertPosts(filelist, draft, blog_id);
44
+ console.log('Done');
45
+ }
46
+
47
+ ////////////////////////////////////////////////////////////////
48
+
49
+ let DEF_READ_FOLDER = pathPublicHtml;
50
+ let thefile = process.argv[2];
51
+
52
+ let archive_blog_url = ARCHIVE_URL;
53
+ let archive_blog_id = ARCHIVE_BLOG_ID;
54
+ let read_folder = DEF_READ_FOLDER;
55
+ let private_upload = false;
56
+
57
+ let args = process.argv[3];
58
+ if (args) {
59
+ args = args.extractInput();
60
+ read_folder = args.dir || read_folder;
61
+ archive_blog_url = args.url || archive_blog_url;
62
+ private_upload = args.pte || private_upload; // Use with cares
63
+ (async () => {archive_blog_id = await(blogId(archive_blog_url))})();
64
+ }
65
+
66
+ if (thefile) {
67
+ (async () => await upload(thefile.split(',').map(item => item.trim()).filter(item => item), read_folder, false, archive_blog_id))();
68
+ } else {
69
+ (async () => await run(private_upload, false, archive_blog_id))();
70
+ }
71
+
72
+ ////////////////////////////////////////////////////////////////