├── static ├── img │ ├── 16.png │ ├── 180.png │ ├── 32.png │ ├── youku.ico │ ├── youku.png │ ├── 450_300.jpg │ ├── favicon.ico │ ├── icon │ │ ├── mojo.ai │ │ ├── 28_28.png │ │ ├── 108_108.png │ │ ├── 1200_240.png │ │ ├── mojo-01.jpg │ │ ├── mojo-01.psd │ │ ├── mojo-02-2.jpg │ │ ├── mojo-02.jpg │ │ ├── mojo-02.psd │ │ ├── mojo-trans.png │ │ ├── mojo-02-eric.psd │ │ ├── mojo-35-long.png │ │ ├── mojotv-690-238.jpg │ │ ├── mojo-trans-35x35.png │ │ ├── mojo-trans-50x50.png │ │ └── mojo-long-960-238.jpg │ ├── logo56x56.png │ ├── qq-video.png │ └── logo_60_60.png ├── js │ └── my.js └── css │ └── my.css ├── .gitignore ├── models ├── modelShow.go ├── modelEpisode.go ├── modelVote.go ├── modelUser.go ├── modelSubtitle.go ├── cachConst.go ├── modelImgur.go ├── modelTag.go ├── initialize.go ├── modelQuote.go ├── modelImage.go └── modelArticle.go ├── views ├── layout │ ├── _breadcrumb.html │ ├── _tags.html │ ├── _script.html │ ├── base_index.html │ ├── base_view.html │ ├── _head.html │ ├── _footer.html │ ├── _share_comment.html │ └── _nav.html ├── error │ └── 404.html ├── article │ ├── _links.html │ ├── index.html │ ├── view.html │ └── _video.html ├── image │ └── cropper_modal.html ├── home │ ├── toutiaoAd.html │ └── index.html ├── tag │ ├── _allTags.html │ └── view.html └── auth │ └── register.html ├── .vscode └── launch.json ├── controllers ├── controllerWxApi.go ├── controllerHome.go ├── controllerError.go ├── imageController.go ├── controllerTag.go ├── controllerFantasy.go ├── controllerVideo.go ├── controllerBase.go ├── controllerArticle.go ├── controllerRenRen.go └── controllerAuth.go ├── conf └── app.conf.example ├── tools └── temple.go ├── tests └── default_test.go ├── main.go ├── ssl ├── 214011752730233.key └── 214011752730233.pem ├── tasks └── fetchEztv.go ├── routers └── router.go └── trytv_2017-11-30.sql /static/img/16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/16.png -------------------------------------------------------------------------------- /static/img/180.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/180.png -------------------------------------------------------------------------------- /static/img/32.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/32.png -------------------------------------------------------------------------------- /static/img/youku.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/youku.ico -------------------------------------------------------------------------------- /static/img/youku.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/youku.png -------------------------------------------------------------------------------- /static/img/450_300.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/450_300.jpg -------------------------------------------------------------------------------- /static/img/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/favicon.ico -------------------------------------------------------------------------------- /static/img/icon/mojo.ai: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo.ai -------------------------------------------------------------------------------- /static/img/logo56x56.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/logo56x56.png -------------------------------------------------------------------------------- /static/img/qq-video.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/qq-video.png -------------------------------------------------------------------------------- /static/img/icon/28_28.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/28_28.png -------------------------------------------------------------------------------- /static/img/logo_60_60.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/logo_60_60.png -------------------------------------------------------------------------------- /static/img/icon/108_108.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/108_108.png -------------------------------------------------------------------------------- /static/img/icon/1200_240.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/1200_240.png -------------------------------------------------------------------------------- /static/img/icon/mojo-01.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-01.jpg -------------------------------------------------------------------------------- /static/img/icon/mojo-01.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-01.psd -------------------------------------------------------------------------------- /static/img/icon/mojo-02-2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-02-2.jpg -------------------------------------------------------------------------------- /static/img/icon/mojo-02.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-02.jpg -------------------------------------------------------------------------------- /static/img/icon/mojo-02.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-02.psd -------------------------------------------------------------------------------- /static/img/icon/mojo-trans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-trans.png -------------------------------------------------------------------------------- /static/img/icon/mojo-02-eric.psd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-02-eric.psd -------------------------------------------------------------------------------- /static/img/icon/mojo-35-long.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-35-long.png -------------------------------------------------------------------------------- /static/img/icon/mojotv-690-238.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojotv-690-238.jpg -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | my_go_web 2 | debug 3 | .* 4 | main 5 | *.log 6 | test.log 7 | test.*.log 8 | nohup.out 9 | conf/app.conf 10 | .vscode 11 | 12 | -------------------------------------------------------------------------------- /static/img/icon/mojo-trans-35x35.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-trans-35x35.png -------------------------------------------------------------------------------- /static/img/icon/mojo-trans-50x50.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-trans-50x50.png -------------------------------------------------------------------------------- /static/img/icon/mojo-long-960-238.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/JJJJJJJerk/american-tv-news-powered-by-beego/HEAD/static/img/icon/mojo-long-960-238.jpg -------------------------------------------------------------------------------- /models/modelShow.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "github.com/jinzhu/gorm" 7 | ) 8 | type Show struct { 9 | gorm.Model 10 | NameEn string 11 | NameZh string 12 | } 13 | -------------------------------------------------------------------------------- /models/modelEpisode.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | ) 6 | 7 | type Episode struct { 8 | gorm.Model 9 | Name string `gorm:"size:255"` 10 | RawName string `gorm:"size:255"` 11 | Provider string 12 | UrlMagnet string 13 | } 14 | -------------------------------------------------------------------------------- /views/layout/_breadcrumb.html: -------------------------------------------------------------------------------- 1 | {{if .BreadCrumbs }} 2 |
3 | 8 |
9 | {{end}} -------------------------------------------------------------------------------- /models/modelVote.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "github.com/jinzhu/gorm" 7 | ) 8 | 9 | type Vote struct { 10 | gorm.Model 11 | ArticleId uint16 12 | ShowId uint16 13 | MovieId uint16 14 | Visit uint16 15 | Score float32 16 | VoteCount uint16 17 | FavorateCount uint16 18 | } 19 | 20 | type Link struct { 21 | Name string 22 | Url string 23 | } -------------------------------------------------------------------------------- /views/layout/_tags.html: -------------------------------------------------------------------------------- 1 |
2 | {{range $index, $value := .Tags}} 3 | {{$value.Name}} 4 | {{end}} 5 |
6 | -------------------------------------------------------------------------------- /views/error/404.html: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |

页面被外星人带走了!

5 | 6 |
7 |
8 | -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | 5 | { 6 | "name": "Launch", 7 | "type": "go", 8 | "request": "launch", 9 | "mode": "debug", 10 | "remotePath": "", 11 | "port": 2345, 12 | "host": "127.0.0.1", 13 | "program": "${workspaceRoot}", 14 | "env": {}, 15 | "args": [], 16 | "showLog": true 17 | } 18 | ] 19 | } -------------------------------------------------------------------------------- /controllers/controllerWxApi.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "www.mojotv.cn/models" 5 | 6 | "github.com/astaxie/beego" 7 | ) 8 | 9 | type WxApiController struct { 10 | beego.Controller //集成beego controller 11 | } 12 | 13 | func (c *WxApiController) ArticleIndex() { 14 | //token = c.GetInt("token") 15 | offset, _ := c.GetInt(":offset", 0) 16 | size, _ := c.GetInt(":size", models.PageSize) 17 | articles := models.GetBatchArticlesForWx(offset, size) 18 | c.Data["json"] = &articles 19 | c.ServeJSON() 20 | } 21 | -------------------------------------------------------------------------------- /views/article/_links.html: -------------------------------------------------------------------------------- 1 | 9 | 10 | 18 | -------------------------------------------------------------------------------- /models/modelUser.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | ) 6 | 7 | type User struct { 8 | gorm.Model 9 | Name string `gorm:"size:255"` 10 | Email string `gorm:"size:255"` 11 | Password string 12 | AvatarImage string 13 | WeiboId uint `gorm:"column:weibo_id"` 14 | WeiboAvatar string 15 | WeiboName string 16 | WeiboToken string 17 | } 18 | 19 | func (user *User) AfterFind() (err error) { 20 | if user.WeiboAvatar != "" && user.AvatarImage == "" { 21 | user.AvatarImage = user.WeiboAvatar 22 | } 23 | return 24 | } 25 | -------------------------------------------------------------------------------- /models/modelSubtitle.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "fmt" 7 | 8 | "github.com/jinzhu/gorm" 9 | ) 10 | 11 | type Subtitle struct { 12 | gorm.Model 13 | NameZh string 14 | NameEn string 15 | Version string 16 | Format string 17 | SourceUrl string 18 | FileName string 19 | Lang string 20 | Uri string 21 | Url string 22 | OssUrl string `gorm:"-"` 23 | HumamTime string `gorm:"_"` 24 | } 25 | 26 | func (sub *Subtitle) AfterFind()(err error) { 27 | sub.OssUrl = fmt.Sprintf("%s%s", CdnHost, sub.Uri) 28 | sub.HumamTime = sub.CreatedAt.Format("06-01-02 15:04") 29 | return 30 | } 31 | -------------------------------------------------------------------------------- /conf/app.conf.example: -------------------------------------------------------------------------------- 1 | appname=mojotv 2 | httpport=9999 3 | runmode=prod 4 | flashname=trytv 5 | FlashSeperator=ez 6 | ServerName=mojotvAwesomeServer 7 | EnableGzip=true 8 | StaticExtensionsToGzip=.css, .js 9 | EnableXSRF=true 10 | XSRFKEY=not_for_jerk 11 | xsrfexpire = 1200 12 | sessionon=true 13 | sessionprovider=memory 14 | sessionname=session 15 | 16 | mysqlport=3306 17 | mysqldb=trytv 18 | #imageCdnHost=https://oeveb4zm9.qnssl.com/ 19 | imageCdnHost=http://img.trytv.org/ 20 | keyword=mojotv.cn| 21 | description=欧美娱乐资讯 22 | #cdnhost=https://oeveb4zm9.qnssl.com/ 23 | [dev] 24 | mysqluser=** 25 | mysqlpass=** 26 | mysqlurls=** 27 | [prod] 28 | mysqluser=** 29 | mysqlpass=** 30 | mysqlurls=** 31 | -------------------------------------------------------------------------------- /views/layout/_script.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /controllers/controllerHome.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "www.mojotv.cn/models" 5 | ) 6 | 7 | type HomeController struct { 8 | BaseController 9 | } 10 | 11 | func (c *HomeController) Get() { 12 | articles := models.GetBatchArticles(0, models.PageSize) 13 | c.Data["BreadCrumbs"] = []Crumb{{"/", "fa fa-home", "首页"}, {"/article", "fa fa-fire", "资讯"}} 14 | c.Data["Articles"] = articles 15 | c.Data["Title"] = "mojoTV资讯|最新最快最热的美剧周边资讯" 16 | c.Data["Keyword"] = "mojoTV资讯,轻松学英语,欧美美剧资讯,国外搞笑小视频," 17 | c.Data["Description"] = "mojoTV资讯|提供最新最热最快最热的美剧资讯,海量英语学习资源,欧美搞笑有创意的短视频gif动图,海量美剧双语原生字幕,这里是英语爱好者的乐园,让每一个人都爱上学习英语" 18 | c.Layout = "layout/base_index.html" 19 | c.TplName = "home/index.html" 20 | } 21 | -------------------------------------------------------------------------------- /views/layout/base_index.html: -------------------------------------------------------------------------------- 1 | {{template "layout/_head.html" .}} 2 | 3 | 4 | 5 | {{template "layout/_nav.html" .}} 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 | {{.LayoutContent}} 16 | 17 | {{template "layout/_share_comment.html" .}} 18 | 19 | 20 |
21 | {{template "layout/_footer.html" .}} 22 | 23 | 24 | 25 | {{template "layout/_script.html" .}} 26 | 27 | 28 | -------------------------------------------------------------------------------- /models/cachConst.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //http://jinzhu.me/gorm/ gorm 文档 8 | 9 | const CK_QUOTE = "ck.base.quotes.5random" 10 | const CK_TAG_ALL = "ck.base.tags.all" 11 | const CK_Imgur_ALL = "ck.base.imgur.all" 12 | 13 | const C_EXPIRE_TIME_FOREVER = -1 14 | const C_EXPIRE_TIME_YEAR = time.Hour * 24 * 365 15 | const C_EXPIRE_TIME_WEEK = time.Hour * 24 * 7 16 | const C_EXPIRE_TIME_DAY = time.Hour * 24 17 | const C_EXPIRE_TIME_HOUR_12 = time.Hour * 12 18 | const C_EXPIRE_TIME_HOUR_06 = time.Hour * 6 19 | const C_EXPIRE_TIME_HOUR_03 = time.Hour * 3 20 | const C_EXPIRE_TIME_HOUR_01 = time.Hour * 1 21 | const C_EXPIRE_TIME_MIN_30 = time.Minute * 30 22 | const C_EXPIRE_TIME_MIN_15 = time.Minute * 15 23 | const C_EXPIRE_TIME_MIN_01 = time.Minute * 1 24 | -------------------------------------------------------------------------------- /tools/temple.go: -------------------------------------------------------------------------------- 1 | package tools 2 | 3 | //防止模板相关的方便函数 4 | import ( 5 | "fmt" 6 | 7 | "www.mojotv.cn/models" 8 | 9 | "github.com/astaxie/beego" 10 | ) 11 | 12 | //注册tmeplate的一些实用函数 13 | //https://beego.me/docs/mvc/view/template.md 14 | 15 | //配置cd镜像地址 16 | var cdn string 17 | var imageCdnHost string 18 | 19 | func init() { 20 | cdn = beego.AppConfig.DefaultString("cdnhost", "/static/") 21 | imageCdnHost = beego.AppConfig.String("imageCdnHost") 22 | 23 | //注册template function 24 | beego.AddFuncMap("cdnSrc", cdnSrc) //拼接cdn资源 25 | 26 | beego.AddFuncMap("cdnImageSrc", cdnImageSrc) //拼接cdn资源 27 | 28 | } 29 | 30 | func cdnImageSrc(image *models.Image, param string) (out string) { 31 | out = fmt.Sprintf("%s%s%s", imageCdnHost, image.Key, param) 32 | return 33 | } 34 | func cdnSrc(in string) (out string) { 35 | out = fmt.Sprintf("%s%s", cdn, in) 36 | return 37 | } 38 | -------------------------------------------------------------------------------- /static/js/my.js: -------------------------------------------------------------------------------- 1 | //在基本模板中已近加载了jq可以在任意的房使用jq 2 | //有些方法需要在bootstrap.js 运行之后在运行 3 | //所有页面都需要执行该js 4 | 5 | 6 | 7 | 8 | //去掉html tag 得到 plain string 9 | function stripHtml(html) { 10 | var tmp = document.createElement("DIV"); 11 | tmp.innerHTML = html; 12 | return tmp.textContent || tmp.innerText || ""; 13 | } 14 | 15 | //资讯列表页面就执行以下js 16 | 17 | //The following solution works in Chrome, Firefox, Safari, IE9+ and also with iframes: 18 | 19 | 20 | 21 | 22 | //格式化是时间 23 | 24 | 25 | 26 | var current_url = window.location.href; 27 | 28 | 29 | $(function () { 30 | //设置导航菜单高亮 31 | $('.nav-link').each(function (i, dom) { 32 | //在html data-uri设置uri 33 | //根据网站设置高亮菜单 34 | var node_uri = $(dom).attr('href'); 35 | if (current_url.indexOf(node_uri) > 0) { 36 | $(dom).parent('li.nav-item').toggleClass('active') 37 | } 38 | }); 39 | //设置面包屑高亮 40 | }); -------------------------------------------------------------------------------- /models/modelImgur.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "encoding/json" 7 | 8 | "github.com/jinzhu/gorm" 9 | ) 10 | 11 | type Imgur struct { 12 | gorm.Model 13 | imgur_id string 14 | title string 15 | title_tanslation string 16 | description string 17 | description_tanslation string 18 | keywords string 19 | Images []Image 20 | } 21 | 22 | func FetchAllImgurCached() (imgurs []Imgur) { 23 | 24 | if x, found := CacheManager.Get(CK_Imgur_ALL); found { 25 | buffer := x.([]byte) 26 | json.Unmarshal(buffer, &imgurs) 27 | } else { 28 | Gorm.Preload("Images").Find(&imgurs) 29 | buffer, _ := json.Marshal(imgurs) 30 | CacheManager.Set(CK_Imgur_ALL,buffer, C_EXPIRE_TIME_HOUR_01) 31 | } 32 | return 33 | } 34 | 35 | func (imgur *Imgur) AfterFind() (err error) { 36 | //装换excerpt 37 | return 38 | } 39 | -------------------------------------------------------------------------------- /controllers/controllerError.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | type ErrorController struct { 8 | beego.Controller 9 | } 10 | 11 | func (c *ErrorController) Error404() { 12 | c.Data["content"] = "page not found" 13 | c.TplName = "error/404.html" 14 | } 15 | 16 | func (c *ErrorController) Error501() { 17 | c.Data["content"] = "server error" 18 | c.TplName = "error/404.html" 19 | } 20 | func (c *ErrorController) Error503() { 21 | c.Data["content"] = "server error" 22 | c.TplName = "error/404.html" 23 | } 24 | func (c *ErrorController) Error500() { 25 | c.Data["content"] = "server error" 26 | c.TplName = "error/404.html" 27 | } 28 | func (c *ErrorController) Error401() { 29 | c.Data["content"] = "server error" 30 | c.TplName = "error/404.html" 31 | } 32 | 33 | func (c *ErrorController) Error403() { 34 | c.Data["content"] = "server error" 35 | c.TplName = "error/404.html" 36 | } 37 | func (c *ErrorController) ErrorDb() { 38 | c.Data["content"] = "database is now down" 39 | c.TplName = "error/404.html" 40 | } 41 | -------------------------------------------------------------------------------- /models/modelTag.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "encoding/json" 7 | "time" 8 | 9 | "github.com/jinzhu/gorm" 10 | ) 11 | 12 | type Tag struct { 13 | gorm.Model 14 | Name string 15 | Description string 16 | KeyWord string 17 | Image *Image 18 | ImageId uint 19 | NameEn string 20 | Articles []Article `gorm:"many2many:article_tag;"` 21 | ArticleCount int `gorm:"-"` 22 | } 23 | 24 | func FetchAllTagsCached() (tags []Tag) { 25 | 26 | if x, found := CacheManager.Get(CK_TAG_ALL); found { 27 | buffer := x.([]byte) 28 | json.Unmarshal(buffer, &tags) 29 | } else { 30 | now := time.Now().AddDate(0, 0, -7) 31 | timestring := now.Format("2006-01-02 15:04:05") 32 | Gorm.Preload("Articles", "articles.created_at >?", timestring).Find(&tags) 33 | buffer, _ := json.Marshal(tags) 34 | CacheManager.Set(CK_TAG_ALL, buffer, C_EXPIRE_TIME_FOREVER) 35 | } 36 | return 37 | } 38 | 39 | func (tag *Tag) AfterFind() (err error) { 40 | //装换excerpt 41 | tag.ArticleCount = len(tag.Articles) 42 | return 43 | } 44 | -------------------------------------------------------------------------------- /tests/default_test.go: -------------------------------------------------------------------------------- 1 | package test 2 | 3 | import ( 4 | "net/http" 5 | "net/http/httptest" 6 | "testing" 7 | "runtime" 8 | "path/filepath" 9 | _ "my_go_web/routers" 10 | 11 | "github.com/astaxie/beego" 12 | . "github.com/smartystreets/goconvey/convey" 13 | ) 14 | 15 | func init() { 16 | _, file, _, _ := runtime.Caller(1) 17 | apppath, _ := filepath.Abs(filepath.Dir(filepath.Join(file, ".." + string(filepath.Separator)))) 18 | beego.TestBeegoInit(apppath) 19 | } 20 | 21 | 22 | // TestBeego is a sample to run an endpoint test 23 | func TestBeego(t *testing.T) { 24 | r, _ := http.NewRequest("GET", "/", nil) 25 | w := httptest.NewRecorder() 26 | beego.BeeApp.Handlers.ServeHTTP(w, r) 27 | 28 | beego.Trace("testing", "TestBeego", "Code[%d]\n%s", w.Code, w.Body.String()) 29 | 30 | Convey("Subject: Test Station Endpoint\n", t, func() { 31 | Convey("Status Code Should Be 200", func() { 32 | So(w.Code, ShouldEqual, 200) 33 | }) 34 | Convey("The Result Should Not Be Empty", func() { 35 | So(w.Body.Len(), ShouldBeGreaterThan, 0) 36 | }) 37 | }) 38 | } 39 | 40 | -------------------------------------------------------------------------------- /models/initialize.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //初始化数据库配置 4 | //http://jinzhu.me/gorm/ gorm 文档 5 | import ( 6 | "fmt" 7 | "time" 8 | 9 | "github.com/astaxie/beego" 10 | _ "github.com/go-sql-driver/mysql" 11 | "github.com/jinzhu/gorm" 12 | "github.com/patrickmn/go-cache" 13 | ) 14 | 15 | //这个是查血的初始 16 | var Gorm *gorm.DB 17 | 18 | const PageSize = 18 19 | 20 | var CacheManager *cache.Cache 21 | 22 | func init() { 23 | //和模型一起实例化一个缓存管理器 24 | CacheManager = cache.New(5*time.Minute, 10*time.Minute) 25 | 26 | user := beego.AppConfig.String("mysqluser") 27 | passwd := beego.AppConfig.String("mysqlpass") 28 | host := beego.AppConfig.String("mysqlurls") 29 | port, err := beego.AppConfig.Int("mysqlport") 30 | dbname := beego.AppConfig.String("mysqldb") 31 | if nil != err { 32 | port = 3306 33 | } 34 | db, err := gorm.Open("mysql", fmt.Sprintf("%s:%s@tcp(%s:%d)/%s?charset=utf8&parseTime=True&loc=Local", user, passwd, host, port, dbname)) 35 | db.DB().SetConnMaxLifetime(600) //TODO::这个地方有可能产生bug 36 | db.DB().SetMaxOpenConns(128) 37 | db.DB().SetMaxIdleConns(16) 38 | //https://github.com/jinzhu/gorm/issues/1053 39 | Gorm = db 40 | Gorm.LogMode(false) 41 | } 42 | -------------------------------------------------------------------------------- /controllers/imageController.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/astaxie/beego" 5 | ) 6 | 7 | // ArticlesController operations for Articles 8 | type ImageController struct { 9 | beego.Controller 10 | } 11 | 12 | // func (c *ImageController) GetOne() { 13 | // articleID, _ := c.GetInt(":id") 14 | // v, err := models.GetArticlesById(articleID) 15 | 16 | // if err != nil { 17 | // //404 18 | // } else { 19 | // //设置head seo参数 20 | // //设置breadcrumb 21 | // //设置side bar 22 | // //设置head navigation bar 23 | // c.Data["Article"] = v 24 | // c.Layout = "layout/base.html" 25 | // c.TplName = "article/detail.html" 26 | // } 27 | // } 28 | 29 | // func (c *ImageController) Upload() { 30 | // _, articles := models.GetAllArticles() 31 | // c.Data["Articles"] = articles 32 | // c.Data["Title"] = "aweosme go web application!!!!" 33 | // c.Layout = "layout/base.html" 34 | // c.TplName = "article/index.html" 35 | // } 36 | 37 | // func (c *ImageController) Upload_canvas() { 38 | // _, articles := models.GetAllArticles() 39 | // c.Data["Articles"] = articles 40 | // c.Data["Title"] = "aweosme go web application!!!!" 41 | // c.Layout = "layout/base.html" 42 | // c.TplName = "image/cropper_modal.html" 43 | // } 44 | -------------------------------------------------------------------------------- /models/modelQuote.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "encoding/json" 7 | "math/rand" 8 | "strconv" 9 | 10 | "github.com/jinzhu/gorm" 11 | ) 12 | 13 | type Quote struct { 14 | gorm.Model 15 | English string `json: "english";` 16 | Chinese string `json:"chinese";` 17 | Writer string `gorm:"size:255";json:"writer";` 18 | ImageUri string `orm:"column(body)";json:"image_uri";` 19 | } 20 | 21 | func Get3RandomQuote() (quotes []Quote) { 22 | if x, found := CacheManager.Get(CK_QUOTE); found { 23 | buffer := x.([]byte) 24 | json.Unmarshal(buffer, "es) 25 | } else { 26 | quotes = QuoteRandom3() 27 | buffer, _ := json.Marshal("es) 28 | CacheManager.Set(CK_QUOTE, buffer, C_EXPIRE_TIME_FOREVER) 29 | } 30 | return 31 | } 32 | 33 | func QuoteRandom3() (quotes []Quote) { 34 | var count int 35 | Gorm.Model(&Quote{}).Count(&count) 36 | rand.Seed(int64(count)) // Try changing this number! 37 | na := strconv.Itoa(rand.Intn(count)) 38 | nb := strconv.Itoa(rand.Intn(count)) 39 | nc := strconv.Itoa(rand.Intn(count)) 40 | nd := strconv.Itoa(rand.Intn(count)) 41 | ne := strconv.Itoa(rand.Intn(count)) 42 | indexs := []string{na, nb, nc, nd, ne} 43 | Gorm.Model(&Quote{}).Where("id in (?)", indexs).Find("es) 44 | return 45 | } 46 | -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | //init(register) html-template function ... 5 | 6 | "www.mojotv.cn/controllers" 7 | _ "www.mojotv.cn/models" 8 | _ "www.mojotv.cn/routers" 9 | _ "www.mojotv.cn/tasks" //启动定时任务 10 | _ "www.mojotv.cn/tools" //init reuters 11 | //init(register) html-template function ... 12 | 13 | "github.com/astaxie/beego" 14 | "github.com/astaxie/beego/plugins/cors" 15 | ) 16 | 17 | func main() { 18 | 19 | beego.SetLogger("file", `{"filename":"weibologin.log"}`) 20 | 21 | //spider.RunDygodMovieSpider() 22 | //没56分钟27秒执行一次; 23 | //2两小时一次 24 | //spider.RunDygodMeijuSpider() 25 | //taskSpiderDygodMeiju := toolbox.NewTask("taskSpiderDygodMeiju", "27 * */2 * * *", func() error { spider.RunDygodMeijuSpider(); return nil }) 26 | //toolbox.AddTask("taskSpiderDygodMeiju", taskSpiderDygodMeiju) 27 | //toolbox.StartTask() 28 | beego.ErrorController(&controllers.ErrorController{}) 29 | beego.InsertFilter("*", beego.BeforeRouter, cors.Allow(&cors.Options{ 30 | AllowAllOrigins: true, 31 | AllowMethods: []string{"GET", "POST", "PUT", "DELETE", "OPTIONS"}, 32 | AllowHeaders: []string{"Origin", "Authorization", "Access-Control-Allow-Origin", "Content-Type"}, 33 | ExposeHeaders: []string{"Content-Length", "Access-Control-Allow-Origin"}, 34 | })) 35 | beego.Run() 36 | } 37 | -------------------------------------------------------------------------------- /views/layout/base_view.html: -------------------------------------------------------------------------------- 1 | {{template "layout/_head.html" .}} 2 | 3 | 4 | 5 | {{template "layout/_nav.html" .}} 6 | 7 | 8 |
9 |
10 | 11 |
12 | 13 | {{template "layout/_breadcrumb.html" .}} 14 | 15 | 16 | {{.LayoutContent}} 17 | 18 | {{template "layout/_share_comment.html" .}} 19 |
20 | 21 | 22 | 23 |
24 | 25 | {{template "layout/_tags.html" .}} 26 | 27 | 28 | {{range $key, $img := .Imgs}} 29 |
30 | 31 |
32 | {{end}} 33 | 34 |
35 |
    36 | {{range $key, $val := .Quotes}} 37 |
  • {{$val.English}}
  • 38 | {{end}} 39 |
40 |
41 | 42 |
43 | 44 | 45 | 46 | 47 |
48 | 49 |
50 | {{template "layout/_footer.html" .}} 51 | 52 | {{template "layout/_script.html" .}} 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /views/article/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{range $index, $value := .Articles}} 6 |
7 |
8 | 9 | {{$value.Title}} 10 | 11 |
12 |
13 | 14 |

{{$value.Title}}

15 |
16 | 17 |

18 | {{ $value.Excerpt }}... 19 |

20 |
    21 |
  • 22 | {{$value.CreatedDate}} 23 |
  • 24 | 25 |
  • 26 | {{$value.CreatedTime}} 27 | 28 |
  • 29 |
  • 30 | {{$value.ReadCount}} 31 |
  • 32 |
  • 33 | {{1000}} 34 |
  • 35 |
  • 36 | {{1001}} 37 |
  • 38 |
39 |
40 | 41 |
42 | {{end}} 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /ssl/214011752730233.key: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIIEogIBAAKCAQEA43rwgV7YfCowa487uuL+UssuHsT13pfLyvwOpNkXv+TsF2rC 3 | EnSk7c5WBTA9zFasBTHnW9B8jYZjhCT77kUTTIeAfGpCRJPKU5R9P5IH0mfG2D9O 4 | +Xsy8gIl+qkc7pFzG17zr8YkFmG1+SGZIf4oHct3WYtk/NlPG03gr26R7jod1XWl 5 | ptUd2HGt+W3dZkdBvkedm+QAo2+wcIcXS8qZ5ULTpj3b9AjmtR7/u35J/a/PuMoS 6 | 1imMkyya9zpSgWqcGDm8RNZP1Lc3rkMWEGMc27GL+FWkGAf+y0WZHjTNyIU/OQko 7 | EOkDLgtV+1o3cmZzYrpfDp4gT36RASM0FWemMQIDAQABAoIBABKskPnN02+99uOd 8 | ioW5BK+/RjX4bUasp2oubvVRbQWvwUHa3buuH6v1+FHMuAYCR3TVt+xtnQvxMFI0 9 | xwm0WfU6Wm3cOzxt9XoPAokpb8LyCfzOlakdV/1N99gv8dQT1KM2lEKlvWio9MtS 10 | 2sNTne90OIP9UXkATeIr7nn4Vbp8mz5XLzr+el1s6Ko0w7cs257wzJochcQEeBru 11 | ZKb76+JG/7a0eP7nX/16wqzvQ1vZAHvEqxBHiK+WstkIssrwbpWmeGzNQJUfyd72 12 | VOTkjsnu8rgzuh0zau5soErHq5iDWuBAI/tvErsHa2wS6+3w4k1PrM5Vv0+jHtmX 13 | +L152cECgYEA9N9A/XdCpQkxI3BawS5IPxH70n+VzcIotEBnuML6S/Ddsjxe84Z3 14 | GBhbYta4nzncdiuztVcO+wpO8D44Kvt2LERvnIA55EZ3aBxZiJbFQ3InbKA9ZzlM 15 | 1UjyCMH9zJgQYiwbQ7Le4fLiEVZH2/Q9ls/rQ7waXTpyK+R458hO9PUCgYEA7dFb 16 | B6FPmY09ljAe0c0ANbE5iwUH+JymhvhtC6xhAz0n8DnlxjKMVwqliFodxyrHiIbx 17 | HX+91GJB23YIQNrhhW0mJbP421v7uAcmFftbDpZgN79UdrAGt/tmd9XXJz9aPua4 18 | BCxoPg/aWl33I68JceG0Kzb8Kl42JnU6FHbYxs0CgYBI1WK6QU/EUNCZzuBfl0mL 19 | 4Oh6+tHu6nI68vEm5m+WSOVYD1barkMcGpqL8nvleEtXprYEGQnup2lFUexY9IR4 20 | tD5SWV1exYrcn5oN43J3FiwdxiedXVC6G8FJ05GO2if9W0scvsZGhHyzVWt4Q9RR 21 | 2DQM6JUa57hvz7wajNzXRQKBgCtoPQ9FeDv0tbsGCXoNyu4B7Rjc0DmmjhawnWa2 22 | DfcDYJjOWIw2ibsRbGlY2XqS6lyXFMdnm4R6cr7V6me8C9HIvF/BW7jeLzHFzEPS 23 | 3ynodKN4PrhzJKbMMkXJOD4nqBc3EXthh51cU2SPJh7TQgwRQEtq+9fX3lZiqzk1 24 | ABg5AoGAN7/iKpCBYhS9urOi3fORmIi8P+g4vc2rdR4Yjt8xkIxKAvemTvgKs2FG 25 | ggZ5fbQdfTi9FTuJ+/lQx6eluefx03Leb0GVU2wnFZUqX/wCbmNBUx9wTVSCTHXB 26 | TUnH2pjygHNiddmCijdffvIBmNOyeoEwGa9YTwNBsx/a8iLUpm0= 27 | -----END RSA PRIVATE KEY----- 28 | -------------------------------------------------------------------------------- /controllers/controllerTag.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "fmt" 5 | "www.mojotv.cn/models" 6 | ) 7 | 8 | type TagController struct { 9 | BaseController 10 | } 11 | 12 | func (c *TagController) View() { 13 | tagId, _ := c.GetInt(":id") 14 | //浏览计数 15 | tag := models.Tag{} 16 | var articles []models.Article 17 | models.Gorm.First(&tag, tagId) 18 | 19 | //models.Gorm.Related("Tags", "article_tag.tag_id = ?", tag.ID).Preload("Images").Limit(90).Find(&articles) 20 | if models.Gorm.Model(&tag).Order("articles.created_at desc").Limit(models.PageSize).Preload("Images").Preload("Vote").Related(&articles, "Articles").RecordNotFound() { 21 | c.Abort("404") 22 | } 23 | 24 | //设置head seo参数 25 | //设置breadcrumb 26 | //设置side bar 27 | //设置head navigation bar 28 | url := fmt.Sprintf("/tag/%d", tagId) 29 | c.Data["BreadCrumbs"] = []Crumb{{"/", "fa fa-home", "首页"}, {url, "fa fa-navicon", tag.Name}} 30 | c.Data["Tag"] = tag 31 | c.Data["Articles"] = articles 32 | c.Data["Title"] = tag.Name 33 | c.Data["Keyword"] = tag.KeyWord 34 | c.Data["Description"] = tag.Description 35 | 36 | c.Layout = "layout/base_index.html" 37 | c.TplName = "tag/view.html" 38 | } 39 | func (c *TagController) LoadMore() { 40 | offset, _ := c.GetInt("offset") 41 | size, _ := c.GetInt("size") 42 | tagId, _ := c.GetInt("tagId") 43 | tag := models.Tag{} 44 | tag.ID = uint(tagId) 45 | articles := []models.Article{} 46 | models.Gorm.Model(&tag).Offset(offset).Limit(size).Order("articles.created_at DESC").Preload("Images").Preload("Tags").Preload("Vote").Related(&articles, "Articles") 47 | c.JsonRetrun("success", "欢迎访问我们的小站", articles) 48 | } 49 | 50 | func (c *TagController) IndexPost() { 51 | var tags []models.Tag 52 | models.Gorm.Find(&tags) 53 | c.JsonRetrun("success", "欢迎使用moojoTV", tags) 54 | } 55 | -------------------------------------------------------------------------------- /tasks/fetchEztv.go: -------------------------------------------------------------------------------- 1 | package tasks 2 | 3 | import ( 4 | "encoding/xml" 5 | "fmt" 6 | "io/ioutil" 7 | "net/http" 8 | 9 | "www.mojotv.cn/models" 10 | 11 | "github.com/astaxie/beego/toolbox" 12 | ) 13 | 14 | const EZTV_XML_URL = "https://eztv.ag/ezrss.xml" 15 | 16 | type Rss struct { 17 | XMLName xml.Name `xml:"rss"` 18 | Channel ChannelNode `xml:"channel"` 19 | } 20 | type ChannelNode struct { 21 | XMLName xml.Name `xml:"channel"` 22 | Episodes []EztvXmlEpisode `xml:"item"` 23 | } 24 | type EztvXmlEpisode struct { 25 | XMLName xml.Name `xml:"item"` 26 | Title string `xml:"title"` 27 | MagnetURI string `xml:"magnetURI"` 28 | } 29 | 30 | //启动定时任务 31 | func init() { 32 | //创建定时任务 33 | taskFetchEztvXml := toolbox.NewTask("fetch-eztv", "43 13 8-20 * * *", fetchEztvXmlThenParse) 34 | //err := taskFetchEztvXml.Run() 35 | //检测定时任务 36 | // if err != nil { 37 | // log.Fatal(err) 38 | // } 39 | //添加定时任务 40 | toolbox.AddTask("fetch-eztv", taskFetchEztvXml) 41 | //启动定时任务 42 | toolbox.StartTask() 43 | //defer toolbox.StopTask() 44 | } 45 | 46 | func fetchEztvXmlThenParse() error { 47 | resp, err := http.Get(EZTV_XML_URL) 48 | if err != nil { 49 | return err 50 | } 51 | defer resp.Body.Close() 52 | if err == nil && resp.StatusCode == 200 { 53 | body, _ := ioutil.ReadAll(resp.Body) 54 | v := Rss{} 55 | err = xml.Unmarshal(body, &v) 56 | if err != nil { 57 | return err 58 | } else { 59 | for _, vo := range v.Channel.Episodes { 60 | temp := models.Episode{} 61 | err := models.Gorm.Where(models.Episode{RawName: vo.Title}).Assign(models.Episode{Name: vo.Title, UrlMagnet: vo.MagnetURI, Provider: "eztv"}).FirstOrCreate(&temp).Error 62 | fmt.Println(err) 63 | } 64 | return nil 65 | } 66 | } else { 67 | return err 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /controllers/controllerFantasy.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "fmt" 5 | "time" 6 | 7 | "io/ioutil" 8 | "math/rand" 9 | "www.mojotv.cn/models" 10 | "net/http" 11 | 12 | "github.com/astaxie/beego" 13 | ) 14 | 15 | type FantasyController struct { 16 | beego.Controller //集成beego controller 17 | } 18 | 19 | func (c *FantasyController) Index() { 20 | 21 | myChannelId := c.GetString(":mcid") 22 | channelId := c.GetString(":cid", "33716") 23 | vId := c.GetString(":vid", "87816") 24 | t := fmt.Sprint(rand.ExpFloat64()) 25 | //https://www.fantasy.tv/tv/playDetails.action?myChannelId=33716&id=87816&channelId=33716&t=0.0958195376527875 26 | cacheKey := fmt.Sprintf("myChannelId=%s&id=%s&channelId=%s", myChannelId, vId, channelId) 27 | var content []byte 28 | if x, found := models.CacheManager.Get(cacheKey); found { 29 | foo := x.(string) 30 | content = []byte(foo) 31 | } else { 32 | client := &http.Client{} 33 | apiUrl := fmt.Sprintf("https://www.fantasy.tv/tv/playDetails.action?myChannelId=%s&id=%s&channelId=%s&t=%s", myChannelId, vId, channelId, t) 34 | fmt.Println(apiUrl) 35 | req, _ := http.NewRequest("GET", apiUrl, nil) 36 | req.Header = http.Header{ 37 | "Cookie": {"acw_tc=AQAAAB4/YV0LXwIA8cxxq7tfQBTcUPei"}, 38 | "Referer": {"https://www.fantasy.tv/newApp/index.html"}, 39 | "User-Agent": {"Mozilla/5.0 (iPhone; CPU iPhone OS 9_1 like Mac OS X) AppleWebKit/601.1.46 (KHTML, like Gecko) Version/9.0 Mobile/13B143 Safari/601.1"}, 40 | "Host": {"www.fantasy.tv"}, 41 | } 42 | resp, err := client.Do(req) 43 | 44 | defer resp.Body.Close() 45 | if err == nil && resp.StatusCode == 200 { 46 | body, _ := ioutil.ReadAll(resp.Body) 47 | content = body 48 | //放缓存 49 | models.CacheManager.Set(cacheKey, string(content), time.Second*90) 50 | } 51 | } 52 | c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8") 53 | c.Ctx.Output.Body(content) 54 | return 55 | } 56 | -------------------------------------------------------------------------------- /controllers/controllerVideo.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "fmt" 5 | "io/ioutil" 6 | "www.mojotv.cn/models" 7 | "net/http" 8 | "regexp" 9 | 10 | "github.com/astaxie/beego" 11 | ) 12 | 13 | type VideoController struct { 14 | beego.Controller //集成beego controller 15 | 16 | } 17 | 18 | func (c *VideoController) WeiboVideoParse() { 19 | fid := c.GetString("id") 20 | key := fmt.Sprint("mp4.", fid) 21 | if x, found := models.CacheManager.Get(key); found { 22 | c.Data["json"] = x.(string) 23 | } else { 24 | mp4Url := c.fetchMp4Url(fid) 25 | c.Data["json"] = mp4Url 26 | //这个过期时间也许还需要调整 进过验证有效期为一小时 27 | models.CacheManager.Set(key, mp4Url, models.C_EXPIRE_TIME_MIN_01*55) 28 | } 29 | c.ServeJSON() 30 | } 31 | 32 | func (c *VideoController) fetchMp4Url(fid string) (mp4Url string) { 33 | url := fmt.Sprint("http://video.weibo.com/show?fid=", fid, "&type=mp4") 34 | //reg := regexp.MustCompile() 35 | client := &http.Client{} 36 | req, _ := http.NewRequest("GET", url, nil) 37 | req.Header.Add("Referer", "http://weibo.com/home?wvr=5") 38 | req.Header.Add("User-Agent", "Mozilla/5.0 (Linux; Android 4.4.2; Nexus 4 Build/KOT49H) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/34.0.1847.114 Mobile Safari/537.36") 39 | req.Header.Add("Host", "www.miaopai.com") 40 | req.Header.Add("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8") 41 | req.Header.Add("Accept-Language", "en-US,en;q=0.8") 42 | req.Header.Add("Accept-Charset", "UTF-8,*;q=0.5") 43 | mp4Url = "" 44 | if resp, err := client.Do(req); err == nil && resp.StatusCode == 200 { 45 | bodyBytes, _ := ioutil.ReadAll(resp.Body) 46 | bodyString := string(bodyBytes) 47 | //
78 | 79 | 80 | 81 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 126 | 127 | -------------------------------------------------------------------------------- /views/layout/_nav.html: -------------------------------------------------------------------------------- 1 | 70 | 71 | 72 | 98 | 117 | {{template "tag/_allTags.html" .}} -------------------------------------------------------------------------------- /views/home/index.html: -------------------------------------------------------------------------------- 1 |
2 | {{range $index, $value := .Articles}} 3 | 4 |
5 |
6 | 7 | 8 |
9 | {{$value.Title}} 10 |
11 | {{$value.FirstTagName}} 12 | {{$value.CreatedHumanTime}} 13 |

{{$value.Title}}

14 |
15 |
16 |
17 | 18 | 19 | 20 |
21 | 22 |

{{ $value.Excerpt }}

23 |
    24 |
  • 25 | 26 | {{$value.CreatedDate}} 27 |
  • 28 |
  • 29 | 30 | {{$value.Vote.Visit}} 31 |
  • 32 | 33 |
  • 34 | 35 | {{$value.Vote.Score}} 36 |
  • 37 |
  • 38 | 39 | {{$value.Vote.FavorateCount}} 40 |
  • 41 |
42 | 43 |
44 | 45 |
46 | 47 | 48 |
49 | 50 | {{end}} 51 |
52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /views/tag/view.html: -------------------------------------------------------------------------------- 1 |
2 | {{range $index, $value := .Articles}} 3 | 4 |
5 |
6 | 7 | 8 |
9 | {{$value.Title}} 10 | 11 |
12 | {{$.Tag.Name}} 13 | {{$value.CreatedHumanTime}} 14 |

{{$value.Title}}

15 |
16 |
17 |
18 | 19 | 20 | 21 |
22 | 23 |

{{ $value.Excerpt }}

24 | 25 |
    26 |
  • 27 | 28 | {{$value.CreatedDate}} 29 |
  • 30 | 31 |
  • 32 | 33 | {{$value.Vote.Visit}} 34 |
  • 35 | 36 |
  • 37 | 38 | {{$value.Vote.Score}} 39 |
  • 40 |
  • 41 | 42 | {{$value.Vote.FavorateCount}} 43 |
  • 44 |
45 | 46 |
47 | 48 |
49 | 50 | 51 |
52 | 53 | {{end}} 54 |
55 | 56 | 57 | 58 | 59 | -------------------------------------------------------------------------------- /controllers/controllerRenRen.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "bytes" 5 | "crypto/md5" 6 | "encoding/hex" 7 | "fmt" 8 | "io/ioutil" 9 | "www.mojotv.cn/models" 10 | "net/http" 11 | "net/url" 12 | 13 | "github.com/astaxie/beego" 14 | ) 15 | 16 | const SERVER = "https://api.rr.tv" 17 | const SECRET_KEY = "clientSecret=08a30ffbc8004c9a916110683aab0060" 18 | 19 | //const TOKEN = "945e82b94c08447aafe45e6051159737" 20 | const TOKEN = "35dafc24e73d461a94c2e69daef72c6b" //我的iOStoken 21 | 22 | var TOKENS = []string{ 23 | "91b7fc36672548259433ca40bc57e6dd", //我的 24 | "35dafc24e73d461a94c2e69daef72c6b", //我的 25 | "99ce6f3f7ff840e586958770472ec893", 26 | "37570aa5dabe44219ab8a13986778390", 27 | "6f8443b2d6c54d39bf7ab780bb5df3b2", 28 | "3739e42b649948febad6dbfeaeecddfe", 29 | "ffeb43e117d744e6822c3fe6abc12dea", 30 | "5f6d0d3a49e5439e8492515c49b797c5", 31 | "41d74adccd4b46389882242949e82cea", 32 | "ff750a61e2684b7d9d4f783b4e3b14b1", 33 | "f703dcbae2fb42889e8b111829b36167", 34 | "9aea227ebb224a8b9bea347c13192706", 35 | "827af86209464b038552a87f1cd546b2", 36 | "bfc156b8c9ce48d98f2f9e48868130b3", 37 | "c0a60ecf198d458d83b475e50b8d7893", 38 | "22f6e8f0fac049849ce6db26535ecf6d", 39 | "cce5bae0fcdd446fa87f0e61d86cd345", 40 | "d1f33f20d83441228adf791215308d6d", 41 | "803db2c8c9de400a9e90f75c2926d98a", 42 | "b7c4f78d734f48fb871b3c7667f32019", 43 | "99b3109e62fa4f1eb449182f5428cb84", 44 | "10347e508c5946ec9116e3044b728f01", 45 | } 46 | 47 | var tokenIndex = 0 48 | 49 | func generateFakeHeader() (headers http.Header) { 50 | // var randomToken = TOKENS[tokenIndex%(len(TOKENS))] 51 | return http.Header{ 52 | "token": {"6b6cfdd3e90843c0a0914425638db7ef"}, 53 | "clientType": {"android_RRMJ"}, 54 | "clientVersion": {"3.6.3"}, 55 | "deviceId": {"861134030056126"}, 56 | "signature": {"643c184f77372e364550e77adc0360cd"}, 57 | "t": {"1491433993933"}, 58 | "Content-Type": {"application/x-www-form-urlencoded"}, 59 | "Authentication": {"RRTV 470164b995ea4aa5a53f9e5cbceded472:IxIYBj:LPWfRb:I9gvePR5R2N8muXD7NWPCj"}, 60 | } 61 | } 62 | 63 | type RenRenController struct { 64 | beego.Controller //集成beego controller 65 | } 66 | 67 | func (c *RenRenController) Index() { 68 | apiURI := "/v3plus/video/indexInfo" 69 | cacheKey := fmt.Sprint(SERVER, apiURI) 70 | paraData := url.Values{} 71 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 72 | } 73 | 74 | //根据episodeId找到对应的电视剧播放地址 75 | func (c *RenRenController) M3u8() { 76 | //55872 77 | var FakeHeader = generateFakeHeader() 78 | var episodeSid = c.GetString(":episodeSid") 79 | //https://github.com/wilsonwen/kanmeiju/blob/adc56d8665b3c99a8d48df3cc2f1eaf623f7be6e/index.js line203 80 | apiURI := "/video/findM3u8ByEpisodeSidAuth" 81 | cacheKey := fmt.Sprint(SERVER, apiURI, "/episodeSid/", episodeSid) 82 | 83 | paraData := url.Values{ 84 | "episodeSid": {episodeSid}, 85 | "quality": {"super"}, 86 | "token": {TOKEN}, 87 | "seasonId": {"0"}, 88 | } 89 | key := fmt.Sprint("episodeSid=", episodeSid, "quality=super", "clientType=", FakeHeader["clientType"][0], "clientVersion=", FakeHeader["clientVersion"][0], "t=", FakeHeader["t"][0], SECRET_KEY) 90 | signature := GetMD5Hash(key) 91 | FakeHeader["signature"] = []string{signature} 92 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, FakeHeader) 93 | 94 | } 95 | func GetMD5Hash(text string) string { 96 | hasher := md5.New() 97 | hasher.Write([]byte(text)) 98 | return hex.EncodeToString(hasher.Sum(nil)) 99 | } 100 | 101 | func (c *RenRenController) Search() { 102 | searchWord := c.GetString(":keyword") 103 | //https://github.com/wilsonwen/kanmeiju/blob/adc56d8665b3c99a8d48df3cc2f1eaf623f7be6e/index.js line203 104 | apiURI := "/v3plus/video/search" 105 | cacheKey := fmt.Sprint(SERVER, apiURI, "/name/", searchWord) 106 | paraData := url.Values{ 107 | "title": {searchWord}, 108 | "enTitle": {searchWord}, 109 | } 110 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 111 | } 112 | 113 | func (c *RenRenController) Hot() { 114 | apiURI := "/video/seasonRankingList" 115 | cacheKey := fmt.Sprint(SERVER, apiURI) 116 | paraData := url.Values{} 117 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 118 | } 119 | 120 | func (c *RenRenController) Top() { 121 | apiURI := "/v3plus/season/topList" 122 | cacheKey := fmt.Sprint(SERVER, apiURI) 123 | paraData := url.Values{} 124 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 125 | } 126 | 127 | func (c *RenRenController) Season() { 128 | apiURI := "/v3plus/season/detail" 129 | seasonId := c.GetString(":seasonId") 130 | cacheKey := fmt.Sprint(SERVER, apiURI, "/seasonId/", seasonId) 131 | paraData := url.Values{ 132 | "seasonId": {seasonId}, 133 | } 134 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 135 | } 136 | 137 | func (c *RenRenController) Album() { 138 | apiURI := "/v3plus/video/album" 139 | albumId := c.GetString(":albumId") 140 | cacheKey := fmt.Sprint(SERVER, apiURI, "/albumId/", albumId) 141 | paraData := url.Values{ 142 | "albumId": {albumId}, 143 | } 144 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 145 | } 146 | 147 | func (c *RenRenController) Category() { 148 | apiURI := "/v3plus/video/search" 149 | cat := c.GetString(":categoryType") 150 | pages := c.GetString(":pages") 151 | cacheKey := fmt.Sprint(SERVER, apiURI, "/category/", cat, "/pages/", pages) 152 | paraData := url.Values{ 153 | "cate": {"cat_list"}, 154 | "cat": {cat}, 155 | "pages": {pages}, 156 | } 157 | c.cacheOrPostReturnJson(cacheKey, apiURI, paraData, generateFakeHeader()) 158 | } 159 | 160 | func (c *RenRenController) cacheOrPostReturnJson(cacheKey string, apiURI string, paraData url.Values, headers http.Header) { 161 | apiUrl := fmt.Sprint(SERVER, apiURI) 162 | var content []byte 163 | if x, found := models.CacheManager.Get(cacheKey); found { 164 | foo := x.(string) 165 | content = []byte(foo) 166 | } else { 167 | client := &http.Client{} 168 | datUrl := paraData.Encode() 169 | req, _ := http.NewRequest("POST", apiUrl, bytes.NewBufferString(datUrl)) 170 | req.Header = headers 171 | resp, err := client.Do(req) 172 | defer resp.Body.Close() 173 | if err == nil && resp.StatusCode == 200 { 174 | body, _ := ioutil.ReadAll(resp.Body) 175 | content = body 176 | //放缓存 177 | models.CacheManager.Set(cacheKey, string(content), models.C_EXPIRE_TIME_HOUR_01) 178 | } 179 | } 180 | c.Ctx.Output.Header("Content-Type", "application/json; charset=utf-8") 181 | c.Ctx.Output.Body(content) 182 | return 183 | } 184 | -------------------------------------------------------------------------------- /controllers/controllerAuth.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "www.mojotv.cn/models" 7 | "net/http" 8 | "net/url" 9 | 10 | "github.com/astaxie/beego" 11 | "github.com/astaxie/beego/logs" 12 | 13 | "golang.org/x/crypto/bcrypt" 14 | ) 15 | 16 | type AuthController struct { 17 | beego.Controller //集成beego controller 18 | 19 | } 20 | type WeibAuth2Response struct { 21 | Access_token string `json:"access_token"` 22 | Uid uint `json:"uid,string"` 23 | } 24 | 25 | //http://open.weibo.com/wiki/2/users/show 26 | type WeiboUser struct { 27 | Id uint `json:"id"` 28 | Screen_name string `json:"screen_name"` 29 | Name string `json:"name"` 30 | Description string `json:"description"` 31 | Avatar_large string `json:"avatar_large"` 32 | } 33 | 34 | //sign up 35 | func (c *AuthController) GetRegister() { 36 | user := models.User{} 37 | //weibo auth2 回调 38 | weiboCode := c.GetString("code") 39 | if weiboCode != "" { 40 | resp, _ := http.PostForm("https://api.weibo.com/oauth2/access_token", url.Values{ 41 | "client_id": {WeiboAppId}, 42 | "client_secret": {WeiboAppSecret}, 43 | "grant_type": {"authorization_code"}, 44 | "code": {weiboCode}, 45 | "redirect_uri": {"https://www.mojotv.cn/auth/register"}, 46 | }) 47 | defer resp.Body.Close() 48 | 49 | //解析json 获取token和uid 50 | 51 | var weiboResponseJson WeibAuth2Response 52 | json.NewDecoder(resp.Body).Decode(&weiboResponseJson) 53 | 54 | //logs.Debug("token struct:", weiboResponseJson) 55 | //logs.Debug("token uid and access token", weiboResponseJson.Uid, weiboResponseJson.Access_token) 56 | 57 | logs.Debug("first weibo id", weiboResponseJson.Uid) 58 | 59 | models.Gorm.Where("weibo_id = ?", weiboResponseJson.Uid).First(&user) 60 | // logs.Debug("weibo struct user:%v", user) 61 | // logs.Debug("weibo struct accesstoken:%v", weiboResponseJson) 62 | if user.ID > 0 { 63 | //用户已注册 64 | //直接登陆 65 | c.SetSession(AuthSessionName, user) 66 | c.Redirect("/", 303) 67 | return 68 | } 69 | //用户未注册 获取用户信息 70 | getURL := fmt.Sprintf("https://api.weibo.com/2/users/show.json?access_token=%s&uid=%d", weiboResponseJson.Access_token, weiboResponseJson.Uid) 71 | respInfo, _ := http.Get(getURL) 72 | defer respInfo.Body.Close() 73 | 74 | //解析json 获取token和uid 75 | var weiboUser WeiboUser 76 | json.NewDecoder(respInfo.Body).Decode(&weiboUser) 77 | //logs.Debug("weibo name info:%v", weiboUser.Name) 78 | //logs.Debug("weibo struct info:%v", weiboUser) 79 | logs.Debug("first weibo info id", weiboUser.Id) 80 | 81 | user.WeiboId = weiboUser.Id 82 | user.Name = weiboUser.Name 83 | user.AvatarImage = weiboUser.Avatar_large 84 | user.Email = fmt.Sprint("weibo_", weiboUser.Id, "@mojotv.cn") 85 | } 86 | c.Data["User"] = user 87 | c.Data["Xsrf"] = c.XSRFToken() //防止跨域 88 | c.TplName = "auth/register.html" 89 | } 90 | 91 | func (c *AuthController) PostRegister() { 92 | password := c.GetString("password") 93 | passwordConfirmed := c.GetString("password_confirmed") 94 | if password == "" || passwordConfirmed == "" || (password != passwordConfirmed) { 95 | c.Data["json"] = map[string]interface{}{"status": "error", "message": "两次输入的密码不相同,或者密码为空", "data": nil} 96 | c.ServeJSON() 97 | return 98 | 99 | } 100 | 101 | email := c.GetString("email") 102 | var isExistUser models.User 103 | models.Gorm.Where("email = ?", email).First(&isExistUser) 104 | if isExistUser.ID > 0 && isExistUser.WeiboId < 1 { 105 | beego.Warning("用户已近存在") 106 | c.Data["json"] = map[string]interface{}{"status": "error", "message": "email已经注册", "data": nil} 107 | c.ServeJSON() 108 | return 109 | } 110 | 111 | //hash password 112 | password_byte := []byte(password) 113 | hashedPassword, _ := bcrypt.GenerateFromPassword(password_byte, bcrypt.DefaultCost) 114 | //new struct from package 115 | //TODO:需要搞清楚 go语言的 pointer * &的用法 116 | isExistUser.Email = email 117 | isExistUser.Password = string(hashedPassword) 118 | isExistUser.Name = c.GetString("name") 119 | isExistUser.WeiboAvatar = c.GetString("avatar_image") 120 | wbId, _ := c.GetInt("weibo_id") 121 | logs.Debug("jerk:", wbId) 122 | isExistUser.WeiboId = uint(wbId) 123 | logs.Debug("jerk:", isExistUser.WeiboId) 124 | 125 | models.Gorm.Create(&isExistUser) 126 | if isExistUser.ID < 1 { 127 | beego.Critical("用户注册数据库添加失败") 128 | c.Data["json"] = map[string]interface{}{"status": "error", "message": "添加新用户失败", "data": nil} 129 | c.ServeJSON() 130 | return 131 | 132 | } else { 133 | c.SetSession(AuthSessionName, isExistUser) 134 | c.Data["json"] = map[string]interface{}{"status": "success", "message": "添加新用户成功", "data": nil} 135 | c.ServeJSON() 136 | return 137 | } 138 | } 139 | 140 | func (c *AuthController) PostLogin() { 141 | email := c.GetString("email") 142 | user := models.User{} 143 | models.Gorm.Table("users").Where("email = ?", email).First(&user) 144 | 145 | if user.ID < 1 { 146 | c.Data["json"] = map[string]interface{}{"status": "error", "message": "用户不存在", "data": nil} 147 | c.ServeJSON() 148 | return 149 | } else { 150 | //比较密码 151 | //string to []byte 152 | password := []byte(c.GetString("password")) 153 | //http://stackoverflow.com/questions/23259586/bcrypt-password-hashing-in-golang-compatible-with-node-js 154 | 155 | // Hashing the password with the default cost of 10 DefaultCost int = 10 156 | //laravel bcrypt /Library/WebServer/Documents/estate/vendor/laravel/framework/src/Illuminate/Hashing/BcryptHasher.php 157 | // Comparing the password with the hash 158 | db_hashed_password := []byte(user.Password) 159 | err := bcrypt.CompareHashAndPassword(db_hashed_password, password) 160 | if err == nil { // nil means it is a match 161 | //设置登陆session info 162 | c.SetSession(AuthSessionName, user) 163 | c.Data["json"] = map[string]interface{}{"status": "success", "message": "用户登陆成功", "data": nil} 164 | c.ServeJSON() 165 | return 166 | } else { 167 | c.Data["json"] = map[string]interface{}{"status": "error", "message": "密码错误", "data": nil} 168 | c.ServeJSON() 169 | return 170 | } 171 | } 172 | } 173 | 174 | // //find password 填写email 175 | func (c *AuthController) GetResetPassword() { 176 | 177 | } 178 | func (c *AuthController) PostResetPassword() { 179 | //获取email地址 发送邮件 180 | 181 | } 182 | 183 | // //注销 184 | func (c *AuthController) GetLogout() { 185 | c.DelSession(AuthSessionName) 186 | c.Redirect("/", 302) 187 | } 188 | 189 | func (c *AuthController) ToutiaoAd() { 190 | c.Redirect("/", 301) 191 | 192 | // c.Data["Title"] = "mojoTV美剧|最新最快最热的美剧周边资讯" 193 | // c.Data["Keyword"] = "mojoTV美剧,轻松学英语,欧美美剧资讯,国外搞笑小视频," 194 | // c.Data["Description"] = "mojoTV美剧|提供最新最热最快最热的美剧资讯,海量英语学习资源,欧美搞笑有创意的短视频gif动图,海量美剧双语原生字幕,这里是英语爱好者的乐园,让每一个人都爱上学习英语" 195 | // c.Layout = "layout/base_index.html" 196 | // c.TplName = "home/toutiaoAd.html" 197 | } 198 | -------------------------------------------------------------------------------- /models/modelArticle.go: -------------------------------------------------------------------------------- 1 | package models 2 | 3 | //http://jinzhu.me/gorm/ gorm 文档 4 | 5 | import ( 6 | "encoding/json" 7 | "math" 8 | "time" 9 | 10 | "strings" 11 | 12 | "regexp" 13 | 14 | "fmt" 15 | 16 | "github.com/astaxie/beego" 17 | "github.com/jinzhu/gorm" 18 | ) 19 | 20 | type Article struct { 21 | gorm.Model 22 | RawTitle string 23 | RawContent string 24 | Title string `gorm:"size:255"` 25 | Body string `orm:"column(body)"` 26 | UrlVideo string 27 | UrlProvider string 28 | VideoCode string 29 | IsShow uint 30 | KeyWord string 31 | Description string 32 | CoverageUri string 33 | VideoTitle string 34 | Images []Image 35 | Tags []Tag `gorm:"many2many:article_tag;"` 36 | Shows []Show `gorm:"many2many:article_show;"` 37 | Vote *Vote 38 | 39 | FirstTagName string `gorm:"_"` 40 | FirstTagNameEn string `gorm:"_"` 41 | FirstTagID uint `gorm:"_"` 42 | Excerpt string `gorm:"-"` 43 | CoverageURL string `gorm:"-"` 44 | CreatedDate string `gorm:"-"` 45 | CreatedTime string `gorm:"-"` 46 | CreatedHumanTime string `gorm:"-"` 47 | VideoYoukuId string `gorm:"-"` 48 | VideoMiaopaiId string `gorm:"-"` 49 | VideoWeiboId string `gorm:"-"` 50 | Links []Link `gorm:"-"` 51 | } 52 | 53 | const ShowHost = "//www.trytv.org/" 54 | 55 | //做一些计算 56 | func (art *Article) AfterFind() (err error) { 57 | //装换excerpt 58 | body := beego.HTML2str(art.Body) 59 | art.Excerpt = beego.Substr(body, 0, 120) 60 | //转换时间啊 61 | art.CreatedDate = beego.Date(art.CreatedAt, "m-d") 62 | art.CreatedTime = beego.Date(art.CreatedAt, "H:i") 63 | art.CreatedHumanTime = CovertTimeToHumanTime(art.CreatedAt) 64 | //param := "?imageView2/1/w/120/h/120" 65 | //param := "?imageView2/1/w/480/h/270" 66 | param := "?imageMogr2/thumbnail/!620x350r/gravity/Center/crop/480x270/blur/1x0/quality/80|watermark/2/text/bW9qb3R2/font/6buR5L2T/fontsize/360/fill/I0ZGRkZGRg==/dissolve/100/gravity/SouthWest/dx/10/dy/10|imageslim" 67 | 68 | imageModel := Image{Key: "article-placeholder"} 69 | if art.CoverageUri != "" { 70 | imageModel.Key = art.CoverageUri 71 | } 72 | art.CoverageURL = imageModel.GetImageURL(param) 73 | 74 | //解析视频类型的优酷vid 75 | if strings.Contains(art.UrlVideo, "youku.com") { 76 | //http://v.youku.com/v_show/id_XMjg4Mzc0NjAxMg==.html?spm=a2hww.20023042.m_223465.5~5~5~5!2~5~5~A&f=50346975 77 | //http://m.youku.com/video/id_XMjg4Mzc0NjAxMg==.html?spm=a2hww.20023042.m_223465.5~5~5~5!2~5~5~A&f=50346975&source= 78 | reg := regexp.MustCompile(`(?:id_)(\w+)(?:[=]{0,2}\.html)`) 79 | ids := reg.FindStringSubmatch(art.UrlVideo) 80 | for k, v := range ids { 81 | if k == 1 { 82 | art.VideoYoukuId = v 83 | } 84 | } 85 | } 86 | //解析微博 87 | //https://m.weibo.cn/status/Fc99eEAbb?fid=1034%3Ae4cb370b2f219a79e8e0d55a4a3bb673&jumpfrom=weibocom 88 | //http://weibo.com/tv/v/Fc99eEAbb?fid=1034:e4cb370b2f219a79e8e0d55a4a3bb673 89 | //http://weibo.com/tv/v/Fc13IAmqT?fid=1034:94f6f34920fa8d2a353f85b6f3fde66a 90 | //http://weibo.com/tv/v/Fc2Mudq0n?fid=1034:2534bf1ffad6701f1a4ac7e60575c756 91 | //http://weibo.com/tv/v/Fc4DPrLRJ?from=vhot 92 | //http://weibo.com/tv/v/Fc99eEAbb?fid=1034:e4cb370b2f219a79e8e0d55a4a3bb673 93 | 94 | if strings.Contains(art.UrlVideo, "weibo.") { 95 | //http://v.youku.com/v_show/id_XMjg4Mzc0NjAxMg==.html?spm=a2hww.20023042.m_223465.5~5~5~5!2~5~5~A&f=50346975 96 | //http://m.youku.com/video/id_XMjg4Mzc0NjAxMg==.html?spm=a2hww.20023042.m_223465.5~5~5~5!2~5~5~A&f=50346975&source= 97 | reg := regexp.MustCompile(`\?fid=(\d{4}:\w{32})`) 98 | ids := reg.FindStringSubmatch(art.UrlVideo) 99 | for k, v := range ids { 100 | if k == 1 { 101 | art.VideoWeiboId = v 102 | } 103 | } 104 | } 105 | //解析秒拍 106 | //http://www.miaopai.com/show/guASDNtbED2~Q-G9lBSCx1ECxxj~vqCc.htm 107 | //http://www.miaopai.com/show/XvEqhME836J9MvRgh6xFz~BY5PNjYS~e.htm 108 | //http://gslb.miaopai.com/stream/c48Xw9OZhOmLRaQeG1vqIxFax5Pmp29O.mp4?yx=&refer=weibo_app&Expires=1499883561&ssig=ibesKAxQRj&KID=unistore,video&playerType=miaopai 109 | if strings.Contains(art.UrlVideo, "miaopai.") { 110 | reg := regexp.MustCompile(`(?:/show/)(.+)(?:\.htm)`) 111 | ids := reg.FindStringSubmatch(art.UrlVideo) 112 | for k, v := range ids { 113 | if k == 1 { 114 | art.VideoMiaopaiId = v 115 | } 116 | } 117 | } 118 | 119 | //处理标签 120 | for k, v := range art.Tags { 121 | //设置第一个标签 122 | if k == 0 { 123 | art.FirstTagID = v.ID 124 | art.FirstTagName = v.Name 125 | art.FirstTagNameEn = v.NameEn 126 | } 127 | //设置外链内链 128 | url := fmt.Sprint("/tag/", v.ID) 129 | link := Link{Name: v.Name, Url: url} 130 | art.Links = append(art.Links, link) 131 | } 132 | for _, show := range art.Shows { 133 | url := fmt.Sprint(ShowHost, "show/", show.ID) 134 | showName := fmt.Sprint(show.NameEn, show.NameZh) 135 | link := Link{Name: showName, Url: url} 136 | art.Links = append(art.Links, link) 137 | } 138 | 139 | return 140 | } 141 | 142 | //这个方法要被废弃了 143 | func GetAllArticles(pageIndex int) (articles []Article, totalPage int) { 144 | //设置默认值 145 | if pageIndex < 1 { 146 | pageIndex = 1 147 | } 148 | 149 | //分页 150 | var count int 151 | Gorm.Model(&Article{}).Count(&count) 152 | totalPage = int(math.Ceil(float64(count) / float64(PageSize))) 153 | 154 | offset := (pageIndex - 1) * PageSize 155 | articles = []Article{} 156 | Gorm.Offset(offset).Limit(PageSize).Order("created_time DESC").Preload("Vote").Find(&articles) 157 | return 158 | } 159 | 160 | func CovertTimeToHumanTime(t time.Time) (humanTimeString string) { 161 | secT := t.Unix() 162 | secNow := time.Now().Unix() 163 | duration := secNow - secT 164 | if duration < 60 { 165 | humanTimeString = "现在" 166 | return 167 | } else if duration < 3600 { 168 | humanTimeString = fmt.Sprint(duration/60, "分前") 169 | return 170 | } else if duration < 24*3600 { 171 | humanTimeString = fmt.Sprint(duration/3600, "小时前") 172 | return 173 | } else if duration < 24*3600*30 { 174 | humanTimeString = fmt.Sprint(duration/24/3600, "天前") 175 | return 176 | } else if duration < 24*3600*366 { 177 | humanTimeString = fmt.Sprint(duration/24/3600/30, "月前") 178 | return 179 | } else { 180 | humanTimeString = t.Format("2006-01-02") 181 | return 182 | } 183 | } 184 | 185 | //首页获取文章地址; 186 | func GetBatchArticles(offset, size int) (articles []Article) { 187 | cacheKey := fmt.Sprint("home_articles_fetch_", offset, "_", size) 188 | //fmt.Println(cacheKey) 189 | if x, found := CacheManager.Get(cacheKey); found { 190 | buffer := x.([]byte) 191 | json.Unmarshal(buffer, &articles) 192 | } else { 193 | Gorm.Offset(offset).Limit(size).Order("created_at DESC").Preload("Tags").Preload("Vote").Preload("Images").Find(&articles) 194 | buffer, _ := json.Marshal(articles) 195 | CacheManager.Set(cacheKey, buffer, C_EXPIRE_TIME_MIN_15) 196 | } 197 | return 198 | } 199 | func GetBatchArticlesForWx(offset, size int) (articles []Article) { 200 | cacheKey := fmt.Sprint("home_articles_fetch_for_wx", offset, "_", size) 201 | //fmt.Println(cacheKey) 202 | if x, found := CacheManager.Get(cacheKey); found { 203 | buffer := x.([]byte) 204 | //buffer 205 | json.Unmarshal(buffer, &articles) 206 | } else { 207 | Gorm.Offset(offset).Limit(size).Order("created_at DESC").Preload("Tags").Preload("Images").Where("url_video LIKE ?", "%.youku.%").Find(&articles) 208 | buffer, _ := json.Marshal(articles) 209 | CacheManager.Set(cacheKey, buffer, C_EXPIRE_TIME_MIN_15) 210 | } 211 | return 212 | } 213 | -------------------------------------------------------------------------------- /views/article/_video.html: -------------------------------------------------------------------------------- 1 | {{if .Article.VideoTitle}} 2 |
3 | 4 | {{.Article.VideoTitle}} 5 |
6 | {{end}} 7 | 8 | {{if .Article.VideoYoukuId}} 9 |
10 | 11 |
12 |
13 | 162 | {{end}} 163 | {{if .Article.VideoMiaopaiId }} 164 |
165 | 166 |
167 | {{end}} {{if .Article.VideoWeiboId }} 168 |
169 | 170 |
171 | 180 | {{end}} -------------------------------------------------------------------------------- /trytv_2017-11-30.sql: -------------------------------------------------------------------------------- 1 | # ************************************************************ 2 | # Sequel Pro SQL dump 3 | # Version 4541 4 | # 5 | # http://www.sequelpro.com/ 6 | # https://github.com/sequelpro/sequelpro 7 | # 8 | # Host: www.cnfluffy.com (MySQL 5.5.51-MariaDB) 9 | # Database: trytv 10 | # Generation Time: 2017-11-29 17:34:00 +0000 11 | # ************************************************************ 12 | 13 | 14 | /*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; 15 | /*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; 16 | /*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; 17 | /*!40101 SET NAMES utf8 */; 18 | /*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; 19 | /*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; 20 | /*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; 21 | 22 | 23 | # Dump of table article_episode 24 | # ------------------------------------------------------------ 25 | 26 | CREATE TABLE `article_episode` ( 27 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 28 | `article_id` int(10) unsigned NOT NULL, 29 | `episode_id` int(10) unsigned NOT NULL, 30 | PRIMARY KEY (`id`), 31 | KEY `article_episode_article_id_index` (`article_id`), 32 | KEY `article_episode_episode_id_index` (`episode_id`), 33 | CONSTRAINT `article_episode_article_id_foreign` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE, 34 | CONSTRAINT `article_episode_episode_id_foreign` FOREIGN KEY (`episode_id`) REFERENCES `episodes` (`id`) ON DELETE CASCADE 35 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 36 | 37 | 38 | 39 | # Dump of table article_movie 40 | # ------------------------------------------------------------ 41 | 42 | CREATE TABLE `article_movie` ( 43 | `article_id` int(10) unsigned NOT NULL, 44 | `movie_id` int(10) unsigned NOT NULL, 45 | KEY `article_movie_article_id_index` (`article_id`), 46 | KEY `article_movie_movie_id_index` (`movie_id`), 47 | CONSTRAINT `article_movie_article_id_foreign` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE, 48 | CONSTRAINT `article_movie_movie_id_foreign` FOREIGN KEY (`movie_id`) REFERENCES `movies` (`id`) ON DELETE CASCADE 49 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 50 | 51 | 52 | 53 | # Dump of table article_show 54 | # ------------------------------------------------------------ 55 | 56 | CREATE TABLE `article_show` ( 57 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 58 | `show_id` int(10) unsigned NOT NULL, 59 | `article_id` int(10) unsigned NOT NULL, 60 | PRIMARY KEY (`id`), 61 | KEY `article_show_show_id_index` (`show_id`), 62 | KEY `article_show_article_id_index` (`article_id`), 63 | CONSTRAINT `article_show_article_id_foreign` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE, 64 | CONSTRAINT `article_show_show_id_foreign` FOREIGN KEY (`show_id`) REFERENCES `shows` (`id`) ON DELETE CASCADE 65 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 66 | 67 | 68 | 69 | # Dump of table article_tag 70 | # ------------------------------------------------------------ 71 | 72 | CREATE TABLE `article_tag` ( 73 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 74 | `created_at` timestamp NULL DEFAULT NULL, 75 | `updated_at` timestamp NULL DEFAULT NULL, 76 | `deleted_at` timestamp NULL DEFAULT NULL, 77 | `article_id` int(10) unsigned NOT NULL, 78 | `tag_id` int(10) unsigned NOT NULL, 79 | PRIMARY KEY (`id`), 80 | KEY `article_tag_article_id_index` (`article_id`), 81 | KEY `article_tag_tag_id_index` (`tag_id`), 82 | CONSTRAINT `article_tag_article_id_foreign` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE, 83 | CONSTRAINT `article_tag_tag_id_foreign` FOREIGN KEY (`tag_id`) REFERENCES `tags` (`id`) ON DELETE CASCADE 84 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 85 | 86 | 87 | 88 | # Dump of table articles 89 | # ------------------------------------------------------------ 90 | 91 | CREATE TABLE `articles` ( 92 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 93 | `title` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 94 | `body` longtext COLLATE utf8_unicode_ci NOT NULL, 95 | `url_provider` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 96 | `key_word` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 97 | `description` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 98 | `raw_title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '爬去的标题', 99 | `raw_content` longtext COLLATE utf8_unicode_ci COMMENT '爬去的内容', 100 | `video_title` varchar(255) COLLATE utf8_unicode_ci NOT NULL COMMENT '视频标题', 101 | `url_video` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '' COMMENT '视频地址', 102 | `coverage_uri` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '封面图片的uri/key', 103 | `created_at` timestamp NULL DEFAULT NULL, 104 | `updated_at` timestamp NULL DEFAULT NULL, 105 | `deleted_at` timestamp NULL DEFAULT NULL, 106 | `video_code` text COLLATE utf8_unicode_ci COMMENT '视频播放代码(准备放弃)', 107 | `is_show` tinyint(1) unsigned NOT NULL COMMENT '废弃和deleted_at重复', 108 | PRIMARY KEY (`id`), 109 | KEY `url_title_unique` (`raw_title`,`url_provider`) 110 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 111 | 112 | 113 | 114 | # Dump of table episodes 115 | # ------------------------------------------------------------ 116 | 117 | CREATE TABLE `episodes` ( 118 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 119 | `name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '重新计算的结果', 120 | `raw_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 121 | `provider` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 122 | `url_provider` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 123 | `season` smallint(6) NOT NULL, 124 | `episode` smallint(6) NOT NULL, 125 | `show_id` int(10) unsigned NOT NULL, 126 | `size` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 127 | `quality` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 128 | `is_auth` tinyint(1) NOT NULL, 129 | `url_torrent` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 130 | `url_magnet` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 131 | `url_ed2k` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 132 | `url_baidupan` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 133 | `url_other` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 134 | `url_video` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 135 | `like_count` mediumint(8) unsigned NOT NULL, 136 | `created_at` timestamp NULL DEFAULT NULL, 137 | `updated_at` timestamp NULL DEFAULT NULL, 138 | `movie_id` int(10) unsigned NOT NULL, 139 | `deleted_at` timestamp NULL DEFAULT NULL, 140 | PRIMARY KEY (`id`), 141 | UNIQUE KEY `episodes_raw_name_unique` (`raw_name`), 142 | KEY `episodes_show_id_foreign` (`show_id`) 143 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 144 | 145 | 146 | 147 | # Dump of table ht_user 148 | # ------------------------------------------------------------ 149 | 150 | CREATE TABLE `ht_user` ( 151 | `id` int(11) NOT NULL AUTO_INCREMENT, 152 | `name` varchar(50) DEFAULT NULL, 153 | `email` varchar(100) DEFAULT NULL, 154 | `phone` varchar(12) DEFAULT NULL, 155 | PRIMARY KEY (`id`), 156 | KEY `email_index` (`email`) USING BTREE, 157 | KEY `phone_index` (`phone`) USING BTREE 158 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 ROW_FORMAT=DYNAMIC; 159 | 160 | 161 | 162 | # Dump of table image_movie 163 | # ------------------------------------------------------------ 164 | 165 | CREATE TABLE `image_movie` ( 166 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 167 | `image_id` int(10) unsigned NOT NULL, 168 | `movie_id` int(10) unsigned NOT NULL, 169 | PRIMARY KEY (`id`), 170 | KEY `image_movie_image_id_index` (`image_id`), 171 | KEY `image_movie_movie_id_index` (`movie_id`), 172 | CONSTRAINT `image_movie_image_id_foreign` FOREIGN KEY (`image_id`) REFERENCES `images` (`id`), 173 | CONSTRAINT `image_movie_movie_id_foreign` FOREIGN KEY (`movie_id`) REFERENCES `movies` (`id`) 174 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 175 | 176 | 177 | 178 | # Dump of table image_show 179 | # ------------------------------------------------------------ 180 | 181 | CREATE TABLE `image_show` ( 182 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 183 | `show_id` int(10) unsigned NOT NULL, 184 | `image_id` int(10) unsigned NOT NULL, 185 | PRIMARY KEY (`id`), 186 | KEY `image_show_show_id_index` (`show_id`), 187 | KEY `image_show_image_id_index` (`image_id`), 188 | CONSTRAINT `image_show_image_id_foreign` FOREIGN KEY (`image_id`) REFERENCES `images` (`id`), 189 | CONSTRAINT `image_show_show_id_foreign` FOREIGN KEY (`show_id`) REFERENCES `shows` (`id`) 190 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 191 | 192 | 193 | 194 | # Dump of table images 195 | # ------------------------------------------------------------ 196 | 197 | CREATE TABLE `images` ( 198 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 199 | `key` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 200 | `article_id` int(10) unsigned NOT NULL, 201 | `description` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 202 | `bucket` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 203 | `fname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 204 | `fsize` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 205 | `created_at` timestamp NULL DEFAULT NULL, 206 | `updated_at` timestamp NULL DEFAULT NULL, 207 | `width` int(10) unsigned NOT NULL, 208 | `height` int(10) unsigned NOT NULL, 209 | `format` varchar(20) COLLATE utf8_unicode_ci DEFAULT NULL, 210 | `deleted_at` timestamp NULL DEFAULT NULL, 211 | `imgur_id` int(10) unsigned DEFAULT NULL COMMENT '管理imgur模型', 212 | PRIMARY KEY (`id`), 213 | UNIQUE KEY `images_key_unique` (`key`), 214 | KEY `imgur_id` (`imgur_id`) 215 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 216 | 217 | 218 | 219 | # Dump of table imgurs 220 | # ------------------------------------------------------------ 221 | 222 | CREATE TABLE `imgurs` ( 223 | `id` int(11) unsigned NOT NULL AUTO_INCREMENT, 224 | `imgur_id` varchar(11) COLLATE utf8_unicode_ci DEFAULT NULL, 225 | `title` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 226 | `title_translation` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 227 | `keywords` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 228 | `created_at` timestamp NULL DEFAULT NULL, 229 | `updated_at` timestamp NULL DEFAULT NULL, 230 | `deleted_at` timestamp NULL DEFAULT NULL, 231 | `description_translation` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 232 | `is_published` tinyint(1) DEFAULT '0', 233 | PRIMARY KEY (`id`) 234 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 235 | 236 | 237 | 238 | # Dump of table jobs 239 | # ------------------------------------------------------------ 240 | 241 | CREATE TABLE `jobs` ( 242 | `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, 243 | `queue` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 244 | `payload` longtext COLLATE utf8_unicode_ci NOT NULL, 245 | `attempts` tinyint(3) unsigned NOT NULL, 246 | `reserved` tinyint(3) unsigned NOT NULL, 247 | `reserved_at` int(10) unsigned DEFAULT NULL, 248 | `available_at` int(10) unsigned NOT NULL, 249 | `created_at` int(10) unsigned NOT NULL, 250 | PRIMARY KEY (`id`), 251 | KEY `jobs_queue_reserved_reserved_at_index` (`queue`,`reserved`,`reserved_at`) 252 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 253 | 254 | 255 | 256 | # Dump of table migrations 257 | # ------------------------------------------------------------ 258 | 259 | CREATE TABLE `migrations` ( 260 | `migration` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 261 | `batch` int(11) NOT NULL 262 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 263 | 264 | 265 | 266 | # Dump of table movies 267 | # ------------------------------------------------------------ 268 | 269 | CREATE TABLE `movies` ( 270 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 271 | `created_at` timestamp NULL DEFAULT NULL, 272 | `updated_at` timestamp NULL DEFAULT NULL, 273 | `name_en` text COLLATE utf8_unicode_ci NOT NULL, 274 | `name_zh` text COLLATE utf8_unicode_ci NOT NULL, 275 | `playwright` text COLLATE utf8_unicode_ci NOT NULL, 276 | `publish_at` timestamp NOT NULL DEFAULT '0000-00-00 00:00:00', 277 | `grade` text COLLATE utf8_unicode_ci NOT NULL, 278 | `length` text COLLATE utf8_unicode_ci NOT NULL, 279 | `official_url` text COLLATE utf8_unicode_ci NOT NULL, 280 | `detail` longtext COLLATE utf8_unicode_ci NOT NULL, 281 | `key_word` text COLLATE utf8_unicode_ci NOT NULL, 282 | `description` text COLLATE utf8_unicode_ci NOT NULL, 283 | PRIMARY KEY (`id`) 284 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 285 | 286 | 287 | 288 | # Dump of table password_resets 289 | # ------------------------------------------------------------ 290 | 291 | CREATE TABLE `password_resets` ( 292 | `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 293 | `token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 294 | `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 295 | KEY `password_resets_email_index` (`email`), 296 | KEY `password_resets_token_index` (`token`) 297 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 298 | 299 | 300 | 301 | # Dump of table quotes 302 | # ------------------------------------------------------------ 303 | 304 | CREATE TABLE `quotes` ( 305 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 306 | `english` mediumtext COLLATE utf8_unicode_ci NOT NULL, 307 | `chinese` mediumtext COLLATE utf8_unicode_ci NOT NULL, 308 | `writer` text COLLATE utf8_unicode_ci NOT NULL, 309 | `image_uri` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 310 | `deleted_at` timestamp NULL DEFAULT NULL, 311 | `updated_at` timestamp NULL DEFAULT NULL, 312 | `created_at` timestamp NULL DEFAULT NULL, 313 | PRIMARY KEY (`id`) 314 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 315 | 316 | 317 | 318 | # Dump of table sessions 319 | # ------------------------------------------------------------ 320 | 321 | CREATE TABLE `sessions` ( 322 | `id` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 323 | `user_id` int(11) DEFAULT NULL, 324 | `ip_address` varchar(45) COLLATE utf8_unicode_ci DEFAULT NULL, 325 | `user_agent` text COLLATE utf8_unicode_ci, 326 | `payload` text COLLATE utf8_unicode_ci NOT NULL, 327 | `last_activity` int(11) NOT NULL, 328 | UNIQUE KEY `sessions_id_unique` (`id`) 329 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 330 | 331 | 332 | 333 | # Dump of table shows 334 | # ------------------------------------------------------------ 335 | 336 | CREATE TABLE `shows` ( 337 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 338 | `name_en` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 339 | `name_zh` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 340 | `detail` longtext COLLATE utf8_unicode_ci NOT NULL, 341 | `key_word` text COLLATE utf8_unicode_ci NOT NULL, 342 | `description` text COLLATE utf8_unicode_ci NOT NULL, 343 | `type` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, 344 | `director` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 345 | `play_writer` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 346 | `created_at` timestamp NULL DEFAULT NULL, 347 | `updated_at` timestamp NULL DEFAULT NULL, 348 | `actor` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL, 349 | `alias` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '美剧其他中文名称,逗号分隔', 350 | `deleted_at` timestamp NULL DEFAULT NULL, 351 | PRIMARY KEY (`id`) 352 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 353 | 354 | 355 | 356 | # Dump of table subtitles 357 | # ------------------------------------------------------------ 358 | 359 | CREATE TABLE `subtitles` ( 360 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 361 | `source_url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '抓取地址', 362 | `name_zh` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '中文名称', 363 | `name_en` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '英文名称', 364 | `version` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '视频格式版本', 365 | `file_name` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '字幕文件名', 366 | `lang` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '语言', 367 | `format` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '字幕格式', 368 | `url` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT '字幕原来地址', 369 | `uri` varchar(255) COLLATE utf8_unicode_ci DEFAULT NULL COMMENT 'oss地址', 370 | `created_at` timestamp NULL DEFAULT NULL, 371 | `updated_at` timestamp NULL DEFAULT NULL, 372 | `deleted_at` timestamp NULL DEFAULT NULL, 373 | PRIMARY KEY (`id`), 374 | UNIQUE KEY `source_url` (`source_url`) 375 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 376 | 377 | 378 | 379 | # Dump of table tags 380 | # ------------------------------------------------------------ 381 | 382 | CREATE TABLE `tags` ( 383 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 384 | `name` varchar(100) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 385 | `name_en` varchar(100) COLLATE utf8_unicode_ci NOT NULL, 386 | `image_id` int(11) NOT NULL, 387 | `key_word` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 388 | `description` varchar(255) COLLATE utf8_unicode_ci NOT NULL DEFAULT '', 389 | `deleted_at` timestamp NULL DEFAULT NULL, 390 | `updated_at` timestamp NULL DEFAULT NULL, 391 | `created_at` timestamp NULL DEFAULT NULL, 392 | PRIMARY KEY (`id`) 393 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 394 | 395 | 396 | 397 | # Dump of table users 398 | # ------------------------------------------------------------ 399 | 400 | CREATE TABLE `users` ( 401 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 402 | `name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 403 | `email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 404 | `password` varchar(60) COLLATE utf8_unicode_ci NOT NULL, 405 | `honor_point` mediumint(9) NOT NULL, 406 | `nick_name` char(20) COLLATE utf8_unicode_ci NOT NULL, 407 | `slogan` char(40) COLLATE utf8_unicode_ci NOT NULL, 408 | `avatar_image` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 409 | `remember_token` varchar(100) COLLATE utf8_unicode_ci DEFAULT NULL, 410 | `created_at` timestamp NULL DEFAULT NULL, 411 | `updated_at` timestamp NULL DEFAULT NULL, 412 | `github_id` int(11) NOT NULL, 413 | `github_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 414 | `github_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 415 | `github_nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 416 | `github_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 417 | `github_avatar` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 418 | `github_json` text COLLATE utf8_unicode_ci NOT NULL, 419 | `weibo_id` int(11) unsigned NOT NULL, 420 | `weibo_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 421 | `weibo_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 422 | `weibo_nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 423 | `weibo_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 424 | `weibo_avatar` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 425 | `weibo_json` text COLLATE utf8_unicode_ci NOT NULL, 426 | `qq_id` int(11) NOT NULL, 427 | `qq_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 428 | `qq_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 429 | `qq_nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 430 | `qq_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 431 | `qq_avatar` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 432 | `qq_json` text COLLATE utf8_unicode_ci NOT NULL, 433 | `weixin_id` int(11) NOT NULL, 434 | `weixin_token` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 435 | `weixin_name` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 436 | `weixin_nickname` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 437 | `weixin_email` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 438 | `weixin_avatar` varchar(255) COLLATE utf8_unicode_ci NOT NULL, 439 | `weixin_json` text COLLATE utf8_unicode_ci NOT NULL, 440 | `deleted_at` timestamp NULL DEFAULT NULL, 441 | PRIMARY KEY (`id`), 442 | UNIQUE KEY `users_email_unique` (`email`) 443 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 444 | 445 | 446 | 447 | # Dump of table votes 448 | # ------------------------------------------------------------ 449 | 450 | CREATE TABLE `votes` ( 451 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 452 | `article_id` int(10) unsigned DEFAULT NULL, 453 | `movie_id` int(10) unsigned DEFAULT NULL, 454 | `show_id` int(10) unsigned DEFAULT NULL, 455 | `visit` int(10) unsigned NOT NULL, 456 | `favorate_count` int(10) unsigned DEFAULT NULL, 457 | `score` decimal(4,2) NOT NULL, 458 | `vote_count` int(10) unsigned NOT NULL, 459 | `deleted_at` timestamp NULL DEFAULT NULL, 460 | `updated_at` timestamp NULL DEFAULT NULL, 461 | `created_at` timestamp NULL DEFAULT NULL, 462 | `fake_read` int(10) unsigned DEFAULT NULL COMMENT '假浏览量', 463 | PRIMARY KEY (`id`), 464 | KEY `votes_article_id_index` (`article_id`), 465 | KEY `votes_movie_id_index` (`movie_id`), 466 | KEY `votes_show_id_index` (`show_id`), 467 | CONSTRAINT `votes_article_id_foreign` FOREIGN KEY (`article_id`) REFERENCES `articles` (`id`) ON DELETE CASCADE, 468 | CONSTRAINT `votes_movie_id_foreign` FOREIGN KEY (`movie_id`) REFERENCES `movies` (`id`) ON DELETE CASCADE, 469 | CONSTRAINT `votes_show_id_foreign` FOREIGN KEY (`show_id`) REFERENCES `shows` (`id`) ON DELETE CASCADE 470 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 471 | 472 | 473 | 474 | # Dump of table weibos 475 | # ------------------------------------------------------------ 476 | 477 | CREATE TABLE `weibos` ( 478 | `id` int(10) unsigned NOT NULL AUTO_INCREMENT, 479 | `wb_id` bigint(20) unsigned NOT NULL, 480 | `body` text COLLATE utf8_unicode_ci NOT NULL, 481 | `images` text COLLATE utf8_unicode_ci NOT NULL, 482 | `type` enum('favorate','myself','friend','trash') COLLATE utf8_unicode_ci NOT NULL, 483 | `is_shown` tinyint(3) unsigned NOT NULL, 484 | `weibor` char(255) COLLATE utf8_unicode_ci NOT NULL, 485 | `avatar` char(255) COLLATE utf8_unicode_ci NOT NULL, 486 | `media_url` char(255) COLLATE utf8_unicode_ci NOT NULL, 487 | `long_url` char(255) COLLATE utf8_unicode_ci DEFAULT NULL, 488 | `media_type` enum('miaopai','youku','bili','acfun','text','miaopai','xiakaxiu','vlook') COLLATE utf8_unicode_ci DEFAULT 'text', 489 | `created_at` timestamp NULL DEFAULT NULL, 490 | `updated_at` timestamp NULL DEFAULT NULL, 491 | PRIMARY KEY (`id`), 492 | UNIQUE KEY `weibos_wb_id_unique` (`wb_id`) 493 | ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_unicode_ci; 494 | 495 | 496 | 497 | 498 | /*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; 499 | /*!40101 SET SQL_MODE=@OLD_SQL_MODE */; 500 | /*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; 501 | /*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; 502 | /*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; 503 | /*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; 504 | --------------------------------------------------------------------------------