Sleazy Fork is available in English.

Javlibrary - 首页一站式影片预览

不需要跳转,在 Javlibrary 首页就能直接预览影片。会缓存影片相关信息,下次可直接使用。可搜索番号或前缀。支持轻量的 torrentkitty 磁力搜索展示。

Versión del día 02/05/2021. Echa un vistazo a la versión más reciente.

// ==UserScript==
// @name              Javlibrary - 首页一站式影片预览
// @version           0.8.3
// @description       不需要跳转,在 Javlibrary 首页就能直接预览影片。会缓存影片相关信息,下次可直接使用。可搜索番号或前缀。支持轻量的 torrentkitty 磁力搜索展示。
// @author            thinker
// @namespace         https://greasyfork.org/users/440616
// @include           http*://www.javlibrary.com/cn/
// @include           http*://www.javlibrary.com/cn/?__cf_chl_jschl_tk__*
// @require           https://cdn.bootcss.com/vue/2.6.10/vue.runtime.min.js
// @require           https://unpkg.com/rectangle-transform@0.4.0/lib/rectangle-transform.min.js
// @grant             GM_xmlhttpRequest
// ==/UserScript==

(function (RTListener, Vue) {
  'use strict';

  

  function __$styleInject(css) {
      if (!css) return;

      if (typeof window == 'undefined') return;
      var style = document.createElement('style');
      style.setAttribute('media', 'screen');

      style.innerHTML = css;
      document.head.appendChild(style);
      return css;
  }

  RTListener = RTListener && Object.prototype.hasOwnProperty.call(RTListener, 'default') ? RTListener['default'] : RTListener;
  Vue = Vue && Object.prototype.hasOwnProperty.call(Vue, 'default') ? Vue['default'] : Vue;

  //
  //
  //
  //
  //
  //
  //
  //
  //
  //
  //

  var script = {
    props: {
      zIndex: {
        default: 1
      }
    },
    data () {
      return {
        show: true
      }
    },
    mounted () {
      this.show = this.optionShow;
    },
    computed: {
      optionShow () {
        return this.$root.options.showApp
      }
    }
  };

  function normalizeComponent(template, style, script, scopeId, isFunctionalTemplate, moduleIdentifier /* server only */, shadowMode, createInjector, createInjectorSSR, createInjectorShadow) {
      if (typeof shadowMode !== 'boolean') {
          createInjectorSSR = createInjector;
          createInjector = shadowMode;
          shadowMode = false;
      }
      // Vue.extend constructor export interop.
      const options = typeof script === 'function' ? script.options : script;
      // render functions
      if (template && template.render) {
          options.render = template.render;
          options.staticRenderFns = template.staticRenderFns;
          options._compiled = true;
          // functional template
          if (isFunctionalTemplate) {
              options.functional = true;
          }
      }
      // scopedId
      if (scopeId) {
          options._scopeId = scopeId;
      }
      let hook;
      if (moduleIdentifier) {
          // server build
          hook = function (context) {
              // 2.3 injection
              context =
                  context || // cached call
                      (this.$vnode && this.$vnode.ssrContext) || // stateful
                      (this.parent && this.parent.$vnode && this.parent.$vnode.ssrContext); // functional
              // 2.2 with runInNewContext: true
              if (!context && typeof __VUE_SSR_CONTEXT__ !== 'undefined') {
                  context = __VUE_SSR_CONTEXT__;
              }
              // inject component styles
              if (style) {
                  style.call(this, createInjectorSSR(context));
              }
              // register component module identifier for async chunk inference
              if (context && context._registeredComponents) {
                  context._registeredComponents.add(moduleIdentifier);
              }
          };
          // used by ssr in case component is cached and beforeCreate
          // never gets called
          options._ssrRegister = hook;
      }
      else if (style) {
          hook = shadowMode
              ? function (context) {
                  style.call(this, createInjectorShadow(context, this.$root.$options.shadowRoot));
              }
              : function (context) {
                  style.call(this, createInjector(context));
              };
      }
      if (hook) {
          if (options.functional) {
              // register for functional component in vue file
              const originalRender = options.render;
              options.render = function renderWithStyleInjection(h, context) {
                  hook.call(context);
                  return originalRender(h, context);
              };
          }
          else {
              // inject component registration as beforeCreate hook
              const existing = options.beforeCreate;
              options.beforeCreate = existing ? [].concat(existing, hook) : [hook];
          }
      }
      return script;
  }

  const isOldIE = typeof navigator !== 'undefined' &&
      /msie [6-9]\\b/.test(navigator.userAgent.toLowerCase());
  function createInjector(context) {
      return (id, style) => addStyle(id, style);
  }
  let HEAD;
  const styles = {};
  function addStyle(id, css) {
      const group = isOldIE ? css.media || 'default' : id;
      const style = styles[group] || (styles[group] = { ids: new Set(), styles: [] });
      if (!style.ids.has(id)) {
          style.ids.add(id);
          let code = css.source;
          if (css.map) {
              // https://developer.chrome.com/devtools/docs/javascript-debugging
              // this makes source maps inside style tags work properly in Chrome
              code += '\n/*# sourceURL=' + css.map.sources[0] + ' */';
              // http://stackoverflow.com/a/26603875
              code +=
                  '\n/*# sourceMappingURL=data:application/json;base64,' +
                      btoa(unescape(encodeURIComponent(JSON.stringify(css.map)))) +
                      ' */';
          }
          if (!style.element) {
              style.element = document.createElement('style');
              style.element.type = 'text/css';
              if (css.media)
                  style.element.setAttribute('media', css.media);
              if (HEAD === undefined) {
                  HEAD = document.head || document.getElementsByTagName('head')[0];
              }
              HEAD.appendChild(style.element);
          }
          if ('styleSheet' in style.element) {
              style.styles.push(code);
              style.element.styleSheet.cssText = style.styles
                  .filter(Boolean)
                  .join('\n');
          }
          else {
              const index = style.ids.size - 1;
              const textNode = document.createTextNode(code);
              const nodes = style.element.childNodes;
              if (nodes[index])
                  style.element.removeChild(nodes[index]);
              if (nodes.length)
                  style.element.insertBefore(textNode, nodes[index]);
              else
                  style.element.appendChild(textNode);
          }
      }
  }

  /* script */
  const __vue_script__ = script;

  /* template */
  var __vue_render__ = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      { staticClass: "ti-container", style: { zIndex: _vm.zIndex } },
      [
        _c(
          "div",
          {
            staticClass: "toggle",
            class: _vm.show ? "to-hide" : "to-show",
            on: {
              click: function($event) {
                _vm.show = !_vm.show;
              }
            }
          },
          [_c("i", { staticClass: "ti-toggle" })]
        ),
        _vm._v(" "),
        _vm.show
          ? _c("div", { staticClass: "main" }, [_vm._t("default")], 2)
          : _vm._e()
      ]
    )
  };
  var __vue_staticRenderFns__ = [];
  __vue_render__._withStripped = true;

    /* style */
    const __vue_inject_styles__ = function (inject) {
      if (!inject) return
      inject("data-v-4a206468_0", { source: ".ti-container[data-v-4a206468] {\n  position: fixed;\n  left: 0;\n  top: 0;\n}\n.ti-container .toggle[data-v-4a206468] {\n  position: absolute;\n  left: -20px;\n  top: -20px;\n  width: 40px;\n  height: 40px;\n  border-bottom-right-radius: 20px;\n  background-color: #ee4dba;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  z-index: 10;\n}\n.ti-container .toggle.to-show[data-v-4a206468] {\n  animation: 1.5s A-data-v-4a206468 infinite;\n}\n.ti-container .toggle .ti-toggle[data-v-4a206468] {\n  font-size: 13px;\n  width: 1em;\n  height: 1em;\n  border: 2px solid #fff;\n  display: inline-block;\n  transition: 0.5s all;\n  border-right: 0;\n  border-bottom: 0;\n}\n.ti-container .toggle.to-show .ti-toggle[data-v-4a206468] {\n  transform: rotate(180deg);\n}\n@keyframes A-data-v-4a206468 {\n50% {\n    transform: scale(1.4, 1.4);\n}\n}\n.ti-container .toggle[data-v-4a206468]:hover {\n  left: 0;\n  top: 0;\n}\n.ti-container .main[data-v-4a206468] {\n  background-color: #000000cb;\n}\n", map: {"version":3,"sources":["container.vue","D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\container.vue"],"names":[],"mappings":"AAAA;EACE,eAAe;EACf,OAAO;EACP,MAAM;AACR;AACA;EACE,kBAAkB;EAClB,WAAW;EACX,UAAU;EACV,WAAW;EACX,YAAY;EACZ,gCAAgC;EAChC,yBAAyB;EACzB,aAAa;EACb,uBAAuB;EACvB,mBAAmB;EACnB,WAAW;AACb;AACA;EACE,0CAA0B;AAC5B;AACA;EACE,eAAe;EACf,UAAU;EACV,WAAW;EACX,sBAAsB;EACtB,qBAAqB;EACrB,oBAAoB;EACpB,eAAe;EACf,gBAAgB;AAClB;AACA;EACE,yBAAyB;AAC3B;AACA;ACCA;IACA,0BAAA;AACA;AACA;AACA;EACA,OAAA;EACA,MAAA;AACA;AACA;EACA,2BAAA;AACA","file":"container.vue","sourcesContent":[".ti-container {\n  position: fixed;\n  left: 0;\n  top: 0;\n}\n.ti-container .toggle {\n  position: absolute;\n  left: -20px;\n  top: -20px;\n  width: 40px;\n  height: 40px;\n  border-bottom-right-radius: 20px;\n  background-color: #ee4dba;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  z-index: 10;\n}\n.ti-container .toggle.to-show {\n  animation: 1.5s A infinite;\n}\n.ti-container .toggle .ti-toggle {\n  font-size: 13px;\n  width: 1em;\n  height: 1em;\n  border: 2px solid #fff;\n  display: inline-block;\n  transition: 0.5s all;\n  border-right: 0;\n  border-bottom: 0;\n}\n.ti-container .toggle.to-show .ti-toggle {\n  transform: rotate(180deg);\n}\n@keyframes A {\n  50% {\n    transform: scale(1.4, 1.4);\n  }\n}\n.ti-container .toggle:hover {\n  left: 0;\n  top: 0;\n}\n.ti-container .main {\n  background-color: #000000cb;\n}\n","<template>\r\n  <div class=\"ti-container\" :style=\"{zIndex}\">\r\n    <div class=\"toggle\"  :class=\"show ? 'to-hide' : 'to-show'\" @click=\"show = !show\">\r\n      <i class=\"ti-toggle\"></i>\r\n    </div>\r\n    <div class=\"main\" v-if=\"show\">\r\n      <slot></slot>\r\n    </div>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n  props: {\r\n    zIndex: {\r\n      default: 1\r\n    }\r\n  },\r\n  data () {\r\n    return {\r\n      show: true\r\n    }\r\n  },\r\n  mounted () {\r\n    this.show = this.optionShow\r\n  },\r\n  computed: {\r\n    optionShow () {\r\n      return this.$root.options.showApp\r\n    }\r\n  }\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"less\">\r\n.ti-container\r\n{\r\n  position: fixed;\r\n  left: 0;\r\n  top: 0;\r\n}\r\n.ti-container .toggle\r\n{\r\n  @size: 40px;\r\n  @half: @size / 2;\r\n  position: absolute;\r\n  left: -@half;\r\n  top: -@half;\r\n  width: @size;\r\n  height: @size;    \r\n  border-bottom-right-radius: @half;\r\n  background-color: #ee4dba;\r\n  display: flex;\r\n  justify-content: center;\r\n  align-items: center;\r\n  z-index: 10;\r\n  &.to-show {\r\n    animation: 1.5s A infinite;\r\n  }\r\n\r\n  .ti-toggle {\r\n    font-size: 13px;\r\n    width: 1em;\r\n    height: 1em;\r\n    border: 2px solid #fff;\r\n    display: inline-block;\r\n    transition: .5s all;\r\n    border-right: 0;\r\n    border-bottom: 0;\r\n  }\r\n  &.to-show .ti-toggle {\r\n    transform: rotate(180deg);\r\n  }\r\n}\r\n\r\n@keyframes A {\r\n  50% {\r\n    transform: scale(1.4, 1.4);\r\n  }\r\n}\r\n\r\n.ti-container .toggle:hover\r\n{\r\n  left: 0;\r\n  top: 0;\r\n}\r\n.ti-container .main\r\n{\r\n  background-color: #000000cb;\r\n}\r\n\r\n</style>\r\n"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__ = "data-v-4a206468";
    /* module identifier */
    const __vue_module_identifier__ = undefined;
    /* functional template */
    const __vue_is_functional_template__ = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__ = normalizeComponent(
      { render: __vue_render__, staticRenderFns: __vue_staticRenderFns__ },
      __vue_inject_styles__,
      __vue_script__,
      __vue_scope_id__,
      __vue_is_functional_template__,
      __vue_module_identifier__,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  var script$1 = {
    props: {
      src: {
        default: ''
      }
    },
    data () {
      return {
        bounding: {
          left: window.screen.availWidth - 838,
          top: window.screen.availHeight - 550,
          width: 838,
          height: 550,
        }
      }
    },
    computed: {
      styles () {
        return Object.keys(this.bounding).reduce((s, k) => {
          s[k] = this.bounding[k] + 'px';
          return s
        }, {})
      }
    },
    methods: {
      onload (ev) {
        console.log('load');
        const doc = ev.target.contentDocument;
        const devStyle = doc.createElement('style');
        devStyle.innerHTML = `
        /*# .vue */ 
        #video_jacket_img {
          width: 100%;
          height: 100%;
        }
        #leftmenu, #toplogo, #topmenu {
          display: none;
        }
        #rightcolumn {
          margin: 0px 10px 10px 0px;
        }
      `;
        doc.head.appendChild(devStyle);
      },
      transform (ev, control) {
        RTListener(ev, {
          control,
          target: this.bounding,
          animationFrameUpdate: true
        }, ({target}) => {
          this.bounding = target;
        });
      },
    }
  };

  /* script */
  const __vue_script__$1 = script$1;

  /* template */
  var __vue_render__$1 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      {
        directives: [
          { name: "show", rawName: "v-show", value: _vm.src, expression: "src" }
        ],
        staticClass: "tm-jav-window",
        style: _vm.styles
      },
      [
        _c(
          "div",
          {
            staticClass: "tm-jav-window--header",
            on: {
              mousedown: function($event) {
                return _vm.transform($event, "xy")
              }
            }
          },
          [
            _c("span", [_vm._v("可拖拽,右下可缩放")]),
            _vm._v(" "),
            _c("i", {
              staticClass: "tm-jav--close",
              on: {
                click: function($event) {
                  return _vm.$emit("close")
                }
              }
            })
          ]
        ),
        _vm._v(" "),
        _vm.src
          ? _c("iframe", {
              ref: "iframe",
              attrs: { src: _vm.src, frameborder: "0" },
              on: { load: _vm.onload }
            })
          : _vm._e(),
        _vm._v(" "),
        _c("i", {
          staticClass: "tm-jav-window--resize",
          on: {
            mousedown: function($event) {
              return _vm.transform($event, "rb")
            }
          }
        })
      ]
    )
  };
  var __vue_staticRenderFns__$1 = [];
  __vue_render__$1._withStripped = true;

    /* style */
    const __vue_inject_styles__$1 = function (inject) {
      if (!inject) return
      inject("data-v-69547121_0", { source: ".tm-jav-window[data-v-69547121] {\n  position: fixed;\n  z-index: 100;\n  background: #fff;\n  box-shadow: 0px -2px 9px 4px rgba(0, 0, 0, 0.35);\n}\n.tm-jav-window iframe[data-v-69547121] {\n  width: 100%;\n  height: 100%;\n}\n.tm-jav-window--header[data-v-69547121] {\n  position: relative;\n  height: 20px;\n  background-color: #ddd;\n  cursor: move;\n  padding-left: 10px;\n  color: #888;\n}\n.tm-jav-window--header .tm-jav--close[data-v-69547121] {\n  position: absolute;\n  right: 10px;\n  font-size: 18px;\n  background: transparent;\n  cursor: pointer;\n}\n.tm-jav-window--resize[data-v-69547121] {\n  position: absolute;\n  right: 0;\n  bottom: -20px;\n  border: 8px solid #888;\n  cursor: nw-resize;\n  border-top-color: transparent;\n  border-left-color: transparent;\n}\n.tm-jav-window--resize[data-v-69547121]:hover {\n  border-right-color: #ccc;\n  border-bottom-color: #ccc;\n}\n", map: {"version":3,"sources":["window.vue"],"names":[],"mappings":"AAAA;EACE,eAAe;EACf,YAAY;EACZ,gBAAgB;EAChB,gDAAgD;AAClD;AACA;EACE,WAAW;EACX,YAAY;AACd;AACA;EACE,kBAAkB;EAClB,YAAY;EACZ,sBAAsB;EACtB,YAAY;EACZ,kBAAkB;EAClB,WAAW;AACb;AACA;EACE,kBAAkB;EAClB,WAAW;EACX,eAAe;EACf,uBAAuB;EACvB,eAAe;AACjB;AACA;EACE,kBAAkB;EAClB,QAAQ;EACR,aAAa;EACb,sBAAsB;EACtB,iBAAiB;EACjB,6BAA6B;EAC7B,8BAA8B;AAChC;AACA;EACE,wBAAwB;EACxB,yBAAyB;AAC3B","file":"window.vue","sourcesContent":[".tm-jav-window {\n  position: fixed;\n  z-index: 100;\n  background: #fff;\n  box-shadow: 0px -2px 9px 4px rgba(0, 0, 0, 0.35);\n}\n.tm-jav-window iframe {\n  width: 100%;\n  height: 100%;\n}\n.tm-jav-window--header {\n  position: relative;\n  height: 20px;\n  background-color: #ddd;\n  cursor: move;\n  padding-left: 10px;\n  color: #888;\n}\n.tm-jav-window--header .tm-jav--close {\n  position: absolute;\n  right: 10px;\n  font-size: 18px;\n  background: transparent;\n  cursor: pointer;\n}\n.tm-jav-window--resize {\n  position: absolute;\n  right: 0;\n  bottom: -20px;\n  border: 8px solid #888;\n  cursor: nw-resize;\n  border-top-color: transparent;\n  border-left-color: transparent;\n}\n.tm-jav-window--resize:hover {\n  border-right-color: #ccc;\n  border-bottom-color: #ccc;\n}\n"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$1 = "data-v-69547121";
    /* module identifier */
    const __vue_module_identifier__$1 = undefined;
    /* functional template */
    const __vue_is_functional_template__$1 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$1 = normalizeComponent(
      { render: __vue_render__$1, staticRenderFns: __vue_staticRenderFns__$1 },
      __vue_inject_styles__$1,
      __vue_script__$1,
      __vue_scope_id__$1,
      __vue_is_functional_template__$1,
      __vue_module_identifier__$1,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  //
  //
  //
  //
  //
  //
  //
  //
  //
  //
  //
  //

  var script$2 = {
    props: {
      video: {
        type: Object,
        default: null
      }
    },
    methods: {
      showPreview () {
        this.$emit('show-preview');
      }
    }
  };

  /* script */
  const __vue_script__$2 = script$2;

  /* template */
  var __vue_render__$2 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("div", { staticClass: "tm-jav-item" }, [
      _c("div", { staticClass: "tm-jav-item--inner" }, [
        _c("img", {
          staticClass: "tm-jav-item--cover",
          attrs: { src: _vm.video.image, alt: _vm.video.title, width: "100%" }
        }),
        _vm._v(" "),
        _c("div", { staticClass: "play-btn", on: { click: _vm.showPreview } }),
        _vm._v(" "),
        _c("div", { staticClass: "tm-jav-item--info" }, [
          _c("span", { staticClass: "tm-jav-item--avid" }, [
            _vm._v(_vm._s(_vm.video.avid))
          ]),
          _vm._v(" "),
          _c(
            "a",
            {
              staticClass: "tm-jav-item--title",
              attrs: {
                target: "_blank",
                href: _vm.video.href,
                title: _vm.video.title
              }
            },
            [_vm._v(_vm._s(_vm.video.title))]
          )
        ])
      ])
    ])
  };
  var __vue_staticRenderFns__$2 = [];
  __vue_render__$2._withStripped = true;

    /* style */
    const __vue_inject_styles__$2 = function (inject) {
      if (!inject) return
      inject("data-v-54e5faad_0", { source: ".tm-jav-item[data-v-54e5faad] {\n  min-height: 200px;\n  min-width: 147px;\n  padding: 8px;\n  display: inline-block;\n  overflow: hidden;\n  position: relative;\n}\n.tm-jav-item--cover[data-v-54e5faad] {\n  max-height: 200px;\n  max-height: 300px;\n  object-fit: cover;\n}\n.tm-jav-item--inner[data-v-54e5faad] {\n  width: 100%;\n  height: 100%;\n  position: relative;\n}\n.tm-jav-item--info[data-v-54e5faad] {\n  color: #fff;\n  text-shadow: 1px 1px 2px black;\n  transition: all 0.5s;\n  position: absolute;\n  z-index: 1;\n  left: 0;\n  top: 70%;\n  height: 30%;\n  display: block;\n  background-color: rgba(32, 32, 32, 0.3);\n  width: 100%;\n  overflow: hidden;\n}\n.tm-jav-item--title[data-v-54e5faad] {\n  color: #fff;\n}\n.tm-jav-item .play-btn[data-v-54e5faad] {\n  transition: all 0.5s;\n  position: absolute;\n  bottom: 30%;\n  left: 0px;\n  width: 1em;\n  height: 1em;\n  border-radius: 1em;\n  font-size: 30px;\n  cursor: pointer;\n  z-index: 2;\n  background-color: rgba(32, 32, 32, 0.3);\n}\n.tm-jav-item .play-btn[data-v-54e5faad]::before {\n  content: '';\n  position: absolute;\n  left: 0.1em;\n  top: 0.1em;\n  width: 0.8em;\n  height: 0.8em;\n  border-radius: 0.8em;\n  border-width: 2px;\n  border-style: solid;\n  border-color: white;\n  border-image: initial;\n  box-sizing: border-box;\n}\n.tm-jav-item .play-btn[data-v-54e5faad]::after {\n  border-width: 0.3em 0 0.3em 0.4em;\n  top: 0.2em;\n  left: 0.35em;\n  content: \"\";\n  position: absolute;\n  border-style: solid;\n  border-color: transparent white;\n  border-image: initial;\n}\n.tm-jav-item .play-btn[data-v-54e5faad]:hover::before {\n  border-color: #ffa04c;\n}\n.tm-jav-item .play-btn[data-v-54e5faad]:hover::after {\n  border-color: transparent #ffa04c;\n}\n.tm-jav-item:hover .play-btn[data-v-54e5faad] {\n  bottom: 4px;\n}\n.tm-jav-item:hover .tm-jav-item[data-v-54e5faad] {\n  box-shadow: rgba(45, 45, 45, 0.05) 0px 2px 2px 0px rgba(42, 42, 42, 0.05) 0px 8px 8px 0px, rgba(32, 32, 32, 0.05) 0px 16px 16px 0px, rgba(49, 49, 49, 0.05) 0px 32px 32px 0px, rgba(35, 35, 35, 0.05) 0px 64px 64px 0px;\n}\n.tm-jav-item:hover .tm-jav-item--inner[data-v-54e5faad] {\n  transform: scale(1.08);\n  transform-origin: center center;\n}\n.tm-jav-item:hover .tm-jav-item--cover[data-v-54e5faad] {\n  filter: blur(2px);\n}\n.tm-jav-item:hover .tm-jav-item--info[data-v-54e5faad] {\n  position: absolute;\n  top: 0;\n  left: 0;\n  height: 100%;\n}\n", map: {"version":3,"sources":["item.vue","D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\item.vue"],"names":[],"mappings":"AAAA;EACE,iBAAiB;EACjB,gBAAgB;EAChB,YAAY;EACZ,qBAAqB;EACrB,gBAAgB;EAChB,kBAAkB;AACpB;AACA;EACE,iBAAiB;EACjB,iBAAiB;EACjB,iBAAiB;AACnB;AACA;EACE,WAAW;EACX,YAAY;EACZ,kBAAkB;AACpB;AACA;EACE,WAAW;EACX,8BAA8B;EAC9B,oBAAoB;EACpB,kBAAkB;EAClB,UAAU;EACV,OAAO;EACP,QAAQ;EACR,WAAW;EACX,cAAc;EACd,uCAAuC;EACvC,WAAW;ECCb,gBAAA;AACA;AACA;EACA,WAAA;AACA;AACA;EACA,oBAAA;EDCE,kBAAkB;ECCpB,WAAA;EACA,SAAA;EACA,UAAA;EACA,WAAA;EACA,kBAAA;EDCE,eAAe;ECCjB,eAAA;EACA,UAAA;EACA,uCAAA;AACA;AACA;EDCE,WAAW;ECCb,kBAAA;EACA,WAAA;EACA,UAAA;EACA,YAAA;EACA,aAAA;EACA,oBAAA;EACA,iBAAA;EACA,mBAAA;EACA,mBAAA;EACA,qBAAA;EACA,sBAAA;AACA;AACA;EACA,iCAAA;EDCE,UAAU;ECCZ,YAAA;EACA,WAAA;EACA,kBAAA;EACA,mBAAA;EACA,+BAAA;EACA,qBAAA;AACA;AACA;EACA,qBAAA;AACA;AACA;EACA,iCAAA;AACA;AACA;EACA,WAAA;ADCA;ACCA;EACA,uNAAA;AACA;AACA;EACA,sBAAA;EACA,+BAAA;AACA;AACA;EACA,iBAAA;AACA;AACA;EACA,kBAAA;EACA,MAAA;EACA,OAAA;EACA,YAAA;AACA","file":"item.vue","sourcesContent":[".tm-jav-item {\n  min-height: 200px;\n  min-width: 147px;\n  padding: 8px;\n  display: inline-block;\n  overflow: hidden;\n  position: relative;\n}\n.tm-jav-item--cover {\n  max-height: 200px;\n  max-height: 300px;\n  object-fit: cover;\n}\n.tm-jav-item--inner {\n  width: 100%;\n  height: 100%;\n  position: relative;\n}\n.tm-jav-item--info {\n  color: #fff;\n  text-shadow: 1px 1px 2px black;\n  transition: all 0.5s;\n  position: absolute;\n  z-index: 1;\n  left: 0;\n  top: 70%;\n  height: 30%;\n  display: block;\n  background-color: rgba(32, 32, 32, 0.3);\n  width: 100%;\n  overflow: hidden;\n}\n.tm-jav-item--title {\n  color: #fff;\n}\n.tm-jav-item .play-btn {\n  transition: all 0.5s;\n  position: absolute;\n  bottom: 30%;\n  left: 0px;\n  width: 1em;\n  height: 1em;\n  border-radius: 1em;\n  font-size: 30px;\n  cursor: pointer;\n  z-index: 2;\n  background-color: rgba(32, 32, 32, 0.3);\n}\n.tm-jav-item .play-btn::before {\n  content: '';\n  position: absolute;\n  left: 0.1em;\n  top: 0.1em;\n  width: 0.8em;\n  height: 0.8em;\n  border-radius: 0.8em;\n  border-width: 2px;\n  border-style: solid;\n  border-color: white;\n  border-image: initial;\n  box-sizing: border-box;\n}\n.tm-jav-item .play-btn::after {\n  border-width: 0.3em 0 0.3em 0.4em;\n  top: 0.2em;\n  left: 0.35em;\n  content: \"\";\n  position: absolute;\n  border-style: solid;\n  border-color: transparent white;\n  border-image: initial;\n}\n.tm-jav-item .play-btn:hover::before {\n  border-color: #ffa04c;\n}\n.tm-jav-item .play-btn:hover::after {\n  border-color: transparent #ffa04c;\n}\n.tm-jav-item:hover .play-btn {\n  bottom: 4px;\n}\n.tm-jav-item:hover .tm-jav-item {\n  box-shadow: rgba(45, 45, 45, 0.05) 0px 2px 2px 0px rgba(42, 42, 42, 0.05) 0px 8px 8px 0px, rgba(32, 32, 32, 0.05) 0px 16px 16px 0px, rgba(49, 49, 49, 0.05) 0px 32px 32px 0px, rgba(35, 35, 35, 0.05) 0px 64px 64px 0px;\n}\n.tm-jav-item:hover .tm-jav-item--inner {\n  transform: scale(1.08);\n  transform-origin: center center;\n}\n.tm-jav-item:hover .tm-jav-item--cover {\n  filter: blur(2px);\n}\n.tm-jav-item:hover .tm-jav-item--info {\n  position: absolute;\n  top: 0;\n  left: 0;\n  height: 100%;\n}\n","<template>\r\n  <div class=\"tm-jav-item\">\r\n    <div class=\"tm-jav-item--inner\">\r\n      <img class=\"tm-jav-item--cover\" :src=\"video.image\" :alt=\"video.title\" width=\"100%\">\r\n      <div class=\"play-btn\" @click=\"showPreview\"></div>\r\n      <div class=\"tm-jav-item--info\">\r\n        <span class=\"tm-jav-item--avid\">{{video.avid}}</span>\r\n        <a class=\"tm-jav-item--title\" target=\"_blank\" :href=\"video.href\" :title=\"video.title\">{{video.title}}</a>\r\n      </div>\r\n    </div>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n  props: {\r\n    video: {\r\n      type: Object,\r\n      default: null\r\n    }\r\n  },\r\n  methods: {\r\n    showPreview () {\r\n      this.$emit('show-preview')\r\n    }\r\n  }\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"less\">\r\n.tm-jav-item {\r\n  min-height: 200px;\r\n  min-width: 147px;\r\n  padding: 8px;\r\n  display: inline-block;\r\n  overflow: hidden;\r\n  position: relative;\r\n\r\n  &--cover {\r\n    max-height: 200px;\r\n    max-height: 300px;\r\n    object-fit: cover;\r\n  }\r\n\r\n  &--inner {\r\n    width: 100%;\r\n    height: 100%;\r\n    position: relative;\r\n  }\r\n\r\n  &--info {\r\n    color: #fff;\r\n    text-shadow: 1px 1px 2px black;\r\n    transition: all 0.5s;\r\n    position: absolute;\r\n    z-index: 1;\r\n    left: 0;\r\n    top: 70%;\r\n    height: 30%;\r\n    display: block;\r\n    background-color: rgba(32, 32, 32, 0.3);\r\n    width: 100%;\r\n    overflow: hidden;\r\n  }\r\n\r\n  &--title {\r\n    color: #fff;\r\n  }\r\n  .play-btn {\r\n    transition: all 0.5s;\r\n    position: absolute;\r\n    bottom: 30%;\r\n    left: 0px;\r\n    width: 1em;\r\n    height: 1em;\r\n    border-radius: 1em;\r\n    font-size: 30px;\r\n    cursor: pointer;\r\n    z-index: 2;\r\n    background-color: rgba(32, 32, 32, 0.3);\r\n\r\n    &::before {\r\n      content: '';\r\n      position: absolute;\r\n      left: 0.1em;\r\n      top: 0.1em;\r\n      width: 0.8em;\r\n      height: .8em;\r\n      border-radius: 0.8em;\r\n      border-width: 2px;\r\n      border-style: solid;\r\n      border-color: white;\r\n      border-image: initial;\r\n      box-sizing: border-box;\r\n    }\r\n    &::after {\r\n      border-width: .3em 0 .3em .4em;\r\n      top: .2em;\r\n      left: .35em;\r\n      content: \"\";\r\n      position: absolute;\r\n      border-style: solid;\r\n      border-color: transparent white;\r\n      border-image: initial;\r\n    }\r\n    &:hover{\r\n      &::before {\r\n        border-color: #ffa04c;\r\n      }\r\n      &::after {\r\n        border-color: transparent #ffa04c;\r\n      }\r\n    }\r\n  }\r\n\r\n  &:hover .play-btn {\r\n    bottom: 4px;\r\n  }\r\n\r\n  &:hover & {\r\n    box-shadow: rgba(45, 45, 45, 0.05) 0px 2px 2px 0px\r\n    rgba(42, 42, 42, 0.05) 0px 8px 8px 0px, \r\n    rgba(32, 32, 32, 0.05) 0px 16px 16px 0px,\r\n    rgba(49, 49, 49, 0.05) 0px 32px 32px 0px,\r\n    rgba(35, 35, 35, 0.05) 0px 64px 64px 0px;\r\n\r\n    &--inner {\r\n      transform: scale(1.08);\r\n      transform-origin: center center;\r\n    }\r\n    &--cover {\r\n      filter: blur(2px);\r\n    }\r\n    &--info { \r\n      position: absolute;\r\n      top: 0;\r\n      left: 0;\r\n      height: 100%;\r\n    }\r\n  }\r\n\r\n}\r\n</style>"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$2 = "data-v-54e5faad";
    /* module identifier */
    const __vue_module_identifier__$2 = undefined;
    /* functional template */
    const __vue_is_functional_template__$2 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$2 = normalizeComponent(
      { render: __vue_render__$2, staticRenderFns: __vue_staticRenderFns__$2 },
      __vue_inject_styles__$2,
      __vue_script__$2,
      __vue_scope_id__$2,
      __vue_is_functional_template__$2,
      __vue_module_identifier__$2,
      false,
      createInjector,
      undefined,
      undefined
    );

  /**
   * 确保 ref 元素已经挂载
   * 
   * @param {Vue} vm 
   * @param {string} ref 
   * @param {number} timeout 
   */

  function throttle (func, wait, immediate) {
    let timeout;
    return function () {
      const context = this;
      const args = arguments;
      const later = function () {
        timeout = null;
        if (!immediate) {
          func.apply(context, args);
        }
      };
      const callNow = immediate && !timeout;
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
      if (callNow) {
        func.apply(context, args);
      }
    }
  }

  function remove (arr, item) {
    if (arr.length) {
      const index = arr.indexOf(item);
      if (index > -1) {
        return arr.splice(index, 1)
      }
    }
  }

  function createLRUCache (LRUStore) {
    return function LRUCache (key, content = null) {
      const {keys, cache, max} = LRUStore;
      function pushKey () {
        remove(keys, key);
        keys.push(key);
      }
      if (content) {
        cache[key] = content;
        pushKey();
        if (max && keys.length > parseInt(max)) {
          const first = keys[0];
          cache[first] = null;
          remove(keys, first);
        }
      } else {
        pushKey();
        return cache[key]
      }
    }
  }

  function similarity(s1, s2, split = false) {
    function editDistance (s1, s2) {
      s1 = s1.toLowerCase();
      s2 = s2.toLowerCase();

      const costs = new Array();
      for (let i = 0; i <= s1.length; i++) {
        let lastValue = i;
        for (let j = 0; j <= s2.length; j++) {
          if (i === 0) {
            costs[j] = j;
          } else {
            if (j > 0) {
              var newValue = costs[j - 1];
              if (s1.charAt(i - 1) != s2.charAt(j - 1)) {
                newValue = Math.min(Math.min(newValue, lastValue), costs[j]) + 1;
              }
              costs[j - 1] = lastValue;
              lastValue = newValue;
            }
          }
        }
        if (i > 0) {
          costs[s2.length] = lastValue;
        }
      }
      return costs[s2.length];
    }

    function doSplitMode (s1, s2){ 
      let split1 = s1.split(' ');
      let split2 = s2.split(' ');
      let sum = 0; let max = 0; let temp = 0; 
      for(let i=0; i < split1.length;i++) { 
        max = 0; 
        for(let j=0; j < split2.length;j++) { 
          temp = genSimilarity(split1[i], split2[j]);
          if(max < temp) {
            max = temp;
          }     }
        sum += max / split1.length; 
      }
      return sum;
    }
    function genSimilarity (s1, s2) {
      let longer = s1;
      let shorter = s2;
      if (s1.length < s2.length) {
        longer = s2;
        shorter = s1;
      }
      const longerLength = longer.length;
      if (longerLength == 0) {
        return 1.0;
      }
      return (longerLength - editDistance(longer, shorter)) / parseFloat(longerLength);
    }

    if (split) {
      return doSplitMode(s1, s2)
    } else {
      return genSimilarity(s1, s2)
    }
  }

  function toMap (arr, key = 'id') {
    return arr.reduce((r, c) => {
      if (c[key]) {
        r[c[key]] = c;
      }
      return r
    }, {})
  }

  function isPlainObject (val) {
    return Object.prototype.toString.call(val) === '[object Object]'
  }

  function parseHtml (html) {
    const parser = new DOMParser();
    const doc = parser.parseFromString(html, "text/html");
    return doc
  }

  function fix503 (src) {
    let iframe = document.createElement('iframe');
    const timeout = 6000;
    const now = Date.now();
    return new Promise(function (resolve, reject) {
      function remove () {
        if (iframe) {
          document.body.removeChild(iframe);
          iframe = null;
        }
      }
      iframe.onload = (e) => {
        requestAnimationFrame(function check () {
          if (Date.now() - now > timeout ||
            (iframe && iframe.contentWindow.document.querySelector('#toplogo'))
          ) {
            remove();
            console.log('iframe:loaded');
            resolve(true);
          } else {
            requestAnimationFrame(check);
          }
        });
      };
      iframe.onerror = (e) => {
        remove();
        console.log('iframe:onerror', e);
        reject(false);
      };
      setTimeout(iframe.onerror, timeout, 'timeout');
      iframe.style="width:600px;height:400px;position:fixed;left: -999999999px;top: 0;z-index: 100";
      document.body.insertBefore(iframe, document.body.firstChild);
      iframe.src = src;
    })
  }

  function get (url, options = {}) {
    return new Promise(function (resolve, reject) {
      GM_xmlhttpRequest({
        url,
        method: 'GET',
        ...options,
        onload: (e) => {
          if (e.status === 200) {
            resolve(e);
          } else {
            console.log('reject', e.status);
            reject(e);
          }
        },
        onerror: (e) => {
          reject(e);
        }
      });
    }).catch((e) => {
      if (e.status === 503) {
        return fix503(url).then(() => get(url, options))
      }
      return Promise.reject(e)
    })
  }

  function getHTML (url, options = {parse: true}) {
    const {parse} = options;
    let request = get(url, {responseType: 'text'}).then((r) => r.responseText, (e) => Promise.reject(e));

    if (parse) {
      return request.then((html) => {
        return parseHtml(html)
      }, (e) => {
        return Promise.reject(e)
      })
    }

    return request
  }

  function post (url, data = {}, options = {}) {
    return new Promise(function (resolve, reject) {
      GM_xmlhttpRequest({
        url,
        method: 'POST',
        data,
        responseType: 'json',
        ...options,
        onload: (e) => {
          if (e.status === 200) {
            resolve(e);
          } else {
            reject(e);
          }
        },
        onerror: (e) => {
          reject(e);
        }
      });
    })
  }

  var Http = {
    install (Vue) {
      Vue.prototype.$getHTML = getHTML;
      Vue.prototype.$get = get;
    }
  };

  const map = {
    star: {
      url: '/ajax/ajax_favoriteadd_star.php',
      type: 4
    }
  };

  function addFav (id, _type) {
    const {url, type} = map[_type];
    return post(url, {id, type}).then((res) => {
      console.log(res.response);
      if (res.response.ERROR === -1) {
        return Promise.reject('already fav')
      }
      return res.response
    })
  }

  function fillListUrl (id, type) {
    const fChar = type[0];
    const url = `vl_${type}.php?${fChar}=${id}`;
    return url
  }

  const ListCacheStore = {
    keys: [],
    cache: {},
    max: 10
  };

  const ListLRUCache = createLRUCache(ListCacheStore);

  const logVue = new Vue({
    data: {
      logs: []
    }
  });
  function log (task) {
    let startTime = Date.now();
    function getPassTime () {
      const currTime = Date.now();
      const pass = currTime - startTime;
      return pass
    }

    const logTask = {
      name: task,
      logs: [],
      finished: false,
      status: '',
    };
    logVue.logs.push(logTask);
    logVue.$emit('log-task', logTask);

    function logStep (status, msg, name) {
      logTask.logs.push({name, msg, status, after: getPassTime()});
      console.log(`[${name}][${status}]:${msg}`);
    }
    
    return {
      msg (msg) {
        logStep('default', msg);
      },
      success (...args) {
        logStep('success', ...args);
      },
      fail (...args) {
        logStep('fail', ...args);
      },
      end (status) {
        logTask.finished = true;
        logTask.status = status;
        logStep('finished', '任务' + (status === 'success' ? '成功' : '失败'), task);
      }
    }
  }

  function parseStep (step) {
    const fns = [];
    const objs = [];
    const strs = [];
    for (const item of step) {
      if (typeof item === 'function' || item instanceof Promise) {
        fns.push(item);
      }
      if (typeof item === 'string') {
        strs.push(item);
      }
      if (isPlainObject(item)) {
        objs.push(item);
      }
    }
    const [exec] = fns;
    const [options] = objs;
    const [name = '操作', resolve = 'next', reject = 'exit'] = strs;

    return {
      name, exec, options,
      resolve, reject
    }
  }

  async function runTask (taskName, ...steps) {
    const logTask = log(taskName);
    let finishedStatus = 'fail';
    let result;
    if (isPlainObject(steps[0])) {
      result = steps[0];
      steps.shift();
    }
    while (steps.length) {
      const step = steps.shift();
      const { name, exec, resolve, reject } = parseStep(step);

      try {
        logTask.msg(`开始执行步骤: ${name}`);
        const promise = exec instanceof Promise ? exec : ( isPlainObject(exec) ? Promise.resolve(exec) : exec(result, logTask) );
        result = await promise;
        logTask.success('执行成功!');
        if (resolve === 'pass') {
          logTask.end('success');
          return Promise.resolve(result)
        }
        // next
        finishedStatus = 'success';
      } catch (e) {
        logTask.fail(e.status || e.message || '执行失败! ', name);
        if (reject === 'exit') {
          logTask.end('fail');
          return Promise.reject(e)
        }
        result = e;
        finishedStatus = 'fail';
        // next
      }
    }
    logTask.end(finishedStatus);
    return finishedStatus === 'success' ? Promise.resolve(result) : Promise.reject(result)
  }

  function queryVideoList (href) {
    function firstStep () {
      const requestPromise = location.pathname === href ?
      Promise.resolve(document) : 
      getHTML(href);
      return requestPromise
    }

    return runTask(
      '查询列表信息',
      ['加载 HTML', firstStep],
      ['解析切页信息', parseNextPage],
      ['解析列表信息', parseList],
    ).catch((e) => {
      return Promise.reject(e)
    })
  }

  function genDefaultPages () {
    return {
      show: false,
      inLast: false,
      length: 0,
      curr: 1,
      list: [],
      last: 0,
      next: 0,
    }
  }

  function parseNextPage (doc) {
    const pageSelector = doc.querySelector('.page_selector');
    let defaultPages = genDefaultPages();
    if (pageSelector && pageSelector.children) {
      defaultPages = [...pageSelector.children].reduce((pages, page) => {
        const {className, innerHTML: p} = page;
        if (/^page(\scurrent|$)/.test(className)) {
          pages.list.push(p);
          if (className === 'page current') {
            pages.curr = p;
          }
          pages.length++;
        }
        if (className === 'page last') {
          pages.last = page.href && page.href.replace(/.*?page=/, '');
        }
        if (className === 'page next') {
          pages.next = page.href && page.href.replace(/.*?page=/, '');
        }
        return pages
      }, defaultPages);
    }
    defaultPages.inLast = defaultPages.curr === defaultPages.last;
    return {doc, pages: defaultPages}
  }

  const videoReg = /<div class="video".*?<a\shref="(.*?)".*?<div\sclass="id">(.*?)<.*?src="(.*?)".*?class="title.*?>(.*?)<\/div/;
  function parseList (payload) {
    const {doc} = payload;
    const list = [...(doc.querySelectorAll('.video'))]
    .map((vEl) => {
      const video = vEl.outerHTML.match(videoReg);
      const [, href, avid, image, title] = video;
      const [prefix, number] = avid.split('-');
      const id = href.replace('./?v=javli', '');
      return {
        id, href, avid, image, title, prefix, number,
        infos: null, favorite: null, previewId: null,
        loaded: {preview: false, detail: false},
        images: null,
        error: ''}
    });
    return {...payload, list}
  }

  const VERSION = 2;
  const DB_NAME = 'tm-jav';
  const TABLE_DEF = [
    [/** empty version 0 */],
    [ // version 1
      { name: 'genres', key: 'id', cols: ['name', 'type'] }
    ],
    [  // version 2
      { name: 'genres', key: 'id', cols: ['name', 'type'] },
      { name: 'stars', key: 'id', cols: ['name']},
      { name: 'templates', key: 'prefix', cols: ['template']},
      { name: 'details', key: 'id', cols: [
        'genres', 'stars', 
        'date', 'duration', 'director', 'maker', 'label',
        'score', 'subscribed', 'watched', 'owned',
        'updatedTime'
      ]},
      { name: 'previews', key: 'id', cols: ['previewId', 'previewCode']} // 0: none match, 1: google match, 2: snapshot match, 4: add zero match, 8: remove zero match
    ]
  ];

  var config = {
    VERSION,
    DB_NAME,
    TABLE_DEF,
  };

  function DB () {
    this.errorCode = '';
    this.db = null;
  }

  const proto = DB.prototype;

  proto.setup = function (dbName, version, ...tableDefs) {
    this.dbName = dbName;
    const request = window.indexedDB.open(dbName, version);
    return new Promise((resolve, reject) => {
      request.onerror = (ev) => {
        this.errorCode = ev.errorCode;
        reject(this);
      };

      request.onsuccess = (ev) => {
        this.db = ev.target.result;
        resolve(this);
      };

      request.onupgradeneeded = (ev) => {
        this.db = ev.target.result;
        this._defTable(tableDefs).then(() => {
          resolve(this);
        }, (ev) => {
          this.errorCode = ev.errorCode;
          reject(this);
        });
      };
    })
  };

  proto.transaction = function (tables, mode = 'readonly') {
    const transaction = this.db.transaction(tables, mode);
    const gTable = (table) => new Table(table, this.db, transaction);

    return function runTransaction (handler) {
      return handler(gTable)
    }
  };

  proto._defTable = function (tables) {
    const existTables = [...this.db.objectStoreNames].reduce((r, c) => { r[c] = true; return r; }, {});
    const allTableTransaction = [];
    for (const table of tables) {
      const {name, key: keyPath, indexes} = table;
      if (existTables[name]) {
        continue
      }
      const objectStore = this.db.createObjectStore(name, { keyPath });

      for (const index of (indexes || [])) {
        objectStore.createIndex(index, index, { unique: false });
      }
      
      allTableTransaction.push(
        new Promise((resolve, reject) => {
          objectStore.transaction.onsuccess = resolve;
          objectStore.transaction.onerror = reject;
        })
      );
    }
    return Promise.all(allTableTransaction)
  };

  proto._removeTable = function (name, existTables) {
    if (!existTables[name]) {
      return
    }

    this.db.deleteObjectStore(name);
  };


  proto.table = function (name) {
    return new Table(name, this.db)
  };

  // ------------ Table ------------

  function Table (name, db, transaction = null) {
    this.name = name;
    this.db = db;
    this._transaction = transaction;
  }

  Table.prototype.get = function (id) {
    return this._asyncExec(id ? 'get' : 'getAll', id)
  };

  Table.prototype.getAll = function () {
    return this.get()
  };

  Table.prototype.add = function (records) {
    return this._batchExec(records, 'add')
  };

  Table.prototype.put = function (records) {
    return this._batchExec(records, 'put')
  };

  Table.prototype.delete = function (records) {
    return this._batchExec(records, 'delete')
  };

  Table.prototype._batchExec = function (records, method = 'add') {
    if (!Array.isArray(records)) {
      records = [records];
    }
    const allRecord = [];
    for (let record of records) {
      allRecord.push(
        this._asyncExec(method, record)
      );
    }
    return Promise.all(allRecord)
  };

  Table.prototype._transactionFn = function (method) {
    let objectStore;
    if (this._transaction) {
      objectStore = this._transaction.objectStore(this.name);
    } else {
      const mode = method.startsWith('get') ? 'readonly' : 'readwrite';
      objectStore = this.db.transaction(this.name, mode).objectStore(this.name);
    }
    return objectStore[method].bind(objectStore)
  };

  Table.prototype._asyncExec = function (method, ...args) {
    return new Promise ((resolve, reject) => {
      const requestFn = this._transactionFn(method);

      if (typeof requestFn !== 'function') {
        reject(`method ${method} is Illegal invocation`);
      } else {
        const request = requestFn(...args);
        request.onsuccess = function (event) {
          resolve(event.target.result);
        };
        request.onerror = function (event) {
          reject(event);
        };
      }
    })
  };

  let dbInstance = null;
  async function getDBInstance () {
    if (dbInstance) {
      return dbInstance
    }
    const {VERSION, DB_NAME, TABLE_DEF} = config;
    const table = TABLE_DEF[VERSION];

    dbInstance = new DB();
    try {
      await dbInstance.setup(DB_NAME, VERSION, ...table);
      return dbInstance
    } catch (e) {
      console.error(e);
    }
  }

  function avDetailResolution (video, htmlDom) {
    const firstArg = htmlDom ? {htmlDom} : (video instanceof Document ? {htmlDom: video} : ['加载 HTML', loadHTML(video.href)]);
    return runTask(
      '解析 AV 相关信息',
      firstArg,
      ['解析基本信息', parseAvInfo],
      ['解析投票信息', parseFavorite],
      ['解析图片预览信息', parseImagePreview],
    ).catch((e) => {
      return Promise.reject(e)
    })
  }

  function loadHTML (href) {
    return getHTML(href)
    .then((htmlDom) => {
      return {htmlDom}
    })
  }

  function parseFavorite (payload) {
    const el = payload.htmlDom.querySelector('#video_favorite_edit');
    
    if (!el) {return payload}
    const subscribed = (el.querySelector('#subscribed a') || {}).textContent; // 我想要
    const watched = (el.querySelector('#watched a') || {}).textContent;    // 我看过
    const owned = (el.querySelector('#owned a') || {}).textContent;      // 我拥有
    return {...payload, favorite: {subscribed, watched, owned}}
  }

  function parseAvInfo (payload) {
    const el = payload.htmlDom.querySelector('#video_info');
    if (!el) {return payload}
    const dateEl = el.querySelector('#video_date .text') || {};
    const date = dateEl.textContent || '';

    const durationEl = el.querySelector('#video_length .text') || {};
    const duration = durationEl.textContent || ''; // 分钟

    const director = genObjInfo(el, 'director');
    const maker = genObjInfo(el, 'maker');
    const label = genObjInfo(el, 'label');

    const scoreEl = el.querySelector('#video_review .text .score') || {};
    const score = scoreEl.textContent || '';

    const genres = genObjInfo(el, 'genre', true);
    const stars = genObjInfo(el, 'star', true, 'cast');

    return {...payload, infos: {date, duration, director, maker, label, score, genres, stars}}
  }

  function genObjInfo (wrapper, type, array = false, idSlt = '') {
    const fChar = type[0];
    const pageReg = new RegExp(`.*vl_${type}\\.php\\?${fChar}=`);
    if (!idSlt) { idSlt = type + (array ? 's' : ''); }
    const selector = `#video_${idSlt} .text a`;
    const els = wrapper.querySelectorAll(selector);
    const result = [...els].map(el => {
      return {
        id: el.href.replace(pageReg, ''),
        name: el.textContent,
      }
    });
    
    return !array && result.length === 1 ? result[0] : result
  }

  function parseImagePreview (payload) {
    const el = payload.htmlDom.querySelectorAll('.previewthumbs > img');
    if (!el || !el.length) {
      payload = {...payload, images: null};
    }
    const result = el[0] && el[0].src.match(/\/([^\/]+?)-(\d+)\.(.*)$/);
    if (result) {
      payload = {...payload, images: {previewId: result[1], ext: result[3], count: el.length}};
    }
    return payload
  }

  function parseBaseInfo (dom) {
    if (!dom instanceof Document) {
      return dom
    }
    const avid = dom.querySelector('#video_id tr td.text').innerText;
    const imgSrc = dom.querySelector('#video_jacket img').src;
    const image = imgSrc.replace(/https?:/, '').replace('pl', 'ps');
    const [prefix, number] = avid.split('-');
    const aLink = dom.querySelector('#video_title h3 a');
    const title = aLink.innerText;
    const href = aLink.href;
    const id = href.replace('./?v=javli', '');

    return {
      id, href, avid, image, title, prefix, number,
      infos: null, favorite: null, previewId: null,
      loaded: {preview: false, detail: false},
      images: null,
      error: ''
    }
  }

  const PREVIEW_CODE = {
    NONE: 0,
    TEMPLATE: 1,
    TEMPLATE_ZERO: 2,
    GOOGLE: 3,
    GOOGLE_ZERO: 4,
    SNAPSHOT: 5,
    SNAPSHOT_ZERO: 6,
    INFO_IMAGE: 7,
  };


  const urlPrefix = location.protocol + '//cc3001.dmm.co.jp/litevideo/freepv/';

  const urlPostfix = ['_mhb_w', '_dmb_w', '_dm_w', '_sm_w'];
  function genSources (previewId) {
    previewId = previewId.replace(/(((\w)\w\w).*)/, '$3/$2/$1/$1');
    return urlPostfix.map(pf => urlPrefix + previewId + pf + '.mp4')
  }

  function getCid (str) {
    return str.replace(/([\s\S]+cid=)(\w+)(\/)/, '$2')
  }
  function getGoogleSearchUrl (avid) {
    const url = `https://www.google.com/search?hl=zh-CN&q=site:https://www.dmm.co.jp+${avid}`;
    return url
  }

  function prepareGoogleSearch (video) {
    const {avid} = video;
    const searchUrl = getGoogleSearchUrl(avid);
    return getHTML(searchUrl).then((dom) => {
      return {dom, searchUrl, video}
    })
  }

  function getSimilarity (s1, s2) {
    const front = s1.slice(0, 15) === s2.slice(0, 15);
    if (front) {
      return 1
    }
    let titleSimilarity = similarity(s1, s2);
    if (titleSimilarity < 0.5) {
      titleSimilarity = similarity(s1, s2, true /* split mode */);
    }

    return titleSimilarity
  }
  function parseGoogleResult (payload, log) {
    const {dom, searchUrl, video} = payload;
    const searched = dom.querySelector('#search');
    let snapshotLink = null;
    if (!searched || !searched.children.length) {
      return Promise.reject(new Error(`not found 'Element #search' in result of '${searchUrl}'`))
    }

    let firstALinks = searched.querySelectorAll('#rso .g .r > a:first-child');
    if (!firstALinks.length) {
      // 确保能匹配到
      firstALinks = searched.querySelectorAll('#rso .g a[href^="https://www.dmm"]:first-child');
    }
    const avTitle = video.title;
    log.msg(`开始匹配标题 '${avTitle}', URL: '${searchUrl}'`);
    let previewId = null;
    for (const firstALink of [...firstALinks]) {
      const link = firstALink.pathname;
      const titleEl = firstALink.querySelector('h3');
      const resultTitle = (titleEl ? titleEl.innerText : '').replace('アダルトDVD・ブルーレイ', '');
      const titleSimilarity = getSimilarity(avTitle, resultTitle);
      if (titleSimilarity < 0.5) {
        log.msg(`标题【不】匹配: '${resultTitle}', 相似度: ${titleSimilarity}`);
        continue
      }
      log.msg(`标题【匹配】: '${resultTitle}', 相似度: ${titleSimilarity}`);
      snapshotLink = firstALink.nextElementSibling.querySelector('.action-menu-item.ab_dropdownitem a');
      snapshotLink = snapshotLink && snapshotLink.href;
      previewId = getCid(link);
      break
    }
    if (previewId) {
      return {previewId, video, snapshotLink}
    }
    return Promise.reject(new Error(`解析失败, URL: '${searchUrl}'`))
  }

  function genPreloadTest (previewCode, video) {
    function genZeroId (prevId) {
      let nextId = '';
      const reg = new RegExp(`.*${video.prefix}(0+?)${video.number}`, 'i');
      const zero = prevId.replace(reg, (m, m1) => m1);
      if (zero !== prevId) {
        nextId = prevId.replace(zero, '');
      } else {
        const addZero = `00000${video.number}`.slice(-5);
        nextId = prevId.replace(video.number, addZero);
      }
      return nextId
    }
    return function preloadTest (payload, log) {
      let {previewId} = payload || {};
      if (!previewId) {
        return Promise.reject({...payload, error: new Error(`EMPTY previewId`)})
      }
      if (
        [
          PREVIEW_CODE.GOOGLE_ZERO, 
          PREVIEW_CODE.SNAPSHOT_ZERO,
          // for kum prefix
          PREVIEW_CODE.INFO_IMAGE
        ]
        .includes(previewCode)
      ) {
        previewId = genZeroId(previewId);
      }
      const path = previewId.replace(/(((\w)\w\w).*)/, '$3/$2/$1/$1');
      const url = urlPrefix + path + '_sm_w.mp4';
      log.msg(`尝试加载 url ... : ${url}`);
      return get(url).then(() => {
        return {previewId, previewCode}
      }, (error) => {
        return Promise.reject({...payload, error})
      })
    }
  }

  function parseFromSnapshot (payload) {
    const { snapshotLink } = payload;
    return getHTML(snapshotLink).then((dom) => {
      const link = dom.body.querySelector('.area-edition .edition:not(.limited)');
      const previewId = link ? getCid(link.pathname) : '';
      return {...payload, previewId}
    })
  }

  function preivewResolution (video, infoPromise) {
    if (video.previewId) {
      return Promise.resolve(video.previewId)
    }

    let templateStep = [];
    if (video.template) {
      templateStep = [
        {previewId: video.template},
        ['测试TEMPLATE预览ID', genPreloadTest(PREVIEW_CODE.TEMPLATE, video), 'pass', 'next'],
        ['测试TEMPLATE_ZERO预览ID', genPreloadTest(PREVIEW_CODE.TEMPLATE_ZERO, video), 'pass', 'next'],
      ];
    }

    const infoStep = [
      ['from information1', infoPromise, 'next', 'next'],
      ['from information2', (video) => Promise.resolve(video.images)],
      ['测试information image ID', genPreloadTest(PREVIEW_CODE.INFO_IMAGE, video), 'pass', 'next'],
    ];

    return runTask(
      '解析预览ID',
      ...templateStep,
      ...infoStep,
      ['谷歌搜索', prepareGoogleSearch(video)],
      ['解析HTML', parseGoogleResult],
      ['测试GOOGLE预览ID', genPreloadTest(PREVIEW_CODE.GOOGLE, video), 'pass', 'next'],
      ['测试GOOGLE_ZERO预览ID', genPreloadTest(PREVIEW_CODE.GOOGLE_ZERO, video), 'pass', 'next'],
      ['快照查找', parseFromSnapshot],
      ['测试SNAPSHOT预览ID', genPreloadTest(PREVIEW_CODE.SNAPSHOT, video), 'pass', 'next'],
      ['测试SNAPSHOT_ZERO预览ID', genPreloadTest(PREVIEW_CODE.SNAPSHOT_ZERO, video), 'pass', 'next'],
    ).catch((e) => {
      return Promise.reject(e)
    })
  }

  class Model {
    constructor (name, keyPath = 'id') {
      this.name = name;
      this.init = false;
      this.keyPath = keyPath;
      this.dataIdMap = {};
    }

    async put (datas) {
      if (!Array.isArray(datas)) {
        datas = [datas];
      }
      datas = datas.map(d => {
        const keyValue = d[this.keyPath];
        if (keyValue && this.dataIdMap[keyValue]) {
          d = {...this.dataIdMap[keyValue], ...d};
        }
        return d
      });
      const idb = await getDBInstance();
      await idb.table(this.name).put(datas);

      for (const data of datas) {
        this.dataIdMap[data[this.keyPath]] = data;
      }
    }

    async getAll () {
      const idb = await getDBInstance();
      let datas = await idb.table(this.name).get();
    
      if (datas && datas.length) {
        this.dataIdMap = toMap(datas, this.keyPath);
      } else {
        datas = await this.getFromRemote();
        await this.put(datas);
      }
      
      this.init = true;
      return this.processData(datas)
    }

    async getFromRemote () {
      return []
    }

    processData (d) {
      return d
    }

    async getMap () {
      if (!this.init) {
        await this.getAll();
      } 
      return this.dataIdMap
    }
  }

  class StarsModel extends Model {
    constructor () {
      super('stars');
    }
  }

  var starsModel = new StarsModel();

  const Config = {
    NAME: 'genres',
    URL: 'genres.php',
  };

  function parseGenres (dom) {
    const nodes = [...dom.querySelectorAll('.textbox')];
    return nodes.reduce((list, node) => {
        const type = node.firstElementChild.innerText;
        const genres = [...node.querySelectorAll('.genreitem a')]
        .map((a) => {
          return {
            id: a.href.replace(location.origin + '/cn/vl_genre.php?g=', ''),
            name: a.innerText,
            type,
          }
        });
        list = list.concat(genres);
        return list
    }, [])
  }

  class GenresModel extends Model {
    constructor () {
      super('genres');
    }
    
    async getFromRemote () {
      return getHTML(Config.URL)
      .then((dom) => {
        const genres = parseGenres(dom.body);
        return genres
      })
    }

    processData (genres) {
      const treeObj = genres.reduce((tree, genre) => {
        const {id, name, type = 'TM-JAV-NEW'} = genre;
        if (!tree[type]) {
          tree[type] = {type, genres: []};
        }
        tree[type].genres.push({id, name});
        return tree
      }, {});
    
      return Object.keys(treeObj).map(k => treeObj[k])
    }
  }

  var genresModel = new GenresModel();

  class TemplatesModel extends Model {
    constructor () {
      super('templates', 'prefix');
    }
  }

  var templatesModel = new TemplatesModel();

  const Details = {
    NAME: 'details',
  };

  async function getVideoDetail (video, dom) {
    const idb = await getDBInstance();
    let details = await idb.table(Details.NAME).get(video.id);

    if (!details || !details.images) {
      const {infos, favorite, images} = await avDetailResolution(video, dom);
      starsModel.put(infos.stars);
      genresModel.put(infos.genres);
      const genres = infos.genres.map(g => g.id);
      const stars = infos.stars.map(s => s.id);
      const putData = {...infos, ...favorite, genres, stars, id: video.id, images};
      await idb.table(Details.NAME).put(putData);
      details = {infos, favorite, images};
    } else {
      const genresMap = await genresModel.getMap();
      const genres = details.genres.map(g => genresMap[g]);
      const starsMap = await starsModel.getMap();
      const stars = details.stars.map(s => starsMap[s]);
      const favorite = genObjectFromKeys(details, ['score', 'subscribed', 'watched', 'owned', 'updatedTime']);
      const infos = {
        stars,
        genres,
        ...genObjectFromKeys(details, ['date', 'duration', 'director', 'maker', 'label'])
      };
      details = {infos, favorite, images: details.images};
    }
    return details
  }

  function genObjectFromKeys (obj, keys) {
    return keys.reduce((result, k) => {
      result[k] = obj[k];
      return result
    }, {})
  }

  const Previews = {
    NAME: 'previews',
  };
  async function getVideoPreview (video, infoPromise, force = false) {
    const idb = await getDBInstance();
    let preview = await idb.table(Previews.NAME).get(video.id);

    if (force && preview) {
      preview.previewId = undefined;
    }
    if (preview && preview.previewId) {
      return preview.previewId
    }

    if (!force) {
      const templatesMap = await templatesModel.getMap();
      const template = (templatesMap[video.prefix] && templatesMap[video.prefix].template) || '';
      video.template = template.replace('{}', video.number);
    }
    const payload = await preivewResolution(video, infoPromise);
    const {previewCode, previewId} = payload;
    if (previewId) {
      const newTemplate = previewId.replace(video.number, '{}');
      templatesModel.put({prefix: video.prefix, template: newTemplate});
      await idb.table(Previews.NAME).put({id: video.id, previewCode, previewId});
    }

    return previewId
  }

  //
  var script$3 = {
    components: {
      TmItem: __vue_component__$2
    },
    data () {
      return {
        list: [],
        loading: false,
        fillError: false,
        ddos: {
          status: false,
          currTime: 5,
          maxTime: 5,
          timer: null
        },
        pages: genDefaultPages()
      }
    },
    props: {
      tab: {
        default: null
      },
    },
    computed: {
      hasNext () {
        return this.tab && this.tab.next !== false && !this.pages.show && this.pages.next
      }
    },
    watch: {
      tab: {
        immediate: true,
        handler (val, old) {
          if (old) {
            this.cacheTab(old);
          }
          if (val) {
            this.onTabChange(val, old);
          }
        }
      }
    },
    methods: {
      inDDoS () {
        if (this.ddos.timer) {
          return true
        }
        this.ddos.status = document.title === 'Just a moment...';
        if (this.ddos.status) {
          this.ddos.currTime = this.ddos.maxTime;

          this.ddos.timer = setInterval(() => {
            this.ddos.currTime--;
            if (!this.ddos.currTime) {
              clearInterval(this.ddos.timer);
              this.ddos.timer = null;
              location.reload();
            }
          }, 1000);
        }
        return this.ddos.status // cf_clearance
      },
      switchLoadMode () {
        const status = !this.pages.show;
        if (status) {
          const url = this.genPageUrl(this.pages.curr);
          this.getContent(url, status);
        } else {
          this.pages.curr = 1;
          this.getContent(this.tab.href);
        }
        
        this.pages.show = status;
      },
      onTabChange (tab, old) {
        const cached = ListLRUCache(tab.href);
        if (cached && cached.list.length) {
          this.list = cached.list;
          this.pages = cached.pages;
        } else if (!this.inDDoS()) {
          this.getContent(tab.href);
          this.pages.curr = 1;
        }
        
        if (this.$refs['scroll-wrapper']) {
          this.$refs['scroll-wrapper'].scrollTop = cached ? cached.scrollTop : 0;
        }
      },
      cacheTab (tab) {
        if (!this.list.length) {return}
        const scroll = this.$refs['scroll-wrapper'];
        ListLRUCache(tab.href, {
          list: this.list,
          pages: this.pages,
          scrollTop: scroll && scroll.scrollTop,
        });
      },
      getContent (href, pageStatus = false) {
        this.loading = true;
        this.list = [];
        queryVideoList(href)
        .then(({list, pages}) => {
          this.list = list;
          this.pages = pages;
          this.pages.show = pageStatus;
          this.fillList();
        }, () => {
          this.list = [];
        }).finally(() => {
          this.loading = false;
        });
      },
      genPageUrl (page = 0) {
        if (!page) {page = ++this.pages.curr;}
        const hasQ = /\?/.test(this.tab.href);
        const url = this.tab.href + `${hasQ ? '&' : '?'}page=${page}`;
        return url
      },
      toPage (p) {
        const url = this.genPageUrl(p);
        this.getContent(url, true);
      },
      queryNext () {
        const url = this.genPageUrl();
        return queryVideoList(url)
        .then(({list, pages}) => {
          this.pages = pages;
          this.list = this.list.concat(list);
          this.fillList();
        }).finally(() => {
          this.loading = false;
        })
      },
      fillList () {
        if (!this.hasNext) {
          return
        }
        this.$nextTick()
        .then(() => {
          if (!this.fillError && this.isScrollEnd()) {
            this.queryNext().catch(() => {
              this.fillError = true;
            });
          }
        });
      },
      showPreview (video) {
        const i = getVideoDetail(video);
        i.then(({infos, favorite, images}) => {
          video.infos = infos; 
          video.favorite = favorite;
          video.images = images;
          video.loaded.detail = true;
          this.$emit('select', video);
          return video
        }).catch((e) => {
          console.log('加载失败:', e);
          video.loaded.detail = false;
        });
        video.error = '';
        const s = getVideoPreview(video, i).then((previewId) => {
          if (previewId) {
            video.previewId = previewId;
            video.loaded.preview = true;
            this.$emit('select', video);
          } else {
            video.error = '加载失败,请查看日志';
          }
        }).catch((e) => {
          console.log('加载失败:', e);
          video.error = '加载失败,请查看日志';
        });
        
        this.$emit('select', video);
        Promise.all([s, i]).then(() => {
          console.log(video);
        });
      },
      isScrollEnd () {
        const t = this.$refs['scroll-wrapper'];
        if (!t) {return false}
        return t.scrollHeight - t.clientHeight - 20 < t.scrollTop
      },
      onScroll: throttle(function (e) {
        if (!this.hasNext || e.deltaY < 0) {
          return false
        }

        if (this.isScrollEnd() && !this.loading) {
          this.loading = true;
          this.queryNext();
        }
      }, 16)
    }
  };

  /* script */
  const __vue_script__$3 = script$3;

  /* template */
  var __vue_render__$3 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("div", { staticClass: "tm-jav-list" }, [
      _vm.ddos.status
        ? _c("div", { staticClass: "tm-jav-list--ddos" }, [
            _vm._m(0),
            _vm._v(" "),
            _c("h1", [_vm._v(_vm._s(_vm.ddos.currTime) + "秒 ... ")]),
            _vm._v(" "),
            _c("h1", [_vm._v("javlibrary.com 正在进行 DDoS 防护")]),
            _vm._v(" "),
            _c("h4", [
              _vm._v(
                "此为自运行程序,最长不超过5秒,你的浏览器会自动加载 javlibrary.com 内容"
              )
            ]),
            _vm._v(" "),
            _c("h4", [_vm._v("如果没有跳转,请自行刷新")])
          ])
        : _c(
            "div",
            {
              ref: "scroll-wrapper",
              staticClass: "tm-jav-list--wrapper",
              on: {
                scroll: function($event) {
                  $event.stopPropagation();
                },
                mousewheel: _vm.onScroll
              }
            },
            [
              _c(
                "div",
                { staticClass: "tm-jav-list--scroll" },
                _vm._l(_vm.list, function(video) {
                  return _c("tm-item", {
                    key: video.href,
                    attrs: { video: video },
                    on: {
                      "show-preview": function($event) {
                        return _vm.showPreview(video)
                      }
                    }
                  })
                }),
                1
              ),
              _vm._v(" "),
              _c(
                "div",
                {
                  directives: [
                    {
                      name: "show",
                      rawName: "v-show",
                      value: _vm.loading,
                      expression: "loading"
                    }
                  ],
                  staticClass: "tm-jav-list--loading",
                  class: { "tm-jav-list--loading-pages": _vm.pages.show }
                },
                [_vm._m(1)]
              )
            ]
          ),
      _vm._v(" "),
      _c(
        "div",
        {
          directives: [
            {
              name: "show",
              rawName: "v-show",
              value: _vm.pages.length,
              expression: "pages.length"
            }
          ],
          staticClass: "tm-jav-list--switch"
        },
        [
          _c("span", { staticClass: "tm-jav-list--switch-default" }, [
            _vm._v("当前为" + _vm._s(_vm.pages.show ? "切页" : "滚动") + "模式")
          ]),
          _vm._v(" "),
          _c(
            "span",
            {
              staticClass: "tm-jav-list--switch-hover",
              on: { click: _vm.switchLoadMode }
            },
            [
              _vm._v(
                "点击切换为" + _vm._s(_vm.pages.show ? "滚动" : "切页") + "模式"
              )
            ]
          )
        ]
      ),
      _vm._v(" "),
      _vm.pages.length && _vm.pages.show
        ? _c(
            "div",
            { staticClass: "tm-jav-list--pages" },
            [
              _vm.pages.list[0] != 1
                ? _c(
                    "i",
                    {
                      staticClass: "tm-jav--tag",
                      on: {
                        click: function($event) {
                          return _vm.toPage(1)
                        }
                      }
                    },
                    [_vm._v("第一页")]
                  )
                : _vm._e(),
              _vm._v(" "),
              _vm._l(_vm.pages.list, function(p) {
                return _c(
                  "i",
                  {
                    staticClass: "tm-jav--tag",
                    class: { "tm-jav--current": p == _vm.pages.curr },
                    on: {
                      click: function($event) {
                        return _vm.toPage(p)
                      }
                    }
                  },
                  [_vm._v(_vm._s(p))]
                )
              }),
              _vm._v(" "),
              _vm.pages.last
                ? _c(
                    "i",
                    {
                      staticClass: "tm-jav--tag",
                      on: {
                        click: function($event) {
                          return _vm.toPage(_vm.pages.last)
                        }
                      }
                    },
                    [_vm._v("最后一页")]
                  )
                : _vm._e()
            ],
            2
          )
        : _vm._e()
    ])
  };
  var __vue_staticRenderFns__$3 = [
    function() {
      var _vm = this;
      var _h = _vm.$createElement;
      var _c = _vm._self._c || _h;
      return _c("div", { staticClass: "tm-jav--loading-wrapper" }, [
        _c("i", { staticClass: "tm-jav--loading" })
      ])
    },
    function() {
      var _vm = this;
      var _h = _vm.$createElement;
      var _c = _vm._self._c || _h;
      return _c("div", { staticClass: "tm-jav--loading-wrapper" }, [
        _c("div", { staticClass: "tm-jav--loading" })
      ])
    }
  ];
  __vue_render__$3._withStripped = true;

    /* style */
    const __vue_inject_styles__$3 = function (inject) {
      if (!inject) return
      inject("data-v-7ee52296_0", { source: ".tm-jav-list[data-v-7ee52296] {\n  background-color: #ffc4ec;\n  border-radius: 4px;\n  padding: 15px 4px;\n  height: 100%;\n  font-size: 12px;\n  position: relative;\n}\n.tm-jav-list--switch[data-v-7ee52296] {\n  display: inline-block;\n  position: absolute;\n  right: 30px;\n  top: 0px;\n  height: 20px;\n  background-color: rgba(0, 0, 0, 0.3);\n  color: #fff;\n  padding: 2px;\n}\n.tm-jav-list--switch-default[data-v-7ee52296] {\n  display: inline-block;\n}\n.tm-jav-list--switch-hover[data-v-7ee52296] {\n  display: none;\n}\n.tm-jav-list--switch:hover .tm-jav-list--switch-hover[data-v-7ee52296] {\n  display: inline-block;\n  cursor: pointer;\n}\n.tm-jav-list--switch:hover .tm-jav-list--switch-default[data-v-7ee52296] {\n  display: none;\n}\n.tm-jav-list--pages[data-v-7ee52296] {\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.tm-jav-list--ddos[data-v-7ee52296] {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n.tm-jav-list--wrapper[data-v-7ee52296] {\n  padding: 0 4px;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n.tm-jav-list--wrapper[data-v-7ee52296]:hover {\n  overflow: auto;\n  padding-right: 0;\n}\n.tm-jav-list--scroll[data-v-7ee52296] {\n  display: flex;\n  flex-wrap: wrap;\n  align-content: flex-start;\n}\n.tm-jav-list--scroll[data-v-7ee52296]::after {\n  content: '';\n  flex: 9999999;\n}\n.tm-jav-list--scroll .tm-jav-item[data-v-7ee52296] {\n  flex-grow: 1;\n}\n.tm-jav-list--loading-pages[data-v-7ee52296] {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  left: 0;\n  top: 0;\n  z-index: 5;\n  background-color: rgba(0, 0, 0, 0.1);\n}\n", map: {"version":3,"sources":["list.vue"],"names":[],"mappings":"AAAA;EACE,yBAAyB;EACzB,kBAAkB;EAClB,iBAAiB;EACjB,YAAY;EACZ,eAAe;EACf,kBAAkB;AACpB;AACA;EACE,qBAAqB;EACrB,kBAAkB;EAClB,WAAW;EACX,QAAQ;EACR,YAAY;EACZ,oCAAoC;EACpC,WAAW;EACX,YAAY;AACd;AACA;EACE,qBAAqB;AACvB;AACA;EACE,aAAa;AACf;AACA;EACE,qBAAqB;EACrB,eAAe;AACjB;AACA;EACE,aAAa;AACf;AACA;EACE,kBAAkB;EAClB,OAAO;EACP,MAAM;AACR;AACA;EACE,WAAW;EACX,YAAY;EACZ,aAAa;EACb,uBAAuB;EACvB,mBAAmB;EACnB,sBAAsB;AACxB;AACA;EACE,cAAc;EACd,WAAW;EACX,YAAY;EACZ,gBAAgB;AAClB;AACA;EACE,cAAc;EACd,gBAAgB;AAClB;AACA;EACE,aAAa;EACb,eAAe;EACf,yBAAyB;AAC3B;AACA;EACE,WAAW;EACX,aAAa;AACf;AACA;EACE,YAAY;AACd;AACA;EACE,WAAW;EACX,YAAY;EACZ,kBAAkB;EAClB,OAAO;EACP,MAAM;EACN,UAAU;EACV,oCAAoC;AACtC","file":"list.vue","sourcesContent":[".tm-jav-list {\n  background-color: #ffc4ec;\n  border-radius: 4px;\n  padding: 15px 4px;\n  height: 100%;\n  font-size: 12px;\n  position: relative;\n}\n.tm-jav-list--switch {\n  display: inline-block;\n  position: absolute;\n  right: 30px;\n  top: 0px;\n  height: 20px;\n  background-color: rgba(0, 0, 0, 0.3);\n  color: #fff;\n  padding: 2px;\n}\n.tm-jav-list--switch-default {\n  display: inline-block;\n}\n.tm-jav-list--switch-hover {\n  display: none;\n}\n.tm-jav-list--switch:hover .tm-jav-list--switch-hover {\n  display: inline-block;\n  cursor: pointer;\n}\n.tm-jav-list--switch:hover .tm-jav-list--switch-default {\n  display: none;\n}\n.tm-jav-list--pages {\n  position: absolute;\n  left: 0;\n  top: 0;\n}\n.tm-jav-list--ddos {\n  width: 100%;\n  height: 100%;\n  display: flex;\n  justify-content: center;\n  align-items: center;\n  flex-direction: column;\n}\n.tm-jav-list--wrapper {\n  padding: 0 4px;\n  width: 100%;\n  height: 100%;\n  overflow: hidden;\n}\n.tm-jav-list--wrapper:hover {\n  overflow: auto;\n  padding-right: 0;\n}\n.tm-jav-list--scroll {\n  display: flex;\n  flex-wrap: wrap;\n  align-content: flex-start;\n}\n.tm-jav-list--scroll::after {\n  content: '';\n  flex: 9999999;\n}\n.tm-jav-list--scroll .tm-jav-item {\n  flex-grow: 1;\n}\n.tm-jav-list--loading-pages {\n  width: 100%;\n  height: 100%;\n  position: absolute;\n  left: 0;\n  top: 0;\n  z-index: 5;\n  background-color: rgba(0, 0, 0, 0.1);\n}\n"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$3 = "data-v-7ee52296";
    /* module identifier */
    const __vue_module_identifier__$3 = undefined;
    /* functional template */
    const __vue_is_functional_template__$3 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$3 = normalizeComponent(
      { render: __vue_render__$3, staticRenderFns: __vue_staticRenderFns__$3 },
      __vue_inject_styles__$3,
      __vue_script__$3,
      __vue_scope_id__$3,
      __vue_is_functional_template__$3,
      __vue_module_identifier__$3,
      false,
      createInjector,
      undefined,
      undefined
    );

  function torrentkittyDetail (path) {
    path = path.replace(/^\//, '');
    const href = 'https://www.torrentkitty.tv/search/' + path;
    return getHTML(href).then((doc) => {
      const detail = doc.querySelector('.detailSummary');
      const innerText = detail && detail.innerText || '';
    
      const size = innerText.match(/Content Size:\s+(.*)?\n/);
      // const count = innerText.match(/Number of Files:\s+(.*)?\n/)
      const created = innerText.match(/Created On:\s+(.*)?\n/);
    
      const torrentDetail = [...(doc.querySelectorAll('#torrentDetail tbody td.name') || [])];
      const files = torrentDetail.map(td => td.innerText);
      return {size, files, created}
    })
  }

  const parserFn = {
    torrentkitty (doc) {
      const actionList = [...(doc.querySelectorAll('tr td.action') || [])];
      return actionList.filter(td => td.children.length).map(td => {
        const detail = td.children[0];
        const open = td.children[1];
        return {
          magnet: open.href,
          title: open.title,
          detail: null,
          detailUrl: detail.href,
          detailParser: torrentkittyDetail
        }
      })
    },
  };

  function getTorrentList (avid, engine = 'torrentkitty') {
    const href = 'https://www.torrentkitty.tv/search/' + avid;
    const parser = parserFn[engine];

    return runTask(
      '查询Torrent信息',
      ['加载 HTML', getHTML(href)],
      ['解析Torrent信息', parser],
    ).catch((e) => {
      window.open(href);
      return Promise.reject(e)
    })
  }

  //
  function g (o, k) {
    return o && o[k] || ''
  }
  var script$4 = {
    props: {
      video: {
        type: Object,
        default: null,
        largeImage: true
      }
    },
    data () {
      return {
        showImages: false,
        torrents: [],
        showTorrent: false
      }
    },
    computed: {
      inDDos: {
        cache: false,
        get () {
          return document.title === 'Just a moment...'
        }
      },
      autoplay () {
        return !this.inDDos && this.$root.options.autoplay
      },
      muted () {
        return this.$root.options.muted
      },
      images () {
        const imgs = this.video && this.video.images || {};
        const count = imgs.count || 0;
        const id = imgs.previewId;
        return Array(count).fill(1).map((v, i) => `//pics.dmm.co.jp/digital/video/${id}/${id}-${i + 1}.jpg`)
      },
      sources () {
        return !this.video || !this.video.previewId ? [] : genSources(this.video.previewId)
      },
      loading () {
        return !this.video || !this.video.loaded.preview
      },
      loadingDetail () {
        return !this.video || !this.video.loaded.detail
      },
      infos () {
        return g(this.video, 'infos')
      },
      favorite () {
        return g(this.video, 'favorite') 
      },
      title () {
        return g(this.video, 'title') 
      },
      image () {
        // const id = (this.avid || '').replace('-', '').toLowerCase()
        // return `//pics.dmm.co.jp/mono/movie/adult/${id}/${id}p${this.largeImage ? 'l' : 's'}.jpg`
        return g(this.video, 'image').replace('ps', 'pl')
      },
      avid () {
        return g(this.video, 'avid')
      }
    },
    methods: {
      onVideoError (e) {
        console.log(e);
      },
      favStar (id) {
        addFav(id, 'star');
      },
      showAvList (target, type) {
        this.$root.pushTab({
          href: fillListUrl(target.id, type),
          name: target.name
        });
      },
      searchSamePrefix () {
        const {prefix} = this.video;
        this.$root.pushTab({
          href: `vl_searchbyid.php?keyword=${prefix}`,
          name: prefix.toUpperCase()
        });
      },
      loadTorrent () {
        this.showTorrent = !this.showTorrent;
        if (!this.showTorrent) {
          return
        }
        getTorrentList(this.avid).then((d) => {
          this.torrents = d;
        }, e => {
          console.error(e);
          this.showTorrent = false;
        });
      },
      reloadVideo () {
        console.log(this.video);
        const video = JSON.parse(JSON.stringify(this.video));
        if (!video) {
          return
        }
        video.previewId = undefined;
        video.template = undefined;
        getVideoPreview(video, Promise.resolve({}), true /** force */)
        .then((previewId) => {
          if (previewId) {
            video.previewId = previewId;
            video.loaded.preview = true;
            this.$emit('select', video);
          } else {
            video.error = '加载失败,请查看日志';
          }
        }).catch((e) => {
          console.log('加载失败:', e);
          video.error = '加载失败,请查看日志';
        });
      }
    }
  };

  /* script */
  const __vue_script__$4 = script$4;

  /* template */
  var __vue_render__$4 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("div", { staticClass: "tm-jav-preview" }, [
      _vm.images.length
        ? _c(
            "span",
            {
              staticClass: "tm-jav-preview--images-trigger",
              on: {
                click: function($event) {
                  _vm.showImages = !_vm.showImages;
                }
              }
            },
            [_vm._v("图")]
          )
        : _vm._e(),
      _vm._v(" "),
      _vm.showImages
        ? _c(
            "div",
            { staticClass: "tm-jav-preview--images" },
            _vm._l(_vm.images, function(src) {
              return _c("img", { key: src, attrs: { src: src, alt: "" } })
            }),
            0
          )
        : _vm._e(),
      _vm._v(" "),
      _c("div", { staticClass: "tm-jav-player" }, [
        _c(
          "video",
          {
            key: _vm.avid,
            ref: "video",
            attrs: { controls: "", autoplay: _vm.autoplay, preload: "true" },
            domProps: { muted: _vm.muted }
          },
          _vm._l(_vm.sources, function(source, index) {
            return _c("source", {
              key: source,
              attrs: { src: source },
              on: {
                error: function($event) {
                  return _vm.onVideoError($event, index)
                }
              }
            })
          }),
          0
        ),
        _vm._v(" "),
        _vm.video && _vm.video.error
          ? _c("div", { staticClass: "tm-jav--loading-wrapper" }, [
              _vm._v("\n        " + _vm._s(_vm.video.error) + "\n      ")
            ])
          : _vm.loading
          ? _c("div", { staticClass: "tm-jav--loading-wrapper" }, [
              _c("i", { staticClass: "tm-jav--loading" })
            ])
          : _vm._e()
      ]),
      _vm._v(" "),
      _c("div", { staticClass: "tm-jav-information" }, [
        _c(
          "div",
          {
            directives: [
              {
                name: "show",
                rawName: "v-show",
                value: _vm.loadingDetail,
                expression: "loadingDetail"
              }
            ],
            staticClass: "tm-jav--loading-wrapper"
          },
          [_c("i", { staticClass: "tm-jav--loading" })]
        ),
        _vm._v(" "),
        _c("div", { staticClass: "tm-jav--torrent" }, [
          _c(
            "span",
            {
              staticClass: "tm-jav--torrent-btn",
              on: { click: _vm.loadTorrent }
            },
            [_vm._v("磁力搜索")]
          ),
          _vm._v(" "),
          _c(
            "div",
            {
              directives: [
                {
                  name: "show",
                  rawName: "v-show",
                  value: _vm.showTorrent,
                  expression: "showTorrent"
                }
              ],
              staticClass: "tm-jav--torrent-list"
            },
            [
              _c(
                "span",
                {
                  directives: [
                    {
                      name: "show",
                      rawName: "v-show",
                      value: !_vm.torrents.length,
                      expression: "!torrents.length"
                    }
                  ]
                },
                [_vm._v("搜索中...")]
              ),
              _vm._v(" "),
              _vm._l(_vm.torrents, function(t) {
                return _c("div", { staticClass: "tm-jav--torrent-item" }, [
                  _c(
                    "a",
                    {
                      staticClass: "tm-jav--torrent-item-title",
                      attrs: { href: t.magnet }
                    },
                    [_vm._v(_vm._s(t.title))]
                  )
                ])
              })
            ],
            2
          )
        ]),
        _vm._v(" "),
        _c("i", {
          staticClass: "tm-jav--close",
          on: {
            click: function($event) {
              return _vm.$emit("close")
            }
          }
        }),
        _vm._v(" "),
        _c("div", { staticClass: "tm-jav-information--cover" }, [
          _vm.image
            ? _c("img", { attrs: { src: _vm.image, alt: "cover" } })
            : _vm._e()
        ]),
        _vm._v(" "),
        _vm.infos
          ? _c("div", { staticClass: "tm-jav-infos" }, [
              _c("div", { staticClass: "tm-jav-infos--row" }, [
                _c(
                  "span",
                  {
                    staticClass: "tm-jav--tag",
                    on: { click: _vm.searchSamePrefix }
                  },
                  [_vm._v(_vm._s(_vm.avid))]
                ),
                _vm._v(" "),
                _c(
                  "a",
                  {
                    staticClass: "tm-jav-infos--title",
                    attrs: { target: "_blank", href: _vm.video && _vm.video.href }
                  },
                  [_vm._v(_vm._s(_vm.title))]
                )
              ]),
              _vm._v(" "),
              _c(
                "div",
                { staticClass: "tm-jav-infos--row" },
                _vm._l(_vm.infos.stars, function(star) {
                  return _c(
                    "span",
                    {
                      staticClass: "tm-jav--tag",
                      on: {
                        click: function($event) {
                          return _vm.showAvList(star, "star")
                        }
                      }
                    },
                    [_c("span", [_vm._v(_vm._s(star.name))])]
                  )
                }),
                0
              ),
              _vm._v(" "),
              _c(
                "div",
                { staticClass: "tm-jav-infos--row" },
                _vm._l(_vm.infos.genres, function(genre) {
                  return _c(
                    "span",
                    {
                      staticClass: "tm-jav--tag",
                      on: {
                        click: function($event) {
                          return _vm.showAvList(genre, "genre")
                        }
                      }
                    },
                    [_vm._v(_vm._s(genre.name))]
                  )
                }),
                0
              ),
              _vm._v(" "),
              _c("div", { staticClass: "tm-jav-infos--row" }, [
                _c("span", { staticClass: "tm-jav--tag" }, [
                  _vm._v(_vm._s(_vm.infos.date))
                ]),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "评分" } },
                  [_vm._v(_vm._s(_vm.favorite.score || "--") + "分")]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "想看的" } },
                  [_vm._v(_vm._s(_vm.favorite.subscribed))]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "看过的" } },
                  [_vm._v(_vm._s(_vm.favorite.watched))]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "拥有的" } },
                  [_vm._v(_vm._s(_vm.favorite.owned))]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "导演" } },
                  [_vm._v(_vm._s(_vm.infos.director.name || "--"))]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "制作商" } },
                  [_vm._v(_vm._s(_vm.infos.maker.name || "--"))]
                ),
                _vm._v(" "),
                _c(
                  "span",
                  { staticClass: "tm-jav--tag", attrs: { title: "发行商" } },
                  [_vm._v(_vm._s(_vm.infos.label.name || "--"))]
                )
              ]),
              _vm._v(" "),
              _c("div", { staticClass: "tm-jav-infos--row" }, [
                _c(
                  "span",
                  {
                    staticClass: "tm-jav--torrent-btn",
                    on: { click: _vm.reloadVideo }
                  },
                  [_vm._v("刷新信息")]
                )
              ])
            ])
          : _vm._e()
      ])
    ])
  };
  var __vue_staticRenderFns__$4 = [];
  __vue_render__$4._withStripped = true;

    /* style */
    const __vue_inject_styles__$4 = function (inject) {
      if (!inject) return
      inject("data-v-7ac117aa_0", { source: ".tm-jav-preview[data-v-7ac117aa] {\n  overflow: auto;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  margin-right: 10px;\n  padding-right: 10px;\n  position: relative;\n  padding: 0 10px;\n}\n.tm-jav-preview--images-trigger[data-v-7ac117aa] {\n  z-index: 10;\n  position: absolute;\n  left: 0px;\n  top: 0;\n  padding: 3px 4px;\n  border-radius: 50%;\n  cursor: pointer;\n  color: #fff;\n  background-color: #ee4dba;\n}\n.tm-jav-preview--images[data-v-7ac117aa] {\n  z-index: 10;\n  position: absolute;\n  right: 0px;\n  top: 30px;\n}\n.tm-jav-preview .tm-jav--torrent[data-v-7ac117aa] {\n  position: absolute;\n  right: 40px;\n  top: 10px;\n  z-index: 4;\n  display: inline-block;\n}\n.tm-jav-preview .tm-jav--torrent-btn[data-v-7ac117aa] {\n  padding: 4px;\n  border-radius: 4px;\n  background-color: #000;\n  color: #fff;\n  cursor: pointer;\n}\n.tm-jav-preview .tm-jav--torrent-list[data-v-7ac117aa] {\n  position: absolute;\n  right: 0;\n  bottom: 24px;\n  background-color: #fff;\n  padding: 10px;\n  border-radius: 10px;\n  width: 250px;\n}\n.tm-jav-preview .tm-jav--close[data-v-7ac117aa] {\n  position: absolute;\n  right: 3px;\n  top: 3px;\n  z-index: 4;\n  font-size: 30px;\n  background-color: #ee4dba;\n}\n.tm-jav-preview .tm-jav-player[data-v-7ac117aa] {\n  width: 100%;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-player video[data-v-7ac117aa] {\n  width: 100%;\n}\n.tm-jav-preview .tm-jav-information[data-v-7ac117aa] {\n  padding: 10px;\n  flex: 1;\n  display: flex;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-information--cover[data-v-7ac117aa] {\n  width: 225px;\n}\n.tm-jav-preview .tm-jav-information--cover img[data-v-7ac117aa] {\n  width: 225px;\n  margin-right: 10px;\n  transition: transform 0.5s;\n  transform-origin: bottom left;\n  z-index: 5;\n}\n.tm-jav-preview .tm-jav-information--cover img[data-v-7ac117aa]:hover {\n  position: relative;\n  bottom: 0;\n  left: 0;\n  transform-origin: bottom left;\n  transform: scale(3);\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos[data-v-7ac117aa] {\n  flex: 1;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos--row[data-v-7ac117aa] {\n  margin-bottom: 4px;\n  border-bottom: 1px solid rgba(119, 119, 119, 0.3);\n  padding-bottom: 4px;\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos--title[data-v-7ac117aa] {\n  color: rgba(0, 0, 0, 0.65);\n}\n", map: {"version":3,"sources":["preview.vue"],"names":[],"mappings":"AAAA;EACE,cAAc;EACd,aAAa;EACb,sBAAsB;EACtB,WAAW;EACX,kBAAkB;EAClB,mBAAmB;EACnB,kBAAkB;EAClB,eAAe;AACjB;AACA;EACE,WAAW;EACX,kBAAkB;EAClB,SAAS;EACT,MAAM;EACN,gBAAgB;EAChB,kBAAkB;EAClB,eAAe;EACf,WAAW;EACX,yBAAyB;AAC3B;AACA;EACE,WAAW;EACX,kBAAkB;EAClB,UAAU;EACV,SAAS;AACX;AACA;EACE,kBAAkB;EAClB,WAAW;EACX,SAAS;EACT,UAAU;EACV,qBAAqB;AACvB;AACA;EACE,YAAY;EACZ,kBAAkB;EAClB,sBAAsB;EACtB,WAAW;EACX,eAAe;AACjB;AACA;EACE,kBAAkB;EAClB,QAAQ;EACR,YAAY;EACZ,sBAAsB;EACtB,aAAa;EACb,mBAAmB;EACnB,YAAY;AACd;AACA;EACE,kBAAkB;EAClB,UAAU;EACV,QAAQ;EACR,UAAU;EACV,eAAe;EACf,yBAAyB;AAC3B;AACA;EACE,WAAW;EACX,kBAAkB;AACpB;AACA;EACE,WAAW;AACb;AACA;EACE,aAAa;EACb,OAAO;EACP,aAAa;EACb,kBAAkB;AACpB;AACA;EACE,YAAY;AACd;AACA;EACE,YAAY;EACZ,kBAAkB;EAClB,0BAA0B;EAC1B,6BAA6B;EAC7B,UAAU;AACZ;AACA;EACE,kBAAkB;EAClB,SAAS;EACT,OAAO;EACP,6BAA6B;EAC7B,mBAAmB;AACrB;AACA;EACE,OAAO;EACP,kBAAkB;AACpB;AACA;EACE,kBAAkB;EAClB,iDAAiD;EACjD,mBAAmB;AACrB;AACA;EACE,0BAA0B;AAC5B","file":"preview.vue","sourcesContent":[".tm-jav-preview {\n  overflow: auto;\n  display: flex;\n  flex-direction: column;\n  width: 100%;\n  margin-right: 10px;\n  padding-right: 10px;\n  position: relative;\n  padding: 0 10px;\n}\n.tm-jav-preview--images-trigger {\n  z-index: 10;\n  position: absolute;\n  left: 0px;\n  top: 0;\n  padding: 3px 4px;\n  border-radius: 50%;\n  cursor: pointer;\n  color: #fff;\n  background-color: #ee4dba;\n}\n.tm-jav-preview--images {\n  z-index: 10;\n  position: absolute;\n  right: 0px;\n  top: 30px;\n}\n.tm-jav-preview .tm-jav--torrent {\n  position: absolute;\n  right: 40px;\n  top: 10px;\n  z-index: 4;\n  display: inline-block;\n}\n.tm-jav-preview .tm-jav--torrent-btn {\n  padding: 4px;\n  border-radius: 4px;\n  background-color: #000;\n  color: #fff;\n  cursor: pointer;\n}\n.tm-jav-preview .tm-jav--torrent-list {\n  position: absolute;\n  right: 0;\n  bottom: 24px;\n  background-color: #fff;\n  padding: 10px;\n  border-radius: 10px;\n  width: 250px;\n}\n.tm-jav-preview .tm-jav--close {\n  position: absolute;\n  right: 3px;\n  top: 3px;\n  z-index: 4;\n  font-size: 30px;\n  background-color: #ee4dba;\n}\n.tm-jav-preview .tm-jav-player {\n  width: 100%;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-player video {\n  width: 100%;\n}\n.tm-jav-preview .tm-jav-information {\n  padding: 10px;\n  flex: 1;\n  display: flex;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-information--cover {\n  width: 225px;\n}\n.tm-jav-preview .tm-jav-information--cover img {\n  width: 225px;\n  margin-right: 10px;\n  transition: transform 0.5s;\n  transform-origin: bottom left;\n  z-index: 5;\n}\n.tm-jav-preview .tm-jav-information--cover img:hover {\n  position: relative;\n  bottom: 0;\n  left: 0;\n  transform-origin: bottom left;\n  transform: scale(3);\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos {\n  flex: 1;\n  position: relative;\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos--row {\n  margin-bottom: 4px;\n  border-bottom: 1px solid rgba(119, 119, 119, 0.3);\n  padding-bottom: 4px;\n}\n.tm-jav-preview .tm-jav-information .tm-jav-infos--title {\n  color: rgba(0, 0, 0, 0.65);\n}\n"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$4 = "data-v-7ac117aa";
    /* module identifier */
    const __vue_module_identifier__$4 = undefined;
    /* functional template */
    const __vue_is_functional_template__$4 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$4 = normalizeComponent(
      { render: __vue_render__$4, staticRenderFns: __vue_staticRenderFns__$4 },
      __vue_inject_styles__$4,
      __vue_script__$4,
      __vue_scope_id__$4,
      __vue_is_functional_template__$4,
      __vue_module_identifier__$4,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  var script$5 = {
    data () {
      return {
        value: ''
      }
    },
    methods: {
      doSearch () {
        if (this.value) {
          const url = `${location.origin}/cn/vl_searchbyid.php?keyword=${this.value}`;
          this.$get(url).then((res) => {
            const html = parseHtml(res.responseText);
            if (res.finalUrl === url) {
              this.toTab(html, this.value);
            } else {
              this.parseDetail(html, res.finalUrl);
            }
          });
          
        }
      },
      toTab (html, name) {
        this.$root.pushTab({
          href: `vl_searchbyid.php?keyword=${name}`,
          name,
        });
      },
      parseDetail (dom) {
        const video = parseBaseInfo(dom);
        const i = getVideoDetail(video, dom);
        i.then(({infos, favorite, images}) => {
          video.infos = infos; 
          video.favorite = favorite;
          video.images = images;
          video.loaded.detail = true;
          this.$emit('select', video);
          return video
        }).catch((e) => {
          console.log('加载失败:', e);
          video.loaded.detail = false;
        });
        video.error = '';
        const s = getVideoPreview(video, i).then((previewId) => {
          if (previewId) {
            video.previewId = previewId;
            video.loaded.preview = true;
            this.$emit('select', video);
          } else {
            video.error = '加载失败,请查看日志';
          }
        }).catch((e) => {
          console.log('加载失败:', e);
          video.error = '加载失败,请查看日志';
        });
        
        this.$emit('select', video);
        Promise.all([s, i]).then(() => {
          console.log(video);
        });
      },
    },
  };

  /* script */
  const __vue_script__$5 = script$5;

  /* template */
  var __vue_render__$5 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("div", { staticClass: "tm-jav-search" }, [
      _c("input", {
        directives: [
          {
            name: "model",
            rawName: "v-model",
            value: _vm.value,
            expression: "value"
          }
        ],
        attrs: { type: "text" },
        domProps: { value: _vm.value },
        on: {
          keyup: function($event) {
            if (
              !$event.type.indexOf("key") &&
              _vm._k($event.keyCode, "enter", 13, $event.key, "Enter")
            ) {
              return null
            }
            return _vm.doSearch($event)
          },
          input: function($event) {
            if ($event.target.composing) {
              return
            }
            _vm.value = $event.target.value;
          }
        }
      }),
      _vm._v(" "),
      _c("button", { on: { click: _vm.doSearch } }, [_vm._v("搜索")])
    ])
  };
  var __vue_staticRenderFns__$5 = [];
  __vue_render__$5._withStripped = true;

    /* style */
    const __vue_inject_styles__$5 = function (inject) {
      if (!inject) return
      inject("data-v-1ae02dbc_0", { source: "\n.tm-jav-search {\r\n  display: inline-block;\n}\r\n", map: {"version":3,"sources":["D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\search.vue"],"names":[],"mappings":";AA4EA;EACA,qBAAA;AACA","file":"search.vue","sourcesContent":["<template>\r\n  <div class=\"tm-jav-search\">\r\n    <input type=\"text\" v-model=\"value\" @keyup.enter=\"doSearch\">\r\n    <button @click=\"doSearch\">搜索</button>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nimport { parseHtml } from '@/utils/functions'\r\nimport { getVideoDetail, getVideoPreview } from '@/api/videos'\r\nimport { parseBaseInfo } from '@/utils/av-info-resolution'\r\nexport default {\r\n  data () {\r\n    return {\r\n      value: ''\r\n    }\r\n  },\r\n  methods: {\r\n    doSearch () {\r\n      if (this.value) {\r\n        const url = `${location.origin}/cn/vl_searchbyid.php?keyword=${this.value}`\r\n        this.$get(url).then((res) => {\r\n          const html = parseHtml(res.responseText)\r\n          if (res.finalUrl === url) {\r\n            this.toTab(html, this.value)\r\n          } else {\r\n            this.parseDetail(html, res.finalUrl)\r\n          }\r\n        })\r\n        \r\n      }\r\n    },\r\n    toTab (html, name) {\r\n      this.$root.pushTab({\r\n        href: `vl_searchbyid.php?keyword=${name}`,\r\n        name,\r\n      })\r\n    },\r\n    parseDetail (dom) {\r\n      const video = parseBaseInfo(dom)\r\n      const i = getVideoDetail(video, dom)\r\n      i.then(({infos, favorite, images}) => {\r\n        video.infos = infos \r\n        video.favorite = favorite\r\n        video.images = images\r\n        video.loaded.detail = true\r\n        this.$emit('select', video)\r\n        return video\r\n      }).catch((e) => {\r\n        console.log('加载失败:', e)\r\n        video.loaded.detail = false\r\n      })\r\n      video.error = ''\r\n      const s = getVideoPreview(video, i).then((previewId) => {\r\n        if (previewId) {\r\n          video.previewId = previewId\r\n          video.loaded.preview = true\r\n          this.$emit('select', video)\r\n        } else {\r\n          video.error = '加载失败,请查看日志'\r\n        }\r\n      }).catch((e) => {\r\n        console.log('加载失败:', e)\r\n        video.error = '加载失败,请查看日志'\r\n      })\r\n      \r\n      this.$emit('select', video)\r\n      Promise.all([s, i]).then(() => {\r\n        console.log(video)\r\n      })\r\n    },\r\n  },\r\n}\r\n</script>\r\n\r\n<style>\r\n.tm-jav-search {\r\n  display: inline-block;\r\n}\r\n</style>"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$5 = undefined;
    /* module identifier */
    const __vue_module_identifier__$5 = undefined;
    /* functional template */
    const __vue_is_functional_template__$5 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$5 = normalizeComponent(
      { render: __vue_render__$5, staticRenderFns: __vue_staticRenderFns__$5 },
      __vue_inject_styles__$5,
      __vue_script__$5,
      __vue_scope_id__$5,
      __vue_is_functional_template__$5,
      __vue_module_identifier__$5,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  //
  //
  //
  //
  //
  //
  //
  //
  //

  var script$6 = {
    data () {
      return {
        scrollLeft: 0
      }
    },
    props: {
      tabs: {
        default () {return []}
      },
      currIndex: {
        default: 0
      }
    },
    methods: {
      scroll (e) {
        this.scrollLeft += e.deltaY / 10;
        this.$el.scrollLeft = this.scrollLeft;
      }
    }
  };

  /* script */
  const __vue_script__$6 = script$6;

  /* template */
  var __vue_render__$6 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      { staticClass: "tm-jav-tabs", on: { mousewheel: _vm.scroll } },
      _vm._l(_vm.tabs, function(tab, index) {
        return _c(
          "div",
          {
            key: tab.href,
            staticClass: "tm-jav-tabs--item",
            class: { curr: _vm.currIndex === index }
          },
          [
            _c(
              "span",
              {
                staticClass: "tm-jav-tabs--name",
                on: {
                  click: function($event) {
                    return _vm.$emit("active", index)
                  }
                }
              },
              [_vm._v(_vm._s(tab.name))]
            ),
            _vm._v(" "),
            !tab.fixed
              ? _c("span", {
                  staticClass: "tm-jav--close",
                  on: {
                    click: function($event) {
                      return _vm.$emit("remove", index)
                    }
                  }
                })
              : _vm._e()
          ]
        )
      }),
      0
    )
  };
  var __vue_staticRenderFns__$6 = [];
  __vue_render__$6._withStripped = true;

    /* style */
    const __vue_inject_styles__$6 = function (inject) {
      if (!inject) return
      inject("data-v-e9386a3a_0", { source: ".tm-jav-tabs {\n  width: 100%;\n  height: 20px;\n  background-color: #fff;\n  overflow-x: auto;\n  white-space: nowrap;\n  overflow-y: hidden;\n}\n.tm-jav-tabs::-webkit-scrollbar {\n  display: none;\n}\n.tm-jav-tabs--item {\n  display: inline-block;\n  align-items: center;\n  height: 20px;\n  min-width: 70px;\n  color: #fff;\n  background-color: #f282ce;\n  padding: 0 4px;\n  margin-right: 1px;\n  line-height: 20px;\n  cursor: pointer;\n}\n.tm-jav-tabs--item:hover {\n  background-color: #ff91dc;\n}\n.tm-jav-tabs--item.curr {\n  background-color: #ffc4ec;\n  color: #ff60cc;\n}\n.tm-jav-tabs--name {\n  text-overflow: ellipsis;\n  overflow: hidden;\n  width: 50px;\n  display: inline-block;\n  white-space: nowrap;\n}\n.tm-jav-tabs--window {\n  width: 16px;\n  height: 16px;\n  background: aquamarine;\n}\n.tm-jav-tabs .tm-jav--close {\n  font-size: 14px;\n  background-color: transparent;\n  top: -7px;\n}\n", map: {"version":3,"sources":["tabs.vue","D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\tabs.vue"],"names":[],"mappings":"AAAA;EACE,WAAW;EACX,YAAY;EACZ,sBAAsB;EACtB,gBAAgB;EAChB,mBAAmB;EACnB,kBAAkB;AACpB;AACA;EACE,aAAa;AACf;AACA;EACE,qBAAqB;EACrB,mBAAmB;EACnB,YAAY;EACZ,eAAe;EACf,WAAW;EACX,yBAAyB;EACzB,cAAc;EACd,iBAAiB;EACjB,iBAAiB;EACjB,eAAe;AACjB;AACA;EACE,yBAAyB;AAC3B;AACA;EACE,yBAAyB;EACzB,cAAc;AAChB;AACA;EACE,uBAAuB;EACvB,gBAAgB;EAChB,WAAW;EACX,qBAAqB;ECCvB,mBAAA;AACA;AACA;EACA,WAAA;EACA,YAAA;EACA,sBAAA;AACA;ADCA;ECCA,eAAA;EACA,6BAAA;EACA,SAAA;AACA","file":"tabs.vue","sourcesContent":[".tm-jav-tabs {\n  width: 100%;\n  height: 20px;\n  background-color: #fff;\n  overflow-x: auto;\n  white-space: nowrap;\n  overflow-y: hidden;\n}\n.tm-jav-tabs::-webkit-scrollbar {\n  display: none;\n}\n.tm-jav-tabs--item {\n  display: inline-block;\n  align-items: center;\n  height: 20px;\n  min-width: 70px;\n  color: #fff;\n  background-color: #f282ce;\n  padding: 0 4px;\n  margin-right: 1px;\n  line-height: 20px;\n  cursor: pointer;\n}\n.tm-jav-tabs--item:hover {\n  background-color: #ff91dc;\n}\n.tm-jav-tabs--item.curr {\n  background-color: #ffc4ec;\n  color: #ff60cc;\n}\n.tm-jav-tabs--name {\n  text-overflow: ellipsis;\n  overflow: hidden;\n  width: 50px;\n  display: inline-block;\n  white-space: nowrap;\n}\n.tm-jav-tabs--window {\n  width: 16px;\n  height: 16px;\n  background: aquamarine;\n}\n.tm-jav-tabs .tm-jav--close {\n  font-size: 14px;\n  background-color: transparent;\n  top: -7px;\n}\n","<template>\r\n  <div class=\"tm-jav-tabs\" @mousewheel=\"scroll\">\r\n    <div class=\"tm-jav-tabs--item\" :class=\"{curr: currIndex === index}\" v-for=\"(tab, index) in tabs\" :key=\"tab.href\">\r\n      <span class=\"tm-jav-tabs--name\" @click=\"$emit('active', index)\">{{tab.name}}</span>\r\n      <!-- <span class=\"tm-jav-tabs--window\" @click=\"$emit('float-tab', tab)\"></span> -->\r\n      <span class=\"tm-jav--close\" v-if=\"!tab.fixed\" @click=\"$emit('remove', index)\"></span>\r\n    </div>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nexport default {\r\n  data () {\r\n    return {\r\n      scrollLeft: 0\r\n    }\r\n  },\r\n  props: {\r\n    tabs: {\r\n      default () {return []}\r\n    },\r\n    currIndex: {\r\n      default: 0\r\n    }\r\n  },\r\n  methods: {\r\n    scroll (e) {\r\n      this.scrollLeft += e.deltaY / 10\r\n      this.$el.scrollLeft = this.scrollLeft\r\n    }\r\n  }\r\n}\r\n</script>\r\n\r\n<style lang=\"less\">\r\n.tm-jav-tabs {\r\n  width: 100%;\r\n  height: 20px;\r\n  background-color: #fff;\r\n  overflow-x: auto;\r\n  white-space: nowrap;\r\n  overflow-y: hidden;\r\n\r\n  &::-webkit-scrollbar {\r\n    display: none;\r\n  }\r\n  &--item {\r\n    display: inline-block;\r\n    align-items: center;\r\n    height: 20px;\r\n    min-width: 70px;\r\n    color: #fff;\r\n    background-color: #f282ce;\r\n    padding: 0 4px;\r\n    margin-right: 1px;\r\n    line-height: 20px;\r\n    cursor: pointer;\r\n\r\n    &:hover {\r\n      background-color: darken(#ffc4ec, 10%);\r\n    }   \r\n    &.curr {\r\n      background-color: #ffc4ec;\r\n      color: #ff60cc;\r\n    }\r\n  }\r\n\r\n  &--name {\r\n    text-overflow: ellipsis;\r\n    overflow: hidden;\r\n    width: 50px;\r\n    display: inline-block;\r\n    white-space: nowrap;\r\n  }\r\n\r\n  &--window {\r\n    width: 16px;\r\n    height: 16px;\r\n    background: aquamarine;\r\n  }\r\n\r\n  .tm-jav--close {\r\n    font-size: 14px;\r\n    background-color: transparent;\r\n    top: -7px;\r\n  }\r\n}\r\n</style>"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$6 = undefined;
    /* module identifier */
    const __vue_module_identifier__$6 = undefined;
    /* functional template */
    const __vue_is_functional_template__$6 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$6 = normalizeComponent(
      { render: __vue_render__$6, staticRenderFns: __vue_staticRenderFns__$6 },
      __vue_inject_styles__$6,
      __vue_script__$6,
      __vue_scope_id__$6,
      __vue_is_functional_template__$6,
      __vue_module_identifier__$6,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  var script$7 = {
    data () {
      return {
        logs: []
      }
    },
    mounted () {
      this.logs = [...logVue.logs];
      logVue.$on('log-task', this.pushLog);
    },
    beforeDestroy () {
      logVue.$off('log-task', this.pushLog);
    },
    methods: {
      pushLog (taskLog) {
        this.logs.unshift(taskLog);
      }
    }
  };

  /* script */
  const __vue_script__$7 = script$7;

  /* template */
  var __vue_render__$7 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      { staticClass: "tm-jav-log" },
      [
        _c("h4", [_vm._v("解析日志")]),
        _vm._v(" "),
        _vm._l(_vm.logs, function(task) {
          return _c("div", { staticClass: "tm-jav-log--task" }, [
            _c("h4", [_vm._v(_vm._s(task.name))]),
            _vm._v(" "),
            _c(
              "div",
              { staticClass: "tm-jav-log--content" },
              _vm._l(task.logs, function(log) {
                return _c("p", { staticClass: "tm-jav-log--row" }, [
                  _c("span", { staticClass: "tm-jav-log--time" }, [
                    _vm._v(_vm._s(log.after) + "ms")
                  ]),
                  _vm._v(" "),
                  _c(
                    "span",
                    {
                      class: [
                        "tm-jav--status",
                        "tm-jav--status-" + log.status,
                        "tm-jav--task-" + task.status
                      ]
                    },
                    [_vm._v(_vm._s(log.status))]
                  ),
                  _vm._v(" "),
                  _c("span", { staticClass: "tm-jav-log--name" }, [
                    _vm._v(_vm._s(log.name))
                  ]),
                  _vm._v(" "),
                  _c("span", { staticClass: "tm-jav-log--msg" }, [
                    _vm._v(_vm._s(log.msg))
                  ])
                ])
              }),
              0
            ),
            _vm._v(" "),
            !task.finished
              ? _c("span", { staticClass: "tm-jav--loading" })
              : _vm._e()
          ])
        })
      ],
      2
    )
  };
  var __vue_staticRenderFns__$7 = [];
  __vue_render__$7._withStripped = true;

    /* style */
    const __vue_inject_styles__$7 = function (inject) {
      if (!inject) return
      inject("data-v-a7903d74_0", { source: ".tm-jav-log[data-v-a7903d74] {\n  width: 100%;\n  height: 28px;\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  background: #fff;\n  z-index: 20;\n  padding: 10px;\n  box-shadow: 0px -1px 6px 3px rgba(142, 142, 142, 0.71);\n  transition: height 0.5s;\n  overflow: hidden;\n}\n.tm-jav-log .tm-jav--loading[data-v-a7903d74] {\n  margin: 10px 90px;\n}\n.tm-jav-log h4[data-v-a7903d74] {\n  margin-top: 0;\n}\n.tm-jav-log[data-v-a7903d74]:hover {\n  overflow: auto;\n  overflow-x: hidden;\n  height: 30vh;\n}\n.tm-jav-log--task[data-v-a7903d74] {\n  margin-top: 4px;\n}\n.tm-jav-log--row[data-v-a7903d74] {\n  text-align: left;\n  margin: 0 0 4px;\n}\n.tm-jav-log--row > span[data-v-a7903d74] {\n  margin-right: 4px;\n}\n.tm-jav-log--time[data-v-a7903d74] {\n  width: 60px;\n  text-align: right;\n  display: inline-block;\n}\n.tm-jav--status[data-v-a7903d74] {\n  display: inline-block;\n  padding: 2px;\n  border-radius: 4px;\n  color: #fff;\n  line-height: 1;\n  text-align: center;\n  width: 60px;\n  background-color: #ccc;\n}\n.tm-jav--status-success[data-v-a7903d74] {\n  background-color: #0dba42;\n}\n.tm-jav--status-fail[data-v-a7903d74] {\n  background-color: #ff6666;\n}\n.tm-jav--status-finished[data-v-a7903d74] {\n  background-color: #2dceff;\n}\n.tm-jav--status-finished.tm-jav--task-success[data-v-a7903d74] {\n  background-color: #0dba42;\n}\n.tm-jav--status-finished.tm-jav--task-fail[data-v-a7903d74] {\n  background-color: #ff6666;\n}\n", map: {"version":3,"sources":["log.vue","D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\log.vue"],"names":[],"mappings":"AAAA;EACE,WAAW;EACX,YAAY;EACZ,eAAe;EACf,SAAS;EACT,OAAO;EACP,gBAAgB;EAChB,WAAW;EACX,aAAa;EACb,sDAAsD;EACtD,uBAAuB;EACvB,gBAAgB;AAClB;AACA;EACE,iBAAiB;AACnB;AACA;EACE,aAAa;AACf;AACA;EACE,cAAc;EACd,kBAAkB;EAClB,YAAY;AACd;AACA;EACE,eAAe;AACjB;AACA;EACE,gBAAgB;EAChB,eAAe;AACjB;AACA;EACE,iBAAiB;AACnB;AACA;EACE,WAAW;EACX,iBAAiB;EACjB,qBAAqB;AACvB;AACA;EACE,qBAAqB;EACrB,YAAY;ECCd,kBAAA;EACA,WAAA;EACA,cAAA;EACA,kBAAA;EACA,WAAA;EACA,sBAAA;AACA;AACA;EACA,yBAAA;AACA;AACA;EACA,yBAAA;ADCA;ACCA;EACA,yBAAA;AACA;ADCA;ECCA,yBAAA;AACA;AACA;EACA,yBAAA;AACA","file":"log.vue","sourcesContent":[".tm-jav-log {\n  width: 100%;\n  height: 28px;\n  position: fixed;\n  bottom: 0;\n  left: 0;\n  background: #fff;\n  z-index: 20;\n  padding: 10px;\n  box-shadow: 0px -1px 6px 3px rgba(142, 142, 142, 0.71);\n  transition: height 0.5s;\n  overflow: hidden;\n}\n.tm-jav-log .tm-jav--loading {\n  margin: 10px 90px;\n}\n.tm-jav-log h4 {\n  margin-top: 0;\n}\n.tm-jav-log:hover {\n  overflow: auto;\n  overflow-x: hidden;\n  height: 30vh;\n}\n.tm-jav-log--task {\n  margin-top: 4px;\n}\n.tm-jav-log--row {\n  text-align: left;\n  margin: 0 0 4px;\n}\n.tm-jav-log--row > span {\n  margin-right: 4px;\n}\n.tm-jav-log--time {\n  width: 60px;\n  text-align: right;\n  display: inline-block;\n}\n.tm-jav--status {\n  display: inline-block;\n  padding: 2px;\n  border-radius: 4px;\n  color: #fff;\n  line-height: 1;\n  text-align: center;\n  width: 60px;\n  background-color: #ccc;\n}\n.tm-jav--status-success {\n  background-color: #0dba42;\n}\n.tm-jav--status-fail {\n  background-color: #ff6666;\n}\n.tm-jav--status-finished {\n  background-color: #2dceff;\n}\n.tm-jav--status-finished.tm-jav--task-success {\n  background-color: #0dba42;\n}\n.tm-jav--status-finished.tm-jav--task-fail {\n  background-color: #ff6666;\n}\n","<template>\r\n  <div class=\"tm-jav-log\">\r\n    <h4>解析日志</h4>\r\n    <div class=\"tm-jav-log--task\" v-for=\"task in logs\">\r\n      <h4>{{task.name}}</h4>\r\n      <div class=\"tm-jav-log--content\">\r\n        <p class=\"tm-jav-log--row\" v-for=\"log in task.logs\">\r\n          <span class=\"tm-jav-log--time\">{{log.after}}ms</span>\r\n          <span :class=\"['tm-jav--status', 'tm-jav--status-' + log.status, 'tm-jav--task-' + task.status]\">{{log.status}}</span>\r\n          <span class=\"tm-jav-log--name\">{{log.name}}</span>\r\n          <span class=\"tm-jav-log--msg\">{{log.msg}}</span>\r\n        </p>\r\n      </div>\r\n      <span class=\"tm-jav--loading\" v-if=\"!task.finished\"></span>\r\n    </div>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nimport { logVue } from '@/utils/log' \r\nexport default {\r\n  data () {\r\n    return {\r\n      logs: []\r\n    }\r\n  },\r\n  mounted () {\r\n    this.logs = [...logVue.logs]\r\n    logVue.$on('log-task', this.pushLog)\r\n  },\r\n  beforeDestroy () {\r\n    logVue.$off('log-task', this.pushLog)\r\n  },\r\n  methods: {\r\n    pushLog (taskLog) {\r\n      this.logs.unshift(taskLog)\r\n    }\r\n  }\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"less\">\r\n.tm-jav-log {\r\n  width: 100%;\r\n  height: 28px;\r\n  position: fixed;\r\n  bottom: 0;\r\n  left: 0;\r\n  background: #fff;\r\n  z-index: 20;\r\n  padding: 10px;\r\n  box-shadow: 0px -1px 6px 3px rgba(142, 142, 142, 0.71);\r\n  transition: height .5s;\r\n  overflow: hidden;\r\n\r\n  .tm-jav--loading {\r\n    margin: 10px 90px;\r\n  }\r\n\r\n  h4 {\r\n    margin-top: 0;\r\n  }\r\n  &:hover {\r\n    overflow: auto;\r\n    overflow-x: hidden;\r\n    height: 30vh;\r\n  }\r\n\r\n  &--task {\r\n    margin-top: 4px;\r\n  }\r\n\r\n  &--row {\r\n    text-align: left;\r\n    margin: 0 0 4px;\r\n    & > span {\r\n      margin-right: 4px;\r\n    }\r\n  }\r\n\r\n  &--time {\r\n    width: 60px;\r\n    text-align: right;\r\n    display: inline-block;\r\n  }\r\n}\r\n.tm-jav--status {\r\n  display: inline-block;\r\n  padding: 2px;\r\n  border-radius: 4px;\r\n  color: #fff;\r\n  line-height: 1;\r\n  text-align: center;\r\n  width: 60px;\r\n  background-color: #ccc;\r\n  \r\n  &-success {\r\n    background-color: #0dba42;\r\n  }\r\n  &-fail {\r\n    background-color: #ff6666\r\n  }\r\n  &-finished {\r\n    background-color: rgb(45, 206, 255);\r\n    &.tm-jav--task-success {\r\n      background-color: #0dba42;\r\n    }\r\n    &.tm-jav--task-fail {\r\n      background-color: #ff6666\r\n    }\r\n  }\r\n}\r\n</style>"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$7 = "data-v-a7903d74";
    /* module identifier */
    const __vue_module_identifier__$7 = undefined;
    /* functional template */
    const __vue_is_functional_template__$7 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$7 = normalizeComponent(
      { render: __vue_render__$7, staticRenderFns: __vue_staticRenderFns__$7 },
      __vue_inject_styles__$7,
      __vue_script__$7,
      __vue_scope_id__$7,
      __vue_is_functional_template__$7,
      __vue_module_identifier__$7,
      false,
      createInjector,
      undefined,
      undefined
    );

  //
  var script$8 = {
    data () {
      return {
        genres: []
      }
    },
    mounted () {
      this.init();
    },
    methods: {
      init () {
        genresModel.getAll().then((result) => {
          this.genres = result;
        });
      },
      showGenre ({id, name}) {
        this.$root.pushTab({
          href: 'vl_genre.php?g=' + id,
          name,
        });
      }
    }
  };

  /* script */
  const __vue_script__$8 = script$8;

  /* template */
  var __vue_render__$8 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c(
      "div",
      { staticClass: "tm-jav-genres" },
      _vm._l(_vm.genres, function(category) {
        return _c("div", { staticClass: "tm-jav-genres--category" }, [
          _c("h3", { staticClass: "tm-jav-genres--category-name" }, [
            _vm._v(_vm._s(category.type))
          ]),
          _vm._v(" "),
          _c(
            "div",
            { staticClass: "tm-jav-genres--list" },
            _vm._l(category.genres, function(genre) {
              return _c(
                "div",
                {
                  staticClass: "tm-jav-genres--item",
                  on: {
                    click: function($event) {
                      return _vm.showGenre(genre)
                    }
                  }
                },
                [_vm._v("\n        " + _vm._s(genre.name) + "\n      ")]
              )
            }),
            0
          )
        ])
      }),
      0
    )
  };
  var __vue_staticRenderFns__$8 = [];
  __vue_render__$8._withStripped = true;

    /* style */
    const __vue_inject_styles__$8 = function (inject) {
      if (!inject) return
      inject("data-v-7c4ad8de_0", { source: ".tm-jav-genres[data-v-7c4ad8de] {\n  position: fixed;\n  right: 0;\n  width: 300px;\n  height: 100vh;\n  transition: transform 0.5s;\n  background-color: #fff;\n  z-index: 50;\n  box-shadow: -2px 0px 10px 1px #6b6b6b78;\n  overflow: hidden;\n  font-size: 14px;\n  transform: translateX(290px);\n}\n.tm-jav-genres[data-v-7c4ad8de]:hover {\n  transform: translateX(0);\n  overflow: auto;\n}\n.tm-jav-genres--category[data-v-7c4ad8de] {\n  border-top: 1px solid #333;\n  margin-top: 20px;\n}\n.tm-jav-genres--category-name[data-v-7c4ad8de] {\n  background-color: #fff;\n  display: inline-block;\n  margin: -10px 12px 0px;\n  height: 20px;\n  padding: 0 10px;\n  overflow: hidden;\n}\n.tm-jav-genres--list[data-v-7c4ad8de] {\n  padding: 0 12px;\n  display: flex;\n  flex-wrap: wrap;\n}\n.tm-jav-genres--item[data-v-7c4ad8de] {\n  margin: 0 4px;\n  padding: 2px;\n  white-space: nowrap;\n  cursor: pointer;\n  border-radius: 2px;\n}\n.tm-jav-genres--item[data-v-7c4ad8de]:hover {\n  background-color: #b1b1b1ab;\n}\n", map: {"version":3,"sources":["genres.vue","D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\components\\genres.vue"],"names":[],"mappings":"AAAA;EACE,eAAe;EACf,QAAQ;EACR,YAAY;EACZ,aAAa;EACb,0BAA0B;EAC1B,sBAAsB;EACtB,WAAW;EACX,uCAAuC;EACvC,gBAAgB;EAChB,eAAe;EACf,4BAA4B;AAC9B;AACA;EACE,wBAAwB;EACxB,cAAc;AAChB;AACA;EACE,0BAA0B;EAC1B,gBAAgB;AAClB;AACA;EACE,sBAAsB;EACtB,qBAAqB;EACrB,sBAAsB;EACtB,YAAY;EACZ,eAAe;EACf,gBAAgB;AAClB;AACA;EACE,eAAe;EACf,aAAa;EACb,eAAe;AACjB;AACA;EACE,aAAa;EACb,YAAY;EACZ,mBAAmB;EACnB,eAAe;EACf,kBAAkB;AACpB;ACCA;EACA,2BAAA;AACA","file":"genres.vue","sourcesContent":[".tm-jav-genres {\n  position: fixed;\n  right: 0;\n  width: 300px;\n  height: 100vh;\n  transition: transform 0.5s;\n  background-color: #fff;\n  z-index: 50;\n  box-shadow: -2px 0px 10px 1px #6b6b6b78;\n  overflow: hidden;\n  font-size: 14px;\n  transform: translateX(290px);\n}\n.tm-jav-genres:hover {\n  transform: translateX(0);\n  overflow: auto;\n}\n.tm-jav-genres--category {\n  border-top: 1px solid #333;\n  margin-top: 20px;\n}\n.tm-jav-genres--category-name {\n  background-color: #fff;\n  display: inline-block;\n  margin: -10px 12px 0px;\n  height: 20px;\n  padding: 0 10px;\n  overflow: hidden;\n}\n.tm-jav-genres--list {\n  padding: 0 12px;\n  display: flex;\n  flex-wrap: wrap;\n}\n.tm-jav-genres--item {\n  margin: 0 4px;\n  padding: 2px;\n  white-space: nowrap;\n  cursor: pointer;\n  border-radius: 2px;\n}\n.tm-jav-genres--item:hover {\n  background-color: #b1b1b1ab;\n}\n","<template>\r\n  <div class=\"tm-jav-genres\">\r\n    <div class=\"tm-jav-genres--category\" v-for=\"category in genres\">\r\n      <h3 class=\"tm-jav-genres--category-name\">{{category.type}}</h3>\r\n      <div class=\"tm-jav-genres--list\">\r\n        <div class=\"tm-jav-genres--item\" v-for=\"genre in category.genres\" @click=\"showGenre(genre)\">\r\n          {{genre.name}}\r\n        </div>\r\n      </div>\r\n    </div>\r\n  </div>\r\n</template>\r\n\r\n<script>\r\nimport genresModel from '@/api/genres'\r\nexport default {\r\n  data () {\r\n    return {\r\n      genres: []\r\n    }\r\n  },\r\n  mounted () {\r\n    this.init()\r\n  },\r\n  methods: {\r\n    init () {\r\n      genresModel.getAll().then((result) => {\r\n        this.genres = result\r\n      })\r\n    },\r\n    showGenre ({id, name}) {\r\n      this.$root.pushTab({\r\n        href: 'vl_genre.php?g=' + id,\r\n        name,\r\n      })\r\n    }\r\n  }\r\n}\r\n</script>\r\n\r\n<style scoped lang=\"less\">\r\n.tm-jav-genres {\r\n  position: fixed;\r\n  right: 0;\r\n  width: 300px;\r\n  height: 100vh;\r\n  transition: transform .5s;\r\n  background-color: #fff;\r\n  z-index: 50;\r\n  box-shadow: -2px 0px 10px 1px #6b6b6b78;\r\n  overflow: hidden;\r\n  font-size: 14px;\r\n  transform: translateX(290px);\r\n  &:hover {\r\n    transform: translateX(0);\r\n    overflow: auto;\r\n  }\r\n  \r\n  &--category {\r\n    border-top: 1px solid #333;\r\n    margin-top: 20px;\r\n    &-name {\r\n      background-color: #fff;\r\n      display: inline-block;\r\n      margin: -10px 12px 0px;\r\n      height: 20px;\r\n      padding: 0 10px;\r\n      overflow: hidden;\r\n    }\r\n  }\r\n  &--list {\r\n    padding: 0 12px;\r\n    display: flex;\r\n    flex-wrap: wrap;\r\n  }\r\n  &--item {\r\n    margin: 0 4px;\r\n    padding: 2px;\r\n    white-space: nowrap;\r\n    cursor: pointer;\r\n    border-radius: 2px;\r\n\r\n    &:hover {\r\n      background-color: #b1b1b1ab;\r\n    }\r\n  }\r\n}\r\n</style>"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$8 = "data-v-7c4ad8de";
    /* module identifier */
    const __vue_module_identifier__$8 = undefined;
    /* functional template */
    const __vue_is_functional_template__$8 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$8 = normalizeComponent(
      { render: __vue_render__$8, staticRenderFns: __vue_staticRenderFns__$8 },
      __vue_inject_styles__$8,
      __vue_script__$8,
      __vue_scope_id__$8,
      __vue_is_functional_template__$8,
      __vue_module_identifier__$8,
      false,
      createInjector,
      undefined,
      undefined
    );

  const STORAGE_KEY = 'tm-jav-prev-status';

  var prevStatus = {
    set (value, key = STORAGE_KEY) {
      if (typeof value !== 'string') {
        value = JSON.stringify(value);
      }
      localStorage.setItem(key, value);
    },
    get (key = STORAGE_KEY) {
      const value = localStorage.getItem(key);
      return JSON.parse(value)
    }
  };

  //

  var script$9 = {
    name: 'tm-app',
    components: {
      TmContainer: __vue_component__,
      TmWindow: __vue_component__$1,
      TmPreview: __vue_component__$4,
      TmSearch: __vue_component__$5,
      TmList: __vue_component__$3,
      TmTabs: __vue_component__$6,
      TmLog: __vue_component__$7,
      TmGenres: __vue_component__$8,
    },
    data () {
      return {
        currVideo: null,
        currWindowSrc: '',
        tabIndex: 0,
        tabs: [
          {name: '最热门', href: '/cn/', next: false, fixed: true},
          {name: '新发行', href: 'vl_newrelease.php', fixed: true},
          {name: '新加入', href: 'vl_newentries.php', fixed: true},
          {name: '最想要', href: 'vl_mostwanted.php', fixed: true},
          {name: '高评价', href: 'vl_bestrated.php', fixed: true},
        ],
        options: {
          autoplay: true,
          muted: false,
          loadPrevStatus: true,
          useWindow: true,
          showApp: true
        }
      }
    },
    created () {
      this.init();
      window.addEventListener('beforeunload', this.onClose);
    },
    beforeDestroy () {
      window.removeEventListener('beforeunload', this.onClose);
    },
    computed: {
      currTab () {
        return this.tabs[this.tabIndex] || null
      }
    },
    methods: {
      removeTab (index) {
        const tab = this.tabs[index];
        if (tab.fixed) { return }

        this.tabs.splice(index, 1);

        if (index === this.tabIndex) {
          const prevIndex = ListCacheStore.keys.length - 2;
          if (prevIndex > -1) {
            index = this.tabs.findIndex(tab => tab.href === ListCacheStore.keys[prevIndex]);
          }
          
          this.tabIndex = Math.max(index, 0);
        } else if (this.tabIndex >= this.tabs.length) {
          this.tabIndex = this.tabs.length - 1;
        }
      },
      pushTab (tab) {
        try {
          const {name, href} = tab;
          const index = this.tabs.findIndex((tab) => tab.href === href);
          if (index > -1) {
            this.tabIndex = index;
          } else {
            const len = this.tabs.push({name, href});
            this.tabIndex = len - 1;
          }
        } catch (e) {
          console.error(e);
        }
      },
      onClose () {
        prevStatus.set(this._data);
      },
      init () {
        const prev = prevStatus.get();
        if (!prev) {
          return
        }
        const loadPrevStatus = prev.options && prev.options.loadPrevStatus;
        prev.options && (this.options = {...this.options, ...prev.options});
        if (prev && loadPrevStatus !== false) {
          for (let key in prev) {
            if (key !== 'options') {
              this[key] = prev[key];
            }
          }
        }
      },
      handleGlobalClick (ev) {
        if (!this.options.useWindow) {
          return
        }
        // A tm-jav-infos--title A tm-jav-item--title
        const target = ev.target;
        if (target.tagName === 'A' && target.className.endsWith('--title')) {
          ev.preventDefault();
          ev.stopPropagation();
          this.currWindowSrc = target.href;
        }
      }
    }
  };

  /* script */
  const __vue_script__$9 = script$9;

  /* template */
  var __vue_render__$9 = function() {
    var _vm = this;
    var _h = _vm.$createElement;
    var _c = _vm._self._c || _h;
    return _c("tm-container", [
      _c(
        "div",
        { staticClass: "tm-jav", on: { click: _vm.handleGlobalClick } },
        [
          _c(
            "header",
            { staticClass: "tm-jav-header" },
            [
              _c("input", {
                directives: [
                  {
                    name: "model",
                    rawName: "v-model",
                    value: _vm.options.showApp,
                    expression: "options.showApp"
                  }
                ],
                attrs: { type: "checkbox" },
                domProps: {
                  checked: Array.isArray(_vm.options.showApp)
                    ? _vm._i(_vm.options.showApp, null) > -1
                    : _vm.options.showApp
                },
                on: {
                  change: function($event) {
                    var $$a = _vm.options.showApp,
                      $$el = $event.target,
                      $$c = $$el.checked ? true : false;
                    if (Array.isArray($$a)) {
                      var $$v = null,
                        $$i = _vm._i($$a, $$v);
                      if ($$el.checked) {
                        $$i < 0 &&
                          _vm.$set(_vm.options, "showApp", $$a.concat([$$v]));
                      } else {
                        $$i > -1 &&
                          _vm.$set(
                            _vm.options,
                            "showApp",
                            $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                          );
                      }
                    } else {
                      _vm.$set(_vm.options, "showApp", $$c);
                    }
                  }
                }
              }),
              _vm._v(" 进入网站自动加载本脚本\r\n      "),
              _c("input", {
                directives: [
                  {
                    name: "model",
                    rawName: "v-model",
                    value: _vm.options.autoplay,
                    expression: "options.autoplay"
                  }
                ],
                attrs: { type: "checkbox" },
                domProps: {
                  checked: Array.isArray(_vm.options.autoplay)
                    ? _vm._i(_vm.options.autoplay, null) > -1
                    : _vm.options.autoplay
                },
                on: {
                  change: function($event) {
                    var $$a = _vm.options.autoplay,
                      $$el = $event.target,
                      $$c = $$el.checked ? true : false;
                    if (Array.isArray($$a)) {
                      var $$v = null,
                        $$i = _vm._i($$a, $$v);
                      if ($$el.checked) {
                        $$i < 0 &&
                          _vm.$set(_vm.options, "autoplay", $$a.concat([$$v]));
                      } else {
                        $$i > -1 &&
                          _vm.$set(
                            _vm.options,
                            "autoplay",
                            $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                          );
                      }
                    } else {
                      _vm.$set(_vm.options, "autoplay", $$c);
                    }
                  }
                }
              }),
              _vm._v(" 自动播放\r\n      "),
              _c("input", {
                directives: [
                  {
                    name: "model",
                    rawName: "v-model",
                    value: _vm.options.muted,
                    expression: "options.muted"
                  }
                ],
                attrs: { type: "checkbox" },
                domProps: {
                  checked: Array.isArray(_vm.options.muted)
                    ? _vm._i(_vm.options.muted, null) > -1
                    : _vm.options.muted
                },
                on: {
                  change: function($event) {
                    var $$a = _vm.options.muted,
                      $$el = $event.target,
                      $$c = $$el.checked ? true : false;
                    if (Array.isArray($$a)) {
                      var $$v = null,
                        $$i = _vm._i($$a, $$v);
                      if ($$el.checked) {
                        $$i < 0 &&
                          _vm.$set(_vm.options, "muted", $$a.concat([$$v]));
                      } else {
                        $$i > -1 &&
                          _vm.$set(
                            _vm.options,
                            "muted",
                            $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                          );
                      }
                    } else {
                      _vm.$set(_vm.options, "muted", $$c);
                    }
                  }
                }
              }),
              _vm._v(" 静音播放\r\n      "),
              _c("input", {
                directives: [
                  {
                    name: "model",
                    rawName: "v-model",
                    value: _vm.options.loadPrevStatus,
                    expression: "options.loadPrevStatus"
                  }
                ],
                attrs: { type: "checkbox" },
                domProps: {
                  checked: Array.isArray(_vm.options.loadPrevStatus)
                    ? _vm._i(_vm.options.loadPrevStatus, null) > -1
                    : _vm.options.loadPrevStatus
                },
                on: {
                  change: function($event) {
                    var $$a = _vm.options.loadPrevStatus,
                      $$el = $event.target,
                      $$c = $$el.checked ? true : false;
                    if (Array.isArray($$a)) {
                      var $$v = null,
                        $$i = _vm._i($$a, $$v);
                      if ($$el.checked) {
                        $$i < 0 &&
                          _vm.$set(
                            _vm.options,
                            "loadPrevStatus",
                            $$a.concat([$$v])
                          );
                      } else {
                        $$i > -1 &&
                          _vm.$set(
                            _vm.options,
                            "loadPrevStatus",
                            $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                          );
                      }
                    } else {
                      _vm.$set(_vm.options, "loadPrevStatus", $$c);
                    }
                  }
                }
              }),
              _vm._v(" 自动加载上一次浏览状态\r\n      "),
              _c("input", {
                directives: [
                  {
                    name: "model",
                    rawName: "v-model",
                    value: _vm.options.useWindow,
                    expression: "options.useWindow"
                  }
                ],
                attrs: { type: "checkbox" },
                domProps: {
                  checked: Array.isArray(_vm.options.useWindow)
                    ? _vm._i(_vm.options.useWindow, null) > -1
                    : _vm.options.useWindow
                },
                on: {
                  change: function($event) {
                    var $$a = _vm.options.useWindow,
                      $$el = $event.target,
                      $$c = $$el.checked ? true : false;
                    if (Array.isArray($$a)) {
                      var $$v = null,
                        $$i = _vm._i($$a, $$v);
                      if ($$el.checked) {
                        $$i < 0 &&
                          _vm.$set(_vm.options, "useWindow", $$a.concat([$$v]));
                      } else {
                        $$i > -1 &&
                          _vm.$set(
                            _vm.options,
                            "useWindow",
                            $$a.slice(0, $$i).concat($$a.slice($$i + 1))
                          );
                      }
                    } else {
                      _vm.$set(_vm.options, "useWindow", $$c);
                    }
                  }
                }
              }),
              _vm._v(" 点击标题在小窗口打开\r\n      "),
              _c("tm-search", {
                on: {
                  select: function(v) {
                    return (_vm.currVideo = v)
                  }
                }
              })
            ],
            1
          ),
          _vm._v(" "),
          _c(
            "div",
            { staticClass: "tm-jav-body" },
            [
              _c("tm-preview", {
                directives: [
                  {
                    name: "show",
                    rawName: "v-show",
                    value: _vm.currVideo,
                    expression: "currVideo"
                  }
                ],
                staticStyle: { flex: "1" },
                attrs: { video: _vm.currVideo },
                on: {
                  select: function(v) {
                    return (_vm.currVideo = v)
                  },
                  close: function($event) {
                    _vm.currVideo = null;
                  }
                }
              }),
              _vm._v(" "),
              _c(
                "div",
                {
                  staticClass: "tm-jav-main-list",
                  style: { width: _vm.currVideo ? "35%" : "100%" }
                },
                [
                  _c("tm-tabs", {
                    attrs: { currIndex: _vm.tabIndex, tabs: _vm.tabs },
                    on: {
                      active: function(index) {
                        return (_vm.tabIndex = index)
                      },
                      remove: _vm.removeTab
                    }
                  }),
                  _vm._v(" "),
                  _c("tm-list", {
                    attrs: { tab: _vm.currTab },
                    on: {
                      select: function(v) {
                        return (_vm.currVideo = v)
                      }
                    }
                  })
                ],
                1
              )
            ],
            1
          ),
          _vm._v(" "),
          _c("footer", { staticClass: "tm-jav-footer" }, [_c("tm-log")], 1),
          _vm._v(" "),
          _c("tm-genres"),
          _vm._v(" "),
          _c("tm-window", {
            attrs: { src: _vm.currWindowSrc },
            on: {
              close: function($event) {
                _vm.currWindowSrc = "";
              }
            }
          })
        ],
        1
      )
    ])
  };
  var __vue_staticRenderFns__$9 = [];
  __vue_render__$9._withStripped = true;

    /* style */
    const __vue_inject_styles__$9 = function (inject) {
      if (!inject) return
      inject("data-v-f562a808_0", { source: "\n.tm-jav[data-v-f562a808]\r\n{\r\n  font-size: 12px;\r\n  background-color: #f5f5f5;\r\n  width: 100vw;\r\n  height: 100vh;\r\n  min-width: 1200px;\r\n  overflow-x: auto;\r\n  display: flex;\r\n  flex-direction: column;\n}\n.tm-jav-header[data-v-f562a808], .tm-jav-footer[data-v-f562a808] {\r\n  height: 28px;\r\n  padding: 0 16px;\n}\n.tm-jav-body[data-v-f562a808] {\r\n  flex: 1;\r\n  overflow: hidden;\r\n  display: flex;\r\n  margin: 0 16px;\r\n  width: 100%;\n}\n.tm-jav-main-list[data-v-f562a808] {\r\n  width: 35vw;\n}\r\n", map: {"version":3,"sources":["D:\\p\\_tampermonkey\\javlib-preview-userscript\\src\\app.vue"],"names":[],"mappings":";AA4JA;;EAEA,eAAA;EACA,yBAAA;EACA,YAAA;EACA,aAAA;EACA,iBAAA;EACA,gBAAA;EACA,aAAA;EACA,sBAAA;AACA;AACA;EACA,YAAA;EACA,eAAA;AACA;AACA;EACA,OAAA;EACA,gBAAA;EACA,aAAA;EACA,cAAA;EACA,WAAA;AACA;AACA;EACA,WAAA;AACA","file":"app.vue","sourcesContent":["<template>\r\n<tm-container>\r\n  <div class=\"tm-jav\" @click=\"handleGlobalClick\">\r\n    <header class=\"tm-jav-header\">\r\n      <input type=\"checkbox\" v-model=\"options.showApp\"> 进入网站自动加载本脚本\r\n      <input type=\"checkbox\" v-model=\"options.autoplay\"> 自动播放\r\n      <input type=\"checkbox\" v-model=\"options.muted\"> 静音播放\r\n      <input type=\"checkbox\" v-model=\"options.loadPrevStatus\"> 自动加载上一次浏览状态\r\n      <input type=\"checkbox\" v-model=\"options.useWindow\"> 点击标题在小窗口打开\r\n      <tm-search @select=\"(v) => currVideo = v\"></tm-search>\r\n    </header>\r\n    <div class=\"tm-jav-body\">\r\n      <tm-preview style=\"flex: 1\" :video=\"currVideo\" v-show=\"currVideo\" @select=\"(v) => currVideo = v\" @close=\"currVideo = null\"></tm-preview>\r\n      <div class=\"tm-jav-main-list\" :style=\"{width: currVideo ? '35%' : '100%'}\">\r\n        <tm-tabs \r\n        :currIndex=\"tabIndex\" :tabs=\"tabs\"\r\n        @active=\"(index) => tabIndex = index\"\r\n        @remove=\"removeTab\"\r\n        ></tm-tabs>\r\n        <tm-list :tab=\"currTab\" @select=\"(v) => currVideo = v\"></tm-list>\r\n      </div>\r\n    </div>\r\n    <footer class=\"tm-jav-footer\">\r\n      <tm-log></tm-log>\r\n    </footer>\r\n    <tm-genres></tm-genres>\r\n    <tm-window :src=\"currWindowSrc\" @close=\"currWindowSrc = ''\"></tm-window>\r\n  </div>\r\n</tm-container>\r\n</template>\r\n\r\n<script>\r\nimport TmContainer from '@/components/container.vue'\r\nimport TmWindow from '@/components/window.vue'\r\nimport TmList from '@/components/list.vue'\r\nimport TmPreview from '@/components/preview.vue'\r\nimport TmSearch from '@/components/search.vue'\r\nimport TmTabs from '@/components/tabs.vue'\r\nimport TmLog from '@/components/log.vue'\r\nimport TmGenres from '@/components/genres.vue'\r\nimport prevStatus from '@/utils/prev-status'\r\nimport { ListCacheStore } from '@/utils/javlibrary'\r\n\r\nexport default {\r\n  name: 'tm-app',\r\n  components: {\r\n    TmContainer,\r\n    TmWindow,\r\n    TmPreview,\r\n    TmSearch,\r\n    TmList,\r\n    TmTabs,\r\n    TmLog,\r\n    TmGenres,\r\n  },\r\n  data () {\r\n    return {\r\n      currVideo: null,\r\n      currWindowSrc: '',\r\n      tabIndex: 0,\r\n      tabs: [\r\n        {name: '最热门', href: '/cn/', next: false, fixed: true},\r\n        {name: '新发行', href: 'vl_newrelease.php', fixed: true},\r\n        {name: '新加入', href: 'vl_newentries.php', fixed: true},\r\n        {name: '最想要', href: 'vl_mostwanted.php', fixed: true},\r\n        {name: '高评价', href: 'vl_bestrated.php', fixed: true},\r\n      ],\r\n      options: {\r\n        autoplay: true,\r\n        muted: false,\r\n        loadPrevStatus: true,\r\n        useWindow: true,\r\n        showApp: true\r\n      }\r\n    }\r\n  },\r\n  created () {\r\n    this.init()\r\n    window.addEventListener('beforeunload', this.onClose)\r\n  },\r\n  beforeDestroy () {\r\n    window.removeEventListener('beforeunload', this.onClose)\r\n  },\r\n  computed: {\r\n    currTab () {\r\n      return this.tabs[this.tabIndex] || null\r\n    }\r\n  },\r\n  methods: {\r\n    removeTab (index) {\r\n      const tab = this.tabs[index]\r\n      if (tab.fixed) { return }\r\n\r\n      this.tabs.splice(index, 1)\r\n\r\n      if (index === this.tabIndex) {\r\n        const prevIndex = ListCacheStore.keys.length - 2\r\n        if (prevIndex > -1) {\r\n          index = this.tabs.findIndex(tab => tab.href === ListCacheStore.keys[prevIndex])\r\n        }\r\n        \r\n        this.tabIndex = Math.max(index, 0)\r\n      } else if (this.tabIndex >= this.tabs.length) {\r\n        this.tabIndex = this.tabs.length - 1\r\n      }\r\n    },\r\n    pushTab (tab) {\r\n      try {\r\n        const {name, href} = tab\r\n        const index = this.tabs.findIndex((tab) => tab.href === href)\r\n        if (index > -1) {\r\n          this.tabIndex = index\r\n        } else {\r\n          const len = this.tabs.push({name, href})\r\n          this.tabIndex = len - 1\r\n        }\r\n      } catch (e) {\r\n        console.error(e)\r\n      }\r\n    },\r\n    onClose () {\r\n      prevStatus.set(this._data)\r\n    },\r\n    init () {\r\n      const prev = prevStatus.get()\r\n      if (!prev) {\r\n        return\r\n      }\r\n      const loadPrevStatus = prev.options && prev.options.loadPrevStatus\r\n      prev.options && (this.options = {...this.options, ...prev.options})\r\n      if (prev && loadPrevStatus !== false) {\r\n        for (let key in prev) {\r\n          if (key !== 'options') {\r\n            this[key] = prev[key]\r\n          }\r\n        }\r\n      }\r\n    },\r\n    handleGlobalClick (ev) {\r\n      if (!this.options.useWindow) {\r\n        return\r\n      }\r\n      // A tm-jav-infos--title A tm-jav-item--title\r\n      const target = ev.target\r\n      if (target.tagName === 'A' && target.className.endsWith('--title')) {\r\n        ev.preventDefault()\r\n        ev.stopPropagation()\r\n        this.currWindowSrc = target.href\r\n      }\r\n    }\r\n  }\r\n}\r\n\r\n</script>\r\n\r\n<style scoped>\r\n.tm-jav\r\n{\r\n  font-size: 12px;\r\n  background-color: #f5f5f5;\r\n  width: 100vw;\r\n  height: 100vh;\r\n  min-width: 1200px;\r\n  overflow-x: auto;\r\n  display: flex;\r\n  flex-direction: column;\r\n}\r\n.tm-jav-header, .tm-jav-footer {\r\n  height: 28px;\r\n  padding: 0 16px;\r\n}\r\n.tm-jav-body {\r\n  flex: 1;\r\n  overflow: hidden;\r\n  display: flex;\r\n  margin: 0 16px;\r\n  width: 100%;\r\n}\r\n.tm-jav-main-list {\r\n  width: 35vw;\r\n}\r\n</style>\r\n"]}, media: undefined });

    };
    /* scoped */
    const __vue_scope_id__$9 = "data-v-f562a808";
    /* module identifier */
    const __vue_module_identifier__$9 = undefined;
    /* functional template */
    const __vue_is_functional_template__$9 = false;
    /* style inject SSR */
    
    /* style inject shadow dom */
    

    
    const __vue_component__$9 = normalizeComponent(
      { render: __vue_render__$9, staticRenderFns: __vue_staticRenderFns__$9 },
      __vue_inject_styles__$9,
      __vue_script__$9,
      __vue_scope_id__$9,
      __vue_is_functional_template__$9,
      __vue_module_identifier__$9,
      false,
      createInjector,
      undefined,
      undefined
    );

  __$styleInject("/* .vue */\n* {\n  box-sizing: border-box;\n}\n#adultwarningmask {\n  display: none;\n}\nbody::-webkit-scrollbar {\n  display: none;\n}\n::-webkit-scrollbar-thumb {\n  height: 56px;\n  background: #ff60cc;\n}\n::-webkit-scrollbar {\n  width: 4px;\n}\n.tm-jav--close {\n  position: relative;\n  width: 1em;\n  height: 1em;\n  opacity: 0.7;\n  font-size: 20px;\n  display: inline-block;\n  background-color: rgba(0, 0, 0, 0.5);\n  border-radius: 50%;\n  vertical-align: middle;\n}\n.tm-jav--close:hover {\n  opacity: 1;\n}\n.tm-jav--close:before,\n.tm-jav--close:after {\n  position: absolute;\n  left: calc(0.5em - 1px);\n  content: ' ';\n  height: 1em;\n  width: 2px;\n  background-color: #fff;\n}\n.tm-jav--close:before {\n  transform: rotate(45deg);\n}\n.tm-jav--close:after {\n  transform: rotate(-45deg);\n}\n.tm-jav--loading-wrapper {\n  position: absolute;\n  left: 50%;\n  top: 50%;\n  z-index: 4;\n  color: #fff;\n  transform: translate(-50%, -50%);\n}\n.tm-jav--loading {\n  font-size: 10px;\n  width: 1em;\n  height: 1em;\n  display: inline-block;\n  margin: 10px 15px;\n  position: relative;\n  left: -9999px;\n  border-radius: 5px;\n  background-color: #f282ce;\n  color: #f282ce;\n  box-shadow: 9999px 0 0 -5px #f282ce;\n  animation: dotPulse 1.5s infinite linear;\n  animation-delay: 0.25s;\n}\n.tm-jav--loading::before,\n.tm-jav--loading::after {\n  content: '';\n  display: inline-block;\n  position: absolute;\n  top: 0;\n  width: 10px;\n  height: 10px;\n  border-radius: 5px;\n  background-color: #f282ce;\n  color: #f282ce;\n}\n.tm-jav--loading::before {\n  box-shadow: 9984px 0 0 -5px #f282ce;\n  animation: dotPulseBefore 1.5s infinite linear;\n  animation-delay: 0s;\n}\n.tm-jav--loading::after {\n  box-shadow: 10014px 0 0 -5px #f282ce;\n  animation: dotPulseAfter 1.5s infinite linear;\n  animation-delay: 0.5s;\n}\n@keyframes dotPulseBefore {\n  0% {\n    box-shadow: 9984px 0 0 -5px #f282ce;\n  }\n  30% {\n    box-shadow: 9984px 0 0 2px #f282ce;\n  }\n  60%,\n  100% {\n    box-shadow: 9984px 0 0 -5px #f282ce;\n  }\n}\n@keyframes dotPulse {\n  0% {\n    box-shadow: 9999px 0 0 -5px #f282ce;\n  }\n  30% {\n    box-shadow: 9999px 0 0 2px #f282ce;\n  }\n  60%,\n  100% {\n    box-shadow: 9999px 0 0 -5px #f282ce;\n  }\n}\n@keyframes dotPulseAfter {\n  0% {\n    box-shadow: 10014px 0 0 -5px #f282ce;\n  }\n  30% {\n    box-shadow: 10014px 0 0 2px #f282ce;\n  }\n  60%,\n  100% {\n    box-shadow: 10014px 0 0 -5px #f282ce;\n  }\n}\n.tm-jav--tag {\n  margin: 0;\n  padding: 0;\n  color: rgba(0, 0, 0, 0.65);\n  font-size: 14px;\n  font-variant: tabular-nums;\n  line-height: 1.5;\n  list-style: none;\n  font-feature-settings: 'tnum';\n  display: inline-block;\n  height: auto;\n  margin-right: 4px;\n  padding: 0 7px;\n  font-size: 12px;\n  line-height: 20px;\n  white-space: nowrap;\n  background: #fafafa;\n  border: 1px solid #d9d9d9;\n  border-radius: 4px;\n  cursor: default;\n  opacity: 1;\n  transition: all 0.3s cubic-bezier(0.78, 0.14, 0.15, 0.86);\n}\n.tm-jav--tag.tm-jav--current {\n  background-color: rgba(0, 0, 0, 0.65);\n  color: #fff;\n}\n.tm-jav--heart {\n  font-size: 8px;\n  background-color: red;\n  display: inline-block;\n  height: 1em;\n  width: 1em;\n  position: relative;\n  top: 0;\n  transform: rotate(-45deg);\n}\n.tm-jav--heart:before,\n.tm-jav--heart:after {\n  content: \"\";\n  background-color: red;\n  border-radius: 50%;\n  height: 1em;\n  position: absolute;\n  width: 1em;\n}\n.tm-jav--heart:before {\n  top: -0.5em;\n  left: 0;\n}\n.tm-jav--heart:after {\n  left: 0.5em;\n  top: 0;\n}\n");

  Vue.use(Http);

  const container = (parent) => {
    const appContainer = document.createElement('div');
    parent.insertBefore(appContainer, parent.firstChild);
    return appContainer
  };

  const vuefactory = (option, parent = document.body) => {
    const vm = new Vue({
      ...option,
      el: container(parent),
    });

    if (!window.__TAMPERMONKEY_VUE__) window.__TAMPERMONKEY_VUE__ = [];
    window.__TAMPERMONKEY_VUE__.push(vm);
  };

  vuefactory(__vue_component__$9);

}(RectangleTransform, Vue));
//# sourceMappingURL=javlib-preview-userscript.user.js.map