Полезная информация

Общайтесь со знакомыми и друзьями в нашей группе в Контакте.

№1522605-03-2021 21:59:29

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

solombala

скрытый текст

Если использовать ChromeUtils.requestProcInfo() то, как уже прозвучало,
residentUniqueSize добавили относительно недавно, FF81.
Плюс, из кнопки это делать не удобно, таймер, по понятиям, должен быть один,
а значит надо добавлять его в NSVO JSM'ок или в их общий глобальный объект.


Но не просто добавлять кодом, а загружать туда скриптом (или использовать что-то eval-like).
Дело в том, что requestProcInfo() возвращает promise, а они капризны,
для их работы глобальный объект (в котором исполнился код) должен быть живым,
и если это было окно, и если это окно закрыть, то всё встанет враскоряку.


К тому же, метод претерпел много прключений, в каких-то семидесятых версиях
показывал ерунду на Linux, а в однопроцессном режиме вообще вызывал краш.


А если использовать nsIMemoryReporterManager, то нужно грузить process script,
и собирать сумму того, что придёт "оттуда" (а всё ли придёт? а сколько ждать?)
что, как и любое межпроцессное взаимодействие, как говориться "радости мало".


И, так можно что-то собрать только с XPCOM-процессов,
то есть выпадают процессы типа gpu, socket, rdd, preallocated(?)...


Вобщем, учитывая «Так то всегда однопроцессорный режим.», скорее нет.

Отсутствует

 

№1522705-03-2021 22:08:01

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

Dumby
Понятно, а скрипт ваш доработать?  Это вставить :

скрытый текст

Выделить код

Код:

if ( memory > 770 ) {
        var file = Services.dirsvc.get('ProfD', Ci.nsIFile);
         file.initWithPath(file.path + "\\memred\\start.vbs"); 
         file.launch();

И клик на это

скрытый текст

Выделить код

Код:

var file = Services.dirsvc.get('ProfD', Ci.nsIFile);
         file.initWithPath(file.path + "\\memred\\start.vbs"); 
         file.launch();


Стиль тоже желательно, хотя и в userchrome.css можно...Короче, автоочистка и принудиловка нужна, и можно от кнопки избавляться...

Отсутствует

 

№1522806-03-2021 00:33:48

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1644
UA: Firefox 78.0

Re: Custom Buttons

rubel
Она же вам не понравилась, типа ничего не показывает. Хотя, мне не совсем понятно, шашечки нужны или ехать. )

custom_script.js

Выделить код

Код:

// MemoryMinimizationButton
try {
      CustomizableUI.createWidget({ //must run createWidget before windowListener.register because the register function needs the button added first
        id: 'memoryMinimizationButton',
        type:  'custom',
        defaultArea: CustomizableUI.AREA_NAVBAR,
        onBuild: function(aDocument) {
          var toolbaritem = aDocument.createElementNS('http://www.mozilla.org/keymaster/gatekeeper/there.is.only.xul', 'toolbarbutton');
          var props = {
            id: "memoryMinimizationButton",
            class: "toolbarbutton-1 chromeclass-toolbar-additional",
            tooltiptext: "Минимизировать память",
            oncommand: "memoryMinimizationButton.doMinimize(event);",
            type: CustomizableUI.TYPE_TOOLBAR,
            label: "Минимизировать память",
            removable: "true"
          };
          for (var p in props) {
            toolbaritem.setAttribute(p, props[p]);
          }
          
          return toolbaritem;
        },
      });
    } catch(ee) {}


custom_script_all_win.js

Выделить код

Код:

// ==UserScript==
// @name           s_MemoryMinimizationButton
// @namespace      http://space.geocities.yahoo.co.jp/gl/alice0775
// @charset        utf-8
// @include        main
// @compatibility  Firefox 60
// @author         Alice0775
// @version        2018/10/09 00:00 fix CSS
// @version        2018/09/07 23:00 fix initial visual status
// ==/UserScript==
var memoryMinimizationButton = {
  get memoryMinimizationButton(){
    return document.getElementById("memoryMinimizationButton");
  },

  get statusinfo() {
    if ("StatusPanel" in window) {
      // fx61+
      return StatusPanel._labelElement.value;
    } else {
      return XULBrowserWindow.statusTextField.label;
    }
  },

  set statusinfo(val) {
    if ("StatusPanel" in window) {
      // fx61+
      StatusPanel._label = val;
    } else {
      XULBrowserWindow.statusTextField.label = val;
    }
    if(this._statusinfotimer)
      clearTimeout(this._statusinfotimer);
    this._statusinfotimer = setTimeout(() => {this.hideStatusInfo();}, 2000);
    this._laststatusinfo = val;
    return val;
  },

  init: function() {
    let style = `
      #memoryMinimizationButton {
          width: 16px;
          height: 16px;
        list-style-image: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACAAAAAgCAYAAABzenr0AAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAYdEVYdFNvZnR3YXJlAHBhaW50Lm5ldCA0LjEuMWMqnEsAAAFdSURBVFhH7VbLbsMwDMsef5dc8z/53F13GXZYm5kaZciqnKro2hxaAkRkmkqI2gI6KNZ1vStPEJluyS6WZVlB3xDpWc3q/Ewf6ASClwicLkhojc5PxaDvgQIU4dWSPjEa/Z1y1ed5fqPUeCmJVhAGUC9YNzz4ghNEelYDrI5aAozjeNyD5QBqgF34DJAN8GN4oGb3cJ527fftumEqgAVurdk7Um680zR92bXWEdMBWB+s14+TegFf93hpgF5dgylK/cFSPSGvOgKA9afWgP4y+lR/xKuOwMN6AdwFXff4H0eAqfhWnU9Mhdx+rrtMBSjER3TUtLYaqOMYjaldN8wGuBmfAWqAcmMPe1ACYF6lIBUZXXFO29I3/5IVoFMpcLoA2iX96gVLiBb0bb6gINSy/WLsgb4HDgBD0BzqXsv0i8nDm+/JCC8lKW5zY4SGvT9LBdbVS0g/64q4fxh+AZvdJHHKcZdFAAAAAElFTkSuQmCC');
      }
      @media (min-resolution: 1.1dppx) {
        #memoryMinimizationButton {
          width: 32px;
          height: 32px;
        }
      }
     `.replace(/\s+/g, " ");

    let sss = Components.classes['@mozilla.org/content/style-sheet-service;1']
                .getService(Components.interfaces.nsIStyleSheetService);
    let newURIParam = {
        aURL: 'data:text/css,' + encodeURIComponent(style),
        aOriginCharset: null,
        aBaseURI: null
    }
    let cssUri = Services.io.newURI(newURIParam.aURL, newURIParam.aOriginCharset, newURIParam.aBaseURI);
    sss.loadAndRegisterSheet(cssUri, sss.AUTHOR_SHEET);

    if (this.memoryMinimizationButton)
      return;
  },

  doMinimize: function(event) {
    function doGlobalGC()  {
       Services.obs.notifyObservers(null, "child-gc-request");
       Cu.forceGC();
    }

    function doCC()  {
      Services.obs.notifyObservers(null, "child-cc-request");
      if (typeof window.windowUtils != "undefined")
        window.windowUtils.cycleCollect();
      else
      window.QueryInterface(Components.interfaces.nsIInterfaceRequestor)
            .getInterface(Components.interfaces.nsIDOMWindowUtils).cycleCollect();
    }

    function doMemMinimize() {
      Services.obs.notifyObservers(null, "child-mmu-request");
      var gMgr = Cc["@mozilla.org/memory-reporter-manager;1"]
             .getService(Ci.nsIMemoryReporterManager);
      gMgr.minimizeMemoryUsage(() => memoryMinimizationButton.displayStatus("Memory minimization done"));
    }
    function sendHeapMinNotifications()  {
      function runSoon(f) {
        var tm = Cc["@mozilla.org/thread-manager;1"]
                  .getService(Ci.nsIThreadManager);

        tm.mainThread.dispatch({ run: f }, Ci.nsIThread.DISPATCH_NORMAL);
      }

      function sendHeapMinNotificationsInner() {
        var os = Cc["@mozilla.org/observer-service;1"]
                 .getService(Ci.nsIObserverService);
        os.notifyObservers(null, "memory-pressure", "heap-minimize");

        if (++j < 3)
          runSoon(sendHeapMinNotificationsInner);
      }

      var j = 0;
      sendHeapMinNotificationsInner();
    }

    this.displayStatus("Начало минимизации памяти")
    doGlobalGC();
    doCC();
    //sendHeapMinNotifications();
    setTimeout(()=> {doMemMinimize();}, 1000);
  },
  
  _statusinfotimer: null,
  _laststatusinfo: null,
  displayStatus: function(val) {
    this.statusinfo = val;
  },
  hideStatusInfo: function() {
    if(this._statusinfotimer)
      clearTimeout(this._statusinfotimer);
    this._statusinfotimer = null;
    if (this._laststatusinfo == this.statusinfo)
      this.statusinfo = "";
  }

}

  memoryMinimizationButton.init();


В custom_script_all_win.js скрипт у меня подключен через лоадер.
   
Добавлено 06-03-2021 00:45:09
Dumby

Можно заменить на тот же residentSetSize

Так работает.
   
Можете подсказать как на него повесить по ЛКМ выполнение скрипта из спойлера "custom_script_all_win.js"?
Ну или другой способ запуска, по ЛКМ или ПКМ на виджете, "Minimize Memory Usage" из about:memory.

Отредактировано _zt (06-03-2021 01:13:40)

Отсутствует

 

№1522906-03-2021 01:59:44

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 86.0

Re: Custom Buttons

_zt пишет

Надо, если хотите подключить ее в UCF. Я ж об этом писал.

А зачем обязательно подключать в UCF? Чем не устраивают методы Aris-t2?

Отсутствует

 

№1523006-03-2021 09:17:00

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

solombala пишет

Понятно, а скрипт ваш доработать?  Это вставить :
И клик на это
Стиль тоже желательно, хотя и в userchrome.css можно...Короче, автоочистка и принудиловка нужна, и можно от кнопки избавляться...

Как-то так, наверно. Но

solombala пишет

Автоматом срабатывает при 770мгб .сами выставляйте. Для особо одаренных - при мультережиме нет большого смысла.

Поскольку это как раз про меня, то не понял. Если имеется в виду,
что для мультирежима прописать отдельное значение, то можно.
А если имеется в виду, вообще не запускать в мультирежиме,
то раскомментируй (там, ближе к концу) //this.notMulti &&

скрытый текст

Выделить код

Код:

(async id => ({

	delay: 2e3,

	get limit() {
		var mb = 1024 * 1024;
		delete this.limit;
		return this.limit = this.notMulti
			? 770 * mb // not multiprocess, 770MB
			: 1.64 * 1024 * mb; // multiprocess, 1.64GB
	},
	xul: `
		<hbox
			id="${id}"
			value="ram"
			tooltiptext="ЛКМ: Очистить Память"
		>
			<label id="${id += "-label"}"/>
		</hbox>
	`,
	css: `
		min-height: 23px !important;
		height: 23px !important;
		border-radius: 3px !important;
		padding: 0px 5px 0px !important;
		font-family: segoe ui !important;
		color: #00ffff !important;
		font-size: 15px !important;
		margin-bottom: 2px !important;
		margin-right: 1px !important;
		margin-left: 3px !important;
		background: linear-gradient(rgb(72, 85, 108),rgb(20, 25, 34)) !important;
	`,
	launch() {
		var file = Services.dirsvc.get("ProfD", Ci.nsIFile);
		["memred", "start.vbs"].forEach(file.append);
		(this.launch = file.launch)();
	},
	val: "",
	init(topic, mm) {
		Services.obs.addObserver(mm = this, topic);
		Services.obs.addObserver(function quit(s, t) {
			this.timer?.cancel();
			Services.obs.removeObserver(mm, topic);
			Services.obs.removeObserver(quit, t);
		}, "quit-application-granted");
	},
	observe(win) {
		var df = win.MozXULElement.parseXULToFragment(this.xul);
		this.click = e => e.button || this.launch();
		this.notMulti = !Services.appinfo.browserTabsRemoteAutostart;
		this.timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);

		(this.observe = async win => {
			this.timer.cancel();
			await new Promise(win.requestAnimationFrame);
			var clone = win.document.importNode(df, true);
			var hbox = clone.firstChild;
			win.document.getElementById("page-action-buttons").append(clone);
			hbox.onclick = this.click;
			hbox.style.cssText = this.css;
			hbox.firstChild.style.setProperty("margin", "0", "important");
			this.notify();
		})(win);
	},
	async notify() {
		var info = await ChromeUtils.requestProcInfo();
		var bytes = info.residentSetSize;
		for(var child of info.children) bytes += child.residentUniqueSize;
		this.timer.initWithCallback(this, this.delay, this.timer.TYPE_ONE_SHOT);

		var prev = this.val;
		if ((this.val = this.mgb(bytes)) != prev)
			for(var win of CustomizableUI.windows)
				win.document.getElementById(id).value = this.val;

		//this.notMulti &&
			bytes > this.limit && this.launch();
	},
	mgb: bytes => bytes < 1073741824
		? String(Math.round(bytes / 1048576))
		: (bytes / 1073741824).toFixed(2)
}).init("browser-delayed-startup-finished"))("ucf-mem-indicator");

_zt пишет

Можете подсказать как на него повесить по ЛКМ выполнение скрипта из спойлера "custom_script_all_win.js"?

скрытый текст
Надеюсь это не следует понимать буквально,
потому что «выполнение скрипта из спойлера» приводит только
к созданию в окне объекта memoryMinimizationButton и вызову его метода init().


Который, кстати, регистрирует стиль через nsIStyleSheetService.loadAndRegisterSheet(),
а, поскольку этот стиль глобален, то такому действию не место в окне, и,
аналогично как с CustomizableUI.createWidget(), желательно быть в custom_script.js


Нет, ну ничего страшного, конечно. Просто с каждым новым окном
регистрируется ещё один (новый, точно такой же) глобальный стиль.


Если имеется в виду вызов doMinimize(), то примерно так.
Если CUI-виджет предполагается удалить, тогда еще в коде для custom_script_all_win.js
удалить или закомментировать последнюю строку memoryMinimizationButton.init();
ну и, по желанию, собственно сам метод init()
скрытый текст

Выделить код

Код:

/*
			`<hbox id="${id}"><label id="${id += "-label"}"/></hbox>`
*/
			`<hbox id="${id}" tooltiptext="${
				"Some tooltip text."
			}" onclick="event.button || ${
				"memoryMinimizationButton.doMinimize()"
			}"><label id="${id += "-label"}"/></hbox>`

Отредактировано Dumby (06-03-2021 09:19:41)

Отсутствует

 

№1523106-03-2021 11:34:39

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1644
UA: Firefox 78.0

Re: Custom Buttons

Dumby

Просто с каждым новым окном
регистрируется ещё один (новый, точно такой же) глобальный стиль.

В лоадере внешних файлов, в custom_script_all_win.js, он прописан в секции основного окна (browser.xhtml) и, насколько я понимаю, в других окнах не выполняется.
Мне memoryMinimizationButton.uc.js в custom_script.js переподключить? Я всегда думал, что custom_script.js для кнопок.
   

собственно сам метод init()

Отлично, спасибо.
   
voqabuhe

А зачем обязательно подключать в UCF? Чем не устраивают методы Aris-t2?

Да тем же чем не устраивает два антивируса, два фаервола, два блокировщика рекламы. Нечего плодить сущности.
Сомнительно что использование двух или трех загрузчиков скриптов (user_chrome_files, Сustom Buttons, CustomJSforFx) положительно скажется на производительности браузера.

Отредактировано _zt (06-03-2021 12:09:28)

Отсутствует

 

№1523206-03-2021 11:42:13

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

DumbyНи черта не понял. это только для мульти? Тогда автоочистка не работает...
Кнопка "видео в плеер" тоже сдыхает при мульти...Это конец...

Отредактировано solombala (06-03-2021 13:50:00)

Отсутствует

 

№1523306-03-2021 14:49:16

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

_zt пишет

В лоадере внешних файлов, в custom_script_all_win.js, он прописан в секции основного окна (browser.xhtml) и, насколько я понимаю, в других окнах не выполняется.

Это верно. Однако самих окон browser.xhtml может быть открыто сколько угодно.
Но да, понимаю, я и сам «одноокошечник». Ещё всё время забывается,
что WebExtensions могут заказать лисе открыть окно системы «popup»,
так вот оно тоже будет browser.xhtml, только тулбаров в нём не видно.

Мне memoryMinimizationButton.uc.js в custom_script.js переподключить? Я всегда думал, что custom_script.js для кнопок.

Нет, не надо ничего переподключать. А custom_script.js
для кнопок, и для всех остальных задач, которым он больше подходит.


solombala пишет

это только для мульти? Тогда автоочистка не работает...

Нет, не только. Я проверял, даже специальный код запускал, который жрёт память.
Как только поднимается выше прописанного лимита — выскакивает окно,
что мол start.vbs не найден. Не знаю чего там у тебя не работает.

Отсутствует

 

№1523406-03-2021 15:49:34

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

d

Отредактировано solombala (07-03-2021 09:45:52)

Отсутствует

 

№1523506-03-2021 18:13:29

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 86.0

Re: Custom Buttons

А как бы ещё Developer Tools подключить?

Отсутствует

 

№1523606-03-2021 19:56:26

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 570
UA: Firefox 86.0

Re: Custom Buttons

_zt

В custom_script_all_win.js скрипт у меня подключен через лоадер.

Что-то у меня это не работает. Сохранил ваш код как s_MemoryMinimizationButton.uc.js , положил в папку custom_scripts
Создал файл  custom_script_all_win.js с кодом по вашей ссылки. Вместо  loadscript("SidebarModoki.uc.js", win);
вставил loadscript("s_MemoryMinimizationButton.uc.js", win);   и кнопка нигде не появляется.

скрытый текст

Выделить код

Код:

(() => {
            var loadscript = (name, win) => {
                try {
                    Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${name}`, win, "UTF-8");
                    return true;
                } catch(e) {
                    if (!window.Services) {
                        try {
                            ChromeUtils.import("resource://gre/modules/Services.jsm", window);
                            Services.scriptloader.loadSubScript(`chrome://user_chrome_files/content/custom_scripts/${name}`, win, "UTF-8");
                            return true;
                        } catch(e) {}
                    }
                }
                return false;
            },
            load_scripts_by_url = {
                "chrome://browser/content/browser.xhtml": (win) => {
                    if (win != window) return;
                    var box = document.querySelector("#browser") || window;
                    var listener = e => {
                        var doc = e.target || ({});
                        load_scripts_by_url[doc.documentURI]?.(doc.defaultView);
                    };
                    box.addEventListener("pageshow", listener);
                    this.loadscriptsallwinorsidebar = {
                        destructor: function() {
                            box.removeEventListener("pageshow", listener);
                        }
                    };
                    this.unloadlisteners.push("loadscriptsallwinorsidebar");
                    setTimeout(() => {
                    //>>>>>>>>>>| Загрузка скриптов для browser.xhtml |>>>>>>>>>>
                        loadscript("ucf_wheretoopenlink.js", win) && win.ucf_where_to_open_link.browser();
                        //loadscript("ucjsDownloadsManager.uc.js", win);
                        loadscript("s_MemoryMinimizationButton.uc.js", win);

                    //<<<<<<<<<<| Загрузка скриптов для browser.xhtml |<<<<<<<<<<
                    }, 0);
                },
                //>>>>>>>>>>| Загрузка скриптов для др. документов |>>>>>>>>>>
                "chrome://browser/content/places/places.xhtml": (win) => {
                    loadscript("ucf_wheretoopenlink.js", win) && win.ucf_where_to_open_link.places();

                },
                "chrome://browser/content/downloads/contentAreaDownloadsView.xhtml": (win) => {
                    //loadscript("ucjsDownloadsManager2.uc.js", win);

                },
                "about:downloads": (win) => {
                    //loadscript("ucjsDownloadsManager2.uc.js", win);

                },
                "chrome://browser/content/places/bookmarksSidebar.xhtml": (win) => {
                    loadscript("ucf_wheretoopenlink.js", win) && win.ucf_where_to_open_link.bookmarksSidebar();

                },
                "chrome://browser/content/places/historySidebar.xhtml": (win) => {
                    loadscript("ucf_wheretoopenlink.js", win) && win.ucf_where_to_open_link.historySidebar();

                },
                //<<<<<<<<<<| Загрузка скриптов для др. документов |<<<<<<<<<<
            };
            load_scripts_by_url[location.href]?.(window);
        })();

Отсутствует

 

№1523707-03-2021 09:36:50

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1644
UA: Firefox 78.0

Re: Custom Buttons

rubel
Что значит "Создал файл  custom_script_all_win.js"? Его не надо создавать, он должен быть изначально, это часть UCF.

Отсутствует

 

№1523807-03-2021 09:54:43

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

Кто сможет.Видео в potplayer. Под мультирежим..

скрытый текст

Выделить код

Код:

/*Initialization Code*/



var path = 'D:\\PotPlayer\\PotPlayerMini64.exe'

var sysPlayerName = "PotPlayer";

var openIn = "Открыть в "+sysPlayerName;
var videoMoved = "Видео перенесено в "+sysPlayerName;
var noFound = "Не найдено видео на странице, доступное для переноса в "+sysPlayerName;

var YoutubeID = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\W|$)/;



if(!(cbu.getPrefs("CB.KMP")) || cbu.getPrefs("CB.KMP").length < 9) cbu.setPrefs("CB.KMP", "videotoplayer");
var tmp = '',
tmpp = '',
innerA = '<div style="display:block!important;color:#00ff00!important;width:250px!important;font:bold 16px serif!important;z-index:999!important;opacity:1!important;visibility: visible!important;',
innerB = 'left:5px!important;position:absolute!important;height:auto!important;box-sizing:border-box!important;padding:5px!important;margin:5px!important;',
stopPl = "javascript:(function(){v=document.getElementById('movie_player');if(v){v.stopVideo()}else{v=document.getElementsByTagName('video');if(v){v[0].src='';try{v[0].load()}catch(e){}};}})();",
ytIMGouter = function(ytID) {return '<div width="100%"><br /><a target="_blank" href="https://www.youtube.com/watch?v=' + ytID + '"><img src="https://i.ytimg.com/vi/' + ytID + '/hqdefault.jpg"></a><br />' + innerA + 'background-color:black!important;position:relative!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div><br /></div><br />'},
handlWin = function(currentWin) {
tmp = '';
var elem = currentWin.document.getElementsByTagName('video'), currLoc = currentWin.location;
if(elem.length > 0) {
if(currLoc.hostname.indexOf('youtu') != -1 && (tmp = currLoc.toString().match(YoutubeID)) && tmp[1].length == 11) {
play(cbu.getPrefs("CB.KMP") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
videoMovedbox = currentWin.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';
loadURI(stopPl);
currentWin.document.getElementById('eow-title').appendChild(videoMovedbox);
return true;
};
for(i = 0; i < elem.length; i++) {
if(((tmp = getSrc(elem[i].parentNode, currLoc)) && tmp.length > 2) || (i == 0 && currentWin.document.body.innerHTML.substring(0, 7) == '<video ' && (tmp = currLoc.toString()))) {
videoMovedbox = currentWin.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:20px!important;background-color:black!important;">' + videoMoved + '</div>';
play(tmp);                
if(currLoc.hostname == 'www.youtube.com') {
elem[i].parentNode.parentNode.appendChild(videoMovedbox);
} else {
elem[i].parentNode.appendChild(videoMovedbox);
};
elem[i].src = '';
try {
elem[i].load()
} catch(e) {};
return true;
}
}
};

currentWin._elems = currentWin.document.getElementsByTagName('iframe');
if(currentWin._elems.length > 0) {
for(currentWin._iCounter = 0; currentWin._iCounter < currentWin._elems.length; currentWin._iCounter++) {
if((currentWin._elems[currentWin._iCounter].src.indexOf('youtube.com') > -1) && (tmp = currentWin._elems[currentWin._iCounter].src.match(YoutubeID)) && (tmp[1].length == 11)) {
play(cbu.getPrefs("CB.KMP") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
currentWin._elems[currentWin._iCounter].outerHTML = ytIMGouter(tmp[1]);
return true;
};
if(currentWin._elems[currentWin._iCounter].clientWidth > 80 && currentWin._elems[currentWin._iCounter].clientHeight > 40 && handlWin(currentWin._elems[currentWin._iCounter].contentWindow))return true;
}
};

elem = currentWin.document.getElementsByTagName('object');
currLoc = currentWin.location;
if(elem.length == 0) {
elem = currentWin.document.getElementsByTagName('embed')
};
if(elem.length > 0) {
for(i = 0; i < elem.length; i++) {
if(elem[i].innerHTML.indexOf('youtu') != -1 && (tmp = elem[i].innerHTML.match(YoutubeID)) && tmp[1].length == 11) {
play(cbu.getPrefs("CB.KMP") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
elem[i].outerHTML = ytIMGouter(tmp[1]);
return true;
} else {
if(elem[i].clientWidth > 80 && elem[i].clientHeight > 40) {
if(((tmp = getSrc(elem[i].parentNode, currLoc)) || (tmp = getLink(elem[i], currLoc))) && tmp.length > 2) {
play(tmp);
elem[i].outerHTML = innerA + 'background-color:black!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div>';
return true;
};
};
}
};
};
return false;
};

this.onclick = this.oncontextmenu = e => {
if (e.target != this) return;
if(e.button == 0) {
if(cbu.getPrefs("CB.KMP").substring(0,6) == "videom"){
elem = content.document.getElementsByTagName('object');
if(elem.length == 0) {
elem = content.document.getElementsByTagName('embed')
};

resizeObjs(elem);
resizeObjs(content.document.getElementsByTagName('iframe'));
resizeObjs(content.document.getElementsByTagName('video'));
} else {
if(!handlWin(content))custombuttons.alertSlide1(noFound);
}
};
if ( e.button == 2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey ) { // ПКМ
e.preventDefault();
if (custombuttons.confirmBox(null, "Запустить плеер из буфера обмена ?", "Да", "Нет") ) {
var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
file.initWithPath('D:\\PotPlayer\\PotPlayerMini64.exe');
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
var link = gClipboard.read();
var args = [link,"/play"];
process.init( file );
process.run( false, args, args.length );
}
};
}
this.oncontextmenu = e => e.target != this ? menu.hasAttribute("context")
    : e.ctrlKey || e.shiftKey || e.altKey || e.metaKey || (
        e.detail != 1 ? menu.hidePopup() : !!menu.openPopup(this, "after_start")
    );
custombuttons.alertSlide1 = function(sTitle) {
var as = Components.classes["@mozilla.org/alerts-service;1"].getService(Components.interfaces.nsIAlertsService);
as.showAlertNotification('chrome://global/skin/icons/information-16.png', "", sTitle, false, "", null);
setTimeout(() => as.closeAlert(), 999);
};
this.tooltipText="Л: Видео в плеер\nП: Видео из Clipboard";
function resizeObjs(objs) {
if(!objs) return;
LEVELS = 3;
dir = (cbu.getPrefs("CB.KMP") == "videomaximize") ? 1 : -1;
for(i = 0; i < objs.length; i++) {
var Width = new Array(LEVELS)
var Height = new Array(LEVELS)
Width[0] = objs[i].clientWidth;
Height[0] = objs[i].clientHeight;
if((Width[0] > (-20 * dir + 100)) && (Height[0] > (-20 * dir + 60))) {
obj = objs[i];
for(var k = 1;
((k < LEVELS) && (obj.parentNode)); k++) {
obj = obj.parentNode
Width[k] = obj.clientWidth;
Height[k] = obj.clientHeight;
};
Width[0] = Width[0] + dir * (Width[0] / 5 | 0);
Height[0] = Height[0] + dir * (Height[0] / 5 | 0);
objs[i].style.width = Width[0] + "px";
objs[i].width = Width[0];
objs[i].style.height = Height[0] + "px";
objs[i].height = Height[0];
obj = objs[i];
for(var k = 1;
((k < LEVELS) && !(objs[i].tagName == 'IFRAME') && (obj.parentNode) && (Width[k]) && (Height[k]) && (Width[k] > (-20 * dir + 100)) && (Height[k] > (-20 * dir + 60))); k++) {
obj = obj.parentNode
Width[k] = Width[k] + dir * (Width[k] / 5 | 0);
Height[k] = Height[k] + dir * (Height[k] / 5 | 0);
obj.style.width = Width[k] + "px";
obj.width = Width[k];
obj.style.height = Height[k] + "px";
obj.height = Height[k];
}
}
};
};

function restProtHost(lnkR, curLoc) {
if(lnkR.length==0)return '';
let tr = lnkR.replace(/^:\/\//, curLoc.protocol + "//");
if(!tr.match(/^https?:\/\//i)){
lnkR = tr.replace(/^\/+/, '');
if(lnkR.split('/')[0].split('?')[0].split('#')[0].toLowerCase().match(/^(?:[-a-z\d]+\.)+[a-z\d]{2,6}$/)){
tr = curLoc.protocol + '//' + lnkR;
}else{
tr = curLoc.protocol + '//' + curLoc.host + "/" + lnkR;
}
};
return tr;
};

function getSrc(vobj, currentLoc) {
var t = '',
tt = '';
if((((t = vobj.innerHTML.match(/<video.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i)) && (t) && (tt = t[1] || t[2] || t[3]) && tt.indexOf('blob:') == -1 ) || ((t = vobj.innerHTML.match(/<source.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*)).*?\stype=['"]?video\//i)) && (t) && (tt = t[1] || t[2] || t[3]))) && tt.length > 2 && tt.indexOf('blob:') == -1 ) {
if(tt.indexOf(".mp4/?") == -1) {
tt = tt.replace(/&amp;/g, "&")
};
t = restProtHost(tt, currentLoc);
return t;
};
return '';
};

function getLink(obj, curLocation) {


if(!obj || !obj.tagName) return '';
var flashvars = '',
//        src = '',
q = obj.tagName.toLowerCase();

var getParam = function(e, n) {
var v = '',
r = new RegExp('^(' + n + ')$', 'i'),
param = e.getElementsByTagName('param');
for(var igp = 0, p; p = param[igp]; igp++) {
if(p.hasAttribute('name') && p.getAttribute('name').match(r)) {
v = p.getAttribute('value');
break
};
};
return v;
};


if(q == 'object') {
//        src = obj.getAttribute('data') || obj.getAttribute('src') || getParam(obj, 'movie|data|src|code|filename|url') || (obj.getElementsByTagName('embed').length > 0 ? obj.getElementsByTagName('embed')[0].getAttribute('src') : '');
flashvars = getParam(obj, 'flashvars');
} else if(q == 'embed') {
//        src = obj.getAttribute('src');
flashvars = obj.getAttribute('flashvars');
} else return '';


if(!flashvars) return '';
//   src = restProtHost(src, curLocation);

var restPath = function(f, s) {
return(f.substring(0, 4) == 'http') ? f : s.replace(/[#?].*$/, '').replace(/[^\/]*$/, f)
};

function videoLinkExtract(fl) {
//alert(fl);
var linkArr = [],
outLinks = [],
jj = 0,
lba = '',
lbb = '',
decodeURL = gBrowser.currentURI.spec; {
try {
return decodeURIComponent(s)
} catch(e) {
return unescape(s)
}
};

for(var ij = 0; ij < 3; ij++) {
lba = lba + String.fromCharCode(parseInt((Math.random() * 15 + 1) + '', 10));
lbb = lbb + String.fromCharCode(parseInt((Math.random() * 15 + 16) + '', 10));
};

function pushWithMerit(lnk) {

var merit = -11;
if(lnk.match(/^https?:\/\//i)) merit = merit + 40;
if(outLinks.length == 0) merit = merit + 1;
if(lnk.match(/^\//)) merit = merit + 7;
if(lnk.match(/^\/\//)) merit = merit + 30;
if(lnk.match(/240p([^a-z]|$)/i)) merit = merit + 1;
if(lnk.match(/[^a-z]240([^a-z0-9]|$)/i)) merit = merit + 1;
if(lnk.match(/360p([^a-z]|$)/i)) merit = merit + 3;
if(lnk.match(/[^a-z]360([^a-z0-9]|$)/i)) merit = merit + 3;
if(lnk.match(/480p([^a-z]|$)/i)) merit = merit + 5;
if(lnk.match(/[^a-z]480([^a-z0-9]|$)/i)) merit = merit + 5;
if(lnk.match(/720p([^a-z]|$)/i)) merit = merit + 7;
if(lnk.match(/[^a-z]720([^a-z0-9]|$)/i)) merit = merit + 7;
if(lnk.match(/\.mp4([^a-z]|$)/i)) merit = merit + 8;
if(lnk.match(/_hd([^a-z]|$)/i)) merit = merit + 6;
if(lnk.match(/\.(jpg|xml)([^a-z]|$)/i)) merit = merit - 40;
if(merit > 0) outLinks.push(merit + lba + lnk);
Services.console.logStringMessage('merit:'+merit+' lnk->'+lnk);
};

linkArr.push(fl);
while(linkArr.length > jj && jj < 30) {

var testPaths = [];
testPaths = linkArr[jj].split(/(\.(?:flv|mp4|m3u8))/i);
if(testPaths[testPaths.length - 1] == '') testPaths.pop();

for(k = 1; k < testPaths.length; k = k + 2) {

if(testPaths[k - 1].indexOf(lba) > -1) {
pref = testPaths[k - 1];
} else {
var testAboutDom = testPaths[k - 1].toLowerCase().split(/(https?:\/\/)/); 
if(testAboutDom[testAboutDom.length - 1]=='') testAboutDom.pop();
var pTest = testAboutDom[testAboutDom.length - 1].split(/(\?[^\?]*?&)/);
if(pTest.length>2){
pTest.pop();
pTest.pop();
};
testAboutDom[testAboutDom.length - 1] = pTest.join('');
pref = testPaths[k - 1].substring(testAboutDom.join('').lastIndexOf("&") + 1);
};

t2 = pref.lastIndexOf(lbb);
if(t2 > -1) {
pref = pref.substring(t2 + 3);
} else {

t2 = pref.lastIndexOf('{"');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.lastIndexOf('["');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.lastIndexOf(',"');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.toLowerCase().lastIndexOf('"http://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf('"https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(',http://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(',https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(';http');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf('*https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(' or ');
if(t2 > -1) pref = pref.substring(t2 + 4);

pref = pref.substring(pref.split('/')[0].toLowerCase().split('%2f')[0].lastIndexOf('=') + 1);

}

if(pref.length > 0) {

if(pref.split('?')[0].toLowerCase().match(/%[2-3][0-9a-f]/)) {

t2 = pref.indexOf('"')
if(t2 > -1) pref = pref.substring(t2 + 1);
suff = testPaths[k + 1] ? testPaths[k + 1].split('&')[0].split('"')[0].split(';')[0].split(/,http/i)[0] : '';
if((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
if(testPaths.length > k + 1) {
testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
};
t2 = pref.lastIndexOf(lba);
if(t2 > -1) pref = pref.substring(t2 + 3)
linkArr.push(decodeURL(pref + testPaths[k] + suff));

} else {
testPaths[k + 1] = (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
}
} else {
suff = testPaths[k + 1] ? testPaths[k + 1].split(';')[0].split('"]')[0].split('"}')[0].split('",')[0].split(/,https?:\/\//i)[0].split('*https://')[0].split(' or ')[0] : '';
t2 = suff.indexOf('&');
if((t2 > -1) && (pref != testPaths[k - 1])) {
if(t2 == 0) suff = '';
if(suff.charAt(0) != '?') suff = suff.split(/(&[^&]+=https?:\/\/)/i)[0];
};
if((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
if(testPaths.length > k + 1) {
testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
};
t2 = pref.lastIndexOf(lba);
if(t2 > -1) pref = pref.substring(t2 + 3);
pushWithMerit(pref + testPaths[k] + suff);

} else {
testPaths[k + 1] = lba + (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
}
}
}
};
jj = jj + 1;
};

if(outLinks.length == 0) return '';
function srt(a, b) {
a = parseInt(a.substr(0, a.indexOf(lba)), 10);
b = parseInt(b.substr(0, b.indexOf(lba)), 10);
if(a < b) return 1;
if(a > b) return -1;
return 0
};
outLinks.sort(srt);
outLinks[0] = outLinks[0].substr(outLinks[0].indexOf(lba) + 3)
if(outLinks[0].indexOf('_hq.mp4/?time=') > 0) outLinks[0] = outLinks[0].replace(/&/g, '&amp;');
return outLinks[0];
};
ol = videoLinkExtract(flashvars);
if(!ol) return '';
//    ol = ol.replace(/^:?\/\//, curLocation.protocol + "//");
//    return restPath(ol, src);
return restProtHost(ol, curLocation);
};

var menu = self.appendChild(document.createXULElement("menupopup"));
self.image = "moz-icon://file://" + path;
var playerName = path.split("\\").pop().replace(".exe","");
setTimeout(() => {
Menu_n_TooltipTxts.forEach((m) => {
if("separator" in m) {
menu.appendChild(document.createXULElement("menuseparator"));
return
};
var mItem = document.createXULElement("menuitem");
mItem.setAttribute("label", m.label);

if("radio" in m) {
mItem.setAttribute("type", "radio");
mItem.setAttribute('checked', cbu.getPrefs("CB.KMP") == m.value);
if(cbu.getPrefs("CB.KMP") == m.value) {
self.tooltipText = m.tooltipTxt;
}
mItem.onclick = () => {
cbu.setPrefs("CB.KMP", m.value);
tmp = (self.image == imgFlashToPlayer || self.image == imgFlashMinimize ||  self.image == imgFlashMaximize);
if(m.value.substring(0,9)=='videotopl'){
self.image = tmp ? imgFlashToPlayer : imgHTML5ToPlayer;
} else if(m.value=='videominimize') {
self.image = tmp ? imgFlashMinimize : imgHTML5Minimize;
} else self.image = tmp ? imgFlashMaximize : imgHTML5Maximize;
self.tooltipText = m.tooltipTxt;
};
}
if("checkbox" in m) {
mItem.setAttribute('type', 'checkbox');
mItem.setAttribute('checked', (self.image == imgFlashToPlayer || self.image == imgFlashMinimize ||  self.image == imgFlashMaximize ));
mItem.onclick = function(e) {
e.stopPropagation();
e.preventDefault();
if(e.button == 0) toggleFlash();
}
}
menu.appendChild(mItem);
});
menu.onclick = function(e) {
e.stopPropagation();
if(e.button > 0) e.preventDefault();
};
}, 100);

var contextMenu = document.getElementById("contentAreaContextMenu");
var menuitem = contextMenu.insertBefore(document.createXULElement("menuitem"), document.getElementById("context-savelink"));
menuitem.setAttribute("label", "Открыть в " +sysPlayerName);      
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image", "moz-icon://file://" + path); 
menuitem.onclick = () => play(gContextMenu.linkURL || gContextMenu.mediaURL);
addEventListener("popupshowing", ()=> menuitem.hidden = !gContextMenu.onLink && !gContextMenu.onVideo && !gContextMenu.onPlainTextLink, false, contextMenu);
addDestructor(()=> menuitem.remove() );

onclick = () => {
e.preventDefault();
var vurl = gContextMenu.mediaURL, videoelem = gContextMenu.target;
if(videoelem && videoelem.nodeName.toLowerCase() == 'video') {
if(content.location.hostname.indexOf('youtu') != -1 && (tmp = content.location.toString().match(YoutubeID)) && tmp[1].length == 11) {
play(vurl);
videoMovedbox = content.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';
loadURI(stopPl);
content.document.getElementById('eow-title').appendChild(videoMovedbox);
return;
};

if(content.location.hostname == 'www.youtube.com') {
videoelem.parentNode.parentNode.appendChild(videoMovedbox);
} else {
var inFrameHref = inFrameWin.location.href, found = false;
if(inFrameWin.location.hostname == 'www.youtube.com' && (tmp = inFrameHref.match(YoutubeID)) && tmp[1].length == 11){//и значит во фрейме
elem = inFrameWin.parent.document.getElementsByTagName('iframe');
if(elem.length > 0) {
for(i = 0; i < elem.length; i++) {
if(elem[i].contentWindow == inFrameWin) {
elem[i].outerHTML = ytIMGouter(tmp[1]);
found = true;
break;
};
};
};
if(!found)inFrameWin.document.body.innerHTML = ytIMGouter(tmp[1]);
return;
};
videoelem.parentNode.appendChild(videoMovedbox);
};
videoelem.src = '';
try {
videoelem.load()
} catch(e) {};
} else play(vurl);
};


addEventListener("popupshowing", () => {
mItem.hidden = !gContextMenu.onVideo || !gContextMenu.mediaURL;
mItem2.hidden = !gContextMenu.linkURL;
mItem3.hidden = framItem.hidden || gContextMenu.target.ownerDocument.location.hostname.indexOf('youtube.com') == -1;
}, false, contextMenu);
addDestructor(() => {mItem.remove();mItem2.remove();mItem3.remove()});


function play(link) {
if (custombuttons.confirmBox(null, "Открыть  ссылку  в плеере ?", "Да", "Отмена") ) {
var file = Services.dirsvc.get('CurProcD', Ci.nsIFile);
var MozExeDir = file.path.split('\\').slice(0,-1).join('\\');
file.initWithPath(path);
if(!file.exists()) {
custombuttons.alertBox("File not found!", MozExeDir + Path);
return;
};
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
var args = [link];
process.init( file );
process.run( false, args, args.length );
};

}

Отсутствует

 

№1523907-03-2021 10:12:52

_zt
Участник
 
Группа: Members
Зарегистрирован: 10-11-2014
Сообщений: 1644
UA: Firefox 78.0

Re: Custom Buttons

solombala
Есть в два раза меньший код, выполняющий в десять раз больше.
https://forum.mozilla-russia.org/viewto … 54#p782454

Отсутствует

 

№1524007-03-2021 11:11:55

rubel
Участник
 
Группа: Members
Откуда: г.Самара
Зарегистрирован: 10-05-2005
Сообщений: 570
UA: Firefox 86.0

Re: Custom Buttons

solombala

Короче, автоочистка и принудиловка нужна, и можно от кнопки избавляться...

Ну да, после правки кода от Dumby и применения твоей приблуды-Папку memreduk - в профиль. :D
Больше и ничего не нужно, спасибо вам,  Dumbysolombala. :beer:

Отсутствует

 

№1524107-03-2021 14:30:55

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

Dumby
https://forum.mozilla-russia.org/viewto … 05#p789105
Что там не так? меняю currentWindow.document на  currentWindowGlobal.documentURI.spec - и не фига...

Отсутствует

 

№1524207-03-2021 16:24:00

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

voqabuhe пишет

А как бы ещё Developer Tools подключить?

:/

скрытый текст

Выделить код

Код:

try {CustomizableUI.createWidget({
	id: "ucf-cbbtn-extDevTools",
	label: "Extensions Developer Tools",
	localized: false,
	get initCode() {
		delete this.initCode;
		return this.initCode = Cu.readUTF8URI(Services.io.newURI(
			"chrome://user_chrome_files/content/custom_scripts/extDevTools.js"
		));
	},
	dp: win => class extends win.DOMParser {constructor() {
		super();
		this.forceEnableXULXBL();
		this.parseFromString = this.parseFromSafeString;
	}},
	LOG(msg) {
		var str = `[ucf: id: ucf-cbbtn-extDevTools@init, line: ${
			Components.stack.caller.lineNumber
		}, name: Extensions Developer Tools]${
			arguments.length ? "\n" + msg : ""
		}`;
		Services.console.logStringMessage(str);
		return msg;
	},
	async onCreated(btn) {
		btn.tooltipText = this.label;
		btn.setAttribute("image", "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAMAAAAoLQ9TAAACOlBMVEX///+Tn54AAAAAAACGk5KDkI+DkI+WoaCDkI9/jY6HkpCJlpWDkI+KlpWMmJeDkI+Gk5KKl5aDkI+QnZyDkI+DkI+FkpGDkI+Hk5KQnZyGk5KGlJJ3hoeSnZ2QnJuHk5OKl5aKl5aRnJx/jYuFkpGFkpGGkpKPnJuXoqGCj4+HlJObp6aeqqmPnJuCj46fqqmEkI+PnJuXo6KIlJSHk5OHk5OvubieqaixubivtreBj46uuLeLl5bAxMe+wsOvubd8iYh+i4p/joyutLV7iId6h4Z9iol1hISrtLSttbR5h4Z5hoV5hYR6hoV4hYSFkpGDkZB6h4Z9iYh+ioq5wcOmsK6ttrSuuLd2goF1goGutrW7wMB4hoR0goG/xcbk5uelrq2nsbCEkpEAAABha2p4hIN4hYRjb2wAAACyvLy/yMe6w8J7iIeos7K2wL+9xsWksK+frKuptLOps7Kfq6ujr67p+viksLCrtrXAyMijsK/BycmlsbCos7OXo6KXoqGyvLq2v76IlJOMmJikr67AyMe/x8aMmZeksbCCj42VoJ+qtrWxv72vube7xcSeq6mMmZihrayirq2hrq2grKyNmZigrKuxu7mEkpDX5eO8xcW2v7+zv77X5OO3wL/Aycecqairt7Wyvbumsa+JlpW+x8ewu7qzvbx+ioqirayJlZSksK6uubmdqqmbqKeuuriWoqGirKu9xcWns7Kuurmvubilsa+ZpaSapqV8jIq8xsXDy8m4wcCqtbWVSIW1AAAAaXRSTlMA+iwg+iID9wIXLf4yxEHc3P0U/AUK9yTu6vT6CzX9+BQ97v70ZtLwFW3zBSr5BxD8+P736/sQEAAA2/j8AAAALf09AFX69V4AAF39+q398szv/WUAAAAAFAkAAAsZAAAAAPZEoPP0pjkqla07AAABCElEQVR4Xh3Ag1YEAQAF0LfItm3btm0bg7Wzbdu23b81pwuGsSb0+kc0oK6FfxZcS11rufxE38DGDgw17uaskaT7WzIcs3ulDcBN51S1T5KqUZIcG/cCw/DxSfA197MlEFyaADA1M9+jKHGQFWuAGhzytEWB/Qyfv+7gCCcWf3vH2QWuBEEcHbsD8Dg7J4gLNL9f39yLvX3g6/fy+vbxCf+AwF/lYXBIaNiUcnojPAKRUdEPzzxel6inl9cXGxePhMQkmUKoEDImZJPJQEpqmnR+YXFpeWVVtJaeAWRmZefk5uUfSOnCouKSUqCsvKKyqpq+vaNrauvqATQ0NnHYLa1t7R2dbA6AP+T9Uy9FYhsYAAAAAElFTkSuQmCC");
		var win = btn.ownerGlobal;
		await new Promise(win.requestAnimationFrame);
		win.addEventListener("unload", this, {once: true});
		new win.Function("DOMParser,LOG", this.initCode)
			.call(btn, this.dp(win), this.LOG);
	},
	handleEvent(e) {
		var btn = e.target.getElementById(this.id);
		btn.onDestroy?.call(btn);
	}
});} catch(ex) {Cu.reportError(ex);}

solombala пишет

Что там не так?

Ну помилосердствуй! :cry:
Сколько раз писал, что здесь ничем помочь не могу.
Вообще никогда видос в браузере не видел,
ну, может, за исключением прямой ссылки на .mp4-файл.

меняю currentWindow.document

Подсчёт: 0 совпадений.

на  currentWindowGlobal.documentURI.spec

currentWindowGlobal — это свойство CanonicalBrowsingContext
(сам интерфейс упоминается здесь).

Отредактировано Dumby (07-03-2021 16:36:06)

Отсутствует

 

№1524307-03-2021 20:19:41

solombala
Забанен
 
Группа: Members
Зарегистрирован: 20-07-2019
Сообщений: 652
UA: Firefox 86.0

Re: Custom Buttons

Dumby
Не понял. Я столько перелопатил ,чтобы на мульти перейти. Теперь из-за этой кнопки все в топку... Если не вы, то кто? Даю новый облегченный вариант.Где поганка?

скрытый текст

Выделить код

Код:

/*Initialization Code*/

  var path = 'D:\\gomplayer\\gom.exe'

 var sysPlayerName = "GOM Player";

 var openIn = "Откыть в "+sysPlayerName;
 var videoMoved = "Видео перенесено в "+sysPlayerName;
 var noFound = "Не найдено видео на странице, доступное для переноса в "+sysPlayerName;

var YoutubeID = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\W|$)/;



if(!(cbu.getPrefs("CB.video")) || cbu.getPrefs("CB.video").length < 9) cbu.setPrefs("CB.video", "videotoplayer");
var tmp = '',
tmpp = '',
innerA = '<div style="display:block!important;color:#00ff00!important;width:250px!important;font:bold 16px serif!important;z-index:999!important;opacity:1!important;visibility: visible!important;',
innerB = 'left:5px!important;position:absolute!important;height:auto!important;box-sizing:border-box!important;padding:5px!important;margin:5px!important;',
stopPl = "javascript:(function(){v=document.getElementById('movie_player');if(v){v.stopVideo()}else{v=document.getElementsByTagName('video');if(v){v[0].src='';try{v[0].load()}catch(e){}};}})();",
ytIMGouter = function(ytID) {return '<div width="100%"><br /><a target="_blank" href="https://www.youtube.com/watch?v=' + ytID + '"><img src="https://i.ytimg.com/vi/' + ytID + '/hqdefault.jpg"></a><br />' + innerA + 'background-color:black!important;position:relative!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div><br /></div><br />'},
handlWin = function(currentWin) {
tmp = '';
var elem = currentWin.document.getElementsByTagName('video'), currLoc = currentWin.location;
if(elem.length > 0) {
if(currLoc.hostname.indexOf('youtu') != -1 && (tmp = currLoc.toString().match(YoutubeID)) && tmp[1].length == 11) {
play(cbu.getPrefs("CB.video") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
videoMovedbox = currentWin.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';
loadURI(stopPl);
currentWin.document.getElementById('eow-title').appendChild(videoMovedbox);
return true;
};
for(i = 0; i < elem.length; i++) {
if(((tmp = getSrc(elem[i].parentNode, currLoc)) && tmp.length > 2) || (i == 0 && currentWin.document.body.innerHTML.substring(0, 7) == '<video ' && (tmp = currLoc.toString()))) {
videoMovedbox = currentWin.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:20px!important;background-color:black!important;">' + videoMoved + '</div>';
play(tmp);                
if(currLoc.hostname == 'www.youtube.com') {
elem[i].parentNode.parentNode.appendChild(videoMovedbox);
} else {
elem[i].parentNode.appendChild(videoMovedbox);
};
elem[i].src = '';
try {
elem[i].load()
} catch(e) {};
return true;
}
}
};

currentWin._elems = currentWin.document.getElementsByTagName('iframe');
if(currentWin._elems.length > 0) {
for(currentWin._iCounter = 0; currentWin._iCounter < currentWin._elems.length; currentWin._iCounter++) {
if((currentWin._elems[currentWin._iCounter].src.indexOf('youtube.com') > -1) && (tmp = currentWin._elems[currentWin._iCounter].src.match(YoutubeID)) && (tmp[1].length == 11)) {
play(cbu.getPrefs("CB.video") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
currentWin._elems[currentWin._iCounter].outerHTML = ytIMGouter(tmp[1]);
return true;
};
if(currentWin._elems[currentWin._iCounter].clientWidth > 80 && currentWin._elems[currentWin._iCounter].clientHeight > 40 && handlWin(currentWin._elems[currentWin._iCounter].contentWindow))return true;
}
};

elem = currentWin.document.getElementsByTagName('object');
currLoc = currentWin.location;
if(elem.length == 0) {
elem = currentWin.document.getElementsByTagName('embed')
};
if(elem.length > 0) {
for(i = 0; i < elem.length; i++) {
if(elem[i].innerHTML.indexOf('youtu') != -1 && (tmp = elem[i].innerHTML.match(YoutubeID)) && tmp[1].length == 11) {
play(cbu.getPrefs("CB.video") == "videotoplaylist" ? 'https://www.youtube.com/embed/' + tmp[1] : 'https://www.youtube.com/watch?v=' + tmp[1]);
elem[i].outerHTML = ytIMGouter(tmp[1]);
return true;
} else {
if(elem[i].clientWidth > 80 && elem[i].clientHeight > 40) {
if(((tmp = getSrc(elem[i].parentNode, currLoc)) || (tmp = getLink(elem[i], currLoc))) && tmp.length > 2) {
play(tmp);
elem[i].outerHTML = innerA + 'background-color:black!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div>';
return true;
};
};
}
};
};
return false;
};

this.onclick = this.oncontextmenu = e => {
if (e.target != this) return;
if(e.button == 0) {
if(cbu.getPrefs("CB.video").substring(0,6) == "videom"){
elem = content.document.getElementsByTagName('object');
if(elem.length == 0) {
elem = content.document.getElementsByTagName('embed')
};

resizeObjs(elem);
resizeObjs(content.document.getElementsByTagName('iframe'));
resizeObjs(content.document.getElementsByTagName('video'));
} else {
if(!handlWin(content))custombuttons.alertSlide1(noFound);
}
};

if ( e.button == 2 && !e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey ) { // ПКМ
e.preventDefault();
if (custombuttons.confirmBox(null, "Запустить плеер из буфера обмена ?", "Да", "Нет") ) {
var file = Cc['@mozilla.org/file/local;1'].createInstance(Ci.nsIFile);
file.initWithPath('D:\\GOMPlayer\\GOM.exe');
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
var link = gClipboard.read();
var args = [link,"/play"];
process.init( file );
process.run( false, args, args.length );

}
};
}
function restProtHost(lnkR, curLoc) {
if(lnkR.length==0)return '';
let tr = lnkR.replace(/^:\/\//, curLoc.protocol + "//");
if(!tr.match(/^https?:\/\//i)){
lnkR = tr.replace(/^\/+/, '');
if(lnkR.split('/')[0].split('?')[0].split('#')[0].toLowerCase().match(/^(?:[-a-z\d]+\.)+[a-z\d]{2,6}$/)){
tr = curLoc.protocol + '//' + lnkR;
}else{
tr = curLoc.protocol + '//' + curLoc.host + "/" + lnkR;
}
};
return tr;
};

function getSrc(vobj, currentLoc) {
var t = '',
tt = '';
if((((t = vobj.innerHTML.match(/<video.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i)) && (t) && (tt = t[1] || t[2] || t[3]) && tt.indexOf('blob:') == -1 ) || ((t = vobj.innerHTML.match(/<source.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*)).*?\stype=['"]?video\//i)) && (t) && (tt = t[1] || t[2] || t[3]))) && tt.length > 2 && tt.indexOf('blob:') == -1 ) {
if(tt.indexOf(".mp4/?") == -1) {
tt = tt.replace(/&amp;/g, "&")
};
t = restProtHost(tt, currentLoc);
return t;
};
return '';
};

function getLink(obj, curLocation) {


if(!obj || !obj.tagName) return '';
q = obj.tagName.toLowerCase();

var getParam = function(e, n) {
var v = '',
r = new RegExp('^(' + n + ')$', 'i'),
param = e.getElementsByTagName('param');
for(var igp = 0, p; p = param[igp]; igp++) {
if(p.hasAttribute('name') && p.getAttribute('name').match(r)) {
v = p.getAttribute('value');
break
};
};
return v;
};




var restPath = function(f, s) {
return(f.substring(0, 4) == 'http') ? f : s.replace(/[#?].*$/, '').replace(/[^\/]*$/, f)
};

function videoLinkExtract(fl) {
alert(fl);
var linkArr = [],
outLinks = [],
jj = 0,
lba = '',
lbb = '',
decodeURL = gBrowser.currentURI.spec; {
try {
return decodeURIComponent(s)
} catch(e) {
return unescape(s)
}
};

for(var ij = 0; ij < 3; ij++) {
lba = lba + String.fromCharCode(parseInt((Math.random() * 15 + 1) + '', 10));
lbb = lbb + String.fromCharCode(parseInt((Math.random() * 15 + 16) + '', 10));
};

function pushWithMerit(lnk) {

var merit = -11;
if(lnk.match(/^https?:\/\//i)) merit = merit + 40;
if(outLinks.length == 0) merit = merit + 1;
if(lnk.match(/^\//)) merit = merit + 7;
if(lnk.match(/^\/\//)) merit = merit + 30;
if(lnk.match(/240p([^a-z]|$)/i)) merit = merit + 1;
if(lnk.match(/[^a-z]240([^a-z0-9]|$)/i)) merit = merit + 1;
if(lnk.match(/360p([^a-z]|$)/i)) merit = merit + 3;
if(lnk.match(/[^a-z]360([^a-z0-9]|$)/i)) merit = merit + 3;
if(lnk.match(/480p([^a-z]|$)/i)) merit = merit + 5;
if(lnk.match(/[^a-z]480([^a-z0-9]|$)/i)) merit = merit + 5;
if(lnk.match(/720p([^a-z]|$)/i)) merit = merit + 7;
if(lnk.match(/[^a-z]720([^a-z0-9]|$)/i)) merit = merit + 7;
if(lnk.match(/\.mp4([^a-z]|$)/i)) merit = merit + 8;
if(lnk.match(/_hd([^a-z]|$)/i)) merit = merit + 6;
if(lnk.match(/\.(jpg|xml)([^a-z]|$)/i)) merit = merit - 40;
if(merit > 0) outLinks.push(merit + lba + lnk);
Services.console.logStringMessage('merit:'+merit+' lnk->'+lnk);
};

linkArr.push(fl);
while(linkArr.length > jj && jj < 30) {

var testPaths = [];
testPaths = linkArr[jj].split(/(\.(?:flv|mp4|m3u8))/i);
if(testPaths[testPaths.length - 1] == '') testPaths.pop();

for(k = 1; k < testPaths.length; k = k + 2) {

if(testPaths[k - 1].indexOf(lba) > -1) {
pref = testPaths[k - 1];
} else {
var testAboutDom = testPaths[k - 1].toLowerCase().split(/(https?:\/\/)/); 
if(testAboutDom[testAboutDom.length - 1]=='') testAboutDom.pop();
var pTest = testAboutDom[testAboutDom.length - 1].split(/(\?[^\?]*?&)/);
if(pTest.length>2){
pTest.pop();
pTest.pop();
};
testAboutDom[testAboutDom.length - 1] = pTest.join('');
pref = testPaths[k - 1].substring(testAboutDom.join('').lastIndexOf("&") + 1);
};

t2 = pref.lastIndexOf(lbb);
if(t2 > -1) {
pref = pref.substring(t2 + 3);
} else {

t2 = pref.lastIndexOf('{"');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.lastIndexOf('["');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.lastIndexOf(',"');
if(t2 > -1) pref = pref.substring(t2 + 2);
t2 = pref.toLowerCase().lastIndexOf('"http://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf('"https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(',http://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(',https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(';http');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf('*https://');
if(t2 > -1) pref = pref.substring(t2 + 1);
t2 = pref.toLowerCase().lastIndexOf(' or ');
if(t2 > -1) pref = pref.substring(t2 + 4);

pref = pref.substring(pref.split('/')[0].toLowerCase().split('%2f')[0].lastIndexOf('=') + 1);

}

if(pref.length > 0) {

if(pref.split('?')[0].toLowerCase().match(/%[2-3][0-9a-f]/)) {

t2 = pref.indexOf('"')
if(t2 > -1) pref = pref.substring(t2 + 1);
suff = testPaths[k + 1] ? testPaths[k + 1].split('&')[0].split('"')[0].split(';')[0].split(/,http/i)[0] : '';
if((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
if(testPaths.length > k + 1) {
testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
};
t2 = pref.lastIndexOf(lba);
if(t2 > -1) pref = pref.substring(t2 + 3)
linkArr.push(decodeURL(pref + testPaths[k] + suff));

} else {
testPaths[k + 1] = (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
}
} else {
suff = testPaths[k + 1] ? testPaths[k + 1].split(';')[0].split('"]')[0].split('"}')[0].split('",')[0].split(/,https?:\/\//i)[0].split('*https://')[0].split(' or ')[0] : '';
t2 = suff.indexOf('&');
if((t2 > -1) && (pref != testPaths[k - 1])) {
if(t2 == 0) suff = '';
if(suff.charAt(0) != '?') suff = suff.split(/(&[^&]+=https?:\/\/)/i)[0];
};
if((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
if(testPaths.length > k + 1) {
testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
};
t2 = pref.lastIndexOf(lba);
if(t2 > -1) pref = pref.substring(t2 + 3);
pushWithMerit(pref + testPaths[k] + suff);

} else {
testPaths[k + 1] = lba + (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
}
}
}
};
jj = jj + 1;
};

if(outLinks.length == 0) return '';
function srt(a, b) {
a = parseInt(a.substr(0, a.indexOf(lba)), 10);
b = parseInt(b.substr(0, b.indexOf(lba)), 10);
if(a < b) return 1;
if(a > b) return -1;
return 0
};
outLinks.sort(srt);
outLinks[0] = outLinks[0].substr(outLinks[0].indexOf(lba) + 3)
if(outLinks[0].indexOf('_hq.mp4/?time=') > 0) outLinks[0] = outLinks[0].replace(/&/g, '&amp;');
return outLinks[0];
};

if(!ol) return '';
   ol = ol.replace(/^:?\/\//, curLocation.protocol + "//");
    return restPath(ol, src);
return restProtHost(ol, curLocation);
};

var menu = self.appendChild(document.createXULElement("menupopup"));
self.image = "moz-icon://file://" + path;
var playerName = path.split("\\").pop().replace(".exe","");
self.label = "Открыть видео в " +sysPlayerName;
setTimeout(() => {
Menu_n_TooltipTxts.forEach((m) => {
if("separator" in m) {
menu.appendChild(document.createXULElement("menuseparator"));
return
};
var mItem = document.createXULElement("menuitem");
mItem.setAttribute("label", m.label);

if("radio" in m) {
mItem.setAttribute("type", "radio");
mItem.setAttribute('checked', cbu.getPrefs("CB.video") == m.value);
if(cbu.getPrefs("CB.video") == m.value) {
self.tooltipText = m.tooltipTxt;
}
mItem.onclick = () => {
cbu.setPrefs("CB.video", m.value);


};
}
if("checkbox" in m) {
mItem.setAttribute('type', 'checkbox');


}
menu.appendChild(mItem);
});
menu.onclick = function(e) {
e.stopPropagation();
if(e.button > 0) e.preventDefault();
};
}, 100);

var contextMenu = document.getElementById("contentAreaContextMenu");
var menuitem = contextMenu.insertBefore(document.createXULElement("menuitem"), document.getElementById("context-savelink"));
menuitem.setAttribute("label", "Открыть в " +sysPlayerName);      
menuitem.setAttribute("class", "menuitem-iconic");
menuitem.setAttribute("image", "moz-icon://file://" + path); 
menuitem.onclick = () => play(gContextMenu.linkURL || gContextMenu.mediaURL);
addEventListener("popupshowing", ()=> menuitem.hidden = !gContextMenu.onLink && !gContextMenu.onVideo && !gContextMenu.onPlainTextLink, false, contextMenu);
addDestructor(()=> menuitem.remove() );

onclick = () => {
e.preventDefault();
var vurl = gContextMenu.mediaURL, videoelem = gContextMenu.target;
if(videoelem && videoelem.nodeName.toLowerCase() == 'video') {
if(content.location.hostname.indexOf('youtu') != -1 && (tmp = content.location.toString().match(YoutubeID)) && tmp[1].length == 11) {
play(vurl);
videoMovedbox = content.document.createElement('videoMoved');
videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';
loadURI(stopPl);
content.document.getElementById('eow-title').appendChild(videoMovedbox);
return;
};

if(content.location.hostname == 'www.youtube.com') {
videoelem.parentNode.parentNode.appendChild(videoMovedbox);
} else {
var inFrameHref = inFrameWin.location.href, found = false;
if(inFrameWin.location.hostname == 'www.youtube.com' && (tmp = inFrameHref.match(YoutubeID)) && tmp[1].length == 11){//и значит во фрейме
elem = inFrameWin.parent.document.getElementsByTagName('iframe');
if(elem.length > 0) {
for(i = 0; i < elem.length; i++) {
if(elem[i].contentWindow == inFrameWin) {
elem[i].outerHTML = ytIMGouter(tmp[1]);
found = true;
break;
};
};
};
if(!found)inFrameWin.document.body.innerHTML = ytIMGouter(tmp[1]);
return;
};
videoelem.parentNode.appendChild(videoMovedbox);
};
videoelem.src = '';
try {
videoelem.load()
} catch(e) {};
} else play(vurl);
};

addEventListener("popupshowing", () => {
mItem.hidden = !gContextMenu.onVideo || !gContextMenu.mediaURL;
mItem2.hidden = !gContextMenu.linkURL;
mItem3.hidden = framItem.hidden || gContextMenu.target.ownerDocument.location.hostname.indexOf('youtube.com') == -1;
}, false, contextMenu);
addDestructor(() => {mItem.remove();mItem2.remove();mItem3.remove()});

function play(link) {
if (custombuttons.confirmBox(null, "Открыть  ссылку в плеере ?", "Да", "Отмена") ) {
var file = Services.dirsvc.get('CurProcD', Ci.nsIFile);

file.initWithPath(path);
if(!file.exists()) {
custombuttons.alertBox("File not found!", MozExeDir + Path);
return;
};
var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
var args = [link];
process.init( file );
process.run( false, args, args.length );
};

}

Отредактировано solombala (07-03-2021 23:41:13)

Отсутствует

 

№1524407-03-2021 20:41:45

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 128
UA: Firefox 85.0

Re: Custom Buttons

Как можно получить доступ к документу ифрейма, минуя кроссдоменные ограничения?
Раньше СВ делали это запросто. Но сейчас же они в контексте страницы не работают. Или есть какой способ?


Насчет прокси и Post Message я знаю, мне это не подходит, но может можно и через Custom Buttons?



И еще вопрос: как объявить функцию глобально, чтоб ее было видно из всех вкладок?
Раньше я делал эту функцию свойством кнопки. Она объявлялась один раз при инициализации кнопки и потом ее можно было вызывать в любой момент. А сейчас как?

Отредактировано beggrr (07-03-2021 21:01:35)

Отсутствует

 

№1524508-03-2021 04:56:16

voqabuhe
Участник
 
Группа: Members
Зарегистрирован: 06-12-2011
Сообщений: 3231
UA: Firefox 86.0

Re: Custom Buttons

Dumby
Спасибо.

Отсутствует

 

№1524608-03-2021 21:20:18

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

solombala пишет

Я столько перелопатил ,чтобы на мульти перейти. Теперь из-за этой кнопки все в топку... Если не вы, то кто?

Нет, ну могу попробовать, чисто формально, коды переставить.
А будет ли работать — без понятия.

скрытый текст

Выделить код

Код:

(func => {
	var sysPlayerName = "GOM Player";
	var path = "D:\\gomplayer\\gom.exe";
	var videoMoved = "Видео перенесено в " + sysPlayerName;
	var noFound = "Не найдено видео на странице, доступное для переноса в " + sysPlayerName;

	this.image = "moz-icon://file://" + path;
	this.label = "Открыть видео в " + sysPlayerName;
	this.tooltipText = "Л: Видео в плеер\nП: Видео из Clipboard";

	this._handleClick = () => {
		var msgName = _id + ":Player";
		var listener = ({data}) => data ? play(data) : notify();
		messageManager.addMessageListener(msgName, listener);
		addDestructor(() => messageManager.removeMessageListener(msgName, listener));

		var url = "data:charset=utf-8," + encodeURIComponent(
			`(${func})()`.replace("MSG_NAME", msgName)
				.replace("VIDEO_MOVED", encodeURIComponent(videoMoved))
		);
		(this._handleClick = () => gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false))();
	}
	this.onauxclick = e => e.button != 1 || gShowPopup(this);
	this.oncontextmenu = e => {
		if (e.ctrlKey || e.shiftKey || e.altKey) return;
		e.preventDefault();
		custombuttons.confirmBox(null, "Запустить плеер из буфера обмена ?", "Да", "Нет")
			&& run([gClipboard.read(), "/play"]);
	}
	var popup = document.getElementById("contentAreaContextMenu");
	addEventListener("popupshowing", {
		get hidden() {
			return !(gContextMenu.onLink || gContextMenu.onVideo || gContextMenu.onPlainTextLink);
		},
		handleEvent() {
			if (this.hidden) return;
			var menuitem = document.createXULElement("menuitem");
			for(var args of Object.entries({
				image: self.image,
				oncommand: "play()",
				class: "menuitem-iconic",
				label: "Открыть в " + sysPlayerName
			}))
				menuitem.setAttribute(...args);
			menuitem.play = () => play(gContextMenu.linkURL || gContextMenu.mediaURL);
			document.getElementById("context-savelink").before(menuitem);
			addDestructor(() => menuitem.remove());
			this.handleEvent = e => {
				if (e.target == popup) menuitem.hidden = this.hidden;
			}
		}
	}, false, popup || 1);

	var play = link => custombuttons.confirmBox(null, "Открыть  ссылку в плеере ?", "Да", "Отмена") && run([link]);
	var run = args => {
		var file = FileUtils.File(path);
		(run = args => {
			if (!file.exists()) return custombuttons.alertBox("File not exists!", path);
			var process = Cc["@mozilla.org/process/util;1"].createInstance(Ci.nsIProcess);
			process.init(file);
			process.runwAsync(args, args.length);
		})(args);
	}
	var notify = () => {
		var name = _id + "-noFound";
		var as = Cc["@mozilla.org/alerts-service;1"].getService(Ci.nsIAlertsService);
		(notify = () => setTimeout(as.closeAlert, 1150, name, as.showAlertNotification(
			"chrome://global/skin/icons/info.svg", "", noFound, false, "", null, name
		)))();
	}

})(() => {

	var sended, SEND = msg => sended = !sendAsyncMessage("MSG_NAME", msg);

	var videoMoved = decodeURIComponent("VIDEO_MOVED");

	var YoutubeID = /(?:youtube(?:-nocookie)?\.com\/(?:[^\/\n\s]+\/\S+\/|(?:v|e(?:mbed)?)\/|\S*?[?&]v=)|youtu\.be\/)([a-zA-Z0-9_-]{11})(?:\W|$)/;

	var tmp = '',
	tmpp = '',
	innerA = '<div style="display:block!important;color:#00ff00!important;width:250px!important;font:bold 16px serif!important;z-index:999!important;opacity:1!important;visibility: visible!important;',
	innerB = 'left:5px!important;position:absolute!important;height:auto!important;box-sizing:border-box!important;padding:5px!important;margin:5px!important;',
	//stopPl = "javascript:(function(){v=document.getElementById('movie_player');if(v){v.stopVideo()}else{v=document.getElementsByTagName('video');if(v){v[0].src='';try{v[0].load()}catch(e){}};}})();",
	ytIMGouter = function (ytID) {
		return '<div width="100%"><br /><a target="_blank" href="https://www.youtube.com/watch?v=' + ytID + '"><img src="https://i.ytimg.com/vi/' + ytID + '/hqdefault.jpg"></a><br />' + innerA + 'background-color:black!important;position:relative!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div><br /></div><br />'
	},
	handlWin = function (currentWin) {
		tmp = '';
		var elem = currentWin.document.getElementsByTagName('video'),
		currLoc = currentWin.location;
		if (elem.length > 0) {
			if (currLoc.hostname.indexOf('youtu') != -1 && (tmp = currLoc.toString().match(YoutubeID)) && tmp[1].length == 11) {

				SEND('https://www.youtube.com/watch?v=' + tmp[1]);

				videoMovedbox = currentWin.document.createElement('videoMoved');
				videoMovedbox.innerHTML = innerA + innerB + 'top:-15px!important;"><b>' + videoMoved + '</b></div>';

				//loadURI(stopPl);
				(function(d){var v=d.getElementById('movie_player');if(v){try{v.stopVideo()}catch{}}
					else{v=d.getElementsByTagName('video');if(v[0]){v[0].src='';try{v[0].load()}catch{}};}})(currentWin.document);

				currentWin.document.getElementById('eow-title').appendChild(videoMovedbox);
				return true;
			};
			for (i = 0; i < elem.length; i++) {
				if (((tmp = getSrc(elem[i].parentNode, currLoc)) && tmp.length > 2) || (i == 0 && currentWin.document.body.innerHTML.substring(0, 7) == '<video ' && (tmp = currLoc.toString()))) {
					videoMovedbox = currentWin.document.createElement('videoMoved');
					videoMovedbox.innerHTML = innerA + innerB + 'top:20px!important;background-color:black!important;">' + videoMoved + '</div>';

					SEND(tmp);

					if (currLoc.hostname == 'www.youtube.com') {
						elem[i].parentNode.parentNode.appendChild(videoMovedbox);
					} else {
						elem[i].parentNode.appendChild(videoMovedbox);
					};
					elem[i].src = '';
					try {
						elem[i].load()
					} catch (e) {};
					return true;
				}
			}
		};

		currentWin._elems = currentWin.document.getElementsByTagName('iframe');
		if (currentWin._elems.length > 0) {
			for (currentWin._iCounter = 0; currentWin._iCounter < currentWin._elems.length; currentWin._iCounter++) {
				if ((currentWin._elems[currentWin._iCounter].src.indexOf('youtube.com') > -1) && (tmp = currentWin._elems[currentWin._iCounter].src.match(YoutubeID)) && (tmp[1].length == 11)) {

				SEND('https://www.youtube.com/watch?v=' + tmp[1]);

				currentWin._elems[currentWin._iCounter].outerHTML = ytIMGouter(tmp[1]);
					return true;
				};
				if (currentWin._elems[currentWin._iCounter].clientWidth > 80 && currentWin._elems[currentWin._iCounter].clientHeight > 40 && handlWin(currentWin._elems[currentWin._iCounter].contentWindow))
					return true;
			}
		};

		elem = currentWin.document.getElementsByTagName('object');
		currLoc = currentWin.location;
		if (elem.length == 0) {
			elem = currentWin.document.getElementsByTagName('embed')
		};
		if (elem.length > 0) {
			for (i = 0; i < elem.length; i++) {
				if (elem[i].innerHTML.indexOf('youtu') != -1 && (tmp = elem[i].innerHTML.match(YoutubeID)) && tmp[1].length == 11) {

					SEND('https://www.youtube.com/watch?v=' + tmp[1]);

					elem[i].outerHTML = ytIMGouter(tmp[1]);
					return true;
				} else {
					if (elem[i].clientWidth > 80 && elem[i].clientHeight > 40) {
						if (((tmp = getSrc(elem[i].parentNode, currLoc)) || (tmp = getLink(elem[i], currLoc))) && tmp.length > 2) {

							SEND(tmp);

							elem[i].outerHTML = innerA + 'background-color:black!important;bottom:20px!important;">&nbsp;&nbsp;' + videoMoved + '</div>';
							return true;
						};
					};
				}
			};
		};
		return false;
	};

	function restProtHost(lnkR, curLoc) {
		if (lnkR.length == 0)
			return '';
		let tr = lnkR.replace(/^:\/\//, curLoc.protocol + "//");
		if (!tr.match(/^https?:\/\//i)) {
			lnkR = tr.replace(/^\/+/, '');
			if (lnkR.split('/')[0].split('?')[0].split('#')[0].toLowerCase().match(/^(?:[-a-z\d]+\.)+[a-z\d]{2,6}$/)) {
				tr = curLoc.protocol + '//' + lnkR;
			} else {
				tr = curLoc.protocol + '//' + curLoc.host + "/" + lnkR;
			}
		};
		return tr;
	};

	function getSrc(vobj, currentLoc) {
		var t = '',
		tt = '';
		if ((((t = vobj.innerHTML.match(/<video.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*))/i)) && (t) && (tt = t[1] || t[2] || t[3]) && tt.indexOf('blob:') == -1) || ((t = vobj.innerHTML.match(/<source.*?\ssrc=(?:(?:'([^']*)')|(?:"([^"]*)")|([^\s]*)).*?\stype=['"]?video\//i)) && (t) && (tt = t[1] || t[2] || t[3]))) && tt.length > 2 && tt.indexOf('blob:') == -1) {
			if (tt.indexOf(".mp4/?") == -1) {
				tt = tt.replace(/&amp;/g, "&")
			};
			t = restProtHost(tt, currentLoc);
			return t;
		};
		return '';
	};

	function getLink(obj, curLocation) {

		if (!obj || !obj.tagName)
			return '';
		q = obj.tagName.toLowerCase();

		var getParam = function (e, n) {
			var v = '',
			r = new RegExp('^(' + n + ')$', 'i'),
			param = e.getElementsByTagName('param');
			for (var igp = 0, p; p = param[igp]; igp++) {
				if (p.hasAttribute('name') && p.getAttribute('name').match(r)) {
					v = p.getAttribute('value');
					break
				};
			};
			return v;
		};

		var restPath = function (f, s) {
			return (f.substring(0, 4) == 'http') ? f : s.replace(/[#?].*$/, '').replace(/[^\/]*$/, f)
		};

		function videoLinkExtract(fl) {
			alert(fl);
			var linkArr = [],
			outLinks = [],
			jj = 0,
			lba = '',
			lbb = '',
			decodeURL = gBrowser.currentURI.spec; {
				try {
					return decodeURIComponent(s)
				} catch (e) {
					return unescape(s)
				}
			};

			for (var ij = 0; ij < 3; ij++) {
				lba = lba + String.fromCharCode(parseInt((Math.random() * 15 + 1) + '', 10));
				lbb = lbb + String.fromCharCode(parseInt((Math.random() * 15 + 16) + '', 10));
			};

			function pushWithMerit(lnk) {

				var merit = -11;
				if (lnk.match(/^https?:\/\//i))
					merit = merit + 40;
				if (outLinks.length == 0)
					merit = merit + 1;
				if (lnk.match(/^\//))
					merit = merit + 7;
				if (lnk.match(/^\/\//))
					merit = merit + 30;
				if (lnk.match(/240p([^a-z]|$)/i))
					merit = merit + 1;
				if (lnk.match(/[^a-z]240([^a-z0-9]|$)/i))
					merit = merit + 1;
				if (lnk.match(/360p([^a-z]|$)/i))
					merit = merit + 3;
				if (lnk.match(/[^a-z]360([^a-z0-9]|$)/i))
					merit = merit + 3;
				if (lnk.match(/480p([^a-z]|$)/i))
					merit = merit + 5;
				if (lnk.match(/[^a-z]480([^a-z0-9]|$)/i))
					merit = merit + 5;
				if (lnk.match(/720p([^a-z]|$)/i))
					merit = merit + 7;
				if (lnk.match(/[^a-z]720([^a-z0-9]|$)/i))
					merit = merit + 7;
				if (lnk.match(/\.mp4([^a-z]|$)/i))
					merit = merit + 8;
				if (lnk.match(/_hd([^a-z]|$)/i))
					merit = merit + 6;
				if (lnk.match(/\.(jpg|xml)([^a-z]|$)/i))
					merit = merit - 40;
				if (merit > 0)
					outLinks.push(merit + lba + lnk);
				Services.console.logStringMessage('merit:' + merit + ' lnk->' + lnk);
			};

			linkArr.push(fl);
			while (linkArr.length > jj && jj < 30) {

				var testPaths = [];
				testPaths = linkArr[jj].split(/(\.(?:flv|mp4|m3u8))/i);
				if (testPaths[testPaths.length - 1] == '')
					testPaths.pop();

				for (k = 1; k < testPaths.length; k = k + 2) {

					if (testPaths[k - 1].indexOf(lba) > -1) {
						pref = testPaths[k - 1];
					} else {
						var testAboutDom = testPaths[k - 1].toLowerCase().split(/(https?:\/\/)/);
						if (testAboutDom[testAboutDom.length - 1] == '')
							testAboutDom.pop();
						var pTest = testAboutDom[testAboutDom.length - 1].split(/(\?[^\?]*?&)/);
						if (pTest.length > 2) {
							pTest.pop();
							pTest.pop();
						};
						testAboutDom[testAboutDom.length - 1] = pTest.join('');
						pref = testPaths[k - 1].substring(testAboutDom.join('').lastIndexOf("&") + 1);
					};

					t2 = pref.lastIndexOf(lbb);
					if (t2 > -1) {
						pref = pref.substring(t2 + 3);
					} else {

						t2 = pref.lastIndexOf('{"');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.lastIndexOf('["');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.lastIndexOf(',"');
						if (t2 > -1)
							pref = pref.substring(t2 + 2);
						t2 = pref.toLowerCase().lastIndexOf('"http://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf('"https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(',http://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(',https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(';http');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf('*https://');
						if (t2 > -1)
							pref = pref.substring(t2 + 1);
						t2 = pref.toLowerCase().lastIndexOf(' or ');
						if (t2 > -1)
							pref = pref.substring(t2 + 4);

						pref = pref.substring(pref.split('/')[0].toLowerCase().split('%2f')[0].lastIndexOf('=') + 1);

					}

					if (pref.length > 0) {

						if (pref.split('?')[0].toLowerCase().match(/%[2-3][0-9a-f]/)) {

							t2 = pref.indexOf('"')
								if (t2 > -1)
									pref = pref.substring(t2 + 1);
								suff = testPaths[k + 1] ? testPaths[k + 1].split('&')[0].split('"')[0].split(';')[0].split(/,http/i)[0] : '';
							if ((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
								if (testPaths.length > k + 1) {
									testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
								};
								t2 = pref.lastIndexOf(lba);
								if (t2 > -1)
									pref = pref.substring(t2 + 3)
										linkArr.push(decodeURL(pref + testPaths[k] + suff));

							} else {
								testPaths[k + 1] = (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
							}
						} else {
							suff = testPaths[k + 1] ? testPaths[k + 1].split(';')[0].split('"]')[0].split('"}')[0].split('",')[0].split(/,https?:\/\//i)[0].split('*https://')[0].split(' or ')[0] : '';
							t2 = suff.indexOf('&');
							if ((t2 > -1) && (pref != testPaths[k - 1])) {
								if (t2 == 0)
									suff = '';
								if (suff.charAt(0) != '?')
									suff = suff.split(/(&[^&]+=https?:\/\/)/i)[0];
							};
							if ((suff != testPaths[k + 1]) || (testPaths.length < k + 3)) {
								if (testPaths.length > k + 1) {
									testPaths[k + 1] = ((pref == testPaths[k - 1]) ? '' : '&') + testPaths[k + 1].substr(suff.length)
								};
								t2 = pref.lastIndexOf(lba);
								if (t2 > -1)
									pref = pref.substring(t2 + 3);
								pushWithMerit(pref + testPaths[k] + suff);

							} else {
								testPaths[k + 1] = lba + (pref == testPaths[k - 1] ? '' : lbb) + pref + testPaths[k] + suff
							}
						}
					}
				};
				jj = jj + 1;
			};

			if (outLinks.length == 0)
				return '';
			function srt(a, b) {
				a = parseInt(a.substr(0, a.indexOf(lba)), 10);
				b = parseInt(b.substr(0, b.indexOf(lba)), 10);
				if (a < b)
					return 1;
				if (a > b)
					return -1;
				return 0
			};
			outLinks.sort(srt);
			outLinks[0] = outLinks[0].substr(outLinks[0].indexOf(lba) + 3)
				if (outLinks[0].indexOf('_hq.mp4/?time=') > 0)
					outLinks[0] = outLinks[0].replace(/&/g, '&amp;');
				return outLinks[0];
		};

		if (!ol)
			return '';
		//ol = ol.replace(/^:?\/\//, curLocation.protocol + "//");
		//return restPath(ol, src);
		return restProtHost(ol, curLocation);
	};

	try {handlWin(content);} finally {sended || SEND();}
});

beggrr пишет

Как можно получить доступ к документу ифрейма, минуя кроссдоменные ограничения?
Раньше СВ делали это запросто. Но сейчас же они в контексте страницы не работают. Или есть какой способ?

Из frame script'а доступ есть. Но не в Fission.
Отправить frame script из CB вполне возможно.

И еще вопрос: как объявить функцию глобально, чтоб ее было видно из всех вкладок?
Раньше я делал эту функцию свойством кнопки. Она объявлялась один раз при инициализации кнопки и потом ее можно было вызывать в любой момент. А сейчас как?

Сейчас точно так же, ничего не изменилось.
Да набрать проверочный код проще и быстрее, чем этот вопрос.

Отсутствует

 

№1524708-03-2021 22:33:49

Dragoljub
Забанен
 
Группа: Members
Зарегистрирован: 08-03-2021
Сообщений: 2
UA: Firefox 86.0

Re: Custom Buttons

Dumby

Dumby пишет

А будет ли работать — без понятия.

Велико хвала! Ти je хероj .

Отсутствует

 

№1524809-03-2021 00:22:12

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 128
UA: Firefox 85.0

Re: Custom Buttons

Dumby пишет

И еще вопрос: как объявить функцию глобально, чтоб ее было видно из всех вкладок?
    Раньше я делал эту функцию свойством кнопки. Она объявлялась один раз при инициализации кнопки и потом ее можно было вызывать в любой момент. А сейчас как?

Сейчас точно так же, ничего не изменилось.
Да набрать проверочный код проще и быстрее, чем этот вопрос.

Хм... Назначить кнопке свойство в виде функции легко. Но как потом эту функцию вызывать из контента страницы?
Раньше это было действительно просто: document.getElementById(button.id).myFunction()

Но сейчас для обычного скрипта на странице document - это сам контент страницы. А как этот скрипт может обратиться к кнопке и ее свойствам?

Из frame script'а доступ есть. Но не в Fission.
Отправить frame script из CB вполне возможно.

Можно приблизительный набросок как это сделать?

Отредактировано beggrr (09-03-2021 00:22:46)

Отсутствует

 

№1524909-03-2021 10:43:50

Dumby
Участник
 
Группа: Members
Зарегистрирован: 12-08-2012
Сообщений: 2245
UA: Firefox 68.0

Re: Custom Buttons

beggrr пишет

Хм... Назначить кнопке свойство в виде функции легко. Но как потом эту функцию вызывать из контента страницы?
Раньше это было действительно просто: document.getElementById(button.id).myFunction()
Но сейчас для обычного скрипта на странице document - это сам контент страницы.

Не могло такого быть.
Для «обычного скрипта на странице» document всегда был документом страницы.
Если бы у «обычного скрипта на странице» был доступ к документу окна браузера,
то он мог бы вытворять что угодно, типа "стереть диск Цэ" и всё такое.

А как этот скрипт может обратиться к кнопке и ее свойствам?

Если говорить о немногопроцессном Firefox, то что за странные идеи.
Залезть на страницу, чтобы потом смотреть оттуда "изнутри вверх".


Нет, ну можно создать функцию, зарегистрировать обсёрвер или листенер,
и запихивать её в контентские окна с помощью Cu.exportFunction(),
а затем вызывать «из контента страницы».


Не слишком то удобно, плюс, наверно, для «скрипта на странице»
будет бесполезным возвращаемое значение, разве что примитив.
Куда логичнее классический взгляд "снаружи вниз",
то есть просто делаешь с контентом что надо сразу из хромского кода.


А если говорить о многопроцессном Firefox, то нет и предмета разговора.
Веб-страница находится в другом процессе,
а обратиться (к чему-либо вообще) можно только в пределах процесса.

Можно приблизительный набросок как это сделать?

Можно. Запускай.
(затем можно код из переменной code запустить с веб консоли, чтобы полюбоваться на ошибку)

скрытый текст

Выделить код

Код:

var code = `
	(win => {
		try {
			win.alert(win.frames[0].document.links);
			// [object HTMLCollection]
		}
		catch(ex) {
			win.alert(ex);
			// SecurityError: Permission denied to access property "document" on cross-origin object
		}
	})(this.window || content);
`;
var url = "data:," + encodeURIComponent(code);
gBrowser.selectedBrowser.messageManager.loadFrameScript(url, false);

Отсутствует

 

№1525009-03-2021 22:07:25

beggrr
Участник
 
Группа: Members
Зарегистрирован: 04-02-2014
Сообщений: 128
UA: Firefox 85.0

Re: Custom Buttons

Dumby
Спасибо за код для фреймов.


Dumby пишет

А если говорить о многопроцессном Firefox, то нет и предмета разговора.
Веб-страница находится в другом процессе,
а обратиться (к чему-либо вообще) можно только в пределах процесса.

Ну вот то то и оно...  Я думал, может можно как то это обойти. Получается никак нельзя.

А есть в многопроцессном  режиме вообще возможность сделать одну глобальную функцию для всех вкладок, чтобы ее можно было вызывать именно из страницы, не из кнопки? Объявляется она один раз скажем при запуске браузера, а дальше ее вызывают когда нужно и на любой странице.

Отсутствует

 

Board footer

Powered by PunBB
Modified by Mozilla Russia
Copyright © 2004–2020 Mozilla Russia GitHub mark
Язык отображения форума: [Русский] [English]