diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9799319 --- /dev/null +++ b/.gitignore @@ -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__ + diff --git a/back/.gitignore b/back/.gitignore new file mode 100644 index 0000000..acc3a63 --- /dev/null +++ b/back/.gitignore @@ -0,0 +1,9 @@ +config.* +config.env +.env +config +data +cache + +__pycache__ +*.pyc diff --git a/back/data_base/bdd_group.json b/back/data_base/bdd_group.json deleted file mode 100644 index 0637a08..0000000 --- a/back/data_base/bdd_group.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/back/data_base/bdd_saison.json b/back/data_base/bdd_saison.json deleted file mode 100644 index 0637a08..0000000 --- a/back/data_base/bdd_saison.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/back/data_base/bdd_type.json b/back/data_base/bdd_type.json deleted file mode 100644 index 0245c90..0000000 --- a/back/data_base/bdd_type.json +++ /dev/null @@ -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" - } -] \ No newline at end of file diff --git a/back/data_base/bdd_video.json b/back/data_base/bdd_video.json deleted file mode 100644 index 0637a08..0000000 --- a/back/data_base/bdd_video.json +++ /dev/null @@ -1 +0,0 @@ -[] \ No newline at end of file diff --git a/back/src/api/data.py b/back/src/api/data.py index 9ae41ea..39e5255 100644 --- a/back/src/api/data.py +++ b/back/src/api/data.py @@ -117,20 +117,66 @@ def add(_app, _name_api): return response.stream(streaming, content_type='application/json') @elem_blueprint.get('/' + _name_api + '/', strict_slashes=True) - @doc.summary("Show resources") - @doc.description("Display a listing of the resource.") + @doc.summary("get a specific resource") + @doc.description("Get a resource with all the needed datas ... It permeit seek for video stream.") @doc.produces(content_type='application/json') 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) - if os.path.isfile(filename) == True: - file_stat = await async_os.stat(filename) - headers = {"Content-Length": str(file_stat.st_size)} - return await file_stream( - filename, - headers=headers, - chunked=False, - ) - raise ServerError("No data found", status_code=404) + headers = { + 'Content-Type': 'video/x-matroska', + 'Accept-Ranges': 'Accept-Ranges: bytes' + } + try: + with open(filename, 'rb') as fff: + range_start = None + range_end = None + 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) diff --git a/back/src/api/video.py b/back/src/api/video.py index 94d7182..b6b635b 100644 --- a/back/src/api/video.py +++ b/back/src/api/video.py @@ -75,6 +75,8 @@ def add(_app, _name_api): description = [str, type(None)] # creating time create_date = str + # date of the video + date = [int, type(None)] # number of second time = [int, type(None)] @@ -89,6 +91,8 @@ def add(_app, _name_api): description = str # creating time create_date = str + # date of the video + date = str # number of second time = int @@ -108,10 +112,10 @@ def add(_app, _name_api): for type_key in ["sha512","type_id","name"]: if type_key not in request.json.keys(): 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(): 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(): request.json[type_key] = None request.json["create_date"] = datetime.datetime.utcnow().strftime('%Y-%m-%dT%H:%M:%S.%f')[:-3] + 'Z' diff --git a/back/src/app_video.py b/back/src/app_video.py index 6936a7d..3a1b0ca 100755 --- a/back/src/app_video.py +++ b/back/src/app_video.py @@ -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['schemes'] = ['http', 'https'] 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(): app.config['REST_MEDIA_DATA'] = os.path.join("data", "media") if "REST_DATA" not in app.config.keys(): @@ -67,10 +67,58 @@ app.blueprint(openapi_blueprint) app.blueprint(swagger_blueprint) -def add_interface(_name): - data_global_elements.add_interface(_name, data_interface.DataInterface(_name, os.path.join(tools.get_run_path(), app.config['REST_DATA'], "bdd_" + _name + ".json"))) +default_values_type = [ + { + "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_SAISON) add_interface(data_global_elements.API_VIDEO) diff --git a/back/src/data_interface.py b/back/src/data_interface.py index 64f4820..c82d216 100644 --- a/back/src/data_interface.py +++ b/back/src/data_interface.py @@ -26,7 +26,6 @@ class DataInterface(): self.last_id = 0 if tools.exist(self.file) == False: self.mark_to_store() - self.last_id = random.randint(20, 100) else: data = tools.file_read_data(self.file) self.bdd = json.loads(data) @@ -35,6 +34,12 @@ class DataInterface(): def set_data_model(self, _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): if self.model == None: return True @@ -78,11 +83,15 @@ class DataInterface(): return True def upgrade_global_bdd_id(self): + self.last_id = 0 for elem in self.bdd: if 'id' not in elem.keys(): continue if elem["id"] >= self.last_id: 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): id_in_bdd = 0 diff --git a/back/tools/sendLocalData.py b/back/tools/sendLocalData.py index 10e1178..4d46779 100755 --- a/back/tools/sendLocalData.py +++ b/back/tools/sendLocalData.py @@ -126,7 +126,7 @@ def push_video_file(_path, _basic_key={}): return True 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"]: debug.warning("Not send file : " + _path + " Not manage file_extension... " + file_extension) return False diff --git a/front/.angular-cli.json b/front/.angular-cli.json new file mode 100644 index 0000000..3d080fc --- /dev/null +++ b/front/.angular-cli.json @@ -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": {} + } +} diff --git a/front/.editorconfig b/front/.editorconfig new file mode 100644 index 0000000..6e87a00 --- /dev/null +++ b/front/.editorconfig @@ -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 diff --git a/front/src/app/app-routing.module.ts b/front/src/app/app-routing.module.ts index 2ef1f92..a04b7e1 100644 --- a/front/src/app/app-routing.module.ts +++ b/front/src/app/app-routing.module.ts @@ -10,6 +10,9 @@ import { ModuleWithProviders } from '@angular/core'; import { HomeComponent } from './home/home.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 { SignUpComponent } from './sign-up/sign-up.component'; import { SettingsComponent } from './settings/settings.component'; @@ -20,6 +23,9 @@ const routes: Routes = [ { path: '', redirectTo: '/home', pathMatch: 'full'}, { path: 'home', component: HomeComponent }, { 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: 'signup', component: SignUpComponent }, { path: 'settings', component: SettingsComponent }, diff --git a/front/src/app/app.module.ts b/front/src/app/app.module.ts index cbf9c31..6fdce0f 100644 --- a/front/src/app/app.module.ts +++ b/front/src/app/app.module.ts @@ -24,9 +24,13 @@ import { SignUpComponent } from './sign-up/sign-up.component'; import { ValidateEmailComponent } from './validate-email/validate-email.component'; import { HomeComponent } from './home/home.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 { ErrorViewerComponent } from './error-viewer/error-viewer.component'; import { ErrorComponent } from './error/error.component'; + import { CookiesService } from './cookies.service'; import { HttpWrapperService } from './http-wrapper.service'; import { UserService } from './user.service'; @@ -52,6 +56,9 @@ import { AppComponent } from './app.component'; ValidateEmailComponent, HomeComponent, TypeDetailComponent, + GroupDetailComponent, + SaisonDetailComponent, + VideoDetailComponent, SettingsComponent, ErrorViewerComponent, ErrorComponent diff --git a/front/src/app/element-video/element-video.component.html b/front/src/app/element-video/element-video.component.html index 34ede39..87159da 100644 --- a/front/src/app/element-video/element-video.component.html +++ b/front/src/app/element-video/element-video.component.html @@ -1,3 +1,11 @@
- {{name}} + {{name}}
+ {{sha512}}
+ + +
+
\ No newline at end of file diff --git a/front/src/app/element-video/element-video.component.ts b/front/src/app/element-video/element-video.component.ts index 4a19785..93faf34 100644 --- a/front/src/app/element-video/element-video.component.ts +++ b/front/src/app/element-video/element-video.component.ts @@ -21,6 +21,7 @@ import { VideoService } from '../video.service'; export class ElementVideoComponent implements OnInit { // input parameters @Input() id_video:number = -1; + @Input() display_video:boolean = false; error:string = "" @@ -33,6 +34,8 @@ export class ElementVideoComponent implements OnInit { time:number = undefined type_id:number = undefined generated_name:string = "" + video_source:string = "" + video_enable:boolean = false; constructor(private router: Router, private videoService: VideoService) { @@ -40,28 +43,40 @@ export class ElementVideoComponent implements OnInit { ngOnInit() { this.name = "ll " + this.id_video 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) .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 + 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"; + 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) { 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.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 = ""; + self.video_enable = false; }); } } \ No newline at end of file diff --git a/front/src/app/group-detail/group-detail.component.html b/front/src/app/group-detail/group-detail.component.html new file mode 100644 index 0000000..5ee53c0 --- /dev/null +++ b/front/src/app/group-detail/group-detail.component.html @@ -0,0 +1,12 @@ +
+
+
+ +
+
+
+
+ +
+
+
\ No newline at end of file diff --git a/front/src/app/group-detail/group-detail.component.less b/front/src/app/group-detail/group-detail.component.less new file mode 100644 index 0000000..09160ef --- /dev/null +++ b/front/src/app/group-detail/group-detail.component.less @@ -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; + } +} + diff --git a/front/src/app/group-detail/group-detail.component.spec.ts b/front/src/app/group-detail/group-detail.component.spec.ts new file mode 100644 index 0000000..e35edd7 --- /dev/null +++ b/front/src/app/group-detail/group-detail.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ GroupDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(GroupDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front/src/app/group-detail/group-detail.component.ts b/front/src/app/group-detail/group-detail.component.ts new file mode 100644 index 0000000..7ad401b --- /dev/null +++ b/front/src/app/group-detail/group-detail.component.ts @@ -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 ]); + } + +} diff --git a/front/src/app/group.service.ts b/front/src/app/group.service.ts index 5bda6d1..f1bd226 100644 --- a/front/src/app/group.service.ts +++ b/front/src/app/group.service.ts @@ -10,10 +10,13 @@ export class GroupService { console.log("Start GroupService"); } - get(_id:number):any { + get_specific(_id:number, _subElement:string = ""):any { console.log("Get All data from types"); const httpOption = { 'Content-Type': 'application/json' }; let url = "group/" + _id; + if (_subElement != "") { + url += "/" + _subElement; + } console.log("call GET " + url); 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"); }; } diff --git a/front/src/app/saison-detail/saison-detail.component.html b/front/src/app/saison-detail/saison-detail.component.html new file mode 100644 index 0000000..a125f51 --- /dev/null +++ b/front/src/app/saison-detail/saison-detail.component.html @@ -0,0 +1,7 @@ +
+
+
+ +
+
+
\ No newline at end of file diff --git a/front/src/app/saison-detail/saison-detail.component.less b/front/src/app/saison-detail/saison-detail.component.less new file mode 100644 index 0000000..09160ef --- /dev/null +++ b/front/src/app/saison-detail/saison-detail.component.less @@ -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; + } +} + diff --git a/front/src/app/saison-detail/saison-detail.component.spec.ts b/front/src/app/saison-detail/saison-detail.component.spec.ts new file mode 100644 index 0000000..e475174 --- /dev/null +++ b/front/src/app/saison-detail/saison-detail.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ SaisonDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(SaisonDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front/src/app/saison-detail/saison-detail.component.ts b/front/src/app/saison-detail/saison-detail.component.ts new file mode 100644 index 0000000..0c95c41 --- /dev/null +++ b/front/src/app/saison-detail/saison-detail.component.ts @@ -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 ]); + } + +} diff --git a/front/src/app/saison.service.ts b/front/src/app/saison.service.ts index 824a4c7..16c3b78 100644 --- a/front/src/app/saison.service.ts +++ b/front/src/app/saison.service.ts @@ -10,10 +10,13 @@ export class SaisonService { console.log("Start SaisonService"); } - get(_id:number):any { + get_specific(_id:number, _subElement:string = ""):any { console.log("Get All data from types"); const httpOption = { 'Content-Type': 'application/json' }; let url = "saison/" + _id; + if (_subElement != "") { + url += "/" + _subElement; + } console.log("call GET " + url); 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"); + }; + } diff --git a/front/src/app/type-detail/type-detail.component.ts b/front/src/app/type-detail/type-detail.component.ts index 12b56c8..bb24a7e 100644 --- a/front/src/app/type-detail/type-detail.component.ts +++ b/front/src/app/type-detail/type-detail.component.ts @@ -22,9 +22,9 @@ import { TypeService } from '../type.service'; export class TypeDetailComponent implements OnInit { type_id = -1; groups_error = ""; - groups = [{name:"group1"}, {name:"group2"}, {name:"group3"}]; + groups = []; videos_error = ""; - videos = [{name:"video1"}, {name:"video2"}, {name:"video3"}]; + videos = []; constructor(private route: ActivatedRoute, private router: Router, private locate: Location, diff --git a/front/src/app/video-detail/video-detail.component.html b/front/src/app/video-detail/video-detail.component.html new file mode 100644 index 0000000..a57823d --- /dev/null +++ b/front/src/app/video-detail/video-detail.component.html @@ -0,0 +1,13 @@ +
+
+

{{name}}

+

{{description}}

+ +
+

Episode {{episode}}

+
+

generated_name {{generated_name}}

+ +
\ No newline at end of file diff --git a/front/src/app/video-detail/video-detail.component.less b/front/src/app/video-detail/video-detail.component.less new file mode 100644 index 0000000..09160ef --- /dev/null +++ b/front/src/app/video-detail/video-detail.component.less @@ -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; + } +} + diff --git a/front/src/app/video-detail/video-detail.component.spec.ts b/front/src/app/video-detail/video-detail.component.spec.ts new file mode 100644 index 0000000..2ff474f --- /dev/null +++ b/front/src/app/video-detail/video-detail.component.spec.ts @@ -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; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ VideoDetailComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(VideoDetailComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/front/src/app/video-detail/video-detail.component.ts b/front/src/app/video-detail/video-detail.component.ts new file mode 100644 index 0000000..d9061c0 --- /dev/null +++ b/front/src/app/video-detail/video-detail.component.ts @@ -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 = ""; + }); + } + +} diff --git a/front/src/app/video.service.ts b/front/src/app/video.service.ts index c2ec374..9a805c9 100644 --- a/front/src/app/video.service.ts +++ b/front/src/app/video.service.ts @@ -10,9 +10,13 @@ export class 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' }; let url = "video/" + _id; + if (_subElement != "") { + url += "/" + _subElement; + } console.log("call GET " + url); return new Promise((resolve, reject) => { @@ -20,7 +24,7 @@ export class VideoService { .then(function(response: any) { if (response.status == 200) { resolve(response.data); - console.log("get data from type : " + response.data); + console.log("get data from response : " + JSON.stringify(response.data, null, 2)); return; } reject("An error occured"); @@ -32,7 +36,9 @@ export class VideoService { } }); }); - + }; + get(_id:number):any { + return this.get_specific(_id); }; }