`, { id : 'status-bar', class : 'status-bar' }));
53 | }
54 |
55 | static bottom(message){
56 | if($("#status-bar-bottom").length <= 0){
57 | $('body').append($(`
`, { id : 'status-bar-bottom', class : 'status-bar-bottom' }));
58 | }
59 |
60 | $("#status-bar-bottom").html(`Cover Next: ` + message);
61 | }
62 | }
63 |
64 | export default StatusBar;
65 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "cover-next",
3 | "version": "1.0.0",
4 | "description": "tools that will help you see new items and make it easier for you to use the website to load bittorrent.",
5 | "main": "cover-next.js",
6 | "repository": "https://github.com/kon3ko/cover-next",
7 | "author": "Neko",
8 | "license": "MIT",
9 | "scripts": {
10 | "dev": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --mode=development",
11 | "build": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --mode=production --node-env=production",
12 | "build:dev": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --mode=development",
13 | "build:prod": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --mode=production --node-env=production",
14 | "watch": "export NODE_OPTIONS=--openssl-legacy-provider && webpack --watch --mode=development --node-env=development",
15 | "serve": "webpack serve"
16 | },
17 | "engines": {
18 | "node": ">=18.0.0"
19 | },
20 | "devDependencies": {
21 | "@babel/core": "^7.14.6",
22 | "@babel/plugin-transform-runtime": "^7.14.5",
23 | "@babel/preset-env": "^7.14.7",
24 | "@webpack-cli/generators": "^2.2.0",
25 | "autoprefixer": "^10.4.20",
26 | "babel-core": "^6.26.3",
27 | "babel-loader": "^8.2.2",
28 | "babel-preset-env": "^1.7.0",
29 | "css-loader": "^5.2.6",
30 | "javascript-obfuscator": "^4.1.1",
31 | "postcss": "^8.4.41",
32 | "postcss-loader": "^8.1.1",
33 | "postcss-preset-env": "^10.0.1",
34 | "prettier": "^2.3.2",
35 | "sass": "^1.35.2",
36 | "sass-loader": "^12.1.0",
37 | "style-loader": "^3.0.0",
38 | "tailwindcss": "^3.4.10",
39 | "webpack": "^5.44.0",
40 | "webpack-cli": "^4.7.2",
41 | "webpack-dev-server": "^3.11.2",
42 | "webpack-obfuscator": "^3.5.1"
43 | },
44 | "dependencies": {
45 | "@babel/runtime": "^7.14.6",
46 | "@fancyapps/ui": "^4.0.0-alpha.4",
47 | "crypto-browserify": "^3.12.0",
48 | "crypto-js": "^4.2.0",
49 | "hash.js": "^1.1.7",
50 | "jquery": "^3.6.0"
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/dist/cover-next.js.LICENSE.txt:
--------------------------------------------------------------------------------
1 | /*!
2 | * Sizzle CSS Selector Engine v2.3.6
3 | * https://sizzlejs.com/
4 | *
5 | * Copyright JS Foundation and other contributors
6 | * Released under the MIT license
7 | * https://js.foundation/
8 | *
9 | * Date: 2021-02-16
10 | */
11 |
12 | /*!
13 | * jQuery JavaScript Library v3.6.0
14 | * https://jquery.com/
15 | *
16 | * Includes Sizzle.js
17 | * https://sizzlejs.com/
18 | *
19 | * Copyright OpenJS Foundation and other contributors
20 | * Released under the MIT license
21 | * https://jquery.org/license
22 | *
23 | * Date: 2021-03-02T17:08Z
24 | */
25 |
26 | /** @preserve
27 | * Counter block mode compatible with Dr Brian Gladman fileenc.c
28 | * derived from CryptoJS.mode.CTR
29 | * Jan Hruby jhruby.web@gmail.com
30 | */
31 |
32 | /** @preserve
33 | (c) 2012 by Cédric Mesnil. All rights reserved.
34 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
35 | - Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
36 | - Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
37 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
38 | */
39 |
--------------------------------------------------------------------------------
/src/modules/head.js:
--------------------------------------------------------------------------------
1 | import Log from "./log";
2 | import Setting from "../setting";
3 | import ServerCache from "./server-cache";
4 |
5 | class Head {
6 | auth;
7 | element;
8 | size;
9 | downloaded;
10 | seed;
11 | peer;
12 | progressBar = {
13 | all : 0,
14 | run : -1,
15 | template : $("
", { title : 'Direct source status.' })
16 | };
17 |
18 | constructor( { element, itemLength, auth } ) {
19 | this.auth = auth;
20 | this.element = element;
21 | this.progressBar.all = itemLength - 1;
22 |
23 | Log('Head...');
24 | Log('find index');
25 | //find index
26 | let td = $('td', element).each(( index, td ) => {
27 | if (['ขนาด', 'ขนาดไฟล์'].includes(td.textContent)) this.size = index;
28 | if (['เสร็จ', 'โหลดเสร็จ', 'คนโหลดเสร็จ'].includes(td.textContent)) this.downloaded = index;
29 | if (['ปล่อย', 'Seeder', 'คนปล่อย'].includes(td.textContent)) this.seed = index;
30 | if (['ดูด', 'Leecher', 'คนดูด'].includes(td.textContent)) this.peer = index;
31 | });
32 |
33 | Log('add column cover');
34 |
35 | //add column
36 | if(itemLength > 0){
37 | if(Setting.preview === true){
38 | $(td.get(0)).after(
39 | $("", {
40 | class : 'colhead 11',
41 | align : 'center',
42 | width : '125px',
43 | text : "รูป"
44 | }).append(this.progressBar.template)
45 | );
46 | }
47 | }
48 |
49 | //touch first
50 | this.touchProgressBar();
51 |
52 | Log('Head Done');
53 | }
54 |
55 | touchProgressBar() {
56 | this.progressBar.run++;
57 | this.progressBar.template.html(` [ ${this.progressBar.run}/${this.progressBar.all} ]`);
58 |
59 | Log('#', `touch progress bar ${this.progressBar.run}`);
60 | }
61 | }
62 |
63 | export default Head;
64 |
--------------------------------------------------------------------------------
/src/modules/clean.js:
--------------------------------------------------------------------------------
1 | import Setting from "../setting";
2 |
3 | class Clean {
4 |
5 | constructor( { element } ) {
6 | //detail
7 | this.detail(element);
8 | }
9 |
10 | detail( element ) {
11 | //always change thank to download
12 | $('#saythankup').html(`Download`)
13 |
14 | if (Setting.cleanDetailBanner) {
15 | let banner = $('tr:first-child td:eq(1) a[target="_blank"]', element);
16 | if (banner) {
17 | banner.next().remove();
18 | banner.remove();
19 | }
20 |
21 | //remove Advertising
22 | $('td.outer table[width="80%"] td.rowhead').each(function( index, item ){
23 | let text = $(item).html().trim();
24 | if(text === 'Advertising' || text === 'Advertising '){
25 | $('td.rowhead', element).each(function( tdIndex, tdItem ){
26 | if(tdIndex === index){
27 | $(tdItem).parent().remove();
28 | }
29 | });
30 | }
31 | if(text === 'ScreenShot'){
32 | const trLeft = $('td[align="left"]', $(item).parent());
33 | const a = $('a', trLeft);
34 |
35 | if(a.length === 2){
36 | a.eq(0).remove();
37 | $('br', trLeft).remove();
38 | }
39 | }
40 | })
41 | }
42 |
43 | //remove br in column download when bookmark and promote is removed
44 | if (Setting.cleanDetailBookmarks && Setting.cleanDetailPromote){
45 | $('br', $('tbody>tr:eq(0)>td:eq(1)', element)).remove();
46 | }
47 |
48 | if (Setting.cleanDetailDownloadImage) {
49 | $('img[src="pic/downloadpic.gif"]', element).remove();
50 | }
51 |
52 | if (Setting.cleanDetailBookmarks) {
53 | $('a[title="Bookmark File"]', element).remove();
54 | $('tr:first-child td:eq(1)', element).html(function () {
55 | return $(this).html().replace(' ', '');
56 | });
57 | }
58 |
59 | if (Setting.cleanDetailPromote) {
60 | $('a[title="Promote this Torrent"]', element).remove();
61 | }
62 | }
63 | }
64 |
65 | export default Clean;
66 |
--------------------------------------------------------------------------------
/src/warning.js:
--------------------------------------------------------------------------------
1 | import Setting from "./setting";
2 |
3 | class Warning {
4 | static element = null;
5 | static statusShow = false;
6 | static timeoutBar = 10; //seconds
7 | static code;
8 | static cache;
9 |
10 | static make( cache ) {
11 | this.cache = cache;
12 |
13 | if(cache.data.warning - cache.timestamp() < 0 || cache.data.warningCode !== Setting.version){
14 | this.panel();
15 | this.show();
16 | }
17 | }
18 |
19 | static html(){
20 | return `แจ้งเตือน - Cover Next ` + Setting.version + `
21 | คุณกำลังใช้ปลั๊กอิน Cover Next เป็นปลั๊กอินที่แจกฟรี! (รายละเอียด คลิก!)โปรดระวังผู้ไม่หวังดีนำมาหลอกลวงหรือขายให้แก่คุณ
22 | อัปเดตนี้อาจจะเป็นอัปเดตสุดท้าย (v2.2x) ช่วงนี้ผมไม่ได้ว่างมาทำงานหน้าคอมเลย หากมีปัญหาให้เปิด Issue ไว้นะครับ
23 | 🎊🎉🎈 สุขสันต์วันปีใหม่ 2025 ล่วงหน้านะครับ 🍻🥳🎆
24 | อัปเดต เพิ่มออโต้อ่านจดหมาย สำหรับคนที่ Donate ให้เปิดได้ที่ตั้งค่าครับ 🤖
25 |
26 | (หน้าต่างนี้จะขึ้นมาทุก 1 เดือนไม่ต้องตกใจครับ)`;
27 | }
28 |
29 | static show() {
30 | if (this.element === null) {
31 | this.element = $('#warning');
32 | }
33 |
34 | if (!this.statusShow) {
35 | this.statusShow = true;
36 | this.element.fadeIn();
37 | }
38 |
39 | this.element.html(this.html());
40 |
41 | $('#warning-close').click(() => {
42 | this.hidePanel();
43 | });
44 | }
45 |
46 | static hidePanel() {
47 | this.element.fadeOut();
48 | this.statusShow = false;
49 |
50 | this.cache.set({
51 | key : 'data',
52 | data : {
53 | key : 'warning',
54 | value : this.cache.timestamp() + 2592000
55 | }
56 | });
57 |
58 | this.cache.set({
59 | key : 'data',
60 | data : {
61 | key : 'warningCode',
62 | value : Setting.version,
63 | }
64 | });
65 | }
66 |
67 | static panel() {
68 | $('body').append($(``, { id : 'warning', class : 'warning' }));
69 | }
70 | }
71 |
72 | export default Warning;
73 |
74 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | // Generated using webpack-cli https://github.com/webpack/webpack-cli
2 | const webpack = require('webpack');
3 | const WebpackObfuscator = require('webpack-obfuscator');
4 | const path = require("path");
5 |
6 | const isProduction = process.env.NODE_ENV === "production";
7 | const stylesHandler = "style-loader";
8 |
9 | const config = {
10 | entry : "./src/cover-next.js",
11 | output : {
12 | path : path.resolve(__dirname, "dist"),
13 | filename : "cover-next.js"
14 | },
15 | devServer : {
16 | open : true,
17 | host : "localhost",
18 | },
19 | plugins : [
20 | new webpack.ProvidePlugin({
21 | $ : "jquery",
22 | jQuery : "jquery"
23 | }),
24 | isProduction ? new WebpackObfuscator({
25 | compact: true,
26 | controlFlowFlattening: true,
27 | controlFlowFlatteningThreshold: 1,
28 | deadCodeInjection: true,
29 | deadCodeInjectionThreshold: 1,
30 | debugProtection: true,
31 | debugProtectionInterval: 1000,
32 | stringArray: true,
33 | stringArrayEncoding: ['rc4'],
34 | stringArrayThreshold: 1,
35 | renameGlobals: true,
36 | identifierNamesGenerator: 'mangled',
37 | selfDefending: true,
38 | simplify: true,
39 | output: {
40 | beautify: false,
41 | comments: false,
42 | }
43 | }) : () => {},
44 | ],
45 | module : {
46 | rules : [
47 | {
48 | test : /\.(js|jsx)$/i,
49 | loader : "babel-loader",
50 | },
51 | {
52 | test : /\.css$/i,
53 | use : [stylesHandler, "css-loader"],
54 | },
55 | {
56 | test : /\.s[ac]ss$/i,
57 | use : [stylesHandler, "css-loader", "sass-loader", "postcss-loader"],
58 | },
59 | {
60 | test : /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
61 | type : "asset",
62 | },
63 |
64 | // Add your rules for custom modules here
65 | // Learn more about loaders from https://webpack.js.org/loaders/
66 | ],
67 | },
68 | resolve : {
69 | fallback : {
70 | "crypto" : false,
71 | "buffer" : false
72 | },
73 | }
74 | };
75 |
76 | module.exports = () => {
77 | if (isProduction) {
78 | config.mode = "production";
79 | } else {
80 | config.mode = "development";
81 | }
82 | return config;
83 | };
84 |
--------------------------------------------------------------------------------
/src/modules/download.js:
--------------------------------------------------------------------------------
1 | import Setting from "../setting";
2 | import Log from "./log";
3 | import Cache from "../cache";
4 |
5 | class Download {
6 | link;
7 | data;
8 |
9 | constructor( { data } ) {
10 | this.data = data;
11 |
12 | Log(this.data.hash, 'download...');
13 |
14 | if (this.data.download !== undefined
15 | && Setting.downloadWithoutVip === false) {
16 | Log(this.data.hash, 'vip link');
17 |
18 | this.vip();
19 | }
20 | }
21 |
22 | vip() {
23 | this.link = window.location.origin + '/' + this.data.download;
24 | }
25 |
26 | async download() {
27 | if (this.link === undefined) {
28 | Log(this.data.hash, 'download link undefined!');
29 | Log(this.data.hash, 'try hook download...');
30 |
31 | let detail = await this.data.hook.detail();
32 | this.link = $('a[title="Download this file"]', detail).attr('href');
33 |
34 | if (this.link === undefined) {
35 | Log(this.data.hash, 'download fail!');
36 |
37 | return;
38 | }
39 | }
40 |
41 | //download
42 | window.location.href = this.link;
43 |
44 | //render downloaded
45 | Download.downloaded({ data : this.data });
46 | Log(this.data.hash, 'download href');
47 | }
48 |
49 | static downloadedDetail( { html, detail } ) {
50 | Log('Downloaded...');
51 |
52 | let _html = typeof html === 'object' ? html.innerHTML : html;
53 | if (_html.indexOf('(Downloaded ไปแล้ว)') !== -1) {
54 | //set cache downloaded
55 | Cache.set({ key : 'downloaded', data : { key : detail.id, value : Cache.timestamp() } });
56 |
57 | Log('set downloaded and cache');
58 | }
59 |
60 | $(html).on('click', 'a[title="Download this file"]', () => {
61 | Log('Click Download');
62 | Log('set downloaded...');
63 |
64 | Cache.set({ key : 'downloaded', data : { key : detail.id, value : Cache.timestamp() } });
65 |
66 | Log('set downloaded and cache');
67 | });
68 |
69 | Log('Downloaded Done');
70 | }
71 |
72 | static downloadedHook( { html, self } ) {
73 | Log(self.hash, 'hook downloaded...');
74 |
75 | if (html.body.innerHTML.indexOf('(Downloaded ไปแล้ว)') !== -1) {
76 | Download.downloaded({ data : self });
77 | }
78 |
79 | Log(self.hash, 'hook downloaded success');
80 | }
81 |
82 | static downloaded( { data } ) {
83 | //set cache downloaded
84 | Cache.set({ key : 'downloaded', data : { key : data.detailId, value : Cache.timestamp() } });
85 |
86 | if (Setting.downloaded === false) return;
87 |
88 | Log(data.hash, `downloaded ${data.hash}`);
89 | data.elements.title.addClass('downloaded');
90 | }
91 | }
92 |
93 | export default Download;
94 |
--------------------------------------------------------------------------------
/src/modules/thank.js:
--------------------------------------------------------------------------------
1 | import Cache from "../cache";
2 | import Log from "./log";
3 | import Setting from "../setting";
4 |
5 | class Thank {
6 | data;
7 | thanked = false;
8 |
9 | constructor( { data } ) {
10 | this.data = data;
11 |
12 | if (Cache.thank[ this.data.detailId ] !== undefined) {
13 | Log(this.data.hash, 'thanked');
14 |
15 | this.thanked = true;
16 | }
17 |
18 | }
19 |
20 | async thank( { html } ) {
21 | return await new Promise(async resolve => {
22 | Log(this.data.hash, 'thanking...');
23 |
24 | let element = $('#saythanks a', html);
25 | if (element.length === 1) {
26 | GM_xmlhttpRequest({
27 | method : "GET",
28 | url : window.location.origin + '/' + 'ajax.php?action=say_thank&id=' + this.data.detailId,
29 | onload : res => {
30 | if (typeof res.responseText === 'string' && res.responseText.includes('กดขอบคุณ')) {
31 | Log(this.data.hash, 'thanked');
32 |
33 | resolve(true);
34 | } else {
35 | Log(this.data.hash, 'thank fail!');
36 | resolve(false);
37 | }
38 | },
39 | ontimeout : () => resolve(false),
40 | onerror : () => resolve(false)
41 | });
42 | } else {
43 | Log(this.data.hash, 'already thanked');
44 | resolve(true);
45 | }
46 | }).then(status => {
47 | if (status === true) {
48 | Cache.set({ key : 'thank', data : { key : this.data.detailId, value : Cache.timestamp() } });
49 | }
50 | });
51 | }
52 |
53 | async hook( { html, self } ) {
54 | if (Setting.autoThankHook === false) return;
55 |
56 | return await new Promise(async resolve => {
57 | if (self.thanked === true) {
58 | resolve();
59 | }
60 |
61 | await self.thank({ html });
62 | resolve();
63 | });
64 | }
65 |
66 | static thankInDetail( element ) {
67 | Log('Thank in detail...');
68 | let a = $('#saythanks a', element);
69 |
70 | if (a) {
71 | const onclick = a.attr('onclick');
72 | if(onclick){
73 | const id = onclick.match(/sndReq\('action=say_thanks&id=(\d+)'/);
74 | $.ajax({
75 | url: '/ajax.php',
76 | type: 'GET',
77 | data: 'action=say_thanks&id=' + id[1],
78 | success: function (data) {
79 | Log('send thank success.');
80 | $('#saythanks').html(data);
81 | }
82 | });
83 | }
84 | }
85 |
86 | //remove text thanks
87 | $('td.outer table[width="80%"] td.rowhead').each(function( index, item ){
88 | let text = $(item).html().trim();
89 | if(text === ' ต้องการกด Thanks กรุณาเลื่อนลงไปด้านล่าง หรือคลิกที่ปุ่ม Download จะมีหน้าให้กด' +
90 | ' Thanks เช่นกัน'){
91 | $(item).html(' Download');
92 | }
93 | });
94 |
95 | Log('Thank in detail Done');
96 | }
97 | }
98 |
99 | export default Thank;
100 |
--------------------------------------------------------------------------------
/cover-next.user.js:
--------------------------------------------------------------------------------
1 | // ==UserScript==
2 | // @name Cover Next (Bearbit)
3 | // @namespace http://tampermonkey.net/
4 | // @version 2.25
5 | // @description tools that will help you see new items and make it easier for you to use the website to load bittorrent.
6 | // @author NEKO
7 | // @icon https://i.imgur.com/qTvfJSr.png
8 | // @match https://www.bearbit.org
9 | // @match https://www.bearbit.org/index.php*
10 | // @match https://www.bearbit.org/viewno18.php*
11 | // @match https://www.bearbit.org/viewbr.php*
12 | // @match https://www.bearbit.org/viewno18sb.php*
13 | // @match https://www.bearbit.org/viewno18sbx.php*
14 | // @match https://www.bearbit.org/viewbrsb.php*
15 | // @match https://www.bearbit.org/torrent_day.php*
16 | // @match https://www.bearbit.org/torrent_week.php*
17 | // @match https://www.bearbit.org/torrent_month.php*
18 | // @match https://www.bearbit.org/upfinish.php*
19 | // @match https://www.bearbit.org/downfinish.php*
20 | // @match https://www.bearbit.org/details.php*
21 | // @match https://bearbit.org
22 | // @match https://bearbit.org/index.php*
23 | // @match https://bearbit.org/viewno18.php*
24 | // @match https://bearbit.org/viewbr.php*
25 | // @match https://bearbit.org/viewno18sb.php*
26 | // @match https://bearbit.org/viewno18sbx.php*
27 | // @match https://bearbit.org/viewbrsb.php*
28 | // @match https://bearbit.org/torrent_day.php*
29 | // @match https://bearbit.org/torrent_week.php*
30 | // @match https://bearbit.org/torrent_month.php*
31 | // @match https://bearbit.org/upfinish.php*
32 | // @match https://bearbit.org/downfinish.php*
33 | // @match https://bearbit.org/details.php*
34 | // @grant GM_addStyle
35 | // @grant GM_xmlhttpRequest
36 | // @require https://raw.githubusercontent.com/kon3ko/cover-next/master/dist/cover-next.js?version=2.25
37 | // @updateURL https://raw.githubusercontent.com/kon3ko/cover-next/master/cover-next.user.js
38 | // @downloadURL https://raw.githubusercontent.com/kon3ko/cover-next/master/cover-next.user.js
39 | // @supportURL https://github.com/kon3ko/cover-next/issues
40 | // @connect img.in.th
41 | // @connect bpicc.cc
42 | // @connect imgtrue.com
43 | // @connect imdb.com
44 | // @connect 55xo.co
45 | // @connect imgur.com
46 | // @connect in.th
47 | // @connect postto.me
48 | // @connect javstore.net
49 | // @connect i-pic.info
50 | // @connect picstate.com
51 | // @connect bpicc.com
52 | // @connect roop.xyz
53 | // @connect mpic.ws
54 | // @connect img.live
55 | // @connect shotcan.com
56 | // @connect ibb.co
57 | // @connect lmgbb.me
58 | // @connect 4shared.com
59 | // @connect lookimg.com
60 | // @connect gstatic.com
61 | // @connect wp.com
62 | // @connect steamstatic.com
63 | // @connect tokopedia.net
64 | // @connect 4gamers.com.tw
65 | // @connect imgbb.me
66 | // @connect clip18zeed.com
67 | // @connect mx7.com
68 | // @connect youtube.com
69 | // @connect youtube.be
70 | // @connect 8e88.in.th
71 | // @connect clipxxx.live
72 | // @connect i-pic.info
73 | // @connect thaibuzz.com
74 | // @connect imgmak.com
75 | // @connect imgbb.me
76 | // @connect picz.in.th
77 | // @connect 234.in.th
78 | // @connect best-story.net
79 | // @connect uppic.cc
80 | // @connect uppicimg.com
81 | // @connect uppic.xyz
82 | // @connect gifyu.com
83 | // @connect imgvb.com
84 | // @connect up-pic.com
85 | // @connect pic.4th.in
86 | // @connect imagenetz.de
87 | // @connect www.imagenetz.de
88 | // @connect *
89 | // ==/UserScript==
90 |
--------------------------------------------------------------------------------
/src/modules/cache.js:
--------------------------------------------------------------------------------
1 | import Setting from "../setting";
2 | import Log from "./log";
3 |
4 | class Cache {
5 | downloaded = {};
6 | source = {};
7 | thank = {};
8 | detail = {};
9 | data = {
10 | downloadFinishTimeout: 0,
11 | welcomeMessage: 0,
12 | warning: 0,
13 | warningCode: '',
14 | };
15 | code;
16 | version = 0;
17 |
18 | constructor() {
19 | Log('Cache loading...');
20 |
21 | this.read();
22 |
23 | Log('Cache Done');
24 | }
25 |
26 | set({ key, data, merge = true }) {
27 | if(typeof data === 'object' && data.hasOwnProperty('key')) {
28 | if(merge === true && typeof data.value === 'object') {
29 | this[key][data.key] = { ...this[key][data.key], ...data.value };
30 | } else {
31 | this[key][data.key] = data.value;
32 | }
33 | } else {
34 | this[key] = data;
35 | }
36 |
37 | let rand = Math.random();
38 | this.code = rand;
39 | setTimeout(() => this.write(rand), 1000);
40 |
41 | Log(`set cache ${key}: ${data.key}, ${data.value?.source ?? data.value}`);
42 | }
43 |
44 | read() {
45 | if(Setting.cache === false) return;
46 |
47 | let caches = localStorage.getItem(`${Setting.key}_CACHE`);
48 | if(caches) {
49 | try {
50 | caches = JSON.parse(caches);
51 | } catch(e) {
52 | caches = {};
53 | }
54 | }
55 | this.downloaded = { ...this.downloaded, ...caches?.downloaded };
56 | this.source = { ...this.source, ...caches?.source };
57 | this.thank = { ...this.thank, ...caches?.thank };
58 | this.detail = { ...this.detail, ...caches?.detail };
59 | this.data = { ...this.data, ...caches?.data };
60 | this.version = caches?.version ?? 0;
61 |
62 | //clean old cache
63 | if(this.version !== Setting.version) {
64 | this.set({
65 | key: 'data', data: {
66 | key: 'welcomeMessage',
67 | value: 0,
68 | }
69 | });
70 | this.set({
71 | key: 'data', data: {
72 | key: 'warning',
73 | value: 0,
74 | }
75 | });
76 | this.set({ key: 'version', data: Setting.version });
77 | }
78 | }
79 |
80 | write(code) {
81 | if(Setting.cache === false) return;
82 |
83 | if(this.code === code) {
84 | this.timeout();
85 |
86 | localStorage.setItem(`${Setting.key}_CACHE`, JSON.stringify({
87 | downloaded: { ...this.downloaded },
88 | source: { ...this.source },
89 | thank: { ...this.thank },
90 | detail: { ...this.detail },
91 | data: { ...this.data },
92 | version: this.version,
93 | }));
94 |
95 | Log('write cache');
96 | }
97 | }
98 |
99 | timeout() {
100 | Log('clear source timeout');
101 |
102 | Object.keys(this.source).forEach(key => {
103 | if(!this.source[key].hasOwnProperty('timeout')) {
104 | this.source[key].timeout = this.timestamp() + Setting.cacheTimeout;
105 | } else if(this.source[key].timeout < this.timestamp()) {
106 | delete this.source[key];
107 |
108 | Log(`delete cache source ${key}`);
109 | }
110 | });
111 |
112 | Object.keys(this.detail).forEach(key => {
113 | if(!this.detail[key].hasOwnProperty('timeout')) {
114 | this.detail[key].timeout = this.timestamp() + Setting.cacheTimeout;
115 | } else if(this.detail[key].timeout < this.timestamp()) {
116 | delete this.detail[key];
117 |
118 | Log(`delete cache detail ${key}`);
119 | }
120 | });
121 | }
122 |
123 | timestamp() {
124 | return (Date.now() / 1000 | 0);
125 | }
126 |
127 | static clean() {
128 | localStorage.setItem(`${Setting.key}_CACHE`, '{}');
129 | }
130 | }
131 |
132 | export default Cache;
133 |
--------------------------------------------------------------------------------
/src/modules/pass-data.js:
--------------------------------------------------------------------------------
1 | import Cover from './cover';
2 | import Log from "./log";
3 | import Hash from "hash.js";
4 | import Setting from "../setting";
5 |
6 | class PassData {
7 | element;
8 | td;
9 | head;
10 | hash;
11 | id;
12 | title;
13 | link;
14 | download;
15 | category;
16 | size;
17 | downloaded;
18 | seed;
19 | peer;
20 | bgColor;
21 | cover;
22 | detailLink;
23 | detailId;
24 | hook;
25 | locked = false;
26 | except = false;
27 | elements = {};
28 |
29 | constructor( { element, head } ) {
30 | Log('Pass data...');
31 |
32 | this.element = element;
33 | this.head = head;
34 |
35 | this.convert();
36 |
37 | Log('Pass data Done');
38 | }
39 |
40 | convert() {
41 | this.td = $('td', this.element);
42 |
43 | //title
44 | let _title = $('a:first-child b', this.td.get(1)).first();
45 | this.title = _title.text();
46 | this.elements.title = _title;
47 |
48 | //check locked
49 | if ($('font b', this.td.get(1)).text() === 'Locked !!') {
50 | this.locked = true;
51 | }
52 |
53 | //Link
54 | this.link = _title.parent();
55 | if (this.link.length > 0) {
56 | if (this.link.get(0).tagName !== 'A') {
57 | this.link = this.link.parent();
58 | }
59 | this.link = this.link.attr('href');
60 | }
61 |
62 | //id
63 | this.id = Hash.sha1().update(this.link).digest('hex');
64 |
65 | //hash
66 | this.hash = this.id.substr(34);
67 |
68 | //cover
69 | let _cover = $(window.location.pathname === '/upfinish.php'
70 | ? 'td a>img[src="/pic/cam.gif"]'
71 | : 'td[width="900"] a>img[src="pic/cams.gif "]', this.element).parent();
72 | if (_cover.is('a')) {
73 | this.cover = _cover.attr('href');
74 | }
75 |
76 | //detail link and id
77 | this.detailLink = $('a', this.td.get(1)).first()?.attr('href');
78 | this.detailId = /id=([0-9]+)/.exec(this.detailLink)[ 1 ];
79 |
80 | //download
81 | this.elements.download = $('td[width="900"] a>img[src="pic/downloaded.gif"]', this.element).parent();
82 | this.download = this.elements.download?.attr('href');
83 |
84 | //category
85 | this.category = $('img', this.td.get(0)).first()?.attr('src').replace('pic/categories/cat-', '')
86 | .replace('pic/categories/', '')
87 | .replace('.gif', '')
88 | .replace('.png', '')
89 | .toLowerCase();
90 |
91 | //from index
92 | this.size = this.td.get(this.head.size)?.textContent;
93 | this.downloaded = this.td.get(this.head.downloaded)?.textContent;
94 | this.seed = this.td.get(this.head.seed)?.textContent;
95 | this.peer = this.td.get(this.head.peer)?.textContent;
96 |
97 | //background color
98 | this.bgColor = $(this.td.get(0)).attr('bgcolor');
99 | if(!/^#[0-9A-F]{6}$/i.test(this.bgColor)){
100 | this.bgColor = '';
101 | }
102 |
103 | //except category or locked
104 | this.except = Setting.exceptCategories.includes(this.category) || this.locked;
105 |
106 | Log(this.hash, `title: ${this.title}`);
107 | Log(this.hash, `locked: ${this.locked}`);
108 | Log(this.hash, `link: ${this.link}`);
109 | Log(this.hash, `id: ${this.id}`);
110 | Log(this.hash, `hash: ${this.hash}`);
111 | Log(this.hash, `cover: ${this.cover}`);
112 | Log(this.hash, `detail Link: ${this.detailLink}`);
113 | Log(this.hash, `detail Id: ${this.detailId}`);
114 | Log(this.hash, `download: ${this.download}`);
115 | Log(this.hash, `category: ${this.category}`);
116 | Log(this.hash, `size: ${this.size}`);
117 | Log(this.hash, `downloaded: ${this.downloaded}`);
118 | Log(this.hash, `seed: ${this.seed}`);
119 | Log(this.hash, `peer: ${this.peer}`);
120 | Log(this.hash, `bg Color: ${this.bgColor}`);
121 | Log(this.hash, `except: ${this.except}`);
122 | }
123 |
124 | }
125 |
126 | export default PassData;
127 |
--------------------------------------------------------------------------------
/src/direct-source.js:
--------------------------------------------------------------------------------
1 | import DirectSource from "./modules/direct-source";
2 |
3 | /*
4 | * Patterns
5 | * s = selector
6 | * m = meta
7 | * e = except
8 | * [find,new] = replace
9 | *
10 | */
11 |
12 | const domains = {
13 | 'postto.me' : 's:1',
14 | 'pic.8e88.in.th' : 's:2',
15 | 'img.clipxxx.live' : 's:3',
16 | 'i-pic.info' : 's:4',
17 | 'www.i-pic.info' : 's:4',
18 | 'img.thaibuzz.com' : 's:5',
19 | 'imgmak.com' : 's:6',
20 | 'imagenetz.de' : 's:7',
21 | 'www.imagenetz.de' : 's:7',
22 | 'www.imgbb.me' : 'm:og:image',
23 | 'imgbb.me' : 'm:og:image',
24 | 'www.picz.in.th' : 'm:og:image',
25 | 'picz.in.th' : 'm:og:image',
26 | 'www.imgtrue.com' : 'm:og:image',
27 | 'imgtrue.com' : 'm:og:image',
28 | 'imdb.com' : 'm:og:image',
29 | 'www.imdb.com' : 'm:og:image',
30 | 'ibb.co' : 'm:og:image',
31 | 'www.lmgbb.me' : 'm:og:image',
32 | 'roop.xyz' : 'm:og:image',
33 | 'www.roop.xyz' : 'm:og:image',
34 | 'bpicc.com' : 'm:og:image',
35 | 'www.bpicc.com' : 'm:og:image',
36 | 'bpicc.cc' : 'm:og:image',
37 | 'www.bpicc.cc' : 'm:og:image',
38 | 'lmgbb.me' : 'm:og:image',
39 | 'www.img.live' : 'm:og:image',
40 | 'img.live' : 'm:og:image',
41 | '234.in.th' : 'm:og:image',
42 | 'www.234.in.th' : 'm:og:image',
43 | 'img.in.th' : 'm:og:image',
44 | 'www.img.in.th' : 'm:og:image',
45 | 'img.best-story.net' : ['viewer.php?file=', 'files/'],
46 | 'uppic.cc' : ['.cc/v', '.cc/d'],
47 | 'uppicimg.com' : ['.com/v/', '.com/s/'],
48 | 'uppic.xyz' : ['.xyz/image/', '.xyz/d/'],
49 | 'imgur.com' : 'c:imgur',
50 | 'www.youtube.com' : 'c:youtube',
51 | 'youtube.com' : 'c:youtube',
52 | 'youtube.be' : 'c:youtube',
53 | };
54 |
55 |
56 | /* Patterns arguments
57 | * attr = $.attr(attr)
58 | * selector = $(selector)
59 | *
60 | */
61 | const patterns = {
62 | 'default' : {
63 | attr : 'content',
64 | selector : 'meta[property=\'og:image\']',
65 | },
66 | 's:1' : {
67 | attr : 'src',
68 | selector : 'div.image_view img',
69 | },
70 | 's:2' : {
71 | attr : 'src',
72 | selector : 'div#image img',
73 | },
74 | 's:3' : {
75 | attr : 'src',
76 | selector : 'div#main div.center img',
77 | },
78 | 's:4' : {
79 | attr : 'src',
80 | selector : 'img#magnific-image',
81 | },
82 | 's:5' : {
83 | attr : 'src',
84 | selector : 'img[alt=\'Free Image Hosting\']',
85 | },
86 | 's:6' : {
87 | attr : 'src',
88 | selector : 'img#full_image',
89 | },
90 | 's:7' : {
91 | attr : 'src',
92 | selector : 'img.img-rounded.img-responsive',
93 | },
94 | 'm:og:image' : {
95 | attr : 'content',
96 | selector : 'meta[property=\'og:image\']',
97 | },
98 | 'c:imgur' : {
99 | sourceIf : ( { url } ) => url.replace('https://', '')
100 | .replace('http://', '')
101 | .startsWith('imgur.com/a/'),
102 | attr : 'content',
103 | selector : 'meta[name=\'twitter:image\']',
104 | callback : [
105 | ( { url } ) => url,
106 | ( { url } ) => {
107 | let _url = url.replace('https://', '').replace('http://', '');
108 | if (_url.startsWith('imgur.com/')
109 | && _url.lastIndexOf('.jpg') === -1
110 | && _url.lastIndexOf('.jpeg') === -1
111 | && _url.lastIndexOf('.gif') === -1
112 | && _url.lastIndexOf('.png') === -1
113 | ) {
114 | url = 'https://i.' + _url + '.jpg';
115 | }
116 |
117 | return url;
118 | }
119 | ]
120 | },
121 | 'c:youtube' : {
122 | sourceIf : false,
123 | callback : ( { url } ) => {
124 | let r, rx = /^.*(?:(?:youtu\.be\/|v\/|vi\/|u\/\w\/|embed\/)|(?:(?:watch)?\?v(?:i)?=|\&v(?:i)?=))([^#\&\?]*).*/;
125 | try {
126 | r = url.match(rx);
127 | r = 'https://img.youtube.com/vi/' + r[ 1 ] + '/maxresdefault.jpg';
128 | } catch (e) {
129 | r = url;
130 | }
131 |
132 | return r;
133 | }
134 | },
135 | };
136 |
137 | // const directSource = new DirectSource(domains, patterns);
138 |
139 | export default { DirectSource, domains, patterns};
140 |
--------------------------------------------------------------------------------
/src/modules/button.js:
--------------------------------------------------------------------------------
1 | import Download from "./download";
2 | import {Fancybox} from "@fancyapps/ui";
3 | import de from "@fancyapps/ui/src/Fancybox/l10n/de";
4 | import Setting from "../setting";
5 | import Log from "./log";
6 |
7 | class Button {
8 | download = $(' |