-
Notifications
You must be signed in to change notification settings - Fork 3
/
UserAgentChanger.uc.js
341 lines (328 loc) · 12.8 KB
/
UserAgentChanger.uc.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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
// ==UserScript==
// @name UserAgentChangeModLite.uc
// @namespace UserAgentChangeModLite_xinggsf
// @downloadUrl https://raw.githubusercontent.com/xinggsf/uc/master/UserAgentChanger.uc.js
// @charset utf-8
// @version 2017.5.22
// @note 2016-10-6 xinggsf: 完善 _blank link 单击事件的处理
// @note 2016-10-4 xinggsf: 自定义站点全部使用正则表达式;[fix bug] 新增自定义站点并重载配置后出错
// @note 2016-09-26 xinggsf: [fix bug] click blank link
// @note modify by lastdream2013 at 20130616 mino fix
// @note modify by lastdream2013 at 20130409 sitelist : change SITELIST idx to Name
// @include chrome://browser/content/browser.xul
// ==/UserScript==
Cu.import('resource://gre/modules/Services.jsm');
var ucjs_UAChanger = {
//现有版本firefox的图标
NOW_UA_IMG : "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABEAAAARCAYAAAA7bUf6AAABtUlEQVQ4ja2UP2hUQRDGJ2Ih2mnE1kotkrSCoATEwlIbtQgmJDzudlbBu3DvfYP3+KaylhQpLYOFCGIhgqC1TQJWmkQtUgSxuSYmilrcXXh3e4L/BqbZP7/Z/b7ZlQifU3BL4Z0/T25H81sSzX/8a4rC9wYH+VnhzyP8pZo/U/MnCj5UcEXNPyQQ+BdReKc3sBnNn0bz9Qh+jOALNe5UNryN4FIEl6oQhXf2IQp/E/P2ZABbwbwZCr8xXFXBNRGROtrnFf4tgUT4apbxsPRCwUYAW9F8vVL1uxqvi4io8UECqRunpBIKHAs5zyn4flADPu7O+0wC6W/OmhyvGSdCwTDKiVD4NRGRWsGTCWR6mgdFROaA4xl4Zsixr/tXsvJir95YAsmaHK/ocUrBhlp5af4Oj0Yje8JuzSwuHhERqefl5VHu3OwieGDB7ETNOKE5Lyi4UnGn0S/Ut3oIwndVYWdneUgLLkT4agQfBfDqgPDGV6nFXeXvyW+EFp6PbLbKke+LyNivAMG4nHRsNO6O6MwNLRyK9tl66+5pLcorCpZqfJ2sNe78r1fM2wpu/9V/YvykoP0E9a4dzemYDMIAAAAASUVORK5CYII=",
UANameIdxHash : [],
TARGET : null,
def_idx : 0,
Current_idx : 0,
init : function () {
this.clickUrl = {};
this.reload();
this.mkData(); // UA データ(UA_LIST)を作る
let uaBtn = document.createElement("toolbarbutton");//若添加到菜单可改为创建menu,相应class属性得改为menu-iconic
uaBtn.setAttribute("id", "ucjs_UserAgentChanger");
uaBtn.setAttribute('type', 'menu');
uaBtn.setAttribute('class', 'toolbarbutton-1 chromeclass-toolbar-additional');
uaBtn.setAttribute("label", "UserAgentChange");
uaBtn.setAttribute("tooltiptext", '左键:弹出菜单\n中键:重载配置\n右键:编辑配置');
uaBtn.setAttribute("image", this.UA_LIST[this.def_idx].img);
uaBtn.setAttribute('onclick', 'if (event.button == 2) {event.preventDefault();closeMenus(event.currentTarget); ucjs_UAChanger.edit();}if(event.button == 1) { ucjs_UAChanger.reload(true);}');
let insPos = document.getElementById('urlbar-icons');
insPos.appendChild(uaBtn);
this.mkPanel(); // 生成菜单、面板
this.setSiteIdx();
Services.obs.addObserver(this, "http-on-modify-request", false);
Services.obs.addObserver(this, "content-document-global-created", false);
let contentArea = document.getElementById("appcontent");
contentArea.addEventListener("load", this, true);
contentArea.addEventListener("select", this, false);
contentArea.addEventListener("click", this, false);
let contentBrowser = this.getContentBrowser();
contentBrowser.tabContainer.addEventListener("TabClose", this, false);
window.addEventListener("unload", this, false);
window.getBrowser().addProgressListener(this);
},
checkUARule : function (url) {
for (let i of this.SITE_LIST) {
if (i.url.test(url)) return this.UA_LIST[i.idx].ua;
}
return null;
},
reload : function (isAlert) {
let data = this.importUserAgentChange();
if (!data)
return this.alert('Load Error: 配置文件不存在');
let sandbox = new Cu.Sandbox(new XPCNativeWrapper(window));
try {
Cu.evalInSandbox(data, sandbox, "1.8");
} catch (e) {
return this.alert('Error: ' + e + '\n请重新检查配置文件');
}
this.DISPLAY_TYPE = sandbox.DISPLAY_TYPE;
this.SITE_LIST = sandbox.SITE_LIST;
this.UA_LIST = sandbox.UA_LIST;
try {
document.getElementById("ucjs_UserAgentChanger").removeChild(document.getElementById("uac_popup"));
this.mkData();
this.mkPanel();
} catch (e) {}
this.setSiteIdx();
if (isAlert)
this.alert('配置已经重新载入');
},
alert : function (aString, aTitle) {
Cc['@mozilla.org/alerts-service;1'].getService(Ci.nsIAlertsService)
.showAlertNotification("", aTitle || "UserAgentChanger", aString, false, "", null);
},
userAgentChangeFile : function () {
let aFile = FileUtils.getFile("UChrm", ["local", "_userAgentChange.js"], false);
if (!aFile.exists() || !aFile.isFile()) return null;
return aFile;
},
importUserAgentChange : function () {
let file = this.userAgentChangeFile();
let fstream = Cc["@mozilla.org/network/file-input-stream;1"].createInstance(Ci.nsIFileInputStream);
let sstream = Cc["@mozilla.org/scriptableinputstream;1"].createInstance(Ci.nsIScriptableInputStream);
fstream.init(file, -1, 0, 0);
sstream.init(fstream);
let data = sstream.read(sstream.available());
try {
data = decodeURIComponent(escape(data));
} catch (e) {}
sstream.close();
fstream.close();
return data;
},
edit : function () {
let aFile = this.userAgentChangeFile();
if (!aFile || !aFile.exists() || !aFile.isFile())
return;
let editor;
try {
editor = Services.prefs.getComplexValue("view_source.editor.path", Ci.nsILocalFile);
} catch (e) {
this.alert("请设置编辑器的路径。\nview_source.editor.path");
toOpenWindowByType('pref:pref', 'about:config?filter=view_source.editor.path');
return;
}
let UI = Cc["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Ci.nsIScriptableUnicodeConverter);
UI.charset = window.navigator.platform.toLowerCase().indexOf("win") >= 0 ? "gbk" : "UTF-8";
let process = Cc['@mozilla.org/process/util;1'].createInstance(Ci.nsIProcess);
try {
let path = UI.ConvertFromUnicode(aFile.path);
let args = [path];
process.init(editor);
process.run(false, args, args.length);
} catch (e) {
this.alert("编辑器不正确!")
}
},
getPlatformString: function(userAgent) {
if (!userAgent) return;
let s = userAgent.toLowerCase();
if (s.indexOf("win64") > -1) return "Win64";
if (s.indexOf("windows") > -1) return "Win32";
if (s.indexOf("android") > -1) return "Linux armv7l";
if (s.indexOf("linux") > -1) return "Linux i686";
if (s.indexOf("iphone") > -1) return "iPhone";
if (s.indexOf("ipad") > -1) return "iPad";
if (s.indexOf("mac os x") > -1) return "MacIntel";
},
mkData : function () {
let ver = this.getVer();
let tmp = [];
tmp.name = "Firefox" + ver;
tmp.ua = "";
tmp.img = this.NOW_UA_IMG;
tmp.label = "Fx" + ver;
this.UA_LIST.unshift(tmp);
const ps = Services.prefs.getBranch("");
if (ps.getPrefType("general.useragent.override") != 0) {
let ua =ps.getCharPref("general.useragent.override");
this.def_idx = this.UA_LIST.findIndex(x => ua === x.ua);
if (this.def_idx <0) this.def_idx = 0;
}
},
mkPanel : function () {
let mi, ppm = document.createElement("menupopup");
ppm.setAttribute("id", "uac_popup");
for (let [i, k] of this.UA_LIST.entries()) {
if (k.name == "分隔线") {
mi = document.createElement("menuseparator");
} else {
mi = document.createElement("menuitem");
mi.setAttribute('label', k.name);
mi.setAttribute('tooltiptext', k.ua);
mi.setAttribute('oncommand', "ucjs_UAChanger.setUA(" + i + ");");
if (this.DISPLAY_TYPE) {
mi.setAttribute('class', 'menuitem-iconic');
mi.setAttribute('image', k.img);
} else {
mi.setAttribute("type", "radio");
mi.setAttribute("checked", i === this.def_idx);
}
if (i === this.def_idx) {
mi.setAttribute("style", 'font-weight: bold;');
mi.style.color = 'red';
} else {
mi.setAttribute("style", 'font-weight: normal;');
mi.style.color = 'black';
}
mi.setAttribute("uac-generated", true);
}
ppm.appendChild(mi);
}
mi = document.createElement("menuseparator");
ppm.appendChild(mi);
mi = document.createElement("menuitem");
mi.setAttribute('id', 'ucjs_UAChangerConfig');
mi.setAttribute('label', '重载UA配置');
mi.setAttribute("tooltiptext", '左键重载;右键编辑');
mi.setAttribute('oncommand', 'event.preventDefault(); ucjs_UAChanger.reload(true);');
mi.setAttribute('onclick', 'if (event.button == 2) {event.preventDefault(); closeMenus(event.currentTarget); ucjs_UAChanger.edit(); }');
ppm.appendChild(mi);
let menu = document.getElementById("ucjs_UserAgentChanger");
menu.addEventListener("popupshowing", this, false);
menu.appendChild(ppm);
},
observe : function (subject, topic, data) {
if (topic === "http-on-modify-request") {
let http = subject.QueryInterface(Ci.nsIHttpChannel);
let ua = this.checkUARule(http.URI.spec);
if (ua) http.setRequestHeader("User-Agent", ua, false);
}
else if (topic === "content-document-global-created") {
let aSubject, aChannel;
if (subject.defaultView) aSubject = subject.defaultView;
if (subject.QueryInterface && subject.document) {//subject可能是iframe
aSubject = subject;
}
if (aSubject) aChannel = aSubject.QueryInterface(Ci.nsIInterfaceRequestor)
.getInterface(Ci.nsIWebNavigation)
.QueryInterface(Ci.nsIDocShell)
.currentDocumentChannel;
if (aChannel instanceof Ci.nsIHttpChannel) {
let navigator = aSubject.navigator;
let ua = this.checkUARule(aChannel.URI.spec) || aChannel.getRequestHeader("User-Agent");
//console.log(aChannel.URI.spec, ua);
if (navigator.userAgent !== ua)
Object.defineProperty(XPCNativeWrapper.unwrap(navigator), "userAgent", {
value : ua,
enumerable : true
});
let platform = this.getPlatformString(ua);
if (platform) {
Object.defineProperty(XPCNativeWrapper.unwrap(navigator), 'platform', {
value: platform,
enumerable: true
});
}
}
else {
//console.info(subject);
let url, ua,
blankWin = subject.content || subject;// .content取chrome窗口的网页窗口,FX53中subject为window
if (!blankWin) return;
url = blankWin.document.URL;
//console.log(url, blankWin.navigator.userAgent);
if (this.nextBlankUA && url.startsWith('about:')) {
Object.defineProperty(XPCNativeWrapper.unwrap(blankWin.navigator), "userAgent", {
value : this.nextBlankUA,
enumerable : true
});
this.nextBlankUA = null;
}
}
}
},
handleEvent : function (aEvent) {
let contentBrowser;
switch (aEvent.type) {
case "click":
if (!aEvent.ctrlKey && 0 === aEvent.button) {
let ua, a = aEvent.target.closest('a[href][target=_blank]');
if (a && (ua = this.checkUARule(a.href))) {
this.clickUrl[a.href] = ua;
this.nextBlankUA = ua;
}
}
break;
case "popupshowing":
for (let [i, k] of aEvent.target.childNodes.entries()) {
if (i == this.Current_idx) {
k.setAttribute("style", 'font-weight: bold;');
k.style.color = 'red';
if (!this.DISPLAY_TYPE)
k.setAttribute("checked", true);
} else {
k.setAttribute("style", 'font-weight: normal;');
k.style.color = 'black';
}
}
break;
case "load":
case "select":
case "TabClose":
contentBrowser = this.getContentBrowser();
let x = this.SITE_LIST.find(k => k.url.test(contentBrowser.currentURI.spec));
x = x ? x.idx : this.def_idx;
this.setImage(x);
break;
case "unload":
Services.obs.removeObserver(this, "http-on-modify-request");
Services.obs.removeObserver(this, "content-document-global-created");
let contentArea = document.getElementById("appcontent");
contentArea.removeEventListener("load", this, true);
contentArea.removeEventListener("select", this, false);
contentBrowser = this.getContentBrowser();
if (contentBrowser)
contentBrowser.tabContainer.removeEventListener("TabClose", this, false);
let ppm = document.getElementById("uac_popup");
ppm.removeEventListener("popupshowing", this, false);
window.removeEventListener("unload", this, false);
window.getBrowser().removeProgressListener(this);
break;
}
},
setUA : function (i) {
let ps = Services.prefs.getBranch("");
if (i == 0) { // オリジナル UA にする場合
if (ps.getPrefType("general.useragent.override") == 0)
return;
ps.clearUserPref("general.useragent.override");
} else { // 指定した UA にする場合
ps.setCharPref("general.useragent.override", this.UA_LIST[i].ua);
}
this.def_idx = i;
this.setImage(i);
},
setImage : function (i) {
let menu = document.getElementById("ucjs_UserAgentChanger");
menu.setAttribute("image", this.UA_LIST[i].img);
menu.setAttribute("label", this.UA_LIST[i].name);
menu.style.padding = "0px 2px";
this.Current_idx = i;
},
getVer : function () {
return Services.appinfo.version.slice(0, 3);
},
setSiteIdx : function () {
for (let [i, k] of this.UA_LIST.entries()) {
this.UANameIdxHash[k.name] = i;
}
for (let k of this.SITE_LIST) {
k.idx = this.UANameIdxHash[k.Name] || this.def_idx;
}
},
getContentBrowser : function () {
let top = Services.wm.getMostRecentWindow("navigator:browser");
if (top)
return top.document.getElementById("content");
return null;
}
}
ucjs_UAChanger.init();