diff --git a/frontend/config/webpack.config.dev.js b/frontend/config/webpack.config.dev.js
index c47821f64c..f09b149e95 100644
--- a/frontend/config/webpack.config.dev.js
+++ b/frontend/config/webpack.config.dev.js
@@ -139,6 +139,11 @@ module.exports = {
require.resolve('react-dev-utils/webpackHotDevClient'),
paths.appSrc + "/view-file-svg.js",
],
+ viewFileAudio: [
+ require.resolve('./polyfills'),
+ require.resolve('react-dev-utils/webpackHotDevClient'),
+ paths.appSrc + "/view-file-audio.js",
+ ],
orgAdmin: [
require.resolve('./polyfills'),
require.resolve('react-dev-utils/webpackHotDevClient'),
diff --git a/frontend/config/webpack.config.prod.js b/frontend/config/webpack.config.prod.js
index b5e7dbc37f..65be6a4430 100644
--- a/frontend/config/webpack.config.prod.js
+++ b/frontend/config/webpack.config.prod.js
@@ -76,6 +76,7 @@ module.exports = {
viewFileVideo: [require.resolve('./polyfills'), paths.appSrc + "/view-file-video.js"],
viewFilePDF: [require.resolve('./polyfills'), paths.appSrc + "/view-file-pdf.js"],
viewFileSVG: [require.resolve('./polyfills'), paths.appSrc + "/view-file-svg.js"],
+ viewFileAudio: [require.resolve('./polyfills'), paths.appSrc + "/view-file-audio.js"],
orgAdmin: [require.resolve('./polyfills'), paths.appSrc + "/pages/org-admin"],
viewFileUMind: [require.resolve('./polyfills'), paths.appSrc + "/view-file-umind.js"],
sysAdmin: [require.resolve('./polyfills'), paths.appSrc + "/pages/sys-admin"],
diff --git a/frontend/src/components/audio-player.js b/frontend/src/components/audio-player.js
new file mode 100644
index 0000000000..0ae8221f22
--- /dev/null
+++ b/frontend/src/components/audio-player.js
@@ -0,0 +1,32 @@
+import React from 'react';
+
+import videojs from 'video.js';
+import 'video.js/dist/video-js.css';
+
+class AudioPlayer extends React.Component {
+ componentDidMount() {
+ // instantiate Video.js
+ this.player = videojs(this.videoNode, this.props, function onPlayerReady() {
+ });
+ }
+
+ // destroy player on unmount
+ componentWillUnmount() {
+ if (this.player) {
+ this.player.dispose();
+ }
+ }
+
+ // wrap the player in a div with a `data-vjs-player` attribute
+ // so videojs won't create additional wrapper in the DOM
+ // see https://github.com/videojs/video.js/pull/3856
+ render() {
+ return (
+
+
+
+ );
+ }
+}
+
+export default AudioPlayer;
diff --git a/frontend/src/css/audio-file-view.css b/frontend/src/css/audio-file-view.css
new file mode 100644
index 0000000000..d19f016367
--- /dev/null
+++ b/frontend/src/css/audio-file-view.css
@@ -0,0 +1,9 @@
+.video-js {
+ width: calc(100% - 40px);
+ max-width: 500px;
+ height: 30px;
+ margin: 0 auto;
+}
+.video-js .vjs-fullscreen-control {
+ display: none;
+}
diff --git a/frontend/src/view-file-audio.js b/frontend/src/view-file-audio.js
new file mode 100644
index 0000000000..dbc5dabada
--- /dev/null
+++ b/frontend/src/view-file-audio.js
@@ -0,0 +1,133 @@
+import React from 'react';
+import ReactDOM from 'react-dom';
+import watermark from 'watermark-dom';
+import { seafileAPI } from './utils/seafile-api';
+import { siteName } from './utils/constants';
+import FileInfo from './components/file-view/file-info';
+import FileToolbar from './components/file-view/file-toolbar';
+import FileViewTip from './components/file-view/file-view-tip';
+import CommentPanel from './components/file-view/comment-panel';
+import AudioPlayer from './components/audio-player';
+
+import './css/file-view.css';
+import './css/audio-file-view.css';
+
+const { isStarred, isLocked, lockedByMe,
+ repoID, filePath, err, enableWatermark, userNickName,
+ // the following are only for this type of file view
+ rawPath
+} = window.app.pageOptions;
+
+class ViewFileAudio extends React.Component {
+
+ constructor(props) {
+ super(props);
+ this.state = {
+ isStarred: isStarred,
+ isLocked: isLocked,
+ lockedByMe: lockedByMe,
+ isCommentPanelOpen: false
+ };
+ }
+
+ toggleCommentPanel = () => {
+ this.setState({
+ isCommentPanelOpen: !this.state.isCommentPanelOpen
+ });
+ }
+
+ toggleStar = () => {
+ if (this.state.isStarred) {
+ seafileAPI.unStarItem(repoID, filePath).then((res) => {
+ this.setState({
+ isStarred: false
+ });
+ });
+ } else {
+ seafileAPI.starItem(repoID, filePath).then((res) => {
+ this.setState({
+ isStarred: true
+ });
+ });
+ }
+ }
+
+ toggleLockFile = () => {
+ if (this.state.isLocked) {
+ seafileAPI.unlockfile(repoID, filePath).then((res) => {
+ this.setState({
+ isLocked: false,
+ lockedByMe: false
+ });
+ });
+ } else {
+ seafileAPI.lockfile(repoID, filePath).then((res) => {
+ this.setState({
+ isLocked: true,
+ lockedByMe: true
+ });
+ });
+ }
+ }
+
+ render() {
+ return (
+
+
+
+
+
+
+
+ {this.state.isCommentPanelOpen &&
+
+ }
+
+
+ );
+ }
+}
+
+class FileContent extends React.Component {
+
+ render() {
+ if (err) {
+ return ;
+ }
+
+ const videoJsOptions = {
+ autoplay: false,
+ controls: true,
+ preload: 'auto',
+ sources: [{
+ src: rawPath
+ }]
+ };
+ return (
+
+ );
+ }
+}
+
+if (enableWatermark) {
+ watermark.init({
+ watermark_txt: `${siteName} ${userNickName}`,
+ watermark_alpha: 0.075
+ });
+}
+
+ReactDOM.render (
+ ,
+ document.getElementById('wrapper')
+);
diff --git a/frontend/src/view-file-video.js b/frontend/src/view-file-video.js
index e485327ede..84e16cc519 100644
--- a/frontend/src/view-file-video.js
+++ b/frontend/src/view-file-video.js
@@ -113,7 +113,7 @@ class FileContent extends React.Component {
}]
};
return (
-
+
);
diff --git a/seahub/templates/audio_file_view_react.html b/seahub/templates/audio_file_view_react.html
new file mode 100644
index 0000000000..a919bd01d0
--- /dev/null
+++ b/seahub/templates/audio_file_view_react.html
@@ -0,0 +1,15 @@
+{% extends 'file_view_react.html' %}
+{% load render_bundle from webpack_loader %}
+{% load seahub_tags %}
+
+{% block extra_style %}
+{% render_bundle 'viewFileAudio' 'css' %}
+{% endblock %}
+
+{% block extra_data %}
+ rawPath: '{{ raw_path|escapejs }}'
+{% endblock %}
+
+{% block render_bundle %}
+{% render_bundle 'viewFileAudio' 'js' %}
+{% endblock %}
diff --git a/seahub/views/file.py b/seahub/views/file.py
index 4b45b1226c..3a42101174 100644
--- a/seahub/views/file.py
+++ b/seahub/views/file.py
@@ -697,8 +697,7 @@ def view_lib_file(request, repo_id, path):
return_dict['raw_path'] = raw_path
send_file_access_msg(request, repo, path, 'web')
- if filetype in (VIDEO, PDF, SVG):
- template = '%s_file_view_react.html' % filetype.lower()
+ template = '%s_file_view_react.html' % filetype.lower()
return render(request, template, return_dict)
elif filetype == DRAW: