diff options
34 files changed, 509 insertions, 192 deletions
diff --git a/.gitignore b/.gitignore index aaa4db4fb..6c0165c41 100644 --- a/.gitignore +++ b/.gitignore | |||
@@ -10,3 +10,4 @@ test5/ | |||
10 | test6/ | 10 | test6/ |
11 | public/stylesheets/global.css | 11 | public/stylesheets/global.css |
12 | public/stylesheets/vendor | 12 | public/stylesheets/vendor |
13 | uploads | ||
diff --git a/client/.gitignore b/client/.gitignore index 439f0c025..4bb21ebab 100644 --- a/client/.gitignore +++ b/client/.gitignore | |||
@@ -1,5 +1,5 @@ | |||
1 | typings | 1 | typings |
2 | components/**/*.js | 2 | angular/**/*.js |
3 | components/**/*.map | 3 | angular/**/*.map |
4 | angular/**/*.css | ||
4 | stylesheets/index.css | 5 | stylesheets/index.css |
5 | components/**/*.css | ||
diff --git a/client/angular/app/app.component.html b/client/angular/app/app.component.html new file mode 100644 index 000000000..590efa0d6 --- /dev/null +++ b/client/angular/app/app.component.html | |||
@@ -0,0 +1,37 @@ | |||
1 | <div class="container"> | ||
2 | |||
3 | <div class="row"> | ||
4 | |||
5 | <menu class="col-md-2"> | ||
6 | <div id="panel_get_videos" class="panel_button"> | ||
7 | <span class="glyphicon glyphicon-list"></span> | ||
8 | <a [routerLink]="['VideosList']">Get videos</a> | ||
9 | </div> | ||
10 | |||
11 | <div id="panel_upload_video" class="panel_button"> | ||
12 | <span class="glyphicon glyphicon-cloud-upload"></span> | ||
13 | <a [routerLink]="['VideosAdd']">Upload a video</a> | ||
14 | </div> | ||
15 | |||
16 | <div id="panel_make_friends" class="panel_button"> | ||
17 | <span class="glyphicon glyphicon-user"></span> | ||
18 | <a (click)='makeFriends()'>Make friends</a> | ||
19 | </div> | ||
20 | |||
21 | <div id="panel_quit_friends" class="panel_button"> | ||
22 | <span class="glyphicon glyphicon-plane"></span> | ||
23 | <a (click)='quitFriends()'>Quit friends</a> | ||
24 | </div> | ||
25 | </menu> | ||
26 | |||
27 | <div class="col-md-9 router_outler_container"> | ||
28 | <router-outlet></router-outlet> | ||
29 | </div> | ||
30 | |||
31 | </div> | ||
32 | |||
33 | |||
34 | <footer> | ||
35 | PeerTube, CopyLeft 2015-2016 | ||
36 | </footer> | ||
37 | </div> | ||
diff --git a/client/angular/app/app.component.scss b/client/angular/app/app.component.scss new file mode 100644 index 000000000..03ecba8f2 --- /dev/null +++ b/client/angular/app/app.component.scss | |||
@@ -0,0 +1,28 @@ | |||
1 | menu { | ||
2 | min-height: 300px; | ||
3 | height: 100%; | ||
4 | margin-right: 20px; | ||
5 | border-right: 1px solid rgba(0, 0, 0, 0.2); | ||
6 | |||
7 | .panel_button { | ||
8 | margin: 8px; | ||
9 | cursor: pointer; | ||
10 | transition: margin 0.2s; | ||
11 | |||
12 | &:hover { | ||
13 | margin-left: 15px; | ||
14 | } | ||
15 | |||
16 | a { | ||
17 | color: #333333; | ||
18 | } | ||
19 | } | ||
20 | |||
21 | .glyphicon { | ||
22 | margin: 5px; | ||
23 | } | ||
24 | } | ||
25 | |||
26 | footer { | ||
27 | margin-top: 30px; | ||
28 | } | ||
diff --git a/client/angular/app/app.component.ts b/client/angular/app/app.component.ts new file mode 100644 index 000000000..3d41183f2 --- /dev/null +++ b/client/angular/app/app.component.ts | |||
@@ -0,0 +1,63 @@ | |||
1 | import { Component, ElementRef } from 'angular2/core'; | ||
2 | import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; | ||
3 | import {HTTP_PROVIDERS} from 'angular2/http'; | ||
4 | |||
5 | import { VideosAddComponent } from '../videos/components/add/videos-add.component'; | ||
6 | import { VideosListComponent } from '../videos/components/list/videos-list.component'; | ||
7 | import { VideosWatchComponent } from '../videos/components/watch/videos-watch.component'; | ||
8 | import { VideosService } from '../videos/services/videos.service'; | ||
9 | import { FriendsService } from '../friends/services/friends.service'; | ||
10 | |||
11 | @RouteConfig([ | ||
12 | { | ||
13 | path: '/videos/list', | ||
14 | name: 'VideosList', | ||
15 | component: VideosListComponent, | ||
16 | useAsDefault: true | ||
17 | }, | ||
18 | { | ||
19 | path: '/videos/watch/:id', | ||
20 | name: 'VideosWatch', | ||
21 | component: VideosWatchComponent | ||
22 | }, | ||
23 | { | ||
24 | path: '/videos/add', | ||
25 | name: 'VideosAdd', | ||
26 | component: VideosAddComponent | ||
27 | } | ||
28 | ]) | ||
29 | |||
30 | @Component({ | ||
31 | selector: 'my-app', | ||
32 | templateUrl: 'app/angular/app/app.component.html', | ||
33 | styleUrls: [ 'app/angular/app/app.component.css' ], | ||
34 | directives: [ ROUTER_DIRECTIVES ], | ||
35 | providers: [ ROUTER_PROVIDERS, HTTP_PROVIDERS, ElementRef, VideosService, FriendsService ] | ||
36 | }) | ||
37 | |||
38 | export class AppComponent { | ||
39 | constructor(private _friendsService: FriendsService) {} | ||
40 | |||
41 | makeFriends() { | ||
42 | this._friendsService.makeFriends().subscribe( | ||
43 | status => { | ||
44 | if (status === 409) { | ||
45 | alert('Already made friends!'); | ||
46 | } | ||
47 | else { | ||
48 | alert('Made friends!'); | ||
49 | } | ||
50 | }, | ||
51 | error => alert(error) | ||
52 | ) | ||
53 | } | ||
54 | |||
55 | quitFriends() { | ||
56 | this._friendsService.quitFriends().subscribe( | ||
57 | status => { | ||
58 | alert('Quit friends!'); | ||
59 | }, | ||
60 | error => alert(error) | ||
61 | ) | ||
62 | } | ||
63 | } | ||
diff --git a/client/components/bootstrap.ts b/client/angular/bootstrap.ts index d0f524f4a..d0f524f4a 100644 --- a/client/components/bootstrap.ts +++ b/client/angular/bootstrap.ts | |||
diff --git a/client/angular/friends/services/friends.service.ts b/client/angular/friends/services/friends.service.ts new file mode 100644 index 000000000..a34ef0d6f --- /dev/null +++ b/client/angular/friends/services/friends.service.ts | |||
@@ -0,0 +1,27 @@ | |||
1 | import {Injectable} from 'angular2/core'; | ||
2 | import {Http, Response, Headers, RequestOptions} from 'angular2/http'; | ||
3 | import {Observable} from 'rxjs/Rx'; | ||
4 | |||
5 | @Injectable() | ||
6 | export class FriendsService { | ||
7 | private _baseFriendsUrl = '/api/v1/pods/'; | ||
8 | |||
9 | constructor (private http: Http) {} | ||
10 | |||
11 | makeFriends() { | ||
12 | return this.http.get(this._baseFriendsUrl + 'makefriends') | ||
13 | .map(res => <number> res.status) | ||
14 | .catch(this.handleError); | ||
15 | } | ||
16 | |||
17 | quitFriends() { | ||
18 | return this.http.get(this._baseFriendsUrl + 'quitfriends') | ||
19 | .map(res => <number> res.status) | ||
20 | .catch(this.handleError); | ||
21 | } | ||
22 | |||
23 | private handleError (error: Response) { | ||
24 | console.error(error); | ||
25 | return Observable.throw(error.json().error || 'Server error'); | ||
26 | } | ||
27 | } | ||
diff --git a/client/angular/videos/components/add/videos-add.component.html b/client/angular/videos/components/add/videos-add.component.html new file mode 100644 index 000000000..5f28ae650 --- /dev/null +++ b/client/angular/videos/components/add/videos-add.component.html | |||
@@ -0,0 +1,39 @@ | |||
1 | <h3>Upload a video</h3> | ||
2 | |||
3 | <form (ngSubmit)="uploadFile()" #videoForm="ngForm"> | ||
4 | <div class="form-group"> | ||
5 | <label for="name">Video name</label> | ||
6 | <input | ||
7 | type="text" class="form-control" name="name" id="name" required | ||
8 | ngControl="name" #name="ngForm" | ||
9 | > | ||
10 | <div [hidden]="name.valid || name.pristine" class="alert alert-danger"> | ||
11 | Name is required | ||
12 | </div> | ||
13 | </div> | ||
14 | |||
15 | <div class="btn btn-default btn-file"> | ||
16 | <span>Select the video...</span> | ||
17 | <input type="file" name="input_video" id="input_video"> | ||
18 | </div> | ||
19 | |||
20 | <span *ngIf="fileToUpload">{{ fileToUpload.name }}</span> | ||
21 | |||
22 | <div class="form-group"> | ||
23 | <label for="description">Description</label> | ||
24 | <textarea | ||
25 | name="description" id="description" class="form-control" placeholder="Description..." required | ||
26 | ngControl="description" #description="ngForm" | ||
27 | > | ||
28 | </textarea> | ||
29 | <div [hidden]="description.valid || description.pristine" class="alert alert-danger"> | ||
30 | A description is required | ||
31 | </div> | ||
32 | </div> | ||
33 | |||
34 | <div id="progress" *ngIf="progressBar.max !== 0"> | ||
35 | <progress [value]="progressBar.value" [max]="progressBar.max"></progress> | ||
36 | </div> | ||
37 | |||
38 | <input type="submit" value="Upload" class="btn btn-default" [disabled]="!videoForm.form.valid || !fileToUpload"> | ||
39 | </form> | ||
diff --git a/client/angular/videos/components/add/videos-add.component.scss b/client/angular/videos/components/add/videos-add.component.scss new file mode 100644 index 000000000..f4187088b --- /dev/null +++ b/client/angular/videos/components/add/videos-add.component.scss | |||
@@ -0,0 +1,25 @@ | |||
1 | .btn-file { | ||
2 | position: relative; | ||
3 | overflow: hidden; | ||
4 | } | ||
5 | |||
6 | .btn-file input[type=file] { | ||
7 | position: absolute; | ||
8 | top: 0; | ||
9 | right: 0; | ||
10 | min-width: 100%; | ||
11 | min-height: 100%; | ||
12 | font-size: 100px; | ||
13 | text-align: right; | ||
14 | filter: alpha(opacity=0); | ||
15 | opacity: 0; | ||
16 | outline: none; | ||
17 | background: white; | ||
18 | cursor: inherit; | ||
19 | display: block; | ||
20 | } | ||
21 | |||
22 | .name_file { | ||
23 | display: inline-block; | ||
24 | margin-left: 10px; | ||
25 | } | ||
diff --git a/client/angular/videos/components/add/videos-add.component.ts b/client/angular/videos/components/add/videos-add.component.ts new file mode 100644 index 000000000..97e3bb3b5 --- /dev/null +++ b/client/angular/videos/components/add/videos-add.component.ts | |||
@@ -0,0 +1,52 @@ | |||
1 | import {Component, ElementRef, Inject, OnInit} from 'angular2/core'; | ||
2 | import {Router} from 'angular2/router'; | ||
3 | import {NgForm} from 'angular2/common'; | ||
4 | |||
5 | import {Video} from '../../models/video'; | ||
6 | |||
7 | declare var jQuery:any; | ||
8 | |||
9 | @Component({ | ||
10 | selector: 'my-videos-add', | ||
11 | styleUrls: [ 'app/angular/videos/components/add/videos-add.component.css' ], | ||
12 | templateUrl: 'app/angular/videos/components/add/videos-add.component.html' | ||
13 | }) | ||
14 | |||
15 | export class VideosAddComponent implements OnInit { | ||
16 | fileToUpload: any; | ||
17 | progressBar: { value: number; max: number; } = { value: 0, max: 0 }; | ||
18 | |||
19 | private _form: any; | ||
20 | |||
21 | constructor(private _router: Router, private _elementRef: ElementRef) {} | ||
22 | |||
23 | ngOnInit() { | ||
24 | jQuery(this._elementRef.nativeElement).find('#input_video').fileupload({ | ||
25 | singleFileUploads: true, | ||
26 | multipart: true, | ||
27 | url: '/api/v1/videos', | ||
28 | autoupload: false, | ||
29 | |||
30 | add: (e, data) => { | ||
31 | this._form = data; | ||
32 | this.fileToUpload = data['files'][0]; | ||
33 | }, | ||
34 | |||
35 | progressall: (e, data) => { | ||
36 | this.progressBar.value = data.loaded; | ||
37 | this.progressBar.max= data.total; | ||
38 | }, | ||
39 | |||
40 | done: (e, data) => { | ||
41 | console.log('finished'); | ||
42 | // Print all the videos once it's finished | ||
43 | this._router.navigate(['VideosList']); | ||
44 | } | ||
45 | }); | ||
46 | } | ||
47 | |||
48 | uploadFile() { | ||
49 | this._form.formData = jQuery(this._elementRef.nativeElement).find('form').serializeArray(); | ||
50 | this._form.submit(); | ||
51 | } | ||
52 | } | ||
diff --git a/client/angular/videos/components/list/videos-list.component.html b/client/angular/videos/components/list/videos-list.component.html new file mode 100644 index 000000000..7ecdacee4 --- /dev/null +++ b/client/angular/videos/components/list/videos-list.component.html | |||
@@ -0,0 +1,11 @@ | |||
1 | <div *ngFor="#video of videos" class="video"> | ||
2 | <div> | ||
3 | <a [routerLink]="['VideosWatch', { id: video._id }]" class="video_name">{{ video.name }}</a> | ||
4 | <span class="video_pod_url">{{ video.podUrl }}</span> | ||
5 | <span *ngIf="video.namePath !== null" (click)="removeVideo(video._id)" class="video_remove glyphicon glyphicon-remove"></span> | ||
6 | </div> | ||
7 | |||
8 | <div class="video_description"> | ||
9 | {{ video.description }} | ||
10 | </div> | ||
11 | </div> | ||
diff --git a/client/angular/videos/components/list/videos-list.component.scss b/client/angular/videos/components/list/videos-list.component.scss new file mode 100644 index 000000000..82ddd80e5 --- /dev/null +++ b/client/angular/videos/components/list/videos-list.component.scss | |||
@@ -0,0 +1,34 @@ | |||
1 | .video { | ||
2 | margin-bottom: 10px; | ||
3 | transition: margin 0.5s ease; | ||
4 | |||
5 | &:hover { | ||
6 | margin-left: 5px; | ||
7 | } | ||
8 | |||
9 | a.video_name { | ||
10 | color: #333333; | ||
11 | margin-right: 5px; | ||
12 | } | ||
13 | |||
14 | .video_pod_url { | ||
15 | font-size: small; | ||
16 | color: rgba(0, 0, 0, 0.5); | ||
17 | } | ||
18 | |||
19 | .video_description { | ||
20 | font-size: small; | ||
21 | font-style: italic; | ||
22 | margin-left: 7px; | ||
23 | } | ||
24 | |||
25 | .video_remove { | ||
26 | margin: 5px; | ||
27 | cursor: pointer; | ||
28 | } | ||
29 | } | ||
30 | |||
31 | .loading { | ||
32 | display: inline-block; | ||
33 | margin-top: 100px; | ||
34 | } | ||
diff --git a/client/angular/videos/components/list/videos-list.component.ts b/client/angular/videos/components/list/videos-list.component.ts new file mode 100644 index 000000000..e5af87448 --- /dev/null +++ b/client/angular/videos/components/list/videos-list.component.ts | |||
@@ -0,0 +1,39 @@ | |||
1 | import {Component, OnInit} from 'angular2/core'; | ||
2 | import {ROUTER_DIRECTIVES} from 'angular2/router'; | ||
3 | |||
4 | import {VideosService} from '../../services/videos.service'; | ||
5 | import {Video} from '../../models/video'; | ||
6 | |||
7 | @Component({ | ||
8 | selector: 'my-videos-list', | ||
9 | styleUrls: [ 'app/angular/videos/components/list/videos-list.component.css' ], | ||
10 | templateUrl: 'app/angular/videos/components/list/videos-list.component.html', | ||
11 | directives: [ ROUTER_DIRECTIVES ] | ||
12 | }) | ||
13 | |||
14 | export class VideosListComponent implements OnInit { | ||
15 | videos: Video[]; | ||
16 | |||
17 | constructor( | ||
18 | private _videosService: VideosService | ||
19 | ) { } | ||
20 | |||
21 | ngOnInit() { | ||
22 | this.getVideos(); | ||
23 | } | ||
24 | |||
25 | getVideos() { | ||
26 | this._videosService.getVideos().subscribe( | ||
27 | videos => this.videos = videos, | ||
28 | error => alert(error) | ||
29 | ); | ||
30 | } | ||
31 | |||
32 | removeVideo(id: string) { | ||
33 | this._videosService.removeVideo(id).subscribe( | ||
34 | status => this.getVideos(), | ||
35 | error => alert(error) | ||
36 | ) | ||
37 | } | ||
38 | |||
39 | } | ||
diff --git a/client/angular/videos/components/watch/videos-watch.component.html b/client/angular/videos/components/watch/videos-watch.component.html new file mode 100644 index 000000000..e47222751 --- /dev/null +++ b/client/angular/videos/components/watch/videos-watch.component.html | |||
@@ -0,0 +1,2 @@ | |||
1 | <div class="embed-responsive embed-responsive-19by9"> | ||
2 | </div> | ||
diff --git a/client/components/app/app.component.scss b/client/angular/videos/components/watch/videos-watch.component.scss index e69de29bb..e69de29bb 100644 --- a/client/components/app/app.component.scss +++ b/client/angular/videos/components/watch/videos-watch.component.scss | |||
diff --git a/client/angular/videos/components/watch/videos-watch.component.ts b/client/angular/videos/components/watch/videos-watch.component.ts new file mode 100644 index 000000000..e3a973820 --- /dev/null +++ b/client/angular/videos/components/watch/videos-watch.component.ts | |||
@@ -0,0 +1,50 @@ | |||
1 | /// <reference path='../../../../typings/browser/ambient/webtorrent/webtorrent.d.ts' /> | ||
2 | |||
3 | import { Component, OnInit, ElementRef } from 'angular2/core'; | ||
4 | import { RouteParams } from 'angular2/router'; | ||
5 | |||
6 | declare var WebTorrent: any; | ||
7 | |||
8 | import { Video } from '../../models/video'; | ||
9 | import { VideosService } from '../../services/videos.service'; | ||
10 | |||
11 | @Component({ | ||
12 | selector: 'my-video-watch', | ||
13 | templateUrl: 'app/angular/videos/components/watch/videos-watch.component.html', | ||
14 | styleUrls: [ 'app/angular/videos/components/watch/videos-watch.component.css' ] | ||
15 | }) | ||
16 | |||
17 | export class VideosWatchComponent { | ||
18 | video: Video; | ||
19 | |||
20 | private client: any; | ||
21 | |||
22 | constructor( | ||
23 | private _videosService: VideosService, | ||
24 | private _routeParams: RouteParams, | ||
25 | private _elementRef: ElementRef | ||
26 | ) { | ||
27 | this.client = new WebTorrent({ dht: false }); | ||
28 | } | ||
29 | |||
30 | ngOnInit() { | ||
31 | let id = this._routeParams.get('id'); | ||
32 | this._videosService.getVideo(id).subscribe( | ||
33 | video => this.loadVideo(video), | ||
34 | error => alert(error) | ||
35 | ); | ||
36 | } | ||
37 | |||
38 | loadVideo(video: Video) { | ||
39 | this.video = video; | ||
40 | |||
41 | this.client.add(this.video.magnetUri, (torrent) => { | ||
42 | torrent.files[0].appendTo(this._elementRef.nativeElement, (err) => { | ||
43 | if (err) { | ||
44 | alert('Cannot append the file.'); | ||
45 | console.error(err); | ||
46 | } | ||
47 | }) | ||
48 | }) | ||
49 | } | ||
50 | } | ||
diff --git a/client/angular/videos/models/video.ts b/client/angular/videos/models/video.ts new file mode 100644 index 000000000..2f998c49a --- /dev/null +++ b/client/angular/videos/models/video.ts | |||
@@ -0,0 +1,6 @@ | |||
1 | export interface Video { | ||
2 | _id: string; | ||
3 | name: string; | ||
4 | description: string; | ||
5 | magnetUri: string; | ||
6 | } | ||
diff --git a/client/angular/videos/services/videos.service.ts b/client/angular/videos/services/videos.service.ts new file mode 100644 index 000000000..784eec68d --- /dev/null +++ b/client/angular/videos/services/videos.service.ts | |||
@@ -0,0 +1,37 @@ | |||
1 | import {Injectable} from 'angular2/core'; | ||
2 | import {Http, Response} from 'angular2/http'; | ||
3 | import {Observable} from 'rxjs/Rx'; | ||
4 | |||
5 | import {Video} from '../models/video'; | ||
6 | |||
7 | @Injectable() | ||
8 | export class VideosService { | ||
9 | private _baseVideoUrl = '/api/v1/videos/'; | ||
10 | |||
11 | constructor (private http: Http) {} | ||
12 | |||
13 | getVideos() { | ||
14 | return this.http.get(this._baseVideoUrl) | ||
15 | .map(res => <Video[]> res.json()) | ||
16 | .catch(this.handleError); | ||
17 | } | ||
18 | |||
19 | getVideo(id: string) { | ||
20 | return this.http.get(this._baseVideoUrl + id) | ||
21 | .map(res => <Video> res.json()) | ||
22 | .catch(this.handleError); | ||
23 | } | ||
24 | |||
25 | removeVideo(id: string) { | ||
26 | if (confirm('Are you sure?')) { | ||
27 | return this.http.delete(this._baseVideoUrl + id) | ||
28 | .map(res => <number> res.status) | ||
29 | .catch(this.handleError); | ||
30 | } | ||
31 | } | ||
32 | |||
33 | private handleError (error: Response) { | ||
34 | console.error(error); | ||
35 | return Observable.throw(error.json().error || 'Server error'); | ||
36 | } | ||
37 | } | ||
diff --git a/client/components/app/app.component.html b/client/components/app/app.component.html deleted file mode 100644 index 5a841ca0f..000000000 --- a/client/components/app/app.component.html +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | <div class="container"> | ||
2 | <div class="row"> | ||
3 | <menu class="col-md-2"> | ||
4 | <div id="panel_get_videos" class="panel_button"> | ||
5 | <a [routerLink]="['VideosList']" class="glyphicon glyphicon-list">Get videos</a> | ||
6 | </div> | ||
7 | |||
8 | <div id="panel_upload_video" class="panel_button"> | ||
9 | <a [routerLink]="['VideosAdd']" class="glyphicon glyphicon-cloud-upload">Upload a video</a> | ||
10 | </div> | ||
11 | |||
12 | <div id="panel_make_friends" class="panel_button"> | ||
13 | <a (click)='makeFriends()' class="glyphicon glyphicon-user">Make friends</a> | ||
14 | </div> | ||
15 | |||
16 | <div id="panel_quit_friends" class="panel_button"> | ||
17 | <a (click)='quitFriends()' class="glyphicon glyphicon-plane">Quit friends</a> | ||
18 | </div> | ||
19 | </menu> | ||
20 | |||
21 | <router-outlet class="col-md-9"></router-outlet> | ||
22 | </div> | ||
23 | </div> | ||
diff --git a/client/components/app/app.component.ts b/client/components/app/app.component.ts deleted file mode 100644 index e2cebf535..000000000 --- a/client/components/app/app.component.ts +++ /dev/null | |||
@@ -1,43 +0,0 @@ | |||
1 | import {Component} from 'angular2/core'; | ||
2 | import { RouteConfig, ROUTER_DIRECTIVES, ROUTER_PROVIDERS } from 'angular2/router'; | ||
3 | |||
4 | import { VideosAddComponent } from '../videos/add/videos-add.component'; | ||
5 | import { VideosListComponent } from '../videos/list/videos-list.component'; | ||
6 | import { VideosWatchComponent } from '../videos/watch/videos-watch.component'; | ||
7 | |||
8 | @RouteConfig([ | ||
9 | { | ||
10 | path: '/videos/list', | ||
11 | name: 'VideosList', | ||
12 | component: VideosListComponent, | ||
13 | useAsDefault: true | ||
14 | }, | ||
15 | { | ||
16 | path: '/videos/watch/:id', | ||
17 | name: 'VideosWatch', | ||
18 | component: VideosWatchComponent | ||
19 | }, | ||
20 | { | ||
21 | path: '/videos/add', | ||
22 | name: 'VideosAdd', | ||
23 | component: VideosAddComponent | ||
24 | } | ||
25 | ]) | ||
26 | |||
27 | @Component({ | ||
28 | selector: 'my-app', | ||
29 | templateUrl: 'app/components/app/app.component.html', | ||
30 | styleUrls: [ 'app/components/app/app.component.css' ], | ||
31 | directives: [ ROUTER_DIRECTIVES ], | ||
32 | providers: [ ROUTER_PROVIDERS ] | ||
33 | }) | ||
34 | |||
35 | export class AppComponent { | ||
36 | makeFriends() { | ||
37 | alert('make Friends'); | ||
38 | } | ||
39 | |||
40 | quitFriends() { | ||
41 | alert('quit Friends'); | ||
42 | } | ||
43 | } | ||
diff --git a/client/components/videos/add/videos-add.component.ts b/client/components/videos/add/videos-add.component.ts deleted file mode 100644 index 0db7c0163..000000000 --- a/client/components/videos/add/videos-add.component.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export class VideosAddComponent {} | ||
diff --git a/client/components/videos/list/videos-list.component.ts b/client/components/videos/list/videos-list.component.ts deleted file mode 100644 index 54470a5ad..000000000 --- a/client/components/videos/list/videos-list.component.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export class VideosListComponent {} | ||
diff --git a/client/components/videos/watch/videos-watch.component.ts b/client/components/videos/watch/videos-watch.component.ts deleted file mode 100644 index 84daef336..000000000 --- a/client/components/videos/watch/videos-watch.component.ts +++ /dev/null | |||
@@ -1 +0,0 @@ | |||
1 | export class VideosWatchComponent {} | ||
diff --git a/client/index.html b/client/index.html index f971b9fdb..4b273aae4 100644 --- a/client/index.html +++ b/client/index.html | |||
@@ -1,34 +1,40 @@ | |||
1 | <html> | 1 | <html> |
2 | <head> | 2 | <head> |
3 | <title>Angular 2 QuickStart</title> | 3 | <title>PeerTube</title> |
4 | <meta name="viewport" content="width=device-width, initial-scale=1"> | 4 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
5 | <link rel="stylesheet" href="/stylesheets/index.css"> | 5 | <link rel="stylesheet" href="/app/stylesheets/index.css"> |
6 | 6 | ||
7 | <!-- 1. Load libraries --> | 7 | <!-- 1. Load libraries --> |
8 | <!-- IE required polyfills, in this exact order --> | 8 | <!-- IE required polyfills, in this exact order --> |
9 | <script src="app/node_modules/es6-shim/es6-shim.min.js"></script> | 9 | <script src="/app/node_modules/es6-shim/es6-shim.min.js"></script> |
10 | <script src="app/node_modules/systemjs/dist/system-polyfills.js"></script> | 10 | <script src="/app/node_modules/systemjs/dist/system-polyfills.js"></script> |
11 | <script src="app/node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script> | 11 | <script src="/app/node_modules/angular2/es6/dev/src/testing/shims_for_IE.js"></script> |
12 | |||
13 | <script src="/app/node_modules/angular2/bundles/angular2-polyfills.js"></script> | ||
14 | <script src="/app/node_modules/systemjs/dist/system.src.js"></script> | ||
15 | <script src="/app/node_modules/rxjs/bundles/Rx.js"></script> | ||
16 | <script src="/app/node_modules/angular2/bundles/angular2.dev.js"></script> | ||
17 | <script src="/app/node_modules/angular2/bundles/router.dev.js"></script> | ||
18 | <script src="/app/node_modules/angular2/bundles/http.dev.js"></script> | ||
19 | <script src="/app/node_modules/jquery/dist/jquery.js"></script> | ||
20 | <script src="/app/node_modules/jquery.ui.widget/jquery.ui.widget.js"></script> | ||
21 | <script src="/app/node_modules/blueimp-file-upload/js/jquery.fileupload.js"></script> | ||
22 | <script src="/app/node_modules/webtorrent/webtorrent.min.js"></script> | ||
12 | 23 | ||
13 | <script src="app/node_modules/angular2/bundles/angular2-polyfills.js"></script> | ||
14 | <script src="app/node_modules/systemjs/dist/system.src.js"></script> | ||
15 | <script src="app/node_modules/rxjs/bundles/Rx.js"></script> | ||
16 | <script src="app/node_modules/angular2/bundles/angular2.dev.js"></script> | ||
17 | <script src="app/node_modules/angular2/bundles/router.dev.js"></script> | ||
18 | 24 | ||
19 | <!-- 2. Configure SystemJS --> | 25 | <!-- 2. Configure SystemJS --> |
20 | <script> | 26 | <script> |
21 | System.config({ | 27 | System.config({ |
22 | packages: { | 28 | packages: { |
23 | app: { | 29 | '/app': { |
24 | components: { | 30 | components: { |
25 | format: 'register', | 31 | format: 'register', |
26 | defaultExtension: 'js' | 32 | defaultExtension: 'js' |
27 | } | 33 | } |
28 | } | 34 | }, |
29 | } | 35 | } |
30 | }); | 36 | }); |
31 | System.import('app/components/bootstrap') | 37 | System.import('/app/angular/bootstrap') |
32 | .then(null, console.error.bind(console)); | 38 | .then(null, console.error.bind(console)); |
33 | </script> | 39 | </script> |
34 | 40 | ||
diff --git a/client/package.json b/client/package.json index 71f305914..dbb065974 100644 --- a/client/package.json +++ b/client/package.json | |||
@@ -20,13 +20,17 @@ | |||
20 | }, | 20 | }, |
21 | "license": "ISC", | 21 | "license": "ISC", |
22 | "dependencies": { | 22 | "dependencies": { |
23 | "angular2": "2.0.0-beta.8", | 23 | "angular2": "2.0.0-beta.9", |
24 | "blueimp-file-upload": "^9.12.1", | ||
24 | "bootstrap-sass": "^3.3.6", | 25 | "bootstrap-sass": "^3.3.6", |
25 | "es6-promise": "^3.0.2", | 26 | "es6-promise": "^3.0.2", |
26 | "es6-shim": "^0.33.3", | 27 | "es6-shim": "^0.33.3", |
28 | "jquery": "^2.2.1", | ||
29 | "jquery.ui.widget": "^1.10.3", | ||
27 | "reflect-metadata": "0.1.2", | 30 | "reflect-metadata": "0.1.2", |
28 | "rxjs": "5.0.0-beta.2", | 31 | "rxjs": "5.0.0-beta.2", |
29 | "systemjs": "0.19.22", | 32 | "systemjs": "0.19.22", |
33 | "webtorrent": "^0.85.1", | ||
30 | "zone.js": "0.5.15" | 34 | "zone.js": "0.5.15" |
31 | }, | 35 | }, |
32 | "devDependencies": { | 36 | "devDependencies": { |
diff --git a/client/stylesheets/application.scss b/client/stylesheets/application.scss index bf9ec90ab..d1b309907 100644 --- a/client/stylesheets/application.scss +++ b/client/stylesheets/application.scss | |||
@@ -1,6 +1,6 @@ | |||
1 | $icon-font-path: "/stylesheets/vendor/fonts/bootstrap/"; | 1 | $icon-font-path: "/app/node_modules/bootstrap-sass/assets/fonts/bootstrap/"; |
2 | 2 | ||
3 | @import "bootstrap-variables"; | 3 | @import "bootstrap-variables"; |
4 | @import "_bootstrap"; | 4 | @import "_bootstrap"; |
5 | @import "base"; | 5 | @import "base.scss"; |
6 | @import "index"; \ No newline at end of file | 6 | @import "index.scss"; |
diff --git a/client/stylesheets/bootstrap-variables.scss b/client/stylesheets/bootstrap-variables.scss index 5a49649f9..a2472f357 100644 --- a/client/stylesheets/bootstrap-variables.scss +++ b/client/stylesheets/bootstrap-variables.scss | |||
@@ -108,9 +108,9 @@ | |||
108 | // $line-height-large: 1.3333333 // extra decimals for Win 8.1 Chrome | 108 | // $line-height-large: 1.3333333 // extra decimals for Win 8.1 Chrome |
109 | // $line-height-small: 1.5 | 109 | // $line-height-small: 1.5 |
110 | 110 | ||
111 | $border-radius-base: 0; | 111 | // $border-radius-base: 0; |
112 | $border-radius-large: 0; | 112 | // $border-radius-large: 0; |
113 | $border-radius-small: 0; | 113 | // $border-radius-small: 0; |
114 | 114 | ||
115 | //** Global color for active items (e.g., navs or dropdowns). | 115 | //** Global color for active items (e.g., navs or dropdowns). |
116 | // $component-active-color: #fff | 116 | // $component-active-color: #fff |
diff --git a/client/stylesheets/index.scss b/client/stylesheets/index.scss index d13dcfa90..5cba54705 100644 --- a/client/stylesheets/index.scss +++ b/client/stylesheets/index.scss | |||
@@ -1,88 +1,5 @@ | |||
1 | .span_action { | ||
2 | margin: 5px; | ||
3 | cursor: pointer; | ||
4 | } | ||
5 | |||
6 | header div { | 1 | header div { |
7 | height: 50px; | 2 | height: 50px; |
8 | line-height: 25px; | 3 | line-height: 25px; |
9 | margin-bottom: 50px; | 4 | margin-bottom: 50px; |
10 | } | 5 | } |
11 | |||
12 | menu { | ||
13 | margin-right: 20px; | ||
14 | border-right: 1px solid rgba(0, 0, 0, 0.2); | ||
15 | } | ||
16 | |||
17 | menu .panel_button { | ||
18 | margin: 8px; | ||
19 | cursor: pointer; | ||
20 | transition: margin 0.2s; | ||
21 | } | ||
22 | |||
23 | menu .panel_button:hover { | ||
24 | margin-left: 15px; | ||
25 | } | ||
26 | |||
27 | menu .glyphicon { | ||
28 | margin: 5px; | ||
29 | } | ||
30 | |||
31 | #ajax_load { | ||
32 | min-height: 500px; | ||
33 | } | ||
34 | |||
35 | .loading { | ||
36 | display: inline-block; | ||
37 | margin-top: 100px; | ||
38 | } | ||
39 | |||
40 | .video { | ||
41 | margin-bottom: 10px; | ||
42 | transition: margin 0.5s ease; | ||
43 | } | ||
44 | |||
45 | .video:hover { | ||
46 | margin-left: 5px; | ||
47 | } | ||
48 | |||
49 | .video_name { | ||
50 | cursor: pointer; | ||
51 | margin-right: 5px; | ||
52 | } | ||
53 | |||
54 | .video_pod_url { | ||
55 | font-size: small; | ||
56 | color: rgba(0, 0, 0, 0.5); | ||
57 | } | ||
58 | |||
59 | .video_description { | ||
60 | font-size: small; | ||
61 | font-style: italic; | ||
62 | margin-left: 7px; | ||
63 | } | ||
64 | |||
65 | .btn-file { | ||
66 | position: relative; | ||
67 | overflow: hidden; | ||
68 | } | ||
69 | .btn-file input[type=file] { | ||
70 | position: absolute; | ||
71 | top: 0; | ||
72 | right: 0; | ||
73 | min-width: 100%; | ||
74 | min-height: 100%; | ||
75 | font-size: 100px; | ||
76 | text-align: right; | ||
77 | filter: alpha(opacity=0); | ||
78 | opacity: 0; | ||
79 | outline: none; | ||
80 | background: white; | ||
81 | cursor: inherit; | ||
82 | display: block; | ||
83 | } | ||
84 | |||
85 | .name_file { | ||
86 | display: inline-block; | ||
87 | margin-left: 10px; | ||
88 | } \ No newline at end of file | ||
diff --git a/client/typings.json b/client/typings.json index f10b7c541..0e3ed5a01 100644 --- a/client/typings.json +++ b/client/typings.json | |||
@@ -1,6 +1,9 @@ | |||
1 | { | 1 | { |
2 | "ambientDependencies": { | 2 | "ambientDependencies": { |
3 | "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", | 3 | "es6-shim": "github:DefinitelyTyped/DefinitelyTyped/es6-shim/es6-shim.d.ts#4de74cb527395c13ba20b438c3a7a419ad931f1c", |
4 | "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#bc92442c075929849ec41d28ab618892ba493504" | 4 | "jasmine": "github:DefinitelyTyped/DefinitelyTyped/jasmine/jasmine.d.ts#bc92442c075929849ec41d28ab618892ba493504", |
5 | "node": "github:DefinitelyTyped/DefinitelyTyped/node/node.d.ts#abc2bcfb8524b1e027e6298d3348012b5b06eda5", | ||
6 | "parse-torrent": "github:DefinitelyTyped/DefinitelyTyped/parse-torrent/parse-torrent.d.ts#abc2bcfb8524b1e027e6298d3348012b5b06eda5", | ||
7 | "webtorrent": "github:DefinitelyTyped/DefinitelyTyped/webtorrent/webtorrent.d.ts#abc2bcfb8524b1e027e6298d3348012b5b06eda5" | ||
5 | } | 8 | } |
6 | } | 9 | } |
diff --git a/package.json b/package.json index aabd5616f..36730aaa0 100644 --- a/package.json +++ b/package.json | |||
@@ -18,19 +18,25 @@ | |||
18 | }, | 18 | }, |
19 | "scripts": { | 19 | "scripts": { |
20 | "build": "concurrently \"npm run client:sass\" \"npm run client:tsc\"", | 20 | "build": "concurrently \"npm run client:sass\" \"npm run client:tsc\"", |
21 | |||
21 | "client:clean": "concurrently \"npm run client:tsc:clean\" \"npm run client:sass:clean\"", | 22 | "client:clean": "concurrently \"npm run client:tsc:clean\" \"npm run client:sass:clean\"", |
23 | |||
22 | "client:sass:index": "npm run client:sass:index:clean && cd client && node-sass --include-path node_modules/bootstrap-sass/assets/stylesheets/ stylesheets/application.scss stylesheets/index.css", | 24 | "client:sass:index": "npm run client:sass:index:clean && cd client && node-sass --include-path node_modules/bootstrap-sass/assets/stylesheets/ stylesheets/application.scss stylesheets/index.css", |
23 | "client:sass:index:watch": "cd client && node-sass -w --include-path node_modules/bootstrap-sass/assets/stylesheets/ stylesheets/application.scss stylesheets/index.css", | 25 | "client:sass:index:watch": "cd client && node-sass -w --include-path node_modules/bootstrap-sass/assets/stylesheets/ stylesheets/application.scss stylesheets/index.css", |
24 | "client:sass:index:clean": "cd client && rm -f stylesheets/index.css", | 26 | "client:sass:index:clean": "cd client && rm -f stylesheets/index.css", |
25 | "client:sass:components": "cd client && node-sass components/ --output components/", | 27 | |
26 | "client:sass:components:watch": "cd client && node-sass -w components/ --output components/", | 28 | "client:sass:angular": "cd client && node-sass angular/ --output angular/", |
27 | "client:sass:components:clean": "cd client && rm -f components/**/*.css", | 29 | "client:sass:angular:watch": "cd client && node-sass -w angular/ --output angular/", |
28 | "client:sass": "concurrently \"npm run client:sass:index\" \"npm run client:sass:components\"", | 30 | "client:sass:angular:clean": "cd client && rm -f angular/**/*.css", |
29 | "client:sass:watch": "concurrently \"npm run client:sass:index:watch\" \"npm run client:sass:components:watch\"", | 31 | |
30 | "client:sass:clean": "concurrently \"npm run client:sass:index:clean\" \"npm run client:sass:components:clean\"", | 32 | "client:sass": "concurrently \"npm run client:sass:index\" \"npm run client:sass:angular\"", |
33 | "client:sass:watch": "concurrently \"npm run client:sass:index:watch\" \"npm run client:sass:angular:watch\"", | ||
34 | "client:sass:clean": "concurrently \"npm run client:sass:index:clean\" \"npm run client:sass:angular:clean\"", | ||
35 | |||
31 | "client:tsc": "cd client && npm run tsc", | 36 | "client:tsc": "cd client && npm run tsc", |
32 | "client:tsc:watch": "cd client && npm run tsc:w", | 37 | "client:tsc:watch": "cd client && npm run tsc:w", |
33 | "client:tsc:clean": "cd client && rm -f components/**/*.js components/**/*.js.map", | 38 | "client:tsc:clean": "cd client && find angular -regextype posix-egrep -regex \".*\\.(js|map)$\" -exec rm -f {} \\;", |
39 | |||
34 | "dev": "npm run build && concurrently \"npm run livereload\" \"npm run client:tsc:watch\" \"npm run client:sass:watch\" \"npm start\"", | 40 | "dev": "npm run build && concurrently \"npm run livereload\" \"npm run client:tsc:watch\" \"npm run client:sass:watch\" \"npm start\"", |
35 | "livereload": "livereload ./client", | 41 | "livereload": "livereload ./client", |
36 | "start": "node server", | 42 | "start": "node server", |
@@ -47,7 +53,6 @@ | |||
47 | "electron-spawn": "https://github.com/Chocobozzz/electron-spawn", | 53 | "electron-spawn": "https://github.com/Chocobozzz/electron-spawn", |
48 | "express": "^4.12.4", | 54 | "express": "^4.12.4", |
49 | "express-validator": "^2.11.0", | 55 | "express-validator": "^2.11.0", |
50 | "jquery": "^2.1.4", | ||
51 | "lodash-node": "^3.10.2", | 56 | "lodash-node": "^3.10.2", |
52 | "mkdirp": "^0.5.1", | 57 | "mkdirp": "^0.5.1", |
53 | "mongoose": "^4.0.5", | 58 | "mongoose": "^4.0.5", |
diff --git a/server/controllers/api/v1/index.js b/server/controllers/api/v1/index.js index abbc5eb60..b562bc2af 100644 --- a/server/controllers/api/v1/index.js +++ b/server/controllers/api/v1/index.js | |||
@@ -20,5 +20,5 @@ module.exports = router | |||
20 | // --------------------------------------------------------------------------- | 20 | // --------------------------------------------------------------------------- |
21 | 21 | ||
22 | function badRequest (req, res, next) { | 22 | function badRequest (req, res, next) { |
23 | res.sendStatus(400) | 23 | res.type('json').status(400).end() |
24 | } | 24 | } |
diff --git a/server/controllers/api/v1/pods.js b/server/controllers/api/v1/pods.js index c93a86ee8..fa9832914 100644 --- a/server/controllers/api/v1/pods.js +++ b/server/controllers/api/v1/pods.js | |||
@@ -66,7 +66,7 @@ function makeFriends (req, res, next) { | |||
66 | friends.makeFriends(function (err) { | 66 | friends.makeFriends(function (err) { |
67 | if (err) return next(err) | 67 | if (err) return next(err) |
68 | 68 | ||
69 | res.sendStatus(204) | 69 | res.type('json').status(204).end() |
70 | }) | 70 | }) |
71 | } | 71 | } |
72 | 72 | ||
@@ -79,7 +79,7 @@ function removePods (req, res, next) { | |||
79 | if (err) logger.error('Cannot remove all remote videos of %s.', url) | 79 | if (err) logger.error('Cannot remove all remote videos of %s.', url) |
80 | else logger.info('%s pod removed.', url) | 80 | else logger.info('%s pod removed.', url) |
81 | 81 | ||
82 | res.sendStatus(204) | 82 | res.type('json').status(204).end() |
83 | }) | 83 | }) |
84 | }) | 84 | }) |
85 | } | 85 | } |
@@ -88,6 +88,6 @@ function quitFriends (req, res, next) { | |||
88 | friends.quitFriends(function (err) { | 88 | friends.quitFriends(function (err) { |
89 | if (err) return next(err) | 89 | if (err) return next(err) |
90 | 90 | ||
91 | res.sendStatus(204) | 91 | res.type('json').status(204).end() |
92 | }) | 92 | }) |
93 | } | 93 | } |
diff --git a/server/controllers/api/v1/remoteVideos.js b/server/controllers/api/v1/remoteVideos.js index 475a874cf..7622e39f5 100644 --- a/server/controllers/api/v1/remoteVideos.js +++ b/server/controllers/api/v1/remoteVideos.js | |||
@@ -48,6 +48,6 @@ function removeRemoteVideo (req, res, next) { | |||
48 | videos.removeRemotesOfByMagnetUris(url, magnetUris, function (err) { | 48 | videos.removeRemotesOfByMagnetUris(url, magnetUris, function (err) { |
49 | if (err) return next(err) | 49 | if (err) return next(err) |
50 | 50 | ||
51 | res.sendStatus(204) | 51 | res.type('json').status(204).end() |
52 | }) | 52 | }) |
53 | } | 53 | } |
diff --git a/server/controllers/api/v1/videos.js b/server/controllers/api/v1/videos.js index 620711925..9398aabb7 100644 --- a/server/controllers/api/v1/videos.js +++ b/server/controllers/api/v1/videos.js | |||
@@ -77,7 +77,7 @@ function addVideo (req, res, next) { | |||
77 | friends.addVideoToFriends(video_data) | 77 | friends.addVideoToFriends(video_data) |
78 | 78 | ||
79 | // TODO : include Location of the new video | 79 | // TODO : include Location of the new video |
80 | res.sendStatus(201) | 80 | res.type('json').status(201).end() |
81 | }) | 81 | }) |
82 | }) | 82 | }) |
83 | } | 83 | } |
@@ -87,7 +87,7 @@ function getVideos (req, res, next) { | |||
87 | if (err) return next(err) | 87 | if (err) return next(err) |
88 | 88 | ||
89 | if (video === null) { | 89 | if (video === null) { |
90 | return res.sendStatus(404) | 90 | res.type('json').status(204).end() |
91 | } | 91 | } |
92 | 92 | ||
93 | res.json(video) | 93 | res.json(video) |
@@ -117,7 +117,7 @@ function removeVideo (req, res, next) { | |||
117 | } | 117 | } |
118 | 118 | ||
119 | friends.removeVideoToFriends(params) | 119 | friends.removeVideoToFriends(params) |
120 | res.sendStatus(204) | 120 | res.type('json').status(204).end() |
121 | }) | 121 | }) |
122 | }) | 122 | }) |
123 | }) | 123 | }) |