summaryrefslogtreecommitdiff
path: root/app/client/common/fileViewer.component.js
blob: b1cabd4ce8fdcd5d56fcf7f42c34ece6ffcfc4f4 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
import { h, Component } from 'preact'
import { connect } from 'react-redux'

import actions from '../actions'

const image_types = {
  'jpg': 'image/jpeg',
  'jpeg': 'image/jpeg',
  'png': 'image/png',
  'gif': 'image/gif',
}

const audio_types = {
  'wav': 'audio/wav',
  'mp3': 'audio/mp3',
  'flac': 'audio/flac',
  'aiff': 'audio/aiff',
}

const video_types = {
  'mp4': 'video/mp4',
}

class FileViewer extends Component {
  state = {
    loading: false,
    stale: false,
    buffer: {}
  }

  fetch() {
    const { file, path } = this.props
    if (!file) return
    if (this.state.loading) {
      this.setState({ stale: true })
      return
    }
    const fn = [path || file.path, file.name].join('/').replace('//','/')
    console.log('fetch file', fn)
    const { tool: module } = this.props.app
    this.setState({ buffer: null, loading: true })
    actions.socket.read_file({ module, fn }).then(buffer => {
      console.log('fetched buffer')
      const { stale } = this.state
      this.setState({ buffer, loading: false, stale: false, }, () => {
        if (stale) {
          console.log('stale, fetching...')
          this.fetch()
        }
      })
    })
  }

  componentDidMount(){
    this.fetch()
  }

  componentDidUpdate(nextProps){
    if (this.props.file !== nextProps.file) {
      this.fetch()
    }
  }

  render() {
    const { file } = this.props
    if (!file) {
      return <div className='fileViewer'></div>
    }
    const { loading, buffer } = this.state
    if (loading) {
      return <div className='fileViewer'>Loading...</div>
    }
    const {
      error,
      name, path,
      date, size,
      buf,
    } = buffer
    if (error) {
      return <div className='fileViewer'>{error}</div>
    }
    if (!name) {
      return <div className='fileViewer'></div>
    }
    if (!buf) {
      return <div className='fileViewer'>File empty</div>
    }
    const ext = extension(name)
    let tag;
    if (ext in image_types) {
      tag = <img src={getURLFor(buf, image_types[ext])} />
    } else if (ext in audio_types) {
      tag = <audio src={getURLFor(buf, audio_types[ext])} controls autoplay />
    } else if (ext in video_types) {
      tag = <video src={getURLFor(buf, video_types[ext])} controls autoplay />
    } else {
      tag = <div className='text'>{ab2str(buf)}</div>
    }
    return (
      <div className='fileViewer'>{tag}</div>
    )
  }
}

const getURLFor = (buf, type) => {
  const arrayBufferView = new Uint8Array(buf)
  const blob = new Blob([arrayBufferView], { type })
  const urlCreator = window.URL || window.webkitURL
  return urlCreator.createObjectURL(blob)
}

const ab2str = buf => String.fromCharCode.apply(null, new Uint8Array(buf))

const extension = fn => fn.split('.').slice(-1)[0].toLowerCase()

const mapStateToProps = state => ({
  app: state.system.app,
})

export default connect(mapStateToProps)(FileViewer)