Skip navigation.

Fat R笔记……与减肥无关

Fat awful terrible Rubbish-bin

Posts tagged with "userJS"

一个可能有用的userjs...

,

嗯,虽然Opera不支持ActiveX控件,导致一些下载网站的“***专用下载地址”不能点,但通过UserJs还是可以把那个地址对应的URL挖出来……

这是我写的一个简单的UserJS,就是用来干这种事的。目前它只支持FlashGet和迅雷两种下载器的专用下载连接,但通过源代码很容易就可以添加对"超级旋风"之类的其它下载器的专用链接的支持。

它的工作方式很简单,"模拟"了一个ActiveXObject类以及一些相关的方法来欺骗浏览器,比如FlashGet就模拟了IsVersion2()和AddUrl()两个方法,并在AddUrl()方法中打开一个新的窗口,把url显示出来

我并没有限制这个UserJS的作用区域,因此直接野蛮地模拟ActiveXObject也许会带来一些副作用……

而对付迅雷采用的方法则是直接重写OnDownloadClick_Simple()方法。迅雷的下载url是这么写的
 <a href="#" thunderHref="thunder://****" thunderPid="00009"  onClick="return OnDownloadClick_Simple(this)" oncontextmenu="ThunderNetwork_SetHref(this)" class="a_tlan14b" >使用迅雷下载</a>

所以直接重写OnDownloadClick_Simple()方法并把连接中的thunderHref属性显示出来就可以了
然而这样的方法也有副作用,就是所有叫OnDownloadClick_Simple()的方法都会被干掉,不知道会不会有误伤……

以后有空再看看能不能加一些判断把代码弄得严谨一些吧……

下载地址
flashgetshowurl.js

Sina blog的用户评论问题and..Opera的bug?

, , ,

研究了一下,sina blog是用ajax来获取用户评论的,在ajax部分作了针对不同浏览器的处理,然而在将获取到的html代码输出到页面时有一句:
<a name="comment" style="display:none;"/>

这个代码的目的是利用name属性创建一个anchor,但根据w3c的标准元素的end tag是必须的,也就是说,这种的写法是不标准的,应该写成

有趣的是Opera对这种不标准的tag的处理。我做了两个sample:
http://files.myopera.com/Returner/blog/disappear.htm
http://files.myopera.com/Returner/blog/1disappear.htm
可以看到,相同的代码直接写在html中,opera是会把它显示出来的。但如果是用innerHTML来动态插入,opera就会把内容隐藏了……似乎A标签中的style="display:none;"在动态插入时对后面的元素起了作用?同样的代码的两种解释行为,不知道是不是Opera的bug。

然而在FireFox中,无论直接写进html中还是用innerHTML来插入,效果都是一致的。但在第一个sample中,A元素后边紧接着的是一个DIV,这个DIV没有显示出来。而第二个sample中则是一个TABLE,这个TABLE却显示出来了。这就是为什么FireFox下能看到sina blog的用户评论。

IE下两个sample的行为更加一致,什么都不会显示。但我没研究在IE中那些用户评论最终是怎么显示出来的。

至于解决的办法,自然还是UserJS。需要做的事情很简单,在innerHTML插入之前将A标签正则替换为
<a name="comment" style=" "></a>

这里我把style去掉了,因为在opera中如果这个tag的style是display:none,Opera是不会用它作为一个anchor的,这就不能用#comment跳转到评论的位置了。

由于opera.defineMagicVariable只能覆盖全局变量,经过考虑最后还是选择对base.js中的output函数动手。output函数就是将ajax获取到的代码用innerHTML插入到指定元素中的“最终输出函数”。

UserJS代码如下:
// ==UserScript==
// @name             Show user comments in sina blog
// @author           Returner
// @include          http://blog.sina.com.cn/u/*
// ==/UserScript==

opera.defineMagicFunction(
  'output',
  function (real, oThis, _sHtml, _box)
  { _sHtml = _sHtml.replace(/(<a\s[^>]+)display\:none;([^>]+)\/>/ig,"$1 $2></a>");  
    real.apply( oThis, arguments.slice(2) );}
);

或下载下面文件到Opera的UserJS目录
sinablogcomment.js

不过添加评论还是有点问题(尤其是使用代理服务器上网时),问题的根源在于验证码的图片没有及时更新,从而总是提示验证码错误。在不使用代理时刷多几次就好了,但使用代理时似乎总是刷新不了验证码图片,郁闷……



新浪可能修改过程序,原来的脚本会找不到新浪脚本里的output函数,于是real.apply时实际上会无限递归地调用自己,从而造成cpu占用率和内存占用率的飙升。
于是只好修改程序,直接把新浪的output函数写到脚本里。不过这样毕竟不是长久之计,新浪如果到时改了程序,脚本又要跟着改,只能算是暂时解决了问题……
新的脚本在这里:
sinablogcomment_v2.js

解决了autosave脚本的ajax caching问题

现在脚本应该能正常工作了。
昨天发现Opera Blog把no-cache写成nocache造成页面被浏览器缓存的bug,下午报告过去,晚上已经修正了(然而据说现在用的方法兼容性并不太好,但至少对我没什么影响了)

然而我的脚本还是有问题,使用load功能时load的页面仍然被缓存了(这样就无法load到最近保存的内容)。估计可能用javascript来Get页面的时候opera只是根据服务器返回的header来判断页面是否应该被缓存。google了一下ajax caching的问题,找到了几个解决办法:

最简单的,把GET请求改成POST请求:
req.open('POST', sURL);

关于GET和POST,这里有详细的解释:
http://www.w3.org/2001/tag/doc/whenToUseGet.html

还有一种方法也比较简单,就是在请求的URL中加上一个随机参数:
req.open( "GET", "xmlprovider.php?sid=" + Math.random());

这样浏览器就会因为每次URL不同而不会从缓存中读取页面了

对上面方法的一个改进是用timestamp代替那个随机参数:
function uncache(url){
  var d = new Date();
  var time = d.getTime();
  return url + ‘&time=’+time;
}
...
req.open( "GET", uncache(sURL));

*写成sURL + "&time=" + new Date().getTime();应该也可以

最后,我决定还是用第一种方案。虽然用POST来请求页面对我来说感觉有点怪(而且某些server可能不支持用POST获取页面),但与另外两种方法相比,它可以避免每次请求回来的页面都被缓存(以及被中间的proxy缓存)。


其它参考资料:
http://en.wikipedia.org/wiki/XMLHTTP
http://www.enja.org/david/?p=25
http://radio.javaranch.com/pascarello/2005/10/21/1129908221072.html
http://ajaxian.com/archives/ajax-ie-caching-issue

一个简单的UserJS

, ,

用于“过滤”http://divx.thu.cn/latest.php 输出。其实只是用不同颜色标示不同类型的rlz,目前区分的是internal、screener、tc/ts/cam等类别。代码如下:
// ==UserScript==
// @name             divx.thu.cn filter
// @version          1.00
// @author           Returner
// @namespace        http://my.opera.com/Returner
// @include          http://divx.thu.cn/latest.php*
// ==/UserScript==

/*Changelog:
 *  1.00: First version.
 */

function divxcolor() {
  var titleColors = {    //这些颜色是随便写的,巨丑
    internal: '#A08585',
    historic: '#A0A585',
    screener: '#B0A585',
    ts: '#707070',
    dummy: '#000000'
  };

  var blockColors = {    //三种类型:none表示不显示标题下面的block,ori表示不改变颜色,#xxxxxx表示用指定颜色显示
    //internal: '#ffeeee',
    internal: 'none',
    historic: 'none',
    //screener: 'ori',
    screener: 'none',
    ts: 'none',
    dummy: '#000000'
  };
  var dTables = document.getElementsByTagName("table");
  for (var i = 0, thisTab; thisTab = dTables[i]; i++){
    if (thisTab.getAttribute('id') == 'table14'){
      var URLText = thisTab.rows[0].cells[0].getElementsByTagName("a")[0].innerText;
      var tabType = 'normal';
      if(URLText)
        if (URLText.match(/\.iNT(ERNAL)?[\.\-]/)){
          tabType = 'internal';
        } else if (URLText.match(/\.19[0-8][\d][\.\-]/)){  //电影时间年份较早的rlz
          tabType = 'historic';
        } else if (URLText.match(/\.(DVDSCR)|(screener)[\.\-]/i)){
          tabType = 'screener';
        } else if (URLText.match(/\.((TS)|(TC)|(CAM)|(TELESYNC))+[\.\-]/i) ){
          tabType = 'ts';
        }

      if (tabType == 'normal'){
        thisTab.rows[0].cells[0].setAttribute('background','/images/001.jpg');
      } else{
        thisTab.rows[0].cells[0].setAttribute('background','');
        thisTab.rows[0].cells[0].setAttribute('bgColor',titleColors[tabType]);
        thisTab = dTables[++i];
        if(blockColors[tabType] == 'none'){
          thisTab.innerHTML = '';
        } else if(blockColors[tabType] == 'ori'){

        } else{
          thisTab.rows[0].cells[0].setAttribute('bgColor',blockColors[tabType]);
        }
        /*thisTab = dTables[++i];
        thisTab.setAttribute('bgColor',tagColors.intBlock1);
        thisTab.rows[1].cells[0].setAttribute('bgColor',tagColors.intBlock1);*/
      }
    }
  }
}
window.opera.addEventListener('AfterEvent.DOMContentLoaded',
  function (ev) {
    divxcolor();
  },
false);


Notes:
  * 在判断ts时,如果正则表达式用/.(TC)|(TS)|(CAM)|(TELESYNC)[.\-]/i,会把标题含有.tsxxxx.之类文本的也判断为真,改成/.((TS)|(TC)|(CAM)|(TELESYNC))+[.\-]/i就OK了。所以前面判断screener的严格来说不太完善

  * Opera下不支持thisTab.rows[0].cells[0].background,所以用DOM的方法thisTab.rows[0].cells[0].setAttribute('background','/images/001.jpg')

  * 获得单元格中的<A>标签可以用thisTab.rows[0].cells[0].all.tags["a"],Opera也支持,但这里还是用了W3C DOM的标准thisTab.rows[0].cells[0].getElementsByTagName("a")

  * 访问一个Object的属性,可以用object.property,也可以用object["property"]。这个程序访问titleColors和blockColors时用的是后者

  * 有空一定要多学学DOM的东西,目前为止我还是这方面的白痴……

继续完善 - My Opera Blog Enhancement

, ,

目前已有的功能:

  • 自动保存
  • 开启完整的7种字体尺寸
  • 自定义字体列表
  • 增加自定义表情
  • 编辑时可以用Tab键输入4个空格


截图:


AutoSave的使用方法:
  1. 需要对myoperaplus.js进行配置才能使用autosave功能。方法如下:
  2. 将myoperaplus.js放到你的User Javascript目录
  3. 登录MyOpera,去到自己blog主页
  4. 点击Add new post新增一篇文章,内容任意,然后保存
  5. 然后Opera会跳转到新增加的这篇文章。记下URL末尾的数字。如:http://my.opera.com/Returner/blog/show.dml/376890,数字就是376890
  6. 打开myoperaplus.js,找到
    var accountsConfig = '<account1%370000><account2%371000>';

    这一行,将account1替换成你的用户名,370000替换成上面那个数字(376890)。如果你只有一个账号,第二个<>可以删掉,即改成
    var accountsConfig = '<account1%376890>';

    这样的格式。修改完后保存退出。
  7. 重新启动Opera,试试新增或编辑一个Post,如果编辑框右下方出现了Preparing或者Ready,则表示AutoSave功能已经可以正常工作了
  8. 在编辑过程中,默认会每2分钟自动保存一次,可以修改myoperaplus.js里的autosaveInterval值来设置保存间隔
  9. 可以点击编辑界面左下方的Save标签,或者在编辑框中按Ctrl+Shift+S来手动保存


下载最新版:
myoperaplus.js

为My Opera增加自动保存功能的Userscript

, , , ...

My Opera的blog有个不爽的地方,就是没有autosave。昨晚就试过敲了一大段文字,结果不知道是敲得太快还是手抽筋还是脑抽筋,按到了ctrl+w,于是十几分钟的键盘便白敲了…… 然后只好心有余悸地开Ultraedit写,写完再c&amp;p到My Opera上面。想想又很不甘心,自己不久前才修改了一下那个BB Code灌水菜单,配合自己的CSS加了些东西,如果用其它编辑器那就算是白加了。于是为了挽回这一损失,我决定写一个实现autosave的userscript……

  写了一天,总算是写了一个:cool: 目前大概是能正常工作了吧,不过还没有进行足够的测试,功能也不够完善。实现的方法嘛,其实还是很简单滴。分两种情况,一是Edit post的时候。这时因为编辑的post已经存在于blog里面了,实现autosave,只需要在后台定时模拟一下sumit的动作就可以了;二是Add new post的时候,这种情况就稍微有点麻烦了。这时post还没有跑进blog里,而且如果像Edit post的时候那样模拟submit动作,每submit一次blog里面就会多出一篇post来。相信不会有人认为把那堆每隔几分钟诞生一篇的“草稿”逐篇删掉是写完一篇blog后的一种很有趣的放松活动吧。其实有一种理论上来说较为理想的解决方法,就是在以add new post方式submit了一次之后,获得生成的新post的id,此后的autosave都改为edit post的方式,保存到新post里。然而这里就不得不对着Opera狠狠地踩两脚了,因为他家的XMLHttpRequest对重定向的处理有问题,使得我的这个idea泡汤了……社区里也有人遇到了同样的问题,希望这个bug能快点修正吧……虽然可以采用更曲折更变态的方法去实现(比如,用一个特定的tag,提交后寻找具有这个tag的最新一篇文章,从而获取到文章ID……嗯,看起来非常地艰苦,所以暂时我没这么干的打算),但我决定还是盼一盼bug fix吧……

  既然理想的方法用不了,我就用了另外一种没那么变态的:在blog里面写一篇post access为private的文章,用它来作为new post时autosave的存储空间。这样new post时进行autosave,就是以edit post的提交方式对那篇文章进行修改。由于那篇文章的命运已经被锁定为autosave的终身缓冲区,为了不让人见到它会产生修改的冲动,便又在写入它的时候对写进去的东西进行了一定的格式化。同时,为了方便add new post时发生意外后恢复保存的内容,又写了一个load函数——于是这个脚本的功能被我越整越啰嗦了。

  嗯,因为要完善的地方还有很多,所以暂时不把脚本放出来,测试几天再说……