ThisVid.com Improved

Infinite scroll [optional]. Preview for private videos. Filter: title, duration, public/private. Check access to private vids. Mass friend request button. Sorts messages. Download button 📼

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey, Greasemonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

You will need to install an extension such as Tampermonkey to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey किंवा Violentmonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

You will need to install an extension such as Tampermonkey or Userscripts to install this script.

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला Tampermonkey यासारखे एक्स्टेंशन इंस्टॉल करावे लागेल..

ही स्क्रिप्ट इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्क्रिप्ट व्यवस्थापक एक्स्टेंशन इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्क्रिप्ट व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला Stylus सारखे एक्स्टेंशन इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

ही स्टाईल इंस्टॉल करण्यासाठी तुम्हाला एक युझर स्टाईल व्यवस्थापक इंस्टॉल करावे लागेल.

(माझ्याकडे आधीच युझर स्टाईल व्यवस्थापक आहे, मला इंस्टॉल करू द्या!)

// ==UserScript==
// @name         ThisVid.com Improved
// @namespace    pervertmonkey
// @version      8.0.0
// @author       violent-orangutan
// @description  Infinite scroll [optional]. Preview for private videos. Filter: title, duration, public/private. Check access to private vids. Mass friend request button. Sorts messages. Download button 📼
// @license      MIT
// @icon         https://www.google.com/s2/favicons?sz=64&domain=thisvid.com
// @homepage     https://github.com/smartacephale/sleazy-fork
// @homepageURL  https://github.com/smartacephale/sleazy-fork
// @source       github:smartacephale/sleazy-fork
// @supportURL   https://github.com/smartacephale/sleazy-fork/issues
// @match        https://*.thisvid.com/*
// @require      https://cdn.jsdelivr.net/npm/[email protected]/dist/core/pervertmonkey.core.umd.js
// @require      data:application/javascript,var core = window.pervertmonkey.core || pervertmonkey.core; var utils = core;
// @grant        GM_addStyle
// @grant        unsafeWindow
// @run-at       document-idle
// ==/UserScript==

(async function (core, utils) {
  'use strict';

function __awaiter(thisArg, _arguments, P, generator) {
    function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
    return new (P || (P = Promise))(function (resolve, reject) {
        function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
        function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
        function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
        step((generator = generator.apply(thisArg, [])).next());
    });
  }

  function __values(o) {
    var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0;
    if (m) return m.call(o);
    if (o && typeof o.length === "number") return {
        next: function () {
            if (o && i >= o.length) o = void 0;
            return { value: o && o[i++], done: !o };
        }
    };
    throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined.");
  }

  function __await(v) {
    return this instanceof __await ? (this.v = v, this) : new __await(v);
  }

  function __asyncGenerator(thisArg, _arguments, generator) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var g = generator.apply(thisArg, _arguments || []), i, q = [];
    return i = Object.create((typeof AsyncIterator === "function" ? AsyncIterator : Object).prototype), verb("next"), verb("throw"), verb("return", awaitReturn), i[Symbol.asyncIterator] = function () { return this; }, i;
    function awaitReturn(f) { return function (v) { return Promise.resolve(v).then(f, reject); }; }
    function verb(n, f) { if (g[n]) { i[n] = function (v) { return new Promise(function (a, b) { q.push([n, v, a, b]) > 1 || resume(n, v); }); }; if (f) i[n] = f(i[n]); } }
    function resume(n, v) { try { step(g[n](v)); } catch (e) { settle(q[0][3], e); } }
    function step(r) { r.value instanceof __await ? Promise.resolve(r.value.v).then(fulfill, reject) : settle(q[0][2], r); }
    function fulfill(value) { resume("next", value); }
    function reject(value) { resume("throw", value); }
    function settle(f, v) { if (f(v), q.shift(), q.length) resume(q[0][0], q[0][1]); }
  }

  function __asyncValues(o) {
    if (!Symbol.asyncIterator) throw new TypeError("Symbol.asyncIterator is not defined.");
    var m = o[Symbol.asyncIterator], i;
    return m ? m.call(o) : (o = typeof __values === "function" ? __values(o) : o[Symbol.iterator](), i = {}, verb("next"), verb("throw"), verb("return"), i[Symbol.asyncIterator] = function () { return this; }, i);
    function verb(n) { i[n] = o[n] && function (v) { return new Promise(function (resolve, reject) { v = o[n](v), settle(resolve, reject, v.done, v.value); }); }; }
    function settle(resolve, reject, d, v) { Promise.resolve(v).then(function(v) { resolve({ value: v, done: d }); }, reject); }
  }

  typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
    var e = new Error(message);
    return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
  };
function bindCallback(func, thisArg, argCount) {
      if (typeof thisArg === 'undefined') {
          return func;
      }
      switch (argCount) {
          case 0:
              return function () {
                  return func.call(thisArg);
              };
          case 1:
              return function (arg) {
                  return func.call(thisArg, arg);
              };
          case 2:
              return function (value, index) {
                  return func.call(thisArg, value, index);
              };
          case 3:
              return function (value, index, collection) {
                  return func.call(thisArg, value, index, collection);
              };
          default:
              return function () {
                  return func.apply(thisArg, arguments);
              };
      }
  }
function identityAsync(x) {
      return __awaiter(this, void 0, void 0, function* () {
          return x;
      });
  }

const isNumber = (x) => typeof x === 'number';
const isBoolean = (x) => typeof x === 'boolean';
const isFunction = (x) => typeof x === 'function';
const isObject = (x) => x != null && Object(x) === x;
const isPromise = (x) => {
      return isObject(x) && isFunction(x.then);
  };
function isArrayLike(x) {
      return isObject(x) && isNumber(x['length']);
  }
function isIterable(x) {
      return x != null && isFunction(x[Symbol.iterator]);
  }
function isIterator(x) {
      return isObject(x) && !isFunction(x[Symbol.iterator]) && isFunction(x['next']);
  }
function isAsyncIterable(x) {
      return isObject(x) && isFunction(x[Symbol.asyncIterator]);
  }
function isObservable(x) {
      return x != null && Object(x) === x && typeof x['subscribe'] === 'function';
  }
const isReadableNodeStream = (x) => {
      return (isObject(x) &&
          isFunction(x['pipe']) &&
          isFunction(x['_read']) &&
          isBoolean(x['readable']) &&
          isObject(x['_readableState']));
  };
const isWritableNodeStream = (x) => {
      return (isObject(x) &&
          isFunction(x['end']) &&
          isFunction(x['_write']) &&
          isBoolean(x['writable']) &&
          isObject(x['_writableState']));
  };
function toInteger(value) {
      const number = Number(value);
      if (isNaN(number)) {
          return 0;
      }
      if (number === 0 || !isFinite(number)) {
          return number;
      }
      return (number > 0 ? 1 : -1) * Math.floor(Math.abs(number));
  }

  const maxSafeInteger = Math.pow(2, 53) - 1;
function toLength(value) {
      const len = toInteger(value);
      return Math.min(Math.max(len, 0), maxSafeInteger);
  }
class AbortError extends Error {
      constructor(message = 'The operation has been aborted') {
          super(message);
          Object.setPrototypeOf(this, AbortError.prototype);
          Error.captureStackTrace(this, this.constructor);
          this.name = 'AbortError';
      }
      get [Symbol.toStringTag]() {
          return 'AbortError';
      }
  }
  function throwIfAborted(signal) {
      if (signal && signal.aborted) {
          throw new AbortError();
      }
  }
  Object.defineProperty(AbortError, Symbol.hasInstance, {
      writable: true,
      configurable: true,
      value(x) {
          return (isObject(x) && (x.constructor.name === 'AbortError' || x[Symbol.toStringTag] === 'AbortError'));
      },
  });
class AsyncIterableX {
forEach(projection, thisArg, signal) {
          var _a, e_1, _b, _c;
          return __awaiter(this, void 0, void 0, function* () {
              const source = signal ? new WithAbortAsyncIterable$1(this, signal) : this;
              let i = 0;
              try {
                  for (var _d = true, source_1 = __asyncValues(source), source_1_1; source_1_1 = yield source_1.next(), _a = source_1_1.done, !_a; _d = true) {
                      _c = source_1_1.value;
                      _d = false;
                      const item = _c;
                      yield projection.call(thisArg, item, i++, signal);
                  }
              }
              catch (e_1_1) { e_1 = { error: e_1_1 }; }
              finally {
                  try {
                      if (!_d && !_a && (_b = source_1.return)) yield _b.call(source_1);
                  }
                  finally { if (e_1) throw e_1.error; }
              }
          });
      }
      pipe(...args) {
          let i = -1;
          const n = args.length;
          let acc = this;
          while (++i < n) {
              acc = args[i](AsyncIterableX.as(acc));
          }
          return acc;
      }
static from(source, selector = identityAsync, thisArg) {
          const fn = bindCallback(selector, thisArg, 2);
          if (isIterable(source) || isAsyncIterable(source)) {
              return new FromAsyncIterable(source, fn);
          }
          if (isPromise(source)) {
              return new FromPromiseIterable(source, fn);
          }
          if (isObservable(source)) {
              return new FromObservableAsyncIterable(source, fn);
          }
          if (isArrayLike(source)) {
              return new FromArrayIterable(source, fn);
          }
          if (isIterator(source)) {
              return new FromAsyncIterable({ [Symbol.asyncIterator]: () => source }, fn);
          }
          throw new TypeError('Input type not supported');
      }

static as(source) {
          if (source instanceof AsyncIterableX) {
              return source;
          }
          if (typeof source === 'string') {
              return new FromArrayIterable([source], identityAsync);
          }
          if (isIterable(source) || isAsyncIterable(source)) {
              return new FromAsyncIterable(source, identityAsync);
          }
          if (isPromise(source)) {
              return new FromPromiseIterable(source, identityAsync);
          }
          if (isObservable(source)) {
              return new FromObservableAsyncIterable(source, identityAsync);
          }
          if (isArrayLike(source)) {
              return new FromArrayIterable(source, identityAsync);
          }
          return new FromArrayIterable([source], identityAsync);
      }
  }
  AsyncIterableX.prototype[Symbol.toStringTag] = 'AsyncIterableX';
  Object.defineProperty(AsyncIterableX, Symbol.hasInstance, {
      writable: true,
      configurable: true,
      value(inst) {
          return !!(inst && inst[Symbol.toStringTag] === 'AsyncIterableX');
      },
  });
  const ARRAY_VALUE = 'value';
  const ARRAY_ERROR = 'error';

class AsyncSink {
      constructor() {
          this._ended = false;
          this._values = [];
          this._resolvers = [];
      }
      [Symbol.asyncIterator]() {
          return this;
      }
      write(value) {
          this._push({ type: ARRAY_VALUE, value });
      }
      error(error) {
          this._push({ type: ARRAY_ERROR, error });
      }
      _push(item) {
          if (this._ended) {
              throw new Error('AsyncSink already ended');
          }
          if (this._resolvers.length > 0) {
              const { resolve, reject } = this._resolvers.shift();
              if (item.type === ARRAY_ERROR) {
                  reject(item.error);
              }
              else {
                  resolve({ done: false, value: item.value });
              }
          }
          else {
              this._values.push(item);
          }
      }
      next() {
          if (this._values.length > 0) {
              const { type, value, error } = this._values.shift();
              if (type === ARRAY_ERROR) {
                  return Promise.reject(error);
              }
              else {
                  return Promise.resolve({ done: false, value });
              }
          }
          if (this._ended) {
              return Promise.resolve({ done: true });
          }
          return new Promise((resolve, reject) => {
              this._resolvers.push({ resolve, reject });
          });
      }
      end() {
          while (this._resolvers.length > 0) {
              this._resolvers.shift().resolve({ done: true });
          }
          this._ended = true;
      }
  }
class FromArrayIterable extends AsyncIterableX {
      constructor(source, selector) {
          super();
          this._source = source;
          this._selector = selector;
      }
      [Symbol.asyncIterator]() {
          return __asyncGenerator(this, arguments, function* _a() {
              let i = 0;
              const length = toLength(this._source.length);
              while (i < length) {
                  yield yield __await(yield __await(this._selector(this._source[i], i++)));
              }
          });
      }
  }
class FromAsyncIterable extends AsyncIterableX {
      constructor(source, selector) {
          super();
          this._source = source;
          this._selector = selector;
      }
      [Symbol.asyncIterator](signal) {
          return __asyncGenerator(this, arguments, function* _a() {
              var _b, e_2, _c, _d, _e, e_3, _f, _g;
              let i = 0;
              if (signal && this._source instanceof AsyncIterableX) {
                  try {
                      for (var _h = true, _j = __asyncValues(new WithAbortAsyncIterable$1(this._source, signal)), _k; _k = yield __await(_j.next()), _b = _k.done, !_b; _h = true) {
                          _d = _k.value;
                          _h = false;
                          const item = _d;
                          yield yield __await(yield __await(this._selector(item, i++)));
                      }
                  }
                  catch (e_2_1) { e_2 = { error: e_2_1 }; }
                  finally {
                      try {
                          if (!_h && !_b && (_c = _j.return)) yield __await(_c.call(_j));
                      }
                      finally { if (e_2) throw e_2.error; }
                  }
              }
              else {
                  throwIfAborted(signal);
                  try {
                      for (var _l = true, _m = __asyncValues(this._source), _o; _o = yield __await(_m.next()), _e = _o.done, !_e; _l = true) {
                          _g = _o.value;
                          _l = false;
                          const item = _g;
                          throwIfAborted(signal);
                          const value = yield __await(this._selector(item, i++));
                          throwIfAborted(signal);
                          yield yield __await(value);
                      }
                  }
                  catch (e_3_1) { e_3 = { error: e_3_1 }; }
                  finally {
                      try {
                          if (!_l && !_e && (_f = _m.return)) yield __await(_f.call(_m));
                      }
                      finally { if (e_3) throw e_3.error; }
                  }
              }
          });
      }
  }
class FromPromiseIterable extends AsyncIterableX {
      constructor(source, selector) {
          super();
          this._source = source;
          this._selector = selector;
      }
      [Symbol.asyncIterator]() {
          return __asyncGenerator(this, arguments, function* _a() {
              const item = yield __await(this._source);
              yield yield __await(yield __await(this._selector(item, 0)));
          });
      }
  }
class FromObservableAsyncIterable extends AsyncIterableX {
      constructor(observable, selector) {
          super();
          this._observable = observable;
          this._selector = selector;
      }
      [Symbol.asyncIterator](signal) {
          return __asyncGenerator(this, arguments, function* _a() {
              throwIfAborted(signal);
              const sink = new AsyncSink();
              const subscription = this._observable.subscribe({
                  next(value) {
                      sink.write(value);
                  },
                  error(err) {
                      sink.error(err);
                  },
                  complete() {
                      sink.end();
                  },
              });
              function onAbort() {
                  sink.error(new AbortError());
              }
              if (signal) {
                  signal.addEventListener('abort', onAbort);
              }
              let i = 0;
              try {
                  for (let next; !(next = yield __await(sink.next())).done;) {
                      throwIfAborted(signal);
                      yield yield __await(yield __await(this._selector(next.value, i++)));
                  }
              }
              finally {
                  if (signal) {
                      signal.removeEventListener('abort', onAbort);
                  }
                  subscription.unsubscribe();
              }
          });
      }
  }
  let WithAbortAsyncIterable$1 = class WithAbortAsyncIterable {
      constructor(source, signal) {
          this._source = source;
          this._signal = signal;
      }
      [Symbol.asyncIterator]() {
return this._source[Symbol.asyncIterator](this._signal);
      }
  };
  try {
      ((isBrowser) => {
          if (isBrowser) {
              return;
          }
          AsyncIterableX.prototype['pipe'] = nodePipe;
          const readableOpts = (x, opts = x._writableState || { objectMode: true }) => opts;
          function nodePipe(...args) {
              let i = -1;
              let end;
              const n = args.length;
              let prev = this;
              let next;
              while (++i < n) {
                  next = args[i];
                  if (typeof next === 'function') {
                      prev = next(AsyncIterableX.as(prev));
                  }
                  else if (isWritableNodeStream(next)) {
                      ({ end = true } = args[i + 1] || {});
return isReadableNodeStream(prev) ? prev.pipe(next, { end }) :
                          AsyncIterableX.as(prev).toNodeStream(readableOpts(next)).pipe(next, { end });
                  }
              }
              return prev;
          }
      })(typeof window === 'object' && typeof document === 'object' && document.nodeType === 9);
  }
  catch (e) {
}
  AsyncIterableX.as;
  const from = AsyncIterableX.from;
class WithAbortAsyncIterable extends AsyncIterableX {
      constructor(source, signal) {
          super();
          this._source = source;
          this._signal = signal;
      }
      withAbort(signal) {
          return new WithAbortAsyncIterable(this._source, signal);
      }
      [Symbol.asyncIterator]() {
return this._source[Symbol.asyncIterator](this._signal);
      }
  }
function wrapWithAbort(source, signal) {
      return signal ? new WithAbortAsyncIterable(source, signal) : source;
  }
function returnAsyncIterator(it) {
      return __awaiter(this, void 0, void 0, function* () {
          if (typeof (it === null || it === void 0 ? void 0 : it.return) === 'function') {
              yield it.return();
          }
      });
  }


function isPrimitive(value) {
      return value === null || (typeof value !== 'object' && typeof value !== 'function');
  }

const wm = new WeakMap();
  function safeRace(contenders) {
      let deferred;
      const result = new Promise((resolve, reject) => {
          deferred = { resolve, reject };
          for (const contender of contenders) {
              if (isPrimitive(contender)) {



Promise.resolve(contender).then(resolve, reject);
                  continue;
              }
              let record = wm.get(contender);
              if (record === undefined) {
                  record = { deferreds: new Set([deferred]), settled: false };
                  wm.set(contender, record);
Promise.resolve(contender).then((value) => {
for (const { resolve } of record.deferreds) {
                          resolve(value);
                      }
                      record.deferreds.clear();
                      record.settled = true;
                  }, (err) => {
for (const { reject } of record.deferreds) {
                          reject(err);
                      }
                      record.deferreds.clear();
                      record.settled = true;
                  });
              }
              else if (record.settled) {

Promise.resolve(contender).then(resolve, reject);
              }
              else {
                  record.deferreds.add(deferred);
              }
          }
      });

return result.finally(() => {
          for (const contender of contenders) {
              if (!isPrimitive(contender)) {
                  const record = wm.get(contender);
                  record.deferreds.delete(deferred);
              }
          }
      });
  }
class MapAsyncIterable extends AsyncIterableX {
      constructor(source, selector, thisArg) {
          super();
          this._source = source;
          this._selector = selector;
          this._thisArg = thisArg;
      }
      [Symbol.asyncIterator](signal) {
          return __asyncGenerator(this, arguments, function* _a() {
              var _b, e_1, _c, _d;
              throwIfAborted(signal);
              let i = 0;
              try {
                  for (var _e = true, _f = __asyncValues(wrapWithAbort(this._source, signal)), _g; _g = yield __await(_f.next()), _b = _g.done, !_b; _e = true) {
                      _d = _g.value;
                      _e = false;
                      const item = _d;
                      const result = yield __await(this._selector.call(this._thisArg, item, i++, signal));
                      yield yield __await(result);
                  }
              }
              catch (e_1_1) { e_1 = { error: e_1_1 }; }
              finally {
                  try {
                      if (!_e && !_b && (_c = _f.return)) yield __await(_c.call(_f));
                  }
                  finally { if (e_1) throw e_1.error; }
              }
          });
      }
  }
function map(selector, thisArg) {
      return function mapOperatorFunction(source) {
          return new MapAsyncIterable(source, selector, thisArg);
      };
  }

  class ConcatMapAsyncIterable extends AsyncIterableX {
      constructor(_source, _selector, _thisArg) {
          super();
          this._source = _source;
          this._selector = _selector;
          this._thisArg = _thisArg;
      }
      [Symbol.asyncIterator](signal) {
          return __asyncGenerator(this, arguments, function* _a() {
              var _b, e_1, _c, _d, _e, e_2, _f, _g;
              throwIfAborted(signal);
              let outerIndex = 0;
              const { _thisArg: thisArg, _selector: selector } = this;
              try {
                  for (var _h = true, _j = __asyncValues(wrapWithAbort(this._source, signal)), _k; _k = yield __await(_j.next()), _b = _k.done, !_b; _h = true) {
                      _d = _k.value;
                      _h = false;
                      const outer = _d;
                      const result = selector.call(thisArg, outer, outerIndex++, signal);
                      const values = (isPromise(result) ? yield __await(result) : result);
                      try {
                          for (var _l = true, _m = (e_2 = void 0, __asyncValues(wrapWithAbort(AsyncIterableX.as(values), signal))), _o; _o = yield __await(_m.next()), _e = _o.done, !_e; _l = true) {
                              _g = _o.value;
                              _l = false;
                              const inner = _g;
                              yield yield __await(inner);
                          }
                      }
                      catch (e_2_1) { e_2 = { error: e_2_1 }; }
                      finally {
                          try {
                              if (!_l && !_e && (_f = _m.return)) yield __await(_f.call(_m));
                          }
                          finally { if (e_2) throw e_2.error; }
                      }
                  }
              }
              catch (e_1_1) { e_1 = { error: e_1_1 }; }
              finally {
                  try {
                      if (!_h && !_b && (_c = _j.return)) yield __await(_c.call(_j));
                  }
                  finally { if (e_1) throw e_1.error; }
              }
          });
      }
  }
function concatMap(selector, thisArg) {
      return function concatMapOperatorFunction(source) {
          return new ConcatMapAsyncIterable(source, selector, thisArg);
      };
  }

  const NEVER_PROMISE = new Promise(() => { });
  function ignoreInnerAbortErrors(signal) {
      return function ignoreInnerAbortError(e) {
          if (signal.aborted && e instanceof AbortError) {
              return NEVER_PROMISE;
          }
          throw e;
      };
  }
  function wrapIterator(source, index, type, signal) {
      return __asyncGenerator(this, arguments, function* wrapIterator_1() {
          var _a, e_1, _b, _c;
          throwIfAborted(signal);
          try {
              for (var _d = true, _e = __asyncValues(wrapWithAbort(source, signal)), _f; _f = yield __await(_e.next()), _a = _f.done, !_a; _d = true) {
                  _c = _f.value;
                  _d = false;
                  const value = _c;
                  throwIfAborted(signal);
                  yield yield __await({ type, index, value });
              }
          }
          catch (e_1_1) { e_1 = { error: e_1_1 }; }
          finally {
              try {
                  if (!_d && !_a && (_b = _e.return)) yield __await(_b.call(_e));
              }
              finally { if (e_1) throw e_1.error; }
          }
          return yield __await({ type, index, value: undefined });
      });
  }
class FlattenConcurrentAsyncIterable extends AsyncIterableX {
      constructor(_source, _selector, _concurrent, _switchMode, _thisArg) {
          super();
          this._source = _source;
          this._selector = _selector;
          this._concurrent = _concurrent;
          this._switchMode = _switchMode;
          this._thisArg = _thisArg;
          this._concurrent = this._switchMode ? 1 : Math.max(_concurrent, 1);
      }
      [Symbol.asyncIterator](outerSignal) {
          return __asyncGenerator(this, arguments, function* _a() {
              throwIfAborted(outerSignal);
              let active = 0;
              let outerIndex = 0;
              let outerComplete = false;
              const thisArg = this._thisArg;
              const selector = this._selector;
              const switchMode = this._switchMode;
              const concurrent = this._concurrent;
              const outerValues = new Array(0);
              const innerIndices = new Array(0);
              const controllers = new Array(isFinite(concurrent) ? concurrent : 0);
              const inners = new Array(isFinite(concurrent) ? concurrent : 0);
              const outer = wrapIterator(this._source, 0, 0 , outerSignal);
              const results = [outer.next()];
              try {
                  do {
                      const { done = false, value: { type, value, index }, } = yield __await(safeRace(results));
                      if (!done) {
                          switch (type) {
                              case 0 : {
                                  if (switchMode) {
                                      active = 0;
                                  }
                                  if (active < concurrent) {
                                      pullNextOuter(value);
                                  }
                                  else {
                                      outerValues.push(value);
                                  }
                                  results[0] = outer.next();
                                  break;
                              }
                              case 1 : {
                                  yield yield __await(value);
                                  const { [index - 1]: inner } = inners;
                                  const { [index - 1]: { signal }, } = controllers;
                                  results[index] = inner.next().catch(ignoreInnerAbortErrors(signal));
                                  break;
                              }
                          }
                      }
                      else {
results[index] = NEVER_PROMISE;
                          switch (type) {
                              case 0 : {
                                  outerComplete = true;
                                  break;
                              }
                              case 1 : {
                                  --active;
innerIndices.push(index);
while (active < concurrent && outerValues.length) {
pullNextOuter(outerValues.shift());
                                  }
                                  break;
                              }
                          }
                      }
                  } while (!outerComplete || active + outerValues.length > 0);
              }
              finally {
                  controllers.forEach((controller) => controller === null || controller === void 0 ? void 0 : controller.abort());
                  yield __await(Promise.all([outer, ...inners].map(returnAsyncIterator)));
              }
              function pullNextOuter(outerValue) {
                  ++active;
                  const index = innerIndices.pop() || active;
if (switchMode && controllers[index - 1]) {
                      controllers[index - 1].abort();
                  }
                  controllers[index - 1] = new AbortController();
                  const innerSignal = controllers[index - 1].signal;

const inner = selector.call(thisArg, outerValue, outerIndex++, innerSignal);
                  results[index] = wrapAndPullInner(index, innerSignal, inner).catch(ignoreInnerAbortErrors(innerSignal));
              }
              function wrapAndPullInner(index, signal, inner) {
                  if (isPromise(inner)) {
                      return inner.then((inner) => wrapAndPullInner(index, signal, inner));
                  }
                  return (inners[index - 1] = wrapIterator(AsyncIterableX.as(inner), index, 1 , signal)).next();
              }
          });
      }
  }
function flatMap(selector, concurrent = Infinity, thisArg) {
      return function flatMapOperatorFunction(source) {
          return new FlattenConcurrentAsyncIterable(source, selector, concurrent, false, thisArg);
      };
  }
class TakeWhileAsyncIterable extends AsyncIterableX {
      constructor(source, predicate) {
          super();
          this._source = source;
          this._predicate = predicate;
      }
      [Symbol.asyncIterator](signal) {
          return __asyncGenerator(this, arguments, function* _a() {
              var _b, e_1, _c, _d;
              throwIfAborted(signal);
              let i = 0;
              try {
                  for (var _e = true, _f = __asyncValues(wrapWithAbort(this._source, signal)), _g; _g = yield __await(_f.next()), _b = _g.done, !_b; _e = true) {
                      _d = _g.value;
                      _e = false;
                      const item = _d;
                      if (!(yield __await(this._predicate(item, i++, signal)))) {
                          break;
                      }
                      yield yield __await(item);
                  }
              }
              catch (e_1_1) { e_1 = { error: e_1_1 }; }
              finally {
                  try {
                      if (!_e && !_b && (_c = _f.return)) yield __await(_c.call(_f));
                  }
                  finally { if (e_1) throw e_1.error; }
              }
          });
      }
  }
function takeWhile(predicate) {
      return function takeWhileOperatorFunction(source) {
          return new TakeWhileAsyncIterable(source, predicate);
      };
  }

  class LSKDB {
    constructor(prefix = "lsm-", lockKey = "lsmngr-lock") {
      this.prefix = prefix;
      this.lockKey = lockKey;
    }
    prefixedKey(key) {
      return `${this.prefix}${key}`;
    }
    getAllKeys() {
      const res = [];
      for (const key in localStorage) {
        if (key.startsWith(this.prefix)) {
          res.push(key.slice(this.prefix.length));
        }
      }
      return res;
    }
    getKeys(n = 12, remove = true) {
      const res = [];
      for (const key in localStorage) {
        if (res.length >= n) break;
        if (key.startsWith(this.prefix)) {
          res.push(key.slice(this.prefix.length));
        }
      }
      if (remove) {
        res.forEach((k) => this.removeKey(k));
      }
      return res;
    }
    hasKey(key) {
      return localStorage.getItem(this.prefixedKey(key)) !== null;
    }
    removeKey(key) {
      localStorage.removeItem(this.prefixedKey(key));
    }
    setKey(key) {
      localStorage.setItem(this.prefixedKey(key), "");
    }
    isLocked() {
      const lock = parseInt(localStorage.getItem(this.lockKey));
      const locktime = 5 * 60 * 1e3;
      return !(!lock || Date.now() - lock > locktime);
    }
    lock(value) {
      if (value) {
        localStorage.setItem(this.lockKey, JSON.stringify(Date.now()));
      } else {
        localStorage.removeItem(this.lockKey);
      }
    }
  }

  var _GM_addStyle = (() => typeof GM_addStyle != "undefined" ? GM_addStyle : undefined)();
  var _unsafeWindow = (() => typeof unsafeWindow != "undefined" ? unsafeWindow : undefined)();

  const $ = _unsafeWindow.$;
  const lskdb = new LSKDB();
  const IS_MEMBER_PAGE = /^\/members\/\d+\/$/.test(location.pathname);
  const IS_MESSAGES_PAGE = /^\/my_messages\//.test(location.pathname);
  const IS_PLAYLIST = /^\/playlist\/\d+\//.test(location.pathname);
  const IS_VIDEO_PAGE = /^\/videos\//.test(location.pathname);
  const IS_MY_WALL = /^\/my_wall\//.test(location.pathname);
  const MY_ID = document.querySelector('[target="_self"]')?.href.match(
    /\/(\d+)\//
  )?.[1];
  const LOGGED_IN = !!MY_ID;
  const IS_MY_MEMBER_PAGE = LOGGED_IN && !!document.querySelector(".my-avatar") && IS_MEMBER_PAGE;
  const IS_OTHER_MEMBER_PAGE = !IS_MY_MEMBER_PAGE && IS_MEMBER_PAGE;
  const IS_MEMBER_FRIEND = IS_OTHER_MEMBER_PAGE && document.querySelector(".case-left")?.innerText.includes(
    "is in your friends"
  );
  function fixPlaylistThumbUrl(src) {
    return src.replace(/playlist\/\d+\/video/, () => "videos");
  }
  const defaultRulesConfig = {
    thumbsSelector: "div:has(> .tumbpu[title]):not(.thumbs-photo) > .tumbpu[title], .thumb-holder",
    getThumbImgData(thumb) {
      const img = thumb.querySelector("img");
      const privateThumb = thumb.querySelector(".private");
      let imgSrc = img?.getAttribute("data-original");
      if (privateThumb) {
        imgSrc = utils.parseCssUrl(privateThumb.style.background);
        privateThumb.removeAttribute("style");
      }
      img.removeAttribute("data-original");
      img.removeAttribute("data-cnt");
      img.classList.remove("lazy-load");
      return { img, imgSrc };
    },
    containerSelectorLast: ".thumbs-items",
    titleSelector: ".title",
    durationSelector: ".duration",
    customThumbDataSelectors: {
      private: { selector: ".private", type: "boolean" },
      hd: { selector: ".quality", type: "boolean" },
      views: { selector: ".view", type: "number" }
    },
    animatePreview,
    customDataSelectorFns: [
      "filterInclude",
      "filterExclude",
      "filterDuration",
      {
        filterPrivate: (el, state) => state.filterPrivate && el.private
      },
      {
        filterPublic: (el, state) => state.filterPublic && !el.private
      },
      {
        filterHD: (el, state) => state.filterHD && !el.hd
      },
      {
        filterNonHD: (el, state) => state.filterNonHD && el.hd
      }
    ],
    schemeOptions: [
      "Text Filter",
      "Duration Filter",
      "Privacy Filter",
      {
        title: "HD Filter",
        content: [
          { filterHD: false, label: "hd" },
          { filterNonHD: false, label: "non-hd" }
        ]
      },
      "Badge",
      {
        title: "Advanced",
        content: [{ autoRequestAccess: false, label: "check access sends friend requests" }]
      }
    ],
    gropeStrategy: utils.getCommonParents([
      ...document.querySelectorAll(
        "div:has(> .tumbpu[title]):not(.thumbs-photo) > .tumbpu[title], .thumb-holder"
      )
    ]).length < 2 ? "all-in-one" : "all-in-all"
  };
  const config = IS_MY_MEMBER_PAGE || IS_MY_WALL ? await( createPrivateFeed()) : defaultRulesConfig;
  const rules = new core.RulesGlobal(config);
  _GM_addStyle(`
  .haveNoAccess { background: linear-gradient(to bottom, #b50000 0%, #2c2c2c 100%) red !important; }
  .haveAccess { background: linear-gradient(to bottom, #4e9299 0%, #2c2c2c 100%) green !important; }
  .success { background: linear-gradient(#2f6eb34f, #66666647) !important; }
  .failure { background: linear-gradient(rgba(179, 47, 47, 0.31), rgba(102, 102, 102, 0.28)) !important; }
  .friend-button { background: radial-gradient(#5ccbf4, #e1ccb1) !important; }
  .friendProfile { background: radial-gradient(circle, rgb(28, 42, 50) 48%, rgb(0, 0, 0) 100%) !important; }
  `);
  function friend(id, message = "") {
    return fetch(
      `https://thisvid.com/members/${id}/?action=add_to_friends_complete&function=get_block&block_id=member_profile_view_view_profile&format=json&mode=async&message=${message}`
    );
  }
  function acceptFriendship(id) {
    const body = utils.objectToFormData({
      action: "confirm_add_to_friends",
      function: "get_block",
      block_id: "member_profile_view_view_profile",
      confirm: "",
      format: "json",
      mode: "async"
    });
    const url = `https://thisvid.com/members/${id}/`;
    return fetch(url, { body, method: "post" });
  }
  async function getMemberFriends(memberId, by) {
    const { friendsCount } = await getMemberData(memberId);
    const offset = Math.ceil(friendsCount / 24);
    let friendsURL = `https://thisvid.com/members/${memberId}/friends/`;
    if (by === "activity") friendsURL = "https://thisvid.com/my_friends_by_activity/";
    if (by === "popularity") friendsURL = "https://thisvid.com/my_friends_by_popularity/";
    async function* g() {
      for (const o of utils.range(offset)) {
        const html = await utils.fetchHtml(`${friendsURL}${o}/`);
        for await (const id of getMembers(html)) {
          yield id;
        }
      }
    }
    return g();
  }
  function getMembers(el) {
    const friendsList = el.querySelector("#list_members_friends_items") || el;
    return Array.from(friendsList.querySelectorAll(".tumbpu") || []).map((e) => e.href.match(/\d+/)?.[0]).filter((_) => _);
  }
  async function friendMemberFriends(orientationFilter) {
    const memberId = window.location.pathname.match(/\d+/)?.[0];
    friend(memberId);
    const friends = await getMemberFriends(memberId);
    await from(friends).pipe(
      flatMap(async (fid) => {
        if (!orientationFilter) {
          await friend(fid);
        } else {
          const { orientation, uploadedPrivate } = await getMemberData(fid);
          if (uploadedPrivate > 0 && (orientation === orientationFilter || orientationFilter === "Straight" && orientation === "Lesbian")) {
            await friend(fid);
          }
        }
      }, 60)
    ).forEach(() => {
    });
  }
  function initFriendship() {
    _GM_addStyle(
      ".buttons {display: flex; flex-wrap: wrap} .buttons button, .buttons a {align-self: center; padding: 4px; margin: 5px;}"
    );
    const buttons = [
      { color: "#ff7194", orientation: void 0 },
      { color: "#ba71ff", orientation: "Straight" },
      { color: "#46baff", orientation: "Gay" },
      { color: "#4ebaaf", orientation: "Bisexual" }
    ];
    buttons.forEach((b) => {
      const button = utils.parseHtml(
        `<button style="background: radial-gradient(red, ${b.color});">friend ${b.orientation || "everyone"}</button>`
      );
      document.querySelector(".buttons")?.append(button);
      button.addEventListener("click", (e) => handleClick(e, b.orientation), {
        once: true
      });
    });
    function handleClick(e, orientationFilter) {
      const button = e.target;
      button.style.background = "radial-gradient(#ff6114, #5babc4)";
      button.innerText = "processing requests";
      friendMemberFriends(orientationFilter).then(() => {
        button.style.background = "radial-gradient(blue, lightgreen)";
        button.innerText = "friend requests sent";
      });
    }
  }
  async function getMemberData(id) {
    const url = id.includes("member") ? id : `/members/${id}/`;
    const doc = await utils.fetchHtml(url);
    const data = {};
    doc.querySelectorAll(".profile span").forEach((s) => {
      if (s.innerText.includes("Name:")) {
        data.name = s.firstElementChild?.innerText;
      }
      if (s.innerText.includes("Orientation:")) {
        data.orientation = s.firstElementChild?.innerText;
      }
    });
    data.uploadedPublic = utils.querySelectorLastNumber(
      ".headline:has(+ #list_videos_public_videos_items) span",
      doc
    );
    data.uploadedPrivate = utils.querySelectorLastNumber(
      ".headline:has(+ #list_videos_private_videos_items) span",
      doc
    );
    data.friendsCount = utils.querySelectorLastNumber("#list_members_friends span", doc);
    return data;
  }
  function requestAccessVideoPage() {
    const holder = document.querySelector(".video-holder > p");
    if (holder) {
      const uploader = document.querySelector("a.author").href.match(/\d+/)?.at(-1);
      const button = utils.parseHtml(
        `<button onclick="requestPrivateAccess(event, ${uploader}); this.onclick=null;">Friend Request</button>`
      );
      holder.parentElement?.append(button);
    }
  }
  const requestPrivateAccess = (e, memberid) => {
    e.preventDefault();
    friend(memberid, "");
    e.target.innerText = e.target.innerText.replace(
      "🚑",
      "🍆"
    );
  };
  async function checkPrivateVideoAccess(url) {
    const html = await utils.fetchHtml(url);
    const holder = html.querySelector(".video-holder > p");
    const access = !holder;
    const uploaderEl = holder ? holder.querySelector("a") : html.querySelector("a.author");
    const uploaderURL = uploaderEl.href.match(/\d+/)?.at(-1);
    const uploaderName = uploaderEl.innerText;
    return {
      access,
      uploaderURL,
      uploaderName
    };
  }
  function getUncheckedPrivateThumbs(html = document) {
    return [
      ...html.querySelectorAll(
        ".tumbpu:has(.private):not(.haveNoAccess,.haveAccess), .thumb-holder:has(.private):not(.haveNoAccess,.haveAccess)"
      )
    ];
  }
  const uploadersChecked = new Set();
  async function requestAccess() {
    const checkAccess = async (thumb) => {
      const url = thumb.querySelector("a")?.href || thumb?.href;
      const { access, uploaderURL } = await checkPrivateVideoAccess(url);
      thumb.classList.add(access ? "haveAccess" : "haveNoAccess");
      if (access) return;
      if (rules.store.state.autoRequestAccess && !uploadersChecked.has(uploaderURL)) {
        acceptFriendship(uploaderURL);
        friend(uploaderURL);
      }
    };
    for (const t of getUncheckedPrivateThumbs()) {
      await checkAccess(t);
    }
  }
  const createDownloadButton = () => utils.downloader({
    append: "",
    after: ".share_btn",
    button: '<li><a href="#" style="text-decoration: none;font-size: 2rem;">📼</a></li>',
    cbBefore: () => $(".fp-ui").click()
  });
  function animatePreview(_) {
    const tick = new utils.Tick(750);
    $('img[alt!="Private"]').off();
    function iteratePreviewFrames(img) {
      img.src = img.getAttribute("src").replace(
        /(\d+)(?=\.jpg$)/,
        (_2, n) => `${utils.circularShift(parseInt(n), 6)}`
      );
    }
    function animate(container) {
      utils.onPointerOverAndLeave(
        container,
        (target) => !!target.getAttribute("src"),
        (target) => {
          const e = target;
          const orig = target.getAttribute("src");
          tick.start(
            () => iteratePreviewFrames(e),
            () => {
              e.src = orig;
            }
          );
        },
        () => tick.stop()
      );
    }
    animate(document.querySelector(".content") || document.body);
  }
  async function getMemberVideos(id, type = "private") {
    const { uploadedPrivate, uploadedPublic, name } = await getMemberData(id);
    const videosCount = type === "private" ? uploadedPrivate : uploadedPublic;
    const url = new URL(`https://thisvid.com/members/${id}/${type}_videos/`);
    const doc = await utils.fetchHtml(url.href);
    const paginationStrategy = core.getPaginationStrategy({ doc, url });
    const memberVideosGenerator = core.InfiniteScroller.generatorForPaginationStrategy(paginationStrategy);
    return { name, videosCount, memberVideosGenerator };
  }
  function createPrivateFeedButton() {
    const container = document.querySelectorAll(".sidebar ul")[1];
    const links = [
      { hov: "#private_feed", text: "My Private Feed" },
      { hov: "#private_feed_popularity", text: "My Private Feed by Popularity" },
      { hov: "#private_feed_activity", text: "My Private Feed by Activity" },
      { hov: "#public_feed", text: "My Public Feed" },
      { hov: "#public_feed_popularity", text: "My Public Feed by Popularity" },
      { hov: "#public_feed_activity", text: "My Public Feed by Activity" }
    ];
    const fragment = document.createDocumentFragment();
    links.forEach(({ hov, text }) => {
      const button = utils.parseHtml(
        `<li><a style="color: lightblue;" href="https://thisvid.com/my_wall/${hov}" class="selective"><i class="ico-arrow"></i>${text}</a></li>`
      );
      fragment.append(button);
    });
    container.append(fragment);
  }
  async function createPrivateFeed() {
    createPrivateFeedButton();
    if (!location.hash.includes("feed")) return defaultRulesConfig;
    const isPubKey = window.location.hash.includes("public_feed") ? "public" : "private";
    const sortByFeed = window.location.hash.includes("activity") ? "activity" : window.location.hash.includes("popularity") ? "popularity" : void 0;
    const container = utils.parseHtml('<div class="thumbs-items"></div>');
    const ignored = utils.parseHtml('<div class="ignored"><h2>IGNORED:</h2></div>');
    const containerParent = document.querySelector(
      ".main > .container > .content"
    );
    containerParent.innerHTML = "";
    containerParent?.nextElementSibling?.remove();
    containerParent.append(container);
    container.before(ignored);
    _GM_addStyle(`
   .content { width: auto; }
   .member-videos, .ignored { background: #b3b3b324; min-height: 3rem; margin: 1rem 0px; color: #fff; font-size: 1.24rem; display: flex; flex-wrap: wrap; justify-content: center;
     padding: 10px; width: 100%; }
   .member-videos * {  padding: 5px; margin: 4px; }
   .member-videos h2 a { font-size: 1.24rem; margin: 0; padding: 0; display: inline; }
   .ignored * {  padding: 4px; margin: 5px; }
   .thumbs-items { display: flex; flex-wrap: wrap; }`);
    const { friendsCount } = await getMemberData(MY_ID);
    class FeedGenerator {
      constructor(id, memberGeneratorCallback, type = "private", by = void 0) {
        this.id = id;
        this.memberGeneratorCallback = memberGeneratorCallback;
        this.type = type;
        this.by = by;
      }
      offset = 0;
      minVideoCount = 1;
      skip(n) {
        this.offset += n;
      }
      filterMinVideoCount(n) {
        this.minVideoCount = n;
      }
      async *consume() {
        const membersIds = await getMemberFriends(this.id, this.by);
        const stream = from(membersIds).pipe(
          concatMap(async (mid, index) => {
            if (index < this.offset) return from([]);
            this.offset = index;
            const { memberVideosGenerator, name, videosCount } = await getMemberVideos(
              mid,
              this.type
            );
            if (lskdb.hasKey(mid) || videosCount < this.minVideoCount) return from([]);
            this.memberGeneratorCallback?.(name, videosCount, mid);
            return from(memberVideosGenerator).pipe(
              takeWhile(() => index >= this.offset),
              map(async (element) => ({ url: element.url, offset: index }))
            );
          })
        );
        yield* stream;
      }
    }
    const feedGenerator = new FeedGenerator(
      MY_ID,
      (name, videosCount, id) => {
        if (container.querySelector(`#mem-${id}`)) return;
        container.append(
          utils.parseHtml(`
       <div class="member-videos" id="mem-${id}">
         <h2><a href="/members/${id}/">${name}</a> ${videosCount} videos</h2>
         <button onClick="hideMemberVideos(event)">ignore 🗡</button>
         <button onClick="hideMemberVideos(event, false)">skip</button>
       </div>`)
        );
      },
      isPubKey,
      sortByFeed
    );
    const ignoredMembers = lskdb.getAllKeys();
    ignoredMembers.forEach((im) => {
      document.querySelector(".ignored")?.append(
        utils.parseHtml(`<button id="#ir-${im}" onClick="unignore(event)">${im} 🗡</button>`)
      );
    });
    const skip = (n) => {
      feedGenerator.skip(n);
      document.querySelector(".thumbs-items").innerHTML = "";
    };
    const hideMemberVideos = (e, ignore = true) => {
      const container2 = e.target?.closest("div");
      let id = container2.id;
      const videosCount = utils.querySelectorLastNumber(`#${id}`);
      document.querySelectorAll(`#${id}~a`).values().take(videosCount).forEach((e2) => {
        e2.remove();
      });
      container2.remove();
      id = id.slice(4);
      if (ignore) {
        const btn = utils.parseHtml(
          `<button id="irm-${id}" onClick="unignore(event)">${id} X</button>`
        );
        document.querySelector(".ignored")?.append(btn);
        lskdb.setKey(id);
      }
    };
    const unignore = (e) => {
      const target = e.target;
      const id = target.id.slice(4);
      lskdb.removeKey(id);
      target.remove();
    };
    const filterMinVideoCount = (n) => feedGenerator.filterMinVideoCount(n);
    Object.assign(_unsafeWindow, { unignore, hideMemberVideos });
    const customGenerator = await feedGenerator.consume();
    const rulesConfig = Object.assign(defaultRulesConfig, {
      containerSelector: () => container,
      intersectionObservableSelector: ".footer",
      customGenerator,
      paginationStrategyOptions: {
        getPaginationLast: () => friendsCount,
        paginationSelector: ".footer"
      },
      schemeOptions: [
        "Text Filter",
        "Duration Filter",
        "Privacy Filter",
        "Badge",
        {
          title: "Feed Controls",
          content: [
            { "skip 10": () => skip(10) },
            { "skip 100": () => skip(100) },
            { "skip 1000": () => skip(1e3) },
            { "filter >10": () => filterMinVideoCount(10) },
            { "filter >25": () => filterMinVideoCount(25) },
            { "filter >100": () => filterMinVideoCount(100) }
          ]
        },
        "Advanced"
      ]
    });
    return rulesConfig;
  }
  function deleteMsg(id) {
    fetch(
      `https://thisvid.com/my_messages/inbox/?mode=async&format=json&action=delete&function=get_block&block_id=list_messages_my_conversation_messages&delete[]=${id}`
    );
  }
  async function clearMessages() {
    const sortMsgs = (doc) => {
      doc.querySelectorAll(".entry").forEach((e) => {
        const id = e.querySelector('input[name="delete[]"]')?.value;
        const msg = e.querySelector(".user-comment")?.innerText;
        if (/has confirmed|declined your|has removed/g.test(msg)) deleteMsg(id);
      });
    };
    await Promise.all(
      Array.from(
        { length: rules.paginationStrategy.getPaginationLast() },
        (_, i) => utils.fetchHtml(`https://thisvid.com/my_messages/inbox/${i + 1}/`).then(
          (html) => sortMsgs(html)
        )
      )
    );
  }
  function clearMessagesButton() {
    const btn = utils.parseHtml("<button>clear messages</button>");
    btn.addEventListener("click", clearMessages);
    document.querySelector(".headline")?.append(btn);
  }
  function highlightMessages() {
    document.querySelectorAll(".entry").forEach((entry) => {
      const memberUrl = entry.querySelector("a")?.href;
      getMemberData(memberUrl).then(({ uploadedPublic, uploadedPrivate }) => {
        if (uploadedPrivate > 0) {
          const success = !entry.innerText.includes("has declined");
          entry.classList.add(success ? "success" : "failure");
        }
        entry.querySelector(".user-comment p").innerText += `  |  videos: ${uploadedPublic} public, ${uploadedPrivate} private`;
      });
    });
  }
  if (LOGGED_IN) {
    rules.store.eventSubject.subscribe((x) => {
      if (x.includes("check access")) {
        requestAccess();
      }
    });
  }
  if (IS_MESSAGES_PAGE) {
    clearMessagesButton();
    highlightMessages();
  }
  if (IS_VIDEO_PAGE) {
    requestAccessVideoPage();
    createDownloadButton();
  }
  if (IS_OTHER_MEMBER_PAGE) {
    initFriendship();
  }
  Object.assign(_unsafeWindow, { requestPrivateAccess });
  if (IS_MEMBER_FRIEND) {
    document.querySelector(".profile")?.classList.add("friendProfile");
  }
  if (IS_PLAYLIST) {
    const videoUrl = fixPlaylistThumbUrl(location.pathname);
    const desc = document.querySelector(
      ".tools-left > li:nth-child(4) > .title-description"
    );
    const link = utils.replaceElementTag(desc, "a");
    link.href = videoUrl;
  }

})(core, utils);