From d5ae415ce14825fd30f5f7f21b8a0ba6635b18f9 Mon Sep 17 00:00:00 2001 From: Adam Svystun Date: Mon, 1 Oct 2018 23:29:29 +0200 Subject: [PATCH] Add YouTube frontend (#5) * Add youtube frontend * Add production build of frontend --- frontend/client/App.js | 61 +- frontend/client/constants.js | 1 + frontend/client/webpack.config.js | 97 +-- frontend/static/frontend/css/app.css | 50 ++ frontend/static/frontend/js/app.client.js | 10 +- package-lock.json | 782 +++++++++++++++------- package.json | 10 +- 7 files changed, 689 insertions(+), 322 deletions(-) diff --git a/frontend/client/App.js b/frontend/client/App.js index fd9e08e..85ec6ab 100644 --- a/frontend/client/App.js +++ b/frontend/client/App.js @@ -8,7 +8,8 @@ import { css } from "react-emotion"; import { COMIXIFY_API, MAX_FILE_SIZE, - PERMITTED_VIDEO_EXTENSIONS + PERMITTED_VIDEO_EXTENSIONS, + FROM_YOUTUBE_API } from "./constants"; class App extends React.Component { @@ -19,6 +20,7 @@ class App extends React.Component { UPLOAD_ERROR: 3, DROP_ERROR: 4 }; + ytInput = React.createRef(); constructor(props) { super(props); this.state = { @@ -27,6 +29,8 @@ class App extends React.Component { result_comics: null }; this.onVideoDrop = this.onVideoDrop.bind(this); + this.handleResponse = this.handleResponse.bind(this); + this.onYouTubeSubmit = this.onYouTubeSubmit.bind(this); this.onVideoUploadProgress = this.onVideoUploadProgress.bind(this); } onVideoUploadProgress(progressEvent) { @@ -35,6 +39,18 @@ class App extends React.Component { ); console.log(percentCompleted); } + handleResponse(res) { + if (res.data["status_message"] === "ok") { + this.setState({ + state: App.appStates.FINISHED, + result_comics: res.data["comic"] + }); + } else { + this.setState({ + state: App.appStates.UPLOAD_ERROR + }); + } + } processVideo(video) { let data = new FormData(); data.append("file", video); @@ -42,18 +58,7 @@ class App extends React.Component { headers: { "content-type": "multipart/form-data" }, onUploadProgress: this.onVideoUploadProgress }) - .then(res => { - if (res.data["status_message"] === "ok") { - this.setState({ - state: App.appStates.FINISHED, - result_comics: res.data["comic"] - }); - } else { - this.setState({ - state: App.appStates.UPLOAD_ERROR - }); - } - }) + .then(this.handleResponse) .catch(err => { console.error(err); this.setState({ @@ -75,10 +80,25 @@ class App extends React.Component { } this.processVideo(files[0]); } - + onYouTubeSubmit() { + let ytLink = this.ytInput.current.value; + post(FROM_YOUTUBE_API, { + url: ytLink + }) + .then(this.handleResponse) + .catch(err => { + console.error(err); + this.setState({ + state: App.appStates.UPLOAD_ERROR + }); + }); + this.setState({ + state: App.appStates.PROCESSING + }); + } render() { let { state, drop_errors, result_comics } = this.state; - let showDropzone = [ + let showUsage = [ App.appStates.INITIAL, App.appStates.UPLOAD_ERROR, App.appStates.DROP_ERROR, @@ -95,7 +115,7 @@ class App extends React.Component { {state === App.appStates.UPLOAD_ERROR && (

Server Error: Please try again later.

)} - {showDropzone && ( + {showUsage && ( -

Drop files here, or click to select manually

+

Drop video here, or click to select manually

)} + {showUsage && ( +
+ + + +
+ )} {state === App.appStates.PROCESSING && ( { + const merge = require("webpack-merge"); + const UglifyJsPlugin = require("uglifyjs-webpack-plugin"); + const webpack = require("webpack"); -let common = { - entry: { - app: __dirname + "/App.js" - }, - output: { - path: __dirname + "/../static/frontend/js", - filename: "[name].client.js" - }, - externals: { - cheerio: "window", - "react/lib/ExecutionEnvironment": true, - "react/lib/ReactContext": true - }, - module: { - rules: [ - { - test: /\.jsx?$/, - exclude: /(node_modules|bower_components)/, - loader: "babel-loader", - query: { - presets: ["react", "stage-0", "flow"], - plugins: ["emotion"] + let common = { + entry: { + app: __dirname + "/App.js" + }, + output: { + path: __dirname + "/../static/frontend/js", + filename: "[name].client.js" + }, + externals: { + cheerio: "window", + "react/lib/ExecutionEnvironment": true, + "react/lib/ReactContext": true + }, + module: { + rules: [ + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: "babel-loader", + query: { + presets: ["react", "stage-0", "flow"], + plugins: ["emotion"] + } + }, + { + test: /\.css$/, + use: ["style-loader", "css-loader"] } - }, - { - test: /\.css$/, - use: ["style-loader", "css-loader"] - } - ] - } -}; + ] + } + }; -if (process.env.NODE_ENV === "production") { - module.exports = merge(common, { - plugins: [ - new webpack.DefinePlugin({ - "process.env.NODE_ENV": JSON.stringify("production") - }), - new UglifyJsPlugin() - ], - mode: "production" - }); -} else { - module.exports = merge(common, { - mode: "development" - }); + if (env.production) { + return merge(common, { + plugins: [ + new webpack.DefinePlugin({ + "process.env.NODE_ENV": JSON.stringify("production") + }), + new UglifyJsPlugin() + ], + mode: "production" + }); + } else { + return merge(common, { + mode: "development" + }); + } } + diff --git a/frontend/static/frontend/css/app.css b/frontend/static/frontend/css/app.css index 87125bf..4deb0b7 100644 --- a/frontend/static/frontend/css/app.css +++ b/frontend/static/frontend/css/app.css @@ -61,6 +61,56 @@ img { background-color: #eee; } +.yt-label { + margin: 10px 0 10px 20px; + display: block; +} + +#yt-link { + height: 30px; + margin-right: 5px; + padding: 6px 10px; + background-color: #fff; + border: 1px solid #D1D1D1; + border-radius: 3px; + box-shadow: none; + box-sizing: border-box; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; +} + + +#yt-link:focus { + border: 1px solid #33C3F0; + outline: 0; +} + +button { + display: inline-block; + height: 30px; + padding: 0 30px; + color: #555; + text-align: center; + font-size: 11px; + font-weight: 600; + line-height: 30px; + text-transform: uppercase; + text-decoration: none; + white-space: nowrap; + background-color: transparent; + border-radius: 3px; + border: 1px solid #bbb; + cursor: pointer; + box-sizing: border-box; +} +button:hover, +button:focus { + color: #333; + border-color: #888; + outline: 0; +} + @media all and (max-width: 700px) { .wrap { margin-top: 0; diff --git a/frontend/static/frontend/js/app.client.js b/frontend/static/frontend/js/app.client.js index 58eea19..7556ac5 100644 --- a/frontend/static/frontend/js/app.client.js +++ b/frontend/static/frontend/js/app.client.js @@ -1,9 +1,9 @@ -!function(e){var t={};function n(r){if(t[r])return t[r].exports;var o=t[r]={i:r,l:!1,exports:{}};return e[r].call(o.exports,o,o.exports,n),o.l=!0,o.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var o in e)n.d(r,o,function(t){return e[t]}.bind(null,o));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=164)}([function(e,t,n){"use strict";e.exports=n(76)},function(e,t,n){e.exports=n(102)()},function(e,t,n){"use strict";n.r(t),function(e){n.d(t,"flush",function(){return i}),n.d(t,"hydrate",function(){return u}),n.d(t,"cx",function(){return l}),n.d(t,"merge",function(){return s}),n.d(t,"getRegisteredStyles",function(){return c}),n.d(t,"injectGlobal",function(){return f}),n.d(t,"keyframes",function(){return p}),n.d(t,"css",function(){return d}),n.d(t,"sheet",function(){return h}),n.d(t,"caches",function(){return m});var r=n(75),o=void 0!==e?e:{},a=Object(r.a)(o),i=a.flush,u=a.hydrate,l=a.cx,s=a.merge,c=a.getRegisteredStyles,f=a.injectGlobal,p=a.keyframes,d=a.css,h=a.sheet,m=a.caches}.call(this,n(55))},function(e,t,n){"use strict";t.__esModule=!0;var r=function(e){return e&&e.__esModule?e:{default:e}}(n(62));t.default=function(e,t){if(!e)throw new ReferenceError("this hasn't been initialised - super() hasn't been called");return!t||"object"!==(void 0===t?"undefined":(0,r.default)(t))&&"function"!=typeof t?e:t}},function(e,t,n){"use strict";n.r(t);var r=n(0),o=n.n(r),a=n(8),i=n.n(a),u=n(12),l=n.n(u),s=n(5),c=n.n(s),f=n(3),p=n.n(f),d=n(6),h=n.n(d);function m(){var e=this.constructor.getDerivedStateFromProps(this.props,this.state);null!==e&&void 0!==e&&this.setState(e)}function y(e){this.setState(function(t){var n=this.constructor.getDerivedStateFromProps(e,t);return null!==n&&void 0!==n?n:null}.bind(this))}function v(e,t){try{var n=this.props,r=this.state;this.props=e,this.state=t,this.__reactInternalSnapshotFlag=!0,this.__reactInternalSnapshot=this.getSnapshotBeforeUpdate(n,r)}finally{this.props=n,this.state=r}}function g(e){var t=e.prototype;if(!t||!t.isReactComponent)throw new Error("Can only polyfill class components");if("function"!=typeof e.getDerivedStateFromProps&&"function"!=typeof t.getSnapshotBeforeUpdate)return e;var n=null,r=null,o=null;if("function"==typeof t.componentWillMount?n="componentWillMount":"function"==typeof t.UNSAFE_componentWillMount&&(n="UNSAFE_componentWillMount"),"function"==typeof t.componentWillReceiveProps?r="componentWillReceiveProps":"function"==typeof t.UNSAFE_componentWillReceiveProps&&(r="UNSAFE_componentWillReceiveProps"),"function"==typeof t.componentWillUpdate?o="componentWillUpdate":"function"==typeof t.UNSAFE_componentWillUpdate&&(o="UNSAFE_componentWillUpdate"),null!==n||null!==r||null!==o){var a=e.displayName||e.name,i="function"==typeof e.getDerivedStateFromProps?"getDerivedStateFromProps()":"getSnapshotBeforeUpdate()";throw Error("Unsafe legacy lifecycles will not be called for components using new component APIs.\n\n"+a+" uses "+i+" but also contains the following legacy lifecycles:"+(null!==n?"\n "+n:"")+(null!==r?"\n "+r:"")+(null!==o?"\n "+o:"")+"\n\nThe above lifecycles should be removed. Learn more about this warning here:\nhttps://fb.me/react-async-component-lifecycle-hooks")}if("function"==typeof e.getDerivedStateFromProps&&(t.componentWillMount=m,t.componentWillReceiveProps=y),"function"==typeof t.getSnapshotBeforeUpdate){if("function"!=typeof t.componentDidUpdate)throw new Error("Cannot polyfill getSnapshotBeforeUpdate() for components that do not define componentDidUpdate() on the prototype");t.componentWillUpdate=v;var u=t.componentDidUpdate;t.componentDidUpdate=function(e,t,n){var r=this.__reactInternalSnapshotFlag?this.__reactInternalSnapshot:n;u.call(this,e,t,r)}}return e}m.__suppressDeprecationWarning=!0,y.__suppressDeprecationWarning=!0,v.__suppressDeprecationWarning=!0;var b=n(44),w=n.n(b),x=n(28),k=n.n(x),_=n(73),E=n.n(_),C=n(45),S=n(29);n.d(t,"mapProps",function(){return j}),n.d(t,"withProps",function(){return U}),n.d(t,"withPropsOnChange",function(){return A}),n.d(t,"withHandlers",function(){return D}),n.d(t,"defaultProps",function(){return F}),n.d(t,"renameProp",function(){return L}),n.d(t,"renameProps",function(){return B}),n.d(t,"flattenProp",function(){return W}),n.d(t,"withState",function(){return V}),n.d(t,"withStateHandlers",function(){return H}),n.d(t,"withReducer",function(){return q}),n.d(t,"branch",function(){return X}),n.d(t,"renderComponent",function(){return G}),n.d(t,"renderNothing",function(){return Q}),n.d(t,"shouldUpdate",function(){return Z}),n.d(t,"pure",function(){return J}),n.d(t,"onlyUpdateForKeys",function(){return ee}),n.d(t,"onlyUpdateForPropTypes",function(){return te}),n.d(t,"withContext",function(){return ne}),n.d(t,"getContext",function(){return re}),n.d(t,"lifecycle",function(){return oe}),n.d(t,"toClass",function(){return ie}),n.d(t,"withRenderProps",function(){return ue}),n.d(t,"setStatic",function(){return O}),n.d(t,"setPropTypes",function(){return le}),n.d(t,"setDisplayName",function(){return P}),n.d(t,"compose",function(){return se}),n.d(t,"getDisplayName",function(){return T}),n.d(t,"wrapDisplayName",function(){return N}),n.d(t,"isClassComponent",function(){return ae}),n.d(t,"createSink",function(){return ce}),n.d(t,"componentFromProp",function(){return fe}),n.d(t,"nest",function(){return pe}),n.d(t,"hoistStatics",function(){return de}),n.d(t,"componentFromStream",function(){return ge}),n.d(t,"componentFromStreamWithConfig",function(){return ve}),n.d(t,"mapPropsStream",function(){return xe}),n.d(t,"mapPropsStreamWithConfig",function(){return we}),n.d(t,"createEventHandler",function(){return _e}),n.d(t,"createEventHandlerWithConfig",function(){return ke}),n.d(t,"setObservableConfig",function(){return me}),n.d(t,"shallowEqual",function(){return l.a});var O=function(e,t){return function(n){return n[e]=t,n}},P=function(e){return O("displayName",e)},T=function(e){return"string"==typeof e?e:e?e.displayName||e.name||"Component":void 0},N=function(e,t){return t+"("+T(e)+")"},j=function(e){return function(t){var n=Object(r.createFactory)(t);return function(t){return n(e(t))}}},U=function(e){return j(function(t){return i()({},t,"function"==typeof e?e(t):e)})},z=function(e,t){for(var n={},r=0;r1?r-1:0),a=1;a1&&void 0!==arguments[1]?arguments[1]:$;return t.setState(function(t){var r=t.stateValue;return{stateValue:n(r,e)}},function(){return r(t.state.stateValue)})},o=e,p()(t,o)}return h()(a,r),a.prototype.initializeStateValue=function(){return void 0!==o?"function"==typeof o?o(this.props):o:n(void 0,{type:"@@recompose/INIT"})},a.prototype.render=function(){var n;return u(i()({},this.props,((n={})[e]=this.state.stateValue,n[t]=this.dispatch,n)))},a}(r.Component)}},K=function(e){return e},X=function(e,t){var n=arguments.length>2&&void 0!==arguments[2]?arguments[2]:K;return function(o){var a=void 0,i=void 0;return function(u){return e(u)?(a=a||Object(r.createFactory)(t(o)))(u):(i=i||Object(r.createFactory)(n(o)))(u)}}},G=function(e){return function(t){var n=Object(r.createFactory)(e);return function(e){return n(e)}}},Y=function(e){function t(){return c()(this,t),p()(this,e.apply(this,arguments))}return h()(t,e),t.prototype.render=function(){return null},t}(r.Component),Q=function(e){return Y},Z=function(e){return function(t){var n=Object(r.createFactory)(t);return function(t){function r(){return c()(this,r),p()(this,t.apply(this,arguments))}return h()(r,t),r.prototype.shouldComponentUpdate=function(t){return e(this.props,t)},r.prototype.render=function(){return n(this.props)},r}(r.Component)}},J=function(e){return Z(function(e,t){return!l()(e,t)})(e)},ee=function(e){return Z(function(t,n){return!l()(z(n,e),z(t,e))})},te=function(e){var t=e.propTypes,n=k()(t||{});return ee(n)(e)},ne=function(e,t){return function(n){var o=Object(r.createFactory)(n),a=function(e){function n(){var r,o,a;c()(this,n);for(var i=arguments.length,u=Array(i),l=0;l=200&&e<300},headers:{common:{Accept:"application/json, text/plain, */*"}}};r.forEach(["delete","get","head"],function(e){u.headers[e]={}}),r.forEach(["post","put","patch"],function(e){u.headers[e]=r.merge(a)}),e.exports=u}).call(this,n(86))},function(e,t,n){var r=n(16);e.exports=function(e,t){if(!r(e))return e;var n,o;if(t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;if("function"==typeof(n=e.valueOf)&&!r(o=n.call(e)))return o;if(!t&&"function"==typeof(n=e.toString)&&!r(o=n.call(e)))return o;throw TypeError("Can't convert object to primitive value")}},function(e,t){e.exports=function(e){if(void 0==e)throw TypeError("Can't call method on "+e);return e}},function(e,t){var n=Math.ceil,r=Math.floor;e.exports=function(e){return isNaN(e=+e)?0:(e>0?r:n)(e)}},function(e,t,n){var r=n(35)("keys"),o=n(25);e.exports=function(e){return r[e]||(r[e]=o(e))}},function(e,t,n){var r=n(9),o=n(10),a=o["__core-js_shared__"]||(o["__core-js_shared__"]={});(e.exports=function(e,t){return a[e]||(a[e]=void 0!==t?t:{})})("versions",[]).push({version:r.version,mode:n(24)?"pure":"global",copyright:"© 2018 Denis Pushkarev (zloirock.ru)"})},function(e,t){e.exports="constructor,hasOwnProperty,isPrototypeOf,propertyIsEnumerable,toLocaleString,toString,valueOf".split(",")},function(e,t){t.f=Object.getOwnPropertySymbols},function(e,t,n){var r=n(32);e.exports=function(e){return Object(r(e))}},function(e,t){e.exports={}},function(e,t,n){var r=n(21),o=n(118),a=n(36),i=n(34)("IE_PROTO"),u=function(){},l=function(){var e,t=n(58)("iframe"),r=a.length;for(t.style.display="none",n(119).appendChild(t),t.src="javascript:",(e=t.contentWindow.document).open(),e.write("