Greasemonkey - Browser redirect - greasemonkey

So it's been a minute since I've used Greasemonkey scripts and I'm probably forgetting to do something basic but...
What I want to do is when ever I navigate to https://beta.crunchyroll.com to instead redirect me to https://beta.crunchyroll.com/simulcasts/seasons/spring-2021 and I think my current code should do that but isn't for some reason.
// ==UserScript==
// #name Crunchyroll Redirect
// #version 1
// #grant none
// #include http://*.crunchyroll.*/*
// #include https://*.crunchyroll.*/*
// ==/UserScript==
var current_location = content.document.location;
if(current_location == "https://beta.crunchyroll.com"){
window.location.replace("https://beta.crunchyroll.com/simulcasts/seasons/spring-2021")
}
So where did I mess up?

You can simplify the logic.
Since you only need to run it on https://beta.crunchyroll.com, there is no point on running it on other pages
#match is more robust than #include
Use #run-at to run at the earliest possible
Here is an example:
// ==UserScript==
// #name Crunchyroll Redirect
// #match *://beta.crunchyroll.com/*
// #version 1
// #grant none
// #run-at document-start
// ==/UserScript==
window.stop(); // stop loading
location.replace('https://beta.crunchyroll.com/simulcasts/seasons/spring-2021');

Related

SAPI 5 TTS Events

I'm writing to ask you some advices for a particular problem regarding SAPI engine. I have an application that can speak both to the speakers and to a WAV file. I also need some events to be aware, i.e. word boundary and end input.
m_cpVoice->SetNotifyWindowMessage(m_hWnd, TTS_MSG, 0, 0);
hr = m_cpVoice->SetInterest(SPFEI_ALL_EVENTS, SPFEI_ALL_EVENTS);
Just for test I added all events! When the engine speaks to speakers all events are triggered and sent to the m_hWnd window, but when I set output to the WAV file, none of them are sent
CSpStreamFormat fmt;
CComPtr<ISpStreamFormat> pOld;
m_cpVoice->GetOutputStream(&pOld);
fmt.AssignFormat(pOld);
SPBindToFile(file, SPFM_CREATE_ALWAYS, &m_wavStream, &fmt.FormatId(), fmt.WaveFormatExPtr());
m_cpVoice->SetOutput(m_wavStream, false);
m_cpVoice->Speak(L"Test", SPF_ASYNC, 0);
Where file is a path passed as argument.
Really this code is taken from the TTS samples found on the SAPI SDK. It seems a little bit obscure the part setting the format...
Can you help me in finding the problem? Or does anyone of you know a better way to write TTS to WAV? I can not use manager code, it should be better to use the C++ version...
Thank you very much for help
EDIT 1
This seems to be a thread problem and searching in the spuihelp.h file, that contains the SPBindToFile helper I found that it uses the CoCreateInstance() function to create the stream. Maybe this is where the ISpVoice object looses its ability to send event in its creation thread.
What do you think about that?
I adopted an on-the-fly solution that I think should be acceptable in most of the cases, In fact when you write speech on files, the major event you would be aware is the "stop" event.
So... take a look a the class definition:
#define TTS_WAV_SAVED_MSG 5000
#define TTS_WAV_ERROR_MSG 5001
class CSpeech {
public:
CSpeech(HWND); // needed for the notifications
...
private:
HWND m_hWnd;
CComPtr<ISpVoice> m_cpVoice;
...
std::thread* m_thread;
void WriteToWave();
void SpeakToWave(LPCWSTR, LPCWSTR);
};
I implemented the method SpeakToWav as follows
// Global variables (***)
LPCWSTR tMsg;
LPCWSTR tFile;
long tRate;
HWND tHwnd;
ISpObjectToken* pToken;
void CSpeech::SpeakToWave(LPCWSTR file, LPCWSTR msg) {
// Using, for example wcscpy_s:
// tMsg <- msg;
// tFile <- file;
tHwnd = m_hWnd;
m_cpVoice->GetRate(&tRate);
m_cpVoice->GetVoice(&pToken);
if(m_thread == NULL)
m_thread = new std::thread(&CSpeech::WriteToWave, this);
}
And now... take a look at the WriteToWave() method:
void CSpeech::WriteToWav() {
// create a new ISpVoice that exists only in this
// new thread, so we need to
//
// CoInitialize(...) and...
// CoCreateInstance(...)
// Now set the voice, i.e.
// rate with global tRate,
// voice token with global pToken
// output format and...
// bind the stream using tFile as I did in the
// code listed in my question
cpVoice->Speak(tMsg, SPF_PURGEBEFORESPEAK, 0);
...
Now, because we did not used the SPF_ASYNC flag the call is blocking, but because we are on a separate thread the main thread can continue. After the Speak() method finished the new thread can continue as follow:
...
if(/* Speak is went ok */)
::PostMessage(tHwn, TTS_WAV_SAVED_MSG, 0, 0);
else
::PostMessage(tHwnd, TTS_WAV_ERROR_MSG, 0, 0);
}
(***) OK! using global variables is not quite cool :) but I was going fast. Maybe using a thread with the std::reference_wrapper to pass parameters would be more elegant!
Obviously, when receiving the TTS messages you need to clean the thread for a next time call! This can be done using a CSpeech::CleanThread() method like this:
void CSpeech::CleanThread() {
m_thread->join(); // I prefer to be sure the thread has finished!
delete m_thread;
m_thread = NULL;
}
What do you think about this solution? Too complex?

L"To fix call CDXUTDialog::Init() first. See comments for details."

After calling callback function DXUTCreateDevice() error is being returned from DXUTgui.cpp assert checking. Assert says first call CDXUTDialog::Init() but where should i put it in WinMain() ?
Compare your DXUT client code to the content of EmptyProject and SimpleSample--assuming you are using the DXUT11 from GitHub.
The typical pattern is to create a global variable for CDXUTDialogResourceManager, and then call CDXUTDialog::Init from InitApp before you get a callback from DXUTCreateDevice
int WINAPI wWinMain( _In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nCmdShow )
{
// Enable run-time memory check for debug builds.
#ifdef _DEBUG
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// DXUT will create and use the best device
// that is available on the system depending on which D3D callbacks are set below
// Set DXUT callbacks
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( OnKeyboard );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackD3D11DeviceAcceptable( IsD3D11DeviceAcceptable );
DXUTSetCallbackD3D11DeviceCreated( OnD3D11CreateDevice );
DXUTSetCallbackD3D11SwapChainResized( OnD3D11ResizedSwapChain );
DXUTSetCallbackD3D11SwapChainReleasing( OnD3D11ReleasingSwapChain );
DXUTSetCallbackD3D11DeviceDestroyed( OnD3D11DestroyDevice );
DXUTSetCallbackD3D11FrameRender( OnD3D11FrameRender );
InitApp(); <-- // THIS IS WHERE DXUT GUI WIDGETS GET INITIALIZED, BEFORE THE WINDOW OR DEVICE IS CREATED
DXUTInit( true, true, nullptr ); // Parse the command line, show msgboxes on error, no extra command line params
DXUTSetCursorSettings( true, true );
DXUTCreateWindow( L"SimpleSample11" );
// Only require 10-level hardware, change to D3D_FEATURE_LEVEL_11_0 to require 11-class hardware
// Switch to D3D_FEATURE_LEVEL_9_x for 10level9 hardware
DXUTCreateDevice( D3D_FEATURE_LEVEL_10_0, true, 800, 600 );
DXUTMainLoop(); // Enter into the DXUT render loop
return DXUTGetExitCode();
}
Starting a new project using DXUT is not recommended. It's really intended only for maintaining existing code that has dependencies on DXUT while removing dependencies on D3DX11 and other legacy DirectX SDK content. The vast majority of DXUT's functionality is complete overkill for most applications. It's also buggy and really only intended for samples.

Userscript stopped working with #grant and causes issues without #grant

I've written an userscript for geocaching.com which switches the language automatically to a specified language (German), if English was set by an external app.
It worked fine until about 10 days ago, for no reason I could imagine.
If I remove #grant from the script, it works again, but causes several issues with the rest of the page.
Any #grant I tried, including none, breaks the script.
It's still working as it's supposed to do in Chrome. But I've already heard, Tampermonkey and Chrome are a little different than Greasemonkey on Firefox.
Any idea I can give a try is very welcome.
Here's the script:
// ==UserScript==
// #name c:geo LangFix Deutsch BETA
// #include https://www.geocaching.com/*/*/*
// #include https://www.geocaching.com/*/*
// #include https://www.geocaching.com/*
// #include https://www.geocaching.com
// #include http://www.geocaching.com/*/*/*
// #include http://www.geocaching.com/*/*
// #include http://www.geocaching.com/*
// #include http://www.geocaching.com
// #exclude http://www.geocaching.com/account/messagecenter
// #exclude https://www.geocaching.com/map/*
// #exclude https://www.geocaching.com/map
// #version 1.2
// #require http://ajax.googleapis.com/ajax/libs/jquery/1.7.2/jquery.min.js
// #grant GM_xmlhttpRequest
// ==/UserScript==
var TargetLink = $('a[href*="LocaleList$ctl04$uxLocaleItem"]');
var LanguageSwitch = $("div.LocaleText:contains('Choose Language')");
if (TargetLink.length && LanguageSwitch.length)
window.location.assign (TargetLink[0].href);
The main issue is that the href, that the script is trying to assign, is actually a javascript function. That is:
TargetLink[0].href has a value of javascript:__doPostBack('ctl00$uxLocaleList$uxLocaleList$ctl04$uxLocaleItem','').
Many browsers will still allow you to pass a javascript: URL to location.assign(), but Firefox has been restricting this practice of late. (See GM bug 2232, Firefox bug 1192821, etc.) This is especially true across sandboxes (#grant set to other than none).
A better practice is to click on such links by sending mouse event(s), see below.
Other minor issues with that script:
The #includes are overlapping, redundant, and possibly a performance drag. The #match statement, below, should be all you need.
Likewise, the #excludes can be condensed.
Some geocaching.com pages use a different structure for the language change mechanism. I added an extra selector to catch an additional scheme. (There is at least one more, rarer, scheme that is not caught by either script.)
Selector components like LocaleList$ctl04$uxLocaleItem are extremely brittle and liable to change on a whim. Avoid these as much as possible.
Under some circumstances, that site loads many iframes -- leading to jQuery errors on some of the frames. Use #noframes to block that and speed things up.
Given all that, this complete script should work much better for you than the old one did:
// ==UserScript==
// #name c:geo LangFix Deutsch BETA
// #match *://www.geocaching.com/*
// #exclude http://www.geocaching.com/account/messagecenter
// #exclude https://www.geocaching.com/map/*
// #version 2.0
// #require http://ajax.googleapis.com/ajax/libs/jquery/2.1.0/jquery.min.js
// #noframes
// #grant GM_xmlhttpRequest
// ==/UserScript==
var EnglishPageIndicator = $(".selected-language > a:contains(English)");
if (EnglishPageIndicator.length) {
var GermanLnk = $(
".language-selector > .language-list > ul > li > a:contains(Deutsch)," +
".LocaleList > .language-list > li > a:contains(Deutsch)"
);
//-- Don't try to assign a JS location! Click the link instead.
var clickEvent = document.createEvent('MouseEvents');
clickEvent.initEvent ("click", true, true);
GermanLnk[0].dispatchEvent (clickEvent);
}

With bookshelf.js, how do I update a model record atomically?

I have a one-to-many relationship with a JOB model and many TASK(s). I have a route for individual tasks, where I fetch the TASK model for display, and some data from its JOB model. When I request a TASK, I need to update the locked and a user_id fields, so I can lock the task and show who has it locked, so other users can't access that task view. Therefore, I need to be guaranteed the task has locked=0, and instantly update that field with a time stamp.
My current router code is:
var route_task = function(req, res, next) {
new Model.Task({id: req.params.id}).fetch(withRelated: ['jobs']})
.then(function(task) {
if (!task) {
res.status(404);
res.render('404_tpl');
return;
}
if (task.get('locked') !== 0) {
res.status(403);
res.render('403_tpl', {title: '403 - Access Denied - Task is locked'});
return;
}
else {
/* I would update it here, but there's a slim */
/* chance someone else can come in and select */
/* the task. */
}
/* .. I set some res.locals vals from my task here .. */
var jobs = task.related('jobs');
jobs.fetch().then(function(job) {
/* .. I set some res.local vals here from my jobs .. */
switch (task.get('task_type')) {
case 0:
res.render('task_alpha_tpl');
break;
/* ... */
}
});
})
}
When I hit my router for a particular task ID, I pretty much want to select * where tasks.id = id and locked = 0, and then set locked with the current timestamp, but, I need to be able to determine if the record with that ID didn't exist, or if it did, but was just locked.
I hope this makes sense. I'm coming from the C and PHP world, so I'm slowly learning async programming.
I think you should do it in a transaction I guess if you want the value not to change, I don't think you should use semaphore or other stuff in the client side to simulate a critical section or something in that mindset.
The general purpose solution for this problem is to run something in the form of:
UPDATE task SET locked=1,user=? WHERE job=? AND locked=0
And then check that the update actually modified at least one row.
If you're doing that in node.js, then I would do something like:
Tasks.forge().where({job: req.param('code'), locked:0}).save({locked:1},{method:"update"});

Browse a page with custom shortcut keys

I want to browse ragecollection.com site using the j and k keys [similar to 9gag.com or google reader] , the default is left right arrow which is not ideal when using a laptop ..
grease monkey script for firefox preffered.
You can't use greasemonkey/javascript to simulate the pressing of a key, as this would cause security problems. The approach in javascript would be to intercept a key press event and trigger the required action that would normally be triggered by a different key press.
To get you started, the following greasemonkey script intercepts g and h character presses on any page:
// ==UserScript==
// #name keytranslate
// #namespace ongar.org
// #description turns g or h keypress into left or right cursor press
// #include *
// ==/UserScript==
function keycheck(e)
{
if (e.keyCode == 71) // code for g
{
// trigger right-cursor event
}
else if (e.keyCode == 72) // code for h
{
// trigger left-cursor event
}
}
window.addEventListener('keydown', keycheck, true);

Resources