Search found 14 matches for userscript

[Userscript] 10wallpaper downloader

Diễn đàn: UserscriptTrả lời: 0Lượt xem: 667

 10.06.17 22:38

Tải hình nền từ 10wallpaper.com chỉ với 1-Click. Có thể chọn độ phân giải cố định để tải xuống.

Demo


Topics tagged under userscript on DEVs forumvi 10wall10
Tải hình nền từ 10wallpaper

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/19854-10wallpaper-downloader
  2. https://openuserjs.org/scripts/baivong/10wallpaper_downloader
  3. https://github.com/baivong/Userscript/raw/master/10wallpaper_downloader/10wallpaper_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        10wallpaper downloader
// @namespace    http://baivong.github.io/
// @version      2.1.2
// @description  1-Click download on 10wallpaper. You should select the resolution before downloading.
// @icon        http://i.imgur.com/08zfJez.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://10wallpaper.com/*
// @match        http://www.10wallpaper.com/*
// @match        https://10wallpaper.com/*
// @match        https://www.10wallpaper.com/*
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM.openInTab
// @grant        GM_openInTab
// ==/UserScript==

(function () {
    'use strict';

    /**
    * Resolution config
    * @type {String} // Eg: 1920x1200, 1366x768, 1280x1024, ...
    */
    var resolution = '';


    // Do not change the code below this line, unless you know how.
    var list = document.querySelectorAll('a[href^="/view/"]'),
        res = location.pathname.match(/\d+x\d+/);
    if (!/\d+x\d+/.test(resolution)) resolution = screen.width + 'x' + screen.height;
    res = !res ? resolution : res[0];

    [].forEach.call(list, function (link) {
        var info = link.querySelector('span'),
            infoContent = info.innerHTML,
            img = link.querySelector('img'),
            imgName;

        if (!img) return;
        img = img.src.replace(/(\/|_)(small|medium)(\/|\.)/g, '$1' + res + '$3');
        imgName = img.replace(/.*\//, '');

        link.addEventListener('click', function (e) {
            e.preventDefault();
            info.innerHTML = 'Downloading...';

            GM.xmlHttpRequest({
                method: 'GET',
                url: img,
                responseType: 'blob',
                onprogress: function (e) {
                    var percent = Math.round((e.loaded / e.total) * 100);
                    info.innerHTML = percent + ' %';
                },
                onload: function (response) {
                    var blob = response.response;

                    info.innerHTML = infoContent;
                    link.setAttribute('href', URL.createObjectURL(blob));
                    link.setAttribute('download', imgName);

                    saveAs(blob, imgName);
                },
                onerror: function (err) {
                    console.error(err);
                }
            });
        });

        link.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            GM.openInTab(img);
        });

        link.setAttribute('title', 'Click to download this image\nRight Click to open in new tab');
    });
})();


Hướng dẫn


Thông thường trang 10wallpaper sẽ tự thiết lập độ phân giải (resolution) tương ứng với thiết bị của bạn. Tuy nhiên, bạn có thể thay đổi bằng cách chỉnh tham số resolution trong mã nguồn, dòng 33.
Nhấn chuột vào ảnh để download.
Nhấn chuột phải để mở ảnh trong cửa sổ mới.
Tags: #userscript #download #photo #10wallpaper

[Userscript] Wallpaperscraft downloader

Diễn đàn: UserscriptTrả lời: 0Lượt xem: 650

 10.06.17 22:17

Tải hình nền từ wallpaperscraft.com chỉ với 1-Click. Có thể chọn độ phân giải cố định để tải xuống.

Demo


Topics tagged under userscript on DEVs forumvi Wallpa10
Tải hình nền từ Wallpaperscraft

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/19843-wallpaperscraft-downloader
  2. https://openuserjs.org/scripts/baivong/Wallpaperscraft_downloader
  3. https://github.com/baivong/Userscript/raw/master/wallpaperscraft_downloader/wallpaperscraft_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        Wallpaperscraft downloader
// @namespace    http://baivong.github.io/
// @version      2.1.2
// @description  1-Click download on Wallpaperscraft. You should select the resolution before downloading.
// @icon        http://i.imgur.com/NA96TWE.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @include      https://wallpaperscraft.com/*
// @exclude      https://wallpaperscraft.com/wallpaper/*
// @exclude      https://wallpaperscraft.com/download/*
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM.openInTab
// @grant        GM_openInTab
// ==/UserScript==

(function () {
    'use strict';

    /**
    * Resolution config
    * @type {String} // Eg: 1920x1200, 1366x768, 1280x1024, ...
    */
    var resolution = '';


    // Do not change the code below this line, unless you know how.
    var list = document.querySelectorAll('.wallpapers__link');
    if (!/\d+x\d+/.test(resolution)) resolution = screen.width + 'x' + screen.height;

    [].forEach.call(list, function (link) {
        var info = link.querySelector('.wallpapers__info'),
            infoContent = info.innerHTML,
            img = link.querySelector('img'),
            imgName,
            res;

        res = !info ? resolution : info.textContent.match(/\d+x\d+/)[0];

        if (!img) return;
        img = img.src.replace(/\d+x\d+/, res);
        imgName = img.replace(/.*\//, '');

        link.addEventListener('click', function (e) {
            e.preventDefault();
            info.innerHTML = 'Downloading...';

            GM.xmlHttpRequest({
                method: 'GET',
                url: img,
                responseType: 'blob',
                onprogress: function (e) {
                    var percent = Math.round((e.loaded / e.total) * 100);
                    info.innerHTML = percent + ' %';
                },
                onload: function (response) {
                    var blob = response.response;

                    info.innerHTML = infoContent;
                    link.setAttribute('href', URL.createObjectURL(blob));
                    link.setAttribute('download', imgName);

                    saveAs(blob, imgName);
                },
                onerror: function (err) {
                    console.error(err);
                }
            });
        });

        link.addEventListener('contextmenu', function (e) {
            e.preventDefault();
            GM.openInTab(img);
        });

        link.setAttribute('title', 'Click to download this image\nRight Click to open in new tab');
    });
})();


Hướng dẫn


Chọn độ phân giải (resolution) từ menu bên phải trước khi download, hoặc chỉnh tham số resolution trong mã nguồn, dòng 32.
Nhấn chuột vào ảnh để download.
Nhấn chuột phải để mở ảnh trong cửa sổ mới.
Tags: #userscript #download #photo #wallpaperscraft

[Userscript] Anti Social Locker

Diễn đàn: UserscriptTrả lời: 0Lượt xem: 876

 10.06.17 20:36

Loại bỏ các widget ép buộc like và share để xem nội dung. Đôi lúc script không hoạt động, bạn hãy tải lại trang và thử lại.

Demo


Topics tagged under userscript on DEVs forumvi Unlock11
Mở khóa nội dung bị ẩn bởi Social Locker for jQuery

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/21137-anti-social-locker
  2. https://openuserjs.org/scripts/baivong/anti_social_locker
  3. https://github.com/baivong/Userscript/raw/master/anti_social_locker/anti_social_locker.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        anti social locker
// @namespace    http://baivong.github.io/
// @description  Anti social locker plugin required user like or share before viewing content. If script doesn't work, please refresh the page to rebuild the cache and try again.
// @version      1.0.3
// @icon        http://i.imgur.com/nOuUrIW.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://*/*
// @match        https://*/*
// @noframes
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-start
// @grant        none
// ==/UserScript==

(function (global) {
    'use strict';

    function antiSocialLocker() {

        // Panda Lockers (https://codecanyon.net/item/optin-panda-for-wordpress/10224279)
        // Social Locker for Wordpress (https://codecanyon.net/item/social-locker-for-wordpress/3667715)
        (function () {
            if (!document.querySelectorAll('.onp-sl-content').length && !document.querySelectorAll('[data-lock-id]').length && !document.querySelectorAll('[data-locker-id]').length) return;
            if (document.getElementById('anti_social_locker') !== null) return;

            var css = '.onp-sl-content,[data-lock-id],[data-locker-id]{display:block!important}.onp-sl,.onp-sl-transparence-mode,.onp-sl-overlap-box,[id^="content-locker"]{display:none!important}.onp-sl-blur-area{filter:none!important}',
                head = document.head || document.getElementsByTagName('head')[0],
                style = document.createElement('style');

            style.id = 'anti_social_locker';
            style.appendChild(document.createTextNode(css));

            head.appendChild(style);
        })();


        if (!('jQuery' in global)) return;

        var unlocked = 'Unlocked by Anti Social Locker',
            counter = 0,
            debug = false,
            showCounter = function () {
                if (debug) global.console.log(counter, 'Social Locker have been disabled!');
            },
            setCookie = function (cname, cvalue, exdays, path) {
                var domain = '',
                    d = new Date();

                if (exdays) {
                    d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
                    exdays = '; expires=' + d.toUTCString();
                }
                if (!path) path = '/';
                document.cookie = cname + '=' + cvalue + '; path=' + path + exdays + domain + ';';
            },
            getCookie = function (name) {
                var cname = name + '=',
                    cpos = document.cookie.indexOf(cname),
                    cstart,
                    cend;
                if (cpos !== -1) {
                    cstart = cpos + cname.length;
                    cend = document.cookie.indexOf(';', cstart);
                    if (cend === -1) cend = document.cookie.length;
                    return decodeURIComponent(document.cookie.substring(cstart, cend));
                }
                return null;
            };

        // Social Locker for jQuery (https://codecanyon.net/item/social-locker-for-jquery/3408941)
        (function ($) {
            if ($.fn.sociallocker) jQuery.fn.sociallocker = function () {
                var $lock = $(this.selector);
                $lock.show().attr('data-lock-id', unlocked);

                counter += $lock.length;
                showCounter();

                return this;
            };
        })(jQuery);

        // Easy Social Locker (https://codecanyon.net/item/easy-social-locker/6190651)
        (function ($) {
            var $events = $._data(document, 'events'),
                $doc = $(document),
                str,
                cid;

            if ($events && $events.esll_button_action) {
                $('script:not([src])').each(function () {
                    var txt = this.textContent;

                    if (txt.indexOf('esll_data') !== -1 && txt.indexOf('esll_button_action') !== -1) {
                        str = txt;
                        return false;
                    }
                });

                if (str) cid = str.match(/var\scid\s?=\s?(\d+);/);

                if (cid) {
                    cid = cid[1];
                } else {
                    cid = str.match(/\['(google|linkedin)(-share)?',\s?(\d+)\]/);

                    if (cid) {
                        cid = cid[3];
                    } else {
                        cid = '0';
                    }
                }
                if (cid !== '0') {
                    $doc.trigger('esll_button_action', ['facebook-share', cid]);
                } else {
                    $doc.trigger('esll_button_action');
                }

                counter += $('.esll-big, .esll-small').length;
                showCounter();
            }
        })(jQuery);

        // ARSocial - Social Share & Social Locker (https://codecanyon.net/item/arsocial-social-share-social-locker/15218913)
        (function ($) {
            var $pageId = $('#ars_page_id'),
                $lockId = $('#ars_locker_id'),
                $lockContents = $('.arsocialshare_locker_main_wrapper'),
                removeClass = 'ars_locked_full ars_locked_transparency ars_locked_blurring';

            if ($pageId.length && $lockId.length && $lockContents.length) {
                $lockContents.each(function () {
                    var $this = $(this),
                        $hidden = $('#' + $this.data('hidden-el'));

                    $hidden.attr('data-lock-id', unlocked).removeClass(removeClass).show();
                    $this.replaceWith($hidden);
                });

                counter += $lockContents.length;
                showCounter();
            }
        })(jQuery);

        // Social Share & Locker Pro Wordpress Plugin (http://codecanyon.net/item/social-share-locker-pro-wordpress-plugin/8137709)
        (function ($) {
            if (!('ism_general_locker' in global)) return;
            var $locker = $('.ism-before-row');

            if ($locker.length) {
                $locker.each(function () {
                    var $this = $(this),
                        $lockerAlert,
                        $lockerContent;

                    (function reUnlock() {
                        $lockerAlert = $('#' + $this.data('lockerid'));
                        $lockerContent = $('#' + $this.data('id'));
                        if (!$lockerAlert.length && !$lockerContent.is('[style]')) return;

                        $lockerContent.attr('data-lock-id', unlocked).removeAttr('style');
                        $lockerContent.parent('.ismLockerWrap').removeAttr('style');
                        $lockerAlert.remove();

                        setTimeout(function () {
                            reUnlock();
                        }, 500);
                    })();
                });

                counter += $locker.length;
                showCounter();
            }
        })(jQuery);

        // Viral Lock - Like, Google+1 or Tweet to Unlock (http://codecanyon.net/item/viral-lock-like-google1-or-tweet-to-unlock/1486602)
        // Viral Lock PHP - Like, Google+1 or Tweet to Unlock (http://codecanyon.net/item/viral-lock-php-like-google1-or-tweet-to-unlock/1632879)
        // Viral Coupon - Like, Tweet or G+ to get a Discount (http://codecanyon.net/item/viral-coupon-like-tweet-or-g-to-get-a-discount/2233568)
        (function ($) {
            if (!('virallocker_use' in global)) return;
            var $locked = $('.virallock-box, .virallocker-box, .virallocker-box-checkout'),
                host = global.location.host,
                str = '',
                pid,
                viralLock = /var\sdata\s?=\s?\{post:\s?"(\d+)",\s?action:/m,
                viralPHP = /"virallocker",\s?myID:\s?"(myid\d+)"\}/m,
                viralCoupon = /var\sdata\s?=\s?{\s?action:\s?"submit",\s?myID:\s?"(\d+)"\};/m,
                afterUnlock = function () {
                    counter += $locked.length;
                    showCounter();
                    global.location.reload();
                },
                viralCookie;

            $('script:not([src])').each(function () {
                var txt = this.textContent;

                if (txt.indexOf('virallocker_use') !== -1 && txt.indexOf('jQuery.post') !== -1) {
                    str = txt;
                    return false;
                }
            });
            if (str === '') return;

            if (viralLock.test(str)) {

                pid = str.match(viralLock);
                if (!pid) return;

                viralCookie = 'virallocker_' + pid[1];
                if (getCookie(viralCookie) !== null) return;
                setCookie(viralCookie, '0001', host);

                afterUnlock();

            } else if (viralPHP.test(str)) {

                pid = str.match(viralPHP);
                if (!pid) return;

                viralCookie = 'virallock_' + pid[1];
                if (getCookie(viralCookie) !== null) return;
                setCookie(viralCookie, '0001', host);

                afterUnlock();

            } else if (viralCoupon.test(str)) {

                pid = str.match(viralCoupon);
                if (!pid) return;

                if (getCookie('virallock_' + pid[1]) !== null && getCookie('virallock_time_' + pid[1]) !== null) return;

                /* globals virallocker_plusone */
                if ('virallocker_plusone' in global) virallocker_plusone({
                    state: 'on'
                });

                counter += $locked.length;
                showCounter();

            }
        })(jQuery);

    }

    document.addEventListener('DOMContentLoaded', function () {
        antiSocialLocker();
        setTimeout(antiSocialLocker, 4000);

    });

    window.addEventListener('load', function () {
        antiSocialLocker();
        setTimeout(antiSocialLocker, 0);
    });

})(window);


Danh sách hỗ trợ


  1. Social Locker for jQuery
  2. Social Locker for Wordpress
  3. Panda Lockers
  4. Easy Social Locker
  5. ARSocial - Social Share & Social Locker
  6. Social Share & Locker Pro Wordpress Plugin
  7. Viral Lock - Like, Google+1 or Tweet to Unlock
  8. Viral Lock PHP - Like, Google+1 or Tweet to Unlock
  9. Viral Coupon - Like, Tweet or G+ to get a Discount

Tags: #userscript #adblock #social #locker

[Userscript] YYApp downloader

Diễn đàn: Lưu trữTrả lời: 3Lượt xem: 2062

 10.06.17 20:03

Tải truyện từ app.truyenyy.com định dạng txt hoặc html. Sau đó, bạn có thể dùng Mobipocket Creator để tạo ebook prc.

Demo


[You must be [You must be registered and logged in to see this link.] and [You must be registered and logged in to see this link.] to see this image.]
YYApp downloader

Cài đặt


Dùng một trong các link sau:

  1. [You must be registered and logged in to see this link.]
  2. [You must be registered and logged in to see this link.]
  3. [You must be registered and logged in to see this link.]

Mã nguồn


Code:
// ==UserScript==
// @name         YYApp downloader
// @namespace    https://baivong.github.io/
// @description  Tải truyện từ app.truyenyy.com định dạng txt hoặc html. Sau đó, bạn có thể dùng Mobipocket Creator để tạo ebook prc
// @version      1.1.0
// @icon         http://i.imgur.com/3lomxTC.png
// @author       Zzbaivong
// @license      MIT
// @include      /^https?:\/\/app\.truyenyy\.com\/truyen\/[^\/]+\/(danh\-sach\-chuong\/(\?p=\d+)?)?$/
// @require      https://code.jquery.com/jquery-3.2.0.min.js
// @require      https://greasyfork.org/scripts/18532-filesaver/code/FileSaver.js?version=164030
// @noframes
// @connect      self
// @supportURL   https://github.com/baivong/Userscript/issues
// @run-at       document-idle
// @grant        GM_xmlhttpRequest
// ==/UserScript==

(function ($, window, document, undefined) {
    'use strict';

    /**
     * Export data to a text file (.txt)
     * @type {Boolean} true  : txt
     *                 false : html
     */
    var textOnly = true;

    /**
     * Enable logging in Console
     * @type {Number} 0 : Disable
     *                1 : Error
     *                2 : Info + Error
     */
    var debugLevel = 0;


    function downloadFail(err) {
        if (!oneChap) {
            $download.css('background', '#f26a65');
            titleError.push(chapTitle);
        }

        if (textOnly) {
            txt += LINE2 + url.toUpperCase() + LINE2;
        } else {
            txt += '<h2 class="title">' + url + '</h2>';
        }

        if (debugLevel == 2) console.log('%cError: ' + url, 'color:red;');
        if (debugLevel > 0) console.error(err);
    }

    function saveEbook() {
        var ebookTitle = oneChap ? chapTitle : $('h1').text().trim(),
            fileName = ebookTitle,
            fileType,
            blob;

        if (endDownload) return;
        endDownload = true;

        if (!oneChap) {
            var ebookAuthor = $('td:contains("Tác giả")').next().find('a').text().trim(),
                $ebookType = $('td:contains("Thể loại")'),
                ebookType = [],

                credits = '<p>Truyện được tải từ <a href="' + location.href + '">TruyenYY</a></p><p>Userscript được viết bởi: <a href="https://baivong.github.io/">Zzbaivong</a></p>',
                creditsTxt = LINE2 + 'Truyện được tải từ ' + location.href + LINE + 'Userscript được viết bởi: Zzbaivong' + LINE2,

                beginEnd = '';

            if ($ebookType.length) {
                $ebookType = $ebookType.next().find('a');
                $ebookType.each(function () {
                    ebookType.push($(this).text().trim());
                });
                ebookType = ebookType.join(', ');

                if (textOnly) {
                    ebookType = LINE + 'Thể loại: ' + ebookType;
                } else {
                    ebookType = '<h3>Thể loại: <font color="green">' + ebookType + '</font></h3>';
                }
            } else {
                ebookType = '';
            }

            if (titleError.length) {
                if (textOnly) {
                    titleError = LINE + 'Các chương lỗi: ' + titleError.join(', ') + LINE;
                } else {
                    titleError = '<h4>Các chương lỗi: <font color="gray">' + titleError.join(', ') + '</font></h4>';
                }

                if (debugLevel > 0) console.warn('Các chương lỗi:', titleError);
            } else {
                titleError = '';
            }

            if (textOnly) {
                if (begin !== end) beginEnd = LINE + 'Từ [' + begin + '] đến [' + end + ']';
                txt = ebookTitle.toUpperCase() + LINE2 + 'Tác giả: ' + ebookAuthor + ebookType + beginEnd + titleError + creditsTxt + txt;
            } else {
                if (begin !== end) beginEnd = '<br><h4>Từ <font color="gray">' + begin + '</font> đến <font color="gray">' + end + '</font></h4>';
                txt = '<html><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"></head><body><h1><font color="red">' + ebookTitle + '</font></h1><h3>Tác giả: <font color="blue">' + ebookAuthor + '</font></h3>' + ebookType + beginEnd + titleError + '<br><br>' + credits + '<br><br><br>' + txt + '</body></html>';
            }
        }

        if (textOnly) {
            fileName += '.txt';
            fileType = 'text/plain';
        } else {
            fileName += '.html';
            fileType = 'text/html';
        }

        if (oneChap) txt = txt.trim();

        blob = new Blob([txt], {
            encoding: 'UTF-8',
            type: fileType + ';charset=UTF-8'
        });

        if (!oneChap) {
            $download.attr({
                href: window.URL.createObjectURL(blob),
                download: fileName
            }).html('<i class="material-icons">check</i> Tải xong').css('background', '#66bb6a').off('click');

            $win.off('beforeunload');
        }

        document.title = '[⇓] ' + ebookTitle;
        if (debugLevel === 2) console.log('%cDownload Finished!', 'color:blue;');
        if (debugLevel > 0) console.timeEnd('YYApp Downloader');

        saveAs(blob, fileName);
    }

    function getContent() {
        if (endDownload) return;

        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            onload: function (response) {
                var $data = $(response.responseText),
                    $chapter = $data.find('.chap-content'),
                    $next = $data.find('.weui_btn:contains("Tiếp"):last'),
                    nextUrl;

                if (endDownload) return;

                chapTitle = $data.find('.chap-title').text().trim().replace(/^(Chương\s\d+)(\s+?Chương\s?[^\:]+\:)?/, '$1 :');

                if (!$chapter.length) {
                    downloadFail('Missing content.');
                } else {
                    if (!oneChap) $download.css('background', 'orange');

                    if (textOnly) {
                        txt += LINE2 + chapTitle.toUpperCase() + LINE2;
                    } else {
                        txt += '<h2 class="title">' + chapTitle + '</h2>';
                    }

                    $chapter.each(function () {
                        var $this = $(this),
                            $img = $this.find('img');

                        if ($img.length) $img.replaceWith(function () {
                            if (textOnly) {
                                return LINE + this.src + LINE;
                            } else {
                                return '<a href="' + this.src + '">Click để xem ảnh</a>';
                            }
                        });

                        if (textOnly) {
                            $this = $($this.html().replace(/\r?\n+/g, ' '));
                            $this.find('br').replaceWith('\r\n');
                            $this.find('p, div').after('\r\n');
                            txt += $this.text().trim();
                        } else {
                            txt += $this.html();
                        }
                    });

                    if (!oneChap) count++;

                    if (debugLevel === 2) console.log('%cComplete: ' + url, 'color:green;');
                }

                if (!oneChap) {
                    if (count === 1) begin = chapTitle;
                    end = chapTitle;

                    $download.text(chapTitle);
                    document.title = '[' + count + '] ' + pageName;
                }

                if ($next.hasClass('weui_btn_disabled') || oneChap) {
                    saveEbook();
                    return;
                }

                if ($next.length) {
                    nextUrl = $next.attr('href');

                    if (nextUrl === url || nextUrl === '') {
                        saveEbook();
                        return;
                    }
                } else {
                    saveEbook();
                    return;
                }

                url = nextUrl;
                getContent();
            },
            onerror: function (err) {
                downloadFail(err);
                saveEbook();
            }
        });
    }


    var oneChap = false,

        txt = '',
        url = '',

        chapTitle = '',

        LINE = '\r\n\r\n',
        LINE2 = '\r\n\r\n\r\n\r\n',

        endDownload = false;


    if (/^\/truyen\/[^\/]+\/danh\-sach\-chuong\/$/.test(location.pathname)) {
        oneChap = true;

        $('a.weui_cell').on('contextmenu', function (e) {
            e.preventDefault();

            if (debugLevel > 0) console.time('YYApp Downloader');
            if (debugLevel === 2) console.log('%cDownload Start!', 'color:blue;');
            document.title = '[...] Vui lòng chờ trong giây lát';

            url = this.href;
            txt = '';

            getContent();
        });
    } else {
        var pageName = document.title,
            $win = $(window),

            $download = $('<a>', {
                class: 'weui_btn weui_btn_default',
                href: '#download',
                css: {
                    background: '#29b6f6',
                    color: '#ffffff'
                },
                text: 'Tải xuống'
            }),

            count = 0,
            begin = '',
            end = '',

            titleError = [];

        url = $('.weui_btn:contains("Đọc Từ Đầu")').attr('href');


        $('.btns').append($('<div>', {
            class: 'flexbox flex-row"'
        }).append($('<div>', {
            class: 'flexbox-item'
        }).append($download)));

        $download.one('click contextmenu', function (e) {
            e.preventDefault();

            if (e.type === 'contextmenu') {
                var beginUrl = prompt("Nhập URL chương truyện bắt đầu tải:", location.origin + url);
                if (beginUrl !== null && /^https?:\/\/app\.truyenyy\.com\/chuong\/[^\/]+\/$/i.test(beginUrl.trim())) url = beginUrl.replace(location.origin, '');

                $download.off('click');
            } else {
                $download.off('contextmenu');
            }

            if (debugLevel > 0) console.time('YYApp Downloader');
            if (debugLevel === 2) console.log('%cDownload Start!', 'color:blue;');
            document.title = '[...] Vui lòng chờ trong giây lát';

            getContent();

            $win.on('beforeunload', function () {
                return 'Truyện đang được tải xuống...';
            });

            $download.one('click', function (e) {
                e.preventDefault();

                saveEbook();
            });
        });
    }

})(jQuery, window, document);


Hướng dẫn


Tải truyện


Script hoạt động sẽ tạo ra nút Tải xuống tại trang giới thiệu truyện, click vào sẽ tải bộ truyện đó.
Bạn có thể theo dõi quá trình trong Console (F12 > console), nếu chương truyện lỗi sẽ hiện link màu đỏ.

Khi quá trình tải hoàn tất, định dạng file tải xuống là txt. Nếu bạn muốn sử dụng định dạng html, hãy chỉnh tham số textOnly trong mã nguồn thành false.

Chọn chương bắt đầu tải


Click chuột phải trên nút Tải xuống và nhập URL của chương cần bắt đầu vào khung nhập liệu, tiến trình sẽ bắt đầu từ chương đó đến cuối danh sách.

Tải từng chương riêng biệt


Nhấn vào nút Danh Sách Chương và Click chuột phải trên liên kết chương cần tải trong danh mục.

Dừng và tải xuống


Khi gặp lỗi trong quá trình tải mà không thể tiếp tục, tiến trình sẽ tự dừng và tải truyện.
Bạn có thể dừng và tải truyện ngay lập tức bằng cách click vào nút Tải xuống khi tiến trình đang chạy.

Đọc truyện


Với định dạng txt, bạn có thể đọc trực tiếp bằng các Ebook Reader phổ biến trên thiết bị của bạn. Ví dụ:


  • Windows: MobiPocket Reader.
  • Linux: FBReader.
  • Windows Phone: MoHoo Reader. Thiết lập Setting >> Reading > Scroll free : On để tránh lỗi ngắt chữ.
  • Android: AlReader.


Định dạng html thường không được hỗ trợ đọc trực tiếp hoặc có nhiều hạn chế, bạn nên chuyển sang dạng prc theo hướng dẫn dưới đây.

Tạo ebook prc


Tải phần mềm Mobipocket Creator. Khi cài đặt, nên chọn phiên bản Creator Home Edition.

Sau khi cài đặt hoàn tất, chạy Mobipocket Creator, trong mục Import From Exiting File, nhấp vào HTML document.

Tại trang Import from HTML document:

  1. Choose a file: Nhấn Browse..., chọn file truyện bạn vừa tải trước đó.
  2. Create publication in folder: Đây là vị trí chứa ebook sau khi tạo, nên để mặc định.
  3. Language: Chọn Vietnamese.
  4. Encoding: Chọn UTF-8.

Nhấn nút Import.

Sau khi import thành công, bạn sẽ được chuyển đến trang cấu hình cho Ebook.

Mục Conver Image là nơi bạn chèn ảnh bìa cho Ebook. Nhấn nút Add a Conver image và chọn ảnh bạn muốn làm bìa rồi nhấn nút Update.

Để tạo mục lục cho các chương truyện, chọn mục Table of contents, nhấn nút Add a Table of contents.
Ở phần Table of Contents Title, bạn điền: Mục lục vào ô nhập liệu.
Phần Table of Contents Generation rules, bạn điền vào 3 ô trên dòng First level lần lượt là:

  • Tagname: h2
  • Attribute: class
  • Value: title

Nhấn nút Update.

Đến đây bạn đã hoàn thành những việc cần thiết để tạo Ebook, Nhấn menu Build ở phía trên, sau đó chọn nút Build ở trang hiện ra để tạo Ebook định dạng prc. File này sẽ được lưu ở thư mục bạn chọn ở Create publication in folder. Trong thư mục này còn chứa một số file cấu hình khác, bạn có thể xóa chúng đi.
Tags: [You must be registered and logged in to see this link.]

[Userscript] TruyenFull downloader

Diễn đàn: UserscriptTrả lời: 0Lượt xem: 920

 10.06.17 19:33

Tải truyện từ TruyenFull.vn định dạng epub.

Demo


Topics tagged under userscript on DEVs forumvi Truyen12
Tải truyện từ TruyenFull

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/28718-truyenfull-downloader
  2. https://openuserjs.org/scripts/baivong/TruyenFull_downloader
  3. https://github.com/baivong/Userscript/raw/master/truyenFull_downloader/truyenFull_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        TruyenFull downloader
// @namespace    https://baivong.github.io/
// @description  Tải truyện từ truyenfull.vn định dạng epub
// @version      4.4.0
// @icon        https://i.imgur.com/FQY8btq.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @include      http://truyenfull.vn/*
// @exclude      http://truyenfull.vn/
// @exclude      http://truyenfull.vn/*/chuong-*
// @exclude      http://truyenfull.vn/danh-sach/*
// @exclude      http://truyenfull.vn/the-loai/*
// @exclude      http://truyenfull.vn/tac-gia/*
// @exclude      http://truyenfull.vn/contact/
// @exclude      http://truyenfull.vn/tos/
// @exclude      http://truyenfull.vn/sitemap.xml
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @require      https://unpkg.com/jepub@1.2.1/dist/jepub.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @noframes
// @connect      self
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        none
// ==/UserScript==

(function ($, window, document) {
    'use strict';

    /**
    * Nhận cảnh báo khi có chương bị lỗi
    */
    var errorAlert = true;

    /**
    * Thời gian giãn cách giữa 2 lần tải
    * @type {Number}
    */
    var downloadDelay = 100;


    function cleanHtml(str) {
        str = str.replace(/\s*Chương\s*\d+\s?:[^<\n]/, '');
        str = str.replace(/[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]+/gm, ''); // eslint-disable-line
        return '<div>' + str + '</div>';
    }

    function downloadError(mess, err) {
        downloadStatus('danger');
        titleError.push(chapTitle);
        if (errorAlert) errorAlert = confirm('Lỗi! ' + mess + '\nBạn có muốn tiếp tục nhận cảnh báo?');

        if (err) console.error(mess);
        return '<p class="no-indent"><a href="' + referrer + chapId + '">' + mess + '</a></p>';
    }

    function saveEbook() {
        if (endDownload) return;
        endDownload = true;
        $download.html('Đang nén EPUB');

        if (titleError.length) {
            titleError = '<p class="no-indent"><strong>Các chương lỗi: </strong>' + titleError.join(', ') + '</p>';
        } else {
            titleError = '';
        }
        beginEnd = '<p class="no-indent">Nội dung từ <strong>' + begin + '</strong> đến <strong>' + end + '</strong></p>';

        jepub.notes(beginEnd + titleError + '<br /><br />' + credits);

        jepub.generate().then(function (epubZipContent) {
            document.title = '[⇓] ' + ebookTitle;
            $win.off('beforeunload');

            $download.attr({
                href: window.URL.createObjectURL(epubZipContent),
                download: ebookFilename
            }).text('Hoàn thành').off('click');
            if (!$download.hasClass('btn-danger')) downloadStatus('success');

            saveAs(epubZipContent, ebookFilename);
        }).catch(function (err) {
            downloadStatus('danger');
            console.error(err);
        });
    }

    function getContent() {
        if (endDownload) return;
        chapId = chapList[count];

        $.get(pathname + chapId + '/').done(function (response) {
            var $data = $(response),
                $chapter = $data.find('.chapter-c'),
                $notContent = $chapter.find('script, style, a'),
                $referrer = $chapter.find('[style]').filter(function () {
                    return (this.style.fontSize === '1px' || this.style.fontSize === '0px' || this.style.color === 'white');
                }),
                chapContent;

            if (endDownload) return;

            chapTitle = $data.find('.chapter-title').text().trim();
            if (chapTitle === '') chapTitle = 'Chương ' + chapId.match(/\d+/)[0];

            if (!$chapter.length) {
                chapContent = downloadError('Không có nội dung');
            } else {
                var $img = $chapter.find('img');
                if ($img.length) $img.replaceWith(function () {
                    return '<br /><a href="' + this.src + '">Click để xem ảnh</a><br />';
                });

                if ($notContent.length) $notContent.remove();
                if ($referrer.length) $referrer.remove();

                if ($chapter.text().trim() === '') {
                    chapContent = downloadError('Nội dung không có');
                } else {
                    if (!$download.hasClass('btn-danger')) downloadStatus('warning');
                    chapContent = cleanHtml($chapter.html());
                }
            }

            jepub.add(chapTitle, chapContent);

            if (count === 0) begin = chapTitle;
            end = chapTitle;

            $download.html('Đang tải: ' + Math.floor((count / chapListSize) * 100) + '%');

            count++;
            document.title = '[' + count + '] ' + pageName;
            if (count >= chapListSize) {
                saveEbook();
            } else {
                setTimeout(function () {
                    getContent();
                }, downloadDelay);
            }
        }).fail(function (err) {
            downloadError('Kết nối không ổn định', err);
            saveEbook();
        });
    }


    var pageName = document.title,
        $win = $(window),

        $download = $('<a>', {
            class: 'btn btn-primary',
            href: '#download',
            text: 'Tải xuống'
        }),
        downloadStatus = function (status) {
            $download.removeClass('btn-primary btn-success btn-info btn-warning btn-danger').addClass('btn-' + status);
        },

        $novelId = $('#truyen-id'),
        chapList = [],
        chapListSize = 0,
        chapId = '',
        chapTitle = '',
        count = 0,
        begin = '',
        end = '',
        endDownload = false,

        ebookTitle = $('h1').text().trim(),
        ebookAuthor = $('.info a[itemprop="author"]').text().trim(),
        // ebookCover = $('.books img').attr('src'),
        ebookDesc = $('.desc-text').html(),
        ebookType = [],
        beginEnd = '',
        titleError = [],

        host = location.host,
        pathname = location.pathname,
        referrer = location.protocol + '//' + host + pathname,

        ebookFilename = pathname.slice(1, -1) + '.epub',

        credits = '<p>Truyện được tải từ <a href="' + referrer + '">TruyenFull</a></p><p>Userscript được viết bởi: <a href="https://lelinhtinh.github.io/jEpub/">Zzbaivong</a></p>',

        jepub;


    if (!$novelId.length) return;

    var $ebookType = $('.info a[itemprop="genre"]');
    if ($ebookType.length)
        $ebookType.each(function () {
            ebookType.push($(this).text().trim());
        });

    jepub = new jEpub({
        title: ebookTitle,
        author: ebookAuthor,
        publisher: host,
        description: ebookDesc,
        tags: ebookType
    }).uuid(referrer);

    $download.insertAfter('.info');
    $download.one('click contextmenu', function (e) {
        e.preventDefault();
        document.title = '[...] Vui lòng chờ trong giây lát';

        $.when($.get('/ajax.php', {
            type: 'hash'
        })).done(function (res) {
            $.get('/ajax.php', {
                type: 'chapter_option',
                data: $novelId.val(),
                bnum: '',
                num: 1,
                hash: res
            }).done(function (data) {
                chapList = data.match(/(?:value=")[^"]+(?=")/g).map(function (val) {
                    return val.slice(7);
                });

                if (e.type === 'contextmenu') {
                    $download.off('click');
                    var startFrom = prompt('Nhập ID chương truyện bắt đầu tải:', chapList[0]);
                    startFrom = chapList.indexOf(startFrom);
                    if (startFrom !== -1) chapList = chapList.slice(startFrom);
                } else {
                    $download.off('contextmenu');
                }

                chapListSize = chapList.length;
                if (chapListSize > 0) {
                    $win.on('beforeunload', function () {
                        return 'Truyện đang được tải xuống...';
                    });

                    $download.one('click', function (e) {
                        e.preventDefault();
                        saveEbook();
                    });

                    getContent();
                }
            }).fail(function (jqXHR, textStatus) {
                downloadError(textStatus);
            });
        }).fail(function (jqXHR, textStatus) {
            $download.text('Lỗi danh mục');
            downloadStatus('danger');
            console.error(err);
        });
    });

})(jQuery, window, document);


Hướng dẫn


Tải truyện


Script hoạt động sẽ tạo ra nút Tải xuống tại trang giới thiệu truyện, click vào sẽ tải bộ truyện đó.
Click chuột phải trên nút Tải xuống và nhập ID của chương cần bắt đầu vào khung nhập liệu, tiến trình sẽ bắt đầu từ chương đó đến cuối danh sách.
Bạn có thể dừng và tải truyện ngay lập tức bằng cách click vào nút Tải xuống khi tiến trình đang chạy.

Đọc truyện


  1. Windows: Bookviser Reader.
  2. Linux: FBReader.
  3. Android: AlReader.

Tags: #userscript #download #ebook #truyenfull

[Userscript] TruyenYY downloader

Diễn đàn: UserscriptTrả lời: 0Lượt xem: 1803

 08.04.16 9:14

Tải truyện từ TruyenYY.com định dạng epub.

Demo


Topics tagged under userscript on DEVs forumvi Truyen10
Tải truyện từ TruyenYY

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/17827-truyenyy-downloader
  2. https://openuserjs.org/scripts/baivong/TruyenYY_downloader
  3. https://github.com/baivong/Userscript/raw/master/truyenYY_downloader/truyenYY_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name         TruyenYY downloader
// @namespace    http://devs.forumvi.com/
// @description  Tải truyện từ truyenyy.com định dạng epub
// @version      4.4.0
// @icon         https://i.imgur.com/obHcq8v.png
// @author       Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        https://truyenyy.com/truyen/*/
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @require      https://unpkg.com/jepub@1.2.1/dist/jepub.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @noframes
// @connect      self
// @supportURL   https://github.com/lelinhtinh/Userscript/issues
// @run-at       document-idle
// @grant        none
// ==/UserScript==

(function ($, window, document) {
    'use strict';

    /**
     * Nhận cảnh báo khi có chương bị lỗi
     */
    var errorAlert = true;

    function cleanText(str) {
        return str.replace(/[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]+/gm, ''); // eslint-disable-line
    }

    function downloadError(mess, err) {
        downloadStatus('danger');
        titleError.push(chapTitle);
        if (errorAlert) errorAlert = confirm('Lỗi! ' + mess + '\nBạn có muốn tiếp tục nhận cảnh báo?');

        if (err) console.error(mess);
        return '<p class="no-indent"><a href="' + referrer + chapId + '">' + mess + '</a></p>';
    }

    function saveEbook() {
        if (endDownload) return;
        endDownload = true;
        $download.html('<i class="iconfont icon-layer"></i> Đang nén EPUB');

        if (titleError.length) {
            titleError = '<p class="no-indent"><strong>Các chương lỗi: </strong>' + titleError.join(', ') + '</p>';
        } else {
            titleError = '';
        }
        beginEnd = '<p class="no-indent">Nội dung từ <strong>' + begin + '</strong> đến <strong>' + end + '</strong></p>';

        jepub.notes(beginEnd + titleError + '<br /><br />' + credits);

        jepub.generate().then(function (epubZipContent) {
            document.title = '[⇓] ' + ebookTitle;
            $win.off('beforeunload');

            $download.attr({
                href: window.URL.createObjectURL(epubZipContent),
                download: ebookFilename
            }).html('<i class="iconfont icon-save"></i> Hoàn thành').off('click');
            if (!$download.hasClass('btn-danger')) downloadStatus('success');

            saveAs(epubZipContent, ebookFilename);
        }).catch(function (err) {
            downloadStatus('danger');
            console.error(err);
        });
    }

    function getContent(pageId) {
        if (endDownload) return;
        chapId = pageId;

        $.get(pathname + chapId).done(function (response) {
            var $data = $(response),
                $chapter = $data.find('#id_chap_content .inner p'),
                chapContent = [],
                $next = $data.find('.buttons .btn-primary'),
                $vip = $data.find('#btn_buy');

            if (endDownload) return;

            chapTitle = $data.find('h1.chapter-title').text().trim();
            if (chapTitle === '') chapTitle = 'Chương ' + chapId.match(/\d+/)[0];

            if ($vip.length) {
                chapContent = downloadError('Chương VIP');
            } else if (!$chapter.length) {
                chapContent = downloadError('Không có nội dung');
            } else {
                if (!$download.hasClass('btn-danger')) downloadStatus('warning');
                $chapter.each(function () {
                    chapContent.push(cleanText(this.textContent.trim()));
                });
            }

            jepub.add(chapTitle, chapContent);

            if (count === 0) begin = chapTitle;
            end = chapTitle;
            ++count;

            downloadProgress(count);

            if ($next.hasClass('disabled')) {
                saveEbook();
            } else {
                getContent(downloadId($next.attr('href')));
            }
        }).fail(function (err) {
            downloadError('Kết nối không ổn định', err);
            saveEbook();
        });
    }


    var pageName = document.title,
        $win = $(window),

        $download = $('.more-buttons').find('a[href$="/epub/"]'),
        downloadStatus = function (status) {
            $download.removeClass('btn-primary btn-success btn-info btn-warning btn-danger').addClass('btn-' + status);
        },
        downloadProgress = function (progress) {
            document.title = '[' + count + '] ' + pageName;
            $download.html('<i class="iconfont icon-more"></i> Đã tải:<span class="pl-2">' + progress + '</span>');
        },
        downloadId = function (url) {
            return url.trim().replace(/^.*\//, '');
        },

        $novelInfo = $('.novel-info'),
        chapId = '',
        chapTitle = '',
        count = 0,
        begin = '',
        end = '',
        endDownload = false,

        ebookTitle = $('h1.name').text().trim(),
        ebookAuthor = $('h2.author').text().trim(),
        // ebookCover = $('.novel-info .zoom-me').attr('src'),
        ebookDesc = $('#id_novel_summary').html(),
        ebookType = [],
        beginEnd = '',
        titleError = [],

        host = location.host,
        pathname = location.pathname,
        referrer = location.protocol + '//' + host + pathname,

        ebookFilename = pathname.slice(8, -1) + '.epub',

        credits = '<p>Truyện được tải từ <a href="' + referrer + '">TruyenYY</a></p><p>Userscript được viết bởi: <a href="https://lelinhtinh.github.io/jEpub/">Zzbaivong</a></p>',

        jepub;


    if (!$novelInfo.length) return;

    var $ebookType = $('a', '.tag-list.list-unstyled.mt-2');
    if ($ebookType.length) $ebookType.each(function () {
        ebookType.push($(this).text().trim());
    });

    jepub = new jEpub({
        title: ebookTitle,
        author: ebookAuthor,
        publisher: host,
        description: ebookDesc,
        tags: ebookType
    }).uuid(referrer);

    $download.addClass('btn btn-primary text-light');
    $download.one('click contextmenu', function (e) {
        e.preventDefault();
        document.title = '[...] Vui lòng chờ trong giây lát';

        var firstChap = $('.info .btn:contains("Đọc Từ Đầu")');
        firstChap = downloadId(firstChap.attr('href'));
        var startFrom = firstChap;

        if (e.type === 'contextmenu') {
            $download.off('click');
            startFrom = prompt('Nhập ID chương truyện bắt đầu tải:', firstChap) || firstChap;
        } else {
            $download.off('contextmenu');
        }

        $win.on('beforeunload', function () {
            return 'Truyện đang được tải xuống...';
        });

        $download.one('click', function (e) {
            e.preventDefault();
            saveEbook();
        });

        getContent(startFrom);
    });

})(jQuery, window, document);


Hướng dẫn


Tải truyện


Script hoạt động sẽ tạo ra nút Tải xuống tại trang giới thiệu truyện, click vào sẽ tải bộ truyện đó.
Click chuột phải trên nút Tải xuống và nhập ID của chương cần bắt đầu vào khung nhập liệu, tiến trình sẽ bắt đầu từ chương đó đến cuối danh sách.
Bạn có thể dừng và tải truyện ngay lập tức bằng cách click vào nút Tải xuống khi tiến trình đang chạy.

Đọc truyện


  1. Windows: Bookviser Reader.
  2. Linux: FBReader.
  3. Android: AlReader.

Tags: #userscript #download #ebook #truyenyy

[Userscript] TruyenCV downloader

Diễn đàn: UserscriptTrả lời: 20Lượt xem: 5767

 08.04.16 9:08

Tải truyện từ TruyenCV.com định dạng epub.

Demo


Topics tagged under userscript on DEVs forumvi Truyen11
Tải truyện từ TruyenCV

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/17826-truyencv-downloader
  2. https://openuserjs.org/scripts/baivong/TruyenCV_downloader
  3. https://github.com/baivong/Userscript/raw/master/truyenCV_downloader/truyenCV_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        TruyenCV downloader
// @namespace    http://devs.forumvi.com/
// @description  Tải truyện từ truyencv.com định dạng epub
// @version      4.4.0
// @icon        http://i.imgur.com/o5cmtkU.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://truyencv.com/*/
// @require      https://code.jquery.com/jquery-3.3.1.min.js
// @require      https://unpkg.com/jepub@1.2.1/dist/jepub.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @noframes
// @connect      self
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        none
// ==/UserScript==
(function ($, window, document) {
    'use strict';

    /**
    * Nhận cảnh báo khi có chương bị lỗi
    */
    var errorAlert = true;

    /**
    * Những đoạn ghi chú cuối chương của converter
    * Chỉ cần ghi phần bắt đầu, không phân biệt hoa thường
    * Ngăn cách các đoạn bằng dấu |
    */
    var converter = 'ps:|hoan nghênh quảng đại bạn đọc quang lâm|Huyền ảo khoái trí ân cừu';


    converter = new RegExp('(' + converter + ')', 'i');

    function cleanHtml(str) {
        str = str.replace(/\s*Chương\s*\d+\s?:[^<\n]/, '');
        str = str.replace(/[^\x09\x0A\x0D\x20-\uD7FF\uE000-\uFFFD\u10000-\u10FFFF]+/gm, ''); // eslint-disable-line
        str = str.replace(/\s[a-zA-Z0-9]{6,8}(="")?\s/gm, function (key, attr) {
            if (attr) return ' ';
            if (!isNaN(key)) return key;
            if (key.split(/[A-Z]/).length > 2) return ' ';
            if (key.split(/\d/).length > 1) return ' ';
            return key;
        });
        str = str.replace(/\([^(]+<button[^/]+<\/button>[^)]*\)\s*/gi, '');
        str = str.split(converter)[0];
        return '<div>' + str + '</div>';
    }

    function downloadError(mess, err) {
        downloadStatus('danger');
        titleError.push(chapTitle);
        if (errorAlert) errorAlert = confirm('Lỗi! ' + mess + '\nBạn có muốn tiếp tục nhận cảnh báo?');

        if (err) console.error(mess);
        return '<p class="no-indent"><a href="' + referrer + chapId + '">' + mess + '</a></p>';
    }

    function saveEbook() {
        if (endDownload) return;
        endDownload = true;
        $download.html('Đang nén EPUB');

        if (titleError.length) {
            titleError = '<p class="no-indent"><strong>Các chương lỗi: </strong>' + titleError.join(', ') + '</p>';
        } else {
            titleError = '';
        }
        beginEnd = '<p class="no-indent">Nội dung từ <strong>' + begin + '</strong> đến <strong>' + end + '</strong></p>';

        jepub.notes(beginEnd + titleError + '<br /><br />' + credits);

        jepub.generate().then(function (epubZipContent) {
            document.title = '[⇓] ' + ebookTitle;
            $win.off('beforeunload');

            $download.attr({
                href: window.URL.createObjectURL(epubZipContent),
                download: ebookFilename
            }).text('Hoàn thành').off('click');
            if (!$download.hasClass('btn-danger')) downloadStatus('success');

            saveAs(epubZipContent, ebookFilename);
        }).catch(function (err) {
            downloadStatus('danger');
            console.error(err);
        });
    }

    function getContent() {
        if (endDownload) return;
        chapId = chapList[count];

        $.ajax({
            url: pathname + chapId + '/',
            xhrFields: {
                withCredentials: true
            }
        }).done(function (response) {
            var $data = $(response),
                $chapter = $data.find('#js-truyencv-content'),
                $notContent = $chapter.find('iframe, script, style, a, div, p:has(a[href*="truyencv.com"])'),
                $referrer = $chapter.find('[style]').filter(function () {
                    return (this.style.fontSize === '1px' || this.style.fontSize === '0px' || this.style.color === 'white');
                }),
                chapContent;

            if (endDownload) return;

            chapTitle = $data.find('#js-truyencv-read-content .title').text().trim();
            if (chapTitle === '') chapTitle = 'Chương ' + chapId.match(/\d+/)[0];

            if (!$chapter.length) {
                chapContent = downloadError('Không có nội dung');
            } else {
                if ($chapter.find('#btnChapterVip').length) {
                    chapContent = downloadError('Chương VIP');
                } else if ($chapter.filter(function () {
                        return (this.textContent.toLowerCase().indexOf('vui lòng đăng nhập để đọc chương này') !== -1);
                    }).length) {
                    chapContent = downloadError('Chương yêu cầu đăng nhập');
                } else {
                    var $img = $chapter.find('img');
                    if ($img.length) $img.replaceWith(function () {
                        return '<br /><a href="' + this.src + '">Click để xem ảnh</a><br />';
                    });

                    if ($notContent.length) $notContent.remove();
                    if ($referrer.length) $referrer.remove();

                    if ($chapter.text().trim() === '') {
                        chapContent = downloadError('Nội dung không có');
                    } else {
                        if (!$download.hasClass('btn-danger')) downloadStatus('warning');
                        chapContent = cleanHtml($chapter.html());
                    }
                }
            }

            jepub.add(chapTitle, chapContent);

            if (count === 0) begin = chapTitle;
            end = chapTitle;

            $download.html('Đang tải: ' + Math.floor((count / chapListSize) * 100) + '%');

            count++;
            document.title = '[' + count + '] ' + pageName;
            if (count >= chapListSize) {
                saveEbook();
            } else {
                getContent();
            }
        }).fail(function (err) {
            downloadError('Kết nối không ổn định', err);
            saveEbook();
        });
    }


    var pageName = document.title,
        $win = $(window),
        $download = $('<a>', {
            class: 'btn btn-info',
            href: '#download',
            text: 'Tải xuống'
        }),
        downloadStatus = function (status) {
            $download.removeClass('btn-primary btn-success btn-info btn-warning btn-danger').addClass('btn-' + status);
        },

        $novelId = $('.basic'),
        chapList = [],
        chapListSize = 0,
        chapId = '',
        chapTitle = '',
        count = 0,
        begin = '',
        end = '',
        endDownload = false,

        ebookTitle = '',
        ebookAuthor = '',
        // ebookCover = '',
        ebookDesc = '',
        ebookType = [],
        beginEnd = '',
        titleError = [],

        host = location.host,
        pathname = location.pathname,
        referrer = location.protocol + '//' + host + pathname,

        ebookFilename = pathname.slice(1, -1) + '.epub',

        credits = '<p>Truyện được tải từ <a href="' + referrer + '">TruyenCV</a></p><p>Userscript được viết bởi: <a href="https://lelinhtinh.github.io/jEpub/">Zzbaivong</a></p>',

        jepub;


    if (!$novelId.length) return;

    var $infoBlock = $('.truyencv-detail-info-block');

    ebookTitle = $infoBlock.find('h1').text().trim();
    ebookAuthor = $infoBlock.find('.author').text().trim();
    // ebookCover = $infoBlock.find('.img-responsive').attr('src');
    ebookDesc = $('.brief').html();

    var $ebookType = $infoBlock.find('.categories a');
    if ($ebookType.length)
        $ebookType.each(function () {
            ebookType.push($(this).text().trim());
        });

    jepub = new jEpub({
        title: ebookTitle,
        author: ebookAuthor,
        publisher: host,
        description: ebookDesc,
        tags: ebookType
    }).uuid(referrer);

    $download.insertAfter('#btnregistRecentReadingStory');
    $download.one('click contextmenu', function (e) {
        e.preventDefault();
        var showChapList = $('.truyencv-detail-block a[href="#truyencv-detail-chap"]');

        document.title = '[...] Vui lòng chờ trong giây lát';

        showChapList = showChapList.attr('onclick');
        showChapList = showChapList.match(/\(([^()]+)\)/)[1];
        showChapList = showChapList.match(/[^',]+/g);

        $.ajax({
            type: 'POST',
            url: '/index.php',
            data: {
                showChapter: 1,
                media_id: showChapList[0],
                number: showChapList[1],
                page: showChapList[2],
                type: showChapList[3]
            },
            contentType: 'application/x-www-form-urlencoded'
        }).done(function (response) {
            chapList = response.match(/(?:href=")[^")]+(?=")/g);
            if (response.indexOf('panel panel-vip') === -1) chapList = chapList.reverse();
            chapList = chapList.map(function (val) {
                val = val.slice(6, -1);
                val = val.replace(referrer, '');
                return val;
            });

            if (e.type === 'contextmenu') {
                $download.off('click');
                var startFrom = prompt('Nhập ID chương truyện bắt đầu tải:', chapList[0]);
                startFrom = chapList.indexOf(startFrom);
                if (startFrom !== -1) chapList = chapList.slice(startFrom);
            } else {
                $download.off('contextmenu');
            }

            chapListSize = chapList.length;
            if (chapListSize > 0) {
                $win.on('beforeunload', function () {
                    return 'Truyện đang được tải xuống...';
                });

                $download.one('click', function (e) {
                    e.preventDefault();
                    saveEbook();
                });

                getContent();
            }
        }).fail(function (err) {
            $download.text('Lỗi danh mục');
            downloadStatus('danger');
            console.error(err);
        });
    });

})(jQuery, window, document);


Hướng dẫn


Tải truyện


Script hoạt động sẽ tạo ra nút Tải xuống tại trang giới thiệu truyện, click vào sẽ tải bộ truyện đó.
Click chuột phải trên nút Tải xuống và nhập ID của chương cần bắt đầu vào khung nhập liệu, tiến trình sẽ bắt đầu từ chương đó đến cuối danh sách.
Bạn có thể dừng và tải truyện ngay lập tức bằng cách click vào nút Tải xuống khi tiến trình đang chạy.

Đọc truyện


  1. Windows: Bookviser Reader.
  2. Linux: FBReader.
  3. Android: AlReader.

Tags: #userscript #truyencv #download #ebook

[Userscript] Download ảnh ở Worldcosplay

Diễn đàn: UserscriptTrả lời: 7Lượt xem: 5018

 31.01.15 11:00

Worldcosplay.net không cho phép download ảnh nên bạn không thể sử dụng cách thông thường để tải được. Userscript này sẽ tạo thêm nút download bên dưới ảnh để bạn có thể dễ dàng làm việc đó.

Demo


Topics tagged under userscript on DEVs forumvi EiBHnCL
(Nút download ảnh đã thêm vào)
Download trong Album:


Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/16114-worldcosplay-download
  2. https://openuserjs.org/scripts/baivong/Worldcosplay_download
  3. https://github.com/baivong/Userscript/raw/master/worldcosplay_downloader/worldcosplay_downloader.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        Worldcosplay download
// @namespace    http://devs.forumvi.com/
// @description  Download photo(s) on worldcosplay.net
// @version      3.1.2
// @icon        http://i.imgur.com/gJLjIzb.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        https://worldcosplay.net/*/photos*
// @match        https://worldcosplay.net/*/favorites*
// @match        https://worldcosplay.net/photo/*
// @match        https://worldcosplay.net/tag/*
// @match        https://worldcosplay.net/search/photos?*
// @match        https://worldcosplay.net/collections/*
// @match        https://worldcosplay.net/character/*
// @match        https://worldcosplay.net/title/*
// @match        https://worldcosplay.net/photos
// @match        https://worldcosplay.net/popular
// @match        https://worldcosplay.net/ranking/good*
// @match        https://worldcosplay.net/*/photo/*
// @match        https://worldcosplay.net/*/tag/*
// @match        https://worldcosplay.net/*/search/photos?*
// @match        https://worldcosplay.net/*/collections/*
// @match        https://worldcosplay.net/*/character/*
// @match        https://worldcosplay.net/*/title/*
// @match        https://worldcosplay.net/*/photos
// @match        https://worldcosplay.net/*/popular
// @match        https://worldcosplay.net/*/ranking/good*
// @require      https://code.jquery.com/jquery-3.3.1.slim.min.js
// @require      https://unpkg.com/file-saver@1.3.8/FileSaver.min.js
// @require      https://greasyfork.org/scripts/6250-waitforkeyelements/code/waitForKeyElements.js?version=23756
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      self
// @connect      sakurastorage.jp
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM.openInTab
// @grant        GM_openInTab
// ==/UserScript==

/* global waitForKeyElements */
(function ($, window) {
    'use strict';

    window.URL = window.URL || window.webkitURL;

    function downloadPhoto(el, url) {
        var photoName = url.replace(/.*\//g, ''),
            $icon = $(el).find('.fa');

        $icon.addClass('fa-spinner fa-spin');

        GM.xmlHttpRequest({
            method: 'GET',
            url: url,
            responseType: 'blob',
            onload: function (response) {
                var blob = response.response;

                $(el).attr({
                    href: window.URL.createObjectURL(blob),
                    download: photoName
                }).off('click');
                $icon.removeClass('fa-spinner fa-spin').addClass('fa-download');

                saveAs(blob, photoName);
            },
            onerror: function (err) {
                $icon.removeClass('fa-spinner fa-spin').addClass('fa-times');
                console.error(err);
            }
        });
    }

    function getImage3000(url) {
        var hasMax = url.match(/\/max-(\d+)\//);
        if (hasMax) return url.replace(/-[\dx]+\./, '-' + hasMax[1] + '.');

        return url.replace(/-[\dx]+\./, '-3000.');
    }

    if (/^(\/[a-z-]+)?\/photo\/\d+$/.test(location.pathname)) {

        var $btn = $('<a>', {
                href: '#download',
                class: 'download-this-photo',
                title: 'Click to download this image\nRight Click to open in new tab',
                html: '<div class="side_buttons" style="right: 250px;"><div class="like-this-photo button fave fa fa-download"><div class="effect-ripple"></div></div></div>'
            }),
            img = $('#photoContainer').find('.img').attr('src');
        $btn.on('click', function (e) {
            e.preventDefault();
            e.stopPropagation();
            downloadPhoto(this, getImage3000(img));
        }).on('contextmenu', function (e) {
            e.preventDefault();
            e.stopPropagation();
            GM.openInTab(getImage3000(img));
        });
        $btn.insertAfter('.side_buttons');

    } else {

        var addBtn = function () {
            $('.preview').not('.added-download-btn').each(function () {
                var $this = $(this),
                    $btn = $('<a>', {
                        href: '#download',
                        class: 'download-this-photo',
                        title: 'Click to download this image\nRight Click to open in new tab',
                        html: '<div class="item likes" style="top: 50px;"><span class="like-this-photo"><i class="fa fa-download"></i><span class="effect-ripple"></span></span></div>'
                    });
                $btn.on('click', function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    downloadPhoto(this, getImage3000($this.find('.photo_img').css('backgroundImage').slice(5, -2)));
                }).on('contextmenu', function (e) {
                    e.preventDefault();
                    e.stopPropagation();
                    GM.openInTab(getImage3000($this.find('.photo_img').css('backgroundImage').slice(5, -2)));
                });
                $this.find('.options').append($btn);
                $this.addClass('added-download-btn');
            });
        };
        addBtn();

        waitForKeyElements('.preview', addBtn);

    }

})(jQuery, window);

Tags: #userscript #download #photo #cosplay #cure #worldcosplay

[Userscript] Sửa tiền tố cho bài viết

Diễn đàn: UserscriptTrả lời: 5Lượt xem: 2355

 31.01.15 10:44

Userscript này dùng cho Mod của diễn đàn, giúp sửa tiền tố cho bài viết trong Thùng rác ở Devs forumvi.

Devs forumvi, mình thiết lập tiền tố riêng cho từng mục, trong đó tiền tố [Thùng rác] có tác dụng là kéo những bài đó xuống cuối bảng thống kê bài mới.
Khi quăng bài vào Thùng rác thì nó vẫn còn nguyên tiền tố chuyên mục cũ, vì vậy phải sửa nó về tiền tố [Thùng rác], userscript này là để giúp Mod làm việc đó nhẹ nhàng hơn.

Nếu diễn đàn khác có nhu cầu tương tự, cần dùng thì sửa Selector và liên kết ở @include cho phù hợp.


Cài đặt


https://openuserjs.org/scripts/baivong/S%E1%BB%ADa_ti%E1%BB%81n_t%E1%BB%91_cho_b%C3%A0i_vi%E1%BA%BFt
https://github.com/baivong/Userscript/blob/master/Forumotion/editPrefix.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        Sửa tiền tố cho bài viết
// @namespace  zzbaivong
// @description Nhấn [Sửa tiền tố] ở những bài chưa đổi tiền tố trong Thùng rác
// @include    http://devs.forumvi.com/f24-*
// @include    http://devs.forumvi.com/f24p*
// @version    1.0.1
// @grant      none
// ==/UserScript==

$(function () {
    $('.prefix').show();
    $('.stat4r a[href^=\'/t\']a[href*=\'#\']').attr('href', function () {
        return '/post?p=' + this.href.split('#') [1] + '&mode=editpost'
    }).text('[ Sửa tiền tố ]').css('float', 'right').click(function (d) {
        d.preventDefault();
        var b = this;
        $.post(b.href, function (a) {
            a = $(a);
            var c = '[' + $('.nav[href^=\'/f\']:last').text() + '] ' + $.trim(a.find('#modif_topic_title').val().replace(/\[([^\[\]])+\]/g, ''));
            $.post(b.href, {
                subject: c,
                modif_topic_title: c,
                message: a.find('#text_editor_textarea').val(),
                post: 'Send'
            }, function (a) {
                $(b).closest('tr').fadeOut(300)
            });
        })
    })
});



Zzbaivong (devs.forumvi.com)
Tags: #google-chrome #firefox #userscript #prefix

[Userscript] Beautify page source

Diễn đàn: UserscriptTrả lời: 2Lượt xem: 2517

 10.05.14 0:51

Xem mã nguồn website đã được định dạng bằng cách nhấn Alt+U.

Demo


Topics tagged under userscript on DEVs forumvi G7PNESO
Source đã được format

Gợi ý: Nếu tổ hợp phím Alt+U bị chặn, chọn Beautify Page Source trên menu User script command.
Nên sử dụng chung với js-css beautify

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/16112-viewsource
  2. https://openuserjs.org/scripts/baivong/viewsource
  3. https://github.com/baivong/Userscript/raw/master/view_source/view_source.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        viewsource
// @namespace    devs.forumvi.com
// @description  View and beautify page source. Shortcut: Alt+U.
// @version      3.1.0
// @icon        http://i.imgur.com/6yZMOeH.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://*/*
// @match        https://*/*
// @resource    js_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.min.js
// @resource    css_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.min.js
// @resource    html_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-html.min.js
// @resource    hljs https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @connect      *
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        GM.getResourceUrl
// @grant        GM_getResourceURL
// @grant        GM.xmlHttpRequest
// @grant        GM_xmlhttpRequest
// @grant        GM.openInTab
// @grant        GM_openInTab
// @grant        GM_registerMenuCommand
// ==/UserScript==

/* eslint-env worker, es6 */
(function () {
    'use strict';

    var doc = document,
        urlpage = location.href,
        urlbeautify = 'https://lelinhtinh.github.io/Userscript/?beautify-source=';

    if (!/^application\/(xhtml+xml|xml|rss+xml)|text\/(html|xml)$/.test(doc.contentType)) return;

    if (urlpage.indexOf(urlbeautify) !== 0) {
        var viewsource = function () {
            if (urlpage.indexOf(urlbeautify) === 0) return;
            GM.openInTab(urlbeautify + encodeURIComponent(urlpage), false);
        };

        GM_registerMenuCommand('Beautify Page Source', viewsource, 'u');
        doc.onkeydown = function (e) {
            if (e.which === 85 && e.altKey) { // Alt+U
                e.preventDefault();
                viewsource();
            }
        };

        return;
    }

    urlbeautify = urlpage.replace(urlbeautify, '');
    urlbeautify = decodeURIComponent(urlbeautify);

    var blobURL, worker,

        addstyle = function (aCss) {
            var head = doc.getElementsByTagName('head')[0];
            if (!head) return null;
            var style = doc.createElement('style');
            style.setAttribute('type', 'text/css');
            style.textContent = aCss;
            head.appendChild(style);
            return style;
        };

    blobURL = URL.createObjectURL(new Blob(['(',
        function () {
            self.window = {};

            self.onmessage = function (e) {
                var source = e.data.content;

                importScripts(e.data.libs[0]);
                importScripts(e.data.libs[1]);
                importScripts(e.data.libs[2]);
                source = self.window.html_beautify(source, { indent_scripts: 'keep' });

                self.postMessage({
                    action: 'beautify',
                    source: source
                });

                importScripts(e.data.libs[3]);
                source = self.window.hljs.highlight('xml', source, true).value;

                source = source.split('\n');
                source = source.join('</code><code>');
                source = '<code>' + source + '</code>';

                self.postMessage({
                    action: 'hljs',
                    source: source
                });
            };

        }.toString(),
        ')()'
    ], {
        type: 'text/javascript'
    }));
    worker = new Worker(blobURL);

    worker.onmessage = function (e) {
        if (!e.data) return;
        var fragment = doc.createDocumentFragment(),
            pre = doc.createElement('pre');

        if (e.data.action === 'beautify') {
            addstyle('*{margin:0;padding:0}html{line-height:1em;background:#1d1f21;color:#c5c8c6}pre{counter-reset:line-numbers;white-space:pre-wrap;word-wrap:break-word;word-break:break-all}code::before{counter-increment:line-numbers;content:counter(line-numbers);display:block;position:absolute;left:-4.5em;top:0;width:4em;text-align:right;color:#60686f;white-space:pre}code{display:block;position:relative;margin-left:4em;padding-left:.5em;min-height:1em;border-left:1px solid #32363b}pre{padding:.5em .5em .5em 5em;border-left:1px solid #1d1f21}pre.hljs{padding-left:.5em;border-left:0 none}code::after{content:".";visibility:hidden}a{color:#b5bd68}a:active,a:hover,a:visited{color:#8b9433} .hljs-comment,.hljs-quote{color:#969896}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#c66}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#de935f}.hljs-attribute{color:#f0c674}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#b5bd68}.hljs-title,.hljs-section{color:#81a2be}.hljs-keyword,.hljs-selector-tag{color:#b294bb}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}');

            pre.textContent = e.data.source;
            fragment.appendChild(pre);
            doc.body.appendChild(fragment);
        } else {
            pre.innerHTML = e.data.source;
            pre.className = 'hljs xml';
            fragment.appendChild(pre);
            doc.body.replaceChild(fragment, doc.getElementsByTagName('pre')[0]);

            var attrUrl = doc.getElementsByClassName('hljs-attr');
            for (var j = 0; j < attrUrl.length; j++) {
                if (/\b(src|href\b)/.test(attrUrl[j].textContent)) {
                    var link = attrUrl[j].nextSibling.nextSibling,
                        url = link.textContent,
                        quote = url.slice(0, 1);

                    if (quote !== '\'' && quote !== '"') {
                        quote = '';
                    } else {
                        url = url.slice(1, -1);
                    }

                    link.innerHTML = quote + '<a href="' + url + '" target="_blank">' + url + '</a>' + quote;
                }
            }
        }
    };

    var js_beautify = GM.getResourceUrl('js_beautify'),
        css_beautify = GM.getResourceUrl('css_beautify'),
        html_beautify = GM.getResourceUrl('html_beautify'),
        hljs = GM.getResourceUrl('hljs');

    GM.xmlHttpRequest({
        method: 'GET',
        url: urlbeautify,
        onload: function (response) {
            doc.title = 'beautify-source:' + urlbeautify;

            Promise.all([js_beautify, css_beautify, html_beautify, hljs]).then(function (urls) {
                worker.postMessage({
                    libs: urls,
                    content: response.response
                });
            });

            var baseUrl,
                baseMatch = response.response.match(/<base\s+href="([^"]+)"\s?[^>]*>/),
                base = doc.createElement('base');

            baseUrl = baseMatch ? baseMatch[1] : urlbeautify.replace(/[^/]*$/, '');

            base.href = baseUrl;
            doc.head.appendChild(base);
        }
    });

}());

Tags: #userscript #highlight #beautify #view-source

 07.05.14 20:47

Userscript này sẽ thay nền xem ảnh dạng lưới, tác dụng của nó thể hiện rõ nhất khi xem ảnh trong suốt. Đối với ảnh lớn, script này hỗ trợ bạn cuộn ảnh thuận tiện hơn bằng cách giữ chuột phải và kéo.

Demo


Topics tagged under userscript on DEVs forumvi YOBYNp4
Hiển thị rõ phần trong suốt của ảnh


Cài đặt


Dùng một trong các liên kết sau:

  1. https://openuserjs.org/scripts/baivong/Image_viewer
  2. https://greasyfork.org/vi/scripts/16113-image-viewer
  3. https://github.com/baivong/Userscript/raw/master/image_viewer/Image_viewer.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        Image viewer
// @namespace    http://devs.forumvi.com/
// @description  Use grid wallpaper to highlight transparent image. Support to view the large image by holding the right mouse and drag.
// @version      2.1.0
// @icon        http://i.imgur.com/ItcjCPc.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://*/*
// @match        https://*/*
// @noframes
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-start
// @grant        none
// ==/UserScript==

(function () {

    'use strict';

    /**
    * Background mode
    * @type {string} dark
    *                light
    */
    var theme = 'dark';


    // Do not change the code below this line, unless you know how.
    var doc = document,
        color = theme === 'light' ? ['#eee', 'white'] : ['gray', '#444'];

    if (doc.contentType.indexOf('image/') !== 0) return;

    function scrollByDragging(container, disableH, disableV) {

        function mouseUp(e) {
            if (e.which !== 3) return;

            window.removeEventListener('mousemove', mouseMove, true);
            container.style.cursor = 'default';
        }

        function mouseDown(e) {
            if (e.which !== 3) return;

            pos = {
                x: e.clientX,
                y: e.clientY
            };

            window.addEventListener('mousemove', mouseMove, true);
            container.style.cursor = 'move';
        }

        function mouseMove(e) {
            if (!disableH) container.scrollLeft -= (-pos.x + (pos.x = e.clientX));
            if (!disableV) container.scrollTop -= (-pos.y + (pos.y = e.clientY));
        }

        var pos = {
            x: 0,
            y: 0
        };

        container.oncontextmenu = function (e) {
            e.preventDefault();
        };

        container.addEventListener('mousedown', mouseDown, false);
        window.addEventListener('mouseup', mouseUp, false);

    }

    function addstyle(aCss) {
        var head = doc.getElementsByTagName('head')[0];
        if (!head) return null;
        var style = doc.createElement('style');
        style.setAttribute('type', 'text/css');
        style.textContent = aCss;
        head.appendChild(style);
        return style;
    }

    addstyle('body{background-attachment: fixed !important; background-position: 0px 0px, 10px 10px !important; background-size: 20px 20px !important; background-image: linear-gradient(45deg, ' + color[0] + ' 25%, transparent 25%, transparent 75%, ' + color[0] + ' 75%, ' + color[0] + ' 100%),linear-gradient(45deg, ' + color[0] + ' 25%, ' + color[1] + ' 25%, ' + color[1] + ' 75%, ' + color[0] + ' 75%, ' + color[0] + ' 100%) !important;} body > img {background-color: transparent !important; background-image: none !important; display: block; margin: auto; position: absolute; left: 0; top: 0; right: 0; bottom: 0;} body > img:hover {background: rgba(0, 0, 0, 0.4) !important; outline: 3px solid #333;} body > img[style*="cursor: zoom-out;"], body > img.overflowing {position: relative !important;}');

    scrollByDragging(doc.body);
    scrollByDragging(doc.documentElement);

}());




Ứng dụng xem ảnh trong forumotion


Demo


https://devs.forumvi.com/viewimage.forum?u=https://i.imgur.com/Yfl5NFO.gif

Hướng dẫn


Thêm vào CSS:
Code:
/* Image viewer - devs.forumvi.com */
p + center > a[href="javascript:window.close()"]{display:block;padding:15px;background:url('data:image/gif;base64,R0lGODlhCgAKAIAAAAAAAP///yH5BAEAAAAALAAAAAAKAAoAAAIRhB2ZhxoM3GMSykqd1VltzxQAOw==') repeat scroll #dddddd;}
p + center > a[href="javascript:window.close()"] img{border:1px solid transparent}
p + center > a[href="javascript:window.close()"] img:hover{border:1px dotted #c0c0c0;background-color:rgba(0,0,0,0.05)}

Tags: #userscript #photo #viewer

[Userscript] Download nhạc 320kbps từ mp3 zing

Diễn đàn: Lưu trữTrả lời: 35Lượt xem: 7843

 07.05.14 19:50

Userscript này sẽ cho phép bạn nghe và tải nhạc chất lượng cao từ mp3 zing, bao gồm các bài hát thu phí.

Demo


[You must be [You must be registered and logged in to see this link.] and [You must be registered and logged in to see this link.] to see this image.]
Download bài hát


Download album

Kiểm tra chất lượng:


Cài đặt


Dùng một trong các link sau:

  1. [You must be registered and logged in to see this link.]
  2. [You must be registered and logged in to see this link.]
  3. [You must be registered and logged in to see this link.]

Sau khi cài đặt, nhấp vào các liên kết bên dưới để kiểm tra:

  1. [You must be registered and logged in to see this link.]
  2. [You must be registered and logged in to see this link.]
  3. [You must be registered and logged in to see this link.]
  4. [You must be registered and logged in to see this link.]

Mã nguồn


Code:
// ==UserScript==
// @name        Download nhạc mp3 zing 320kbps
// @namespace    baivong.download.mp3zing
// @description  Nghe và tải nhạc nhất lượng cao 320kbps tại mp3.zing.vn
// @version      5.7.0
// @icon        http://i.imgur.com/PnF4UN2.png
// @author      Zzbaivong
// @license      MIT
// @match        http://mp3.zing.vn/*
// @require      https://ajax.googleapis.com/ajax/libs/jquery/2.2.4/jquery.min.js
// @require      https://cdnjs.cloudflare.com/ajax/libs/FileSaver.js/1.3.3/FileSaver.min.js
// @noframes
// @connect      zing.vn
// @connect      zadn.vn
// @connect      zdn.vn
// @supportURL  https://github.com/baivong/Userscript/issues
// @run-at      document-idle
// @grant        GM_xmlhttpRequest
// @grant        GM_addStyle
// ==/UserScript==

(function ($, window, document) {
    'use strict';

    /**
    * Cookie tài khoản VIP
    * 04/10/2017
    */
    var vipKey = 'miup.107493696.0.HpC1cghJzuNgwf-3gjFtXT_Hfbc9CFm2gxSKCFFJzuK';


    GM_addStyle('.bv-icon{background-image:url(http://static.mp3.zdn.vn/skins/zmp3-v4.1/images/icon.png)!important;background-repeat:no-repeat!important;background-position:-25px -2459px!important;}.bv-download{background-color:#721799!important;border-color:#721799!important;}.bv-download span{color:#fff!important;margin-left:8px!important;}.bv-disable,.bv-download:hover{background-color:#2c3e50!important;border-color:#2c3e50!important;}.bv-text{background-image:none!important;color:#fff!important;text-align:center!important;font-size:smaller!important;line-height:25px!important;}.bv-waiting{cursor:wait!important;background-color:#2980b9!important;border-color:#2980b9!important;}.bv-complete,.bv-complete:hover{background-color:#27ae60!important;border-color:#27ae60!important;}.bv-error,.bv-error:hover{background-color:#c0392b!important;border-color:#c0392b!important;}.bv-disable{cursor:not-allowed!important;opacity:0.4!important;}');

    function getCookie(name) {
        var cname = name + '=',
            cpos = document.cookie.indexOf(cname),
            cstart,
            cend;

        if (cpos !== -1) {
            cstart = cpos + cname.length;
            cend = document.cookie.indexOf(';', cstart);
            if (cend === -1) cend = document.cookie.length;
            return decodeURIComponent(document.cookie.substring(cstart, cend));
        }

        return null;
    }

    function setCookie(cname, cvalue, exdays, path) {
        var domain = '',
            d = new Date();

        if (exdays) {
            d.setTime(d.getTime() + (exdays * 24 * 60 * 60 * 1000));
            exdays = '; expires=' + d.toUTCString();
        }
        if (!path) path = '/';

        document.cookie = cname + '=' + cvalue + '; path=' + path + exdays + domain + ';';
    }

    function getParams(name, url) {
        if (!url) url = window.location.href;
        name = name.replace(/[\[\]]/g, '\\$&');
        var regex = new RegExp('[?&]' + name + '(=([^&#]*)|&|#|$)'),
            results = regex.exec(url);
        if (!results) return null;
        if (!results[2]) return '';
        return decodeURIComponent(results[2].replace(/\+/g, ' '));
    }

    function setQuanlity(qty) {
        var $qtyStyle = $('#bv-quanlity-style');

        if (!$qtyStyle.length) $qtyStyle = $('<style />', {
            id: 'bv-quanlity-style',
            type: 'text/css'
        }).appendTo('head');

        $qtyStyle.text('.zm-quanlity-display{font-size:0!important}.zm-quanlity-display::after{content:"' + qty + '";font-size:12px!important}');
    }

    function albumCounter() {
        if (!enableAlbum) return;
        if (!$album.length) return;

        var temp = ++listCurr;
        if (temp === listSize) {
            $btnAll.removeClass('bv-waiting').addClass('bv-disable').off('click');
            $txtAll.text('Đã tải toàn bộ');
            return;
        }

        $txtAll.text('Đã tải ' + temp + '/' + listSize);

        if ($list.eq(temp).attr('href') !== '#download') {
            albumCounter();
            return;
        }
        multiDownloads($list.eq(temp));
    }

    function getData(callback, songCode) {
        var url = $('#zplayerjs-wrapper').data('xml'),
            key;

        if (songCode) {
            key = songCode;
            url = '/json/song/get-source/' + songCode;
        } else {
            key = getParams('key', url);
            url = 'http://mp3.zing.vn/xhr' + url;
        }

        if (cache[key]) {
            callback(cache[key]);
            return;
        }

        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            headers: {
                'Cookie': 'wsid=' + vipKey
            },
            responseType: 'json',

            onload: function (source) {
                var data = source.response.data;

                if (data) {
                    cache[key] = data;
                    callback(data);
                } else {
                    callback();
                }
            },

            onerror: function (e) {
                console.error(e);
                callback();
            }
        });
    }

    function downloadSong(url, name, progress, complete, error) {
        GM_xmlhttpRequest({
            method: 'GET',
            url: url,
            responseType: 'blob',

            onload: function (source) {
                complete(source.response, name + '.mp3');
                albumCounter();
            },

            onprogress: function (e) {
                if (e.lengthComputable) {
                    progress(Math.floor(e.loaded * 100 / e.total) + '%');
                } else {
                    progress('');
                }
            },

            onerror: function (e) {
                console.error(e);
                error();
                albumCounter();
            }
        });
    }

    function baiHat() {
        var $largeBtn = $('#tabService'),
            $btn = $('<a>', {
                class: 'button-style-1 pull-left bv-download',
                href: '#download',
                html: '<i class="zicon icon-dl"></i>'
            }),
            $txt = $('<span>', {
                text: 'Tải nhạc 320kbps'
            }),
            downloadFail = function () {
                $btn.removeClass('bv-waiting').addClass('bv-error');
                $txt.text('Lỗi! Không tải được');
            };

        $largeBtn.replaceWith($btn.append($txt));

        getData(function (data) {
            if (data && data.source && data.source['320']) {
                $('#zplayerjs').attr('src', data.source['320']);
                setQuanlity('320kbps');

                $btn.attr({
                    'data-name': data.link.match(/^\/bai-hat\/([^\/]+)/)[1],
                    'data-mp3': data.source['320']
                });
            } else {
                setQuanlity('128kbps');

                downloadFail();
                return;
            }
        });

        $btn.one('click', function (e) {
            e.preventDefault();

            $btn.addClass('bv-waiting');
            $txt.text('Chờ một chút...');

            downloadSong(
                $btn.data('mp3'),
                $btn.data('name'),
                function (percent) {
                    $txt.text('Đang tải... ' + percent);
                },
                function (blob, fileName) {
                    $btn.attr({
                        href: window.URL.createObjectURL(blob),
                        download: fileName
                    }).removeClass('bv-waiting').addClass('bv-complete').off('click');
                    $txt.text('Nhấn để tải nhạc');

                    saveAs(blob, fileName);
                },
                function () {
                    downloadFail();
                }
            );
        });
    }

    function multiDownloads($btn) {
        $btn.addClass('bv-waiting bv-text').text('...').attr({
            href: '#downloading'
        });

        downloadSong(
            $btn.data('mp3'),
            $btn.data('name'),
            function (percent) {
                if (percent !== '') {
                    $btn.text(percent);
                }
            },
            function (blob, fileName) {
                $btn.attr({
                    href: window.URL.createObjectURL(blob),
                    download: fileName
                }).removeClass('bv-waiting bv-text').addClass('bv-complete').text('').off('click');

                saveAs(blob, fileName);
            },
            function () {
                $btn.removeClass('bv-waiting bv-text').addClass('bv-error').text('');
            }
        );
    }

    function album() {
        getData(function (data) {
            var playlist = window.eval('window.playlist;'),
                download = function (e) {
                    e.preventDefault();
                    multiDownloads($(this));
                };

            if (!(data && data.items)) return;
            setQuanlity('320kbps');

            $album.find('.fn-dlsong').each(function (i, v) {
                if (data.items[i] && data.items[i].source && data.items[i].source['320']) {
                    playlist[i].sourceLevel[0].source = data.items[i].source['320'];
                    $(v).replaceWith('<a title="Tải nhạc 320kbps" class="bv-download bv-album-download bv-icon" href="#download" data-name="' + data.items[i].link.match(/^\/bai-hat\/([^\/]+)/)[1] + '" data-mp3="' + data.items[i].source['320'] + '"></a>');
                }
            });

            window.eval('var disableRePlaying; player2.on("play", function (){ if (!disableRePlaying) { $(".fn-name", ".playing.fn-current").click(); disableRePlaying = true; } });');

            $btnAll = $('<a>', {
                class: 'button-style-1 pull-left bv-download',
                href: '#download-album',
                html: '<i class="zicon icon-dl"></i>'
            });
            $txtAll = $('<span>', {
                text: 'Tải toàn bộ'
            });
            $btnAll.append($txtAll).insertAfter('#tabAdd');

            if (!checkList()) return;

            $list.on('contextmenu', function (e) {
                e.preventDefault();
                var $this = $(this),
                    href = $this.attr('href');

                if (href === '#download') {
                    $this.addClass('bv-disable').attr({
                        href: '#download-disabled',
                    }).off('click', download);
                } else if (href === '#download-disabled') {
                    $this.removeClass('bv-disable').attr({
                        href: '#download',
                    }).one('click', download);
                }
            }).one('click', download);

            $btnAll.one('click', function (e) {
                e.preventDefault();

                if (!checkList()) {
                    $btnAll.addClass('bv-error').off('click');
                    $txtAll.text('Không có nhạc cần tải');
                    return;
                }

                enableAlbum = true;
                $btnAll.addClass('bv-waiting');
                $txtAll.text('Đang tải...');

                $list.off('click');

                listCurr = 0;
                multiDownloads($list.eq(listCurr));
            });
        });
    }

    function video() {
        var videoPlay = function (qty) {
            getData(function (data) {
                if (data && data.source && data.source[qty]) {
                    window.eval('player2.setSource("' + data.source[qty] + '");');
                } else {
                    console.warn(data);
                }

                setCookie('videoQuanlity', qty, 30, '/');
                setQuanlity(qty);
            });
        }

        if (getCookie('videoQuanlity') !== null) videoPlay(getCookie('videoQuanlity'));

        $(document).on('click', '.zm-list-quanlity li', function (e) {
            e.preventDefault();
            var qty = this.textContent.replace('(VIP)', '').trim();

            videoPlay(qty);
        });
    }

    function checkPath(key) {
        return (location.pathname.indexOf('/' + key + '/') === 0);
    }


    window.URL = window.URL || window.webkitURL;
    var cache = [];

    window.eval('zmp3Login._show = zmp3Login.show; zmp3Login.show = function (){ return; }; $(".fn-login").on("click", zmp3Login._show);');

    if (checkPath('bai-hat')) baiHat();
    if (checkPath('video-clip')) video();

    var $album = $('#playlistItems'),
        $btnAll,
        $txtAll,
        $list,
        listCurr = 0,
        listSize = 0,
        checkList = function () {
            $list = $album.find('.bv-album-download[href="#download"]');
            listSize = $list.length;

            return listSize > 0;
        },
        enableAlbum;
    if (checkPath('album') || checkPath('playlist')) album();

    $(document).on('mouseenter', 'li[data-code]', function (e) {
        e.preventDefault();
        var $this = $(this),
            $btn = $this.find('.fn-dlsong');

        if ($this.closest('#playlistItems').length) return;
        if ($this.data('code') === '') return;
        if (!$btn.length) return;

        $btn.replaceWith(function () {
            return '<a title="Tải nhạc 320kbps" class="bv-download bv-multi-download bv-icon" href="#download" data-code="' + $this.data('code') + '"></a>';
        });
    }).on('click', '.bv-multi-download', function (e) {
        e.preventDefault();
        var $this = $(this);

        getData(function (data) {
            if (data && data[0].source_list && data[0].source_list.length >= 2 && data[0].source_list[1] !== '') {
                $this.attr({
                    'data-name': data[0].link.match(/^\/bai-hat\/([^\/]+)/)[1],
                    'data-mp3': data[0].source_list[1]
                });
                multiDownloads($this);
            } else {
                $this.removeClass('bv-waiting bv-text').addClass('bv-error').text('');
            }
        }, $this.data('code'));
    });

})(jQuery, window, document);


Hướng dẫn


Chỉ có tuỳ chọn nghe và tải xuống duy nhất là 320kbps, với những bài có chất lượng thấp hơn sẽ không tải được.
Những vị trí tải được thì khi rê chuột lên sẽ hiện nút tải xuống màu tím.
Khi dùng chức năng tải toàn bộ trong album, nếu không muốn tải xuống bài nào, thì nhấp chuột phải nên nút tải của bài đó, để vô hiệu hoá nó.

Một số trang cho phép tải nhạc chất lượng cao khác.

  • CSN : [You must be registered and logged in to see this link.]
  • NhacPro : [You must be registered and logged in to see this link.]
  • Youtube : Xem hướng dẫn Tải nhạc MP3 từ Youtube dùng Youtube-DL và Firefox

Tags: [You must be registered and logged in to see this link.]

[Userscript] Javascript-css beautify

Diễn đàn: UserscriptTrả lời: 2Lượt xem: 2641

 05.05.14 5:23

Javascript-css beautify chỉ hoạt động với các URL file js/json/css. Tác dụng của nó là định dạng và làm nổi cú pháp trong code, giúp việc đọc code thuận tiện hơn.

Demo


Topics tagged under userscript on DEVs forumvi Z2fhzSR
File CSS

Topics tagged under userscript on DEVs forumvi Rt0HUaw
File Javascript

Cài đặt


Dùng một trong các link sau:

  1. https://greasyfork.org/vi/scripts/16111-javascript-css-beautify
  2. https://openuserjs.org/scripts/baivong/Javascript-css_beautify
  3. https://github.com/baivong/Userscript/raw/master/js-css_beautify/js-css_beautify.user.js

Mã nguồn


Code:
// ==UserScript==
// @name        Javascript-css beautify
// @namespace    http://devs.forumvi.com
// @description  Beautify and syntax highlighting for source code javascript, json, css.
// @version      3.1.0
// @icon        http://i.imgur.com/kz8nqz1.png
// @author      Zzbaivong
// @oujs:author  baivong
// @license      MIT; https://baivong.mit-license.org/license.txt
// @match        http://*/*
// @match        https://*/*
// @resource    js_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify.min.js
// @resource    css_beautify https://cdnjs.cloudflare.com/ajax/libs/js-beautify/1.7.5/beautify-css.min.js
// @resource    hljs https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.12.0/highlight.min.js
// @require      https://greasemonkey.github.io/gm4-polyfill/gm4-polyfill.js?v=a834d46
// @noframes
// @supportURL  https://github.com/lelinhtinh/Userscript/issues
// @run-at      document-idle
// @grant        GM.getResourceUrl
// @grant        GM_getResourceURL
// ==/UserScript==

/* eslint-env worker, es6 */
(function () {
    'use strict';

    var doc = document,
        contenttype = doc.contentType,
        pathname = location.pathname;

    if (!(/^application\/(x-javascript|javascript|json)|text\/css$/.test(contenttype) || (/.+\.(js|json|css)$/.test(pathname) && !/^application\/(xhtml+xml|xml|rss+xml)|text\/(html|xml)$/.test(contenttype)))) return;

    var output = doc.getElementsByTagName('pre')[0],
        lang = 'javascript',
        blobURL, worker,

        addstyle = function (aCss) {
            var head = doc.getElementsByTagName('head')[0];
            if (!head) return null;
            var style = doc.createElement('style');
            style.setAttribute('type', 'text/css');
            style.textContent = aCss;
            head.appendChild(style);
            return style;
        };

    if (contenttype === 'text/css' || /.+\.css$/.test(pathname)) lang = 'css';

    blobURL = URL.createObjectURL(new Blob(['(',
        function () {
            self.window = {};

            self.onmessage = function (e) {
                var source = e.data.content,
                    beautify = 'js_beautify';

                if (e.data.lang === 'javascript') {
                    importScripts(e.data.libs[0]);
                } else {
                    importScripts(e.data.libs[1]);
                    beautify = 'css_beautify';
                }
                source = self.window[beautify](source);

                self.postMessage({
                    action: 'beautify',
                    source: source
                });

                importScripts(e.data.libs[2]);
                source = self.window.hljs.highlight(e.data.lang, source, true).value;

                source = source.split('\n');
                source = source.join('</code><code>');
                source = '<code>' + source + '</code>';

                self.postMessage({
                    action: 'hljs',
                    source: source
                });
            };

        }.toString(),
        ')()'
    ], {
        type: 'text/javascript'
    }));
    worker = new Worker(blobURL);

    worker.onmessage = function (e) {
        if (!e.data) return;

        var fragment = doc.createDocumentFragment(),
            pre = doc.createElement('pre');

        if (e.data.action === 'beautify') {
            addstyle('*{margin:0;padding:0}html{line-height:1em;background:#1d1f21;color:#c5c8c6}pre{counter-reset:line-numbers;white-space:pre-wrap;word-wrap:break-word;word-break:break-all}code::before{counter-increment:line-numbers;content:counter(line-numbers);display:block;position:absolute;left:-4.5em;top:0;width:4em;text-align:right;color:#60686f;white-space:pre}code{display:block;position:relative;margin-left:4em;padding-left:.5em;min-height:1em;border-left:1px solid #32363b}pre{padding:.5em .5em .5em 5em;border-left:1px solid #1d1f21}pre.hljs{padding-left:.5em;border-left:0 none}code::after{content:".";visibility:hidden} .hljs-comment,.hljs-quote{color:#969896}.hljs-variable,.hljs-template-variable,.hljs-tag,.hljs-name,.hljs-selector-id,.hljs-selector-class,.hljs-regexp,.hljs-deletion{color:#c66}.hljs-number,.hljs-built_in,.hljs-builtin-name,.hljs-literal,.hljs-type,.hljs-params,.hljs-meta,.hljs-link{color:#de935f}.hljs-attribute{color:#f0c674}.hljs-string,.hljs-symbol,.hljs-bullet,.hljs-addition{color:#b5bd68}.hljs-title,.hljs-section{color:#81a2be}.hljs-keyword,.hljs-selector-tag{color:#b294bb}.hljs{display:block;overflow-x:auto;background:#1d1f21;color:#c5c8c6;padding:.5em}.hljs-emphasis{font-style:italic}.hljs-strong{font-weight:700}');

            pre.textContent = e.data.source;
        } else {
            pre.innerHTML = e.data.source;
            pre.className = 'hljs ' + lang;
        }

        fragment.appendChild(pre);
        doc.body.replaceChild(fragment, output);

        if (e.data.action === 'beautify') output = doc.getElementsByTagName('pre')[0];
    };

    var js_beautify = GM.getResourceUrl('js_beautify'),
        css_beautify = GM.getResourceUrl('css_beautify'),
        hljs = GM.getResourceUrl('hljs');

    Promise.all([js_beautify, css_beautify, hljs]).then(function (urls) {
        worker.postMessage({
            libs: urls,
            lang: lang,
            content: output.textContent
        });
    });

}());

Tags: #userscript #highlight #beautify #source-code

[Userscript] Giới thiệu User script và cách sử dụng

Diễn đàn: UserscriptTrả lời: 8Lượt xem: 8987

 27.11.13 2:15

Userscript là gì?


Userscript (hoặc User script) là các script dùng trong trình duyệt, hướng tới việc đọc thông tin của trang web hoặc thay đổi chúng.

Topics tagged under userscript on DEVs forumvi Unlock10
Anti Social Locker

Về cơ bản, Userscript là JavaScript, được bổ sung một số API mạnh mẽ mà thông thường không được phép.
Userscript thường không được phép cài trực tiếp vào trình duyệt, mà phải chạy thông qua một tiện ích (extension) quản lý, nếu không trình duyệt sẽ xem nó như một tệp JavaScript thông thường. Các trình duyệt nhân Chromium cho phép nó chạy như một tiện ích, tuy nhiên có nhiều hạn chế.
Tùy thuộc vào tiện ích quản lý mà Userscript có đuôi mở rộng khác nhau như .tamper.js, .grease.js, .ieuser.js, ... Tuy nhiên, phổ biến nhất vẫn là .user.js, hầu hết các tiện ích quản lý đều hỗ trợ đuôi này.
Từ Userscript, bạn có thể nâng cấp nó thành tiện ích trình duyệt với các API dành cho Content script.

Topics tagged under userscript on DEVs forumvi Youtub10
Download YouTube Videos as MP4

Mặc dù những gì Userscript làm được thì các Extension cũng làm được và còn hơn nữa, nhưng Userscript vẫn tồn tại. Đó là vì, muốn tạo ra Extension cho trình duyệt thì còn phải theo sự kiểm soát của chủ quản trình duyệt đó, còn Userscript là anh chàng Libero linh hoạt hơn nhiều. Như trong ảnh minh họa trên, Extension download video từ Youtube bị cấm trên Google Chrome, nhưng với Userscript bạn vẫn sẽ có được chức năng đó.

Cách sử dụng


Cài tiện ích quản lý


Tùy vào trình duyệt bạn sử dụng mà tải tiện ích quản lý Userscript phù hợp.

  • Firefox: Greasemonkey hoặc Tampermonkey
  • Chrome: Tampermonkey hoặc Violentmonkey
  • Opera: Tampermonkey hoặc Violentmonkey
  • Safari: Tampermonkey
  • Microsoft Edge: Tampermonkey
  • Maxthon: Violentmonkey
  • Dolphin: Tampermonkey
  • UC: Tampermonkey
  • Qupzilla: Greasemonkey (Có sẵn, bật trong Edit > Preferences > Extensions)

Với các trình duyệt mà mình gợi ý hai tiện ích nổi bật, bạn nên dùng tiện ích đầu. Có thể còn tiện ích khác nhưng chậm cập nhật hoặc không hoạt động nên mình không đưa vào.
Bạn có thể thấy được sự phổ biến của tiện ích Tampermonkey, tuy nhiên nếu bạn có ý định viết Userscript một lần rồi chạy ở tất cả trình duyệt sẽ rất nhanh thất vọng. Vì tùy vào trình duyệt và phiên bản, mức độ hỗ trợ API của tiện ích này cũng không giống nhau.

Cài Userscript


Sau khi cài tiện ích quản lý, bạn có thể vào trang chia sẻ như OpenUserjs, GreasyFork để tìm một Userscript phù hợp và nhấn Cài đặt (Install).
Đây là hai cộng đồng sử dụng và phát triển Userscript lớn nhất hiện nay. OpenUserJs có giao diện đẹp và quản lý dễ dãi hơn, còn GreasyFork có cộng đồng đông đảo và chức năng quản lý tốt hơn.

Ngoài ra, bạn cũng có thể cài đặt Userscript từ nguồn không chính thống khác như Github Gist.
Hoặc dùng chức năng tạo Userscript mới (New Userscript...) trên tiện ích quản lý, và sử dụng mã nguồn được chia sẻ.

Cảnh báo


Trang Userscripts mirror là một bản sao của Userscripts.org, đã bị đóng cửa bởi chủ quản, với lý do chứa nhiều mã độc, không thể kiểm soát.
Các Userscript trong này đã không còn được cập nhật. Nếu bạn là nhà phát triển, có thể ghé qua lấy ý tưởng, tham khảo. Còn nếu bạn là người dùng thông thường, thì không nên sử dụng trang này.

Userscript có thể chèn mã độc, đánh cắp thông tin, gây tổn hại đến người dùng. Vì thế, không nên sử dụng từ nguồn không đáng tin cậy, tránh dùng các Userscript bị nén, bị mã hóa.

Cách viết Userscript


Userscript luôn chứa một Metadata Block, được đặt ở phần đầu mã nguồn. Đây là nơi khai báo các thông tin như tên, phiên bản, giới hạn sử dụng...

Định dạng chuẩn của một Metadata Block.
Code:
// ==UserScript==
// @key1  value1
// @key2  value2
// @keyN  valueN
// ==/UserScript==


Việc hỗ trợ khóa (key) Metadata cũng khác nhau tùy tiện ích quản lý, nên mình chỉ giới thiệu các khóa phổ biến, dựa trên Greasemonkey, và một số khóa quan trọng trong các tiện ích quản lý thông dụng.

Các khóa Metadata


@name


Tên của Userscript, bạn nên sử dụng tiếng Anh hoặc viết không dấu, và không ký tự đặc biệt, vì nó cũng được dùng làm tên tệp. Ví dụ:
Code:
// @name  anti social locker


@namespace


Tên bổ sung, nó được kết hợp với @name để tạo thành cặp khóa định danh cho Userscript đó, nếu bạn tạo ra một Userscript mới mà cặp khóa này trùng nhau, tiện ích quản lý sẽ xem nó như một bản cập nhật và thay thế nó. Vì @namespace không có nghĩa nên tác giả thường dùng để đăng URL website, một số tiện ích quản lý cũng dùng khóa này để xác định Trang chủ của Userscript. Ví dụ:
Code:
// @namespace  http://baivong.github.io/


@description


Giới thiệu thông tin sơ lược. Ví dụ:
Code:
// @description  Anti social locker plugin required user like or share before viewing content. If script doesn't work, please refresh the page to rebuild the cache and try again.


@version


Phiên bản hiện tại. Giá trị này được tiện ích quản lý sử dụng để cập nhật Userscript. Xem thêm quy chuẩn Semantic Versioning để hiểu cách viết phiên bản. Ví dụ:
Code:
// @version  1.0.0


@icon


URL icon, ảnh đại diện cho Userscript. Ví dụ:
Code:
// @icon  http://i.imgur.com/nOuUrIW.png


@author


Tên tác giả. Ví dụ:
Code:
// @author  Zzbaivong


@license


Tên hoặc URL đến giấy phép sử dụng Userscript. Truy cập Choose a License để biết thêm thông tin và cách lựa chọn. Ví dụ:
Code:
// @license  MIT


@include


Giới hạn địa chỉ trang web mà Userscript sẽ chạy, có thể dùng biểu thức chính quy (Regular Expressions). Khóa này có thể dùng nhiều lần. Ví dụ:
Code:
// @include  /^https?://*/*.js$/
// @include  /^https?://*/*.css$/


@match


Chức năng tương tự @include nhưng được đặt quy tắc nghiêm ngặt hơn trong cách sử dụng dấu *, không được dùng biểu thức chính quy. Xem chi tiết về Match Patterns. Ví dụ:
Code:
// @match  http://*/*.js
// @match  https://*/*.js
// @match  http://*/*.css
// @match  https://*/*.css


@exclude


Cách dùng tương tự @include nhưng có vai trò ngược lại, nó loại trừ địa chỉ trang web mà Userscript sẽ chạy. Ví dụ:
Code:
// @exclude  /^https?://*/*.json$/
// @exclude  /^https?://*/*.less$/


@downloadURL


URL để cập nhật Userscript. Nếu không dùng khóa này, tiện ích quản lý sẽ dùng URL lúc bạn tải về để làm URL cập nhật. Ví dụ:
Code:
// @downloadURL  https://openuserjs.org/install/baivong/anti_social_locker.user.js


@updateURL


URL để kiểm tra thông tin phiên bản, có đuôi .meta.js, thông thường chỉ chứa Metadata Block (tối thiểu phải có 3 khóa @version, @name,
Code:
@namespace

). Nếu thông tin @version trong này mới hơn thì tiện ích quản lý sẽ tiến hành cập nhật Userscript. Nếu không dùng khóa này, tiện ích quản lý sẽ dùng URL lúc bạn tải về, hoặc khóa @downloadURL để làm kiểm tra thông tin phiên bản. Ví dụ:
Code:
// @updateURL  https://openuserjs.org/install/baivong/anti_social_locker.meta.js


@supportURL


URL dẫn đến trang hỗ trợ, báo lỗi. Ví dụ:
Code:
// @supportURL  https://github.com/baivong/Userscript/issues


@require


URL của thư viện JavaScript cần sử dụng. Khóa này có thể dùng nhiều lần. Ví dụ:
Code:
// @require  https://code.jquery.com/jquery-2.2.4.min.js
// @require  https://greasyfork.org/scripts/19855-jszip/code/jszip.js
// @require  https://greasyfork.org/scripts/18532-filesaver/code/FileSaver.js


@resource


Bổ sung thêm tài nguyên để sử dụng, chúng sẽ được tải về máy người dùng nên sẽ nhanh và ổn định hơn dùng URL trực tuyến. Bạn có thể truy cập thông qua API GM_getResourceText hoặc GM_getResourceURL. Khóa này có thể dùng nhiều lần. Ví dụ:
Code:
// @resource  devsLogo https://baivong.github.io/css/images/logo-header.png
// @resource  lightTheme https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/github-gist.min.css
// @resource  darkTheme https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.11.0/styles/monokai-sublime.min.css


@run-at


Thời điểm chạy Userscript so với trang web. Bao gồm 3 giá trị document-start, document-end document-idle. Ví dụ:
Code:
// @run-at document-idle


@noframes


Ngăn không cho Userscript chạy trong thẻ nhúng như iframe. Nó không có đối số, chỉ là dùng hoặc không dùng. Nên sử dụng khóa này để tránh lỗi hiệu suất, nhất là với các trang có quảng cáo nhúng. Ví dụ:
Code:
// @noframes


@grant


Yêu cầu cấp quyền sử dụng API đặc biệt với tiện ích quản lý, không có nó, tiện ích quản lý có thể đưa ra thông tin sai, gây lỗi. Các quyền này có thể khiến Userscript của bạn bị cách ly (sandbox) với các script trong trang. Nếu bạn không yêu cầu quyền API đặc biệt hãy đặt giá trị none. Khóa này có thể dùng nhiều lần. Ví dụ:
Code:
// @grant GM_addStyle
// @grant GM_getResourceText


@connect


Đây là khóa bổ sung khi yêu cầu API GM_xmlhttpRequest, nó xác định tên miền chứa dữ liệu cần lấy. Bao gồm các giá trị: domain (cũng sẽ bao gồm toàn bộ sub-domain), sub-domain, IP address, localhost, self (trang mà Userscript đang chạy), * (tất cả). Khóa này có thể dùng nhiều lần. Ví dụ:
Code:
// @connect baivong.github.io
// @connect self


Chú ý


Một Metadata Block tối thiểu phải có 3 khóa @name, @namespace, @grant (có tiện ích quản lý yêu cầu thêm @match, @id).
Tài nguyên từ @require@resource chỉ được tải về một lần vào máy người dùng, đến khi có bản cập nhật thì nó mới tải lại.

Sau khi tạo Metadata Block, bạn đã có thể bắt đầu viết code cho nó bằng JavaScript ở bên dưới, sử dụng thêm API nếu cần thiết. Tuy nhiên, mức độ hỗ trợ API của mỗi tiện ích quản lý đều có vài điểm khác biệt, trong bài này mình chỉ hướng dẫn cách tạo Userscript cơ bản với Javascript. Nếu bạn muốn viết nâng cao hơn thì nên tìm xem các tài liệu API của tiện ích quản lý mà bạn sử dụng. Ví dụ:
Code:
// ==UserScript==
// @name reverse
// @namespace Zzbaivong
// @grant none
// ==/UserScript==

document.body.style.transform = "rotate(180deg)";


Bạn có thể cài trực tiếp Userscript vào trình duyệt nhân Chromium, tuy nhiên nó chỉ cho phép các khóa @name, @namespace, @description, @version, @match, @include, @exclude và một số API (không bắt buộc dùng @grant) GM_log, GM_openInTab, GM_addStyle, GM_xmlhttpRequest (chỉ trong cùng nguồn, tương đương @connect self). Ví dụ:
Code:
// ==UserScript==
// @match http://github.com/*
// ==/UserScript==

GM_openInTab("https://github.com/baivong/Userscript");

Tags: #userscript #extension #tutorial #browser


Back to top