// ==UserScript==
// @name View image links
// @namespace http://gaia.freera.net/~horance/userscripts/
// @description generate album view for image links. all button has access key (the first letter).
// @include http://www.wretch.cc/album/album.php*
// @include http://*diggirl.net/*detail.jsp*
// @include http://photo.xuite.net/*/*
// @include http://www.pixnet.net/album/*
// @include http://album.blog.yam.com/*&folder=*
// ==/UserScript==
// $Author$
(function(){
const MY_NAME = 'View image links';
const MY_NAMESPACE = 'http://gaia.freera.net/~horance/userscripts/';
const UPDATE_URL = 'https://opensvn.csie.org/MirrorScripts/userscripts/view.image.links.user.js';
const FILTER_URL = 'https://opensvn.csie.org/MirrorScripts/userscripts/view.image.links.filter.js';
checkUpdate();
/*
* see https://opensvn.csie.org/traccgi/MirrorScripts/trac.cgi/log/userscripts/view.image.links.user.js for change logs.
*/
var EMPTY_FEED_XML = '';
// PicLens API URL
//var PICLENS_API_URL = 'http://fundnav.googlepages.com/piclens.js';
var PICLENS_API_URL = 'http://lite.piclens.com/current/piclens.js';
loadPicLensAPI();
// filter map
var filterMap = {};
// current matched url regex
var currentMatch = '';
// filter
var filter = defaultFilter;
//filtering links
var urls = new Array();
//preload 5 images by default. if i == 0, this will load 0,1,2 elements in urls array.
//if i == 2, then 0,1,2,3,4 will be pre-loaded
var preload = 5;
//refresh url
urls = refreshURLs();
var piclensfeeddata = generateFeedDataForPicLens(urls);
//current edit
var curEdit = 1;
//initialize cache
if(preload % i == 0){
preload ++;
}
//current image index
var i = 0;
var c_url = '';
var c_desc = '';
var c_link = '';
if(urls[i]){
c_url = urls[i].src;
c_desc = urls[i].desc;
c_link = urls[i].link?urls[i].link:urls[i].src;
}
// HTML injection ;)
var div = document.createElement('div');
div.innerHTML = '
';
document.body.insertBefore(div, document.body.firstChild);
// get object references
var img = _gel('vil_img');
var btn_prev = _gel('vil_prev');
var btn_next = _gel('vil_next');
var btn_top = _gel('vil_top');
var btn_end = _gel('vil_end');
var btn_jump = _gel('vil_jump');
var btn_del = _gel('vil_del');
var vil_fit = _gel('vil_fit');
var ctrl = _gel('vil_control');
var disp = _gel('vil_display');
var conf = _gel('vil_config');
var text_input = _gel('vil_input');
var text_width = _gel('vil_width');
var text_fg = _gel('vil_fg');
var text_bg = _gel('vil_bg');
var text_regex = _gel('vil_regex');
var text_filter = _gel('vil_filter');
var vil_list = _gel('vil_list');
var vil_style = _gel('vil_style');
var link_href = _gel('vil_url');
var radio_filter = _gel('radio_filter');
var radio_style = _gel('radio_style');
var disp_image = _gel('vil_image');
// main function to refresh config and URLs
function refreshURLs(){
//load filters
filterMap = loadFilterMap();
//get filter
filter = getFilter();
//execute filter
return getURLs();
}
//function to load filter map by GM_getValue
function loadFilterMap(){
var filterSrc = GM_getValue('filters', 'no filter defined');
if(filterSrc != 'no filter defined'){
try {
eval( 'var tmpMap = ' + filterSrc );
return tmpMap;
} catch (err){
GM_log(filterSrc);
alert('error parsing filter config! ' + err);
// return empty map
return {};
}
} else {
return {};
}
}
//get current filter by matching current window.location.href
function getFilter(){
//filter loaded, matching document.location
var loc = window.location.href;
for( key in filterMap ){
var regex = new RegExp(key, 'ig');
if(regex && loc.match(regex)){
filter = filterMap[key];
currentMatch = key;
return filter;
}
}
}
//exec filter to get URLS
function getURLs(){
//get urls
if(filter){
urls = filter();
//invalid return
if(!urls || 'object' != typeof urls){
alert('invalid return from filter function:' + urls);
//fallback to default
urls = defaultFilter();
}
} else {
urls = defaultFilter();
}
if('string' == typeof urls[0]){
for(var i=0;i img.height){
if(img.width > w){
img.height = Math.round(w/img.width*img.height);
img.width = w;
}
}
}
if(f == 'h' || f == 'b'){
if(f != 'b' || img.height > img.width){
if(img.height > w){
img.width = Math.round(w/img.height*img.width);
img.height = w;
}
}
}
if(f == 'n'){
//reset inmage size
img.removeAttribute('width');
img.removeAttribute('height');
}
}else{
alert('invalid width: '+text_width);
}
preloadImage();
setButtons();
}
function MM_preload() { //v2.1 (OSL)
if (document.images) {
var imgFiles = MM_preload.arguments;
if (document.preloadArray==null) document.preloadArray = new Array();
document.preloadArray.length = imgFiles.length;
var i = document.preloadArray.length;
with (document) for (var j=0; j0?(i-size):0;
var end = (i+size > urls.length)?urls.length:i+size;
var str = '';
for(var j = start;j= urls.length){
alert('Invalid input: no such image');
}else{
i = idx;
showImage();
}
}
//prev image
function prev(){
i--;
if(i<0){
alert('This is the first picture!');
}else{
showImage();
}
}
//next image
function next(){
i++;
if(i >= urls.length){
alert('This is the last picture!');
}else{
showImage();
}
}
// first image
function top(){
i=0;
showImage();
}
// last image
function end(){
i=urls.length-1;
showImage();
}
// show display panel
function show(){
if(urls.length==0){
alert('no image links!');
return;
}
ctrl.style.display = 'none';
disp.style.display = 'block';
}
// hide display panel
function hide(){
ctrl.style.display = 'block';
disp.style.display = 'none';
}
// toggle config panel
function toggle(tid, flag){
var obj = _gel(tid);
if(obj){
if(flag){
obj.style.display = flag;
}else{
if(obj.style.display != 'none'){
obj.style.display = 'none';
}else{
obj.style.display = '';
}
}
}
}
//show image!
function showImage(){
if(urls[i]){
c_url = urls[i].src;
c_desc = urls[i].desc;
link_href.href=c_url;
link_href.innerHTML=loadingimg+' loading......';
//reset image size
img.removeAttribute('width');
img.removeAttribute('height');
//load image
img.src=c_url;
img.alt=c_desc;
}
}
// set navigation button state
function setButtons(){
text_input.value=i;
btn_top.disabled = false;
btn_prev.disabled = false;
btn_next.disabled = false;
btn_end.disabled = false;
if(i<=0){
btn_top.disabled = true;
btn_prev.disabled = true;
}
if(i>=urls.length-1){
btn_next.disabled = true;
btn_end.disabled = true;
}
}
// prepare config list
function prepareConfigList(){
var label1 = 'URL Regex: ';
var label2 = 'Filter function:';
var label3 = 'New Filter';
var selectedValue = currentMatch;
var dataMap = filterMap;
if(curEdit == 2){
label1 = 'CSS Name : ';
label2 = 'CSS Style:';
label3 = 'New Style';
selectedValue = cssName;
dataMap = cssMap;
}
text_regex.previousSibling.nodeValue = label1;
text_filter.previousSibling.previousSibling.nodeValue = label2;
var tmpstr = '';
for(key in dataMap){
tmpstr += '';
}
vil_list.innerHTML = tmpstr;
listChange();
var ac = GM_getValue('checkInterval','1');
var isac = (parseInt(ac) > 0);
_gel('vil_autocheck').checked = isac;
_gel('vil_ac_int').value = (isac?ac:'1');
toggle('vil_ac_config', (isac?'block':'none'));
}
// update UI, call by event listener
function listChange(){
var isFilter = (curEdit == 1);
var dataMap = (isFilter)?filterMap:cssMap;
var def_value = (isFilter)?defaultFilter.toString():defaultStyle;
var key = vil_list.value;
if(key == '--'){
btn_del.disabled = true;
key = (isFilter?'^.*foo\\.bar\\.com.*$':'default');
}else{
btn_del.disabled = false;
}
text_regex.value = key;
text_filter.value = (dataMap[key])?dataMap[key].toString():def_value;
if(!isFilter){
changeStyle(key);
}
}
//save CSS or filter config
function saveData(){
//check auto-update setting
var ac = _gel('vil_autocheck').checked;
if(ac){
var days = parseInt(_gel('vil_ac_int').value);
if(isNaN(days) || days < 1){
alert('invalid check interval! (must be an integer and > 0)');
_gel('vil_ac_int').focus();
return;
}else{
GM_setValue('checkInterval',''+days);
}
}else{
GM_setValue('checkInterval','-1');
}
var dataMap = filterMap;
var dataValue = null;
var saveTag = 'filters';
var refreshFunction = refreshURLs;
if(curEdit == 1){ // filter
try {
//test URL Regexp
new RegExp(text_regex.value);
//test filter code
eval('var f = ' + text_filter.value);
if( 'function' != typeof f ){
throw 'invalid filter function';
} else { //check return
var us = f();
if( 'object' != typeof us ){
throw 'invalid return from filter: '+us;
}
}
dataValue = f;
}catch(ex){
alert('error parsing URL Pattern or filter: ' + ex);
return false;
}
}else if(curEdit == 2){
saveTag = 'styleMap';
dataMap = cssMap;
dataValue = text_filter.value;
refreshFunction = reloadStyle;
}
//all passed, store filter
dataMap[text_regex.value] = dataValue;
//save filterMap
GM_setValue(saveTag, serializeMap(dataMap));
//reload
refreshFunction();
//tell user we've done
alert('data saved!');
//reset config list
prepareConfigList();
}
//delete CSS or filter
function deleteData(){
var dataMap = filterMap;
var saveTag = 'filters';
var refreshFunction = refreshURLs;
var confirmStr = 'Delete filter for ';
if(curEdit == 2){
saveTag = 'styleMap';
dataMap = cssMap;
refreshFunction = reloadStyle;
confirmStr = 'Delete style: ';
}
if(confirm(confirmStr + text_regex.value + ' ?')){
//there no way to remove value from map, instead we set it to null,
// and skip it in function serializeMap()
dataMap[text_regex.value] = null;
//save
GM_setValue(saveTag, serializeMap(dataMap));
//reload
refreshFunction();
//reset config list
prepareConfigList();
}
}
//convert filter config to String
function serializeMap(map){
var res = '{';
for(key in map){
if(map[key]){
var mapValue = map[key];
if(curEdit == 2){
mapValue = '"' + map[key].replace(/\n/mg,'\\n').replace(/\r/mg,'\\r') + '"';
}
res+=('"' + key + '" : ' + mapValue + ',');
}
}
res += '}';
return res;
}
//change panel color
function changeColor(){
disp.style.color = text_fg.value;
disp.style.backgroundColor = text_bg.value;
}
//addGlobalStyle -- derived from http://diveintogreasemonkey.org/patterns/add-css.html
function addGlobalStyle(css) {
var head, style;
head = document.getElementsByTagName('head')[0];
if (!head) { return; }
style = document.createElement('style');
style.type = 'text/css';
style.innerHTML = css;
head.appendChild(style);
return style;
}
//register event listener for click
document.addEventListener('click', function(event) {
if(event.target.name && event.target.name.match(/^vil/)){
if(event.target.name == 'vil_next'){
next();
}else if(event.target.name == 'vil_prev'){
prev();
}else if(event.target.name == 'vil_show'){
show();
}else if(event.target.name == 'vil_piclens'){
startPicLensLite();
}else if(event.target.name == 'vil_hide'){
hide();
}else if(event.target.name == 'vil_top'){
top();
}else if(event.target.name == 'vil_end'){
end();
}else if(event.target.name == 'vil_jump'){
jumpto();
}else if(event.target.name == 'vil_color'){
changeColor();
}else if(event.target.name == 'vil_conf'){
toggle('vil_download_panel','none');
prepareConfigList();
toggle('vil_config');
}else if(event.target.name == 'vil_save'){
saveData();
}else if(event.target.name == 'vil_del'){
deleteData();
}else if(event.target.name == 'vil_download'){
toggle('vil_config','none');
prepareFileList();
toggle('vil_download_panel');
}else if(event.target.name == 'vil_browse'){
browseOutputFolder();
}else if(event.target.name == 'vil_start'){
startDownload();
}else if(event.target.name == 'vil_autocheck'){
var ac = _gel('vil_autocheck').checked;
toggle('vil_ac_config', (ac?'block':'none'));
}else if(event.target.name == 'vil_checknow'){
var ac = _gel('vil_checknow').checked;
checkUpdate(true);
}
}
}, true);
function handleError(event, imgobj, idx){
GM_log('error loading img:'+imgobj.src + "current idx: "+idx);
}
//register event listener for img.onload
img.addEventListener('load', function(event){
resize();
}, true);
img.addEventListener('error', function(event){
handleError(event, this, i);
}, true);
//register event listener for select.onchange
vil_list.addEventListener('change', function(event){
listChange();
}, true);
//register event listener for select.onchange
vil_style.addEventListener('change', function(event){
changeStyle(vil_style.value);
}, true);
//register event listener for select.onchange
vil_fit.addEventListener('change', function(event){
resize();
}, true);
//register event listener for radio.onchange
radio_filter.addEventListener('click', function(event){
curEdit = 1;
prepareConfigList();
}, true);
//register event listener for radio.onchange
radio_style.addEventListener('click', function(event){
curEdit = 2;
prepareConfigList();
}, true);
//loading animation icon
const loadingimg = '
';
const defaultStyle = '#vil_control {\n' +
' position: absolute;\n' +
' right: 0px;\n' +
' top: 0px;\n' +
'}\n' +
'div.vil {\n' +
' margin: 5px;\n' +
' padding: 10px;\n' +
' z-index: 999;\n' +
' background-color: #E5ECF9;\n' +
'}\n' +
'.vil, div.vil > input, div.vil > p > textarea , div.vil > p > select, div.vil > p > input {\n' +
' color: black;\n' +
' font-style: normal;\n' +
' font-weight: 400;\n' +
' font-size: 13px;\n' +
' font-family: arial;\n' +
'}\n' +
'div.vil > p > textarea, #vil_flist {\n' +
' width: 285px;\n' +
'}\n' +
'#vil_style {\n' +
' width: 50px;\n' +
'}\n' +
'div.vil > p > select {\n' +
' width: 225px;\n' +
'}\n' +
'#vil_del {\n' +
' color: red;\n' +
' margin-left: 5px;\n' +
' width: 50px;\n' +
'}\n' +
'#vil_regex {\n' +
' margin: 5 0 5 0;\n' +
' vertical-align: middle;\n' +
' width: 210px;\n' +
'}\n' +
'#vil_save, #vil_start {\n' +
' position: absolute;\n' +
' right: 15px;\n' +
'}\n' +
'#vil_url > img {\n' +
' margin-right: 5px;\n' +
' border: 0px;\n' +
' vertical-align: middle;\n' +
'}\n' +
'#vil_img {\n' +
' margin-top: 5px;\n' +
'}\n';
//setting up style
function reloadStyle(){
cssMap = loadStyleMap();
cssName = GM_getValue('style', 'default');
var cssStyleStr = defaultStyle;
if(cssMap[cssName]){
cssStyleStr = cssMap[cssName];
}
setStyle(cssStyleStr);
//reset style list
var tmpStr = '';
for(key in cssMap){
tmpStr += '';
}
vil_style.innerHTML = tmpStr;
}
// set current style
function setStyle(cssStyleStr){
if(cssStyleElement){
cssStyleElement.innerHTML = cssStyleStr;
}else{
cssStyleElement = addGlobalStyle(cssStyleStr);
}
}
//load style map with GM_getValue();
function loadStyleMap(){
var styleSrc = GM_getValue('styleMap', 'no style defined');
if(styleSrc != 'no style defined'){
try {
eval( 'var tmpCSSMap = ' + styleSrc );
return tmpCSSMap;
} catch (err){
GM_log(styleSrc);
alert('error parsing CSS config! ' + err);
// return empty map
return {};
}
} else {
return {};
}
}
//change style - called by event listener
function changeStyle(key){
if(cssMap[key]){
cssName = key;
setStyle(cssMap[cssName]);
GM_setValue('style', cssName);
}
}
//add for PicLens support
function parseXMLtoDOM(xmlstring){
var parser = new DOMParser();
try{
return parser.parseFromString(xmlstring, 'application/xml');
}catch(err){
GM_log('error parsing xml, reason:'+err);
}
}
/**
* using current imgage url object, attributes are:
* src: image url (required)
* desc: description text of the image (optional, using image url if empty),
* thumburl: thumbnail image url (optional, using image url if empty),
* link: link url (optional, using image url if empty)
**/
function generateFeedDataForPicLens(turls){
if(!turls || turls.length == 0){
return false;
}
var feedxml = parseXMLtoDOM(EMPTY_FEED_XML);
var channelNode = feedxml.documentElement.firstChild;
for(i=0;i tag ...');
var head = document.getElementsByTagName('head')[0];
if(!head){ // head element not found ?!
head = document.createElement('head');
document.documentElement.insertBefore(head,document.body);
}
var stag = document.createElement('script');
stag.setAttribute('type', 'text/javascript');
stag.setAttribute('src', PICLENS_API_URL);
head.appendChild(stag);
}
}
// start!
function startPicLensLite(){
if (typeof unsafeWindow.PicLensLite == 'undefined'){
GM_log('PicLensLite object not found, waiting ...');
window.setTimeout(startPicLensLite, 1000);
}else{
var hasClient = unsafeWindow.PicLensLite.hasClient();
GM_log('PicLensLite.hasPicLensClient() = '+hasClient);
var temprss = false;
if(!piclensfeeddata && urls.length > 0){
//regenerate feed data
piclensfeeddata = generateFeedDataForPicLens(urls);
}
if(hasClient && (temprss = writeTempFeedFile(piclensfeeddata)) ){
unsafeWindow.PicLensLite.start({feedUrl:temprss});
}else{
var feedtext = serializeXMLtoString(piclensfeeddata);
unsafeWindow.PicLensLite.start({feedData:feedtext});
}
}
}
//serialize XML to String
function serializeXMLtoString(xmldoc){
var se = new XMLSerializer();
return se.serializeToString(xmldoc);
}
//thanks to tiddly wiki source..:p
function writeTempFeedFile(feeddata){
var filePath;
try{
unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
filePath = writeToFile(manualConvertUnicodeToUTF8(serializeXMLtoString(feeddata)), null, 'gm_vil_temp_rss.xml');
}catch(ex){
alert("Oops! I can't create temp feed file for PicLens extension,\n"+
"I will use Lite version instead...\n"+
"you can set \"signed.applets.codebase_principal_support\" = true in \"about:config\""
+"to avoid this problem.");
GM_log("error creating file:"+filePath+", reason:"+ex);
}
return filePath;
}
function writeToFile(content, outputPath, fname){
var filePath;
if(Components) {
// ask user permission
//unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
var fileObj;
if(!outputPath){
// get home directory
fileObj= Components.classes["@mozilla.org/file/directory_service;1"]
.getService(Components.interfaces.nsIProperties)
.get("Home", Components.interfaces.nsILocalFile);
}else{
fileObj = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
fileObj.initWithPath(outputPath);
}
// append file name
fileObj.append(fname);
// file is nsIFile
var ios = Components.classes["@mozilla.org/network/io-service;1"]
.getService(Components.interfaces.nsIIOService);
var fileHandler = ios.getProtocolHandler("file")
.QueryInterface(Components.interfaces.nsIFileProtocolHandler);
filePath = fileHandler.getURLSpecFromFile(fileObj);
// get file:// URL
GM_log("filePath:"+filePath);
if(!fileObj.exists())
//0 for File, 0600 is permission
fileObj.create(0,0600);
//prepare output stream
var out = Components.classes["@mozilla.org/network/file-output-stream;1"]
.createInstance(Components.interfaces.nsIFileOutputStream);
out.init(fileObj,0x20|0x02,00004,null);
//it's very strange that the PicLens extension refuse to load feed which contains UTF-8 chinese character,
//manualConvertUnicodeToUTF8 will convert unicode character to nnnn notation.
out.write(content,content.length);
out.flush();
out.close();
return filePath;
}
return false;
}
//using XPCOM converter service
function mozConvertUnicodeToUTF8(s)
{
//unsafeWindow.netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");
try {
var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"].createInstance(Components.interfaces.nsIScriptableUnicodeConverter);
converter.charset = "UTF-8";
} catch(ex) {
GM_log("error convert from mozConvertUnicodeToUTF8:"+ex);
return manualConvertUnicodeToUTF8(s);
} // fallback
var u = converter.ConvertFromUnicode(s);
var fin = converter.Finish();
return fin.length > 0 ? u + fin : u;
}
//convert unicode to nnnnn;
function manualConvertUnicodeToUTF8(s)
{
var re = /[^\u0000-\u007F]/g ;
return s.replace(re,function($0) {return "" + $0.charCodeAt(0).toString() + ";";});
}
//
function downloadFile(httpLoc, outputFolder, localfile, listener, flag) {
try {
//new obj_URI object
var obj_URI = Components.classes["@mozilla.org/network/io-service;1"].getService(Components.interfaces.nsIIOService).newURI(httpLoc, null, null);
//new file object
var obj_TargetFile = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
//set file with path
obj_TargetFile.initWithPath(outputFolder);
obj_TargetFile.append(localfile);
//if file doesn't exist, create
if(!obj_TargetFile.exists()) {
obj_TargetFile.create(0x00,0644);
}
//new persitence object
var obj_Persist = Components.classes["@mozilla.org/embedding/browser/nsWebBrowserPersist;1"].createInstance(Components.interfaces.nsIWebBrowserPersist);
obj_Persist.persistFlags = Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_REPLACE_EXISTING_FILES;
obj_Persist.persistFlags |= Components.interfaces.nsIWebBrowserPersist.PERSIST_FLAGS_AUTODETECT_APPLY_CONVERSION;
if(flag){
obj_Persist.persistFlags |= flag;
}
//save file to target
obj_Persist.progressListener = (listener?listener:defaultProgressListener);
obj_Persist.saveURI(obj_URI,null,null,null,null,obj_TargetFile);
} catch (e) {
alert(e);
}
}
function prepareFileList(){
var obj = _gel('vil_flist');
var opts = obj.options;
for(var j=0;j' + urls[j].desc + '\n';
}
idxdata += '