feat(collections): insert movie into collections

This commit is contained in:
OldHawk
2017-10-24 17:33:25 +08:00
parent 4366947153
commit c53e73fa21
12 changed files with 384 additions and 136 deletions

View File

@@ -164,16 +164,22 @@
@media (max-width: @screen-xs-max) {
min-width: ~"calc(100% - 50px)";
}
padding: 30px 15px;
.maker-form {
margin-top: 20px;
input {
width: 100%;
}
textarea {
.maker-popup {
background-color: #fdfdfd;
width: 100%;
height: ~"calc(100% - 50px)";
overflow: auto;
padding: 30px 15px;
.maker-form {
margin-top: 20px;
width: 100%;
height: 150px;
input {
width: 100%;
}
textarea {
margin-top: 20px;
width: 100%;
height: 150px;
}
}
}
.bottom-control {

View File

@@ -8,20 +8,29 @@
@media (max-width: @screen-xs-max) {
min-width: ~"calc(100% - 50px)";
}
padding: 30px 15px;
.collection-form {
margin-top: 20px;
input {
width: 100%;
}
textarea {
.collection-popup {
background-color: #fdfdfd;
width: 100%;
height: ~"calc(100% - 50px)";
overflow: auto;
padding: 30px 15px;
.collection-form {
margin-top: 20px;
width: 100%;
height: 200px;
}
img {
margin-top: 10px;
width: 100%;
input {
width: 100%;
}
textarea {
margin-top: 20px;
width: 100%;
height: 200px;
}
img {
margin-top: 10px;
width: 100%;
}
.text-muted {
color: #aaa;
}
}
}
.bottom-control {
@@ -34,7 +43,6 @@
bottom: 0;
padding: 8px 10px;
}
}
.collections-list {
@@ -50,58 +58,69 @@
}
}
}
.collection-item {
cursor: pointer;
position: relative;
margin: 20px 0 0 0;
overflow: hidden;
border-radius: 8px;
&:hover {
img {
/* csslint ignore:start */
transform: scale(2);
/* csslint ignore:end */
}
}
img {
width: 100%;
transition-property: transform, opacity;
transition-duration: 1s;
transition-timing-function: ease;
border: solid 1px #666;
border-radius: 8px;
}
.item-info {
color: #999;
position: absolute;
.collection-items {
text-align: -webkit-center;
.collection-item {
cursor: pointer;
position: relative;
margin: 20px 0 0 0;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 30px 20px;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 8px;
.name {
margin-bottom: 2px;
font-size: 1.6em;
max-width: 400px;
text-align: -webkit-center;
&:hover {
img {
/* csslint ignore:start */
transform: scale(2);
/* csslint ignore:end */
}
}
.collection-data {
position: absolute;
left: 0;
right: 0;
bottom: 30px;
}
}
&:hover {
.fa {
color: @mt-base-color !important;
img {
width: 100%;
transition-property: transform, opacity;
transition-duration: 1s;
transition-timing-function: ease;
border: solid 1px #666;
border-radius: 8px;
}
.item-info {
color: #fff;
color: #ddd;
position: absolute;
overflow: hidden;
top: 0;
bottom: 0;
left: 0;
right: 0;
padding: 30px 20px;
background-color: rgba(0, 0, 0, 0.6);
border-radius: 8px;
.name {
margin-bottom: 2px;
font-size: 1.6em;
text-shadow: 0 0 0.1em #000,-0 -0 0.1em #000;
}
.collection-data {
position: absolute;
left: 0;
right: 0;
bottom: 30px;
strong {
text-shadow: 0 0 0.1em #000,-0 -0 0.1em #000;
}
}
}
&:hover {
.fa {
color: @mt-base-color !important;
}
.item-info {
background-color: rgba(0, 0, 0, 0.3);
color: #fff;
}
}
}
}

View File

@@ -29,6 +29,22 @@
id: '@id',
language: '@language'
}
},
insertIntoCollection: {
method: 'PUT',
url: '/api/collections/:collectionId/insert/:torrentId',
params: {
collectionId: '@collectionId',
torrentId: '@torrentId'
}
},
removeFromCollection: {
method: 'PUT',
url: '/api/collections/:collectionId/remove/:torrentId',
params: {
collectionId: '@collectionId',
torrentId: '@torrentId'
}
}
});

View File

@@ -27,31 +27,26 @@
<div class="row">
<div class="col-sm-6 col-md-4" ng-repeat="m in vm.pagedItems">
<div class="collection-item"
ui-sref="collections.view({ collectionId: m._id })">
<img ng-src="{{vm.tmdbConfig.backdropImgBaseUrl_780 + m.backdrop_path}}">
<div class="collection-items">
<div class="collection-item"
ui-sref="collections.view({ collectionId: m._id })">
<img ng-src="{{vm.tmdbConfig.backdropImgBaseUrl_780 + m.backdrop_path}}">
<div class="item-info text-center">
<div class="name">{{m.name}}</div>
<div class="item-info text-center">
<div class="name">{{m.name}}</div>
<div class="row margin-top-40 collection-data">
<div class="col-xs-4 col-small-padding text-right">
<!--<i class="fa fa-user-circle-o text-info"> {{m.members.length}}</i>-->
</div>
<div class="col-xs-4 col-small-padding text-center">
<i class="fa fa-upload text-info"> {{m.torrents.length}}</i>
</div>
<div class="col-xs-4 col-small-padding text-left">
<!--<i class="fa fa-star-half-o text-info"> {{m.vote_average}}/{{m.vote_count}} {{ 'TMDB_FIELDS.VOTE_UNIT' | translate}}</i>-->
<div class="row margin-top-40 collection-data">
<div class="col-xs-6 col-small-padding text-center">
<i class="fa fa-list text-info">
<strong> {{'COLLECTIONS.FILES_NUMBERS' | translate}}: {{m.torrents.length}}</strong></i>
</div>
<div class="col-xs-6 col-small-padding text-center">
<i class="fa fa-star-half-o text-info">
<strong> {{'COLLECTIONS.VOTE_AVERAGE' | translate}}: {{m.torrents.length}}</strong></i>
</div>
</div>
</div>
</div>
<!--<span>{{'ABOUT.GROUP_FOUNDER' | translate}}</span>-->
<!--<span info-class="h5" user-info="m.user" info-name></span>-->
<!--<span to-class="h5" message-to="m.user" to-class="message-to-icon"></span>-->
</div>
</div>
</div>

View File

@@ -128,6 +128,49 @@ exports.update = function (req, res) {
});
};
/**
* insertIntoCollection
* @param req
* @param res
*/
exports.insertIntoCollection = function (req, res) {
var coll = req.collection;
var torrent = req.torrent;
coll.torrents.push(torrent);
coll.save(function (err) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(coll);
}
});
};
/**
* removeFromCollection
* @param req
* @param res
*/
exports.removeFromCollection = function (req, res) {
var coll = req.collection;
var torrent = req.torrent;
coll.update({
$pull: {torrents: torrent._id}
}).exec(function (err, res) {
if (err) {
return res.status(422).send({
message: errorHandler.getErrorMessage(err)
});
} else {
res.json(res);
}
});
};
/**
* Delete an collection
*/
@@ -151,16 +194,21 @@ exports.delete = function (req, res) {
exports.list = function (req, res) {
var skip = 0;
var limit = 0;
var tmdb_id = 0;
var keysA = [];
var condition = {};
if (req.body.skip !== undefined) {
if (req.query.skip !== undefined) {
skip = parseInt(req.query.skip, 10);
}
if (req.body.limit !== undefined) {
if (req.query.limit !== undefined) {
limit = parseInt(req.query.limit, 10);
}
if (req.query.tmdb_id !== undefined) {
tmdb_id = parseInt(req.query.tmdb_id, 10);
}
if (req.query.keys && req.query.keys.length > 0) {
var keysS = req.query.keys + '';
var keysT = keysS.split(' ');
@@ -171,6 +219,10 @@ exports.list = function (req, res) {
});
}
if (tmdb_id !== 0) {
condition.tmdb_id = tmdb_id;
}
if (keysA.length > 0) {
condition.$or = [
{name: {'$all': keysA}},

View File

@@ -20,7 +20,9 @@ exports.invokeRolesPolicies = function () {
{resources: '/api/search/collection/:language', permissions: '*'},
{resources: '/api/collectionInfo/:id/:language', permissions: '*'},
{resources: '/api/collections', permissions: '*'},
{resources: '/api/collections/:collectionId', permissions: '*'}
{resources: '/api/collections/:collectionId', permissions: '*'},
{resources: '/api/collections/:collectionId/insert/:torrentId', permissions: '*'},
{resources: '/api/collections/:collectionId/remove/:torrentId', permissions: '*'}
]
},
{

View File

@@ -22,5 +22,10 @@ module.exports = function (app) {
.put(collections.update)
.delete(collections.delete);
app.route('/api/collections/:collectionId/insert/:torrentId').all(collectionsPolicy.isAllowed)
.put(collections.insertIntoCollection);
app.route('/api/collections/:collectionId/remove/:torrentId').all(collectionsPolicy.isAllowed)
.put(collections.removeFromCollection);
app.param('collectionId', collections.collectionByID);
};

View File

@@ -511,7 +511,16 @@
COLL_LIST: 'Movie Collections List',
CREATE_SUCCESSFULLY: 'Create movie collection successfully',
CREATE_FAILED: 'Create movie collection failed',
LIST_ERROR: 'Movie collections list error'
FILES_NUMBERS: 'Torrents',
VOTE_AVERAGE: 'Vote average',
LIST_ERROR: 'Movie collections list error',
INSERT_INTO: 'Insert Movie Into Collection for - {{cid}}',
TORRENT_INTO: 'Torrent info',
SELECT_INFO: 'Select a collection to insert',
INSERT_SUCCESSFULLY: 'Insert move into collection successfully',
INSERT_FAILED: 'Insert move into collection FAILED',
ALREADY_IN: '(Already In)',
NO_COLLECTION: 'No collection founded can insert movie, you can create first, then insert this movie into it.'
},
//user settings

View File

@@ -511,7 +511,16 @@
COLL_LIST: '电影系列清单',
CREATE_SUCCESSFULLY: '电影系列创建成功',
CREATE_FAILED: '电影系列创建失败',
LIST_ERROR: '电影系列清单列出失败'
FILES_NUMBERS: '种子数',
VOTE_AVERAGE: '平均得分',
LIST_ERROR: '电影系列清单列出失败',
INSERT_INTO: '添加电影到系列 - {{cid}}',
TORRENT_INTO: '种子信息',
SELECT_INFO: '选择要加入的电影系列',
INSERT_SUCCESSFULLY: '添加电影到系列成功',
INSERT_FAILED: '添加电影到系列失败',
ALREADY_IN: '(已加入)',
NO_COLLECTION: '没有可加入的系列, 如果还没有创建,你可以先创建一个系列, 再执行加入操作.'
},
//user settings

View File

@@ -227,7 +227,7 @@
status: 'loading'
};
SideOverlay.open(evt, 'collectionsSlide');
SideOverlay.open(evt, 'collectionsCreateSlide');
CollectionsService.getCollectionInfo({
id: vm.collection.tmdb_id,
@@ -250,14 +250,14 @@
* hideCollectionPopup
*/
vm.hideCollectionPopup = function () {
SideOverlay.close(null, 'collectionsSlide');
SideOverlay.close(null, 'collectionsCreateSlide');
};
/**
* saveCollection
*/
vm.saveCollection = function () {
SideOverlay.close(null, 'collectionsSlide');
SideOverlay.close(null, 'collectionsCreateSlide');
var coll = new CollectionsService(vm.collection);
coll.$save(function (res) {
@@ -268,6 +268,87 @@
};
/**
* insertIntoCollection
* @param evt
*/
vm.insertIntoCollection = function (evt) {
vm.collectionsItems = undefined;
vm.collectionTorrent = {
tmdb_id: vm.torrentLocalInfo.resource_detail_info.belongs_to_collection.id || 0,
id: vm.torrentLocalInfo._id,
cid: undefined,
title: vm.TGI.getTorrentTitle(vm.torrentLocalInfo),
file: vm.torrentLocalInfo.torrent_filename,
status_msg: 'loading movie collection list ...',
status: 'loading'
};
SideOverlay.open(evt, 'collectionsInsertSlide');
CollectionsService.get({
tmdb_id: vm.collectionTorrent.tmdb_id
}, function (res) {
vm.collectionsItems = res.rows;
vm.collectionTorrent.status = 'ok';
mtDebug.info(res);
}, function (err) {
vm.collectionTorrent.status = 'error';
vm.collectionTorrent.status_msg = 'Error: get collection items error';
});
};
/**
* hideCollectionInsertPopup
*/
vm.hideCollectionInsertPopup = function () {
SideOverlay.close(null, 'collectionsInsertSlide');
};
/**
* saveInsertCollection
*/
vm.saveInsertCollection = function () {
SideOverlay.close(null, 'collectionsInsertSlide');
var sc = undefined;
angular.forEach(vm.collectionsItems, function (c) {
if (c._id === vm.collectionTorrent.cid) {
sc = c;
}
});
CollectionsService.insertIntoCollection({
collectionId: vm.collectionTorrent.cid,
torrentId: vm.collectionTorrent.id
}, function (res) {
mtDebug.info(res);
NotifycationService.showSuccessNotify('COLLECTIONS.INSERT_SUCCESSFULLY');
}, function (res) {
NotifycationService.showErrorNotify(res.data.message, 'COLLECTIONS.CREATE_FAILED');
});
};
/**
* isAlreadyIn
* @param c
* @returns {boolean}
*/
vm.isAlreadyIn = function (c) {
var result = false;
angular.forEach(c.torrents, function (t) {
if (vm.torrentLocalInfo._id === t._id) {
result = true;
}
});
return result;
};
/**
* onRadioTagClicked
* @param event

View File

@@ -428,38 +428,41 @@
</div>
</div>
<!-- =================================================================
side-overlay collections
side-overlay collections create
================================================================== -->
<div id="collectionsSlide" side-overlay="right" side-class="collections-side-overlay" side-close-on-esc side-modal>
<h4 translate="COLLECTIONS.FORM_FOR" translate-values="{cid: vm.torrentLocalInfo.resource_detail_info.belongs_to_collection.id}"></h4>
<div id="collectionsCreateSlide" side-overlay="right" side-class="collections-side-overlay" side-close-on-esc side-modal>
<div class="collection-popup">
<legend class="h4"
translate="COLLECTIONS.FORM_FOR" translate-values="{cid: vm.torrentLocalInfo.resource_detail_info.belongs_to_collection.id}">
</legend>
<div class="collection-form">
<input type="text" class="form-control" id="name" placeholder="{{'COLLECTIONS.FORM_NAME' | translate}}"
ng-model="vm.collection.name" autofocus>
<div class="collection-form">
<input type="text" class="form-control" id="name" placeholder="{{'COLLECTIONS.FORM_NAME' | translate}}"
ng-model="vm.collection.name" autofocus>
<textarea class="form-control" id="overview" placeholder="{{'COLLECTIONS.FORM_DESC' | translate}}"
ng-model="vm.collection.overview"></textarea>
<div class="margin-top-10" style="display: table;">
<a class="message-extra" href="https://guides.github.com/features/mastering-markdown/" target="_blank"
data-ga-click="Markdown Toolbar, click, help">
<svg aria-hidden="true" height="16" version="1.1"
viewBox="0 0 16 16" width="16">
<path fill-rule="evenodd"
d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"/>
</svg>
{{ 'MARKDOWN_LINK' | translate }}
</a>
</div>
<div class="margin-top-10" style="display: table;">
<a class="message-extra" href="https://guides.github.com/features/mastering-markdown/" target="_blank"
data-ga-click="Markdown Toolbar, click, help">
<svg aria-hidden="true" height="16" version="1.1"
viewBox="0 0 16 16" width="16">
<path fill-rule="evenodd"
d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"/>
</svg>
{{ 'MARKDOWN_LINK' | translate }}
</a>
</div>
<img class="img-thumbnail" ng-if="vm.collection.backdrop_path"
ng-src="{{vm.tmdbConfig.backdropImgBaseUrl_780 + vm.collection.backdrop_path}}"
on-error-src="http://image.tmdb.org/t/p/w1280/5pAGnkFYSsFJ99ZxDIYnhQbQFXs.jpg">
<img class="img-thumbnail" ng-if="vm.collection.backdrop_path"
ng-src="{{vm.tmdbConfig.backdropImgBaseUrl_780 + vm.collection.backdrop_path}}"
on-error-src="http://image.tmdb.org/t/p/w1280/5pAGnkFYSsFJ99ZxDIYnhQbQFXs.jpg">
<div class="margin-top-20 h5" ng-class="vm.collection.status == 'loading' ? 'text-success' : 'text-danger'"
ng-if="vm.collection.status != 'ok'">{{vm.collection.status_msg}}
<div class="margin-top-20 h5" ng-class="vm.collection.status == 'loading' ? 'text-success' : 'text-danger'"
ng-if="vm.collection.status != 'ok'">{{vm.collection.status_msg}}
</div>
</div>
</div>
@@ -472,6 +475,53 @@
</div>
</div>
<!-- =================================================================
side-overlay collections insert
================================================================== -->
<div id="collectionsInsertSlide" side-overlay="right" side-class="collections-side-overlay" side-close-on-esc side-modal>
<div class="collection-popup">
<legend class="h4"
translate="COLLECTIONS.INSERT_INTO" translate-values="{cid: vm.torrentLocalInfo.resource_detail_info.belongs_to_collection.id}">
</legend>
<div class="collection-form">
<div class="h5 margin-bottom-5">{{'COLLECTIONS.TORRENT_INTO' | translate}}:</div>
<input type="text" class="form-control margin-top-10" id="tid"
ng-model="vm.collectionTorrent.id" autofocus>
<input type="text" class="form-control margin-top-10" id="ttitle"
ng-model="vm.collectionTorrent.title" autofocus>
<input type="text" class="form-control margin-top-10" id="tfile"
ng-model="vm.collectionTorrent.file" autofocus>
<div ng-if="vm.collectionsItems.length<=0">
<div class="h5 text-danger margin-top-40 margin-bottom-5">{{'COLLECTIONS.NO_COLLECTION' | translate}}</div>
</div>
<div ng-if="vm.collectionsItems.length>0">
<div class="h5 margin-top-40 margin-bottom-5">{{'COLLECTIONS.SELECT_INFO' | translate}}:</div>
<div class="radio margin-left-10" ng-repeat="c in vm.collectionsItems">
<label ng-class="{'text-muted': vm.isAlreadyIn(c)}">
<input type="radio" name="n_{{c._id}}" id="i_{{c._id}}" value="{{c._id}}"
ng-model="vm.collectionTorrent.cid" ng-disabled="vm.isAlreadyIn(c)">
{{c.name}} <span ng-if="vm.isAlreadyIn(c)">{{'COLLECTIONS.ALREADY_IN' | translate}}</span>
</label>
</div>
</div>
<div class="margin-top-20 h5" ng-class="vm.collectionTorrent.status == 'loading' ? 'text-success' : 'text-danger'"
ng-if="vm.collectionTorrent.status != 'ok'">{{vm.collectionTorrent.status_msg}}
</div>
</div>
</div>
<div class="bottom-control">
<button class="btn btn-success btn-width-100"
ng-disabled="!vm.collectionTorrent.cid"
ng-click="vm.saveInsertCollection();">{{ 'BUTTON_SAVE' | translate }}
</button>
<button class="btn btn-default btn-width-100" ng-click="vm.hideCollectionInsertPopup();">{{ 'BUTTON_CANCEL' | translate }}</button>
</div>
</div>
<!-- =================================================================
torrentInfo.html
================================================================== -->
@@ -937,7 +987,7 @@
ng-click="vm.createCollection($event);">{{ 'ADMIN_COLLECTION_CREATE' | translate}}
</button>
<button class="btn btn-default btn-sm"
ng-click="">{{ 'ADMIN_COLLECTION_ADDINTO' | translate}}
ng-click="vm.insertIntoCollection($event);">{{ 'ADMIN_COLLECTION_ADDINTO' | translate}}
</button>
</dd>
</div>

View File

@@ -249,23 +249,27 @@
</div>
<div id="makerSlide" side-overlay="right" side-class="maker-side-overlay" side-close-on-esc side-modal>
<h4 translate="ABOUT.FORM_MAKER_FOR" translate-values="{name: vm.user.displayName}"></h4>
<div class="maker-form">
<input type="text" class="form-control" id="name" placeholder="{{'ABOUT.FORM_MAKER_NAME' | translate}}"
ng-model="vm.maker.name" autofocus>
<div class="maker-popup">
<h4 translate="ABOUT.FORM_MAKER_FOR" translate-values="{name: vm.user.displayName}"></h4>
<div class="maker-form">
<input type="text" class="form-control" id="name" placeholder="{{'ABOUT.FORM_MAKER_NAME' | translate}}"
ng-model="vm.maker.name" autofocus>
<textarea class="form-control" id="desc" placeholder="{{'ABOUT.FORM_MAKER_DESC' | translate}}"
ng-model="vm.maker.desc"></textarea>
<div class="margin-top-10" style="display: table;">
<a class="message-extra" href="https://guides.github.com/features/mastering-markdown/" target="_blank"
data-ga-click="Markdown Toolbar, click, help">
<svg aria-hidden="true" height="16" version="1.1"
viewBox="0 0 16 16" width="16">
<path fill-rule="evenodd"
d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"/>
</svg>
{{ 'MARKDOWN_LINK' | translate }}
</a>
<div class="margin-top-10" style="display: table;">
<a class="message-extra" href="https://guides.github.com/features/mastering-markdown/" target="_blank"
data-ga-click="Markdown Toolbar, click, help">
<svg aria-hidden="true" height="16" version="1.1"
viewBox="0 0 16 16" width="16">
<path fill-rule="evenodd"
d="M14.85 3H1.15C.52 3 0 3.52 0 4.15v7.69C0 12.48.52 13 1.15 13h13.69c.64 0 1.15-.52 1.15-1.15v-7.7C16 3.52 15.48 3 14.85 3zM9 11H7V8L5.5 9.92 4 8v3H2V5h2l1.5 2L7 5h2v6zm2.99.5L9.5 8H11V5h2v3h1.5l-2.51 3.5z"/>
</svg>
{{ 'MARKDOWN_LINK' | translate }}
</a>
</div>
</div>
</div>