├── .gitignore ├── static ├── favicon.ico ├── icons │ ├── android-chrome-192x192.png │ └── android-chrome-512x512.png └── manifest.json ├── src ├── polyfills.js ├── pwa.js ├── index.js ├── utils │ ├── event.js │ └── handle-url.js ├── router │ └── index.js ├── components │ ├── App.vue │ ├── SiteHeader.vue │ ├── Player.vue │ └── PromptVideo.vue └── views │ └── Home.vue ├── .editorconfig ├── poi.config.js ├── index.ejs ├── package.json └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | *.log 3 | .DS_Store 4 | 5 | # poi dist 6 | dist 7 | -------------------------------------------------------------------------------- /static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/anii/HEAD/static/favicon.ico -------------------------------------------------------------------------------- /static/icons/android-chrome-192x192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/anii/HEAD/static/icons/android-chrome-192x192.png -------------------------------------------------------------------------------- /static/icons/android-chrome-512x512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/egoist/anii/HEAD/static/icons/android-chrome-512x512.png -------------------------------------------------------------------------------- /src/polyfills.js: -------------------------------------------------------------------------------- 1 | if (!window.Promise) { 2 | window.Promise = require('promise-polyfill') 3 | } 4 | 5 | Object.assign = require('object-assign') 6 | -------------------------------------------------------------------------------- /src/pwa.js: -------------------------------------------------------------------------------- 1 | import runtime from 'offline-plugin/runtime' 2 | 3 | runtime.install({ 4 | onUpdateReady() { 5 | runtime.applyUpdate() 6 | } 7 | }) 8 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './components/App.vue' 3 | 4 | import router from './router' 5 | 6 | new Vue({ 7 | router, 8 | el: '#app', 9 | render: h => h(App) 10 | }) 11 | -------------------------------------------------------------------------------- /src/utils/event.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | 3 | export default new Vue({ 4 | data: { 5 | loading: false 6 | }, 7 | created() { 8 | this.$on('isLoading', state => { 9 | this.loading = state 10 | }) 11 | } 12 | }) 13 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | indent_style = space 5 | indent_size = 2 6 | end_of_line = lf 7 | charset = utf-8 8 | trim_trailing_whitespace = true 9 | insert_final_newline = true 10 | 11 | [*.md] 12 | trim_trailing_whitespace = false -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Router from 'vue-router' 3 | 4 | Vue.use(Router) 5 | 6 | const Home = resolve => require(['../views/Home.vue'], resolve) 7 | 8 | const router = new Router({ 9 | routes: [{ 10 | path: '/', 11 | component: Home 12 | }] 13 | }) 14 | 15 | export default router 16 | -------------------------------------------------------------------------------- /src/utils/handle-url.js: -------------------------------------------------------------------------------- 1 | export function parseVideoURL(video) { 2 | let src = video.src 3 | 4 | if (video.type === 'bilibili') { 5 | const matched = /(?:av)?([\d]+)/.exec(src) 6 | if (matched) { 7 | const id = matched[1] 8 | src = `https://api.prprpr.me/dplayer/video/bilibili?aid=${id}` 9 | } 10 | return { src } 11 | } 12 | 13 | if (!video.type) { 14 | return { src } 15 | } 16 | 17 | return video 18 | } 19 | -------------------------------------------------------------------------------- /static/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "anii", 3 | "short_name": "ANII", 4 | "icons": [ 5 | { 6 | "src": "/icons/android-chrome-192x192.png", 7 | "sizes": "192x192", 8 | "type": "image/png" 9 | }, 10 | { 11 | "src": "/icons/android-chrome-512x512.png", 12 | "sizes": "512x512", 13 | "type": "image/png" 14 | } 15 | ], 16 | "start_url": "/", 17 | "display": "standalone", 18 | "background_color": "#000000", 19 | "theme_color": "#4DBA87" 20 | } 21 | -------------------------------------------------------------------------------- /poi.config.js: -------------------------------------------------------------------------------- 1 | const path = require('path') 2 | const pkg = require('./package') 3 | 4 | module.exports = { 5 | entry: [ 6 | 'src/polyfills.js', 7 | 'src/index.js' 8 | ], 9 | html: { 10 | title: pkg.productName, 11 | description: pkg.descrption, 12 | template: path.join(__dirname, 'index.ejs') 13 | }, 14 | postcss: { 15 | plugins: [ 16 | // Your postcss plugins 17 | ] 18 | }, 19 | presets: [ 20 | require('poi-preset-bundle-report')(), 21 | require('poi-preset-offline')({ 22 | pwa: './src/pwa.js', // Path to pwa runtime entry 23 | pluginOptions: { 24 | AppCache: false 25 | } // Additional options for offline-plugin 26 | }) 27 | ], 28 | define: { 29 | __VERSION__: pkg.version 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /index.ejs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | <%= htmlWebpackPlugin.options.title %> 8 | 9 | 10 | 11 | 12 | 13 | 14 | <% if (htmlWebpackPlugin.options.description) { %> 15 | 16 | <% } %> 17 | 18 | <% for (var chunk of webpack.chunks) { 19 | for (var file of chunk.files) { 20 | if (file.match(/\.(js|css)$/)) { %> 21 | <% }}} %> 22 | 23 | 24 | 27 |
28 | 29 | 30 | -------------------------------------------------------------------------------- /src/components/App.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 8 | 9 | 10 | 46 | 47 | -------------------------------------------------------------------------------- /src/views/Home.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 39 | 40 | 41 | 42 | 48 | 49 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "name": "anii", 4 | "productName": "ANII", 5 | "description": "A modern web video player.", 6 | "version": "0.0.1", 7 | "license": "MIT", 8 | "scripts": { 9 | "dev": "poi", 10 | "build": "poi build", 11 | "report": "poi build --bundle-report", 12 | "serve": "serve dist --single", 13 | "surge": "npm run build && surge -d anii.surge.sh -p dist", 14 | "now": "now .", 15 | "start": "serve dist" 16 | }, 17 | "now": { 18 | "alias": "anii" 19 | }, 20 | "babel": { 21 | "presets": [ 22 | "vue-app" 23 | ] 24 | }, 25 | "author": { 26 | "name": "EGOIST", 27 | "email": "0x142857@gmail.com" 28 | }, 29 | "dependencies": { 30 | "normalize.css": "^7.0.0", 31 | "object-assign": "^4.1.1", 32 | "offline-plugin": "^4.8.0", 33 | "plyr": "^2.0.13", 34 | "promise-polyfill": "^6.0.2", 35 | "text-spinners": "^1.0.5", 36 | "vue-router": "^2.5.3" 37 | }, 38 | "devDependencies": { 39 | "poi": "^8.0.0", 40 | "poi-preset-bundle-report": "^1.0.1", 41 | "poi-preset-offline": "^8.0.0", 42 | "serve": "^3.1.0", 43 | "stylus": "^0.54.5", 44 | "stylus-loader": "^3.0.1", 45 | "surge": "^0.19.0" 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/components/SiteHeader.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 58 | 59 | 73 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # ANII 2 | 3 | An alternative web app to the awesome video player [IINA](https://lhc70000.github.io/iina/) (Obviously IINA is much more powerful) 4 | 5 | As it's using HTML5 video tag, it only supports these formats: MP4, Ogg, WebM. 6 | 7 | 8 | 11 | 12 | 13 | You can visit https://anii.surge.sh for an offline version. 14 | 15 | ## Commands 16 | 17 | You can replace `yarn` with `npm run` here. 18 | 19 | ```bash 20 | # build for production 21 | yarn build 22 | 23 | # development mode 24 | yarn dev 25 | 26 | # serve the bundled dist folder in production mode 27 | yarn serve 28 | ``` 29 | 30 | ## Polyfills 31 | 32 | By default we only polyfill `window.Promise` and `Object.assign`. You can add more polyfills in `./src/polyfills.js`. 33 | 34 | ## Code splitting 35 | 36 | As webpack supports both [dynamic import](https://webpack.js.org/guides/code-splitting-async/#dynamic-import-import-) and [`require.ensure`](https://webpack.js.org/guides/code-splitting-async/#require-ensure-) syntax, we would recommend you to stick to `require.ensure` for now because of [performance issue](https://github.com/webpack/webpack/issues/4636). 37 | 38 | ## Analyze bundle size 39 | 40 | Run `yarn report` to get a report of bundle size which helps you: 41 | 42 | - Realize what's really inside your bundle 43 | - Find out what modules make up the most of it's size 44 | - Find modules that got there by mistake 45 | - Optimize it! 46 | 47 | 48 | ## Progress Web App 49 | 50 | Your app is now offline-ready (only in production bundle), which means you can visit it without network. 51 | 52 | Here we use a default [manifest.json](./static/manifest.json) to configurure your pwa, for example, to enable [Add to Home Screen] feature on Android. It will be copied directly to `./dist/manifest.json`. 53 | 54 | 55 | For all the available options, please head to [poi-preset-offline](https://github.com/egoist/poi/tree/master/packages/poi-preset-offline#api). 56 | 57 | --- 58 | 59 | This project is generated from [template-vue](https://github.com/egoist/template-vue). 60 | -------------------------------------------------------------------------------- /src/components/Player.vue: -------------------------------------------------------------------------------- 1 | 14 | 15 | 77 | 78 | 79 | 80 | 94 | -------------------------------------------------------------------------------- /src/components/PromptVideo.vue: -------------------------------------------------------------------------------- 1 | 45 | 46 | 102 | 103 | 138 | --------------------------------------------------------------------------------