javbus.waterfall

Infinite scroll @ javbus.com

От 01.11.2017. Виж последната версия.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey, Greasemonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да инсталирате разширение, като например Tampermonkey .

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Violentmonkey.

За да инсталирате този скрипт, трябва да имате инсталирано разширение като Tampermonkey или Userscripts.

За да инсталирате скрипта, трябва да инсталирате разширение като Tampermonkey.

За да инсталирате този скрипт, трябва да имате инсталиран скриптов мениджър.

(Вече имам скриптов мениджър, искам да го инсталирам!)

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да инсталирате разширение като Stylus.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

За да инсталирате този стил, трябва да имате инсталиран мениджър на потребителски стилове.

(Вече имам инсталиран мениджър на стиловете, искам да го инсталирам!)

// ==UserScript==
// @name        javbus.waterfall
// @description Infinite scroll @ javbus.com
// @namespace   https://github.com/FlandreDaisuki
// @include     *://*.javbus.*/*
// @version     2017.11.02
// @grant       none
// ==/UserScript==
const $ = jQuery;

class Lock {
	constructor(d = false) {
		this.locked = d;
	}
	lock() {
		this.locked = true;
	}
	unlock() {
		this.locked = false;
	}
}

class Waterfall {
	constructor(selectorcfg = {}) {
		this.lock = new Lock();
		this.baseURI = this.getBaseURI();
		this.selector = {
			next: 'a.next',
			item: '',
			cont: '', //container
			pagi: '.pagination',
		};
		Object.assign(this.selector, selectorcfg);
		this.pagegen = this.fetchSync(location.href);
		this.anchor = $(this.selector.pagi)[0];
		this._count = 0;
		this._1func = function(cont, elems) {
			cont.empty().append(elems);
		};
		this._2func = function(cont, elems) {
			cont.append(elems);
		};

		if ($(this.selector.item).length) {
			document.addEventListener('scroll', this.scroll.bind(this));
			document.addEventListener('wheel', this.wheel.bind(this));
			this.appendElems(this._1func);
		}
	}

	getBaseURI() {
		let _ = location;
		return `${_.protocol}//${_.hostname}${_.port && `:${_.port}`}`;
	}

	getNextURL(href) {
		let a = document.createElement('a');
		a.href = href;
		return `${this.baseURI}${a.pathname}${a.search}`;
	}

	fetchURL(url) {
		console.log(`fetchUrl = ${url}`);
		const fetchwithcookie = fetch(url, { credentials: 'same-origin' });
		return fetchwithcookie
			.then(response => response.text())
			.then(html => new DOMParser().parseFromString(html, 'text/html'))
			.then(doc => {
				let $doc = $(doc);
				let href = $doc.find(this.selector.next).attr('href');
				let nextURL = href ? this.getNextURL(href) : undefined;
				let elems = $doc.find(this.selector.item);

				return {
					nextURL,
					elems,
				};
			});
	}

	*fetchSync(urli) {
		let url = urli;
		do {
			yield new Promise((resolve, reject) => {
				if (this.lock.locked) {
					reject();
				} else {
					this.lock.lock();
					resolve();
				}
			})
				.then(() => {
					return this.fetchURL(url).then(info => {
						url = info.nextURL;
						return info.elems;
					});
				})
				.then(elems => {
					this.lock.unlock();
					return elems;
				})
				.catch(err => {
					// Locked!
				});
		} while (url);
	}

	appendElems() {
		let nextpage = this.pagegen.next();
		if (!nextpage.done) {
			nextpage.value.then(elems => {
				const cb = this._count === 0 ? this._1func : this._2func;
				cb($(this.selector.cont), elems);
				this._count += 1;
			});
		}
		return nextpage.done;
	}

	end() {
		console.info('The End');
		document.removeEventListener('scroll', this.scroll.bind(this));
		document.removeEventListener('wheel', this.wheel.bind(this));
		$(this.anchor).replaceWith($(`<h1>The End</h1>`));
	}

	static reachBottom(elem, limit) {
		return elem.getBoundingClientRect().top - $(window).height() < limit;
	}

	scroll() {
		if (
			Waterfall.reachBottom(this.anchor, 500) &&
			this.appendElems(this._2func)
		) {
			this.end();
		}
	}

	wheel() {
		if (
			Waterfall.reachBottom(this.anchor, 1000) &&
			this.appendElems(this._2func)
		) {
			this.end();
		}
	}

	setFirstCallback(f) {
		this._1func = f;
	}

	setSecondCallback(f) {
		this._2func = f;
	}
}

const w = new Waterfall({
	next: 'a#next',
	item: '.item',
	cont: '#waterfall',
});

w.setSecondCallback(function(cont, elems) {
	if (location.pathname.includes('/star/')) {
		cont.append(elems.slice(1));
	} else {
		cont.append(elems);
	}
});

function addStyle(styleStr) {
	$('head').append(`<style>${styleStr}</style>`);
}

addStyle(`
  #waterfall {
    height: initial !important;
    width: initial !important;
    display: flex;
    flex-direction: row;
    flex-wrap: wrap;
  }
  #waterfall .item.item {
    position: relative !important;
    top: initial !important;
    left: initial !important;
    float: none;
    flex: 25%;
  }
  #waterfall .movie-box,
  #waterfall .avatar-box {
    width: initial !important;
    display: flex;
  }
  #waterfall .movie-box .photo-frame {
    overflow: visible;
  }`);