初步可用后台

This commit is contained in:
j4587698 2020-02-16 22:11:24 +08:00
parent 104cfb2463
commit c448afdd1d
37 changed files with 2278 additions and 310 deletions

View File

@ -1,18 +0,0 @@
using JXCMS.CMS.Attribute;
using Microsoft.AspNetCore.Mvc;
namespace JXCMS.CMS.Admin.Controllers
{
[Area("Admin")]
[AdminAuthentication]
public class ArticleController : Controller
{
// GET
public IActionResult Index()
{
ViewBag.title = "所有文章";
return View();
}
}
}

View File

@ -0,0 +1,73 @@
using System.Linq;
using FreeSql;
using JXCMS.CMS.Attribute;
using JXCMS.CMS.Entity;
using JXCMS.CMS.Movie.Entity;
using JXCMS.CMS.Movie.Spider;
using JXCMS.CMS.Movie.Utils;
using Microsoft.AspNetCore.Mvc;
namespace JXCMS.CMS.Movie.Admin.Controllers
{
[Area("Admin")]
[AdminAuthentication]
public class ClassifyController : Controller
{
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
{
var list = ClassifyEntity.Select.Include(x => x.Parent).Count(out long count).Page(pageNumber, pageSize).ToList(
x => new ClassifyEntity{Id = x.Id, Name = x.Name, Alias = x.Alias, ParentId = x.ParentId, Parent = x.Parent, UpdateTime = x.UpdateTime,
Count = MovieEntity.Select.Where(y => y.ClassifyId == x.Id).Count()});
ViewBag.count = count;
ViewBag.pageNumber = pageNumber;
ViewBag.totlePage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
return View(list);
}
public IActionResult ClassifyDialog(int id)
{
ClassifyEntity classifyEntity = null;
if (id == 0)
{
classifyEntity = new ClassifyEntity();
ViewBag.title = "添加新分类";
ViewBag.classifyEntities = ClassifyEntity.Select.ToList();
}
else
{
classifyEntity = ClassifyEntity.Find(id);
ViewBag.title = "修改分类" + classifyEntity.Name;
ViewBag.classifyEntities = Classify.FindAllNotChildren(ClassifyEntity.Select.ToList(), id);
}
return View(classifyEntity);
}
public IActionResult DeleteClassify(int id)
{
if (MovieEntity.Select.Any(x => x.ClassifyId == id))
{
return Redirect(Url.Action("Index"));
}
if (ClassifyEntity.Select.Any(x => x.ParentId == id))
{
ClassifyEntity.Where(x => x.ParentId == id).ToUpdate().Set(x => x.ParentId, 0).ExecuteAffrows();
}
ClassifyEntity.Find(id).Delete();
return Redirect(Url.Action("Index"));
}
public IActionResult ModifyClassify(ClassifyEntity classifyEntity)
{
if (classifyEntity.Id != 0 &&
Classify.FindAllChildren(ClassifyEntity.Select.ToList(), classifyEntity.Id).Any(x => x.Id == classifyEntity.ParentId))
{
return Redirect(Url.Action("Index"));
}
classifyEntity.Save();
return Redirect(Url.Action("Index"));
}
}
}

View File

@ -1,8 +1,12 @@
using System;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using FreeSql;
using JXCMS.CMS.Attribute; using JXCMS.CMS.Attribute;
using JXCMS.CMS.Movie.Entity; using JXCMS.CMS.Movie.Entity;
using JXCMS.CMS.Movie.Jobs; using JXCMS.CMS.Movie.Jobs;
using JXCMS.CMS.Movie.Spider;
using JXCMS.CMS.Movie.Utils;
using JXCMS.Core.TimingTask; using JXCMS.Core.TimingTask;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Quartz; using Quartz;
@ -16,7 +20,11 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
public IActionResult Index(int pageNumber = 1, int pageSize = 20) public IActionResult Index(int pageNumber = 1, int pageSize = 20)
{ {
ViewBag.title = "采集地址"; ViewBag.title = "采集地址";
var website = WebSiteEntity.Select.Count(out long count).Page(pageNumber, pageSize).ToList(); var website = WebSiteEntity.Select.Count(out long count).Page(pageNumber, pageSize).ToList().Select(x =>
{
x.NextRunTime = x.IsEnable ? QuartzTask.GetCronSchedule(x.Cron, 1, DateTimeOffset.Now) : "已禁用";
return x;
}).ToList();
ViewBag.website = website; ViewBag.website = website;
ViewBag.count = count; ViewBag.count = count;
ViewBag.pageNumber = pageNumber; ViewBag.pageNumber = pageNumber;
@ -27,6 +35,10 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
[HttpPost] [HttpPost]
public IActionResult AddWebSite(WebSiteEntity webSiteEntity) public IActionResult AddWebSite(WebSiteEntity webSiteEntity)
{ {
if (!CronExpression.IsValidExpression(webSiteEntity.Cron))
{
return Redirect(Url.Action("Index"));
}
webSiteEntity.Save(); webSiteEntity.Save();
if (webSiteEntity.IsEnable) if (webSiteEntity.IsEnable)
{ {
@ -88,6 +100,25 @@ namespace JXCMS.CMS.Movie.Admin.Controllers
return View(webSiteEntity); return View(webSiteEntity);
} }
public IActionResult BindingClassifyDialog(int id)
{
var classifyEntities = Classify.Structured(ClassifyEntity.Select.ToList());
var webSiteClassifyEntities = WebSiteClassifyEntity.Where(x => x.WebSiteId == id).ToList();
var webSiteEntity = WebSiteEntity.Find(id);
classifyEntities.Insert(0, new ClassifyEntity(){Id = 0, Name = "未绑定"});
ViewBag.classifyEntities = classifyEntities;
ClassifySpider.GetAllClassifyFromUrl(id, webSiteEntity.ApiUrl, webSiteClassifyEntities);
ViewBag.title = "修改" + webSiteEntity.WebSiteName + "的类型绑定";
return View(webSiteClassifyEntities);
}
public IActionResult UpdateBindingClassify(WebSiteClassifyEntity[] webSiteClassifyEntities)
{
foreach (var webSiteClassifyEntity in webSiteClassifyEntities)
{
webSiteClassifyEntity.Save();
}
return Redirect(Url.Action("Index"));
}
} }
} }

View File

@ -1,17 +1,15 @@
using System.Security.Claims; using System.Security.Claims;
using System.Threading.Tasks; using System.Threading.Tasks;
using JXCMS.CMS.Attribute; using JXCMS.CMS.Attribute;
using JXCMS.CMS.Entity;
using JXCMS.CMS.Movie.Entity; using JXCMS.CMS.Movie.Entity;
using JXCMS.CMS.Utils; using JXCMS.CMS.Utils;
using JXCMS.Core.Auth; using JXCMS.Core.Auth;
using JXCMS.Core.Encrypt; using JXCMS.Core.Encrypt;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization; using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
namespace JXCMS.CMS.Admin.Controllers namespace JXCMS.CMS.Movie.Admin.Controllers
{ {
[Area("Admin")] [Area("Admin")]
[AdminAuthentication] [AdminAuthentication]

View File

@ -73,6 +73,180 @@ namespace JXCMS.CMS.Admin.Controllers
Type = "Settings" Type = "Settings"
}); });
BaseEntity.Orm.Insert(settings).ExecuteInserted(); BaseEntity.Orm.Insert(settings).ExecuteInserted();
var classify = new ClassifyEntity()
{
Name = "电影",
Alias = "dianying",
ParentId = 0
};
classify.Save();
List<ClassifyEntity> classifyEntities = new List<ClassifyEntity>();
classifyEntities.Add(new ClassifyEntity()
{
Name = "动作片",
Alias = "dongzuo",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "喜剧片",
Alias = "xiju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "爱情片",
Alias = "aiqing",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "科幻片",
Alias = "kehuan",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "恐怖片",
Alias = "kongbu",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "剧情片",
Alias = "juqing",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "战争片",
Alias = "zhanzheng",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "纪录片",
Alias = "jilupian",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "微电影",
Alias = "weidianying",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "伦理片",
Alias = "lunli",
ParentId = classify.Id
});
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
classify = new ClassifyEntity()
{
Name = "电视剧",
Alias = "tv",
ParentId = 0
};
classify.Save();
classifyEntities.Clear();
classifyEntities.Add(new ClassifyEntity()
{
Name = "国产剧",
Alias = "guochanju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "香港剧",
Alias = "xianggangju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "韩国剧",
Alias = "hanguoju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "欧美剧",
Alias = "oumeiju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "台湾剧",
Alias = "taiwanju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "日本剧",
Alias = "ribenju",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "海外剧",
Alias = "haiwaiju",
ParentId = classify.Id
});
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
classify = new ClassifyEntity()
{
Name = "综艺片",
Alias = "zongyi",
ParentId = 0
};
classify.Save();
classifyEntities.Clear();
classifyEntities.Add(new ClassifyEntity()
{
Name = "内地综艺",
Alias = "neidizongyi",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "日韩综艺",
Alias = "rihanzongyi",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "欧美综艺",
Alias = "oumeizongyi",
ParentId = classify.Id
});
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
classify = new ClassifyEntity()
{
Name = "动漫片",
Alias = "dongman",
ParentId = 0
};
classify.Save();
classifyEntities.Clear();
classifyEntities.Add(new ClassifyEntity()
{
Name = "国产动漫",
Alias = "guochandongman",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "日韩动漫",
Alias = "rihandongman",
ParentId = classify.Id
});
classifyEntities.Add(new ClassifyEntity()
{
Name = "欧美动漫",
Alias = "oumeidongman",
ParentId = classify.Id
});
BaseEntity.Orm.Insert(classifyEntities).ExecuteAffrows();
System.IO.File.Create("install.lock"); System.IO.File.Create("install.lock");
return View(); return View();
} }

View File

@ -0,0 +1,21 @@
using JXCMS.CMS.Attribute;
using JXCMS.CMS.Movie.Entity;
using Microsoft.AspNetCore.Mvc;
namespace JXCMS.CMS.Movie.Admin.Controllers
{
[Area("Admin")]
[AdminAuthentication]
public class MovieController : Controller
{
public IActionResult Index(int pageNumber = 1, int pageSize = 20)
{
var model = MovieEntity.Select.Count(out long count).Page(pageNumber, pageSize)
.Include(x => x.DirectorEntity).Include(x => x.ClassifyEntity).ToList();
ViewBag.count = count;
ViewBag.pageNumber = pageNumber;
ViewBag.totlePage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
return View(model);
}
}
}

View File

@ -1,265 +0,0 @@
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-toolbar clearfix">
<form class="pull-right search-bar" method="get" action="#!" role="form">
<div class="input-group">
<div class="input-group-btn">
<input type="hidden" name="search_field" id="search-field" value="title">
<button class="btn btn-default dropdown-toggle" id="search-btn" data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
标题 <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li> <a tabindex="-1" href="javascript:void(0)" data-field="title">标题</a> </li>
<li> <a tabindex="-1" href="javascript:void(0)" data-field="cat_name">栏目</a> </li>
</ul>
</div>
<input type="text" class="form-control" value="" name="keyword" placeholder="请输入名称">
</div>
</form>
<div class="toolbar-btn-action">
<a class="btn btn-primary m-r-5" href="#!"><i class="mdi mdi-plus"></i> 新增</a>
<a class="btn btn-success m-r-5" href="#!"><i class="mdi mdi-check"></i> 启用</a>
<a class="btn btn-warning m-r-5" href="#!"><i class="mdi mdi-block-helper"></i> 禁用</a>
<a class="btn btn-danger" href="#!"><i class="mdi mdi-window-close"></i> 删除</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" id="check-all"><span></span>
</label>
</th>
<th>编号</th>
<th>标题</th>
<th>书籍</th>
<th>作者</th>
<th>阅读量</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="1"><span></span>
</label>
</td>
<td>1</td>
<td>第01章 天涯思君不可忘</td>
<td>《倚天屠龙记》</td>
<td>金庸</td>
<td>36</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="2"><span></span>
</label>
</td>
<td>2</td>
<td>第01章 古道腾驹惊白发,危峦快剑识青翎</td>
<td>《书剑恩仇录》</td>
<td>金庸</td>
<td>44</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="3"><span></span>
</label>
</td>
<td>3</td>
<td>一个戴水獭皮帽子的朋友</td>
<td>《湘行散记》</td>
<td>沈从文</td>
<td>39</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="4"><span></span>
</label>
</td>
<td>4</td>
<td>你是要灼灼容颜,还是要宜其室家</td>
<td>《诗三百:思无邪》</td>
<td>安意如</td>
<td>36</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="5"><span></span>
</label>
</td>
<td>5</td>
<td>海上的消息</td>
<td>《打开心内的窗》</td>
<td>林清玄</td>
<td>32</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="6"><span></span>
</label>
</td>
<td>6</td>
<td>楔子 一阕词来 南国清秋魂梦绕 十年人散 绣房红烛剑光寒</td>
<td>《七剑下天山》</td>
<td>梁羽生</td>
<td>42</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="7"><span></span>
</label>
</td>
<td>7</td>
<td>祝福</td>
<td>《彷徨》</td>
<td>鲁迅</td>
<td>40</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="8"><span></span>
</label>
</td>
<td>8</td>
<td>一个女长年的故事</td>
<td>《莫泊桑短篇小说集》</td>
<td>莫泊桑</td>
<td>36</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="9"><span></span>
</label>
</td>
<td>9</td>
<td>第一回 赈民饥包公奉旨 图谋害庞相施计</td>
<td>《五虎征西》</td>
<td>李雨堂</td>
<td>35</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="10"><span></span>
</label>
</td>
<td>10</td>
<td>第一回 于按察山东赴任 邹其仁赴路登程</td>
<td>《于公案》</td>
<td>佚名</td>
<td>37</td>
<td><font class="text-success">正常</font></td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip"><i class="mdi mdi-pencil"></i></a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip"><i class="mdi mdi-window-close"></i></a>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<ul class="pagination">
<li class="disabled"><span>«</span></li>
<li class="active"><span>1</span></li>
<li><a href="#1">2</a></li>
<li><a href="#1">3</a></li>
<li><a href="#1">4</a></li>
<li><a href="#1">5</a></li>
<li><a href="#1">6</a></li>
<li><a href="#1">7</a></li>
<li><a href="#1">8</a></li>
<li class="disabled"><span>...</span></li>
<li><a href="#!">14452</a></li>
<li><a href="#!">14453</a></li>
<li><a href="#!">»</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,42 @@
@using JXCMS.CMS.Movie.Entity
@model JXCMS.CMS.Movie.Entity.ClassifyEntity
@{
Layout = "_DialogLayout";
}
<form id="modify_classify" action="@Url.Action("ModifyClassify")" method="post">
<input type="hidden" id="id" name="id" value="@Model.Id"/>
<div class="form-group">
<label for="name" class="control-label">分类名称:</label>
<input type="text" class="form-control" id="name" name="name" value="@Model.Name">
</div>
<div class="form-group">
<label for="alias" class="control-label">别名:</label>
<input type="text" class="form-control" id="alias" name="alias" value="@Model.Alias">
</div>
<div class="form-group">
<label for="parentId" class="control-label">父级分类:</label>
<select class="form-control" id="parentId" name="parentId">
<option value="0">无</option>
@foreach (ClassifyEntity classify in ViewBag.classifyEntities)
{
@:<option value="@classify.Id" @(Model.ParentId == classify.Id ? "selected" : "")>@classify.Name</option>
}
</select>
</div>
</form>
@section dialogScript
{
<script type="text/javascript">
$('#commit').click(function() {
var name = $("#name").val();
if (name === ""){
lightyear.notify('分类名称不能为空', 'danger', 100);
return;
}
$('#modify_classify').submit();
})
</script>
}

View File

@ -0,0 +1,160 @@
@using JXCMS.CMS.Movie.Entity
@using JXCMS.Core.Extensions
@model List<JXCMS.CMS.Movie.Entity.ClassifyEntity>
@{
ViewBag.Title = "分类目录";
Layout = "_Layout";
}
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-toolbar clearfix">
<div class="toolbar-btn-action">
<a data-src="@Url.Action("ClassifyDialog", "Classify", new {id = 0})" class="btn btn-primary m-r-5" id="new" data-toggle="modal" data-target="#exampleModal"><i class="mdi mdi-plus"></i> 新增</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>名称</th>
<th>别名</th>
<th>上级分类</th>
<th>视频数量</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@if (Model.Count == 0)
{
<tr>
<td colspan="5" style="text-align: center">无数据</td>
</tr>
}
@foreach (var classifyEntity in Model)
{
<tr>
<td>@classifyEntity.Name</td>
<td>@(classifyEntity.Alias.IsNullOrEmpty() ? "-" : classifyEntity.Alias)</td>
<td>@(classifyEntity.Parent == null ? "无" : classifyEntity.Parent.Name)</td>
<td>@classifyEntity.Count</td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" data-src="@Url.Action("ClassifyDialog", "Classify", new {id = classifyEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal">
<i class="mdi mdi-pencil"></i>
</a>
<a class="btn btn-xs btn-default" title="删除" data-toggle="tooltip" onclick="delClassify(@classifyEntity.Id, '@classifyEntity.Name')"
@if (classifyEntity.Count > 0)
{
@:disabled
}>
<i class="mdi mdi-window-close"></i>
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
<ul class="pagination">
@if (ViewBag.pageNumber != 1)
{
<li>
<a href="@Url.Action("Index", "Classify")">&lt;&lt;</a>
</li>
}
@for (int i = ViewBag.pageNumber - 3; i < ViewBag.pageNumber + 3; i++)
{
if (i < 1 || i > ViewBag.totlePage)
{
continue;
}
if (i == ViewBag.pageNumber)
{
<li class="active">
<span>@i</span>
</li>
}
else
{
<li>
<a href="@Url.Action("Index", "Classify", new {pageNumber = i})">@i</a>
</li>
}
}
@if (ViewBag.pageNumber < ViewBag.totlePage)
{
<li>
<a href="@Url.Action("Index", "Classify", new {pageNumber = ViewBag.totlePage})">&gt;&gt;</a>
</li>
}
</ul>
</div>
</div>
</div>
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
正在加载,请稍后...
</div>
</div>
</div>
</div>
<form id="delForm" action="@Url.Action("DeleteClassify")" method="post">
<input type="hidden" name="id" id="delId"/>
</form>
</div>
@section style
{
<link rel="stylesheet" href="@Url.ContentAdmin("js/jconfirm/jquery-confirm.min.css")">
}
@section script
{
<script src="@Url.ContentAdmin("js/bootstrap-notify.min.js")"></script>
<script type="text/javascript" src="@Url.ContentAdmin("js/lightyear.js")"></script>
<script src="@Url.ContentAdmin("js/jconfirm/jquery-confirm.min.js")"></script>
<script type="text/javascript">
$('#exampleModal').on('show.bs.modal', function(event) {
var button = $(event.relatedTarget); // Button that triggered the modal
var recipient = button.data('src'); // Extract info from data-* attributes
var content = $(this).find(".modal-content");
content.html("正在加载,请稍后...");
$.get(recipient, function(data, status) {
if (status === "success") {
content.html(data)
} else{
content.html("发生错误,请重试")
}
})
});
function delClassify(id, name) {
$.alert({
title: '删除分类地址' + name,
content: '是否删除' + name + '?(如果该分类下有子分类,子分类将变为顶级分类)<br />该操作不可恢复',
buttons: {
confirm: {
text: '是',
btnClass: 'btn-primary',
action: function(){
$('#delId').val(id);
$('#delForm').submit();
}
},
cancel: {
text: '否'
}
}
});
}
</script>
}

View File

@ -0,0 +1,35 @@
@{
Layout = "_DialogLayout";
}
@using JXCMS.CMS.Movie.Entity
@model List<JXCMS.CMS.Movie.Entity.WebSiteClassifyEntity>
@{
var classifyEntities = (List<ClassifyEntity>) ViewBag.classifyEntities;
}
<form id="modify_website" action="@Url.Action("UpdateBindingClassify")" method="post">
@for (int i = 0; i < Model.Count; i++)
{
@Html.HiddenFor(x => x[i].Id)
@Html.HiddenFor(x => x[i].WebSiteId)
@Html.HiddenFor(x => x[i].TypeName)
@Html.HiddenFor(x => x[i].TypeId)
<div class="input-daterange input-group" style="margin-bottom: 10px">
<span class="form-control">@Model[i].TypeName</span>
<span class="input-group-addon">
<i class="mdi mdi-link-variant"></i>
</span>
@Html.DropDownListFor(x => x[i].ClassifyId, new SelectList(classifyEntities, "Id", "Name", Model[i].ClassifyId),
new {@class = "form-control"})
</div>
}
</form>
@section dialogScript
{
<script type="text/javascript">
$('#commit').click(function() {
$('#modify_website').submit();
})
</script>
}

View File

@ -47,10 +47,17 @@
<th>网站url</th> <th>网站url</th>
<th>采集cron</th> <th>采集cron</th>
<th>状态</th> <th>状态</th>
<th>下次执行时间</th>
<th>操作</th> <th>操作</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@if (ViewBag.website.Count == 0)
{
<tr>
<td colspan="7" style="text-align: center">无数据</td>
</tr>
}
@foreach (WebSiteEntity webSiteEntity in ViewBag.website) @foreach (WebSiteEntity webSiteEntity in ViewBag.website)
{ {
<tr> <tr>
@ -65,12 +72,13 @@
<td> <td>
<span class="text-success">@(webSiteEntity.IsEnable ? "正常" : "已禁用")</span> <span class="text-success">@(webSiteEntity.IsEnable ? "正常" : "已禁用")</span>
</td> </td>
<td>@webSiteEntity.NextRunTime</td>
<td> <td>
<div class="btn-group"> <div class="btn-group">
<a class="btn btn-xs btn-default" data-src="@Url.Action("WebSiteDialog", "Collection", new {id = webSiteEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal"> <a class="btn btn-xs btn-default" data-src="@Url.Action("WebSiteDialog", "Collection", new {id = webSiteEntity.Id})" title="编辑" data-toggle="modal" data-target="#exampleModal">
<i class="mdi mdi-pencil"></i> <i class="mdi mdi-pencil"></i>
</a> </a>
<a class="btn btn-xs btn-default" href="#" title="绑定分类" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')"> <a class="btn btn-xs btn-default" data-src="@Url.Action("BindingClassifyDialog", "Collection", new {id = webSiteEntity.Id})" data-toggle="modal" data-target="#exampleModal">
<i class="mdi mdi-link-variant"></i> <i class="mdi mdi-link-variant"></i>
</a> </a>
<a class="btn btn-xs btn-default" href="#" title="删除" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')"> <a class="btn btn-xs btn-default" href="#" title="删除" onclick="delWebsite(@webSiteEntity.Id, '@webSiteEntity.WebSiteName')">

View File

@ -34,11 +34,10 @@
<ul class="nav nav-drawer"> <ul class="nav nav-drawer">
<li class="nav-item active"> <a class="multitabs" href="@Url.Action("Home")"><i class="mdi mdi-home"></i> <span>后台首页</span></a> </li> <li class="nav-item active"> <a class="multitabs" href="@Url.Action("Home")"><i class="mdi mdi-home"></i> <span>后台首页</span></a> </li>
<li class="nav-item nav-item-has-subnav"> <li class="nav-item nav-item-has-subnav">
<a href="javascript:void(0)"><i class="mdi mdi-format-align-justify"></i> <span>文章</span></a> <a href="javascript:void(0)"><i class="mdi mdi-format-align-justify"></i> <span>影视</span></a>
<ul class="nav nav-subnav"> <ul class="nav nav-subnav">
<li> <a class="multitabs" href="@Url.Action("Index", "Article")">所有文章</a> </li> <li> <a class="multitabs" href="@Url.Action("Index", "Movie")">所有影视</a> </li>
<li> <a class="multitabs" href="lyear_forms_radio.html">写文章</a> </li> <li> <a class="multitabs" href="@Url.Action("Index", "Classify")">分类目录</a> </li>
<li> <a class="multitabs" href="lyear_forms_checkbox.html">分类目录</a> </li>
<li> <a class="multitabs" href="lyear_forms_switch.html">标签</a> </li> <li> <a class="multitabs" href="lyear_forms_switch.html">标签</a> </li>
</ul> </ul>
</li> </li>

View File

@ -0,0 +1,131 @@
@model List<JXCMS.CMS.Movie.Entity.MovieEntity>
@{
Layout = "_Layout";
}
<div class="container-fluid p-t-15">
<div class="row">
<div class="col-lg-12">
<div class="card">
<div class="card-toolbar clearfix">
<form class="pull-right search-bar" method="get" action="#!" role="form">
<div class="input-group">
<div class="input-group-btn">
<input type="hidden" name="search_field" id="search-field" value="title">
<button class="btn btn-default dropdown-toggle" id="search-btn" data-toggle="dropdown" type="button" aria-haspopup="true" aria-expanded="false">
标题 <span class="caret"></span>
</button>
<ul class="dropdown-menu">
<li>
<a tabindex="-1" href="javascript:void(0)" data-field="title">标题</a>
</li>
<li>
<a tabindex="-1" href="javascript:void(0)" data-field="cat_name">栏目</a>
</li>
</ul>
</div>
<input type="text" class="form-control" value="" name="keyword" placeholder="请输入名称">
</div>
</form>
<div class="toolbar-btn-action">
<a class="btn btn-primary m-r-5" href="#!"><i class="mdi mdi-plus"></i> 新增</a>
<a class="btn btn-success m-r-5" href="#!"><i class="mdi mdi-check"></i> 显示</a>
<a class="btn btn-warning m-r-5" href="#!"><i class="mdi mdi-block-helper"></i> 隐藏</a>
<a class="btn btn-danger" href="#!"><i class="mdi mdi-window-close"></i> 删除</a>
</div>
</div>
<div class="card-body">
<div class="table-responsive">
<table class="table table-bordered">
<thead>
<tr>
<th>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" id="check-all"><span></span>
</label>
</th>
<th>名称</th>
<th>导演</th>
<th>年份</th>
<th>语种</th>
<th>分类</th>
<th>状态</th>
<th>操作</th>
</tr>
</thead>
<tbody>
@foreach (var movieEntity in Model)
{
<tr>
<td>
<label class="lyear-checkbox checkbox-primary">
<input type="checkbox" name="ids[]" value="1"><span></span>
</label>
</td>
<td>@movieEntity.Name</td>
<td>@movieEntity.DirectorEntity.DirectorName</td>
<td>@movieEntity.Year</td>
<td>@movieEntity.Lang</td>
<td>@movieEntity.ClassifyEntity.Name</td>
<td>
<font class="text-success">@(movieEntity.IsEnable ? "正常" : "已隐藏")</font>
</td>
<td>
<div class="btn-group">
<a class="btn btn-xs btn-default" href="#!" title="编辑" data-toggle="tooltip">
<i class="mdi mdi-pencil"></i>
</a>
<a class="btn btn-xs btn-default" href="#!" title="删除" data-toggle="tooltip">
<i class="mdi mdi-window-close"></i>
</a>
</div>
</td>
</tr>
}
</tbody>
</table>
</div>
<ul class="pagination">
@if (ViewBag.pageNumber != 1)
{
<li>
<a href="@Url.Action("Index", "Collection")">&lt;&lt;</a>
</li>
}
@for (int i = ViewBag.pageNumber - 3; i < ViewBag.pageNumber + 3; i++)
{
if (i < 1 || i > ViewBag.totlePage)
{
continue;
}
if (i == ViewBag.pageNumber)
{
<li class="active">
<span>@i</span>
</li>
}
else
{
<li>
<a href="@Url.Action("Index", "Collection", new {pageNumber = i})">@i</a>
</li>
}
}
@if (ViewBag.pageNumber < ViewBag.totlePage)
{
<li>
<a href="@Url.Action("Index", "Collection", new {pageNumber = ViewBag.totlePage})">&gt;&gt;</a>
</li>
}
</ul>
</div>
</div>
</div>
</div>
</div>

View File

@ -6,6 +6,8 @@ using System.Threading.Tasks;
using Microsoft.AspNetCore.Mvc; using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using JXCMS.CMS.Models; using JXCMS.CMS.Models;
using JXCMS.CMS.Movie.Entity;
using JXCMS.CMS.Movie.Spider;
using JXCMS.Core.Themes; using JXCMS.Core.Themes;
namespace JXCMS.CMS.Controllers namespace JXCMS.CMS.Controllers
@ -35,5 +37,10 @@ namespace JXCMS.CMS.Controllers
{ {
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier }); return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
} }
public IActionResult Test()
{
return View();
}
} }
} }

View File

@ -0,0 +1,14 @@
using System.Collections.Generic;
using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity
{
public class ActorEntity : BaseEntity<ActorEntity, int>
{
public string ActorName { get; set; }
[Navigate(ManyToMany = typeof(MovieActorEntity))]
public List<MovieEntity> MovieEntities { get; set; }
}
}

View File

@ -1,4 +1,7 @@
using System.Collections.Generic;
using FreeSql; using FreeSql;
using FreeSql.DataAnnotations;
using Renci.SshNet.Messages.Transport;
namespace JXCMS.CMS.Movie.Entity namespace JXCMS.CMS.Movie.Entity
{ {
@ -6,6 +9,17 @@ namespace JXCMS.CMS.Movie.Entity
{ {
public string Name { get; set; } public string Name { get; set; }
public string Alias { get; set; }
public int ParentId { get; set; } public int ParentId { get; set; }
[Navigate("ParentId")]
public ClassifyEntity Parent { get; set; }
public ICollection<ClassifyEntity> Childs { get; set; }
[Column(IsIgnore = true)]
public long Count { get; set; }
} }
} }

View File

@ -0,0 +1,9 @@
using FreeSql;
namespace JXCMS.CMS.Movie.Entity
{
public class DirectorEntity : BaseEntity<DirectorEntity, int>
{
public string DirectorName { get; set; }
}
}

View File

@ -0,0 +1,18 @@
using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity
{
public class MovieActorEntity : BaseEntity<MovieActorEntity, int>
{
public int ActorId { get; set; }
[Navigate("ActorId")]
public ActorEntity ActorEntity { get; set; }
public int MovieId { get; set; }
[Navigate("MovieId")]
public MovieEntity MovieEntity { get; set; }
}
}

View File

@ -0,0 +1,44 @@
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity
{
public class MovieEntity : BaseEntity<MovieEntity, int>
{
public string Name { get; set; }
public string Pic { get; set; }
public int ClassifyId { get; set; }
public string Lang { get; set; }
public string Area { get; set; }
public string Year { get; set; }
public int DirectorId { get; set; }
public DateTime LastUpdate { get; set; }
public bool IsEnable { get; set; } = true;
[StringLength(-1)]
public string Des { get; set; }
[Navigate("DirectorId")]
public virtual DirectorEntity DirectorEntity { get; set; }
[Navigate("ClassifyId")]
public virtual ClassifyEntity ClassifyEntity { get; set; }
[Navigate(ManyToMany = typeof(MovieActorEntity))]
public virtual List<ActorEntity> ActorEntities { get; set; }
[Navigate("Id")]
public virtual List<MovieListEntity> MovieListEntities { get; set; }
}
}

View File

@ -0,0 +1,22 @@
using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity
{
public class MovieListEntity : BaseEntity<MovieListEntity, int>
{
public string Name { get; set; }
public string PlayUrl { get; set; }
public string Type { get; set; }
public int MovieId { get; set; }
public int WebSiteId { get; set; }
[Navigate("MovieId")]
public virtual MovieEntity MovieEntity { get; set; }
}
}

View File

@ -0,0 +1,19 @@
using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity
{
public class WebSiteClassifyEntity : BaseEntity<WebSiteClassifyEntity, int>
{
public int WebSiteId { get; set; }
public int TypeId { get; set; }
public string TypeName { get; set; }
public int ClassifyId { get; set; }
[Navigate("WebSiteId")]
public virtual WebSiteEntity WebSiteEntity { get; set; }
}
}

View File

@ -1,4 +1,7 @@
using System;
using System.Collections.Generic;
using FreeSql; using FreeSql;
using FreeSql.DataAnnotations;
namespace JXCMS.CMS.Movie.Entity namespace JXCMS.CMS.Movie.Entity
{ {
@ -11,5 +14,15 @@ namespace JXCMS.CMS.Movie.Entity
public string Cron { get; set; } = "0 0 * * * ?"; public string Cron { get; set; } = "0 0 * * * ?";
public bool IsEnable { get; set; } = true; public bool IsEnable { get; set; } = true;
public string LatestMovieNote { get; set; }
public DateTime LatestMoveTime { get; set; }
[Navigate("Id")]
public List<ClassifyEntity> WebSiteClassifyEntities { get; set; }
[Column(IsIgnore = true)]
public string NextRunTime { get; set; }
} }
} }

View File

@ -21,6 +21,7 @@
<ItemGroup> <ItemGroup>
<Folder Include="Admin\Content" /> <Folder Include="Admin\Content" />
<Folder Include="Logs" />
<Folder Include="Views\Default" /> <Folder Include="Views\Default" />
</ItemGroup> </ItemGroup>

View File

@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using JXCMS.CMS.Movie.Entity;
namespace JXCMS.CMS.Movie.Models
{
public class MovieListInfoModel
{
public string RecordCount { get; set; }
public string PageSize { get; set; }
public string CurrentPage { get; set; }
public string PageCount { get; set; }
public List<MovieInfoModel> MovieInfoModels { get; set; } = new List<MovieInfoModel>();
}
public class MovieInfoModel
{
public string Id { get; set; }
public string TypeId { get; set; }
public DateTime LastUpdateTime { get; set; }
public string Name { get; set; }
public string TypeName { get; set; }
}
}

View File

@ -7,6 +7,7 @@ using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Hosting;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using Serilog;
namespace JXCMS.CMS namespace JXCMS.CMS
{ {
@ -22,6 +23,6 @@ namespace JXCMS.CMS
.ConfigureWebHostDefaults(webBuilder => .ConfigureWebHostDefaults(webBuilder =>
{ {
webBuilder.UseStartup<Startup>(); webBuilder.UseStartup<Startup>();
}); }).UseSerilog();
} }
} }

View File

@ -0,0 +1,38 @@
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Xml;
using JXCMS.CMS.Movie.Entity;
using SufeiUtil;
namespace JXCMS.CMS.Movie.Spider
{
public class ClassifySpider
{
public static void GetAllClassifyFromUrl(int websiteId, string url, List<WebSiteClassifyEntity> webSiteClassifyEntities)
{
var helper = new HttpHelper();
var item = new HttpItem();
item.URL = url;
var result = helper.GetHtml(item);
if (result.StatusCode == HttpStatusCode.OK)
{
XmlDocument doc = new XmlDocument();
doc.LoadXml(result.Html);
var classNode = doc.SelectSingleNode("/rss/class");
foreach (XmlNode childNode in classNode.ChildNodes)
{
if (webSiteClassifyEntities.All(x => x.TypeId.ToString() != childNode.Attributes["id"].Value))
{
WebSiteClassifyEntity webSiteClassifyEntity = new WebSiteClassifyEntity();
webSiteClassifyEntity.TypeId = int.Parse(childNode.Attributes["id"].Value);
webSiteClassifyEntity.TypeName = childNode.InnerText;
webSiteClassifyEntity.WebSiteId = websiteId;
webSiteClassifyEntities.Add(webSiteClassifyEntity);
}
}
}
}
}
}

View File

@ -0,0 +1,265 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Xml;
using FreeSql;
using JXCMS.CMS.Movie.Entity;
using JXCMS.CMS.Movie.Models;
using JXCMS.Core.Extensions;
using JXCMS.Core.Log;
using SufeiUtil;
using Log = Serilog.Log;
namespace JXCMS.CMS.Movie.Spider
{
public class MovieSpider
{
private readonly List<WebSiteClassifyEntity> _webSiteClassifyEntities;
private readonly List<ActorEntity> _actorEntities;
private readonly List<DirectorEntity> _directorEntities;
private static MovieSpider _instance;
public static MovieSpider Instance => _instance ??= new MovieSpider();
private MovieSpider()
{
_webSiteClassifyEntities = WebSiteClassifyEntity.Select.ToList();
_actorEntities = ActorEntity.Select.ToList();
_directorEntities = DirectorEntity.Select.ToList();
}
public MovieListInfoModel GetMovieList(WebSiteEntity webSiteEntity, int number)
{
HttpItem item = new HttpItem();
item.URL = $"{webSiteEntity.ApiUrl}?pg={number}";
HttpHelper helper = new HttpHelper();
var result = helper.GetHtml(item);
if (result.StatusCode == HttpStatusCode.OK)
{
Log.Logger.Information($"{{@name}} 成功获取地址:{item.URL}", webSiteEntity.WebSiteName);
XmlDocument doc = new XmlDocument();
doc.LoadXml(result.Html);
var listNode = doc.SelectSingleNode("/rss/list");
MovieListInfoModel movieListInfoModel = new MovieListInfoModel();;
movieListInfoModel.CurrentPage = listNode.Attributes["page"].Value;
movieListInfoModel.PageCount = listNode.Attributes["pagecount"].Value;
movieListInfoModel.PageSize = listNode.Attributes["pagesize"].Value;
movieListInfoModel.RecordCount = listNode.Attributes["recordcount"].Value;
var videos = listNode.SelectNodes("//video");
foreach (XmlNode video in videos)
{
MovieInfoModel model = new MovieInfoModel
{
LastUpdateTime = DateTime.Parse(video.SelectSingleNode("last").InnerText),
Name = video.SelectSingleNode("name").InnerText,
TypeId = video.SelectSingleNode("tid").InnerText,
Id = video.SelectSingleNode("id").InnerText,
TypeName = video.SelectSingleNode("type").InnerText
};
movieListInfoModel.MovieInfoModels.Add(model);
}
return movieListInfoModel;
}
Log.Warning($"{{@name}} 获取api失败错误码{result.StatusCode}", webSiteEntity.WebSiteName);
return null;
}
public DateTime GetMovieInfos(WebSiteEntity webSiteEntity, List<(string id, string name, string typeId)> idNameTypes)
{
HttpItem item = new HttpItem();
item.URL = $"{webSiteEntity.ApiUrl}?ac=videolist&ids={string.Join(",", idNameTypes.Select(x => x.id))}";
HttpHelper helper = new HttpHelper();
var result = helper.GetHtml(item);
if (result.StatusCode == HttpStatusCode.OK)
{
DateTime dt = DateTime.MinValue;
Log.Logger.Information($"{{@name}} 成功获取地址:{item.URL}", webSiteEntity.WebSiteName);
XmlDocument doc = new XmlDocument();
doc.LoadXml(result.Html);
var videoNode = doc.SelectNodes("/rss/list/video");
foreach (XmlNode video in videoNode)
{
var name = video.SelectSingleNode("name").InnerText;
var director = video.SelectSingleNode("director").InnerText;
if (director.IsNullOrEmpty())
{
director = "未知";
}
var movieEntity = MovieEntity.Select.Include(x => x.DirectorEntity)
.Where(x => x.Name == name && x.DirectorEntity.DirectorName == director).First();
if (movieEntity == null)
{
movieEntity = new MovieEntity();
movieEntity.Area = video.SelectSingleNode("area").InnerText == "" ? "未知":video.SelectSingleNode("area").InnerText;
movieEntity.Des = video.SelectSingleNode("des").InnerText == "" ? "暂无介绍":video.SelectSingleNode("des").InnerText;
movieEntity.Lang = video.SelectSingleNode("lang").InnerText == "" ? "未知":video.SelectSingleNode("lang").InnerText;
movieEntity.Name = video.SelectSingleNode("name").InnerText;
movieEntity.Pic = video.SelectSingleNode("pic").InnerText == "" ? "/img/cover.jpg":video.SelectSingleNode("lang").InnerText;
movieEntity.Year = video.SelectSingleNode("year").InnerText == "" || video.SelectSingleNode("year").InnerText == "0" ? "未知":video.SelectSingleNode("year").InnerText;
movieEntity.ClassifyId = int.Parse(idNameTypes.First(x => x.id == video.SelectSingleNode("id").InnerText).typeId);
var directorId = _directorEntities.FirstOrDefault(x => x.DirectorName == director)?.Id;
if (directorId == null)
{
DirectorEntity directorEntity = new DirectorEntity();
directorEntity.DirectorName = director;
directorEntity.Save();
directorId = directorEntity.Id;
}
movieEntity.DirectorId = directorId.Value;
movieEntity.LastUpdate = DateTime.Parse(video.SelectSingleNode("last").InnerText);
movieEntity.Save();
if (movieEntity.LastUpdate > dt)
{
dt = movieEntity.LastUpdate;
}
var actorStr = video.SelectSingleNode("actor").InnerText;
if (actorStr.IsNullOrEmpty())
{
actorStr = "未知";
}
var actorsStr = actorStr.Split(',', ' ');
var actors = _actorEntities.Where(x => actorsStr.Contains(x.ActorName)).ToList();
foreach (var actor in actorsStr)
{
var id = actors.FirstOrDefault(x => x.ActorName == actor)?.Id;
if (id == null)
{
ActorEntity actorEntity = new ActorEntity {ActorName = actor};
actorEntity.Save();
id = actorEntity.Id;
}
MovieActorEntity movieActorEntity = new MovieActorEntity
{
ActorId = id.Value, MovieId = movieEntity.Id
};
movieActorEntity.Save();
}
}
var dds = video.SelectNodes("dl/dd");
var movieListEntity = MovieListEntity.Where(x => x.MovieId == movieEntity.Id && x.WebSiteId == webSiteEntity.Id)
.OrderByDescending(x => x.Id).First();
if (movieListEntity == null)
{
foreach (XmlNode dd in dds)
{
var number = dd.InnerText.Split('#');
if (number.Length <= 0 || !number[0].Split('$')[1].ToLower().EndsWith("m3u8"))
{
continue;
}
Log.Logger.Information("{@name} 获取到m3u8列表", webSiteEntity.WebSiteName);
var movieListEntities = number.Select(x =>
{
var sp = x.Split('$');
return new MovieListEntity
{
Name = sp[0],
Type = sp[2],
MovieId = movieEntity.Id,
PlayUrl = sp[1],
WebSiteId = webSiteEntity.Id
};
});
BaseEntity.Orm.Insert(movieListEntities).ExecuteAffrows();
Log.Logger.Information($"{{@name}} 插入剧集{movieEntity.Name}成功!", webSiteEntity.WebSiteName);
}
}
else
{
var node = dds.Cast<XmlNode>().FirstOrDefault(x => x.Attributes["flag"].Value == movieListEntity.Type);
if (node == null)
{
Log.Logger.Error("{@name} 未找到指定的剧集列表!", webSiteEntity.WebSiteName);
}
bool flag = false;
foreach (var number in node.InnerText.Split('#'))
{
var sp = number.Split('$');
if (sp[0] == movieListEntity.Name)
{
flag = true;
continue;
}
if (!flag)
{
continue;
}
new MovieListEntity()
{
Name = sp[0],
MovieId = movieEntity.Id,
PlayUrl = sp[1],
Type = sp[2],
WebSiteId = webSiteEntity.Id
}.Save();
Log.Logger.Information($"{{@name}} 插入剧集{movieEntity.Name}-{sp[0]}成功!", webSiteEntity.WebSiteName);
}
}
}
return dt;
}
return DateTime.MinValue;
}
public void StartSpider(WebSiteEntity webSiteEntity, bool reGetAll = false)
{
var model = GetMovieList(webSiteEntity, 1);
if (model == null)
{
Log.Logger.Error("{@name} 获取信息失败,采集结束!", webSiteEntity.WebSiteName);
return;
}
int number = 1;
if (!int.TryParse(model.PageCount, out int count))
{
Log.Logger.Error("{@name} 获取总页数失败,采集结束!", webSiteEntity.WebSiteName);
return;
}
DateTime dt = DateTime.MinValue;
do
{
model = GetMovieList(webSiteEntity, number++);
if (model == null)
{
Log.Logger.Error("{@name} 获取信息失败,采集结束!", webSiteEntity.WebSiteName);
return;
}
List<(string id, string name, string typeId)> idNameTypes = new List<(string, string, string)>();
foreach (var modelMovieInfoModel in model.MovieInfoModels)
{
if (webSiteEntity.LatestMoveTime > modelMovieInfoModel.LastUpdateTime)
{
Log.Logger.Information("{@name} 已检查到最后一条", webSiteEntity.WebSiteName);
break;
}
if (!_webSiteClassifyEntities.Any(x => x.WebSiteId == webSiteEntity.Id && x.TypeId.ToString() == modelMovieInfoModel.TypeId))
{
Log.Logger.Warning($"{{@name}} 未找到与{modelMovieInfoModel.TypeName}对应的分类,自动跳过", webSiteEntity.WebSiteName);
continue;
}
idNameTypes.Add((modelMovieInfoModel.Id, modelMovieInfoModel.Name, modelMovieInfoModel.TypeId));
}
if (idNameTypes.Count == 0)
{
if (webSiteEntity.LatestMoveTime < dt)
{
webSiteEntity.LatestMoveTime = dt;
webSiteEntity.Save();
}
Log.Information("{@name} 采集完成!", webSiteEntity.WebSiteName);
return;
}
dt = GetMovieInfos(webSiteEntity, idNameTypes);
} while (number <= count);
}
}
}

View File

@ -8,12 +8,15 @@ using JXCMS.CMS.Entity;
using JXCMS.Core; using JXCMS.Core;
using JXCMS.Core.Auth; using JXCMS.Core.Auth;
using JXCMS.Core.Db; using JXCMS.Core.Db;
using JXCMS.Core.Log;
using JXCMS.Core.Themes; using JXCMS.Core.Themes;
using JXCMS.Core.Utils;
using Microsoft.AspNetCore.Authentication.Cookies; using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Builder; using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Hosting; using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http; using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.HttpsPolicy; using Microsoft.AspNetCore.HttpsPolicy;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Mvc.Razor; using Microsoft.AspNetCore.Mvc.Razor;
using Microsoft.Extensions.Configuration; using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.DependencyInjection;
@ -28,6 +31,8 @@ namespace JXCMS.CMS
{ {
Configuration = configuration; Configuration = configuration;
Environment = environment; Environment = environment;
ConfigHelper.Configs = Configuration;
Log.Init();
} }
public IHostEnvironment Environment { get; } public IHostEnvironment Environment { get; }
@ -54,6 +59,10 @@ namespace JXCMS.CMS
services.AddCms(); services.AddCms();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
} }
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.

View File

@ -0,0 +1,46 @@
using System.Collections.Generic;
using System.Linq;
using JXCMS.CMS.Movie.Entity;
using JXCMS.Core.Extensions;
namespace JXCMS.CMS.Movie.Utils
{
public static class Classify
{
public static List<ClassifyEntity> FindAllChildren(List<ClassifyEntity> classifyEntities, int baseId, bool includeSelf = true)
{
var returnValue = new List<ClassifyEntity>();
if (includeSelf)
{
returnValue.AddRange(classifyEntities.Where(x => x.Id == baseId));
}
var classifyEntityList = classifyEntities.Where(x => x.ParentId == baseId).ToList();
returnValue.AddRange(classifyEntityList);
foreach (var classifyEntity in classifyEntityList)
{
returnValue.AddRange(FindAllChildren(classifyEntities, classifyEntity.Id, false));
}
return returnValue;
}
public static List<ClassifyEntity> FindAllNotChildren(List<ClassifyEntity> classifyEntities, int baseId)
{
var children = FindAllChildren(classifyEntities, baseId, true);
return classifyEntities.Where(x => !children.Contains(x)).ToList();
}
public static List<ClassifyEntity> Structured(List<ClassifyEntity> classifyEntities, int baseId = 0, int hierarchy = 0)
{
var returnValue = new List<ClassifyEntity>();
var classifyEntityList = classifyEntities.Where(x => x.ParentId == baseId).ToList();
foreach (var classifyEntity in classifyEntityList)
{
classifyEntity.Name = classifyEntity.Name.InsertMultipleString("-", hierarchy * 2);
returnValue.Add(classifyEntity);
returnValue.AddRange(Structured(classifyEntities, classifyEntity.Id, hierarchy + 1));
}
return returnValue;
}
}
}

View File

@ -0,0 +1,848 @@
/// <summary>
/// 类说明HttpHelper类用来实现Http访问Post或者Get方式的直接访问带Cookie的带证书的等方式可以设置代理
/// 重要提示:请不要自行修改本类,如果因为你自己修改后将无法升级到新版本。如果确实有什么问题请到官方网站提建议,
/// 我们一定会及时修改
/// 编码日期2011-09-20
/// 编 码 人:苏飞
/// 联系方式361983679
/// 官方网址http://www.sufeinet.com/thread-3-1-1.html
/// 修改日期2020-02-10
/// 版 本 号2.2.9
/// </summary>
using System;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.IO;
using System.Text.RegularExpressions;
using System.IO.Compression;
using System.Security.Cryptography.X509Certificates;
using System.Net.Security;
using System.Linq;
using System.Net.Cache;
namespace SufeiUtil
{
/// <summary>
/// Http连接操作帮助类
/// </summary>
public class HttpHelper
{
#region
//默认的编码
private Encoding encoding = Encoding.Default;
//Post数据编码
private Encoding postencoding = Encoding.Default;
//HttpWebRequest对象用来发起请求
private HttpWebRequest request = null;
//获取影响流的数据对象
private HttpWebResponse response = null;
//设置本地的出口ip和端口
private IPEndPoint _IPEndPoint = null;
#endregion
#region Public
/// <summary>
/// 根据相传入的数据,得到相应页面数据
/// </summary>
/// <param name="item">参数类对象</param>
/// <returns>返回HttpResult类型</returns>
public HttpResult GetHtml(HttpItem item)
{
//返回参数
HttpResult result = new HttpResult();
try
{
//准备参数
SetRequest(item);
}
catch (Exception ex)
{
//配置参数时出错
return new HttpResult() { Cookie = string.Empty, Header = null, Html = ex.Message, StatusDescription = "配置参数时出错:" + ex.Message };
}
try
{
//请求数据
using (response = (HttpWebResponse)request.GetResponse())
{
GetData(item, result);
}
}
catch (WebException ex)
{
if (ex.Response != null)
{
using (response = (HttpWebResponse)ex.Response)
{
GetData(item, result);
}
}
else
{
result.Html = ex.Message;
}
}
catch (Exception ex)
{
result.Html = ex.Message;
}
if (item.IsToLower) result.Html = result.Html.ToLower();
//重置requestresponse为空
if (item.IsReset)
{
request = null;
response = null;
}
return result;
}
#endregion
#region GetData
/// <summary>
/// 获取数据的并解析的方法
/// </summary>
/// <param name="item"></param>
/// <param name="result"></param>
private void GetData(HttpItem item, HttpResult result)
{
if (response == null)
{
return;
}
#region base
//获取StatusCode
result.StatusCode = response.StatusCode;
//获取StatusDescription
result.StatusDescription = response.StatusDescription;
//获取Headers
result.Header = response.Headers;
//获取最后访问的URl
result.ResponseUri = response.ResponseUri.ToString();
//获取CookieCollection
if (response.Cookies != null) result.CookieCollection = response.Cookies;
//获取set-cookie
if (response.Headers["set-cookie"] != null) result.Cookie = response.Headers["set-cookie"];
#endregion
#region byte
//处理网页Byte
byte[] ResponseByte = GetByte();
#endregion
#region Html
if (ResponseByte != null && ResponseByte.Length > 0)
{
//设置编码
SetEncoding(item, result, ResponseByte);
//得到返回的HTML
result.Html = encoding.GetString(ResponseByte);
}
else
{
//没有返回任何Html代码
result.Html = string.Empty;
}
#endregion
}
/// <summary>
/// 设置编码
/// </summary>
/// <param name="item">HttpItem</param>
/// <param name="result">HttpResult</param>
/// <param name="ResponseByte">byte[]</param>
private void SetEncoding(HttpItem item, HttpResult result, byte[] ResponseByte)
{
//是否返回Byte类型数据
if (item.ResultType == ResultType.Byte) result.ResultByte = ResponseByte;
//从这里开始我们要无视编码了
if (encoding == null)
{
Match meta = Regex.Match(Encoding.Default.GetString(ResponseByte), "<meta[^<]*charset=([^<]*)[\"']", RegexOptions.IgnoreCase);
string c = string.Empty;
if (meta != null && meta.Groups.Count > 0)
{
c = meta.Groups[1].Value.ToLower().Trim();
}
if (c.Length > 2)
{
try
{
encoding = Encoding.GetEncoding(c.Replace("\"", string.Empty).Replace("'", "").Replace(";", "").Replace("iso-8859-1", "gbk").Trim());
}
catch
{
if (string.IsNullOrEmpty(response.CharacterSet))
{
encoding = Encoding.UTF8;
}
else
{
encoding = Encoding.GetEncoding(response.CharacterSet);
}
}
}
else
{
if (string.IsNullOrEmpty(response.CharacterSet))
{
encoding = Encoding.UTF8;
}
else
{
encoding = Encoding.GetEncoding(response.CharacterSet);
}
}
}
}
/// <summary>
/// 提取网页Byte
/// </summary>
/// <returns></returns>
private byte[] GetByte()
{
byte[] ResponseByte = null;
using (MemoryStream _stream = new MemoryStream())
{
//GZIIP处理
if (response.ContentEncoding != null && response.ContentEncoding.Equals("gzip", StringComparison.InvariantCultureIgnoreCase))
{
//开始读取流并设置编码方式
new GZipStream(response.GetResponseStream(), CompressionMode.Decompress).CopyTo(_stream, 1024);
}
else
{
//开始读取流并设置编码方式
response.GetResponseStream().CopyTo(_stream, 1024);
}
//获取Byte
ResponseByte = _stream.ToArray();
}
return ResponseByte;
}
#endregion
#region SetRequest
/// <summary>
/// 为请求准备参数
/// </summary>
///<param name="item">参数列表</param>
private void SetRequest(HttpItem item)
{
// 验证证书
SetCer(item);
if (item.IPEndPoint != null)
{
_IPEndPoint = item.IPEndPoint;
//设置本地的出口ip和端口
request.ServicePoint.BindIPEndPointDelegate = new BindIPEndPoint(BindIPEndPointCallback);
}
//设置Header参数
if (item.Header != null && item.Header.Count > 0) foreach (string key in item.Header.AllKeys)
{
request.Headers.Add(key, item.Header[key]);
}
// 设置代理
SetProxy(item);
if (item.ProtocolVersion != null) request.ProtocolVersion = item.ProtocolVersion;
request.ServicePoint.Expect100Continue = item.Expect100Continue;
//请求方式Get或者Post
request.Method = item.Method;
request.Timeout = item.Timeout;
request.KeepAlive = item.KeepAlive;
request.ReadWriteTimeout = item.ReadWriteTimeout;
if (!string.IsNullOrWhiteSpace(item.Host))
{
request.Host = item.Host;
}
if (item.IfModifiedSince != null) request.IfModifiedSince = Convert.ToDateTime(item.IfModifiedSince);
if (item.Date!=null)
{
request.Date = Convert.ToDateTime(item.Date);
}
//Accept
request.Accept = item.Accept;
//ContentType返回类型
request.ContentType = item.ContentType;
//UserAgent客户端的访问类型包括浏览器版本和操作系统信息
request.UserAgent = item.UserAgent;
// 编码
encoding = item.Encoding;
//设置安全凭证
request.Credentials = item.ICredentials;
//设置Cookie
SetCookie(item);
//来源地址
request.Referer = item.Referer;
//是否执行跳转功能
request.AllowAutoRedirect = item.Allowautoredirect;
if (item.MaximumAutomaticRedirections > 0)
{
request.MaximumAutomaticRedirections = item.MaximumAutomaticRedirections;
}
//设置Post数据
SetPostData(item);
//设置最大连接
if (item.Connectionlimit > 0) request.ServicePoint.ConnectionLimit = item.Connectionlimit;
}
/// <summary>
/// 设置证书
/// </summary>
/// <param name="item"></param>
private void SetCer(HttpItem item)
{
if (!string.IsNullOrWhiteSpace(item.CerPath))
{
//这一句一定要写在创建连接的前面。使用回调的方法进行证书验证。
ServicePointManager.ServerCertificateValidationCallback = new System.Net.Security.RemoteCertificateValidationCallback(CheckValidationResult);
//初始化对像并设置请求的URL地址
request = (HttpWebRequest)WebRequest.Create(item.URL);
SetCerList(item);
//将证书添加到请求里
request.ClientCertificates.Add(new X509Certificate(item.CerPath));
}
else
{
//初始化对像并设置请求的URL地址
request = (HttpWebRequest)WebRequest.Create(item.URL);
SetCerList(item);
}
}
/// <summary>
/// 设置多个证书
/// </summary>
/// <param name="item"></param>
private void SetCerList(HttpItem item)
{
if (item.ClentCertificates != null && item.ClentCertificates.Count > 0)
{
foreach (X509Certificate c in item.ClentCertificates)
{
request.ClientCertificates.Add(c);
}
}
}
/// <summary>
/// 设置Cookie
/// </summary>
/// <param name="item">Http参数</param>
private void SetCookie(HttpItem item)
{
if (!string.IsNullOrEmpty(item.Cookie)) request.Headers[HttpRequestHeader.Cookie] = item.Cookie;
//设置CookieCollection
if (item.ResultCookieType == ResultCookieType.CookieCollection)
{
request.CookieContainer = new CookieContainer();
if (item.CookieCollection != null && item.CookieCollection.Count > 0)
{
//默认为20个如果超出需要增加长度
if (item.CookieCollection.Count > 20)
{
request.CookieContainer.PerDomainCapacity = item.CookieCollection.Count;
}
request.CookieContainer.Add(item.CookieCollection);
}
}
}
/// <summary>
/// 设置Post数据
/// </summary>
/// <param name="item">Http参数</param>
private void SetPostData(HttpItem item)
{
//验证在得到结果时是否有传入数据
if (!request.Method.Trim().ToLower().Contains("get"))
{
if (item.PostEncoding != null)
{
postencoding = item.PostEncoding;
}
byte[] buffer = null;
//写入Byte类型
if (item.PostDataType == PostDataType.Byte && item.PostdataByte != null && item.PostdataByte.Length > 0)
{
//验证在得到结果时是否有传入数据
buffer = item.PostdataByte;
}//写入文件
else if (item.PostDataType == PostDataType.FilePath && !string.IsNullOrWhiteSpace(item.Postdata))
{
StreamReader r = new StreamReader(item.Postdata, postencoding);
buffer = postencoding.GetBytes(r.ReadToEnd());
r.Close();
} //写入字符串
else if (!string.IsNullOrWhiteSpace(item.Postdata))
{
buffer = postencoding.GetBytes(item.Postdata);
}
if (buffer != null)
{
request.ContentLength = buffer.Length;
request.GetRequestStream().Write(buffer, 0, buffer.Length);
}
else
{
request.ContentLength = 0;
}
}
}
/// <summary>
/// 设置代理
/// </summary>
/// <param name="item">参数对象</param>
private void SetProxy(HttpItem item)
{
bool isIeProxy = false;
if (!string.IsNullOrWhiteSpace(item.ProxyIp))
{
isIeProxy = item.ProxyIp.ToLower().Contains("ieproxy");
}
if (!string.IsNullOrWhiteSpace(item.ProxyIp) && !isIeProxy)
{
//设置代理服务器
if (item.ProxyIp.Contains(":"))
{
string[] plist = item.ProxyIp.Split(':');
WebProxy myProxy = new WebProxy(plist[0].Trim(), Convert.ToInt32(plist[1].Trim()));
//建议连接
myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd);
//给当前请求对象
request.Proxy = myProxy;
}
else
{
WebProxy myProxy = new WebProxy(item.ProxyIp, false);
//建议连接
myProxy.Credentials = new NetworkCredential(item.ProxyUserName, item.ProxyPwd);
//给当前请求对象
request.Proxy = myProxy;
}
}
else if (isIeProxy)
{
//设置为IE代理
}
else
{
request.Proxy = item.WebProxy;
}
}
#endregion
#region private main
/// <summary>
/// 回调验证证书问题
/// </summary>
/// <param name="sender">流对象</param>
/// <param name="certificate">证书</param>
/// <param name="chain">X509Chain</param>
/// <param name="errors">SslPolicyErrors</param>
/// <returns>bool</returns>
private bool CheckValidationResult(object sender, X509Certificate certificate, X509Chain chain, SslPolicyErrors errors) { return true; }
/// <summary>
/// 通过设置这个属性可以在发出连接的时候绑定客户端发出连接所使用的IP地址。
/// </summary>
/// <param name="servicePoint"></param>
/// <param name="remoteEndPoint"></param>
/// <param name="retryCount"></param>
/// <returns></returns>
private IPEndPoint BindIPEndPointCallback(ServicePoint servicePoint, IPEndPoint remoteEndPoint, int retryCount)
{
return _IPEndPoint;//端口号
}
#endregion
}
#region public calss
/// <summary>
/// Http请求参考类
/// </summary>
public class HttpItem
{
/// <summary>
/// 请求URL必须填写
/// </summary>
public string URL { get; set; }
string _Method = "GET";
/// <summary>
/// 请求方式默认为GET方式,当为POST方式时必须设置Postdata的值
/// </summary>
public string Method
{
get { return _Method; }
set { _Method = value; }
}
int _Timeout = 100000;
/// <summary>
/// 默认请求超时时间
/// </summary>
public int Timeout
{
get { return _Timeout; }
set { _Timeout = value; }
}
int _ReadWriteTimeout = 30000;
/// <summary>
/// 默认写入Post数据超时间
/// </summary>
public int ReadWriteTimeout
{
get { return _ReadWriteTimeout; }
set { _ReadWriteTimeout = value; }
}
/// <summary>
/// 设置Host的标头信息
/// </summary>
public string Host { get; set; }
Boolean _KeepAlive = true;
/// <summary>
/// 获取或设置一个值,该值指示是否与 Internet 资源建立持久性连接默认为true。
/// </summary>
public Boolean KeepAlive
{
get { return _KeepAlive; }
set { _KeepAlive = value; }
}
string _Accept = "text/html, application/xhtml+xml, */*";
/// <summary>
/// 请求标头值 默认为text/html, application/xhtml+xml, */*
/// </summary>
public string Accept
{
get { return _Accept; }
set { _Accept = value; }
}
string _ContentType = "text/html";
/// <summary>
/// 请求返回类型默认 text/html
/// </summary>
public string ContentType
{
get { return _ContentType; }
set { _ContentType = value; }
}
string _UserAgent = "Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)";
/// <summary>
/// 客户端访问信息默认Mozilla/5.0 (compatible; MSIE 9.0; Windows NT 6.1; Trident/5.0)
/// </summary>
public string UserAgent
{
get { return _UserAgent; }
set { _UserAgent = value; }
}
/// <summary>
/// 返回数据编码默认为NUll,可以自动识别,一般为utf-8,gbk,gb2312
/// </summary>
public Encoding Encoding { get; set; }
private PostDataType _PostDataType = PostDataType.String;
/// <summary>
/// Post的数据类型
/// </summary>
public PostDataType PostDataType
{
get { return _PostDataType; }
set { _PostDataType = value; }
}
/// <summary>
/// Post请求时要发送的字符串Post数据
/// </summary>
public string Postdata { get; set; }
/// <summary>
/// Post请求时要发送的Byte类型的Post数据
/// </summary>
public byte[] PostdataByte { get; set; }
/// <summary>
/// Cookie对象集合
/// </summary>
public CookieCollection CookieCollection { get; set; }
/// <summary>
/// 请求时的Cookie
/// </summary>
public string Cookie { get; set; }
/// <summary>
/// 来源地址,上次访问地址
/// </summary>
public string Referer { get; set; }
/// <summary>
/// 证书绝对路径
/// </summary>
public string CerPath { get; set; }
/// <summary>
/// 设置代理对象不想使用IE默认配置就设置为Null而且不要设置ProxyIp
/// </summary>
public WebProxy WebProxy { get; set; }
private Boolean isToLower = false;
/// <summary>
/// 是否设置为全文小写,默认为不转化
/// </summary>
public Boolean IsToLower
{
get { return isToLower; }
set { isToLower = value; }
}
private DateTime? _Date = null;
/// <summary>
/// 获取或设置要在 HTTP 请求中使用的 Date HTTP 标头值。默认不填写
/// </summary>
public DateTime? Date
{
get { return _Date; }
set { _Date = value; }
}
private Boolean allowautoredirect = false;
/// <summary>
/// 支持跳转页面,查询结果将是跳转后的页面,默认是不跳转
/// </summary>
public Boolean Allowautoredirect
{
get { return allowautoredirect; }
set { allowautoredirect = value; }
}
private int connectionlimit = 1024;
/// <summary>
/// 最大连接数
/// </summary>
public int Connectionlimit
{
get { return connectionlimit; }
set { connectionlimit = value; }
}
/// <summary>
/// 代理Proxy 服务器用户名
/// </summary>
public string ProxyUserName { get; set; }
/// <summary>
/// 代理 服务器密码
/// </summary>
public string ProxyPwd { get; set; }
/// <summary>
/// 代理 服务IP,如果要使用IE代理就设置为ieproxy
/// </summary>
public string ProxyIp { get; set; }
private ResultType resulttype = ResultType.String;
/// <summary>
/// 设置返回类型String和Byte
/// </summary>
public ResultType ResultType
{
get { return resulttype; }
set { resulttype = value; }
}
private WebHeaderCollection header = new WebHeaderCollection();
/// <summary>
/// header对象
/// </summary>
public WebHeaderCollection Header
{
get { return header; }
set { header = value; }
}
/// <summary>
// 获取或设置用于请求的 HTTP 版本。返回结果:用于请求的 HTTP 版本。默认为 System.Net.HttpVersion.Version11。
/// </summary>
public Version ProtocolVersion { get; set; }
private Boolean _expect100continue = false;
/// <summary>
/// 获取或设置一个 System.Boolean 值,该值确定是否使用 100-Continue 行为。如果 POST 请求需要 100-Continue 响应,则为 true否则为 false。默认值为 true。
/// </summary>
public Boolean Expect100Continue
{
get { return _expect100continue; }
set { _expect100continue = value; }
}
/// <summary>
/// 设置509证书集合
/// </summary>
public X509CertificateCollection ClentCertificates { get; set; }
/// <summary>
/// 设置或获取Post参数编码,默认的为Default编码
/// </summary>
public Encoding PostEncoding { get; set; }
private ResultCookieType _ResultCookieType = ResultCookieType.String;
/// <summary>
/// Cookie返回类型,默认的是只返回字符串类型
/// </summary>
public ResultCookieType ResultCookieType
{
get { return _ResultCookieType; }
set { _ResultCookieType = value; }
}
private ICredentials _ICredentials = CredentialCache.DefaultCredentials;
/// <summary>
/// 获取或设置请求的身份验证信息。
/// </summary>
public ICredentials ICredentials
{
get { return _ICredentials; }
set { _ICredentials = value; }
}
/// <summary>
/// 设置请求将跟随的重定向的最大数目
/// </summary>
public int MaximumAutomaticRedirections { get; set; }
private DateTime? _IfModifiedSince = null;
/// <summary>
/// 获取和设置IfModifiedSince默认为当前日期和时间
/// </summary>
public DateTime? IfModifiedSince
{
get { return _IfModifiedSince; }
set { _IfModifiedSince = value; }
}
#region ip-port
private IPEndPoint _IPEndPoint = null;
/// <summary>
/// 设置本地的出口ip和端口
/// </summary>]
/// <example>
///item.IPEndPoint = new IPEndPoint(IPAddress.Parse("192.168.1.1"),80);
/// </example>
public IPEndPoint IPEndPoint
{
get { return _IPEndPoint; }
set { _IPEndPoint = value; }
}
#endregion
private bool _isReset = false;
/// <summary>
/// 是否重置request,response的值默认不重置当设置为True时request,response将被设置为Null
/// </summary>
public bool IsReset
{
get { return _isReset; }
set { _isReset = value; }
}
}
/// <summary>
/// Http返回参数类
/// </summary>
public class HttpResult
{
/// <summary>
/// Http请求返回的Cookie
/// </summary>
public string Cookie { get; set; }
/// <summary>
/// Cookie对象集合
/// </summary>
public CookieCollection CookieCollection { get; set; }
private string _html = string.Empty;
/// <summary>
/// 返回的String类型数据 只有ResultType.String时才返回数据其它情况为空
/// </summary>
public string Html
{
get { return _html; }
set { _html = value; }
}
/// <summary>
/// 返回的Byte数组 只有ResultType.Byte时才返回数据其它情况为空
/// </summary>
public byte[] ResultByte { get; set; }
/// <summary>
/// header对象
/// </summary>
public WebHeaderCollection Header { get; set; }
/// <summary>
/// 返回状态说明
/// </summary>
public string StatusDescription { get; set; }
/// <summary>
/// 返回状态码,默认为OK
/// </summary>
public HttpStatusCode StatusCode { get; set; }
/// <summary>
/// 最后访问的URl
/// </summary>
public string ResponseUri { get; set; }
/// <summary>
/// 获取重定向的URl
/// </summary>
public string RedirectUrl
{
get
{
try
{
if (Header != null && Header.Count > 0)
{
if (Header.AllKeys.Any(k => k.ToLower().Contains("location")))
{
string baseurl = Header["location"].ToString().Trim();
string locationurl = baseurl.ToLower();
if (!string.IsNullOrWhiteSpace(locationurl))
{
bool b = locationurl.StartsWith("http://") || locationurl.StartsWith("https://");
if (!b)
{
baseurl = new Uri(new Uri(ResponseUri), baseurl).AbsoluteUri;
}
}
return baseurl;
}
}
}
catch { }
return string.Empty;
}
}
}
/// <summary>
/// 返回类型
/// </summary>
public enum ResultType
{
/// <summary>
/// 表示只返回字符串 只有Html有数据
/// </summary>
String,
/// <summary>
/// 表示返回字符串和字节流 ResultByte和Html都有数据返回
/// </summary>
Byte
}
/// <summary>
/// Post的数据格式默认为string
/// </summary>
public enum PostDataType
{
/// <summary>
/// 字符串类型这时编码Encoding可不设置
/// </summary>
String,
/// <summary>
/// Byte类型需要设置PostdataByte参数的值编码Encoding可设置为空
/// </summary>
Byte,
/// <summary>
/// 传文件Postdata必须设置为文件的绝对路径必须设置Encoding的值
/// </summary>
FilePath
}
/// <summary>
/// Cookie返回类型
/// </summary>
public enum ResultCookieType
{
/// <summary>
/// 只返回字符串类型的Cookie
/// </summary>
String,
/// <summary>
/// CookieCollection格式的Cookie集合同时也返回String类型的cookie
/// </summary>
CookieCollection
}
#endregion
}

View File

@ -0,0 +1,16 @@
@{
Layout = null;
}
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div>
@Html.Action("Index")
</div>
</body>
</html>

View File

@ -110,12 +110,9 @@ namespace JXCMS.Core.Db
jsonObject.Add("Db", JObject.FromObject(dbConfig)); jsonObject.Add("Db", JObject.FromObject(dbConfig));
} }
using (var writer = new StreamWriter(filePath)) using var writer = new StreamWriter(filePath);
using (JsonTextWriter jsonwriter = new JsonTextWriter(writer)) using JsonTextWriter jsonWriter = new JsonTextWriter(writer) {Formatting = Formatting.Indented};
{ jsonObject.WriteTo(jsonWriter);
jsonwriter.Formatting = Formatting.Indented;
jsonObject.WriteTo(jsonwriter);
}
} }
} }
} }

View File

@ -0,0 +1,99 @@
using Microsoft.AspNetCore.Html;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Infrastructure;
using Microsoft.AspNetCore.Routing;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.IO;
using System.Threading.Tasks;
namespace Microsoft.AspNetCore.Mvc.Rendering
{
public static class HtmlHelperViewExtensions
{
public static IHtmlContent Action(this IHtmlHelper helper, string action, object parameters = null)
{
var controller = (string)helper.ViewContext.RouteData.Values["controller"];
return Action(helper, action, controller, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, object parameters = null)
{
var area = (string)helper.ViewContext.RouteData.Values["area"];
return Action(helper, action, controller, area, parameters);
}
public static IHtmlContent Action(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
if (action == null)
throw new ArgumentNullException("action");
if (controller == null)
throw new ArgumentNullException("controller");
var task = RenderActionAsync(helper, action, controller, area, parameters);
return task.Result;
}
private static async Task<IHtmlContent> RenderActionAsync(this IHtmlHelper helper, string action, string controller, string area, object parameters = null)
{
// fetching required services for invocation
var serviceProvider = helper.ViewContext.HttpContext.RequestServices;
var actionContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IActionContextAccessor>();
var httpContextAccessor = helper.ViewContext.HttpContext.RequestServices.GetRequiredService<IHttpContextAccessor>();
var actionSelector = serviceProvider.GetRequiredService<IActionSelector>();
// creating new action invocation context
var routeData = new RouteData();
foreach (var router in helper.ViewContext.RouteData.Routers)
{
routeData.PushState(router, null, null);
}
routeData.PushState(null, new RouteValueDictionary(new { controller = controller, action = action, area = area }), null);
routeData.PushState(null, new RouteValueDictionary(parameters ?? new { }), null);
//get the actiondescriptor
RouteContext routeContext = new RouteContext(helper.ViewContext.HttpContext) { RouteData = routeData };
var candidates = actionSelector.SelectCandidates(routeContext);
var actionDescriptor = actionSelector.SelectBestCandidate(routeContext, candidates);
var originalActionContext = actionContextAccessor.ActionContext;
var originalhttpContext = httpContextAccessor.HttpContext;
try
{
var newHttpContext = serviceProvider.GetRequiredService<IHttpContextFactory>().Create(helper.ViewContext.HttpContext.Features);
if (newHttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
newHttpContext.Items.Remove(typeof(IUrlHelper));
}
newHttpContext.Response.Body = new MemoryStream();
var actionContext = new ActionContext(newHttpContext, routeData, actionDescriptor);
actionContextAccessor.ActionContext = actionContext;
var invoker = serviceProvider.GetRequiredService<IActionInvokerFactory>().CreateInvoker(actionContext);
await invoker.InvokeAsync();
newHttpContext.Response.Body.Position = 0;
using (var reader = new StreamReader(newHttpContext.Response.Body))
{
return new HtmlString(reader.ReadToEnd());
}
}
catch (Exception ex)
{
return new HtmlString(ex.Message);
}
finally
{
actionContextAccessor.ActionContext = originalActionContext;
httpContextAccessor.HttpContext = originalhttpContext;
if (helper.ViewContext.HttpContext.Items.ContainsKey(typeof(IUrlHelper)))
{
helper.ViewContext.HttpContext.Items.Remove(typeof(IUrlHelper));
}
}
}
}
}

View File

@ -1,4 +1,6 @@
namespace JXCMS.Core.Extensions using System.Text;
namespace JXCMS.Core.Extensions
{ {
public static class StringExtension public static class StringExtension
{ {
@ -6,5 +8,18 @@
{ {
return string.IsNullOrEmpty(str); return string.IsNullOrEmpty(str);
} }
public static string InsertMultipleString(this string str, string insertStr, int count)
{
StringBuilder returnValue = new StringBuilder();
for (int i = 0; i < count; i++)
{
returnValue.Append(insertStr);
}
returnValue.Append(str);
return returnValue.ToString();
}
} }
} }

View File

@ -1,4 +1,4 @@
<Project Sdk="Microsoft.NET.Sdk.Web"> <Project Sdk="Microsoft.NET.Sdk.Web">
<PropertyGroup> <PropertyGroup>
<TargetFramework>netcoreapp3.1</TargetFramework> <TargetFramework>netcoreapp3.1</TargetFramework>
@ -11,12 +11,12 @@
<PackageReference Include="BouncyCastle" Version="1.8.5" /> <PackageReference Include="BouncyCastle" Version="1.8.5" />
<PackageReference Include="DeviceDetector.NET" Version="4.1.0" /> <PackageReference Include="DeviceDetector.NET" Version="4.1.0" />
<PackageReference Include="DotnetSpider" Version="4.0.7" /> <PackageReference Include="DotnetSpider" Version="4.0.7" />
<PackageReference Include="FreeSql.Extensions.BaseEntity" Version="0.11.20" /> <PackageReference Include="FreeSql.Extensions.BaseEntity" Version="1.2.0-preview1" />
<PackageReference Include="FreeSql.Provider.MySql" Version="0.11.20" /> <PackageReference Include="FreeSql.Provider.MySql" Version="1.2.0-preview1" />
<PackageReference Include="FreeSql.Provider.Oracle" Version="0.11.20" /> <PackageReference Include="FreeSql.Provider.Oracle" Version="1.2.0-preview1" />
<PackageReference Include="FreeSql.Provider.PostgreSQL" Version="0.11.20" /> <PackageReference Include="FreeSql.Provider.PostgreSQL" Version="1.2.0-preview1" />
<PackageReference Include="FreeSql.Provider.Sqlite" Version="0.11.20" /> <PackageReference Include="FreeSql.Provider.Sqlite" Version="1.2.0-preview1" />
<PackageReference Include="FreeSql.Provider.SqlServer" Version="0.11.20" /> <PackageReference Include="FreeSql.Provider.SqlServer" Version="1.2.0-preview1" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="0.3.1" /> <PackageReference Include="McMaster.NETCore.Plugins" Version="0.3.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" /> <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
<PackageReference Include="Quartz" Version="3.0.7" /> <PackageReference Include="Quartz" Version="3.0.7" />

View File

@ -53,5 +53,41 @@ namespace JXCMS.Core.TimingTask
return await _scheduler.DeleteJobs(jobKeys); return await _scheduler.DeleteJobs(jobKeys);
} }
/// <summary>
/// Corn表达式的运行时间
/// </summary>
/// <param name="cron">表达式</param>
/// <param name="times">计算次数</param>
/// <param name="startTime">开始时间</param>
/// <returns></returns>
public static string GetCronSchedule(String cron, int times, DateTimeOffset startTime)
{
String timeSchedule = "";
if (!CronExpression.IsValidExpression(cron))
{
return "Cron表达式不合法!";
}
try
{
ITrigger trigger1 = TriggerBuilder.Create()
.WithCronSchedule(cron)
.StartNow()
.Build();
for (int i = 0; i < times; i++)
{
DateTimeOffset? s = trigger1.GetFireTimeAfter(startTime);
DateTime? time = s?.LocalDateTime;
timeSchedule = time?.ToString("F");
}
}
catch (System.Exception e)
{
timeSchedule = "未知时间";
}
return timeSchedule;
}
} }
} }

View File

@ -0,0 +1,15 @@
using Microsoft.Extensions.Configuration;
namespace JXCMS.Core.Utils
{
public class ConfigHelper
{
public static IConfiguration Configs { get; set; }
public static string GetValue(string key)
{
var res = Configs.GetSection(key).Value;
return res;
}
}
}