<repo_name>cc7gs/node-movie<file_sep>/server/tasks/qiniu.js


const qiniu=require('qiniu');
const nanoid=require('nanoid');
const config=require('../config')
//bucket 即七牛上的存储空间名
const bucket=config.qiniu.bucket;
//生成鉴权对象
const mac=new qiniu.auth.digest.Mac(config.qiniu.AK,config.qiniu.SK);
//构建配置对象
const cfg=new qiniu.conf.Config();
const client=new qiniu.rs.BucketManager(mac,cfg);

const uploadToQiniu=async(url,key)=>{
    return new Promise((resolve,reject)=>{
        client.fetch(url,bucket,key,(err,ret,info)=>{
            if(err){
                reject(err);
            }else{
                if(info.statusCode===200){
                    resolve({key});
                }else{
                    reject(info);
                }
            }
        })
    }) 
}
;(async ()=>{
    const movies = [{
        doubanId: 27110296,
        video: 'http://vt1.doubanio.com/201901221122/f5bffd7d2db0f38c62c3ae394584aede/view/movie/M/402390189.mp4M/402390189.mp4',
        cover: 'https://img3.doubanio.com/img/trailer/medium/2539667252.jpg',
        poster: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2539661066.jpg'
    }]
    movies.map(async moive=>{
        if(moive.video && !moive.key){
            try {
                console.log('正在转换video');
                let videoData=await uploadToQiniu(moive.video,nanoid()+'.mp4');
                console.log('正在转换cover');
                let coverData=await uploadToQiniu(moive.cover,nanoid()+'.png');
                console.log('正在转换poster');
                let posterData=await uploadToQiniu(moive.video,nanoid()+'.png');
                if(videoData.key){
                    moive.videoKey=videoData.key
                }
                if(coverData.key){
                    moive.coverKey=coverData.key
                }
                if(posterData.key){
                    moive.posterKey=posterData.key
                }
                console.log(moive)
            } catch (error) {
                console.log(error,'error');
            }
        }
    })
})()<file_sep>/server/crawler/trailer-list.js
const  puppeteer=require('puppeteer');
const URL=`https://movie.douban.com/explore#!type=movie&tag=%E7%83%AD%E9%97%A8&sort=recommend&page_limit=20&page_start=0`;

const sleep=time=>new Promise(resolve=>{
    setTimeout(resolve,time);  
});
console.log('开始执行...');
(
    async ()=>{
        console.log('Start visit the target page');
        const browser= await puppeteer.launch({
            args:['--no-sanbox'], //启动非沙箱模式
            dumpio:false
        });
        const page=await browser.newPage(); //开启新页面
        await page.goto(URL,{
            waitUntil:'networkidle2'
        })
         await sleep(3000);
        //点击页面加载更多
        await page.waitForSelector('.more');
        for(let i=0;i<1;i++){
            await page.click('.more');
            await sleep(3000);
        }
        const result=await page.evaluate(()=>{
            var $=window.$;
            var items=$('.list-wp a');
            var links=[];
            
            if(items.length>=1){
                items.each((index,item)=>{
                    let it=$(item);
                    let doubanId=it.find('div').data('id');
                    let title=it.find('img').attr('alt');
                    let rate=Number(it.find('strong').text())
                    let poster=it.find('img').attr('src');
                    //换成大图
                    // let poster=it.find('img').attr('src').replace('s_ratio','l_ratio');

                    links.push({
                        doubanId,
                        title,
                        rate,
                        poster
                    })
                })
            }
            return links;
        })  
        //关闭浏览器
        browser.close();
        // console.log(result);
        // console.log(result.length,'length--------')
        
        //将结果发送出去
        process.send({result});
        //退出进程
        process.exit(0);
    })()<file_sep>/server/tasks/api.js
//根据电影id获取电影信息列表 api
//http://api.douban.com/v2/movie/subject/电影id

const rp = require('request-promise-native');
//获取电影详情信息
async function fetchMovie(item) {
    const url = `http://api.douban.com/v2/movie/subject/${item.doubanId}`;
    const res = await rp(url);
    return res;
}

(async () => {
    let movies = [{
            doubanId: 26972258,
            title: '江湖儿女',
            rate: 7.6,
            poster: 'https://img3.doubanio.com/view/photo/s_ratio_poster/public/p2533283770.jpg'
        },
        {
            doubanId: 26654498,
            title: '爱你，西蒙',
            rate: 8.3,
            poster: 'https://img1.doubanio.com/view/photo/s_ratio_poster/public/p2523592367.jpg'
        }
    ];
    movies.map(async moive => {
        let moiveData = await fetchMovie(moive);
        try{
            moiveData=JSON.parse(moiveData);
            console.log(moiveData,'movieData');
        }catch(error){
            console.log('转换异常',error);
        }
    })
})();
<file_sep>/server/test/async.js

function doSync(doSth,time){
   return new Promise(resolve=>{
    setTimeout(()=>{
        console.log(doSth+'用了'+time+'毫秒');
        resolve();
    },time) 
   }) 
}
const Scott={doSync}
const Meizi={doSync}
;(async ()=>{
    console.log('case 1: 起床来到门口')
    await Scott.doSync('刷牙',1000)
    console.log('啥也没干 一直等');
    await Meizi.doSync('去洗澡...',2000);
    console.log('什么也没干...');
})();<file_sep>/README.md
# node-movie
基于react koa2 node 搭建的一个电影预告片项目


#获取数据
 通过 puppeteer 模拟浏览器获取数据 [github地址](https://github.com/GoogleChrome/puppeteer)

  除此之外我们还可以用其它库比如:Selenium、PhantomJs
    
**Puppeteer好处:**
- 利用网页生成PDF、图片
- 爬取SPA应用,并生成预渲染内容(SSR)
- 获取网页内容

**常用知识点**
- puppeteer.launch 启动浏览器
- browser.newPage() 创建一个新页面
- page.goto 进入指定网页
- page.screenshot 截图

## node父子进程通信

## 进程问题
### 什么是同步异步
 同步和异步关注的是**消息通信机制**。
 **同步:** 指的是发送者发出消息后，若消息没有返回,调用者就主动等待结果什么时也不干。
**异步:** 指的发送者发出消息后,就去做别的事,当消息回来后就通知它,它就处里该消息。

### 什么是异步IO

### 什么是阻塞与非阻塞
 阻塞与非阻塞关注的是**程序等待调用结果时的==状态==**
**阻塞:** 指的是调用结果返回之前,当前线程处于被挂起。调用线程只有在得到结果后才会返回。
**非阻塞:** 指的调用结果返回之前，该调用者不会阻塞当前线程。

### 什么是事件循环与事件驱动
### 什么是单线程
### 什么是进程
### 什么是子进程
### 怎么来启动子进程
### 进程如何通信


## node上传资源到七牛云

> nanoid //可以生成随机id


## MongoDB vs mysql
|MongoDB|mysql|名称|
|---|---|---|
|document|record|记录|
|collection|table|表|  
|database|database|数据库| 
### Mongoose
 是mongoDB的一个对象模型库,封装了mongoDB对文档的一些增删改查等常用方法,让nodejs操作mongoDB数据库变得更容易
**Schema**
是一种文件形式存储的数据库模型骨架,不具备数据库的操作能力,即定义数据类型
例如:
```javascript
var PersonSchema=new mongoose.Schema({
  name:String;
})
```
**Model**
由Schema构造生成的模型,具有抽象属性和行为的数据库操作
```javascript
var PersonModel=db.model('person',PersonSchema)
```
**entity**
由Model创造的实体，他的操作也会影响数据库,可以操作数据库CRUD

```javascript
var personEntity=new PersonModel({
  name:'kk'
})
```
[原文传送门](https://cnodejs.org/topic/504b4924e2b84515770103dd)

**git常用操作**
```
git checkout master -b 分支名
git add .
git commit -m 描述
//将分支提交到远程分支
git push origin 分支名
//回到主分支
git checkout master
//合并远程分支 
git merge origin/分支名
//推送
git push master

```<file_sep>/server/test/stage.js
const {readFile}=require('fs')
const EventEmitter=require('events');

class EE extends EventEmitter{}
const yy=new EE();

yy.on('event',()=>{
    console.log('event 监听');
})

setTimeout(() => {
    console.log("0 毫秒后执行的定时器回调 ");
}, 0);

setTimeout(() => {
    console.log("100 毫秒后执行的定时器回调 ");
}, 100);

setTimeout(() => {
    console.log("200 毫秒后执行的定时器回调 ");
}, 200);

readFile('./async.js',data=>{
    console.log('完成文件 async读操作');
})

readFile('../index.js',data=>{
    console.log('完成文件 async读操作');
})

setImmediate(()=>{
    console.log('immediate 回调');
})
process.nextTick(()=>{
    console.log('process.nextTick 的回调');
})

Promise.resolve()
.then(()=>{
    yy.emit('event');
    process.nextTick(()=>{
        console.log('Process.nextTick 2 回调');
    })
    console.log('Promise的一次回调');
})
.then(()=>{
    console.log('Promise 的2 次回调');
})<file_sep>/server/config/index.js
module.exports={
    "qiniu":{
        "bucket":"movie",
        "AK":"<KEY>",
        "SK":"<KEY>"
    }
}<file_sep>/server/index.js
const Koa=require('koa');
const mongoose=require('mongoose');
require('./database/schema/movie');
const {connect,initSchemas}=require('./database/init');
const views=require('koa-views');
const {resolve} =require('path');

const app=new Koa();
app.use(views(resolve(__dirname + '/views'), {
    extension: 'pug'    // 以 pug 模版为例
  }))

;(async ()=>{
    await connect()
    initSchemas();
    const Movie=mongoose.model('Movie');
    const Movies=await Movie.find({})
    console.log(Movies);
})()

app.use(async (ctx,next)=>{
    await ctx.render('index',{
        you:'Luck',
        me:'Scott'
    })
})
// //添加端口号
app.listen(3333,()=>{
    console.log('监听端口 3333');
});<file_sep>/server/test/eventloop.js
setImmediate(()=>{
    console.log('阶段三 immediate 回调1');
});
setImmediate(()=>{
    console.log('阶段三 immediate 回调2');
});
setImmediate(()=>{
    console.log('阶段三 immediate 回调3');
});

setTimeout(() => {
   console.log('定时器零毫秒'); 
},0);