Find and remove file from cache - firefox-addon

I have this css which applies background-image: path/to/desktop/build1.png.
So whatever is build1.png on desktop will be the background image. However, in my addon, after I dynamically delete build1.png and replace it with another image that I rename build1.png, the background-image does not update. I tried ctrl+f5 and it didn't work. So I'm thinking after I dynamically replace the image on the desktop I should delete it from cache.
Test case, copy paste to scratchpad with environment browser and hit run, it opens a new tab with a gui for the test case. Hit "Release Img" then hit "applyCss" then hit "Aurora Img" and watch how the background of the div doesn't change.
Here is youtube video demo of this testcase demo'ing the issue: https://www.youtube.com/watch?v=mbGJxHtstrw
var tab = gBrowser.loadOneTab('data:text/html,<div class="profilist-icon-build-1">backround of this span is of icon on desktop</div><input type="button" value="applyCss"><input type="button" value="removeCss"> Change File on Desktop to: <input type="button" value="Release Img"><input type="button" value="Beta Img"><input type="button" value="Aurora Img"><input type="button" value="Nightly Img">', {inBackground:false});
//start - listen for loadOneTab to finish loading per https://gist.github.com/Noitidart/0f076070bc77abd5e406
var mobs = new window.MutationObserver(function(mutations) {
mutations.forEach(function(mutation) {
if (mutation.attributeName == 'progress' && tab.getAttribute('progress') == '') {
//alert('tab done loading');
init();
mobs.disconnect();
}
});
});
mobs.observe(tab, {attributes: true});
//end - listen for loadOneTab to finish loading per https://gist.github.com/Noitidart/0f076070bc77abd5e406
function init() {
//run on load of the loadOneTab
var win = tab.linkedBrowser.contentWindow;
var doc = win.document;
var btns = doc.querySelectorAll('input[type=button]');
Array.prototype.forEach.call(btns, function(b) {
b.addEventListener('click', handleBtnClick, false);
});
}
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/osfile.jsm');
var sss = Cc['#mozilla.org/content/style-sheet-service;1'].getService(Ci.nsIStyleSheetService);
var cssBuildIconsStr = '.profilist-icon-build-1 { background-image: url("' + OS.Path.toFileURI(OS.Path.join(OS.Constants.Path.desktopDir, 'build1.png')) + '"); ';
var newURIParam = {
aURL: 'data:text/css,' + encodeURIComponent(cssBuildIconsStr),
aOriginCharset: null,
aBaseURI: null
};
var cssBuildIconsURI = Services.io.newURI(newURIParam.aURL, newURIParam.aOriginCharset, newURIParam.aBaseURI);
function handleBtnClick(e) {
var targ = e.target;
var doc = e.target.ownerDocument;
var win = doc.defaultView;
switch(targ.value) {
case 'applyCss':
if (sss.sheetRegistered(cssBuildIconsURI, sss.AUTHOR_SHEET)) {
win.alert('ERROR: Sheet is already registered! Will not re-register...');
} else {
sss.loadAndRegisterSheet(cssBuildIconsURI, sss.AUTHOR_SHEET);
win.alert('REGISTERED')
}
break;
case 'removeCss':
if (sss.sheetRegistered(cssBuildIconsURI, sss.AUTHOR_SHEET)) {
sss.unregisterSheet(cssBuildIconsURI, sss.AUTHOR_SHEET);
win.alert('UNregged');
} else {
win.alert('ERROR: Sheet is not registered! Nothing to unregister...');
}
break;
case 'Release Img':
xhr('https://raw.githubusercontent.com/Noitidart/Profilist/%2321/bullet_release.png', function(d){saveToDiskAsBuild1(d, win)});
break;
case 'Beta Img':
xhr('https://raw.githubusercontent.com/Noitidart/Profilist/%2321/bullet_beta.png', function(d){saveToDiskAsBuild1(d, win)});
break;
case 'Aurora Img':
xhr('https://raw.githubusercontent.com/Noitidart/Profilist/%2321/bullet_aurora.png', function(d){saveToDiskAsBuild1(d, win)});
break;
case 'Nightly Img':
xhr('https://raw.githubusercontent.com/Noitidart/Profilist/%2321/bullet_nightly.png', function(d){saveToDiskAsBuild1(d, win)});
break;
default:
win.alert('unknown button clicked, value = "' + targ.value + '"');
}
}
function xhr(url, cb) {
let xhr = Cc["#mozilla.org/xmlextras/xmlhttprequest;1"].createInstance(Ci.nsIXMLHttpRequest);
let handler = ev => {
evf(m => xhr.removeEventListener(m, handler, !1));
switch (ev.type) {
case 'load':
if (xhr.status == 200) {
cb(xhr.response);
break;
}
default:
Services.prompt.alert(null, 'XHR Error', 'Error Fetching Package: ' + xhr.statusText + ' [' + ev.type + ':' + xhr.status + ']');
break;
}
};
let evf = f => ['load', 'error', 'abort'].forEach(f);
evf(m => xhr.addEventListener(m, handler, false));
xhr.mozBackgroundRequest = true;
xhr.open('GET', url, true);
xhr.channel.loadFlags |= Ci.nsIRequest.LOAD_ANONYMOUS | Ci.nsIRequest.LOAD_BYPASS_CACHE | Ci.nsIRequest.INHIBIT_PERSISTENT_CACHING;
xhr.responseType = "arraybuffer"; //dont set it, so it returns string, you dont want arraybuffer. you only want this if your url is to a zip file or some file you want to download and make a nsIArrayBufferInputStream out of it or something
xhr.send(null);
}
function saveToDiskAsBuild1(data, win) {
var file = OS.Path.join(OS.Constants.Path.desktopDir, 'build1.png');
var promised = OS.File.writeAtomic(file, new Uint8Array(data));
promised.then(
function() {
win.alert('succesfully saved image to desktop')
},
function(ex) {
win.alert('FAILED in saving image to desktop')
}
);
}

Related

Is it possible to get Google Ouath2 access token without setting a redirect URI?

I am trying to implement Google Oauth2 consent screen within a popup but it says redirect URI mismatch. Is there any way where I can set up a web Ouath Client App without setting redirect uri in the dashboard?
I know setting up client type from web to others or application may solve this issue. But I want to implement it for web type only. Is this possible?
<!DOCTYPE html>
<html>
<head>
<script>
'use strict';
var GO2 = function GO2(options) {
if (!options || !options.clientId) {
throw 'You need to at least set the clientId';
}
if (typeof window != 'undefined'){
this._redirectUri = window.location.href.substr(0,
window.location.href.length -
window.location.hash.length)
.replace(/#$/, '');
}
// Save the client id
this._clientId = options.clientId;
// if scope is an array, convert it into a string.
if (options.scope) {
this._scope = Array.isArray(options.scope) ?
options.scope.join(' ') :
options.scope;
}
// rewrite redirect_uri
if (options.redirectUri) {
this._redirectUri = options.redirectUri;
}
// popup dimensions
if (options.popupHeight) {
this._popupHeight = options.popupHeight;
}
if (options.popupWidth) {
this._popupWidth = options.popupWidth;
}
if (options.responseType) {
this._responseType = options.responseType;
}
if (options.accessType) {
this._accessType = options.accessType;
}
};
GO2.receiveMessage = function GO2_receiveMessage() {
var go2;
if (window.opener && window.opener.__windowPendingGO2) {
go2 = window.opener.__windowPendingGO2;
}
if (window.parent && window.parent.__windowPendingGO2) {
go2 = window.parent.__windowPendingGO2;
}
var hash = window.location.hash;
if (go2 && hash.indexOf('access_token') !== -1) {
go2._handleMessage(
hash.replace(/^.*access_token=([^&]+).*$/, '$1'),
parseInt(hash.replace(/^.*expires_in=([^&]+).*$/, '$1'), 10),
hash.replace(/^.*state=go2_([^&]+).*$/, '$1')
);
}
if (go2 && window.location.search.indexOf('code=')) {
go2._handleMessage(
window.location.search.replace(/^.*code=([^&]+).*$/, '$1'),
null,
window.location.search.replace(/^.*state=go2_([^&]+).*$/, '$1')
);
}
if (go2 && window.location.search.indexOf('error=')) {
go2._handleMessage(false);
}
};
GO2.prototype = {
WINDOW_NAME: 'google_oauth2_login_popup',
OAUTH_URL: 'https://accounts.google.com/o/oauth2/v2/auth',
_clientId: undefined,
_scope: 'https://www.googleapis.com/auth/plus.me',
_redirectUri: '',
_popupWindow: null,
_immediateFrame: null,
_stateId: Math.random().toString(32).substr(2),
_accessToken: undefined,
_timer: undefined,
_popupWidth: 500,
_popupHeight: 400,
_responseType: 'token',
_accessType: 'online',
onlogin: null,
onlogout: null,
login: function go2_login(forceApprovalPrompt, immediate) {
if (this._accessToken) {
return;
}
this._removePendingWindows();
window.__windowPendingGO2 = this;
var url = this.OAUTH_URL +
'?response_type=' + this._responseType +
'&access_type='+ encodeURIComponent(this._accessType) +
'&redirect_uri=' + encodeURIComponent(this._redirectUri) +
'&scope=' + encodeURIComponent(this._scope) +
'&state=go2_' + this._stateId +
'&client_id=' + encodeURIComponent(this._clientId);
console.log(url);
if (!immediate && forceApprovalPrompt) {
url += '&approval_prompt=force';
}
if (immediate) {
url += '&approval_prompt=auto';
// Open up an iframe to login
// We might not be able to hear any of the callback
// because of X-Frame-Options.
var immediateFrame =
this._immediateFrame = document.createElement('iframe');
immediateFrame.src = url;
immediateFrame.hidden = true;
immediateFrame.width = immediateFrame.height = 1;
immediateFrame.name = this.WINDOW_NAME;
document.body.appendChild(immediateFrame);
return;
}
// Open the popup
var left =
window.screenX + (window.outerWidth / 2) - (this._popupWidth / 2);
var top =
window.screenY + (window.outerHeight / 2) - (this._popupHeight / 2);
var windowFeatures = 'width=' + this._popupWidth +
',height=' + this._popupHeight +
',top=' + top +
',left=' + left +
',location=no,toolbar=no,menubar=no';
this._popupWindow = window.open(url, this.WINDOW_NAME, windowFeatures);
},
logout: function go2_logout() {
if (!this._accessToken) {
return;
}
this._removePendingWindows();
clearTimeout(this._timer);
this._accessToken = undefined;
if (this.onlogout) {
this.onlogout();
}
},
getAccessToken: function go2_getAccessToken() {
return this._accessToken;
},
// receive token from popup / frame
_handleMessage: function go2_handleMessage(token, expiresIn, stateId) {
if (this._stateId !== stateId) {
return;
}
this._removePendingWindows();
// Do nothing if there is no token received.
if (!token) {
return;
}
this._accessToken = token;
if (this.onlogin) {
this.onlogin(this._accessToken);
}
if (expiresIn) {
// Remove the token if timed out.
clearTimeout(this._timer);
this._timer = setTimeout(
function tokenTimeout() {
this._accessToken = undefined;
if (this.onlogout) {
this.onlogout();
}
}.bind(this),
expiresIn * 1000
);
}
},
destory: function go2_destory() {
if (this._timer) {
clearTimeout(this._timer);
}
this._removePendingWindows();
},
_removePendingWindows: function go2_removePendingWindows() {
if (this._immediateFrame) {
document.body.removeChild(this._immediateFrame);
this._immediateFrame = null;
}
if (this._popupWindow) {
this._popupWindow.close();
this._popupWindow = null;
}
if (window.__windowPendingGO2 === this) {
delete window.__windowPendingGO2;
}
}
};
// if the context is the browser
if (typeof window !== 'undefined') {
// If the script loads in a popup matches the WINDOW_NAME,
// we need to handle the request instead.
if (window.name === GO2.prototype.WINDOW_NAME) {
GO2.receiveMessage();
}
}
// Expose the library as an AMD module
if (typeof define === 'function' && define.amd) {
define('google-oauth2-web-client', [], function () { return GO2; });
} else if (typeof module === 'object' && typeof require === 'function') {
// export GO2 in Node.js, assuming we are being browserify'd.
module.exports = GO2;
if (require.main === module) {
console.error('Error: GO2 is not meant to be executed directly.');
}
} else {
window.GO2 = GO2;
}
function test(){
var go2 = new GO2({
clientId: 'dfsdffdfgsfsdfggdgd.apps.googleusercontent.com',
redirectUri: 'http://localhost:8888/gapi/test.html',
responseType: 'code',
accessType: 'offline'
});
go2.login();
}
</script>
</head>
<body>
<a href='#' onClick='test();'> Click here to login </a>
</body>
</html>
It looks like you're using the implicit grant type which requires a redirect uri with response_type=token.
Can you use the authorization code grant type?
The redirect uri is optional for the authorization code grant type.
https://www.rfc-editor.org/rfc/rfc6749#section-4.1.1

Get term for selected autocomplete when multiple are on one page

I have a page where I am adding jquery-ui autocompletes dynamically
My .autocomplete() code includes a $.getJSON('my_url', my_payload) where, in my_payload,' I am trying to send the request.term (what I typed into the jqueryui textbox) as well as the id of the jquery ui text box.
The problem is, for all the dynamically added textboxes, they were just picking up the term and id of the original autocomplete.
I managed to find a way to get the id of the added (not original) autocomplete by wrapping the autocomplete in a function that has the added field passed in as a parameter, but because the 'term' is in the request, which comes from .autocomplete, I do not know how to get this for the new ones.
https://jsfiddle.net/amchugh89/1L8jvea5/4/
//=======dynamic formset script from https://medium.com/all-about-
django/adding-forms-dynamically-to-a-django-formset-375f1090c2b0======
function updateElementIndex(el, prefix, ndx) {
var id_regex = new RegExp('(' + prefix + '-\\d+)');
var replacement = prefix + '-' + ndx;
if ($(el).attr("for")) $(el).attr("for", $(el).attr("for").replace(id_regex, replacement));
if (el.id) el.id = el.id.replace(id_regex, replacement);
if (el.name) el.name = el.name.replace(id_regex, replacement);
}
function cloneMore(selector, prefix) {
var newElement = $(selector).clone(true);
var total = $('#id_' + prefix + '-TOTAL_FORMS').val();
newElement.find(':input:not([type=button]):not([type=submit]):not([type=reset])').each(function() {
if ($(this).attr('name')){
var name = $(this).attr('name').replace('-' + (total-1) + '-', '-' + total + '-');
var id = 'id_' + name;
$(this).attr({'name': name, 'id': id}).val('').removeAttr('checked');
if($(this).attr('id').includes('gl')){
console.log($(this).attr('id'))
make_autocomplete($(this))
}
}
});
newElement.find('label').each(function() {
var forValue = $(this).attr('for');
if (forValue) {
forValue = forValue.replace('-' + (total-1) + '-', '-' + total + '-');
$(this).attr({'for': forValue});
}
});
total++;
$('#id_' + prefix + '-TOTAL_FORMS').val(total);
$(selector).after(newElement);
var conditionRow = $('.form-row:not(:last)');
conditionRow.find('.btn.add-form-row')
.removeClass('btn-success').addClass('btn-danger')
.removeClass('add-form-row').addClass('remove-form-row')
.html('<span class="glyphicon glyphicon-minus" aria-hidden="true"></span>');
return false;
}
function deleteForm(prefix, btn) {
var total = parseInt($('#id_' + prefix + '-TOTAL_FORMS').val());
if (total > 1){
btn.closest('.form-row').remove();
var forms = $('.form-row');
$('#id_' + prefix + '-TOTAL_FORMS').val(forms.length);
for (var i=0, formCount=forms.length; i<formCount; i++) {
$(forms.get(i)).find(':input').each(function() {
updateElementIndex(this, prefix, i);
});
}
}
return false;
}
$(document).on('click', '.add-form-row', function(e){
e.preventDefault();
cloneMore('.form-row:last', 'form');
return false;
});
$(document).on('click', '.remove-form-row', function(e){
e.preventDefault();
deleteForm('form', $(this));
return false;
});
//====================
//AUTOCOMPLETE==(that allows for multiple ACs
https://stackoverflow.com/questions/24656589/using-jquery-ui-autocomplete-
with-multiple-input-fields)===================================
function make_autocomplete(ee) {
ee.on("focus", function(){ //.autocomplete({
$(this).autocomplete({
minLength: 2,
source: function( request, response ) {
var term = request.term;
//with the formset, I want to get the row for which I am typing in the
'term'
var this_formset_row_autocomplete_id
=ee.attr('id');//$(this.element).prop("id");//
$(this).attr('id');
console.log(this_formset_row_autocomplete_id);
var corresponding_branch_html_id =
this_formset_row_autocomplete_id.replace('gl_account','branch');
var this_formset_row_branch_sym_id =
$('#'+corresponding_branch_html_id).val();
//console.log(corresponding_branch_html_id, this_formset_row_branch_sym_id)
var appended_data={term:term,
this_formset_row_branch_sym_id:this_formset_row_branch_sym_id};
console.log(appended_data);
$.getJSON( "{% url 'dashapp:account_autocomplete' %}", appended_data,
function( data,
status, xhr ) {
//cache[ term ] = data;
response( data );
});
}
});
});
}//end function make_autocomplete
var ee =$( ".account_autocomplete" )
make_autocomplete(ee)
//===============
You may want to try to make it more simple for testing. Something like:
function make_autocomplete(obj) {
obj.autocomplete({
minLength: 2,
source: function(req, resp) {
var myData = {
term: req.term,
original_form_branch_id: $(this).closest("form").attr("id"),
this_formset_row_branch_sym_id: $(this).closest(".row").find("select").val()
}
$.getJSON("myurl", myData, function(results) {
resp(results);
});
}
});
}
Fiddle: https://jsfiddle.net/Twisty/pywb9nhv/23/
This uses .closest() to gather details from the relative objects. Also I do not see any benefit to initializing Autocomplete on focus event.
If you would like further help, please provide Example Data that can be used in a working example.
Hope that helps a little.

Service worker - Can't specify width of browser in sw.js

I want to be able to change width on my images depending on the size of the browser, so I am trying to specify the width of the browser with document.body.clientWidth within my sw.js. But I get the error saying that document is not defined.
Any other suggestions in how to get the size of the browser, or how I can wait until document is defined?
sw.js
var connection = "4g";
if (typeof navigator.connection != "undefined") {
var connection = navigator.connection.effectiveType;
}
var isQualitySet = false;
var imageQuality = "";
var tabletUP = document.body.clientWidth < 500;
self.addEventListener('fetch', function(event) {
if (/\.jpg$|.png$|.gif$|.webp$/.test(event.request.url)) {
if (!isQualitySet) {
switch (connection) {
case '4g':
imageQuality = 'q_auto:good';
break;
case '3g':
imageQuality = 'q_auto:eco';
break;
case'2g':
case 'slow-2g':
imageQuality = 'q_auto:low';
break;
default:
'q_auto:best';
break;
}
isQualitySet = true;
}
var fixWidth = "";
if(!tabletUP) != -1) {
fixWidth = ",w_170";
}
var fixedImg = "https://example.org/"+imageQuality+fixWidth+"/"+event.request.url;
var finalImageURL = new URL(fixedImg);
event.respondWith(
fetch(finalImageURL.href, { headers: event.request.headers })
);
}
}
);
app.js
if ('serviceWorker' in navigator) {
window.addEventListener('load', function() {
navigator.serviceWorker.register('/sw.js').then(function(registration) {
console.log('Service Worker registered! Scope: '+registration.scope);
}).catch(function(err) {
console.log('Service Worker registration failed: '+err);
});
});
}
because the service worker is running on it's own thread and not with the main thread of your website.
it's a bit like it would run server-side.
your images should get inside the service workers cache when they get loaded on your website. it's definitiv the wrong location for this check.

How can I play downloaded mp3 files with Xamarin.Forms iOS

I want to play mp3 files with the program that I will perform. I can play the file without downloading the files, but I can not play the file which I downloaded. Can you help me with this?
I am working on the Xamarin.Forms project. I download the mp3 file from the internet via API. But I can not figure out where the downloaded file is specifically registered. I share the codes that I wrote on the IOS layer and on the PCL side with you.
Note: I can check that the download is successful and check the download status.
Note2: I use Xam.Plugins.DownloadManager for the download.
The code that I wrote at the IOS layer.
public void SetDownloadPath()
{
CrossDownloadManager.Current.PathNameForDownloadedFile = new System.Func<IDownloadFile, string>(file =>
{
string fileName = (new NSUrl(file.Url, false)).LastPathComponent;
return Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments), fileName);
});
}
The code I wrote in ViewModel.
public async Task<DownloadItem> AddBookDownload(BookInfo _bookInfo)
{
var downloadItem = new DownloadItem
{
BookName = _bookInfo.Title,
DownloadID = _bookInfo.ID,
DistinctionCount = _bookInfo.SectionCount
};
var sections = await LibraryClient.GetBookSections(_bookInfo.ID);
downloadItem.Sections = sections.Data;
if (downloadItem.Sections == null || downloadItem.Sections.Count <0)
{
return null;
}
var linkFile =
CrossDownloadManager.Current.CreateDownloadFile(downloadItem.Sections.FirstOrDefault()
?.GetLink()
.ToString());
downloadItem.DownloadedTaskList.Add(linkFile.GetHashCode(), downloadItem);
linkFile.PropertyChanged += (sender, e) =>
{
// Update UI text-fields
var downloadFile = (IDownloadFile) sender;
switch (e.PropertyName)
{
case nameof(IDownloadFile.Status):
Device.BeginInvokeOnMainThread(() =>
{
downloadItem.DownloadState = downloadFile.Status;
Debug.WriteLine("Download Status: " + downloadFile.Status);
});
break;
case nameof(IDownloadFile.StatusDetails):
Device.BeginInvokeOnMainThread(() =>
{
Debug.WriteLine("Download Details: " + downloadFile.StatusDetails);
});
break;
case nameof(IDownloadFile.TotalBytesExpected):
Device.BeginInvokeOnMainThread(() =>
{
Debug.WriteLine("BytesExpected" + downloadFile.TotalBytesExpected);
});
break;
case nameof(IDownloadFile.TotalBytesWritten):
Device.BeginInvokeOnMainThread(() =>
{
Debug.WriteLine("BytesWritten" + downloadFile.TotalBytesWritten);
});
break;
}
// Update UI if download-status changed.
if (e.PropertyName == "Status")
switch (((IDownloadFile) sender).Status)
{
case DownloadFileStatus.COMPLETED:
downloadItem.DownloadState = DownloadFileStatus.COMPLETED;
DistinctionCount = downloadItem.DistinctionCount;
BookName = downloadItem.BookName;
DownloadedBooks.Add(downloadItem);
NativeServices.DownloadService.SaveDownloadsItem(downloadItem);
NativeServices.MediaPlayerService.PlayFromFile(Path.GetFileName(CrossDownloadManager.Current.PathNameForDownloadedFile.ToString()));
Debug.WriteLine("Download Completed");
break;
case DownloadFileStatus.FAILED:
downloadItem.DownloadState = DownloadFileStatus.FAILED;
Debug.WriteLine("Download Failed");
break;
case DownloadFileStatus.CANCELED:
Device.BeginInvokeOnMainThread(() => { Debug.WriteLine("Download Cancelled"); });
break;
}
// Update UI while donwloading.
if (e.PropertyName == "TotalBytesWritten" || e.PropertyName == "TotalBytesExpected")
{
var bytesExpected = ((IDownloadFile) sender).TotalBytesExpected;
var bytesWritten = ((IDownloadFile) sender).TotalBytesWritten;
if (bytesExpected > 0)
{
var percentage = Math.Round(bytesWritten / bytesExpected * 100);
Device.BeginInvokeOnMainThread(() => { Debug.WriteLine("Downloading" + percentage + "%"); });
}
}
};
CrossDownloadManager.Current.Start(linkFile);
return downloadItem;
}
You can find the Audio file Xamrin form sample on below URL :
Audio File Integration Xamarin Forms

firefox addon, how to modify(change) the url before the request is sent (even made) by the browser?

I want to remove some parameters in a url, currently my code:
require("sdk/tabs").on("ready", removeList);
function removeList(tab) {
var index = tab.url.indexOf("&list=");
if (tab.url.indexOf("youtube.com") > -1 && index > -1) {
console.log(tab.url);
var temp = tab.url.slice(0, index);
console.log(temp);
tab.url = "";
tab.url = temp;
}
}
But it will send two urls(requests) to the server, the original one (I can see the response without the video being played) and the truncated one(as expected).
Your two options are http-on-modify-request and http-on-opening-request. The first is fine, but the second fires earlier and you lose a lot of a ability. The first method the url is fine because server never sees it.
const { Ci, Cu, Cc, Cr } = require('chrome'); //const {interfaces: Ci, utils: Cu, classes: Cc, results: Cr } = Components;
Cu.import('resource://gre/modules/Services.jsm');
Cu.import('resource://gre/modules/devtools/Console.jsm');
var observers = {
'http-on-examine-response': {
observe: function (aSubject, aTopic, aData) {
console.info('http-on-modify-request: aSubject = ' + aSubject + ' | aTopic = ' + aTopic + ' | aData = ' + aData);
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
var requestUrl = httpChannel.URI.spec
var index = requestUrl.indexOf('&list=');
if (requestUrl.indexOf('youtube.com') > -1 && index > -1) {
console.log(requestUrl);
var temp = requestUrl.slice(0, index);
httpChannel.redirectTo(Services.io.newURI(temp, null, null));
}
},
reg: function () {
Services.obs.addObserver(observers['http-on-modify-request'], 'http-on-modify-request', false);
},
unreg: function () {
Services.obs.removeObserver(observers['http-on-modify-request'], 'http-on-modify-request');
}
}
};
or instead of the redirectTo line you can do httpChannel.cancel(Cr.NS_BINDING_ABORTED); than get that loadConext and change the url.
To start observing
To start start obseving all requests do this (for example on startup of your addon)
for (var o in observers) {
observers[o].reg();
}
To stop observing
Its important to stop observring (make sure to run this at least on shutdown of addon, you dont want to leave the observer registered for memory reasons)
for (var o in observers) {
observers[o].unreg();
}

Resources