update tslint -> eslint
This commit is contained in:
@@ -3,10 +3,10 @@ import {TestBed} from '@angular/core/testing';
|
||||
import {FileDataService} from './file-data.service';
|
||||
|
||||
describe('FileDataService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => void TestBed.configureTestingModule({}));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: FileDataService = TestBed.get(FileDataService);
|
||||
expect(service).toBeTruthy();
|
||||
const service: FileDataService = TestBed.inject(FileDataService);
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -5,12 +5,10 @@ import {FileServer} from './fileServer';
|
||||
import {DbService} from '../../../services/db.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FileDataService {
|
||||
|
||||
constructor(private db: DbService) {
|
||||
}
|
||||
public constructor(private db: DbService) {}
|
||||
|
||||
public async set(songId: string, file: FileServer): Promise<string> {
|
||||
const songRef = this.db.doc('songs/' + songId);
|
||||
@@ -27,8 +25,5 @@ export class FileDataService {
|
||||
public read$(songId: string): Observable<File[]> {
|
||||
const songRef = this.db.doc('songs/' + songId);
|
||||
return songRef.collection<File>('files').valueChanges({idField: 'id'});
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -6,11 +6,11 @@ describe('FileService', () => {
|
||||
let service: FileService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
void TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(FileService);
|
||||
});
|
||||
|
||||
it('should be created', () => {
|
||||
expect(service).toBeTruthy();
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,22 +4,17 @@ import {Observable} from 'rxjs';
|
||||
import {FileDataService} from './file-data.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class FileService {
|
||||
|
||||
constructor(
|
||||
private storage: AngularFireStorage,
|
||||
private fileDataService: FileDataService
|
||||
) {
|
||||
}
|
||||
public constructor(private storage: AngularFireStorage, private fileDataService: FileDataService) {}
|
||||
|
||||
public getDownloadUrl(path: string): Observable<string> {
|
||||
const ref = this.storage.ref(path);
|
||||
return ref.getDownloadURL();
|
||||
return ref.getDownloadURL() as Observable<string>;
|
||||
}
|
||||
|
||||
public async delete(path: string, songId: string, fileId: string) {
|
||||
public async delete(path: string, songId: string, fileId: string): Promise<void> {
|
||||
const ref = this.storage.ref(path);
|
||||
await ref.delete().toPromise();
|
||||
await this.fileDataService.delete(songId, fileId);
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
export class FileBase {
|
||||
|
||||
protected basePath = '/attachments';
|
||||
protected directory = (songId: string) => `${this.basePath}/${songId}`;
|
||||
protected directory: (songId: string) => string = (songId: string) => `${this.basePath}/${songId}`;
|
||||
}
|
||||
|
||||
@@ -1,133 +1,156 @@
|
||||
export const KEYS = [
|
||||
'C#', 'C', 'Db', 'D#', 'D', 'Eb', 'E', 'F#', 'F', 'Gb', 'G#', 'G', 'Ab', 'A#', 'A', 'B', 'H',
|
||||
'c#', 'c', 'db', 'd#', 'd', 'eb', 'e', 'f#', 'f', 'gb', 'g#', 'g', 'ab', 'a#', 'a', 'b', 'h'
|
||||
];
|
||||
export const KEYS_MAJOR_FLAT = [
|
||||
'C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H',
|
||||
];
|
||||
export const KEYS_MAJOR_B = [
|
||||
'C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H',
|
||||
];
|
||||
export const KEYS_MINOR_FLAT = [
|
||||
'c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'h',
|
||||
];
|
||||
export const KEYS_MINOR_B = [
|
||||
'c', 'db', 'd', 'eb', 'e', 'f', 'gb', 'g', 'ab', 'a', 'b', 'h',
|
||||
export const KEYS: string[] = [
|
||||
'C#',
|
||||
'C',
|
||||
'Db',
|
||||
'D#',
|
||||
'D',
|
||||
'Eb',
|
||||
'E',
|
||||
'F#',
|
||||
'F',
|
||||
'Gb',
|
||||
'G#',
|
||||
'G',
|
||||
'Ab',
|
||||
'A#',
|
||||
'A',
|
||||
'B',
|
||||
'H',
|
||||
'c#',
|
||||
'c',
|
||||
'db',
|
||||
'd#',
|
||||
'd',
|
||||
'eb',
|
||||
'e',
|
||||
'f#',
|
||||
'f',
|
||||
'gb',
|
||||
'g#',
|
||||
'g',
|
||||
'ab',
|
||||
'a#',
|
||||
'a',
|
||||
'b',
|
||||
'h',
|
||||
];
|
||||
export const KEYS_MAJOR_FLAT: string[] = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'H'];
|
||||
export const KEYS_MAJOR_B: string[] = ['C', 'Db', 'D', 'Eb', 'E', 'F', 'Gb', 'G', 'Ab', 'A', 'B', 'H'];
|
||||
export const KEYS_MINOR_FLAT: string[] = ['c', 'c#', 'd', 'd#', 'e', 'f', 'f#', 'g', 'g#', 'a', 'a#', 'h'];
|
||||
export const KEYS_MINOR_B: string[] = ['c', 'db', 'd', 'eb', 'e', 'f', 'gb', 'g', 'ab', 'a', 'b', 'h'];
|
||||
|
||||
export type scale = 'b' | 'flat'
|
||||
export type scale = 'b' | 'flat';
|
||||
|
||||
const scaleTypeAssignment: { [key: string]: string[][] } = {
|
||||
'C': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
const scaleTypeAssignment: {[key: string]: string[][]} = {
|
||||
C: [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'C#': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'Db': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'D': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
Db: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
D: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'D#': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'Eb': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'E': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'F': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
Eb: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
E: [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
F: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'F#': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'Gb': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'G': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
Gb: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
G: [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'G#': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'Ab': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'A': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
Ab: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
A: [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'A#': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'B': [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
'H': [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
'c': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
B: [KEYS_MAJOR_B, KEYS_MINOR_B],
|
||||
H: [KEYS_MAJOR_FLAT, KEYS_MINOR_FLAT],
|
||||
c: [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'c#': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'db': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'd': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
db: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
d: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'd#': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'eb': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'e': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'f': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
eb: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
e: [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
f: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'f#': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'gb': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'g': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
gb: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
g: [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'g#': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'ab': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'a': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
ab: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
a: [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'a#': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
'b': [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
'h': [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
}
|
||||
|
||||
const scaleAssignment = {
|
||||
'C': KEYS_MAJOR_FLAT,
|
||||
'C#': KEYS_MAJOR_FLAT,
|
||||
'Db': KEYS_MAJOR_B,
|
||||
'D': KEYS_MAJOR_B,
|
||||
'D#': KEYS_MAJOR_FLAT,
|
||||
'Eb': KEYS_MAJOR_B,
|
||||
'E': KEYS_MAJOR_FLAT,
|
||||
'F': KEYS_MAJOR_B,
|
||||
'F#': KEYS_MAJOR_FLAT,
|
||||
'Gb': KEYS_MAJOR_B,
|
||||
'G': KEYS_MAJOR_FLAT,
|
||||
'G#': KEYS_MAJOR_FLAT,
|
||||
'Ab': KEYS_MAJOR_B,
|
||||
'A': KEYS_MAJOR_FLAT,
|
||||
'A#': KEYS_MAJOR_FLAT,
|
||||
'B': KEYS_MAJOR_B,
|
||||
'H': KEYS_MAJOR_FLAT,
|
||||
'c': KEYS_MINOR_FLAT,
|
||||
'c#': KEYS_MINOR_FLAT,
|
||||
'db': KEYS_MINOR_B,
|
||||
'd': KEYS_MINOR_B,
|
||||
'd#': KEYS_MINOR_FLAT,
|
||||
'eb': KEYS_MINOR_B,
|
||||
'e': KEYS_MINOR_FLAT,
|
||||
'f': KEYS_MINOR_B,
|
||||
'f#': KEYS_MINOR_FLAT,
|
||||
'gb': KEYS_MINOR_B,
|
||||
'g': KEYS_MINOR_FLAT,
|
||||
'g#': KEYS_MINOR_FLAT,
|
||||
'ab': KEYS_MINOR_B,
|
||||
'a': KEYS_MINOR_FLAT,
|
||||
'a#': KEYS_MINOR_FLAT,
|
||||
'b': KEYS_MINOR_B,
|
||||
'h': KEYS_MINOR_FLAT,
|
||||
b: [KEYS_MINOR_B, KEYS_MAJOR_B],
|
||||
h: [KEYS_MINOR_FLAT, KEYS_MAJOR_FLAT],
|
||||
};
|
||||
|
||||
export const scaleMapping = {
|
||||
'C': 'C',
|
||||
const scaleAssignment: {[key: string]: string[]} = {
|
||||
C: KEYS_MAJOR_FLAT,
|
||||
'C#': KEYS_MAJOR_FLAT,
|
||||
Db: KEYS_MAJOR_B,
|
||||
D: KEYS_MAJOR_B,
|
||||
'D#': KEYS_MAJOR_FLAT,
|
||||
Eb: KEYS_MAJOR_B,
|
||||
E: KEYS_MAJOR_FLAT,
|
||||
F: KEYS_MAJOR_B,
|
||||
'F#': KEYS_MAJOR_FLAT,
|
||||
Gb: KEYS_MAJOR_B,
|
||||
G: KEYS_MAJOR_FLAT,
|
||||
'G#': KEYS_MAJOR_FLAT,
|
||||
Ab: KEYS_MAJOR_B,
|
||||
A: KEYS_MAJOR_FLAT,
|
||||
'A#': KEYS_MAJOR_FLAT,
|
||||
B: KEYS_MAJOR_B,
|
||||
H: KEYS_MAJOR_FLAT,
|
||||
c: KEYS_MINOR_FLAT,
|
||||
'c#': KEYS_MINOR_FLAT,
|
||||
db: KEYS_MINOR_B,
|
||||
d: KEYS_MINOR_B,
|
||||
'd#': KEYS_MINOR_FLAT,
|
||||
eb: KEYS_MINOR_B,
|
||||
e: KEYS_MINOR_FLAT,
|
||||
f: KEYS_MINOR_B,
|
||||
'f#': KEYS_MINOR_FLAT,
|
||||
gb: KEYS_MINOR_B,
|
||||
g: KEYS_MINOR_FLAT,
|
||||
'g#': KEYS_MINOR_FLAT,
|
||||
ab: KEYS_MINOR_B,
|
||||
a: KEYS_MINOR_FLAT,
|
||||
'a#': KEYS_MINOR_FLAT,
|
||||
b: KEYS_MINOR_B,
|
||||
h: KEYS_MINOR_FLAT,
|
||||
};
|
||||
|
||||
export const scaleMapping: {[key: string]: string} = {
|
||||
C: 'C',
|
||||
'C#': 'C♯',
|
||||
'Db': 'D♭',
|
||||
'D': 'D',
|
||||
Db: 'D♭',
|
||||
D: 'D',
|
||||
'D#': 'D♯',
|
||||
'Eb': 'E♭',
|
||||
'E': 'E',
|
||||
'F': 'F',
|
||||
Eb: 'E♭',
|
||||
E: 'E',
|
||||
F: 'F',
|
||||
'F#': 'F♯',
|
||||
'Gb': 'D♭',
|
||||
'G': 'G',
|
||||
Gb: 'D♭',
|
||||
G: 'G',
|
||||
'G#': 'G♯',
|
||||
'Ab': 'A♭',
|
||||
'A': 'A',
|
||||
Ab: 'A♭',
|
||||
A: 'A',
|
||||
'A#': 'A♯',
|
||||
'B': 'B',
|
||||
'H': 'H',
|
||||
'c': 'c',
|
||||
B: 'B',
|
||||
H: 'H',
|
||||
c: 'c',
|
||||
'c#': 'c♯',
|
||||
'db': 'd♭',
|
||||
'd': 'd',
|
||||
db: 'd♭',
|
||||
d: 'd',
|
||||
'd#': 'd♯',
|
||||
'eb': 'e♭',
|
||||
'e': 'e',
|
||||
'f': 'f',
|
||||
eb: 'e♭',
|
||||
e: 'e',
|
||||
f: 'f',
|
||||
'f#': 'f♯',
|
||||
'gb': 'g♭',
|
||||
'g': 'g',
|
||||
gb: 'g♭',
|
||||
g: 'g',
|
||||
'g#': 'g♯',
|
||||
'ab': 'a♭',
|
||||
'a': 'a',
|
||||
ab: 'a♭',
|
||||
a: 'a',
|
||||
'a#': 'a♯',
|
||||
'b': 'b',
|
||||
'h': 'h',
|
||||
b: 'b',
|
||||
h: 'h',
|
||||
};
|
||||
|
||||
export const getScale = (key: string): string[] => scaleAssignment[key];
|
||||
export const getScaleType = (key: string): string[][] => scaleTypeAssignment[key];
|
||||
|
||||
|
||||
@@ -5,37 +5,35 @@ import {AngularFirestore} from '@angular/fire/firestore';
|
||||
import {of} from 'rxjs';
|
||||
|
||||
describe('SongDataService', () => {
|
||||
|
||||
const songs = [
|
||||
{title: 'title1'}
|
||||
];
|
||||
const songs = [{title: 'title1'}];
|
||||
|
||||
const angularFirestoreCollection = {
|
||||
valueChanges: () => of(songs)
|
||||
valueChanges: () => of(songs),
|
||||
};
|
||||
|
||||
const mockAngularFirestore = {
|
||||
collection: () => angularFirestoreCollection
|
||||
collection: () => angularFirestoreCollection,
|
||||
};
|
||||
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{provide: AngularFirestore, useValue: mockAngularFirestore}
|
||||
]
|
||||
}));
|
||||
beforeEach(
|
||||
() =>
|
||||
void TestBed.configureTestingModule({
|
||||
providers: [{provide: AngularFirestore, useValue: mockAngularFirestore}],
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: SongDataService = TestBed.get(SongDataService);
|
||||
expect(service).toBeTruthy();
|
||||
const service: SongDataService = TestBed.inject(SongDataService);
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should list songs', waitForAsync(() => {
|
||||
const service: SongDataService = TestBed.get(SongDataService);
|
||||
service.list$().subscribe(s => {
|
||||
expect(s).toEqual([
|
||||
{title: 'title1'}
|
||||
] as any);
|
||||
}
|
||||
);
|
||||
}));
|
||||
it(
|
||||
'should list songs',
|
||||
waitForAsync(() => {
|
||||
const service: SongDataService = TestBed.inject(SongDataService);
|
||||
service.list$().subscribe(s => {
|
||||
void expect(s[0].title).toEqual('title1');
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -4,19 +4,16 @@ import {Observable} from 'rxjs';
|
||||
import {DbService} from '../../../services/db.service';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SongDataService {
|
||||
private collection = 'songs';
|
||||
|
||||
constructor(private dbService: DbService) {
|
||||
}
|
||||
public constructor(private dbService: DbService) {}
|
||||
|
||||
public list$ = (): Observable<Song[]> => this.dbService.col$(this.collection);
|
||||
public read$ = (songId: string): Observable<Song | undefined> => this.dbService.doc$(this.collection + '/' + songId);
|
||||
public update$ = async (songId: string, data: Partial<Song>): Promise<void> => await this.dbService.doc(this.collection + '/' + songId).update(data);
|
||||
public add = async (data: Partial<Song>): Promise<string> => (await this.dbService.col(this.collection).add(data)).id;
|
||||
public delete = async (songId: string): Promise<void> => await this.dbService.doc(this.collection + '/' + songId).delete();
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -5,32 +5,31 @@ import {SongDataService} from './song-data.service';
|
||||
import {of} from 'rxjs';
|
||||
|
||||
describe('SongService', () => {
|
||||
|
||||
const songs = [
|
||||
{title: 'title1'}
|
||||
];
|
||||
const songs = [{title: 'title1'}];
|
||||
|
||||
const mockSongDataService = {
|
||||
list: () => of(songs)
|
||||
list: () => of(songs),
|
||||
};
|
||||
|
||||
beforeEach(() => TestBed.configureTestingModule({
|
||||
providers: [
|
||||
{provide: SongDataService, useValue: mockSongDataService}
|
||||
]
|
||||
}));
|
||||
beforeEach(
|
||||
() =>
|
||||
void TestBed.configureTestingModule({
|
||||
providers: [{provide: SongDataService, useValue: mockSongDataService}],
|
||||
})
|
||||
);
|
||||
|
||||
it('should be created', () => {
|
||||
const service: SongService = TestBed.get(SongService);
|
||||
expect(service).toBeTruthy();
|
||||
const service: SongService = TestBed.inject(SongService);
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should list songs', waitForAsync(() => {
|
||||
const service: SongService = TestBed.get(SongService);
|
||||
service.list$().subscribe(s => {
|
||||
expect(s).toEqual([
|
||||
{title: 'title1'}
|
||||
] as any);
|
||||
});
|
||||
}));
|
||||
it(
|
||||
'should list songs',
|
||||
waitForAsync(() => {
|
||||
const service: SongService = TestBed.inject(SongService);
|
||||
service.list$().subscribe(s => {
|
||||
void expect(s[0].title).toEqual('title1');
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
@@ -2,31 +2,30 @@ import {Injectable} from '@angular/core';
|
||||
import {Observable} from 'rxjs';
|
||||
import {Song} from './song';
|
||||
import {SongDataService} from './song-data.service';
|
||||
import {first, tap} from 'rxjs/operators';
|
||||
import {first} from 'rxjs/operators';
|
||||
import {UserService} from '../../../services/user/user.service';
|
||||
import * as firebase from 'firebase';
|
||||
import Timestamp = firebase.firestore.Timestamp;
|
||||
|
||||
declare var importCCLI: any;
|
||||
// declare let importCCLI: any;
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class SongService {
|
||||
|
||||
public static TYPES = ['Praise', 'Worship'];
|
||||
public static STATUS = ['draft', 'set', 'final'];
|
||||
|
||||
public static LEGAL_OWNER = ['CCLI', 'other'];
|
||||
public static LEGAL_TYPE = ['open', 'allowed'];
|
||||
|
||||
private list: Song[];
|
||||
// private list: Song[];
|
||||
|
||||
constructor(private songDataService: SongDataService, private userService: UserService) {
|
||||
importCCLI = (songs: Song[]) => this.updateFromCLI(songs);
|
||||
public constructor(private songDataService: SongDataService, private userService: UserService) {
|
||||
// importCCLI = (songs: Song[]) => this.updateFromCLI(songs);
|
||||
}
|
||||
|
||||
public list$ = (): Observable<Song[]> => this.songDataService.list$().pipe(tap(_ => this.list = _));
|
||||
public list$ = (): Observable<Song[]> => this.songDataService.list$(); //.pipe(tap(_ => (this.list = _)));
|
||||
public read$ = (songId: string): Observable<Song | undefined> => this.songDataService.read$(songId);
|
||||
public read = (songId: string): Promise<Song | undefined> => this.read$(songId).pipe(first()).toPromise();
|
||||
|
||||
@@ -38,38 +37,41 @@ export class SongService {
|
||||
await this.songDataService.update$(songId, {...data, edits});
|
||||
}
|
||||
|
||||
public async new(number: number, title: string): Promise<string> {
|
||||
return await this.songDataService.add({number, title, status: 'draft', legalType: 'open'});
|
||||
public async new(songNumber: number, title: string): Promise<string> {
|
||||
return await this.songDataService.add({
|
||||
number: songNumber,
|
||||
title,
|
||||
status: 'draft',
|
||||
legalType: 'open',
|
||||
});
|
||||
}
|
||||
|
||||
public async delete(songId: string): Promise<void> {
|
||||
await this.songDataService.delete(songId);
|
||||
}
|
||||
|
||||
// https://www.csvjson.com/csv2json
|
||||
private async updateFromCLI(songs: Song[]) {
|
||||
const mapped = songs.map(_ => ({
|
||||
number: _.number,
|
||||
legalType: _.legalType === 'ja' ? 'allowed' : 'open',
|
||||
legalOwner: _.legalOwner === 'ja' ? 'CCLI' : 'other',
|
||||
title: _.title,
|
||||
legalOwnerId: _.legalOwnerId,
|
||||
origin: _.origin,
|
||||
artist: _.artist,
|
||||
comment: _.comment
|
||||
}));
|
||||
const promises = this.list.map(async _ => {
|
||||
// tslint:disable-next-line:triple-equals
|
||||
const mappedSongs = mapped.filter(f => f.number == _.number);
|
||||
if (mappedSongs.length === 1) {
|
||||
const mappedSong = mappedSongs[0];
|
||||
const id = _.id;
|
||||
return await this.update$(id, mappedSong);
|
||||
}
|
||||
});
|
||||
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
|
||||
// https://www.csvjson.com/csv2json
|
||||
// private async updateFromCLI(songs: Song[]) {
|
||||
// const mapped = songs.map(_ => ({
|
||||
// number: _.number,
|
||||
// legalType: _.legalType === 'ja' ? 'allowed' : 'open',
|
||||
// legalOwner: _.legalOwner === 'ja' ? 'CCLI' : 'other',
|
||||
// title: _.title,
|
||||
// legalOwnerId: _.legalOwnerId,
|
||||
// origin: _.origin,
|
||||
// artist: _.artist,
|
||||
// comment: _.comment,
|
||||
// }));
|
||||
// const promises = this.list.map(async _ => {
|
||||
// // eslint-disable-next-line eqeqeq
|
||||
// const mappedSongs = mapped.filter(f => f.number == _.number);
|
||||
// if (mappedSongs.length === 1) {
|
||||
// const mappedSong = mappedSongs[0];
|
||||
// const id = _.id;
|
||||
// return await this.update$(id, mappedSong);
|
||||
// }
|
||||
// });
|
||||
//
|
||||
// await Promise.all(promises);
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import {TestBed} from '@angular/core/testing';
|
||||
|
||||
import {LineType, SectionType, TextRenderingService} from './text-rendering.service';
|
||||
import {TextRenderingService} from './text-rendering.service';
|
||||
import {LineType} from './line-type';
|
||||
import {SectionType} from './section-type';
|
||||
|
||||
describe('TextRenderingService', () => {
|
||||
const testText = `Strophe
|
||||
@@ -23,60 +24,59 @@ Bridge
|
||||
Cool bridge without any chords
|
||||
`;
|
||||
|
||||
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => void TestBed.configureTestingModule({}));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: TextRenderingService = TestBed.get(TextRenderingService);
|
||||
expect(service).toBeTruthy();
|
||||
const service: TextRenderingService = TestBed.inject(TextRenderingService);
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should parse section types', () => {
|
||||
const service: TextRenderingService = TestBed.get(TextRenderingService);
|
||||
const service: TextRenderingService = TestBed.inject(TextRenderingService);
|
||||
const sections = service.parse(testText, null);
|
||||
expect(sections[0].type).toBe(SectionType.Verse);
|
||||
expect(sections[0].number).toBe(0);
|
||||
expect(sections[1].type).toBe(SectionType.Verse);
|
||||
expect(sections[1].number).toBe(1);
|
||||
expect(sections[2].type).toBe(SectionType.Chorus);
|
||||
expect(sections[2].number).toBe(0);
|
||||
expect(sections[3].type).toBe(SectionType.Bridge);
|
||||
expect(sections[3].number).toBe(0);
|
||||
void expect(sections[0].type).toBe(SectionType.Verse);
|
||||
void expect(sections[0].number).toBe(0);
|
||||
void expect(sections[1].type).toBe(SectionType.Verse);
|
||||
void expect(sections[1].number).toBe(1);
|
||||
void expect(sections[2].type).toBe(SectionType.Chorus);
|
||||
void expect(sections[2].number).toBe(0);
|
||||
void expect(sections[3].type).toBe(SectionType.Bridge);
|
||||
void expect(sections[3].number).toBe(0);
|
||||
});
|
||||
|
||||
it('should parse text lines', () => {
|
||||
const service: TextRenderingService = TestBed.get(TextRenderingService);
|
||||
const service: TextRenderingService = TestBed.inject(TextRenderingService);
|
||||
const sections = service.parse(testText, null);
|
||||
expect(sections[0].lines[1].type).toBe(LineType.text);
|
||||
expect(sections[0].lines[1].text).toBe('Text Line 1-1');
|
||||
expect(sections[0].lines[3].type).toBe(LineType.text);
|
||||
expect(sections[0].lines[3].text).toBe('Text Line 2-1');
|
||||
expect(sections[1].lines[1].type).toBe(LineType.text);
|
||||
expect(sections[1].lines[1].text).toBe('Text Line 1-2');
|
||||
expect(sections[1].lines[3].type).toBe(LineType.text);
|
||||
expect(sections[1].lines[3].text).toBe('Text Line 2-2');
|
||||
expect(sections[2].lines[1].type).toBe(LineType.text);
|
||||
expect(sections[2].lines[1].text).toBe('and the chorus');
|
||||
expect(sections[3].lines[0].type).toBe(LineType.text);
|
||||
expect(sections[3].lines[0].text).toBe('Cool bridge without any chords');
|
||||
void expect(sections[0].lines[1].type).toBe(LineType.text);
|
||||
void expect(sections[0].lines[1].text).toBe('Text Line 1-1');
|
||||
void expect(sections[0].lines[3].type).toBe(LineType.text);
|
||||
void expect(sections[0].lines[3].text).toBe('Text Line 2-1');
|
||||
void expect(sections[1].lines[1].type).toBe(LineType.text);
|
||||
void expect(sections[1].lines[1].text).toBe('Text Line 1-2');
|
||||
void expect(sections[1].lines[3].type).toBe(LineType.text);
|
||||
void expect(sections[1].lines[3].text).toBe('Text Line 2-2');
|
||||
void expect(sections[2].lines[1].type).toBe(LineType.text);
|
||||
void expect(sections[2].lines[1].text).toBe('and the chorus');
|
||||
void expect(sections[3].lines[0].type).toBe(LineType.text);
|
||||
void expect(sections[3].lines[0].text).toBe('Cool bridge without any chords');
|
||||
});
|
||||
|
||||
it('should parse chord lines', () => {
|
||||
const service: TextRenderingService = TestBed.inject(TextRenderingService);
|
||||
const sections = service.parse(testText, null);
|
||||
expect(sections[0].lines[0].type).toBe(LineType.chord);
|
||||
expect(sections[0].lines[0].text).toBe('C D E F G A H');
|
||||
expect(sections[0].lines[2].type).toBe(LineType.chord);
|
||||
expect(sections[0].lines[2].text).toBe(' a d e f g a h c b');
|
||||
expect(sections[1].lines[0].type).toBe(LineType.chord);
|
||||
expect(sections[1].lines[0].text).toBe('C D E F G A H');
|
||||
expect(sections[1].lines[2].type).toBe(LineType.chord);
|
||||
expect(sections[1].lines[2].text).toBe(' a d e f g a h c b');
|
||||
expect(sections[2].lines[0].type).toBe(LineType.chord);
|
||||
expect(sections[2].lines[0].text).toBe('c c# db c7 cmaj7 c/e');
|
||||
void expect(sections[0].lines[0].type).toBe(LineType.chord);
|
||||
void expect(sections[0].lines[0].text).toBe('C D E F G A H');
|
||||
void expect(sections[0].lines[2].type).toBe(LineType.chord);
|
||||
void expect(sections[0].lines[2].text).toBe(' a d e f g a h c b');
|
||||
void expect(sections[1].lines[0].type).toBe(LineType.chord);
|
||||
void expect(sections[1].lines[0].text).toBe('C D E F G A H');
|
||||
void expect(sections[1].lines[2].type).toBe(LineType.chord);
|
||||
void expect(sections[1].lines[2].text).toBe(' a d e f g a h c b');
|
||||
void expect(sections[2].lines[0].type).toBe(LineType.chord);
|
||||
void expect(sections[2].lines[0].text).toBe('c c# db c7 cmaj7 c/e');
|
||||
|
||||
// c c# db c7 cmaj7 c/e
|
||||
expect(sections[2].lines[0].chords).toEqual([
|
||||
void expect(sections[2].lines[0].chords).toEqual([
|
||||
{chord: 'c', length: 1, position: 0},
|
||||
{chord: 'c#', length: 2, position: 2},
|
||||
{chord: 'db', length: 2, position: 5},
|
||||
@@ -92,10 +92,9 @@ Cool bridge without any chords
|
||||
g# F# E g# F# E
|
||||
text`;
|
||||
const sections = service.parse(text, null);
|
||||
expect(sections[0].lines[0].type).toBe(LineType.chord);
|
||||
expect(sections[0].lines[0].text).toBe('g# F# E g# F# E');
|
||||
expect(sections[0].lines[1].type).toBe(LineType.text);
|
||||
expect(sections[0].lines[1].text).toBe('text');
|
||||
|
||||
void expect(sections[0].lines[0].type).toBe(LineType.chord);
|
||||
void expect(sections[0].lines[0].text).toBe('g# F# E g# F# E');
|
||||
void expect(sections[0].lines[1].type).toBe(LineType.text);
|
||||
void expect(sections[0].lines[1].text).toBe('text');
|
||||
});
|
||||
});
|
||||
|
||||
@@ -8,13 +8,12 @@ import {Chord} from './chord';
|
||||
import {Line} from './line';
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class TextRenderingService {
|
||||
private regexSection = /(Strophe|Refrain|Bridge)/;
|
||||
|
||||
constructor(private transposeService: TransposeService) {
|
||||
}
|
||||
public constructor(private transposeService: TransposeService) {}
|
||||
|
||||
public parse(text: string, transpose: TransposeMode): Section[] {
|
||||
if (!text) {
|
||||
@@ -28,12 +27,15 @@ export class TextRenderingService {
|
||||
};
|
||||
return arrayOfLines.reduce((array, line) => {
|
||||
const type = this.getSectionTypeOfLine(line);
|
||||
if (line.match(this.regexSection)) {
|
||||
return [...array, {
|
||||
type,
|
||||
number: indices[type]++,
|
||||
lines: []
|
||||
}];
|
||||
if (this.regexSection.exec(line)) {
|
||||
return [
|
||||
...array,
|
||||
{
|
||||
type,
|
||||
number: indices[type]++,
|
||||
lines: [],
|
||||
},
|
||||
];
|
||||
}
|
||||
array[array.length - 1].lines.push(this.getLineOfLineText(line, transpose));
|
||||
return array;
|
||||
@@ -49,36 +51,35 @@ export class TextRenderingService {
|
||||
const type = hasMatches ? LineType.chord : LineType.text;
|
||||
|
||||
const line = {type, text, chords: hasMatches ? cords : undefined};
|
||||
return transpose
|
||||
? this.transposeService.transpose(line, transpose.baseKey, transpose.targetKey)
|
||||
: this.transposeService.renderChords(line);
|
||||
return transpose ? this.transposeService.transpose(line, transpose.baseKey, transpose.targetKey) : this.transposeService.renderChords(line);
|
||||
}
|
||||
|
||||
private getSectionTypeOfLine(line: string): SectionType {
|
||||
if (!line) {
|
||||
return null;
|
||||
}
|
||||
const match = line.match(this.regexSection);
|
||||
const match = this.regexSection.exec(line);
|
||||
if (!match || match.length < 2) {
|
||||
return null;
|
||||
}
|
||||
const typeString = match[1];
|
||||
switch (typeString) {
|
||||
case 'Strophe':
|
||||
case 'Strophe':
|
||||
return SectionType.Verse;
|
||||
case 'Refrain':
|
||||
case 'Refrain':
|
||||
return SectionType.Chorus;
|
||||
case 'Bridge':
|
||||
case 'Bridge':
|
||||
return SectionType.Bridge;
|
||||
}
|
||||
}
|
||||
|
||||
private readChords(chordLine: string): Chord[] {
|
||||
let match;
|
||||
let match: string[];
|
||||
const chords: Chord[] = [];
|
||||
|
||||
// https://regex101.com/r/68jMB8/5
|
||||
const regex = /(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?/mg;
|
||||
const regex =
|
||||
/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h)(\/(C#|C|Db|D#|D|Eb|E|F#|F|Gb|G#|G|Ab|A#|A|B|H|c#|c|db|d#|d|eb|e|f#|f|gb|g#|g|ab|a#|a|b|h))?(\d+|maj7)?/gm;
|
||||
|
||||
while ((match = regex.exec(chordLine)) !== null) {
|
||||
const chord: Chord = {
|
||||
@@ -101,5 +102,4 @@ export class TextRenderingService {
|
||||
const isChrod = chordCount * 1.2 > lineCount;
|
||||
return isChrod ? chords : [];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ describe('TransposeService', () => {
|
||||
let service: TransposeService;
|
||||
|
||||
beforeEach(() => {
|
||||
TestBed.configureTestingModule({});
|
||||
void TestBed.configureTestingModule({});
|
||||
service = TestBed.inject(TransposeService);
|
||||
});
|
||||
|
||||
@@ -15,6 +15,6 @@ describe('TransposeService', () => {
|
||||
const map = service.getMap('D', distance);
|
||||
|
||||
console.log(map);
|
||||
expect(service).toBeTruthy();
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -4,11 +4,12 @@ import {LineType} from './line-type';
|
||||
import {Chord} from './chord';
|
||||
import {Line} from './line';
|
||||
|
||||
type TransposeMap = {[key: string]: string};
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class TransposeService {
|
||||
|
||||
public transpose(line: Line, baseKey: string, targetKey: string): Line {
|
||||
if (line.type !== LineType.chord) {
|
||||
return line;
|
||||
@@ -33,13 +34,10 @@ export class TransposeService {
|
||||
|
||||
public getDistance(baseKey: string, targetKey: string): number {
|
||||
const scale = getScaleType(baseKey);
|
||||
return scale ? (
|
||||
(scale[0].indexOf(targetKey) - scale[0].indexOf(baseKey)) ??
|
||||
(scale[1].indexOf(targetKey) - scale[1].indexOf(baseKey))
|
||||
) % 12 : 0;
|
||||
return scale ? (scale[0].indexOf(targetKey) - scale[0].indexOf(baseKey) ?? scale[1].indexOf(targetKey) - scale[1].indexOf(baseKey)) % 12 : 0;
|
||||
}
|
||||
|
||||
public getMap(baseKey: string, difference: number) {
|
||||
public getMap(baseKey: string, difference: number): TransposeMap | null {
|
||||
const scale = getScaleType(baseKey);
|
||||
if (!scale) {
|
||||
return null;
|
||||
@@ -59,10 +57,14 @@ export class TransposeService {
|
||||
return map;
|
||||
}
|
||||
|
||||
private transposeChord(chord: Chord, map: {}): Chord {
|
||||
private transposeChord(chord: Chord, map: TransposeMap): Chord {
|
||||
const translatedChord = map[chord.chord];
|
||||
const translatedSlashChord = chord.slashChord ? map[chord.slashChord] : null;
|
||||
return {...chord, chord: translatedChord, slashChord: translatedSlashChord};
|
||||
return {
|
||||
...chord,
|
||||
chord: translatedChord,
|
||||
slashChord: translatedSlashChord,
|
||||
};
|
||||
}
|
||||
|
||||
private renderLine(chords: Chord[]): string {
|
||||
@@ -83,9 +85,6 @@ export class TransposeService {
|
||||
}
|
||||
|
||||
private renderChord(chord: Chord) {
|
||||
return (
|
||||
scaleMapping[chord.chord] +
|
||||
(chord.add ? chord.add : '') +
|
||||
(chord.slashChord ? '/' + scaleMapping[chord.slashChord] : ''));
|
||||
return scaleMapping[chord.chord] + (chord.add ? chord.add : '') + (chord.slashChord ? '/' + scaleMapping[chord.slashChord] : '');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,10 +3,10 @@ import {TestBed} from '@angular/core/testing';
|
||||
import {UploadService} from './upload.service';
|
||||
|
||||
describe('UploadServiceService', () => {
|
||||
beforeEach(() => TestBed.configureTestingModule({}));
|
||||
beforeEach(() => void TestBed.configureTestingModule({}));
|
||||
|
||||
it('should be created', () => {
|
||||
const service: UploadService = TestBed.get(UploadService);
|
||||
expect(service).toBeTruthy();
|
||||
const service: UploadService = TestBed.inject(UploadService);
|
||||
void expect(service).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -6,17 +6,15 @@ import {finalize} from 'rxjs/operators';
|
||||
import {FileBase} from './fileBase';
|
||||
import {FileServer} from './fileServer';
|
||||
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
providedIn: 'root',
|
||||
})
|
||||
export class UploadService extends FileBase {
|
||||
|
||||
constructor(private fileDataService: FileDataService, private angularFireStorage: AngularFireStorage) {
|
||||
public constructor(private fileDataService: FileDataService, private angularFireStorage: AngularFireStorage) {
|
||||
super();
|
||||
}
|
||||
|
||||
public async pushUpload(songId: string, upload: Upload) {
|
||||
public pushUpload(songId: string, upload: Upload): void {
|
||||
const directory = this.directory(songId);
|
||||
const filePath = `${directory}/${upload.file.name}`;
|
||||
upload.path = directory;
|
||||
@@ -24,20 +22,18 @@ export class UploadService extends FileBase {
|
||||
const ref = this.angularFireStorage.ref(filePath);
|
||||
const task = ref.put(upload.file);
|
||||
|
||||
task.percentageChanges().subscribe(percent => upload.progress = percent);
|
||||
task.snapshotChanges().pipe(
|
||||
finalize(() => {
|
||||
this.saveFileData(songId, upload);
|
||||
})
|
||||
).subscribe();
|
||||
|
||||
task.percentageChanges().subscribe(percent => (upload.progress = percent));
|
||||
task
|
||||
.snapshotChanges()
|
||||
.pipe(finalize(() => void this.saveFileData(songId, upload)))
|
||||
.subscribe();
|
||||
}
|
||||
|
||||
private async saveFileData(songId: string, upload: Upload) {
|
||||
const file: FileServer = {
|
||||
name: upload.file.name,
|
||||
path: upload.path,
|
||||
createdAt: new Date()
|
||||
createdAt: new Date(),
|
||||
};
|
||||
await this.fileDataService.set(songId, file);
|
||||
}
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
export class Upload {
|
||||
public $key: string;
|
||||
public file: File;
|
||||
public name: string;
|
||||
public path: string;
|
||||
public progress: number;
|
||||
public createdAt: Date = new Date();
|
||||
|
||||
$key: string;
|
||||
file: Upload;
|
||||
name: string;
|
||||
path: string;
|
||||
progress: number;
|
||||
createdAt: Date = new Date();
|
||||
|
||||
constructor(file: Upload) {
|
||||
public constructor(file: File) {
|
||||
this.file = file;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user