Greasy Fork is available in English.

lib:file opener

none

Tendrás que instalar una extensión para tu navegador como Tampermonkey, Greasemonkey o Violentmonkey si quieres utilizar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Violentmonkey para instalar este script.

Necesitarás instalar una extensión como Tampermonkey o Userscripts para instalar este script.

Necesitará instalar una extensión como Tampermonkey para instalar este script.

Necesitarás instalar una extensión para administrar scripts de usuario si quieres instalar este script.

(Ya tengo un administrador de scripts de usuario, déjame instalarlo)

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión como Stylus para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

Necesitará instalar una extensión del gestor de estilos de usuario para instalar este estilo.

(Ya tengo un administrador de estilos de usuario, déjame instalarlo)

// ==UserScript==
// @name         lib:file opener
// @version      10
// @description  none
// @license      GPLv3
// @run-at       document-start
// @author       rssaromeo
// @match        *://*/*
// @include      *
// @tag          lib
// @exclude      /livereload.net\/files\/ffopen\/index.html$/
// @icon         data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAEgAAABICAMAAABiM0N1AAAAAXNSR0IB2cksfwAAAAlwSFlzAAAOxAAADsQBlSsOGwAAAHJQTFRFAAAAEIijAo2yAI60BYyuF4WaFIifAY6zBI2wB4usGIaZEYigIoiZCIyrE4igG4iYD4mjEomhFoedCoqpDIqnDomlBYyvE4efEYmiDYqlA42xBoytD4mkCYqqGYSUFYidC4qoC4upAo6yCoupDYqmCYur4zowOQAAACZ0Uk5TAO////9vr////1+/D/+/L+/Pf/////+f3///////H4////////+5G91rAAACgUlEQVR4nM2Y22KjIBCGidg1264liZqDadK03X3/V2wNKHMC7MpF/xthHD5mgERAqZhWhfYqH6K+Qf2qNNf625hCoFj9/gblMUi5q5jLkXLCKudgyiRm0FMK82cWJp1fLbV5VmvJbCIc0GCYaFqqlDJgADdBjncqAXYobm1xh72aFMflbysteFfdy2Yi1XGOm5HGBzQ1dq7TzEoxjeNTjQZb7VA3e1c7+ImgasAgQ9+xusNVNZIo5xmOMgihIS2PbCQIiHEUdTvhxCcS/kPomfFI2zHy2PkWmA6aNatIJpKFJyekyy02xh5Y3DI9T4aOT6VhIUrsNTFp1pf79Z4SIIVDegl6IJO6cHiL/GimIZDhgTu/BlYWCQzHMl0zBWT/T3KAhtxOuUB9FtBrpsz0RV4xsjHmW+UCaffcSy/5viMGer0/6HdFNMZBq/vjJL38H9Dqx4Fuy0Em12DbZy+9pGtiDijbglwAehyj11n0tRD3WUBm+lwulE/8h4BuA+iWAQQnteg2Xm63WQLTpnMnpjdge0Mgu/GRPsV4xdjQ94Lfi624fabhDkfUqIKNrM64Q837v8yL0prasepCgrtvw1sJpoqanGEX7b5mQboNW8eawXaWXTMfMGxub472hzWzHSn6Sg2G9+6TAyRruE71s+zAzjWaknoyJCQzwxrghH2k5FDT4eqWunuNxyN9QCGcxVod5oADbYnIUkDTGZEf1xDJnSFteQ3KdsT8zYDMQXcHxsevcLH1TrsABzkNPyA/L7b0jg704viMMlpQI96WsHknCt/3YH0kOEo9zcGkwrFK39ck72rmoehmKqo2RKlilzSy/nJKEV45CT38myJp456fezktHjN5aeMAAAAASUVORK5CYII=
// @grant        none
// @namespace https://greasyfork.org/users/1184528
// ==/UserScript==
;(() => {
  const a = loadlib("allfuncs")
  const progressBar = loadlib("progress bar")
  const run = {
    file: runfile,
    folder: runfolder,
    globals: window.ERwkOoQYn9C3jxDZdovIZoZ2DmGt5wKyTMPU2uck ?? [],
  }
  delete window.ERwkOoQYn9C3jxDZdovIZoZ2DmGt5wKyTMPU2uck
  ;(async () => {
    var cac = {}
    async function newglobaljs(name, func = (e) => e, newname) {
      if ((newname ?? name).startsWith("blob:http")) return
      var text = cac[name] ?? (await (await fetch(name)).text())
      if (newname) name = newname
      cac[name] ??= text
      run.globals.push({
        text: func(text),
        name: name,
      })
    }
    run.newglobaljs = newglobaljs
  })()
  function hashformat({ isglobal, name }) {
    const hashformat = "#__isglobal: filename"
    if (isglobal == true) isglobal = "global"
    if (isglobal == false) isglobal = "local"
    return _replaceall(hashformat, [
      ["isglobal", isglobal],
      ["filename", name],
    ])
  }

  loadlib("libloader").savelib("file opener", run)
  async function runfile(file) {
    file = await formatfiles(await file.getFile())
    replaceglobalurls(file)
    await updateglobals(file)
    newurl(file, file.format)
    return openfile(file, file.name)
  }
  async function updateglobals(file) {
    const tempglobals = JSON.stringify([
      ...run.globals.map((e) => {
        return { name: e.name, text: e.text }
      }),
    ])
    //       .replaceAll("<", "&lt;")
    //       .replaceAll("&", "&amp;")
    if (file.name.endsWith(".html"))
      file.text =
        `<script>window.ERwkOoQYn9C3jxDZdovIZoZ2DmGt5wKyTMPU2uck = ${tempglobals}<\/script>` +
        file.text
  }
  async function runfolder(folder, mainfile = "index.html") {
    var files = await getfilesfromfolder(folder)
    const name = files[0].path.match(/^([^\/]+)\//, "")[1]
    files = await formatfiles(files)

    setupget(files)
    var index = files.get(mainfile)
    if (!index) {
      error(
        `folder ${name} doesn't contain ${mainfile}, searching for index.html instead`
      )
      index = files.get("index.html")
    }
    if (!index)
      throw new Error(`folder ${name} doesn't contain index.html`)
    var htmls = files.get(/\.html/i)
    //     error(a(files.get(/\.png/i)[0].file).readfile('DataURL'))
    var BAR = new progressBar(0, files.length + htmls.length)
    {
      for (var i in files) {
        var file = files[i]
        BAR.set(i, file.name)
        newurl(file, file.format)
        if (Number(i) % 15 == 0) await a.wait(0)
      }
      var f = files.get(/\./)
      f = f.filter((e) => ["js", "css"].includes(e.extension))
      for (var i in f) {
        var e = f[i]
        if (Number(i) % 15 == 0) {
          BAR.set(Number(i), e.name)
          await a.wait(0)
        }
        replaceallurls(e, files)
        replaceglobalurls(e)
        newurl(e)
      }
      for (var i in htmls) {
        var e = htmls[i]
        if (Number(i) % 15 == 0) {
          BAR.set(Number(i) + files.length, e.name)
          await a.wait(0)
        }
        replaceallurls(e, files)
        replaceglobalurls(e)
        newurl(e, "text/html")
      }
    }
    //     warn(index, index.path.split("/"))
    replaceallurls(index, files, true)
    await updateglobals(index)
    newurl(index, "text/html")
    BAR.remove()
    return openfile(index, name)
  }
  function openfile(file, name) {
    name ??= file?.file?.name
    return file.url
  }
  function getallgoodpaths(file, files, lll) {
    var p = file.path.split("/")
    var n = p.pop()
    return files.map((e) => {
      if (!e.path) error(e, file)
      var path = e.path.split("/")
      var name = path.pop()
      if (same(p, path)) {
        return { ...e, path: name }
      }
      var newpath = ""
      var rs = false
      p.forEach((e, i) => {
        if (same(e, path[i]) && !rs) return
        rs = true
        newpath += "../"
      })
      path.push("")
      return {
        ...e,
        path: newpath + path.join("/") + name,
      }
    })
    function same(a, s) {
      return JSON.stringify(a) == JSON.stringify(s)
    }
  }
  function replaceallurls(file, files, lll) {
    if (file.text.startsWith("#redirect")) {
      var redir = file.text.match(/^#redirect (.*)/)[1]
      var redirfile = files.get(redir)
      if (!redirfile)
        throw new Error(
          `failed to redirect from ${file.name} to ${redir}`
        )
      file.text =
        file.text.replace(`#redirect ${redir}`, "") +
        "\n" +
        redirfile.text
    }
    var goodfiles = getallgoodpaths(file, files, lll)
    goodfiles.forEach(({ path, url }) => {
      file.text = file.text.replaceAll(
        new RegExp(`(['"])(?:\\.\\/)*${regescape(path)}\\1`, "gi"),
        `"${url}${hashformat({ isglobal: false, name: path })}"`
      )
    })
    replaceglobalurls(file)
  }
  function regescape(reg) {
    return reg.replaceAll(/[.*+?^${}()|[\]\\]/g, "\\$&")
  }
  function newurl(file, type) {
    type ??= file.format
    var blob =
      type && type.startsWith("image/")
        ? new Blob([file.file], { type })
        : new Blob([file.text], { type })
    file.url = URL.createObjectURL(blob)
    return file
  }
  async function replaceglobalurls(file) {
    run.globals.forEach((e) => {
      if (!e.regex)
        e.regex = new RegExp(
          `(['"])(?:\\.?\\.\\/)*${regescape(e.name)}\\1`,
          "gi"
        )
      if (!e.url)
        e.url = URL.createObjectURL(
          new Blob([e.text], { type: "text/javascript" })
        )
      file.text = file.text.replaceAll(
        e.regex,
        `"${e.url}${hashformat({ isglobal: true, name: e.name })}"`
      )
    })
    return file
  }
  async function formatfiles(files) {
    if (!a.gettype(files, "array")) return await format(files)
    return await Promise.all(files.map(format))
    async function format(file) {
      var data = await a.readfile(file)
      //       if(file.name.match(/\.(\w+)$/)?.[1]=='svg'){
      //         error(file)
      //       }
      return {
        name: file.name,
        text: data,
        path: file?.path?.replace?.(/^[^\/]+\//, ""),
        extension: file.name.match(/\.(\w+)$/)?.[1],
        format: {
          js: "text/javascript",
          html: "text/html",
          css: "text/css",
          jpg: "image/jpg",
          jpeg: "image/jpeg",
          png: "image/png",
          svg: "image/svg+xml",
        }[file.name.match(/\.(\w+)$/)?.[1]],
        file,
      }
    }
  }
  function setupget(files) {
    files.get = function (name, skip = 0) {
      if (a.gettype(name, "string"))
        return files.find((e) => {
          return e.path == name
        })
      else return files.filter((e) => name.test(e.path))
    }
  }

  async function getfilesfromfolder(
    dirHandle,
    path = dirHandle.name
  ) {
    const dirs = []
    const files = []
    //     warn(path)
    for await (const entry of dirHandle.values()) {
      const nestedPath = `${path}/${entry.name}`
      if (
        nestedPath.startsWith(dirHandle.name + "/codemirror/mode/ja")
      )
        error(nestedPath, entry)
      if (entry.kind === "file") {
        files.push(
          entry.getFile().then((file) => {
            file.directoryHandle = dirHandle
            file.handle = entry
            Object.defineProperty(file, "path", {
              configurable: true,
              enumerable: true,
              get: () => nestedPath,
            })
            return Object.defineProperty(file, "webkitRelativePath", {
              configurable: true,
              enumerable: true,
              get: () => nestedPath,
            })
          })
        )
      } else if (entry.kind === "directory") {
        // warn(entry, nestedPath)
        dirs.push(getfilesfromfolder(entry, nestedPath))
      } else {
        error(entry.kind)
      }
    }
    return [
      ...(await Promise.all(dirs)).flat(),
      ...(await Promise.all(files)),
    ]
  }
  function _replaceall(q, w, e) {
    switch (a.gettype(w, "array") + " " + a.gettype(e, "array")) {
      case "true true":
        if (e.length == w.length) {
          w.forEach((ww, i) => {
            q = q.replaceAll(ww, e[i])
          })
          return q
        }
        throw new Error(
          "when both are arrays the length must be the same"
        )
        break
      case "true false":
        if (a.gettype(w[0], "array")) {
          w.forEach(([ww, e]) => {
            q = q.replaceAll(ww, e)
          })
        } else {
          w.forEach((ww) => {
            q = q.replaceAll(ww, e)
          })
        }
        return q
        break
      case "false false":
        return q.replaceAll(w, e)
        break
    }
  }
})()