<script>
  import { onMount } from "svelte";
  import { selectedFilter, nodes, inputs, previewCommand } from "./stores.js";
  import Filter from "./Filter.svelte";
  import FilterPicker from "./FilterPicker.svelte";
  import Graph from "./Graph.svelte";
  import { FFmpeg } from "@ffmpeg/ffmpeg";
  import { fetchFile, toBlobURL } from "@ffmpeg/util";

  const isChrome = navigator.userAgent.match(/chrome|chromium|crios/i);
  const baseURL = `https://unpkg.com/@ffmpeg/core${!isChrome ? "-mt" : ""}@0.12.2/dist/esm`;
  // const baseURL = "";
  const TIMEOUT = 40000;

  const ffmpeg = new FFmpeg();

  let videoValue = "/" + $inputs[0].name;
  let ffmpegLoaded = false;
  let rendering = false;
  let log = "";
  let logbox;
  let commandRef;
  let vidPlayerRef;

  function render() {
    transcode();
  }

  function copyCommand() {
    commandRef.select();
    document.execCommand("copy");
  }

  async function transcode() {
    videoValue = null;
    rendering = true;
    try {
      for (let vid of $inputs) {
        await ffmpeg.writeFile(vid.name, await fetchFile("/" + vid.name));
      }
      let clist = $previewCommand
        .replaceAll('"', "")
        .replace("ffmpeg", "")
        .split(" ")
        .filter((i) => i.trim() != "");
			clist.splice(clist.length-1, 0, "-pix_fmt")
			clist.splice(clist.length-1, 0, "yuv420p")
      console.log("command", clist);
      await ffmpeg.exec(clist, TIMEOUT);
      const data = await ffmpeg.readFile("out.mp4");
      rendering = false;
      videoValue = URL.createObjectURL(new Blob([data.buffer], { type: "video/mp4" }));
    } catch (e) {
      console.log(e);
      log += "Failed";
    }
    rendering = false;
  }

  async function loadFFmpeg() {
    ffmpeg.on("log", ({ message: msg }) => {
      log += msg + "\n";
      logbox.scrollTop = logbox.scrollHeight;
    });
    if (isChrome) {
      await ffmpeg.load({
        coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
        wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"),
        // workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"),
      });
    } else {
      await ffmpeg.load({
        coreURL: await toBlobURL(`${baseURL}/ffmpeg-core.js`, "text/javascript"),
        wasmURL: await toBlobURL(`${baseURL}/ffmpeg-core.wasm`, "application/wasm"),
        workerURL: await toBlobURL(`${baseURL}/ffmpeg-core.worker.js`, "text/javascript"),
      });
    }
    ffmpegLoaded = true;
  }

  onMount(async () => {
		vidPlayerRef.volume = 0.5;
    loadFFmpeg();
  });
</script>

<main>
  <section class="header">
    <h1>FFmpeg Explorer</h1>
    <div class="help">
      <p>
        A tool to help you explore <a href="https://www.ffmpeg.org/" target="_blank">FFmpeg</a>
        filters. To use:
      </p>
      <ol>
        <li>Add filters from the list on the left.</li>
        <li>Click on filters in the center panel to edit options.</li>
        <li>Hit "render" to preview the output in browser.</li>
        <li>For more complex filtergraphs, disable "automatic layout."</li>
      </ol>
      <p>
        Note: this is a work in progress, many things may still be broken! If it hangs/crashes
        refresh the page. Post issues/feedback to
        <a href="https://github.com/antiboredom/ffmpeg-explorer/" target="_blank">GitHub</a>. By
        <a href="https://lav.io" target="_blank">Sam Lavigne</a>.
      </p>
    </div>
  </section>
  <!-- {message} -->
  <section class="command">
    <h3>Output Command</h3>
    <div class="inner-command">
      <textarea
        readonly
        class="actual-command"
        bind:this={commandRef}
        on:click={() => commandRef.select()}>{$previewCommand}</textarea
      >
      <div>
        <button on:click={copyCommand}>Copy Command</button>
      </div>
    </div>
  </section>

  <section class="log">
    <h3>FFmpeg Log</h3>
    <textarea readonly class="the-log" bind:this={logbox}>{log}</textarea>
  </section>

  <section class="preview">
    <div class="vid-holder">
      {#if rendering}
        <div class="rendering-video"><span>Rendering...</span></div>
      {/if}
      <video bind:this={vidPlayerRef} controls src={videoValue} />
    </div>
    <div style="text-align: right;padding-top:5px;">
      <button on:click={render} disabled={!ffmpegLoaded || rendering}>
        {#if ffmpegLoaded}
          {#if rendering}
            Rendering...
          {:else}
            Render Preview
          {/if}
        {:else}
          Loading ffmpeg
        {/if}
      </button>
    </div>
  </section>

  <section class="filters">
    <h3>Filters (click to add)</h3>
    <div class="filter-picker">
      <FilterPicker select={"video"} />
    </div>
  </section>

  <section class="graph">
    <Graph />
  </section>

  <section class="filter-editor">
    {#if $selectedFilter && $nodes.length > 0 && $nodes[$selectedFilter]}
      <Filter bind:filter={$nodes[$selectedFilter].data} />
    {/if}
  </section>
</main>

<style>
  main {
    display: grid;
    grid-template-columns: 300px 1fr 1fr 1fr 1fr 300px;
    grid-template-areas:
      "hdr log log log prv prv"
      "hdr cmd cmd cmd prv prv"
      "flt gra gra gra gra edt";
    /* grid-template-rows: 16% 17% 77%; */
    grid-template-rows: 15% 15% calc(70% - 40px);
    padding: 10px;
    grid-gap: 20px;
    height: 100vh;
    align-items: stretch;
  }

  section {
    /* border: 1px solid #999; */
    /* box-shadow: 7px 7px 0px rgba(0, 0, 0, 0.7); */
    border: 1px solid var(--b1);
    box-shadow: 7px 7px var(--b2);
    padding: 10px;
    background-color: rgb(245, 245, 245);
  }

  .header {
    grid-area: hdr;
    overflow: scroll;
  }

  .command {
    grid-area: cmd;
    display: flex;
    flex-direction: column;
  }

  .preview {
    grid-area: prv;
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: stretch;
    justify-content: stretch;
  }

  .preview video {
    width: 100%;
    /* object-fit: contain; */
    flex: 1;
  }

  .vid-holder {
    flex: 1;
    display: flex;
    width: 100%;
    height: calc(100% - 30px);
  }

  .log {
    grid-area: log;
    display: flex;
    flex-direction: column;
  }

  .filters {
    grid-area: flt;
    display: flex;
    flex-direction: column;
  }

  .graph {
    grid-area: gra;
    display: flex;
  }

  .filter-editor {
    grid-area: edt;
    display: flex;
  }

  .filter-picker {
    /* max-height: 500px; */
    /* width: 400px; */
    top: 0;
    left: 0;
    overflow: scroll;
    background-color: #fff;
  }

  h1,
  h3 {
    font-weight: normal;
    margin: 0;
    padding: 0;
  }
  h1 {
    margin-bottom: 5px;
  }
  h3 {
    margin-bottom: 10px;
  }
  .header p {
    margin: 0;
  }

  .inner-command {
    display: flex;
    align-items: center;
    flex: 1;
  }

  textarea {
    outline: none;
    -webkit-box-shadow: none;
    -moz-box-shadow: none;
    box-shadow: none;
    resize: none;
  }

  .actual-command {
    border: none;
    margin-right: 10px;
    flex: 1;
    font: inherit;
    padding: 5px;
    height: 100%;
  }
  .the-log {
    border: none;
    resize: none;
    padding: 5px;
    flex: 1;
  }
  .rendering-video {
    position: absolute;
    width: 100%;
    height: 100%;
    z-index: 2;
    background-color: rgba(255, 255, 255, 0.8);
    top: 0;
    left: 0;
    display: grid;
    align-items: center;
    justify-content: center;
  }

  .help {
    font-size: 0.9em;
  }
  ol {
    margin: 5px 0px;
    padding-left: 20px;
  }
  ol li {
    margin-bottom: 5px;
  }

  @media only screen and (max-width: 1400px) {
  }

  @media only screen and (max-width: 600px) {
    main {
      grid-template-areas:
        "hdr hdr hdr"
        "cmd cmd cmd"
        "prv prv prv"
        "log log log"
        "flt flt flt"
        "gra gra gra"
        "edt edt edt";
      grid-gap: 5px;
      padding: 10px;
      height: auto;
      grid-template-columns: repeat(3, 1fr);
      grid-template-rows: auto;
    }
    .graph {
      height: 50vh;
    }
    .command {
      margin: 0;
      margin-bottom: 10px;
    }
    section {
      box-shadow: none;
      margin-bottom: 10px;
      padding: 10px;
      box-shadow: 2px 2px 0px var(--b2);
    }
    .filter-picker {
      width: 100%;
      margin-bottom: 20px;
      height: 300px;
      position: static;
    }
  }
</style>
