[DEV] basic usable version with use condition (webm or mkv(h264+opus))

This commit is contained in:
Edouard DUPIN 2019-12-27 23:22:28 +01:00
parent 4c226971f5
commit 682b36c167
33 changed files with 848 additions and 92 deletions

51
.gitignore vendored Normal file
View File

@ -0,0 +1,51 @@
# See http://help.github.com/ignore-files/ for more about ignoring files.
# compiled output
/dist
/dist-server
/tmp
/out-tsc
# dependencies
applicationFront/node_modules
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
# misc
/.sass-cache
/connect.lock
/coverage
/libpeerconnection.log
npm-debug.log
yarn-error.log
testem.log
/typings
# e2e
/e2e/*.js
/e2e/*.map
# System Files
.DS_Store
Thumbs.db
backPY/env
*.pyc
__pycache__

9
back/.gitignore vendored Normal file
View File

@ -0,0 +1,9 @@
config.*
config.env
.env
config
data
cache
__pycache__
*.pyc

View File

@ -1 +0,0 @@
[]

View File

@ -1 +0,0 @@
[]

View File

@ -1,43 +0,0 @@
[
{
"id": 0,
"name": "Documentary",
"description": "Documentary (annimals, space, earth...)"
},{
"id": 1,
"name": "Movie",
"description": "Movie with real humans (film)"
},{
"id": 2,
"name": "Annimation",
"description": "Annimation movies (film)"
},{
"id": 3,
"name": "Short Films",
"description": "Small movies (less 2 minutes)"
},{
"id": 4,
"name": "tv show",
"description": "Tv show form old peoples"
}, {
"id": 5,
"name": "Anniation tv show",
"description": "Tv show form young peoples"
}, {
"id": 6,
"name": "Theater",
"description": "recorder theater pices"
}, {
"id": 7,
"name": "One man show",
"description": "Recorded stand up"
}, {
"id": 8,
"name": "Concert",
"description": "Recorded concert"
}, {
"id": 9,
"name": "Opera",
"description": "Recorded Opera"
}
]

View File

@ -1 +0,0 @@
[]

View File

@ -117,20 +117,66 @@ def add(_app, _name_api):
return response.stream(streaming, content_type='application/json') return response.stream(streaming, content_type='application/json')
@elem_blueprint.get('/' + _name_api + '/<id:string>', strict_slashes=True) @elem_blueprint.get('/' + _name_api + '/<id:string>', strict_slashes=True)
@doc.summary("Show resources") @doc.summary("get a specific resource")
@doc.description("Display a listing of the resource.") @doc.description("Get a resource with all the needed datas ... It permeit seek for video stream.")
@doc.produces(content_type='application/json') @doc.produces(content_type='application/json')
async def retrive(request, id): async def retrive(request, id):
debug.warning("Request data media 2 : " + id);
if id[-4:] == ".mp4":
id = id[:-4]
if id[-4:] == ".mkv":
id = id[:-4]
if id[-4:] == ".avi":
id = id[:-4]
if id[-4:] == ".ts":
id = id[:-3]
filename = os.path.join(_app.config['REST_MEDIA_DATA'], id) filename = os.path.join(_app.config['REST_MEDIA_DATA'], id)
if os.path.isfile(filename) == True: headers = {
file_stat = await async_os.stat(filename) 'Content-Type': 'video/x-matroska',
headers = {"Content-Length": str(file_stat.st_size)} 'Accept-Ranges': 'Accept-Ranges: bytes'
return await file_stream( }
filename, try:
headers=headers, with open(filename, 'rb') as fff:
chunked=False, range_start = None
) range_end = None
raise ServerError("No data found", status_code=404) fff.seek(0, 2)
file_length = fff.tell()
fff.seek(0)
try:
range_ = '0-' + str(file_length)
if 'range' in request.headers:
range_ = request.headers['range'].split('=')[1]
range_split = range_.split('-')
range_start = int(range_split[0])
fff.seek(range_start)
range_end = int(range_split[1])
except ValueError:
pass
if range_start and range_start != 0:
if not range_end:
range_end = file_length
read_length = range_end - range_start
else:
range_start = 0
read_length = file_length
range_end = file_length
fff.seek(range_start)
headers['Content-Length'] = read_length
headers['Content-Range'] = f'bytes {range_start}-{range_end-1}/{file_length}'
async def streaming_fn(response):
with open(filename, 'rb') as fff:
chunk_size = 8192
current_offset = range_start
while (current_offset < file_length):
chunk_start = current_offset
fff.seek(current_offset)
chunk_data = fff.read(min(chunk_size, file_length - current_offset))
current_offset += chunk_size
await response.write(chunk_data)
return response.stream(streaming_fn, headers=headers, status=206)
except FileNotFoundError:
return response.HTTPResponse(status=404)
_app.blueprint(elem_blueprint) _app.blueprint(elem_blueprint)

View File

@ -75,6 +75,8 @@ def add(_app, _name_api):
description = [str, type(None)] description = [str, type(None)]
# creating time # creating time
create_date = str create_date = str
# date of the video
date = [int, type(None)]
# number of second # number of second
time = [int, type(None)] time = [int, type(None)]
@ -89,6 +91,8 @@ def add(_app, _name_api):
description = str description = str
# creating time # creating time
create_date = str create_date = str
# date of the video
date = str
# number of second # number of second
time = int time = int
@ -108,10 +112,10 @@ def add(_app, _name_api):
for type_key in ["sha512","type_id","name"]: for type_key in ["sha512","type_id","name"]:
if type_key not in request.json.keys(): if type_key not in request.json.keys():
raise ServerError("Bad Request: Missing Key '" + type_key + "'", status_code=400) raise ServerError("Bad Request: Missing Key '" + type_key + "'", status_code=400)
for type_key in ["date"]: for type_key in ["create_date"]:
if type_key in request.json.keys(): if type_key in request.json.keys():
raise ServerError("Forbidden: Must not be set Key '" + type_key + "'", status_code=403) raise ServerError("Forbidden: Must not be set Key '" + type_key + "'", status_code=403)
for type_key in ["saison_id","episode","time","group_id","description"]: for type_key in ["saison_id","episode","date","time","group_id","description"]:
if type_key not in request.json.keys(): if type_key not in request.json.keys():
request.json[type_key] = None request.json[type_key] = None
request.json["create_date"] = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' request.json["create_date"] = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z'

View File

@ -53,7 +53,7 @@ app.config['API_LICENSE_NAME'] = 'MPL 2.0'
app.config['API_LICENSE_URL'] = 'https://www.mozilla.org/en-US/MPL/2.0/' app.config['API_LICENSE_URL'] = 'https://www.mozilla.org/en-US/MPL/2.0/'
app.config['schemes'] = ['http', 'https'] app.config['schemes'] = ['http', 'https']
if "REST_TMP_DATA" not in app.config.keys(): if "REST_TMP_DATA" not in app.config.keys():
app.config['REST_TMP_DATA'] = "tmp" app.config['REST_TMP_DATA'] = os.path.join("data", "tmp")
if "REST_MEDIA_DATA" not in app.config.keys(): if "REST_MEDIA_DATA" not in app.config.keys():
app.config['REST_MEDIA_DATA'] = os.path.join("data", "media") app.config['REST_MEDIA_DATA'] = os.path.join("data", "media")
if "REST_DATA" not in app.config.keys(): if "REST_DATA" not in app.config.keys():
@ -67,10 +67,58 @@ app.blueprint(openapi_blueprint)
app.blueprint(swagger_blueprint) app.blueprint(swagger_blueprint)
def add_interface(_name): default_values_type = [
data_global_elements.add_interface(_name, data_interface.DataInterface(_name, os.path.join(tools.get_run_path(), app.config['REST_DATA'], "bdd_" + _name + ".json"))) {
"id": 0,
"name": "Documentary",
"description": "Documentary (annimals, space, earth...)"
},{
"id": 1,
"name": "Movie",
"description": "Movie with real humans (film)"
},{
"id": 2,
"name": "Annimation",
"description": "Annimation movies (film)"
},{
"id": 3,
"name": "Short Films",
"description": "Small movies (less 2 minutes)"
},{
"id": 4,
"name": "tv show",
"description": "Tv show form old peoples"
}, {
"id": 5,
"name": "Anniation tv show",
"description": "Tv show form young peoples"
}, {
"id": 6,
"name": "Theater",
"description": "recorder theater pices"
}, {
"id": 7,
"name": "One man show",
"description": "Recorded stand up"
}, {
"id": 8,
"name": "Concert",
"description": "Recorded concert"
}, {
"id": 9,
"name": "Opera",
"description": "Recorded Opera"
}
]
add_interface(data_global_elements.API_TYPE)
def add_interface(_name, _default_value = None):
interface = data_interface.DataInterface(_name, os.path.join(tools.get_run_path(), app.config['REST_DATA'], "bdd_" + _name + ".json"))
if _default_value != None:
interface.reset_with_value(_default_value);
data_global_elements.add_interface(_name, interface)
add_interface(data_global_elements.API_TYPE, default_values_type)
add_interface(data_global_elements.API_GROUP) add_interface(data_global_elements.API_GROUP)
add_interface(data_global_elements.API_SAISON) add_interface(data_global_elements.API_SAISON)
add_interface(data_global_elements.API_VIDEO) add_interface(data_global_elements.API_VIDEO)

View File

@ -26,7 +26,6 @@ class DataInterface():
self.last_id = 0 self.last_id = 0
if tools.exist(self.file) == False: if tools.exist(self.file) == False:
self.mark_to_store() self.mark_to_store()
self.last_id = random.randint(20, 100)
else: else:
data = tools.file_read_data(self.file) data = tools.file_read_data(self.file)
self.bdd = json.loads(data) self.bdd = json.loads(data)
@ -35,6 +34,12 @@ class DataInterface():
def set_data_model(self, _data_model): def set_data_model(self, _data_model):
self.model = _data_model self.model = _data_model
def reset_with_value(self, _data):
self.bdd = _data
self.last_id = 0
self.mark_to_store()
self.upgrade_global_bdd_id();
def check_with_model(self, _data): def check_with_model(self, _data):
if self.model == None: if self.model == None:
return True return True
@ -78,11 +83,15 @@ class DataInterface():
return True return True
def upgrade_global_bdd_id(self): def upgrade_global_bdd_id(self):
self.last_id = 0
for elem in self.bdd: for elem in self.bdd:
if 'id' not in elem.keys(): if 'id' not in elem.keys():
continue continue
if elem["id"] >= self.last_id: if elem["id"] >= self.last_id:
self.last_id = elem["id"] + 1 self.last_id = elem["id"] + 1
# start at a random value permit to vaidate the basis inctance test
if self.last_id == 0:
self.last_id = random.randint(20, 100)
def get_table_index(self, _id): def get_table_index(self, _id):
id_in_bdd = 0 id_in_bdd = 0

View File

@ -126,7 +126,7 @@ def push_video_file(_path, _basic_key={}):
return True return True
debug.info("Add media : '" + _path + "'") debug.info("Add media : '" + _path + "'")
if file_extension[1:] not in ["avi", "mkv", "mov", "mp4", "ts"] \ if file_extension[1:] not in ["webm", "avi", "mkv", "mov", "mp4", "ts"] \
and file_name not in ["cover_1.jpg","cover_1.png", "cover_1.till", "cover_1.bmp", "cover_1.tga"]: and file_name not in ["cover_1.jpg","cover_1.png", "cover_1.till", "cover_1.bmp", "cover_1.tga"]:
debug.warning("Not send file : " + _path + " Not manage file_extension... " + file_extension) debug.warning("Not send file : " + _path + " Not manage file_extension... " + file_extension)
return False return False

63
front/.angular-cli.json Normal file
View File

@ -0,0 +1,63 @@
{
"$schema": "./node_modules/@angular/cli/lib/config/schema.json",
"project": {
"name": "no-comment"
},
"apps": [
{
"root": "src",
"outDir": "dist",
"assets": [
"assets",
"favicon.ico"
],
"index": "index.html",
"main": "main.ts",
"polyfills": "polyfills.ts",
"test": "test.ts",
"tsconfig": "tsconfig.app.json",
"testTsconfig": "tsconfig.spec.json",
"prefix": "app",
"styles": [
"styles.less",
"theme.color.blue.less",
"theme.checkbox.less",
"theme.modal.less"
],
"scripts": [],
"environmentSource": "environments/environment.ts",
"environments": {
"dev": "environments/environment.ts",
"prod": "environments/environment.prod.ts"
}
}
],
"e2e": {
"protractor": {
"config": "./protractor.conf.js"
}
},
"lint": [
{
"project": "src/tsconfig.app.json",
"exclude": "**/node_modules/**"
},
{
"project": "src/tsconfig.spec.json",
"exclude": "**/node_modules/**"
},
{
"project": "e2e/tsconfig.e2e.json",
"exclude": "**/node_modules/**"
}
],
"test": {
"karma": {
"config": "./karma.conf.js"
}
},
"defaults": {
"styleExt": "less",
"component": {}
}
}

13
front/.editorconfig Normal file
View File

@ -0,0 +1,13 @@
# Editor configuration, see http://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 2
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false

View File

@ -10,6 +10,9 @@ import { ModuleWithProviders } from '@angular/core';
import { HomeComponent } from './home/home.component'; import { HomeComponent } from './home/home.component';
import { TypeDetailComponent } from './type-detail/type-detail.component'; import { TypeDetailComponent } from './type-detail/type-detail.component';
import { GroupDetailComponent } from './group-detail/group-detail.component';
import { SaisonDetailComponent } from './saison-detail/saison-detail.component';
import { VideoDetailComponent } from './video-detail/video-detail.component';
import { LoginComponent } from './login/login.component'; import { LoginComponent } from './login/login.component';
import { SignUpComponent } from './sign-up/sign-up.component'; import { SignUpComponent } from './sign-up/sign-up.component';
import { SettingsComponent } from './settings/settings.component'; import { SettingsComponent } from './settings/settings.component';
@ -20,6 +23,9 @@ const routes: Routes = [
{ path: '', redirectTo: '/home', pathMatch: 'full'}, { path: '', redirectTo: '/home', pathMatch: 'full'},
{ path: 'home', component: HomeComponent }, { path: 'home', component: HomeComponent },
{ path: 'type/:id', component: TypeDetailComponent }, { path: 'type/:id', component: TypeDetailComponent },
{ path: 'group/:id', component: GroupDetailComponent },
{ path: 'saison/:id', component: SaisonDetailComponent },
{ path: 'video/:id', component: VideoDetailComponent },
{ path: 'login', component: LoginComponent }, { path: 'login', component: LoginComponent },
{ path: 'signup', component: SignUpComponent }, { path: 'signup', component: SignUpComponent },
{ path: 'settings', component: SettingsComponent }, { path: 'settings', component: SettingsComponent },

View File

@ -24,9 +24,13 @@ import { SignUpComponent } from './sign-up/sign-up.component';
import { ValidateEmailComponent } from './validate-email/validate-email.component'; import { ValidateEmailComponent } from './validate-email/validate-email.component';
import { HomeComponent } from './home/home.component'; import { HomeComponent } from './home/home.component';
import { TypeDetailComponent } from './type-detail/type-detail.component'; import { TypeDetailComponent } from './type-detail/type-detail.component';
import { GroupDetailComponent } from './group-detail/group-detail.component';
import { SaisonDetailComponent } from './saison-detail/saison-detail.component';
import { VideoDetailComponent } from './video-detail/video-detail.component';
import { SettingsComponent } from './settings/settings.component'; import { SettingsComponent } from './settings/settings.component';
import { ErrorViewerComponent } from './error-viewer/error-viewer.component'; import { ErrorViewerComponent } from './error-viewer/error-viewer.component';
import { ErrorComponent } from './error/error.component'; import { ErrorComponent } from './error/error.component';
import { CookiesService } from './cookies.service'; import { CookiesService } from './cookies.service';
import { HttpWrapperService } from './http-wrapper.service'; import { HttpWrapperService } from './http-wrapper.service';
import { UserService } from './user.service'; import { UserService } from './user.service';
@ -52,6 +56,9 @@ import { AppComponent } from './app.component';
ValidateEmailComponent, ValidateEmailComponent,
HomeComponent, HomeComponent,
TypeDetailComponent, TypeDetailComponent,
GroupDetailComponent,
SaisonDetailComponent,
VideoDetailComponent,
SettingsComponent, SettingsComponent,
ErrorViewerComponent, ErrorViewerComponent,
ErrorComponent ErrorComponent

View File

@ -1,3 +1,11 @@
<div> <div>
{{name}} {{name}}<br/>
{{sha512}}<br/>
<!--<div [disabled]="display_video=='false' ? true : null">
aaa sdfsdfsdfsdf aaa
</div>
-->
<div *ngIf="video_enable">
</div>
</div> </div>

View File

@ -21,6 +21,7 @@ import { VideoService } from '../video.service';
export class ElementVideoComponent implements OnInit { export class ElementVideoComponent implements OnInit {
// input parameters // input parameters
@Input() id_video:number = -1; @Input() id_video:number = -1;
@Input() display_video:boolean = false;
error:string = "" error:string = ""
@ -33,6 +34,8 @@ export class ElementVideoComponent implements OnInit {
time:number = undefined time:number = undefined
type_id:number = undefined type_id:number = undefined
generated_name:string = "" generated_name:string = ""
video_source:string = ""
video_enable:boolean = false;
constructor(private router: Router, constructor(private router: Router,
private videoService: VideoService) { private videoService: VideoService) {
@ -40,28 +43,40 @@ export class ElementVideoComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.name = "ll " + this.id_video this.name = "ll " + this.id_video
let self = this; let self = this;
console.log("get parameter id: " + this.id_video); console.log("get video id: " + this.id_video);
this.videoService.get(this.id_video) this.videoService.get(this.id_video)
.then(function(response) { .then(function(response) {
console.log("get response of video : " + JSON.stringify(response, null, 2));
self.error = ""; self.error = "";
self.name = response.name self.name = response.name;
self.description = response.description self.description = response.description;
self.episode = response.episode self.episode = response.episode;
self.group_id = response.group_id self.group_id = response.group_id;
self.saison_id = response.saison_id self.saison_id = response.saison_id;
self.sha512 = response.sha512 self.sha512 = response.sha512;
self.time = response.time self.time = response.time;
self.generated_name = response.generated_name self.generated_name = response.generated_name;
if (self.sha512 != "") {
self.video_source = "http://localhost:15080/data/" + self.sha512 + ".mp4";
self.video_enable = true;
} else {
self.video_source = "";
self.video_enable = false;
}
console.log("101010 " + self.video_enable + " " + self.video_source);
//console.log("set transformed : " + JSON.stringify(self, null, 2));
}).catch(function(response) { }).catch(function(response) {
self.error = "Can not get the data"; self.error = "Can not get the data";
self.name = "" self.name = "";
self.description = "" self.description = "";
self.episode = undefined self.episode = undefined;
self.group_id = undefined self.group_id = undefined;
self.saison_id = undefined self.saison_id = undefined;
self.sha512 = "" self.sha512 = "";
self.time = undefined self.time = undefined;
self.generated_name = "" self.generated_name = "";
self.video_source = "";
self.video_enable = false;
}); });
} }
} }

View File

@ -0,0 +1,12 @@
<div class="main-reduce">
<div class="fill-all">
<div *ngFor="let data of saisons" class="item" (click)="onSelectSaison(data)">
<app-element-saison [id_saison]="data"></app-element-saison>
</div>
</div>
<div class="fill-all">
<div *ngFor="let data of videos" class="item item-video" (click)="onSelectVideo(data)">
<app-element-video [id_video]="data"></app-element-video>
</div>
</div>
</div>

View File

@ -0,0 +1,62 @@
.fill-all{
width:100%;
height:100%;
margin:0;
padding:0;
border:0;
background-color:#0F0;
}
.item {
font-size: 20px;
height: 21%;
width: 23%;
margin: 1%;
padding: 0;
overflow: hidden;
//box-shadow: 0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.6);
line-height: normal;
border: none;
font-family: "Roboto","Helvetica","Arial",sans-serif;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0;
will-change: box-shadow;
outline: none;
cursor: pointer;
text-decoration: none;
text-align: center;
vertical-align: middle;
transition-duration: 0.4s;
float:left;
display:block;
h1 {
font-size: 24px;
}
&:hover {
background-color: #F00;
}
.material-icons {
vertical-align: middle;
}
.material-icons {
position: absolute;
top: 50%;
left: 50%;
transform: ~"translate(-12px,-12px)";
line-height: 24px;
width: 24px;
}
}
.item-video {
&:hover {
background-color: #0F0;
}
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { GroupDetailComponent } from './group-detail.component';
describe('GroupDetailComponent', () => {
let component: GroupDetailComponent;
let fixture: ComponentFixture<GroupDetailComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ GroupDetailComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(GroupDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,64 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { Location } from '@angular/common';
import { fadeInAnimation } from '../_animations/index';
import { GroupService } from '../group.service';
@Component({
selector: 'app-group-detail',
templateUrl: './group-detail.component.html',
styleUrls: ['./group-detail.component.less'],
animations: [fadeInAnimation],
host: { '[@fadeInAnimation]': '' }
})
export class GroupDetailComponent implements OnInit {
id_group = -1;
saisons_error = "";
saisons = [];
videos_error = "";
videos = [];
constructor(private route: ActivatedRoute,
private router: Router,
private locate: Location,
private groupService: GroupService) {
}
ngOnInit() {
this.id_group = parseInt(this.route.snapshot.paramMap.get('id'));
let self = this;
console.log("get parameter id: " + this.id_group);
this.groupService.getSaison(this.id_group)
.then(function(response) {
self.saisons_error = "";
self.saisons = response
}).catch(function(response) {
self.saisons_error = "Can not get the list of saison in this group";
self.saisons = []
});
this.groupService.getVideoNoSaison(this.id_group)
.then(function(response) {
self.videos_error = "";
self.videos = response
}).catch(function(response) {
self.videos_error = "Can not get the List of video without saison";
self.videos = []
});
}
onSelectSaison(_idSelected: number):void {
this.router.navigate(['saison/' + _idSelected ]);
}
onSelectVideo(_idSelected: number):void {
this.router.navigate(['video/' + _idSelected ]);
}
}

View File

@ -10,10 +10,13 @@ export class GroupService {
console.log("Start GroupService"); console.log("Start GroupService");
} }
get(_id:number):any { get_specific(_id:number, _subElement:string = ""):any {
console.log("Get All data from types"); console.log("Get All data from types");
const httpOption = { 'Content-Type': 'application/json' }; const httpOption = { 'Content-Type': 'application/json' };
let url = "group/" + _id; let url = "group/" + _id;
if (_subElement != "") {
url += "/" + _subElement;
}
console.log("call GET " + url); console.log("call GET " + url);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -33,7 +36,21 @@ export class GroupService {
} }
}); });
}); });
};
get(_id:number):any {
return this.get_specific(_id);
};
getVideo(_id:number):any {
return this.get_specific(_id, "video");
};
getSaison(_id:number):any {
return this.get_specific(_id, "saison");
};
getVideoNoSaison(_id:number):any {
return this.get_specific(_id, "video_no_saison");
}; };
} }

View File

@ -0,0 +1,7 @@
<div class="main-reduce">
<div class="fill-all">
<div *ngFor="let data of videos" class="item item-video" (click)="onSelectVideo(data)">
<app-element-video [id_video]="data"></app-element-video>
</div>
</div>
</div>

View File

@ -0,0 +1,62 @@
.fill-all{
width:100%;
height:100%;
margin:0;
padding:0;
border:0;
background-color:#0F0;
}
.item {
font-size: 20px;
height: 21%;
width: 23%;
margin: 1%;
padding: 0;
overflow: hidden;
//box-shadow: 0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.6);
line-height: normal;
border: none;
font-family: "Roboto","Helvetica","Arial",sans-serif;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0;
will-change: box-shadow;
outline: none;
cursor: pointer;
text-decoration: none;
text-align: center;
vertical-align: middle;
transition-duration: 0.4s;
float:left;
display:block;
h1 {
font-size: 24px;
}
&:hover {
background-color: #F00;
}
.material-icons {
vertical-align: middle;
}
.material-icons {
position: absolute;
top: 50%;
left: 50%;
transform: ~"translate(-12px,-12px)";
line-height: 24px;
width: 24px;
}
}
.item-video {
&:hover {
background-color: #0F0;
}
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { SaisonDetailComponent } from './saison-detail.component';
describe('SaisonDetailComponent', () => {
let component: SaisonDetailComponent;
let fixture: ComponentFixture<SaisonDetailComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ SaisonDetailComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(SaisonDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,51 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { Location } from '@angular/common';
import { fadeInAnimation } from '../_animations/index';
import { SaisonService } from '../saison.service';
@Component({
selector: 'app-saison-detail',
templateUrl: './saison-detail.component.html',
styleUrls: ['./saison-detail.component.less'],
animations: [fadeInAnimation],
host: { '[@fadeInAnimation]': '' }
})
export class SaisonDetailComponent implements OnInit {
id_saison = -1;
videos_error = "";
videos = [];
constructor(private route: ActivatedRoute,
private router: Router,
private locate: Location,
private saisonService: SaisonService) {
}
ngOnInit() {
this.id_saison = parseInt(this.route.snapshot.paramMap.get('id'));
let self = this;
console.log("get parameter id: " + this.id_saison);
this.saisonService.getVideo(this.id_saison)
.then(function(response) {
self.videos_error = "";
self.videos = response
}).catch(function(response) {
self.videos_error = "Can not get the List of video without saison";
self.videos = []
});
}
onSelectVideo(_idSelected: number):void {
this.router.navigate(['video/' + _idSelected ]);
}
}

View File

@ -10,10 +10,13 @@ export class SaisonService {
console.log("Start SaisonService"); console.log("Start SaisonService");
} }
get(_id:number):any { get_specific(_id:number, _subElement:string = ""):any {
console.log("Get All data from types"); console.log("Get All data from types");
const httpOption = { 'Content-Type': 'application/json' }; const httpOption = { 'Content-Type': 'application/json' };
let url = "saison/" + _id; let url = "saison/" + _id;
if (_subElement != "") {
url += "/" + _subElement;
}
console.log("call GET " + url); console.log("call GET " + url);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -33,7 +36,15 @@ export class SaisonService {
} }
}); });
}); });
}; };
get(_id:number):any {
return this.get_specific(_id);
};
getVideo(_id:number):any {
return this.get_specific(_id, "video");
};
} }

View File

@ -22,9 +22,9 @@ import { TypeService } from '../type.service';
export class TypeDetailComponent implements OnInit { export class TypeDetailComponent implements OnInit {
type_id = -1; type_id = -1;
groups_error = ""; groups_error = "";
groups = [{name:"group1"}, {name:"group2"}, {name:"group3"}]; groups = [];
videos_error = ""; videos_error = "";
videos = [{name:"video1"}, {name:"video2"}, {name:"video3"}]; videos = [];
constructor(private route: ActivatedRoute, constructor(private route: ActivatedRoute,
private router: Router, private router: Router,
private locate: Location, private locate: Location,

View File

@ -0,0 +1,13 @@
<div class="main-reduce">
<div class="fill-all">
<h1>{{name}}</h1>
<p>{{description}}</p>
<div *ngIf="episode!=null">
<p>Episode <b>{{episode}}</b></p>
</div>
<p>generated_name <b>{{generated_name}}</b></p>
<video src="{{video_source}}" controls width="50%">
<!--<p>Your browser des not suport HTML5 video player. download video: <a href="{{video_source}}>link here</a>.</p>-->
</video>
</div>

View File

@ -0,0 +1,62 @@
.fill-all{
width:100%;
height:100%;
margin:0;
padding:0;
border:0;
background-color:#0F0;
}
.item {
font-size: 20px;
height: 21%;
width: 23%;
margin: 1%;
padding: 0;
overflow: hidden;
//box-shadow: 0 1px 1.5px 0 rgba(0,0,0,.12),0 1px 1px 0 rgba(0,0,0,.24);
box-shadow: 0px 2px 4px 0 rgba(0, 0, 0, 0.6);
line-height: normal;
border: none;
font-family: "Roboto","Helvetica","Arial",sans-serif;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0;
will-change: box-shadow;
outline: none;
cursor: pointer;
text-decoration: none;
text-align: center;
vertical-align: middle;
transition-duration: 0.4s;
float:left;
display:block;
h1 {
font-size: 24px;
}
&:hover {
background-color: #F00;
}
.material-icons {
vertical-align: middle;
}
.material-icons {
position: absolute;
top: 50%;
left: 50%;
transform: ~"translate(-12px,-12px)";
line-height: 24px;
width: 24px;
}
}
.item-video {
&:hover {
background-color: #0F0;
}
}

View File

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { VideoDetailComponent } from './video-detail.component';
describe('VideoDetailComponent', () => {
let component: VideoDetailComponent;
let fixture: ComponentFixture<VideoDetailComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ VideoDetailComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(VideoDetailComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

View File

@ -0,0 +1,81 @@
/** @file
* @author Edouard DUPIN
* @copyright 2018, Edouard DUPIN, all right reserved
* @license PROPRIETARY (see license file)
*/
import { Component, OnInit } from '@angular/core';
import { Router, ActivatedRoute, ParamMap } from '@angular/router';
import { Location } from '@angular/common';
import { fadeInAnimation } from '../_animations/index';
import { VideoService } from '../video.service';
@Component({
selector: 'app-video-detail',
templateUrl: './video-detail.component.html',
styleUrls: ['./video-detail.component.less'],
animations: [fadeInAnimation],
host: { '[@fadeInAnimation]': '' }
})
export class VideoDetailComponent implements OnInit {
id_video:number = -1;
error:string = ""
name:string = ""
description:string = ""
episode:number = undefined
group_id:number = undefined
saison_id:number = undefined
sha512:string = ""
time:number = undefined
type_id:number = undefined
generated_name:string = ""
video_source:string = ""
constructor(private route: ActivatedRoute,
private router: Router,
private locate: Location,
private videoService: VideoService) {
}
ngOnInit() {
this.id_video = parseInt(this.route.snapshot.paramMap.get('id'));
let self = this;
this.videoService.get(this.id_video)
.then(function(response) {
console.log("get response of video : " + JSON.stringify(response, null, 2));
self.error = "";
self.name = response.name;
self.description = response.description;
self.episode = response.episode;
self.group_id = response.group_id;
self.saison_id = response.saison_id;
self.sha512 = response.sha512;
self.time = response.time;
self.generated_name = response.generated_name;
if (self.sha512 != "") {
self.video_source = "http://localhost:15080/data/" + self.sha512 + ".mp4";
} else {
self.video_source = "";
}
console.log("display source " + self.video_source);
//console.log("set transformed : " + JSON.stringify(self, null, 2));
}).catch(function(response) {
self.error = "Can not get the data";
self.name = "";
self.description = "";
self.episode = undefined;
self.group_id = undefined;
self.saison_id = undefined;
self.sha512 = "";
self.time = undefined;
self.generated_name = "";
self.video_source = "";
});
}
}

View File

@ -10,9 +10,13 @@ export class VideoService {
console.log("Start VideoService"); console.log("Start VideoService");
} }
get(_id:number):any { get_specific(_id:number, _subElement:string = ""):any {
console.log("Get All data from types");
const httpOption = { 'Content-Type': 'application/json' }; const httpOption = { 'Content-Type': 'application/json' };
let url = "video/" + _id; let url = "video/" + _id;
if (_subElement != "") {
url += "/" + _subElement;
}
console.log("call GET " + url); console.log("call GET " + url);
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
@ -20,7 +24,7 @@ export class VideoService {
.then(function(response: any) { .then(function(response: any) {
if (response.status == 200) { if (response.status == 200) {
resolve(response.data); resolve(response.data);
console.log("get data from type : " + response.data); console.log("get data from response : " + JSON.stringify(response.data, null, 2));
return; return;
} }
reject("An error occured"); reject("An error occured");
@ -32,7 +36,9 @@ export class VideoService {
} }
}); });
}); });
};
get(_id:number):any {
return this.get_specific(_id);
}; };
} }