@Override
  public void donePlaying(DLNAMediaInfo media, DLNAResource resource) {
    // currently only for videofiles
    if (enabledMV && resource.getType() == Format.VIDEO) {
      // get path information
      Path infoFilePath = Paths.get(resource.getSystemName());
      String folderName = infoFilePath.getParent().toString();
      String infoFile = folderName + "/.viewstatus";
      String infoKey = resource.getName();

      // create handler for properties
      Properties props = new Properties();

      double fileViewPercentage = 0;

      try {
        props.load(new FileInputStream(infoFile)); // load the viewinfo file (if any)
        fileViewPercentage = Integer.parseInt(props.getProperty(infoKey, "0"));
      } catch (IOException e) {
        log.error("viewinfo at " + infoFile + " file does not yet exist");
      }

      double playLengthSec = 0; // total length of the file

      /**
       * @TODO: calculation below should work without startdate. Is it possible to get the exact
       * number of seconds the file was stopped?
       */
      playLengthSec = (int) (new Date().getTime() - startDates.poll().getTime()) / 1000;

      double fullLengthSec = media.getDurationInSeconds();

      if (fullLengthSec > 0) {
        double currentFileViewPercentage = (playLengthSec / fullLengthSec) * 100;

        // if the watched percentage is bigger than in the viewinfo file, write it to viewinfo
        if (currentFileViewPercentage > fileViewPercentage) {
          fileViewPercentage = Math.min(100, currentFileViewPercentage);
          props.setProperty(infoKey, Integer.toString((int) fileViewPercentage));

          try {
            props.store(new FileOutputStream(infoFile), null);

            // update the thumbnail
            media.setThumb(null);
            InputFile input = new InputFile();
            input.setFile(((RealFile) resource).getFile());
            media.generateThumbnail(input, resource.getExt(), resource.getType());

          } catch (IOException e) {
            logExeptionError(e);
          }
        }
      }
    }
  }
  @Override
  public void handle(HttpExchange t) throws IOException {
    if (RemoteUtil.deny(t)) {
      throw new IOException("Access denied");
    }
    RootFolder root = parent.getRoot(RemoteUtil.userName(t), t);
    if (root == null) {
      throw new IOException("Unknown root");
    }
    Headers h = t.getRequestHeaders();
    for (String h1 : h.keySet()) {
      LOGGER.debug("key " + h1 + "=" + h.get(h1));
    }
    String id = RemoteUtil.getId(path, t);
    id = RemoteUtil.strip(id);
    RendererConfiguration r = render;
    if (render == null) {
      r = root.getDefaultRenderer();
    }
    DLNAResource dlna = root.getDLNAResource(id, r);
    if (dlna == null) {
      // another error
      LOGGER.debug("media unkonwn");
      throw new IOException("Bad id");
    }
    if (!dlna.isCodeValid(dlna)) {
      LOGGER.debug("coded object with invalid code");
      throw new IOException("Bad code");
    }
    DLNAMediaSubtitle sid = null;
    long len = dlna.length();
    Range range = RemoteUtil.parseRange(t.getRequestHeaders(), len);
    String mime = root.getDefaultRenderer().getMimeType(dlna.mimeType());
    // DLNAResource dlna = res.get(0);
    WebRender render = (WebRender) r;
    DLNAMediaInfo m = dlna.getMedia();
    if (m == null) {
      m = new DLNAMediaInfo();
      dlna.setMedia(m);
    }
    if (mime.equals(FormatConfiguration.MIMETYPE_AUTO) && m.getMimeType() != null) {
      mime = m.getMimeType();
    }
    int code = 200;
    dlna.setDefaultRenderer(r);
    if (dlna.getFormat().isVideo()) {
      if (flash) {
        mime = "video/flash";
      } else if (!RemoteUtil.directmime(mime) || RemoteUtil.transMp4(mime, m)) {
        mime = render != null ? render.getVideoMimeType() : RemoteUtil.transMime();
        if (FileUtil.isUrl(dlna.getSystemName())) {
          dlna.setPlayer(new FFmpegWebVideo());
        } else {
          dlna.setPlayer(new FFMpegVideo());
        }
        // code = 206;
      }
      if (PMS.getConfiguration().getWebSubs()
          && dlna.getMediaSubtitle() != null
          && dlna.getMediaSubtitle().isExternal()) {
        // fetched on the side
        sid = dlna.getMediaSubtitle();
        dlna.setMediaSubtitle(null);
      }
    }

    if (!RemoteUtil.directmime(mime) && dlna.getFormat().isAudio()) {
      dlna.setPlayer(new FFmpegAudio());
      code = 206;
    }

    m.setMimeType(mime);
    LOGGER.debug("dumping media " + mime + " " + dlna);
    InputStream in = dlna.getInputStream(range, root.getDefaultRenderer());
    Headers hdr = t.getResponseHeaders();
    hdr.add("Content-Type", mime);
    hdr.add("Accept-Ranges", "bytes");
    if (range != null) {
      long end = range.asByteRange().getEnd();
      long start = range.asByteRange().getStart();
      String rStr = start + "-" + end + "/*";
      hdr.add("Content-Range", "bytes " + rStr);
      if (start != 0) {
        code = 206;
      }
    }
    hdr.add("Server", PMS.get().getServerName());
    hdr.add("Connection", "keep-alive");
    t.sendResponseHeaders(code, 0);
    OutputStream os = t.getResponseBody();
    render.start(dlna);
    if (sid != null) {
      dlna.setMediaSubtitle(sid);
    }
    RemoteUtil.dump(in, os, render);
  }