docs: function getMedia (uri, cert, mode, user, tag, path, safe, buffers) {
    return new Promise(function (resolve, reject) {
      if (mode === 'api') {
        balance(user).then((ret) => {
          debug('got balance')
          return ret
        }).then(function (ret) {
          var fn = getFnFromURI(uri, 'qpm_media')
          debug('uri', uri)
          debug('fn', fn)
          debug('ret', ret)
          debug('cost', cost)
          debug(qpm_media.getLastFragment)
          if (ret >= cost) {
            if (fn === 'qpm_media.getLastFragment') {
              var params = {}
              if (tag) {
                params.tag = tag
              }
              if (user) {
                params.webid = user
              }
              if (safe && safe === 'off') {
                params.safe = 0
              } else {
                params.safe = 1
              }
              qpm_media.getLastFragment(params).then(function (row) {
                row.conn.close()
                resolve(row.ret[0][0])
  
                // pay
                var credit = {}
                credit['https://w3id.org/cc#source'] = user
                credit['https://w3id.org/cc#amount'] = cost
                credit['https://w3id.org/cc#currency'] = 'https://w3id.org/cc#bit'
                credit['https://w3id.org/cc#destination'] = workbot
                pay(credit)
              }).catch(function (err) {
                row.conn.close()
                reject(err)
              })
            } else if (fn === 'qpm_media.getRatedFragment') {
              var params = {}
              if (tag) {
                params.tag = tag
              }
              if (user) {
                params.webid = user
              }
              if (safe && safe === 'off') {
                params.safe = 0
              } else {
                params.safe = 1
              }
              qpm_media.getRatedFragment(params).then(function (row) {
                row.conn.close()
                resolve(row.ret[0][0])
  
                // pay
                var credit = {}
                credit['https://w3id.org/cc#source'] = user
                credit['https://w3id.org/cc#amount'] = cost
                credit['https://w3id.org/cc#currency'] = 'https://w3id.org/cc#bit'
                credit['https://w3id.org/cc#destination'] = workbot
                pay(credit)
              }).catch(function (err) {
                row.conn.close()
                reject(err)
              })
            } else if (fn === 'qpm_media.getRandomUnseenFragment') {
              var params = {}
              if (tag) {
                params.tag = tag
              }
              if (user) {
                params.webid = user
              }
              if (safe && safe === 'off') {
                params.safe = 0
              } else {
                params.safe = 1
              }
              qpm_media.getRandomUnseenFragment(params).then(function (row) {
                row.conn.close()
                resolve(row.ret[0][0])
  
                // pay
                var credit = {}
                credit['https://w3id.org/cc#source'] = user
                credit['https://w3id.org/cc#amount'] = cost
                credit['https://w3id.org/cc#currency'] = 'https://w3id.org/cc#bit'
                credit['https://w3id.org/cc#destination'] = workbot
                pay(credit)
              }).catch(function (err) {
                row.conn.close()
                reject(err)
              })
            }
          } else {
            reject(new Error('not enough funds'))
          }
        })
      } else if (mode === 'buffer') {
        var fn = getFnFromURI(uri, 'qpm_media')
        debug('fn', fn)
  
        if (fn === 'qpm_media.getLastFragment') {
          type = 0
  
          balance(user).then((ret) => {
            return ret
          }).then(function (ret) {
            if (ret >= cost) {
              var bufferPath = root + '/../' + path
              var files = fs.readdirSync(bufferPath)
  
              var f = []
              for (var i = 0; i < files.length; i++) {
                var file = files[i]
                if (file && /.ttl$/.test(file)) {
                  continue
                }
                var mtime = fs.statSync(bufferPath + file).mtime.getTime()
                var start = getStart(file)
                var type = getType(file)
                var fileURI = getFile(file)
                f.push({ 'mtime': mtime, 'uri': file, 'file': fileURI, 'start': start, 'type': type })
              }
  
              f.sort(sortFiles)
              debug('f', f)
  
              var current = getCurrentVideo(0, f, buffers)
              debug('current', current, f[current], f[current - 1].uri)
  
              files.sort(function (a, b) {
                return fs.statSync(bufferPath + b).mtime.getTime() -
                        fs.statSync(bufferPath + a).mtime.getTime()
              })
              var file = getNextFile(files, type)
              file = f[current].uri
  
              debug('file', file)
              if (files && file) {
                var duration = 15
                var nextFile = bufferPath + file
                var start = file.split(',')[0]
                var end = parseInt(start)
                var cacheURI = removeComma(file)
                debug('removed comma', cacheURI)
                cacheURI = urlencode.decode(cacheURI)
                cacheURI = removeMp4(cacheURI)
                var ret = { 'uri': cacheURI, 'cacheURI': cacheURI, 'end': end }
                debug(ret)
                var lastFile = bufferPath + getLastFile(files, type)
                resolve(ret)
              } else {
                reject(new Error('nothing in buffer'))
              }
  
              setTimeout(() => {
                try {
                  // fs.unlinkSync(lastFile)
                } catch (e) {
                  console.error(e)
                }
  
                var fn = getFnFromURI(uri)
                var params = {}
                if (tag) {
                  params.tag = tag
                }
                if (user) {
                  params.webid = user
                }
                if (safe && safe === 'off') {
                  params.safe = 0
                } else {
                  params.safe = 1
                }
                qpm_media.getLastFragment(params).then(function (row) {
                  debug('getLastFragment', row.ret)
                  debug('files', files)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 1))
                  splitVideo(start, bufferPath, path, row, true, user, 0, duration)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 2))
                  var candidate = start + ',' + type + ',' + urlencode(row.ret[0][0].uri) + '.mp4'
                  debug('candidate', candidate)
                  if (files.indexOf(candidate) !== -1) {
                    debug('candidate is in files')
                  } else {
                    debug('candidate is NOT in files')
                    if (parseInt(buffers) === 2) {
                      splitVideo(start, bufferPath, path, row, true, user, 0, duration)
                    }
                  }
                  // var buffers = 2
                })
              }, 500)
            } else {
              reject(new Error('not enough funds'))
            }
          })
        } else if (fn === 'qpm_media.getRatedFragment') {
          type = 1
  
          balance(user).then((ret) => {
            return ret
          }).then(function (ret) {
            if (parseInt(ret) >= parseInt(cost)) {
              debug('balance', parseInt(ret), 'cost', parseInt(cost), 'path', path)
  
              var bufferPath = root + '/..' + path
              debug('buffer', bufferPath)
              var files = fs.readdirSync(bufferPath)
              files.sort(function (a, b) {
                return fs.statSync(bufferPath + b).mtime.getTime() -
                        fs.statSync(bufferPath + a).mtime.getTime()
              })
              var file = getNextFile(files, type)
              debug('next file', file)
              if (files && file) {
                var file = getNextFile(files, type)
                var nextFile = bufferPath + file
                var start = file.split(',')[0]
                var end = parseInt(start)
                var cacheURI = removeComma(file)
                debug('removed comma', cacheURI)
                cacheURI = urlencode.decode(cacheURI)
                cacheURI = removeMp4(cacheURI)
                var ret = { 'uri': cacheURI, 'cacheURI': cacheURI, 'end': end }
                debug(ret)
                var lastFile = bufferPath + getLastFile(files, type)
                resolve(ret)
              } else {
                reject(new Error('nothing in buffer'))
              }
  
              setTimeout(() => {
                try {
                  // fs.unlinkSync(lastFile)
                } catch (e) {
                  console.error(e)
                }
  
                var fn = getFnFromURI(uri)
                fn = qpm_media.getRatedFragment
                params = {}
                if (tag) {
                  fn = qpm_media.getTaggedFragment
                  params.tag = tag
                }
                if (user) {
                  params.webid = user
                }
                if (safe && safe === 'off') {
                  params.safe = 0
                } else {
                  params.safe = 1
                }
                fn(params).then(function (row) {
                  /*
                  debug('unseen', row.ret)
                  var start    = row.ret[0][0].end
                  var cacheURI = row.ret[0][0].cacheURI || row.ret[0][0].uri
                  var filePath = cacheURI.substr('file://'.length)
                  var destination = start + ',' + type + ',' + urlencode(cacheURI) + '.mp4'
                  var subtitles = row.ret[0][0].subtitlesURI || ''
                  subtitlesCmd = ''
                  if (/file:\/\//.test(subtitles)) {
                    subtitles = subtitles.substr(7)
                  }
                  if (subtitles) {
                    if (subtitles) {
                      var charenc = row.ret[0][0].charenc
                      var subtitlesCmd = ' -vf subtitles="' + subtitles + '"'
                      if (charenc) {
                        subtitlesCmd += ':charenc=' + charenc + ' '
                      }
  
                    }
                  }
                  console.log('copying', filePath)
                  */
  
                  var start = row.ret[0][0].end
                  var duration = 15
  
                  splitVideo(start, bufferPath, path, row, true, user, 1, duration)
  
                  /*
                  var cmd = 'sleep 1 ; ffmpeg -i "' + filePath + '" -ss '+ start +' -movflags faststart -strict -2  ' + subtitlesCmd + ' -t 00:00:15 "' + bufferPath + destination + '"'
  
                  debug(cmd)
  
                  exec(cmd, function (err) {
                    if (err) {
                      console.error(err)
                    } else {
  
                      hook(root + '/..' + path + '../hook.sh', destination)
  
                      console.log("success!")
                      // pay
                      var credit = {}
                      credit['https://w3id.org/cc#source'] = user
                      credit['https://w3id.org/cc#amount'] = cost
                      credit['https://w3id.org/cc#currency'] = 'https://w3id.org/cc#bit'
                      credit['https://w3id.org/cc#destination'] = workbot
                      pay(credit)
  
                      if (row && row.conn) {
                        row.conn.close()
                      }
                    }
  
                  })
                  */
                })
  
                var params = {}
                if (tag) {
                  params.tag = tag
                }
                if (user) {
                  params.webid = user
                }
                if (safe && safe === 'off') {
                  params.safe = 0
                } else {
                  params.safe = 1
                }
                qpm_media.getLastFragment(params).then(function (row) {
                  debug('getLastFragment', row.ret)
                  debug('files', files)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 1))
                  splitVideo(start, bufferPath, path, row, true, user, 0, duration)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 2))
                  var candidate = start + ',' + type + ',' + urlencode(row.ret[0][0].uri) + '.mp4'
                  debug('candidate', candidate)
                  if (files.indexOf(candidate) !== -1) {
                    debug('candidate is in files')
                  } else {
                    debug('candidate is NOT in files')
                    if (parseInt(buffers) === 2) {
                      splitVideo(start, bufferPath, path, row, true, user, 0, duration)
                    }
                  }
  
                  /*
                  debug('unseen', row.ret)
                  var start    = row.ret[0][0].end
                  var cacheURI = row.ret[0][0].cacheURI || row.ret[0][0].uri
                  var filePath = cacheURI.substr('file://'.length)
                  var destination =  start + ',' + 0 + ',' + urlencode(cacheURI) + '.mp4'
                  var subtitles = row.ret[0][0].subtitlesURI || ''
                  subtitlesCmd = ''
                  if (/file:\/\//.test(subtitles)) {
                    subtitles = subtitles.substr(7)
                  }
                  if (subtitles) {
                    if (subtitles) {
                      var charenc = row.ret[0][0].charenc
                      var subtitlesCmd = ' -vf subtitles="' + subtitles + '"'
                      if (charenc) {
                        subtitlesCmd += ':charenc=' + charenc + ' '
                      }
  
                    }
                  }
                  console.log('copying', filePath)
                  var start = row.ret[0][0].end
                  var duration = 15
  
                  splitVideo(filePath, start, subtitlesCmd, bufferPath, destination, path, row, false, user)
  
                  if ( parseInt(buffers) === 2 ) {
                    setTimeout(function() {
                      var destination =  ( start + duration ) + ',' + 0 + ',' + urlencode(cacheURI) + '.mp4'
                      splitVideo(filePath, start + duration, subtitlesCmd, bufferPath, destination, path, row, false, user)
                    }, duration * 500)
                  }
                  */
  
                  /*
                  var cmd = 'ffmpeg -i "' + filePath + '" -ss '+ start +' -movflags faststart -strict -2  ' + subtitlesCmd + ' -t 00:00:15 "' + bufferPath + destination + '"'
                  debug(cmd)
  
                  exec(cmd, function (err) {
                    if (err) {
                      console.error(err)
                    } else {
  
                      hook(root + '/..' + path + '../hook.sh', destination)
  
                      console.log("success!")
  
                      if (row && row.conn) {
                        row.conn.close()
                      }
                    }
  
                  })
                  */
                })
              }, 500)
            } else {
              reject(new Error('not enough funds'))
            }
          })
        } else if (fn === 'qpm_media.getRandomUnseenFragment') {
          type = 2
  
          balance(user).then((ret) => {
            return ret
          }).then(function (ret) {
            if (ret >= cost) {
              var bufferPath = root + '/..' + path
              debug('bufferPath', bufferPath)
              var files = fs.readdirSync(bufferPath)
              files.sort(function (a, b) {
                return fs.statSync(bufferPath + b).mtime.getTime() -
                        fs.statSync(bufferPath + a).mtime.getTime()
              })
              var file = getNextFile(files, type)
              if (files && file) {
                var file = getNextFile(files, type)
                var nextFile = bufferPath + file
                var start = file.split(',')[0]
                var end = parseInt(start)
                var cacheURI = removeComma(file)
                debug('removed comma', cacheURI)
                cacheURI = urlencode.decode(cacheURI)
                cacheURI = removeMp4(cacheURI)
                var ret = { 'uri': cacheURI, 'cacheURI': cacheURI, 'end': end }
                debug(ret)
                var lastFile = bufferPath + getLastFile(files, type)
                resolve(ret)
              } else {
                reject(new Error('nothing in buffer'))
              }
  
              setTimeout(() => {
                try {
                  // fs.unlinkSync(lastFile)
                } catch (e) {
                  console.error(e)
                }
  
                var fn = getFnFromURI(uri)
                var params = {}
                if (tag) {
                  params.tag = tag
                }
                if (user) {
                  params.webid = user
                }
                if (safe && safe === 'off') {
                  params.safe = 0
                } else {
                  params.safe = 1
                }
                debug('play.js', params, safe)
                qpm_media.getRandomUnseenFragment(params).then(function (row) {
                  debug('getRandomUnseenFragment', row.ret)
  
                  var start = 0
                  var duration = 15
  
                  splitVideo(start, bufferPath, path, row, true, user, 2, duration)
  
                  /*
                  var cmd = 'ffmpeg -i "' + filePath + '" -ss '+ start +' -movflags faststart -strict -2 ' + subtitlesCmd + ' -t 00:00:15 "' + bufferPath + destination + '"'
                  debug(cmd)
  
                  exec(cmd, function (err) {
                    if (err) {
                      console.error(err)
                    } else {
  
                      hook(root + '/..' + path + '../hook.sh', destination)
  
                      // pay
                      var credit = {}
                      credit['https://w3id.org/cc#source'] = user
                      credit['https://w3id.org/cc#amount'] = cost
                      credit['https://w3id.org/cc#currency'] = 'https://w3id.org/cc#bit'
                      credit['https://w3id.org/cc#destination'] = workbot
                      pay(credit)
  
                      if (row && row.conn) {
                        row.conn.close()
                      }
                    }
  
                  })
                  */
                })
  
                debug('now getting last fragment seen')
                var params = {}
                if (tag) {
                  params.tag = tag
                }
                if (user) {
                  params.webid = user
                }
                if (safe && safe === 'off') {
                  params.safe = 0
                } else {
                  params.safe = 1
                }
                qpm_media.getLastFragment(params).then(function (row) {
                  debug('getLastFragment', row.ret)
                  debug('files', files)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 1))
                  splitVideo(start, bufferPath, path, row, true, user, 0, duration)
  
                  var duration = 15
                  var start = parseInt(row.ret[0][0].end) + (duration * (buffers - 2))
                  var candidate = start + ',' + type + ',' + urlencode(row.ret[0][0].uri) + '.mp4'
                  debug('candidate', candidate)
                  if (files.indexOf(candidate) !== -1) {
                    debug('candidate is in files')
                  } else {
                    debug('candidate is NOT in files')
                    if (parseInt(buffers) === 2) {
                      splitVideo(start, bufferPath, path, row, true, user, 0, duration)
                    }
                  }
  
                  /*
                  debug('unseen', row.ret)
                  var start    = row.ret[0][0].end
                  var cacheURI = row.ret[0][0].cacheURI || row.ret[0][0].uri
                  var filePath = cacheURI.substr('file://'.length)
                  var destination =  start + ',' + 0 + ',' + urlencode(cacheURI) + '.mp4'
                  */
                  /*
                  var subtitles = row.ret[0][0].subtitlesURI || ''
                  subtitlesCmd = ''
                  if (/file:\/\//.test(subtitles)) {
                    subtitles = subtitles.substr(7)
                  }
                  if (subtitles) {
                    if (subtitles) {
                      var charenc = row.ret[0][0].charenc
                      var subtitlesCmd = ' -vf subtitles="' + subtitles + '"'
                      if (charenc) {
                        subtitlesCmd += ':charenc=' + charenc + ' '
                      }
  
                    }
                  }
                  */
                 /*
                  console.log('copying', filePath)
                  console.log('buffers', buffers)
                  var duration = 15
  
                  splitVideo(filePath, start, subtitlesCmd, bufferPath, destination, path, row, false, user)
  
                  if ( parseInt(buffers) === 2 ) {
                    setTimeout(function() {
                      var destination =  ( start + duration ) + ',' + 0 + ',' + urlencode(cacheURI) + '.mp4'
                      splitVideo(filePath, start + duration, subtitlesCmd, bufferPath, destination, path, row, false, user)
                    }, duration * 500)
                  }
                  */
                  /*
                  var cmd = 'ffmpeg -i "' + filePath + '" -ss '+ row.ret[0][0].end +' -movflags faststart -strict -2  ' + subtitlesCmd + ' -t 00:00:15 "' + bufferPath + destination + '"'
                  debug(cmd)
  
                  exec(cmd, function (err) {
                    if (err) {
                      console.error(err)
                    } else {
  
                      hook(root + '/..' + path + '../hook.sh', destination)
  
                      console.log("success!")
  
                      if (row && row.conn) {
                        row.conn.close()
                      }
                    }
  
                  })
                  */
                })
              }, 500)
            } else {
              reject(new Error('not enough funds'))
            }
          })
        }
      } else if (mode === 'http') {
        var cookiePath = __dirname + '/../data/cookie.json'
  
        var cookies = readCookie(cookiePath)
  
        if (cookies) {
          options.headers['Set-Cookie'] = 'connect.sid=' + sid + '; Path=/; HttpOnly; Secure'
        }
  
        var options = {
          url: uri,
          key: fs.readFileSync(cert),
          cert: fs.readFileSync(cert),
          headers: { // We can define headers too
            'Accept': 'application/json'
          }
        }
  
        request.get(options, function (error, response, body) {
          writeCookie(response, cookiePath)
  
          if (!error && response.statusCode == 200) {
            json = JSON.parse(body)
            resolve(json)
          } else {
            reject(error)
          }
        })
      }
    })
  }