├── .editorconfig ├── .gitignore ├── README.md ├── angular.json ├── e2e ├── protractor.conf.js ├── src │ ├── app.e2e-spec.ts │ └── app.po.ts └── tsconfig.e2e.json ├── package-lock.json ├── package.json ├── src ├── app │ ├── biger-music-routing.module.ts │ ├── biger-music.component.html │ ├── biger-music.component.scss │ ├── biger-music.component.ts │ ├── biger-music.module.ts │ ├── core │ │ ├── core.module.ts │ │ └── player.service.ts │ ├── modules │ │ └── music │ │ │ ├── music.component.html │ │ │ ├── music.component.scss │ │ │ ├── music.component.ts │ │ │ └── music.module.ts │ └── shared │ │ ├── components │ │ ├── header │ │ │ ├── header.component.html │ │ │ ├── header.component.scss │ │ │ └── header.component.ts │ │ ├── mini-player │ │ │ ├── mini-player.component.html │ │ │ ├── mini-player.component.scss │ │ │ └── mini-player.component.ts │ │ ├── progress │ │ │ ├── progress.component.html │ │ │ ├── progress.component.scss │ │ │ ├── progress.component.ts │ │ │ └── utilities.ts │ │ └── volume-slider │ │ │ ├── volume-slider.component.html │ │ │ ├── volume-slider.component.scss │ │ │ └── volume-slider.component.ts │ │ ├── decorators │ │ └── auto-unsubscribe.decorator.ts │ │ ├── enums │ │ └── index.ts │ │ ├── shared.module.ts │ │ └── types │ │ └── index.ts ├── assets │ ├── .gitkeep │ ├── data.json │ └── images │ │ ├── background-dark.jpg │ │ └── lizhi.png ├── browserslist ├── environments │ ├── environment.prod.ts │ └── environment.ts ├── favicon.ico ├── index.html ├── karma.conf.js ├── main.ts ├── polyfills.ts ├── scss │ ├── _components.scss │ └── _variables.scss ├── styles.scss ├── test.ts ├── tsconfig.app.json ├── tsconfig.spec.json └── tslint.json ├── tsconfig.json └── tslint.json /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see https://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 4 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | 11 | [*.md] 12 | max_line_length = off 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See http://help.github.com/ignore-files/ for more about ignoring files. 2 | 3 | # compiled output 4 | /dist 5 | /tmp 6 | /out-tsc 7 | # Only exists if Bazel was run 8 | /bazel-out 9 | 10 | # dependencies 11 | /node_modules 12 | 13 | # profiling files 14 | chrome-profiler-events.json 15 | speed-measure-plugin.json 16 | 17 | # IDEs and editors 18 | /.idea 19 | .project 20 | .classpath 21 | .c9/ 22 | *.launch 23 | .settings/ 24 | *.sublime-workspace 25 | 26 | # IDE - VSCode 27 | .vscode/* 28 | !.vscode/settings.json 29 | !.vscode/tasks.json 30 | !.vscode/launch.json 31 | !.vscode/extensions.json 32 | .history/* 33 | 34 | # misc 35 | /.sass-cache 36 | /connect.lock 37 | /coverage 38 | /libpeerconnection.log 39 | npm-debug.log 40 | yarn-error.log 41 | testem.log 42 | /typings 43 | 44 | # System Files 45 | .DS_Store 46 | Thumbs.db 47 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Biger Music 2 | #### 一个逼粉的音乐播放器 3 | 4 | 项目还在开发中,目前完成了基本的播放功能 5 | 6 | --------- 7 | > 逼哥曾经说过 "不要忽视你们的力量" ,作为一个逼粉我觉得是时候该做些什么了,所以就开发了这个项目,目的是让更多的人听到逼哥的歌并让更多的人知道有李志这样一个民谣歌手。 8 | 9 | **「 我们不能失去信仰 」** 10 | 11 | #### 在线播放: 12 | 13 | + https://biger.webhcj.net 14 | + https://tian-hun.github.io/biger-music 15 | 16 | 17 | #### 已添加的专辑: 18 | 19 | > ![洗心革面](http://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0) 20 | 21 | #### 第三方 22 | > 歌词编辑工具: https://github.com/magic-akari/lrc-maker 23 | -------------------------------------------------------------------------------- /angular.json: -------------------------------------------------------------------------------- 1 | { 2 | "$schema": "./node_modules/@angular/cli/lib/config/schema.json", 3 | "version": 1, 4 | "newProjectRoot": "projects", 5 | "projects": { 6 | "biger-music": { 7 | "root": "src", 8 | "sourceRoot": "src", 9 | "projectType": "application", 10 | "prefix": "biger", 11 | "schematics": { 12 | "@schematics/angular:component": { 13 | "style": "scss" 14 | } 15 | }, 16 | "architect": { 17 | "build": { 18 | "builder": "@angular-devkit/build-angular:browser", 19 | "options": { 20 | "outputPath": "dist/biger-music", 21 | "index": "src/index.html", 22 | "main": "src/main.ts", 23 | "polyfills": "src/polyfills.ts", 24 | "tsConfig": "src/tsconfig.app.json", 25 | "assets": [ 26 | "src/favicon.ico", 27 | "src/assets" 28 | ], 29 | "styles": [ 30 | "src/styles.scss" 31 | ], 32 | "stylePreprocessorOptions": { 33 | "includePaths": [ 34 | "src/scss" 35 | ] 36 | }, 37 | "scripts": [ 38 | "./node_modules/gsap/umd/TweenMax.js" 39 | ], 40 | "es5BrowserSupport": true 41 | }, 42 | "configurations": { 43 | "production": { 44 | "fileReplacements": [ 45 | { 46 | "replace": "src/environments/environment.ts", 47 | "with": "src/environments/environment.prod.ts" 48 | } 49 | ], 50 | "optimization": true, 51 | "outputHashing": "all", 52 | "sourceMap": false, 53 | "extractCss": true, 54 | "namedChunks": false, 55 | "aot": true, 56 | "extractLicenses": true, 57 | "vendorChunk": false, 58 | "buildOptimizer": false, 59 | "budgets": [ 60 | { 61 | "type": "initial", 62 | "maximumWarning": "2mb", 63 | "maximumError": "5mb" 64 | } 65 | ] 66 | } 67 | } 68 | }, 69 | "serve": { 70 | "builder": "@angular-devkit/build-angular:dev-server", 71 | "options": { 72 | "browserTarget": "biger-music:build" 73 | }, 74 | "configurations": { 75 | "production": { 76 | "browserTarget": "biger-music:build:production" 77 | } 78 | } 79 | }, 80 | "extract-i18n": { 81 | "builder": "@angular-devkit/build-angular:extract-i18n", 82 | "options": { 83 | "browserTarget": "biger-music:build" 84 | } 85 | }, 86 | "test": { 87 | "builder": "@angular-devkit/build-angular:karma", 88 | "options": { 89 | "main": "src/test.ts", 90 | "polyfills": "src/polyfills.ts", 91 | "tsConfig": "src/tsconfig.spec.json", 92 | "karmaConfig": "src/karma.conf.js", 93 | "styles": [ 94 | "src/styles.scss" 95 | ], 96 | "scripts": [], 97 | "assets": [ 98 | "src/favicon.ico", 99 | "src/assets" 100 | ] 101 | } 102 | }, 103 | "lint": { 104 | "builder": "@angular-devkit/build-angular:tslint", 105 | "options": { 106 | "tsConfig": [ 107 | "src/tsconfig.app.json", 108 | "src/tsconfig.spec.json" 109 | ], 110 | "exclude": [ 111 | "**/node_modules/**" 112 | ] 113 | } 114 | } 115 | } 116 | }, 117 | "biger-music-e2e": { 118 | "root": "e2e/", 119 | "projectType": "application", 120 | "prefix": "", 121 | "architect": { 122 | "e2e": { 123 | "builder": "@angular-devkit/build-angular:protractor", 124 | "options": { 125 | "protractorConfig": "e2e/protractor.conf.js", 126 | "devServerTarget": "biger-music:serve" 127 | }, 128 | "configurations": { 129 | "production": { 130 | "devServerTarget": "biger-music:serve:production" 131 | } 132 | } 133 | }, 134 | "lint": { 135 | "builder": "@angular-devkit/build-angular:tslint", 136 | "options": { 137 | "tsConfig": "e2e/tsconfig.e2e.json", 138 | "exclude": [ 139 | "**/node_modules/**" 140 | ] 141 | } 142 | } 143 | } 144 | } 145 | }, 146 | "defaultProject": "biger-music" 147 | } 148 | -------------------------------------------------------------------------------- /e2e/protractor.conf.js: -------------------------------------------------------------------------------- 1 | // Protractor configuration file, see link for more information 2 | // https://github.com/angular/protractor/blob/master/lib/config.ts 3 | 4 | const { SpecReporter } = require('jasmine-spec-reporter'); 5 | 6 | exports.config = { 7 | allScriptsTimeout: 11000, 8 | specs: [ 9 | './src/**/*.e2e-spec.ts' 10 | ], 11 | capabilities: { 12 | 'browserName': 'chrome' 13 | }, 14 | directConnect: true, 15 | baseUrl: 'http://localhost:4200/', 16 | framework: 'jasmine', 17 | jasmineNodeOpts: { 18 | showColors: true, 19 | defaultTimeoutInterval: 30000, 20 | print: function() {} 21 | }, 22 | onPrepare() { 23 | require('ts-node').register({ 24 | project: require('path').join(__dirname, './tsconfig.e2e.json') 25 | }); 26 | jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); 27 | } 28 | }; -------------------------------------------------------------------------------- /e2e/src/app.e2e-spec.ts: -------------------------------------------------------------------------------- 1 | import { AppPage } from './app.po'; 2 | import { browser, logging } from 'protractor'; 3 | 4 | describe('workspace-project App', () => { 5 | let page: AppPage; 6 | 7 | beforeEach(() => { 8 | page = new AppPage(); 9 | }); 10 | 11 | it('should display welcome message', () => { 12 | page.navigateTo(); 13 | expect(page.getTitleText()).toEqual('Welcome to biger-music!'); 14 | }); 15 | 16 | afterEach(async () => { 17 | // Assert that there are no errors emitted from the browser 18 | const logs = await browser.manage().logs().get(logging.Type.BROWSER); 19 | expect(logs).not.toContain(jasmine.objectContaining({ 20 | level: logging.Level.SEVERE, 21 | } as logging.Entry)); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /e2e/src/app.po.ts: -------------------------------------------------------------------------------- 1 | import { browser, by, element } from 'protractor'; 2 | 3 | export class AppPage { 4 | navigateTo() { 5 | return browser.get(browser.baseUrl) as Promise; 6 | } 7 | 8 | getTitleText() { 9 | return element(by.css('app-root h1')).getText() as Promise; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /e2e/tsconfig.e2e.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "module": "commonjs", 6 | "target": "es5", 7 | "types": [ 8 | "jasmine", 9 | "jasminewd2", 10 | "node" 11 | ] 12 | } 13 | } -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "biger-music", 3 | "version": "0.0.0", 4 | "scripts": { 5 | "ng": "ng", 6 | "start": "ng serve", 7 | "build": "ng build", 8 | "test": "ng test", 9 | "lint": "ng lint", 10 | "e2e": "ng e2e", 11 | "deploy": "ng build --prod --base-href /biger-music/ && angular-cli-ghpages --dir ./dist/biger-music/" 12 | }, 13 | "private": true, 14 | "dependencies": { 15 | "@angular/animations": "~8.0.0-rc.5", 16 | "@angular/common": "~8.0.0-rc.5", 17 | "@angular/compiler": "~8.0.0-rc.5", 18 | "@angular/core": "~8.0.0-rc.5", 19 | "@angular/forms": "~8.0.0-rc.5", 20 | "@angular/platform-browser": "~8.0.0-rc.5", 21 | "@angular/platform-browser-dynamic": "~8.0.0-rc.5", 22 | "@angular/router": "~8.0.0-rc.5", 23 | "angular-tslint-rules": "^1.14.0", 24 | "core-js": "^2.5.4", 25 | "gsap": "^2.1.3", 26 | "hammerjs": "^2.0.8", 27 | "howler": "^2.1.2", 28 | "localforage": "^1.7.3", 29 | "ngforage": "^4.0.3", 30 | "rxjs": "~6.5.2", 31 | "tslib": "^1.9.0", 32 | "zone.js": "~0.9.1" 33 | }, 34 | "devDependencies": { 35 | "@angular-devkit/build-angular": "~0.800.0-rc.4", 36 | "@angular/cli": "~8.0.0-rc.4", 37 | "@angular/compiler-cli": "~8.0.0-rc.5", 38 | "@angular/language-service": "~8.0.0-rc.5", 39 | "@types/gsap": "^1.20.2", 40 | "@types/howler": "^2.1.0", 41 | "@types/jasmine": "~2.8.8", 42 | "@types/jasminewd2": "~2.0.3", 43 | "@types/node": "~8.9.4", 44 | "angular-cli-ghpages": "^0.5.3", 45 | "codelyzer": "^5.0.1", 46 | "jasmine-core": "~2.99.1", 47 | "jasmine-spec-reporter": "~4.2.1", 48 | "karma": "~4.0.0", 49 | "karma-chrome-launcher": "~2.2.0", 50 | "karma-coverage-istanbul-reporter": "~2.0.1", 51 | "karma-jasmine": "~1.1.2", 52 | "karma-jasmine-html-reporter": "^0.2.2", 53 | "protractor": "~5.4.0", 54 | "ts-node": "~7.0.0", 55 | "tslint": "~5.11.0", 56 | "typescript": "~3.4.5" 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /src/app/biger-music-routing.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { RouterModule, Routes } from '@angular/router'; 3 | 4 | const routes: Routes = [ 5 | { 6 | path: '', 7 | redirectTo: 'music', 8 | pathMatch: 'full' 9 | }, 10 | { 11 | path: 'music', 12 | loadChildren: () => import('./modules/music/music.module').then(m => m.MusicModule) 13 | } 14 | ]; 15 | 16 | @NgModule({ 17 | imports: [RouterModule.forRoot(routes)], 18 | exports: [RouterModule] 19 | }) 20 | export class BigerMusicRoutingModule { 21 | } 22 | -------------------------------------------------------------------------------- /src/app/biger-music.component.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /src/app/biger-music.component.scss: -------------------------------------------------------------------------------- 1 | :host { 2 | } 3 | -------------------------------------------------------------------------------- /src/app/biger-music.component.ts: -------------------------------------------------------------------------------- 1 | import { Component } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'biger-root', 5 | templateUrl: './biger-music.component.html', 6 | styleUrls: ['./biger-music.component.scss'] 7 | }) 8 | export class BigerMusicComponent { 9 | title = 'biger-music'; 10 | } 11 | -------------------------------------------------------------------------------- /src/app/biger-music.module.ts: -------------------------------------------------------------------------------- 1 | import { BrowserModule } from '@angular/platform-browser'; 2 | import { NgModule } from '@angular/core'; 3 | import { DEFAULT_CONFIG, Driver, NgForageOptions } from 'ngforage'; 4 | import 'hammerjs'; 5 | 6 | import { CoreModule } from '@core/core.module'; 7 | import { SharedModule } from '@shared/shared.module'; 8 | import { BigerMusicRoutingModule } from './biger-music-routing.module'; 9 | import { BigerMusicComponent } from './biger-music.component'; 10 | 11 | const ngForageOptions: NgForageOptions = { 12 | name: 'BigerMusic', 13 | driver: [ // defaults to indexedDB -> webSQL -> localStorage 14 | Driver.INDEXED_DB, 15 | Driver.LOCAL_STORAGE 16 | ] 17 | }; 18 | 19 | @NgModule({ 20 | declarations: [ 21 | BigerMusicComponent 22 | ], 23 | imports: [ 24 | BrowserModule, 25 | CoreModule, 26 | SharedModule, 27 | BigerMusicRoutingModule, 28 | ], 29 | providers: [ 30 | { 31 | provide: DEFAULT_CONFIG, 32 | useValue: ngForageOptions 33 | } 34 | ], 35 | bootstrap: [BigerMusicComponent] 36 | }) 37 | export class BigerMusicModule { 38 | } 39 | -------------------------------------------------------------------------------- /src/app/core/core.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { HttpClientModule } from '@angular/common/http'; 3 | 4 | @NgModule({ 5 | declarations: [], 6 | imports: [ 7 | HttpClientModule 8 | ] 9 | }) 10 | export class CoreModule { } 11 | -------------------------------------------------------------------------------- /src/app/core/player.service.ts: -------------------------------------------------------------------------------- 1 | import { Injectable } from '@angular/core'; 2 | import { HttpClient } from '@angular/common/http'; 3 | import { Howl, Howler } from 'howler'; 4 | import { NgForage } from 'ngforage'; 5 | import { BehaviorSubject, combineLatest, from, Observable } from 'rxjs'; 6 | import { map, shareReplay } from 'rxjs/operators'; 7 | import { Album, Progress, Song } from '@shared/types'; 8 | import { Direction, LoopMode } from '@shared/enums'; 9 | 10 | export const _playlistKey = 'PLAY_LIST'; 11 | 12 | @Injectable({ 13 | providedIn: 'root' 14 | }) 15 | export class PlayerService { 16 | 17 | dataUrl = 'assets/data.json'; 18 | albums: Array; 19 | songChange: BehaviorSubject = new BehaviorSubject(void (0)); 20 | progress: Progress; 21 | analyserChange: BehaviorSubject = new BehaviorSubject(void (0)); 22 | playingChange: BehaviorSubject = new BehaviorSubject(false); 23 | 24 | private currentIndex = 0; 25 | private randomLoop = false; 26 | private _sound: Howl; 27 | private _playlist: Array; 28 | private _progressValue: BehaviorSubject = new BehaviorSubject(0); 29 | private _progressTime: BehaviorSubject<{original: number, format: string}> = 30 | new BehaviorSubject<{original: number, format: string}>({original: 0, format: '00:00'}); 31 | private _progressLoaded: BehaviorSubject = new BehaviorSubject(false); 32 | 33 | get progressValue(): Observable { 34 | return this._progressValue.asObservable(); 35 | } 36 | 37 | get progressTime(): Observable<{original: number, format: string}> { 38 | return this._progressTime.asObservable(); 39 | } 40 | 41 | get progressLoaded(): Observable { 42 | return this._progressLoaded.asObservable(); 43 | } 44 | 45 | constructor( 46 | private http: HttpClient, 47 | private ngForage: NgForage 48 | ) { 49 | this.initialize(); 50 | 51 | this.progress = { 52 | duration: '', 53 | value: this.progressValue, 54 | time: this.progressTime, 55 | loaded: this.progressLoaded 56 | }; 57 | } 58 | 59 | private initialize(): void { 60 | combineLatest( 61 | this.http.get(this.dataUrl) 62 | .pipe( 63 | shareReplay(1), 64 | map((data: any) => data.albums) 65 | ), 66 | from(this.ngForage.getItem(_playlistKey)) 67 | ) 68 | .pipe(map(([albums, songs]) => ({albums, songs}))) 69 | .subscribe((data: {albums: Array, songs: Array}) => { 70 | this.albums = data.albums; 71 | if (!data.songs) { 72 | this._playlist = data.albums[0].songs; 73 | 74 | this.ngForage.setItem(_playlistKey, this._playlist) 75 | .then(_ => { 76 | this.progress.duration = this.durationStr; 77 | }); 78 | } else { 79 | this._playlist = data.songs; 80 | this.progress.duration = this.durationStr; 81 | } 82 | 83 | this.songChange.next(this._playlist[0]); 84 | }); 85 | } 86 | 87 | private createAnalyser(): void { 88 | const analyser = Howler.ctx.createAnalyser(); 89 | Howler.masterGain.connect(analyser); 90 | this.analyserChange.next(analyser); 91 | } 92 | 93 | get sound(): Howl { 94 | const song = this._playlist[this.currentIndex]; 95 | if (song.howl && song.howl.state() !== 'unloaded') { 96 | this._sound = song.howl; 97 | } else { 98 | this._sound = song.howl = new Howl({ 99 | src: [song.url], 100 | preload: true, 101 | html5: false, 102 | onplay: () => { 103 | this.playingChange.next(true); 104 | this._progressLoaded.next(true); 105 | requestAnimationFrame(this.step.bind(this)); 106 | this.createAnalyser(); 107 | }, 108 | onpause: () => { 109 | this.playingChange.next(false); 110 | }, 111 | onstop: () => { 112 | this.playingChange.next(false); 113 | }, 114 | onseek: () => requestAnimationFrame(this.step.bind(this)), 115 | onload: () => this._progressLoaded.next(true), 116 | onend: () => !this.sound.loop() && this.skip(this.randomLoop ? Direction.random : Direction.next), 117 | onloaderror: err => console.log(err), 118 | onplayerror: err => console.log(err) 119 | }); 120 | } 121 | 122 | return this._sound; 123 | } 124 | 125 | private get durationStr(): string { 126 | return formatTime(Math.round(this.sound.duration())); 127 | } 128 | 129 | public play(index?): void { 130 | if (index !== void(0)) { 131 | this.currentIndex = index; 132 | } 133 | this.songChange.next(this._playlist[this.currentIndex]); 134 | this.sound.play(); 135 | } 136 | 137 | public pause(): void { 138 | this.sound.pause(); 139 | } 140 | 141 | public skip(direction: Direction): void { 142 | this._progressLoaded.next(false); 143 | 144 | let index = 0; 145 | if (direction === Direction.prev) { 146 | index = this.currentIndex - 1; 147 | if (index < 0) { 148 | index = this._playlist.length - 1; 149 | } 150 | } else if (direction === Direction.next) { 151 | index = this.currentIndex + 1; 152 | if (index >= this._playlist.length) { 153 | index = 0; 154 | } 155 | } else { 156 | index = randomNumber(0, this._playlist.length - 1); 157 | } 158 | 159 | this.skipTo(index); 160 | } 161 | 162 | public skipTo(index: number): void { 163 | const song = this._playlist[this.currentIndex]; 164 | if (song.howl) { 165 | if (song.howl.state() === 'loading') { 166 | song.howl.unload(); 167 | } else { 168 | song.howl.stop(); 169 | } 170 | } 171 | 172 | this.play(index); 173 | } 174 | 175 | public loop(mode: LoopMode): void { 176 | const loopActions = [ 177 | () => true, 178 | () => this.sound.loop(true), 179 | () => this.randomLoop = true 180 | ]; 181 | 182 | loopActions[mode](); 183 | } 184 | 185 | public volume(value?: number): void | number { 186 | if (value !== void (0)) { 187 | Howler.volume(value); 188 | } else { 189 | return Howler.volume() * 100; 190 | } 191 | } 192 | 193 | public seek(percentage: number): void { 194 | this.sound.seek(this.sound.duration() * percentage); 195 | } 196 | 197 | public step(): void { 198 | const seek: number = (this.sound.seek() as number) || 0; 199 | this._progressTime.next({original: seek, format: formatTime(Math.round(seek))}); 200 | this._progressValue.next(Number((((seek / this.sound.duration()) * 100) || 0))); 201 | 202 | if (this.sound.playing()) { 203 | setTimeout(() => requestAnimationFrame(this.step.bind(this)), 500); 204 | } 205 | } 206 | } 207 | 208 | export function formatTime(secs: number): string { 209 | const minutes = Math.floor(secs / 60) || 0; 210 | const seconds = (secs - minutes * 60) || 0; 211 | 212 | return `${(minutes < 10 ? '0' : '') + minutes}:${(seconds < 10 ? '0' : '') + seconds}`; 213 | } 214 | 215 | export function randomNumber(minNum: number, maxNum: number): number { 216 | return Math.floor(Math.random() * (maxNum - minNum + 1) + minNum); 217 | } 218 | -------------------------------------------------------------------------------- /src/app/modules/music/music.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |

{{lyric[1]}}

4 |
5 |
6 | 7 | 8 | -------------------------------------------------------------------------------- /src/app/modules/music/music.component.scss: -------------------------------------------------------------------------------- 1 | .lyric-wrapper { 2 | position: absolute; 3 | width: 650px; 4 | height: 65%; 5 | top: 100px; 6 | left: 50%; 7 | transform: translateX(-325px); 8 | overflow: hidden; 9 | z-index: 10; 10 | 11 | .lyric-inner { 12 | transition: top 300ms ease-out; 13 | transform-origin: 0 0 0; 14 | position: absolute; 15 | left: 10px; 16 | right: 10px; 17 | top: 280px; 18 | 19 | p { 20 | overflow: hidden; 21 | height: 42px; 22 | line-height: 42px; 23 | text-overflow: ellipsis; 24 | white-space: nowrap; 25 | font-size: 16px; 26 | color: rgba(225, 225, 225, .6); 27 | text-align: center; 28 | margin: 0; 29 | 30 | &.active { 31 | font-size: 20px; 32 | color: #FFF; 33 | } 34 | } 35 | } 36 | } 37 | 38 | canvas { 39 | position: fixed; 40 | left: 0; 41 | top: 0; 42 | width: 100vw; 43 | height: 100vh; 44 | } 45 | -------------------------------------------------------------------------------- /src/app/modules/music/music.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnInit, ViewChild, OnDestroy } from '@angular/core'; 2 | import { PlayerService } from '@core/player.service'; 3 | import { distinctUntilChanged, filter } from 'rxjs/operators'; 4 | import { AutoUnsubscribe } from '@shared/decorators/auto-unsubscribe.decorator'; 5 | 6 | @AutoUnsubscribe() 7 | @Component({ 8 | selector: 'biger-home', 9 | templateUrl: './music.component.html', 10 | styleUrls: ['./music.component.scss'] 11 | }) 12 | export class MusicComponent implements OnInit, OnDestroy { 13 | 14 | @ViewChild('canvas', {static: true}) canvasElementRef: ElementRef; 15 | 16 | lyrics: Array; 17 | currentIndex: number; 18 | analyser: any; 19 | bufferLength: any; 20 | dataArray: Uint8Array; 21 | canvasElement: HTMLCanvasElement; 22 | 23 | frequencyBarGraphs: { 24 | fullWidth: number; 25 | fullHeight: number; 26 | barWidth: number; 27 | barHeight: number; 28 | x: number; 29 | ctx: any; 30 | }; 31 | 32 | constructor( 33 | private player: PlayerService, 34 | ) { 35 | } 36 | 37 | initialize(analyser): void { 38 | this.analyser = analyser; 39 | this.analyser.fftSize = 256; 40 | this.bufferLength = this.analyser.frequencyBinCount; 41 | this.frequencyBarGraphs.barWidth = (this.canvasElement.width / this.bufferLength) * 2.5; 42 | this.dataArray = new Uint8Array(this.bufferLength); 43 | } 44 | 45 | ngOnInit(): void { 46 | this.canvasElement = this.canvasElementRef.nativeElement; 47 | this.canvasElement.width = window.innerWidth; 48 | this.canvasElement.height = window.innerHeight; 49 | 50 | this.player 51 | .analyserChange 52 | .pipe(filter(analyser => !!analyser)) 53 | .subscribe(analyser => { 54 | this.initialize(analyser); 55 | this.drawFrequencyBarGraphs(); 56 | }); 57 | 58 | this.frequencyBarGraphs = { 59 | fullWidth: this.canvasElement.width, 60 | fullHeight: this.canvasElement.height, 61 | barWidth: 0, 62 | barHeight: 0, 63 | x: 0, 64 | ctx: this.canvasElement.getContext('2d') 65 | }; 66 | 67 | this.player 68 | .songChange 69 | .pipe( 70 | distinctUntilChanged(), 71 | filter(song => !!song) 72 | ) 73 | .subscribe(song => { 74 | this.generateLyric(song.lyric); 75 | }); 76 | 77 | this.player 78 | .progressTime 79 | .pipe(filter(value => !!value.original)) 80 | .subscribe(({ original }) => { 81 | let currentIndex = 0; 82 | for (let i = 0; i < this.lyrics.length; i++) { 83 | if (original > this.lyrics[i][0] - 1) { 84 | currentIndex = i; 85 | } 86 | } 87 | this.currentIndex = currentIndex; 88 | }); 89 | } 90 | 91 | drawFrequencyBarGraphs(): void { 92 | 93 | this.frequencyBarGraphs.x = 0; 94 | 95 | this.analyser.getByteFrequencyData(this.dataArray); 96 | this.frequencyBarGraphs.ctx.clearRect(0, 0, this.frequencyBarGraphs.fullWidth, this.frequencyBarGraphs.fullHeight); 97 | 98 | for (let i = 0; i < this.bufferLength; i++) { 99 | this.frequencyBarGraphs.barHeight = this.dataArray[i]; 100 | 101 | const r = this.frequencyBarGraphs.barHeight + ((i / this.bufferLength) * 150); 102 | const g = (i / this.bufferLength) * 100; 103 | const b = 50; 104 | 105 | this.frequencyBarGraphs.ctx.fillStyle = `rgb(${r}, ${g}, ${b})`; 106 | this.frequencyBarGraphs.ctx.fillRect( 107 | this.frequencyBarGraphs.x, 108 | this.frequencyBarGraphs.fullHeight - this.frequencyBarGraphs.barHeight, 109 | this.frequencyBarGraphs.barWidth, 110 | this.frequencyBarGraphs.barHeight 111 | ); 112 | this.frequencyBarGraphs.x += this.frequencyBarGraphs.barWidth + 1; 113 | 114 | } 115 | 116 | requestAnimationFrame(this.drawFrequencyBarGraphs.bind(this)); 117 | 118 | } 119 | 120 | generateLyric(lyric: string = ''): void { 121 | const originalLyric = decodeURIComponent(escape(window.atob(lyric || ''))); 122 | this.lyrics = parseLyric(originalLyric); 123 | } 124 | 125 | ngOnDestroy(): void {} 126 | 127 | 128 | } 129 | 130 | export function parseLyric(lyric: string): any { 131 | const lines = lyric.split('\n'); 132 | const pattern = /\[(\d{2,}):(\d{2})(?:\.(\d{2,3}))?]/; 133 | const result = []; 134 | 135 | lines[lines.length - 1].length === 0 && lines.pop(); 136 | 137 | for (const line of lines) { 138 | if (pattern.test(line)) { 139 | const index = line.indexOf(']'); 140 | const time = line.substring(0, index + 1); 141 | const value = line.substring(index + 1); 142 | const timeString = time.substring(1, time.length - 2); 143 | const timeArr = timeString.split(':'); 144 | result.push([parseInt(timeArr[0], 10) * 60 + parseFloat(timeArr[1]), value]); 145 | } 146 | } 147 | result.sort((a, b) => a[0] - b[0]); 148 | 149 | return result; 150 | } 151 | -------------------------------------------------------------------------------- /src/app/modules/music/music.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | import { RouterModule, Routes } from '@angular/router'; 4 | 5 | import { MusicComponent } from './music.component'; 6 | 7 | const routes: Routes = [ 8 | { 9 | path: '', 10 | component: MusicComponent 11 | } 12 | ]; 13 | 14 | @NgModule({ 15 | declarations: [MusicComponent], 16 | imports: [ 17 | CommonModule, 18 | RouterModule.forChild(routes) 19 | ] 20 | }) 21 | export class MusicModule { 22 | } 23 | -------------------------------------------------------------------------------- /src/app/shared/components/header/header.component.html: -------------------------------------------------------------------------------- 1 |
2 | 13 | 14 |
15 | -------------------------------------------------------------------------------- /src/app/shared/components/header/header.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | .header { 4 | position: fixed; 5 | top: 2.2vw; 6 | color: $primary; 7 | z-index: 103; 8 | display: flex; 9 | align-items: flex-end; 10 | justify-content: space-between; 11 | cursor: pointer; 12 | width: 100%; 13 | height: 30px; 14 | padding: 0 2.2vw; 15 | 16 | .nav { 17 | display: flex; 18 | justify-content: space-between; 19 | align-items: flex-end; 20 | 21 | .nav-bar { 22 | color: $primary; 23 | margin-right: 40px; 24 | } 25 | 26 | .logo { 27 | display: flex; 28 | align-items: flex-end; 29 | font-size: 24px; 30 | color: $primary; 31 | position: relative; 32 | img { 33 | width: 40px; 34 | height: 40px; 35 | position: absolute; 36 | top: -9px; 37 | } 38 | 39 | .logo-text { 40 | margin-left: 55px; 41 | } 42 | } 43 | 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/app/shared/components/header/header.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, OnInit } from '@angular/core'; 2 | 3 | @Component({ 4 | selector: 'biger-header', 5 | templateUrl: './header.component.html', 6 | styleUrls: ['./header.component.scss'] 7 | }) 8 | export class HeaderComponent implements OnInit { 9 | 10 | constructor() { } 11 | 12 | ngOnInit() { 13 | } 14 | 15 | } 16 | -------------------------------------------------------------------------------- /src/app/shared/components/mini-player/mini-player.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 |
4 | 5 |
6 |
{{song?.title}}
7 |
{{song?.artist}}
8 |
9 |
10 |
11 | 12 |
13 | 14 |
15 | 20 | 21 |
22 | 30 | 39 |
40 | 41 | 46 | 57 | 58 | 63 |
64 | 65 |
66 | 67 |
68 | -------------------------------------------------------------------------------- /src/app/shared/components/mini-player/mini-player.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | .mini-player { 4 | color: $primary; 5 | z-index: 1; 6 | display: flex; 7 | align-items: center; 8 | 9 | &-track-info-wrapper { 10 | border-right: 1px solid rgba(225,225,225,0.11); 11 | margin-right: 23px; 12 | padding: 5px 30px 5px 0; 13 | 14 | .track-info { 15 | display: flex; 16 | align-items: center; 17 | cursor: pointer; 18 | opacity: 1; 19 | 20 | .thumb { 21 | width: 45px; 22 | height: 45px; 23 | margin-right: 10px; 24 | background-color: #D3D6DA; 25 | border-radius: 2px; 26 | } 27 | 28 | .title { 29 | font-weight: bold; 30 | white-space: nowrap; 31 | overflow: hidden; 32 | text-overflow: ellipsis; 33 | font-size: 14px; 34 | } 35 | 36 | .artist { 37 | white-space: nowrap; 38 | overflow: hidden; 39 | text-overflow: ellipsis; 40 | font-size: 12px; 41 | color: rgba(255,225,225,0.7); 42 | } 43 | } 44 | } 45 | 46 | &-controls-wrapper { 47 | display: flex; 48 | flex-flow: column nowrap; 49 | justify-content: space-between; 50 | align-items: center; 51 | position: relative; 52 | 53 | .button-wrapper { 54 | %defaultState { 55 | display: none; 56 | opacity: 0; 57 | } 58 | 59 | display: flex; 60 | justify-content: space-between; 61 | align-items: center; 62 | position: relative; 63 | 64 | .prev { 65 | transform-origin: center; 66 | transform: rotate(180deg); 67 | } 68 | 69 | .switch-group { 70 | width: 30px; 71 | margin-right: 15px; 72 | display: flex; 73 | justify-content: center; 74 | height: 31px; 75 | 76 | .play, 77 | .pause { 78 | position: absolute; 79 | } 80 | } 81 | 82 | .pause { 83 | @extend %defaultState; 84 | } 85 | 86 | .loop { 87 | height: 32px; 88 | width: 32px; 89 | 90 | position: relative; 91 | 92 | svg { 93 | position: absolute; 94 | top: 5px; 95 | left: 5px; 96 | } 97 | 98 | .single, 99 | .random { 100 | @extend %defaultState; 101 | } 102 | } 103 | 104 | .volume { 105 | margin-right: 15px; 106 | } 107 | 108 | .icon-button { 109 | font-size: 24px; 110 | color: $primary; 111 | margin-right: 15px; 112 | 113 | &:last-child { 114 | margin-right: 0; 115 | } 116 | } 117 | } 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/app/shared/components/mini-player/mini-player.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, ElementRef, OnDestroy, OnInit, ViewChild } from '@angular/core'; 2 | import { Power2, TweenMax } from 'gsap'; 3 | import { Subject, Observable } from 'rxjs'; 4 | import { debounceTime, distinctUntilChanged, filter } from 'rxjs/operators'; 5 | 6 | import { PlayerService } from '@core/player.service'; 7 | import { AutoUnsubscribe } from '@shared/decorators/auto-unsubscribe.decorator'; 8 | import { Progress, Song } from '@shared/types'; 9 | import { Direction, LoopMode } from '@shared/enums'; 10 | 11 | @AutoUnsubscribe() 12 | @Component({ 13 | selector: 'biger-mini-player', 14 | templateUrl: './mini-player.component.html', 15 | styleUrls: ['./mini-player.component.scss'] 16 | }) 17 | export class MiniPlayerComponent implements OnInit, OnDestroy { 18 | 19 | @ViewChild('playButton', {static: true}) playButton: ElementRef; 20 | @ViewChild('pauseButton', {static: true}) pauseButton: ElementRef; 21 | @ViewChild('list', {static: true}) loopList: ElementRef; 22 | @ViewChild('single', {static: true}) loopSingle: ElementRef; 23 | @ViewChild('random', {static: true}) loopRandom: ElementRef; 24 | 25 | song: Song; 26 | progress: Progress; 27 | loopMode: LoopMode; 28 | progressSubject: Observable = new Subject(); 29 | volumeSubject: Observable = new Subject(); 30 | loaded: boolean; 31 | 32 | get volume(): number { 33 | return this.player.volume() as number; 34 | } 35 | 36 | constructor( 37 | private player: PlayerService 38 | ) { 39 | this.loopMode = LoopMode.list; 40 | } 41 | 42 | ngOnInit(): void { 43 | this.progress = this.player.progress; 44 | 45 | this.player 46 | .songChange 47 | .pipe( 48 | distinctUntilChanged(), 49 | filter(song => !!song) 50 | ) 51 | .subscribe(song => this.song = song); 52 | 53 | this.progress 54 | .loaded 55 | .subscribe(loaded => this.loaded = loaded); 56 | 57 | this.player 58 | .playingChange 59 | .pipe(distinctUntilChanged()) 60 | .subscribe(playing => { 61 | if (playing) { 62 | buildToggleAnimation(this.playButton.nativeElement, this.pauseButton.nativeElement); 63 | } else { 64 | buildToggleAnimation(this.pauseButton.nativeElement, this.playButton.nativeElement); 65 | } 66 | }); 67 | 68 | this.progressSubject 69 | .pipe(debounceTime(500)) 70 | .subscribe(value => this.player.seek(value / 100)); 71 | 72 | this.volumeSubject 73 | .pipe(debounceTime(200)) 74 | .subscribe(value => this.player.volume(value)); 75 | 76 | } 77 | 78 | onPlayClick(): void { 79 | buildToggleAnimation(this.playButton.nativeElement, this.pauseButton.nativeElement); 80 | 81 | this.player.play(); 82 | } 83 | 84 | onPauseClick(): void { 85 | buildToggleAnimation(this.pauseButton.nativeElement, this.playButton.nativeElement); 86 | 87 | this.player.pause(); 88 | } 89 | 90 | onPrevClick(): void { 91 | this.player.skip(Direction.prev); 92 | } 93 | 94 | onNextClick(): void { 95 | this.player.skip(Direction.next); 96 | } 97 | 98 | onLoopClick(): void { 99 | const modes = [ 100 | LoopMode.single, 101 | LoopMode.random, 102 | LoopMode.list 103 | ]; 104 | 105 | const loopSvg = [ 106 | [this.loopList.nativeElement, this.loopSingle.nativeElement], 107 | [this.loopSingle.nativeElement, this.loopRandom.nativeElement], 108 | [this.loopRandom.nativeElement, this.loopList.nativeElement] 109 | ]; 110 | 111 | const [original, target] = loopSvg[this.loopMode]; 112 | 113 | buildToggleAnimation(original, target); 114 | 115 | this.loopMode = modes[this.loopMode]; 116 | 117 | this.player.loop(this.loopMode); 118 | 119 | } 120 | 121 | ngOnDestroy(): void { 122 | } 123 | 124 | } 125 | 126 | export function buildToggleAnimation(original: Element, target: Element): void { 127 | TweenMax.to(original, 0.2, {x: 20, opacity: 0, display: 'none', scale: 0.3, ease: Power2.easeInOut}); 128 | TweenMax.fromTo(target, 0.2, 129 | {x: -20, opacity: 0, scale: 0.3, display: 'none'}, 130 | {x: 0, opacity: 1, display: 'block', scale: 1, ease: Power2.easeInOut} 131 | ); 132 | } 133 | -------------------------------------------------------------------------------- /src/app/shared/components/progress/progress.component.html: -------------------------------------------------------------------------------- 1 |
2 |
3 | 8 | 9 |
10 | 11 |
12 |
13 |
14 | -------------------------------------------------------------------------------- /src/app/shared/components/progress/progress.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | $bar-background-color: rgba(225, 225, 225, 0.12); 4 | $filler-background-color: rgba(225, 33, 32, 0.5); 5 | 6 | :host { 7 | width: 100%; 8 | } 9 | 10 | .progress-slider { 11 | display: block; 12 | width: 100%; 13 | height: 24px; 14 | cursor: default; 15 | position: relative; 16 | margin-right: 15px; 17 | opacity: 1; 18 | vertical-align: middle; 19 | 20 | &:hover { 21 | & .handle { 22 | opacity: 1 !important; 23 | } 24 | } 25 | 26 | .bar { 27 | width: 100%; 28 | height: 2px; 29 | background: $bar-background-color; 30 | border-radius: 2px; 31 | box-shadow: inset 1px 1px 5px darken($bar-background-color, 18%); 32 | position: absolute; 33 | top: 12px; 34 | cursor: pointer; 35 | 36 | & > .handle { 37 | display: inline-block; 38 | width: 12px; 39 | height: 12px; 40 | background-color: $primary; 41 | border-radius: 50%; 42 | position: absolute; 43 | top: -5px; 44 | margin-left: -10px; 45 | z-index: 1; 46 | cursor: move; 47 | transition: left 200ms ease, opacity 250ms ease-in; 48 | ; 49 | opacity: 0; 50 | 51 | &.last-active { 52 | z-index: 2; 53 | } 54 | } 55 | 56 | .filler { 57 | display: block; 58 | width: 100%; 59 | height: 100%; 60 | position: relative; 61 | overflow: hidden; 62 | border-radius: 5px; 63 | 64 | & > span { 65 | display: inline-block; 66 | height: 100%; 67 | position: absolute; 68 | top: 0; 69 | background: $filler-background-color; 70 | transition: all 0.2s ease; 71 | } 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/app/shared/components/progress/progress.component.ts: -------------------------------------------------------------------------------- 1 | import { 2 | Component, 3 | ElementRef, 4 | EventEmitter, 5 | HostListener, 6 | Input, 7 | OnChanges, 8 | OnInit, 9 | Output, 10 | SimpleChanges, 11 | ViewChild 12 | } from '@angular/core'; 13 | import { Utilities } from './utilities'; 14 | 15 | @Component({ 16 | selector: 'biger-progress', 17 | templateUrl: './progress.component.html', 18 | styleUrls: ['./progress.component.scss'] 19 | }) 20 | export class ProgressComponent extends Utilities implements OnInit, OnChanges { 21 | 22 | private sliderModel = [0, 0, 0]; 23 | private sliderWidth = 0; 24 | private totalDiff = 100; 25 | private startClientX = 0; 26 | private startPosition = 0; 27 | private minValue: number; 28 | private maxValue: number; 29 | private minSelected: number; 30 | private maxSelected: number; 31 | private sliderInitiated = false; 32 | 33 | public handlerX = 0; 34 | public isHandlerActive = false; 35 | public isTouchEventStart = false; 36 | public isMouseEventStart = false; 37 | public currentHandlerIndex = 0; 38 | 39 | private initValue = 0; 40 | private currentValue = 0; 41 | 42 | constructor() { 43 | super(); 44 | } 45 | 46 | @Input('min') 47 | set setMinValue(value: number) { 48 | if (!isNaN(value)) { 49 | this.minValue = Number(value); 50 | } 51 | } 52 | 53 | @Input('max') 54 | set setMaxValue(value: number) { 55 | if (!isNaN(value)) { 56 | this.maxValue = Number(value); 57 | } 58 | } 59 | 60 | @Input('value') 61 | set setCurrentValue(value: number) { 62 | if (!isNaN(value) && this.currentValue !== Number(value)) { 63 | this.currentValue = Number(value); 64 | } 65 | } 66 | 67 | @Output() 68 | readonly change = new EventEmitter(); 69 | 70 | @ViewChild('bar', {static: true}) bar: ElementRef; 71 | 72 | ngOnInit(): void { 73 | this.initializeSlider(); 74 | } 75 | 76 | ngOnChanges(changes: SimpleChanges): void { 77 | if (this.sliderInitiated) { 78 | this.resetModel(); 79 | } 80 | } 81 | 82 | /*Method to initailize entire Slider*/ 83 | public initializeSlider(): void { 84 | try { 85 | // Taking width of slider bar element. 86 | this.sliderWidth = this.bar.nativeElement.offsetWidth; 87 | this.sliderInitiated = true; 88 | } catch (e) { 89 | console.error(e); 90 | } 91 | } 92 | 93 | /*Method to initialize variables and model values */ 94 | private resetModel(): void { 95 | this.validateSliderValues(); 96 | // Setting the model values 97 | this.sliderModel = [ 98 | this.currentValue - this.initValue, 99 | 100 - this.currentValue, 100 | 0 101 | ]; 102 | requestAnimationFrame(this.setHandlerPosition.bind(this, true)); 103 | } 104 | 105 | /*Method to do validation of init and seleted range values*/ 106 | private validateSliderValues(): void { 107 | if (this.isNullOrEmpty(this.minValue) || this.isNullOrEmpty(this.maxValue)) { 108 | this.updateCurrentValue(0); 109 | } else if (this.minValue > this.maxValue) { 110 | this.updateCurrentValue(0); 111 | } else { 112 | this.initValue = this.minValue; 113 | /* 114 | * Validation for Selected range values 115 | */ 116 | if (this.isNullOrEmpty(this.minSelected) || this.minSelected < this.minValue || this.minSelected > this.maxValue) { 117 | this.minSelected = this.minValue; 118 | } 119 | if (this.isNullOrEmpty(this.maxSelected) || this.maxSelected < this.minValue || this.maxSelected > this.maxValue) { 120 | this.maxSelected = this.maxValue; 121 | } 122 | if (this.minSelected > this.maxSelected) { 123 | this.minSelected = this.minValue; 124 | this.maxSelected = this.maxValue; 125 | } 126 | } 127 | } 128 | 129 | /*Method to set current selected values */ 130 | private updateCurrentValue(value: number): void { 131 | this.minSelected = this.currentValue = value; 132 | this.change.emit(this.currentValue); 133 | } 134 | 135 | /*Method to set handler position */ 136 | private setHandlerPosition(privateChange: boolean = false): void { 137 | // Updating selected values : current values 138 | if (!privateChange) { 139 | this.updateCurrentValue(this.initValue + this.currentValue); 140 | } 141 | /*Setting handler position */ 142 | this.handlerX = this.currentValue; 143 | } 144 | 145 | /*Method to set model array values - will try to refine the values using step */ 146 | private setModelValue(value: number): void { 147 | this.sliderModel[0] = value; 148 | this.currentValue = value; 149 | } 150 | 151 | /*Method to disable handler movement*/ 152 | 153 | /*Execute on events: 154 | * on-mouseup 155 | * on-panend 156 | */ 157 | @HostListener('document:mouseup') 158 | @HostListener('document:panend') 159 | setHandlerActiveOff(): void { 160 | this.isMouseEventStart = false; 161 | this.isTouchEventStart = false; 162 | this.isHandlerActive = false; 163 | } 164 | 165 | /*Method to detect start draging handler*/ 166 | 167 | /*Execute on events: 168 | * on-mousedown 169 | * on-panstart 170 | */ 171 | public setHandlerActive(event: any): void { 172 | event.preventDefault(); 173 | if (!this.isNullOrEmpty(event.clientX)) { 174 | this.startClientX = event.clientX; 175 | this.isMouseEventStart = true; 176 | this.isTouchEventStart = false; 177 | } else if (!this.isNullOrEmpty(event.deltaX)) { 178 | this.startClientX = event.deltaX; 179 | this.isTouchEventStart = true; 180 | this.isMouseEventStart = false; 181 | } 182 | if (this.isMouseEventStart || this.isTouchEventStart) { 183 | this.startPosition = this.sliderModel[0]; 184 | this.isHandlerActive = true; 185 | } 186 | } 187 | 188 | public onBarClick(event: MouseEvent): void { 189 | const size = this.bar.nativeElement.clientWidth; 190 | const val = event.clientX; 191 | const {left} = this.bar.nativeElement.getBoundingClientRect(); 192 | const offset: number = Math.abs(val - left); 193 | const model = Math.round((offset / size) * (this.maxValue - this.minValue)) + this.minValue; 194 | 195 | this.setModelValue(model); 196 | requestAnimationFrame(this.setHandlerPosition.bind(this, false)); 197 | } 198 | 199 | 200 | /*Method to calculate silder handler movement */ 201 | 202 | /*Execute on events: 203 | * on-mousemove 204 | * on-panmove 205 | */ 206 | public handlerSliding(event: any): void { 207 | if ((this.isMouseEventStart && event.clientX) || (this.isTouchEventStart && event.deltaX)) { 208 | const movedX = Math.round(((event.clientX || event.deltaX) - this.startClientX) / this.sliderWidth * this.totalDiff); 209 | const model = this.startPosition + movedX; 210 | if (model >= this.minValue && model <= this.maxValue) { 211 | this.setModelValue(model); 212 | requestAnimationFrame(this.setHandlerPosition.bind(this, false)); 213 | } 214 | } 215 | } 216 | 217 | } 218 | -------------------------------------------------------------------------------- /src/app/shared/components/progress/utilities.ts: -------------------------------------------------------------------------------- 1 | /*Utilities */ 2 | export class Utilities { 3 | public isNullOrEmpty(obj: any): boolean { 4 | return obj === undefined || obj === null || obj === ''; 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /src/app/shared/components/volume-slider/volume-slider.component.html: -------------------------------------------------------------------------------- 1 | 6 |
7 | 8 |
9 | -------------------------------------------------------------------------------- /src/app/shared/components/volume-slider/volume-slider.component.scss: -------------------------------------------------------------------------------- 1 | @import "variables"; 2 | 3 | :host { 4 | display: flex; 5 | justify-content: flex-start; 6 | align-items: center; 7 | } 8 | .volume-button { 9 | font-size: 24px; 10 | color: $primary; 11 | } 12 | .volume-slider { 13 | display: none; 14 | // display: flex; 15 | 16 | .range { 17 | -webkit-appearance: none; /* Hides the slider so that custom slider can be made */ 18 | width: 100px; /* Specific width is required for Firefox. */ 19 | background-color:transparent; 20 | height: 23px; 21 | 22 | /* Special styling for WebKit/Blink */ 23 | &::-webkit-slider-thumb { 24 | -webkit-appearance: none; 25 | box-shadow: 0 0 10px rgba(50, 50, 50, 0.5); 26 | height: 20px; 27 | width: 8px; 28 | border-radius: 30px; 29 | cursor: grab; 30 | background: rgba(225, 225, 225, .6); 31 | margin-top: -8px; /* You need to specify a margin in Chrome, but in Firefox and IE it is automatic */ 32 | } 33 | 34 | /* All the same stuff for Firefox */ 35 | &::-moz-range-thumb { 36 | box-shadow: 0 0 10px rgba(50, 50, 50, 0.5); 37 | height: 20px; 38 | width: 8px; 39 | border-radius: 30px; 40 | cursor: grab; 41 | background: rgba(225, 225, 225, .6); 42 | } 43 | 44 | &::-webkit-slider-runnable-track { 45 | width: 50px !important; 46 | height: 3px; 47 | cursor: pointer; 48 | background: rgba(225, 225, 225, .5); 49 | border-radius: 50px; 50 | } 51 | 52 | &:focus::-webkit-slider-runnable-track { 53 | background: rgba(225, 225, 225, .5); 54 | } 55 | 56 | &:focus::-webkit-slider-thumb, 57 | &:hover::-webkit-slider-thumb { 58 | background: rgba(225, 225, 225, 1); 59 | } 60 | 61 | &::-moz-range-track { 62 | width: 100%; 63 | height: 3px; 64 | cursor: pointer; 65 | background: rgba(225, 225, 225, .5); 66 | border-radius: 5px; 67 | border: 0px solid #010101; 68 | } 69 | 70 | &:focus { 71 | outline: none; 72 | } 73 | 74 | &::-moz-focus-outer { 75 | border: 0; 76 | } 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /src/app/shared/components/volume-slider/volume-slider.component.ts: -------------------------------------------------------------------------------- 1 | import { Component, EventEmitter, Input, Output, ElementRef, ViewChild } from '@angular/core'; 2 | import { TweenMax, Power2 } from 'gsap'; 3 | 4 | @Component({ 5 | selector: 'biger-volume-slider', 6 | templateUrl: './volume-slider.component.html', 7 | styleUrls: ['./volume-slider.component.scss'] 8 | }) 9 | export class VolumeSliderComponent { 10 | 11 | @ViewChild('volumeButton', {static: true}) volumeButton: ElementRef; 12 | @ViewChild('slider', {static: true}) slider: ElementRef; 13 | 14 | @Input() value: number; 15 | 16 | @Output() readonly rangeChange: EventEmitter; 17 | 18 | 19 | constructor() { 20 | this.value = 0; 21 | this.rangeChange = new EventEmitter(); 22 | } 23 | 24 | onInput(value: number): void { 25 | this.rangeChange.next(Number((value / 100).toFixed(1))); 26 | } 27 | 28 | onVolumeButtonClick(): void { 29 | TweenMax.fromTo(this.slider.nativeElement, 0.2, 30 | {x: -20, opacity: 0, scale: 0.3, display: 'none'}, 31 | {x: 0, opacity: 1, display: 'flex', scale: 1, ease: Power2.easeInOut} 32 | ); 33 | } 34 | 35 | onSliderMouseleave(): void { 36 | TweenMax.to(this.slider.nativeElement, 0.2, {opacity: 0, display: 'none', ease: Power2.easeInOut}); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /src/app/shared/decorators/auto-unsubscribe.decorator.ts: -------------------------------------------------------------------------------- 1 | const isFunction = fn => typeof fn === 'function'; 2 | 3 | const doUnsubscribe = subscription => { 4 | subscription && 5 | isFunction(subscription.unsubscribe) && 6 | subscription.unsubscribe(); 7 | }; 8 | 9 | const doUnsubscribeIfArray = subscriptionsArray => { 10 | Array.isArray(subscriptionsArray) && 11 | subscriptionsArray.forEach(doUnsubscribe); 12 | }; 13 | 14 | export function AutoUnsubscribe({ 15 | blackList = [], 16 | arrayName = '', 17 | event = 'ngOnDestroy' 18 | } = {}): (constructor: Function) => void { 19 | return function(constructor: Function): void { 20 | const original = constructor.prototype[event]; 21 | 22 | if (!isFunction(original)) { 23 | throw new Error( 24 | `${constructor.name} is using @AutoUnsubscribe but does not implement OnDestroy` 25 | ); 26 | } 27 | 28 | constructor.prototype[event] = function(): void { 29 | if (arrayName) { 30 | doUnsubscribeIfArray(this[arrayName]); 31 | isFunction(original) && original.apply(this, arguments); 32 | 33 | return; 34 | } 35 | 36 | for (const propName in this) { 37 | if (blackList.includes(propName)) { continue; } 38 | 39 | const property = this[propName]; 40 | doUnsubscribe(property); 41 | } 42 | 43 | isFunction(original) && original.apply(this, arguments); 44 | }; 45 | }; 46 | } 47 | -------------------------------------------------------------------------------- /src/app/shared/enums/index.ts: -------------------------------------------------------------------------------- 1 | export enum Direction { 2 | prev, 3 | next, 4 | random 5 | } 6 | 7 | export enum LoopMode { 8 | list, 9 | single, 10 | random 11 | } 12 | -------------------------------------------------------------------------------- /src/app/shared/shared.module.ts: -------------------------------------------------------------------------------- 1 | import { NgModule } from '@angular/core'; 2 | import { CommonModule } from '@angular/common'; 3 | 4 | import { HeaderComponent } from '@shared/components/header/header.component'; 5 | import { MiniPlayerComponent } from '@shared/components/mini-player/mini-player.component'; 6 | import { ProgressComponent } from '@shared/components/progress/progress.component'; 7 | import { VolumeSliderComponent } from '@shared/components/volume-slider/volume-slider.component'; 8 | 9 | @NgModule({ 10 | declarations: [ 11 | HeaderComponent, 12 | MiniPlayerComponent, 13 | ProgressComponent, 14 | VolumeSliderComponent, 15 | ], 16 | imports: [ 17 | CommonModule, 18 | ], 19 | exports: [ 20 | HeaderComponent, 21 | MiniPlayerComponent, 22 | ProgressComponent, 23 | VolumeSliderComponent 24 | ] 25 | }) 26 | export class SharedModule { 27 | } 28 | -------------------------------------------------------------------------------- /src/app/shared/types/index.ts: -------------------------------------------------------------------------------- 1 | import { Observable } from 'rxjs'; 2 | import { Howl } from 'howler'; 3 | 4 | export interface Song { 5 | thumb: string; 6 | url: string; 7 | title: string; 8 | artist: string; 9 | lyric: string; 10 | howl: Howl; 11 | [propName: string]: any; 12 | } 13 | 14 | export interface Album { 15 | cover: string; 16 | name: string; 17 | issueDate: string; 18 | songs: Array; 19 | } 20 | 21 | export interface Progress { 22 | duration: string; 23 | value: Observable; 24 | time: Observable<{original: number, format: string}>; 25 | loaded: Observable; 26 | } 27 | -------------------------------------------------------------------------------- /src/assets/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tian-Hun/biger-music/84f6a02f18048052909358b5cf6b98b6b99316ee/src/assets/.gitkeep -------------------------------------------------------------------------------- /src/assets/data.json: -------------------------------------------------------------------------------- 1 | { 2 | "albums": [ 3 | { 4 | "cover": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 5 | "name": "李志 洗心革面(Live)", 6 | "issueDate": "2018-12-31", 7 | "songs": [ 8 | { 9 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 10 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!578:/意味.m4a?authkey=AIi2BPhsvSW-Bd0", 11 | "title": "意味-洗心革面(Live)", 12 | "artist": "李志", 13 | "lyric": "W3RpOiDmhI/lkbMt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDozMC4zM10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDoxMS45OF3mhI/lkbMKWzAwOjIwLjQ0XUludHJvIOmSoueQtApbMDA6MzkuMDBdClswMDo0NC4xOV3lv5jkuobku5Yg5Zyo5aSc6YeMClswMDo1NC44Ml3pmLTmmpfnmoTpnZLmmKXkuI3lj6rmmK/pgqPkupvkurrpgqPkupvkuosKWzAxOjI2LjM1XeS9oOeahOWFieS6rueFp+iAgOWcqOWTqumHjApbMDE6MjkuNTRd5oiR5Zyo5rKJ6buY5Lit6KKr5pS+5bGB5oOK6YaSClswMTozMi45OV3ku5bku6znnIvop4HnmoTkvaDlkozmiJHnnIvop4HnmoTlpbnor7TkuZ/or7TkuI3muIUKWzAxOjM4LjAyXeatpOWIu+S9oOWcqOS4lueVjOeahOS4reW/gwpbMDE6NDEuNTFd5oiW6ICF5bCx5Zyo5Lit5b+D55qE6L6557yYClswMTo0NC44NV3ov5nkuKrkuJbnlYzkuI3kuLrkvaDkuI3kuLrmiJHmiYDkuobop6Pog73mjozmjqcKWzAxOjUwLjUxXeaIluiuuOWug+agueacrOWwseS4jeWtmOWcqApbMDE6NTUuMjhdClswMjoyOC40NV3mnInkupvkurog5Y675q275ZCnClswMjozOC43MF3lhbblrp7miJHlhoXlv4PnmoTlubvop4nkuZ/kuI3ov4fmmK/ov5nmoLcKWzAyOjQ5LjA5XeWFhOW8n+WViiDnrpfkuoblkKcKWzAyOjU5LjU1XeWwseeul+aIkeS8muaDs+i1t+S9oOWPiOiDveaEj+WRs+edgOS7gOS5iApbMDM6MDkuODVd5L2g55qE5YWJ5Lqu54Wn6ICA5Zyo5ZOq6YeMClswMzoxMy4wMl3miJHlnKjmsonpu5jkuK3ooqvmlL7lsYHmg4rphpIKWzAzOjE2LjM1XeS7luS7rOeci+ingeeahOS9oOWSjOaIkeeci+ingeeahOWlueivtOS5n+ivtOS4jea4hQpbMDM6MjEuMzRd5q2k5Yi75L2g5Zyo5LiW55WM55qE5Lit5b+DClswMzoyNC44Ml3miJbogIXlsLHlnKjkuK3lv4PnmoTovrnnvJgKWzAzOjI4LjM4Xei/meS4quS4lueVjOS4jeS4uuS9oOS4jeS4uuaIkeaJgOS6huino+iDveaOjOaOpwpbMDM6MzMuODld5oiW6K645a6D5qC55pys5bCx5LiN5a2Y5ZyoClswMzo0MC4zMl0KWzAzOjQzLjI5XeWwseeul+aIkeS8muaDs+i1t+S9oOWPiOiDveaEj+WRs+edgOS7gOS5iApbMDM6NTMuNDRd5bCx566X5oiR5Lya5oOz6LW35L2g5Y+I6IO95oSP5ZGz552A5LuA5LmIClswNDowNy45MV0=" 14 | }, 15 | { 16 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 17 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!579:/鸵鸟-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 18 | "title": "鸵鸟-洗心革面(Live)", 19 | "artist": "李志", 20 | "lyric": "W3RpOiDpuLXpuJ8t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNzozNC42OV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowNi4zNl3puLXpuJ8t5rSX5b+D6Z2p6Z2iClswMDoyMi43N10KWzAyOjAyLjI4XeWIq+aKiuaIkeWSjOS7luS7rOaJr+WcqOS4gOi1twpbMDI6MDcuMjBd5oiR5rKh5pyJ5LuW5Lus6YKj5LmI5bSH6auY77yM5Lmf5rKh5pyJ5LuW5Lus6YKj5LmI6KOF6YC8ClswMjoxNC4zMF3liKvnrqHmiJHvvIzmiJHlj6rmmK/kuIDlj6rlj5Hpu5HnmoToi7nmnpwKWzAyOjE3LjkzXQpbMDI6MjQuNDld5pyL5Y+L77yM5L2g55qE6Lqr5p2Q5Y+v5Yir6LWw5qC35ZKvClswMjozMC40Nl3nnIvnnYDkvaDmiJDkuLrkuIDkuKrog5blrZDvvIzlpJrlsJHmiJHkvJrmnInkuIDngrnlsLTlsKwKWzAyOjM3LjgyXeS6uue+pOmHjOS4jeWSjOiwkOeahOatjOWUse+8jOaIkeWPquaYr+S4gOWktOWPkeaDheeahOm4tem4nwpbMDI6NDMuODRdClswMjo0Ni43MV3mmK/osIHluKbkvaDmnaXnnIvov5nlnLrlupnkvJoKWzAyOjU0LjEzXeihjOS4uuaOqemlsOWQjui2hei2iuS6huaAnee7tApbMDI6NTkuMDddClswMzowMS43MV3oiJ7lj7DkuIrnmoTlsI/kuJHlkozkvaDnmoTlt6blsI/ohb8KWzAzOjA1LjA1XeWIq+euoeaIke+8jOWIq+aKiuaIkeWSjOS7luS7rOaJr+WcqOS4gOi1twpbMDM6MTAuMzFdClswMzoyNC4xMl3mmK/osIHluKbkvaDmnaXnnIvov5nlnLrlupnkvJoKWzAzOjMxLjQyXeihjOS4uuaOqemlsOWQjui2hei2iuS6huaAnee7tApbMDM6MzguODBd6Iie5Y+w5LiK55qE5bCP5LiR5ZKM5L2g55qE5bem5bCP6IW/ClswMzo0Mi40N13liKvnrqHmiJHvvIzliKvmiormiJHlkozku5bku6zmia/lnKjkuIDotbcKWzAzOjQ5LjY2XQpbMDM6NTAuMzFd5LiW55WM6KKr5Lyk5a6z5LqG5peg5rOV5YWl552hClswMzo1Ny43M13lo7Dpn7Pooqvph43lpI3nnYDmgIDnlpHnnLzms6oKWzA0OjA1LjE1XeS4reWbveaYr+S7luS7rOeahOS5n+aIluaYr+S9oOS7rOeahApbMDQ6MDguNjVd5Yir566h5oiR77yM5oiR5Y+q5piv5LiA5Liq5YG25YOP5rS+5q2M5omLClswNDoxNC4wNV0KWzA0OjE0Ljk3XeiuqeS7luS7rOWOu+Wvu+aJvuWPr+iDveaYr+mrmOi0teeahOiNo+iAgApbMDQ6MTkuMzdd5oiR5bey57uP5aSx5Y6754ix55qE5pys6aKGClswNDoyMy4wM13kuZ/kuI3kvJrmgajnmoTpgqPkuYjogarmmI4KWzA0OjI2Ljc0XeWIq+euoeaIke+8jOaIkeWPquaYr+WPkeWHuuS4i+i0seeahOWjsOmfswpbMDQ6MzAuMzBd" 21 | }, 22 | { 23 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 24 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!580:/墙上的向日葵-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 25 | "title": "墙上的向日葵-洗心革面(Live)", 26 | "artist": "李志", 27 | "lyric": "W3RpOiDlopnkuIrnmoTlkJHml6XokbUt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwODo1Mi42OV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMy4xOF3lopnkuIrnmoTlkJHml6XokbUKWzAwOjA4Ljg4XQpbMDA6MTIuNjNd5L2c6K+N77ya5p2O5b+XClswMDoxNy4yNV3kvZzmm7LvvJrmnY7lv5cKWzAwOjIxLjQyXQpbMDE6MTMuODRd56qX5aSW55qE6aOO77yM5ZC56L+H5oiR55qE5oi/6Ze0ClswMTozMS41M13lkLnliqjvvIzkvaDnmoTlkJHml6XokbUKWzAxOjQ2Ljk5XeWfjuW4guWwsei6suWcqOWFieaYjueahOiDjOWQjgpbMDE6NTQuMzhd5YWJ5piO5Y+q5piv5L2g6ZqQ56eY55qE5ZOA5oSBClswMjowMS42N13ml7blhYnlsLHov5nmoLfmgoTmgoTlnLDmupzotbAKWzAyOjEyLjI5Xea6nOi1sApbMDI6MTQuNzVdClswMjo0Mi4zOV3ljYHlubTnmoTpo47mma/lsLHlg4/nqpfliY3nmoTkupEKWzAzOjAwLjkyXeS9oOWSjOS9oOeahOWktOWPkeaRh+abs+S4jeWumgpbMDM6MTUuNjJd5bim552A5aW555qE5b2x5a2Q56uZ5Zyo6KGX5aS0ClswMzoyMi44Nl3lg4/mgZDmg6fnmoTpsbzmi7zlkb3lnLDmuLgKWzAzOjMwLjI2XeaXtuWFieWwsei/meagt+aChOaChOWcsOa6nOi1sApbMDM6MzUuMjVdClswMzo0MS40MF3ku4DkuYjmmK/miJHku6zliIblvIDnmoTlgJ/lj6MKWzAzOjQ4LjY1XeS7gOS5iOiDveiuqeaIkeS4uuiwgeWBnOeVmQpbMDM6NTYuMTNd5pe25YWJ5bCx6L+Z5qC35oKE5oKE5Zyw5rqc6LWwClswNDowNi44Nl3mupzotbAKWzA0OjA4LjM2XQpbMDU6MDYuMzNd5LuA5LmI5piv5oiR5Lus5YiG5byA55qE5YCf5Y+jClswNToxMy43MV3ku4DkuYjog73orqnmiJHkuLrosIHlgZznlZkKWzA1OjIxLjA3XeaXtuWFieWwsei/meagt+aChOaChOWcsOa6nOi1sApbMDU6MjYuODRdClswNTozMi4yNl3luKbnnYDlpbnnmoTlvbHlrZDnq5nlnKjooZflpLQKWzA1OjM5LjU2XeWDj+aBkOaDp+eahOmxvOaLvOWRveWcsOa4uApbMDU6NDcuMjFd5pe25YWJ5bCx6L+Z5qC35oKE5oKE5Zyw5rqc6LWwClswNTo1Ny41MV3mupzotbAKWzA2OjAzLjcyXQpbMDc6NDYuMDJdMjAxOOW5tOWwseimgei/h+WOu+S6hu+8jOaIkeS4jeaDs+aAgOW/teWugw==" 28 | }, 29 | { 30 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 31 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!581:/这个世界会好吗-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 32 | "title": "这个世界会好吗-洗心革面(Live)", 33 | "artist": "李志", 34 | "lyric": "W3RpOiDov5nkuKrkuJbnlYzkvJrlpb3lkJct5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDowMy40Nl0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMi40NF3ov5nkuKrkuJbnlYzkvJrlpb3lkJcKWzAwOjEzLjIyXQpbMDA6NTMuODVd5Y+q5piv6YKj5Lqb54yb54OI55qE5oOF57uqClswMTowMC42Nl3lnKjnnaHkuI3nnYDnmoTml7blgJnmipjno6jnnYDmiJEKWzAxOjA4Ljc0XeaIkemCo+aXqeW3suatu+WOu+eahOeItuS6sgpbMDE6MTUuODVd5Zyo5rKh5pyJ5pif5pif55qE5aSc5pma55yL552A5L2gClswMToyMS4xNF0KWzAxOjIzLjY3XeWmiOWmiO+8jOS7luS7rOaKm+W8g+S6huaIkQpbMDE6MzEuNDhd5YOP5q2M5ZSx5LiA5qC35oqb5byD5LqG5oiRClswMTozOC4wOF3lpojlpojvvIzmiJHmmK/lpJrkuYjniLHkvaAKWzAxOjQ2LjA0XeW9k+S9oOayiem7mOeahOaXtuWAmeaIkeeIseS9oApbMDE6NTAuMDldClswMTo1Mi45OV3lpojlpojvvIzmiJHkvJrlnKjlpI/lpKnlvIDmlL7lkJcKWzAyOjAwLjc1XeWDj+S9oOabvue7j+eahOWuueminOmCo+agtwpbMDI6MDcuNjdd5aaI5aaI77yM6L+Z56eN5aSx6JC95Lya5oyB5LmF5ZCXClswMjoxNS41N13ov5nkuKrkuJbnlYzkvJrlpb3lkJcKWzAyOjIyLjMyXeW/mOiusOS4gOS6m+makOenmOeahOWnlOWxiApbMDI6MjkuNjhd5Zyo5Zue5aS06KeC5pyb55qE5pe25YCZ6L+35aSx5LqG6Ieq5bexClswMjozNC43MF0KWzAyOjM3LjE4XeaIkeeahOato+WcqOiAgeWOu+eahOi6q+S9kwpbMDI6NDQuNDVd5LuO5p+Q5LiA5aSp5byA5aeL5bCx5Zyo5riQ5riQ5q275Y67ClswMjo1MC44NV3lpojlpojmiJHniLHkvaAKWzAyOjUyLjg3XQpbMDM6MjEuNjJd5aaI5aaI77yM5oiR5bGF54S254ix5LiK5LqG5aW5ClswMzoyOC43N13lg4/mrYzllLHkuIDmoLflsLHniLHkuIrkuoblpbkKWzAzOjM2LjQwXeWmiOWmiO+8jOW9k+S9oOWPiOWbnummluS4gOWIhwpbMDM6NDMuNDZd6L+Z5Liq5LiW55WM5Lya5aW95ZCXClswMzo1Ni42NF0=" 35 | }, 36 | { 37 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 38 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!582:/定西-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 39 | "title": "定西-洗心革面(Live)", 40 | "artist": "李志", 41 | "lyric": "W3RpOiDlrpropb8t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDo1MS45N10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMi4yMl3lrpropb8KWzAwOjA3LjE2XQpbMDA6MjkuMDdd6L+Z5LmI5aSa5bm05L2g5LiA5Liq5Lq65LiA55u05Zyo6LWwClswMDozNS42N13mlrnlkJHlkozlpKnmsJTnmoToioLlpY/kvJrorqnkvaDlv6fmhIEKWzAwOjQyLjQ3XeS9oOivtOS9oOmBh+ingeS6huS4gOWkp+WghuWlh+aAqueahOS6ugpbMDA6NDkuNTFd5LuW5Lus55yL5LiK5Y675aW95YOP6YO95q+U5L2g5byA5b+DClswMDo1Ni4yMl3kvaDog73kuI3og73mir3nqbrmm7/miJHljrvkuIDkuKrlnLDmlrkKWzAxOjAzLjAyXeaNruivtOmCo+eahOS6uumDveaThemVv+e7meWIq+S6uuetlOahiApbMDE6MDkuOTFd5aaC5p6c5L2g5oOz55+l6YGT5YWz5LqO5a6D55qE5YW25LuW5LqL5oOFClswMToxNi43OF3miJHkuZ/kuI3kvJrnu5nkvaDliJjloIPnmoTnlLXor53lj7fnoIEKWzAxOjIxLjcxXQpbMDE6MjMuODdd5aSa5oOz5ZKM5L2g5LiA5qC36Iet5LiN6KaB6IS4ClswMTozMC44MF3loqjplZzlkozooajmg4Xpg73mjILlnKjohLjkuIoKWzAxOjM3LjUyXeepv+S7gOS5iOWQg+S7gOS5iOeOqeS7gOS5iOmDveWPr+S7pQpbMDE6NDQuMzNd5LuK5aSp54ix5LuW5piO5aSp5oGo5LuW5Lmf5Y+v5LulClswMTo0OC4yOV0KWzAyOjE4LjcwXei/meS5iOWkmuW5tOaIkeS4gOS4quS6uuS4gOebtOWcqOi1sApbMDI6MjUuMzdd6LWw6L+H5LqG5Lq65oCn55qE6IOM5ZCO5ZKM55m95LqR6IuN54uXClswMjozMi4xNV3mgLvku6XkuLrnrZTmoYjkvJrlh7rnjrDlnKjkuIvkuIDkuKrovabnq5kKWzAyOjM4Ljk4Xemaj+WQjueahOS6i+aDheaIkeS4jeivtOS9oOS5n+iDveaYjueZvQpbMDI6NDMuOThdClswMjo0Ni4wNl3mgrLkvKTmmK/lpaLkvojlk4HmiJHmtojlj5fkuI3otbcKWzAyOjUyLjk4XeW/q+S5kOWDj+WZqeaipuaAu+iuqeS6uuaDiumGkgpbMDI6NTkuODdd5L2g6KaB5ZOt5ZCn5bCx5ZOt5ZCn5bCx6ZqP5oSP5ZCnClswMzowNi43MF3lj43mraPmiJHml6nlt7LkuaDmg6/kuI3ljrvnm7jkv6EKWzAzOjEzLjUxXeaCsuS8pOaYr+WlouS+iOWTgeaIkea2iOWPl+S4jei1twpbMDM6MjAuMzld5b+r5LmQ5YOP5Zmp5qKm5LiA6L2s55y85oOK6YaSClswMzoyNy4zMl3kvaDopoHotbDlkKflsLHotbDlkKflsLHpmo/mhI/lkKcKWzAzOjM0LjI0XeWPjeato+aIkeaXqeW3suWGs+WumuS4jeWGjeWbnuWOuwpbMDM6MzguNTdd" 42 | }, 43 | { 44 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 45 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!583:/倒影-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 46 | "title": "倒影-洗心革面(Live)", 47 | "artist": "李志", 48 | "lyric": "W3RpOiDlgJLlvbEt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDo1Ni44OV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowNS4zNl3lgJLlvbEKWzAwOjExLjE0XQpbMDA6MzQuMzJd5oiR5pu+57uP5Lul5Li65bm456aP6Lef6ZqP552A5L2gClswMDo0MS41Ml3kvaDljbTnlKjnkIbmg7PmnaXpgIPpgb8KWzAwOjQ4LjYxXeivtuKApuKApuS6sueIseeahOadjuW/l+WFiOeUnwpbMDA6NTUuMzdd5L2g5bCx5YOP5bGO55qE5YCS5b2xClswMTowMS4xOF0KWzAxOjAyLjUyXeaIkeabvue7j+W5u+aDs+acquadpeS+nemdoOedgOS9oApbMDE6MDkuNDZd5L2g5Y2055So6Led56a75p2l5oqb5byDClswMToxNi44MF3or7bigKbigKbkurLniLHnmoTmnY7lv5flhYjnlJ8KWzAxOjIzLjU4XeS9oOWwseWDj+WxjueahOWAkuW9sQpbMDE6MzAuNzRd5L2g5bCx5YOP5bGO55qE5YCS5b2xClswMTozNS42N10KWzAyOjA2LjU4XeaIkeabvue7j+WOn+iwheS9oOWTreedgOetieS9oApbMDI6MTMuMTFd5L2g5Y2055So6Ieq55Sx5p2l5oqX5ouSClswMjoyMC4zOF3or7bigKbigKbkurLniLHnmoTmnY7lv5flhYjnlJ8KWzAyOjI3LjEzXeS9oOWwseWDj+WxjueahOWAkuW9sQpbMDI6MzQuMjNd5L2g5bCx5YOP5bGO55qE5YCS5b2xClswMjo0MS4yOV3kvaDlsLHlg4/lsY7nmoTlgJLlvbEKWzAyOjQ4LjI2XeS9oOWwseWDj+WxjueahOWAkuW9sQpbMDI6NTUuODld" 49 | }, 50 | { 51 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 52 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!566:/和你在一起-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 53 | "title": "和你在一起-洗心革面(Live)", 54 | "artist": "李志", 55 | "lyric": "W3RpOiDlkozkvaDlnKjkuIDotbct5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoyMi43NF0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowOS42M13lkozkvaDlnKjkuIDotbcKWzAwOjE4LjA0XQpbMDA6MjguNjZd5pio5aSp5Zyo5qKm6YeM77yM5oiR5Y+I55yL6KeB5L2g44CC5a6d6LSd77yM5LuW5Lus6K+05oiR5LiN54ix5L2gClswMDo0Ni4xOF3kvaDmi6XmnInmiJHnmoTvvIzkuI3mraLmmK/ku4rlpJzjgILlj6/mmK/vvIzkvaDmr5TmiJHlsI/kuoblha3lsoEKWzAxOjAzLjM2XeWmguaenOaIkeS7rOS4jeiDvee7k+WpmuS9oOaAjuS5iOWPl+W+l+S6hu+8jOWunei0ne+8jOaIkeefpemBk+iZveeEtuS9oOS4jeivtApbMDE6MjAuNDld5aaC5p6c5oiR5Lus5bCx6KaB57uT5ama5oiR5oCO5LmI6IO95Y+X5b6X5LqG77yM5a6d6LSd77yM5Yir5Zyo5aSc6YeM562J5oiRClswMTozMy42MF0KWzAxOjU2LjkwXeaIkeW3sue7j+S4jeS8mu+8jOe7j+W4uOaDs+WlueS7rO+8jOWPr+aYr++8jOi/h+WOu+aAjuiDveWFqOW/mOiusApbMDI6MTQuMDld5L2g5LiN55u45L+h5oiR77yM5Lmf5LiN5Lya5YaN6K+077yM5a6d6LSd77yM6ZqP5L6/5ZCn77yM6ZqP5L6/5ZCnClswMjozMS4xM13miJHmg7PlkozkvaDlnKjkuIDotbfvvIzlsLHnrpfmiJHkuI3niLHkvaDvvIzlrp3otJ3vvIzkurrlkozkurrmmK/kuIDlnLrmuLjmiI8KWzAyOjQ4LjQzXeaIkeaEv+aEj+S4uuS9oOatu+WOu++8jOWmguaenOaIkei/mOeIseS9oO+8jOWunei0ne+8jOWPjeato+a0u+edgOS5n+ayoeaEj+S5iQpbMDM6MDQuOTFdClswMzowNS40Nl3miJHopoHlkozkvaDlnKjkuIDotbfvvIzlsLHnrpfmiJHkuI3niLHkvaDvvIzlrp3otJ3vvIzkurrlkozkurrkuIDlnLrmuLjmiI8KWzAzOjIyLjQzXeaIkeaEv+aEj+S4uuS9oOatu+WOu++8jOWmguaenOaIkei/mOeIseS9oO+8jOWunei0ne+8jOaIkeS5n+WPquiDvei/meagt+S4uuS9oApbMDM6MzkuMTNd5a6d6LSd77yM5oiR5Lmf5Y+q6IO96L+Z5qC35Li65L2g44CC5a6d6LSd77yM5oiR5Lmf5Y+q6IO96L+Z5qC35Li65L2gClswMzo1My43NF0=" 56 | }, 57 | { 58 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 59 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!558:/天空之城-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 60 | "title": "天空之城-洗心革面(Live)", 61 | "artist": "李志", 62 | "lyric": "W3RpOiDlpKnnqbrkuYvln44t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwMzozOC44M10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC4wMF3lpKnnqbrkuYvln44KWzAwOjAwLjI3XQpbMDA6MDAuOTBd6aOe5py66aOe6L+H5aSp56m6IOWkqeepuuS5i+WfjgpbMDA6MDguOTBd6JC96Zuo5LiL55qE6buE5piP55qE5oiR5LusClswMDoxNi4xOV3mraTliLvmiJHlnKjljZfkuqznmoTlpJzph4wKWzAwOjIzLjQzXeaDs+W/teedgOS9oOWOn+adpei2iuadpei2iui/nApbMDA6MzAuMDBdClswMDozMS4wOF3miJHmg7Plm57liLDov4fljrsg5rKJ6buY552A5qyi5ZacClswMDozOC4zNl3lpKnnqbrkuYvln47lnKjlk63ms6PotormnaXotormmI7kuq7nmoTkvaAKWzAwOjQ1Ljg0XeeIseaDheS4jei/h+aYr+eUn+a0u+eahOWxgQpbMDA6NTMuMTRd5oqY56Oo552A5oiR5Lmf5oqY56Oo552A5L2gClswMDo1Ny42NF0KWzAwOjU4Ljc2Xea4r+Wym+WmueWmuSDkvaDnjK7nu5nmiJHnmoTopb/nj63niZnppoXppbwKWzAxOjA2LjkxXeeUnOicnOWcsOiejeWMluS6huaIkSDlpKnnqbrkuYvln47lnKjlk63ms6MKWzAxOjEzLjM5Xea4r+Wym+WmueWmuSDmiJHku6zmm77mi6XmnInnmoTnlJzonJznmoTniLHmg4UKWzAxOjIwLjk4XeeWr+eLguWcsOaSleijguS6huaIkSDlpKnnqbrkuYvln47lnKjlk63ms6MKWzAxOjI2LjY3XQpbMDE6NTcuODhd5riv5bKb5aa55aa5IOS9oOeMrue7meaIkeeahOilv+ePreeJmemmhemlvApbMDI6MDUuNDVd55Sc6Jyc5Zyw6J6N5YyW5LqG5oiRIOWkqeepuuS5i+WfjuWcqOWTreazowpbMDI6MTIuNjRd5riv5bKb5aa55aa5IOaIkeS7rOabvuaLpeacieeahOeUnOicnOeahOeIseaDhQpbMDI6MTkuODBd55av54uC5Zyw5pKV6KOC5LqG5oiRIOWkqeepuuS5i+WfjuWcqOWTreazowpbMDI6MjUuOTBdClswMjoyNy4zNl3muK/lspvlprnlprkg5L2g54yu57uZ5oiR55qE6KW/54+t54mZ6aaF6aW8ClswMjozNC42OV3nlJzonJzlnLDono3ljJbkuobmiJEg5aSp56m65LmL5Z+O5Zyo5ZOt5rOjClswMjo0Mi4wN13muK/lspvlprnlprkg5oiR5Lus5pu+5oul5pyJ55qE55Sc6Jyc55qE54ix5oOFClswMjo0OS42MV3nlq/ni4LlnLDmkpXoo4LkuobmiJEg5aSp56m65LmL5Z+O5Zyo5ZOt5rOjClswMjo1Ny41MF0KWzAzOjAyLjA1XeacieS6uui3r+i/h+mCo+mHjCDlm57mnaXlkYror4nmiJEKWzAzOjEwLjA1XeWkqeepuuS5i+WfjuWcqOWTreazo+aXoOazleWRvOWQuOeahOS9oApbMDM6MTcuMzhd5q2k5Yi75oiR5Zyo5Y2X5Lqs55qE5aSc6YeMClswMzoyNC43Ml3mg7Plv7XnnYDkvaDotormnaXotorov5wKWzAzOjI5LjU0XQpbMDM6MzMuNDRd" 63 | }, 64 | { 65 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 66 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!565:/结婚-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 67 | "title": "结婚-洗心革面(Live)", 68 | "artist": "李志", 69 | "lyric": "W3RpOiDnu5PlqZot5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbdG9vbDog5q2M6K+N5rua5Yqo5aesIGh0dHBzOi8vbHJjLW1ha2VyLmdpdGh1Yi5pb10KW2xlbmd0aDogMDU6MTYuMjZdClswMDowMi41MF3nu5PlqZot5rSX5b+D6Z2p6Z2iClswMDowNS45MF0KWzAwOjEwLjA3Xeivjeabsu+8muadjuW/lwpbMDA6MTMuMTdd57yW5puy77ya5rGf5bu65rCRClswMDoyMi4zMV0KWzAxOjA1LjQyXeS9oOWDj+aIkeingei/h+eahOmCo+S4quWwkeW5tApbMDE6MTIuODJd6IOM552A6Z2S5pil6LWw5Zyo5Lmd5pyI55qE6KGX5aS0ClswMToyMC42OV3kuIDpmLXpo47lkLnkubHkuobmiJHnmoTlpLTlj5EKWzAxOjI4LjI2XeeqgeeEtuWkqeawlOWPmOW+l+WmguatpOWTgOaAqApbMDE6MzYuMDFd5Y+q5LiN6L+H5piv5LiA5Zy655Sf5rS7ClswMTo0My42OF3lj6rkuI3ov4fmmK/kuIDlnLrnlJ/mtLsKWzAxOjUxLjM4XeWPquS4jei/h+aYr+S4gOWcuueUn+a0uwpbMDE6NTkuMTld5Y+q5LiN6L+H5piv5LiA5Zy655Sf5rS7ClswMjowNS4zMl0KWzAyOjA2Ljk5XeS7luS4vuedgOaWsOmynOeahOiKseWciOWcqOi3r+WPowpbMDI6MTQuNTVd562J5b6F5Lq65Lus57uZ5LuW56m/6LaK55qE5L+h5Y+3ClswMjoyMi40NV3pmL/lp6jov4XpgJ/lnLDovaznp7vkuoblpbnnmoTnm67lhYkKWzAyOjI5Ljk3XeS9oOWDj+S4queUu+WDj+WumuagvOWcqOS4reWkrgpbMDI6MzcuODVd5Y+q5LiN6L+H5piv5LiA5Zy65ZG96L+QClswMjo0NS42OF3lj6rkuI3ov4fmmK/kuIDlnLrlkb3ov5AKWzAyOjUzLjMyXeWPquS4jei/h+aYr+S4gOWcuuWRvei/kApbMDM6MDEuMTRd5Y+q5LiN6L+H5piv5LiA5Zy65ZG96L+QClswMzowNS42N10KWzAzOjQzLjYxXeaIkeaDs+e7meS9oOS4ieS4h+aUtuS5sOi/meWpmuWnuwpbMDM6NTEuMjld5ZKM6YKj5Liq6ZmM55Sf55qE5aWz5Lq66Jma5bqm6L+Z5pe25YWJClswMzo1OS4yNF3kuIDkuKrnlLXor53miZPlh7rkuobmiJHnmoTnnLzms6oKWzA0OjA2Ljk2XeW+gOS6i+a2jOS4iuW/g+WktOmdkuaYpeWwseaVo+WcugpbMDQ6MTQuNjhd5Y+q5LiN6L+H5piv5LiA5Zy65ri45oiPClswNDoyMi40MV3lj6rkuI3ov4fmmK/kuIDlnLrmuLjmiI8KWzA0OjMwLjA1XeWPquS4jei/h+aYr+S4gOWcuua4uOaIjwpbMDQ6MzcuODJd5Y+q5LiN6L+H5piv5LiA5Zy65ri45oiP" 70 | }, 71 | { 72 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 73 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!573:/关于郑州的记忆-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 74 | "title": "关于郑州的记忆-洗心革面(Live)", 75 | "artist": "李志", 76 | "lyric": "W2xlbmd0aDogMDU6MzMuNTZdClt0aTog5YWz5LqO6YOR5bee55qE6K6w5b+GLea0l+W/g+mdqemdol0KW2FyOiDmnY7lv5ddClthbDog5rSX5b+D6Z2p6Z2iXQpbYnk6IOWkqemtgl0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS42OV3lhbPkuo7pg5Hlt57nmoTorrDlv4YKWzAwOjAzLjQ4XQpbMDA6MDQuNTFd5L2c6K+N77ya5p2O5b+XClswMDowNS42OV3kvZzmm7LvvJrmnY7lv5cKWzAwOjE2LjMxXQpbMDA6NDguMThd5YWz5LqO6YOR5bee5oiR55+l6YGT55qE5LiN5aSaClswMDo1NS40NF3kuLrkuobniLHmg4Xmm77nu4/ljrvov4fpgqPph4wKWzAxOjAyLjM3XeWkmuWwkeasoeWcqOeBq+i9puS4iui3r+i/h+i/meWfjuW4ggpbMDE6MDkuNDFd5LiA5Liq5Lq65oKE5oKE5Zyw5oOz6LW35aW5ClswMToxMy4yOV0KWzAxOjE2LjY4XeWlueivtOWlueWWnOasoumDkeW3nuWGrOWkqeeahOmYs+WFiQpbMDE6MjMuNTZd5be35a2Q6YeM6aOY5ruh54Wk54KJ55qE5ZGz6YGTClswMTozMC42Ml3pm77msJTnqb/ov4flpbnlubTovbvnmoTohJblrZAKWzAxOjM3LjYzXeebtOWIsOS7iuWkqemDveayoeaVo+WOuwpbMDE6NDIuMDldClswMTo0Ni4xMV3lhbPkuo7pg5Hlt57miJHmg7PnmoTlhajmmK/kvaAKWzAxOjUxLjc2XeaDs+adpeaDs+WOu+mDveaYr+W/j+aClOWSjOWnlOWxiApbMDE6NTguOTNd5YWz5LqO6YOR5bee5oiR54ix55qE5YWo5piv5L2gClswMjowNS45Nl3niLHmnaXniLHljrvkuI3mmI7nmb3niLHnmoTmhI/kuYkKWzAyOjExLjgyXQpbMDI6MTMuMTRd5YWz5LqO6YOR5bee5Y+q5piv5YG25bCU5oOz6LW3ClswMjoxOS44OV3njrDlnKjlpbnnmoTlkbPpgZPpg73lnKjlm57lv4bph4wKWzAyOjI3LjAwXeavj+asoeWSjOaci+WPi+iBiui1t+i/h+WOu+eahOaXheihjApbMDI6MzQuNTNd5oiR5LiN5pWi6K+05oiR5pu+5Y676L+H6YKj6YeMClswMjozOS4zMF0KWzAzOjM3LjY2XeWFs+S6jumDkeW3nuaIkeaDs+eahOWFqOaYr+S9oApbMDM6NDQuNTZd5oOz5p2l55Sf5rS75peg6Z2e5piv55eb6Ium5ZKM576O5Li9ClswMzo1MS42OV3lhbPkuo7pg5Hlt57miJHniLHnmoTlhajmmK/kvaAKWzAzOjU4LjgyXeeIseadpeeIseWOu+aIkeS7rOmDveaXoOi3r+WPr+WOuwpbMDQ6MDUuOTFd5YWz5LqO6YOR5bee5oiR5oOz55qE5YWo5piv5L2gClswNDoxMi44NV3mg7PmnaXnlJ/mtLvml6DpnZ7mmK/nl5voi6blkoznvo7kuL0KWzA0OjIwLjEwXeWFs+S6jumDkeW3nuaIkeeIseeahOWFqOaYr+S9oApbMDQ6MjcuMDld54ix5Yiw5pyA5ZCO5oiR5Lus6YO95peg6Lev5Y+v5Y67ClswNDozNC4zMV3kvLzmmK/ogIzpnZ7miJbmmK/kuJbkuovlj6/nlY8KWzA0OjQxLjE0XeacieaDheacieS5ieWPiOaYr+acieexs+aXoOeCigpbMDQ6NDguMTRd5pe26Ze05pS55Y+Y5LqG5b6I5aSa5Lmf5LuA5LmI6YO95rKh5pyJClswNTowNy4xNl3orqnmiJHlho3mrKHmi6XmirHkvaAg5byg546u546u" 77 | }, 78 | { 79 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 80 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!567:/董卓瑶-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 81 | "title": "董卓瑶-洗心革面(Live)", 82 | "artist": "李志", 83 | "lyric": "W3RpOiDokaPljZPnkbYt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoyNi4yN10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS4xNl3okaPljZPnkbYKWzAwOjAzLjI5XQpbMDA6MDMuNzRd6L+Z5piv5LiA5Liq57uT5ama55qE6L2m6ZifClswMDowNi45N13lnKjml6DkurrnmoTlpJzph4zlpZTot5EKWzAwOjEwLjY3XeaIkeinguacm+edgOaJvuS4jeWIsOaWsOWomOWcqOWTqumHjApbMDA6MTcuNzBd54Gv5YWJ5ZKM5pif5YWJ5piv56Wd56aP55qE54Of54GrClswMDoyNC43Ml3mgrLliaflnKjlpKnkuq7ml7blj5HnlJ8KWzAwOjI4LjM0XQpbMDA6MzEuNzZd5q+b5q+b5L2g5Liq5aW95aeR5aiYClswMDozNC4xOF3kvaDopoHkv53miqTlpb3kvaDoh6rlt7EKWzAwOjM4LjgwXeS9oOWPr+efpeS4luS4iuayoeacieS7gOS5iOWlveS6ugpbMDA6NDEuNjZd5L2g5Yir57uZ5LuW5Lus6YO95LiK5LqGClswMDo0NS45Ml3mr5vmr5vkvaDmmK/kuKrlpb3lp5HlqJgKWzAwOjQ4LjU3XeS9oOimgeaKiuaMgeS9j+S9oOeahOassuacmwpbMDA6NTIuOTFd5L2g5Y+v55+l5oiR5oOz5YOP5L2g5LiA5qC357qv5rSBClswMDo1NS43NV3kvaDkuI3og73mr5TmiJHov5jopoHmlL7ojaEKWzAwOjU5Ljc4XQpbMDE6MjkuOTVd5oKy5Lyk55qE5LqL5oOF5pei54S25a6D5bey57uP6L+Z5LmI5Y+R55Sf77yM5L2g5bCx5LiN6IO96L+Z5qC355qE55yL552A5oiRClswMTo0NC4xN13kuIDliIfnmoTkuIDliIfkuI3ov4flj6rmmK/kvaDlkozmiJHpo57ov4flpKnnqbrvvIzlranlrZDkvaDmnIDnuq/mtIHnmoTlubvmg7Pnqbbnq5/mmK/ku4DkuYgKWzAxOjU2LjU2XQpbMDE6NTguMzld5q+b5q+b5L2g5Liq5aW95aeR5aiY77yM5L2g6KaB5L+d5oqk5aW95L2g6Ieq5bexClswMjowNS4yNl3kvaDlj6/nn6XkuJbkuIrmsqHmnInku4DkuYjlpb3kurrvvIzkvaDliKvnu5nku5bku6znu5nkuIrkuoYKWzAyOjEyLjUwXeavm+avm+S9oOaYr+S4quWlveWnkeWomO+8jOS9oOimgeaKiuaMgeS9j+S9oOeahOassuacmwpbMDI6MTkuMzVd5L2g5Y+v55+l5oiR5oOz5YOP5L2g5LiA5qC357qv5rSB77yM5L2g5LiN6IO95q+U5oiR6L+Y6KaB5pS+6I2hClswMjoyNS40Nl0=" 84 | }, 85 | { 86 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 87 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!563:/春末的南方的城市-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 88 | "title": "春末的南方城市-洗心革面(Live)", 89 | "artist": "李志", 90 | "lyric": "W3RpOiDmmKXmnKvljZfmlrnnmoTln47luIIt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoxMi43Nl0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMi40OF3mmKXmnKvnmoTljZfmlrnln47luIIKWzAwOjA0LjU0XQpbMDA6MzIuNzJd6L+Z5Liq5LiL6Zuo55qE5riF5pmoClswMDozNC44NV3miJHku47ljZfmlrnnmoTov5nkuKrln47luILlh4blpIfljrvljZfmlrnnmoTpgqPkuKrln47luIIKWzAwOjQxLjc2XeaIkeWSjOaIkeeahOWFhOW8n+WcqOS4gOWutuWMheWtkOmTuumXqOWPo+WIhuaJi+i1tuW+gOi/nOWkhOeahOermeWPsApbMDA6NTIuNTNd6L2m5LiK55qE55m96aKG552h5oSP5pym6IOn6ZqU552A55y85bGO55yL552A5oiRClswMDo1OS4zN13ov5norqnkurrlv4PmhYwg6L+Z6K6p5Lq65b+D5oWMClswMTowNi41N13ov5norqnkurrlv4PmhYwg6L+Z6K6p5Lq65b+D5oWMClswMToxMy4wOV0KWzAxOjI5LjIwXei/meS4quS4i+mbqOeahOa4heaZqApbMDE6MzEuMjBd5oiR5LuO5Z+O5biC55qE6L+Z5aS05rih6L+H5rKz5Y675Z+O5biC55qE6YKj5aS0ClswMTozOC40Nl3ooZfkuIrnmoTnuqLnga/nu7/nga/pl6rng4HkuI3lgZzpl6rng4HkuI3lgZzpl6rng4Eg6L+Z6K6p5Lq65b+D5oWMClswMTo0OC44NV3lhYTlvJ/lnKjnjrvnkoPnmoTlu7rnrZHph4wg5oiR5Zyo5r2u5rm/55qE6Lev5LiKClswMTo1Ni4xNl3kurrku6zph43lpI3nnYDph43lpI3nnYDph43lpI3nnYDph43lpI0KWzAyOjAyLjk1Xei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAyOjA5Ljk5XQpbMDI6MTEuNjJd5LiN55+l6YGT5pyJ6LCB6IO96K6p5L2g6L+w6K+0ClswMjoxOC42Ml3kvaDov5nmoLfnmoTnlJ/mtLvliLDlupXkuLrkuobku4DkuYgKWzAyOjI1LjY4XeaIkeeci+ingeS9oOmdoOWcqOeql+WPo+ayiem7mApbMDI6MzMuMThd6Lev6L+H5LqG6Z2S5pil5oiR5Lus6L+Y5oul5pyJ5LuA5LmIClswMjozOC4wMF0KWzAyOjM4LjU2Xei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAyOjQ1LjM3Xei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAyOjUwLjk0XQpbMDI6NTQuMDFd5LiN55+l6YGT5pyJ6LCB6IO96K6p5L2g6L+w6K+0ClswMzowMC45OV3kvaDov5nmoLfnmoTnlJ/mtLvliLDlupXkuLrkuobku4DkuYgKWzAzOjA3Ljk4XeaIkeeci+ingeS9oOmdoOWcqOeql+WPo+ayiem7mApbMDM6MTUuMDZd6Lev6L+H5LqG6Z2S5pil5oiR5Lus6L+Y5oul5pyJ5LuA5LmIClswMzoyMC4xNl0KWzAzOjIxLjI2Xei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAzOjI0LjIxXei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAzOjMxLjIyXei/meiuqeS6uuW/g+aFjCDov5norqnkurrlv4PmhYwKWzAzOjM4LjE2XQ==" 91 | }, 92 | { 93 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 94 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!559:/一个夜晚-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 95 | "title": "一个夜晚-洗心革面(Live)", 96 | "artist": "李志", 97 | "lyric": "W3RpOiDkuIDkuKrlpJzmmZot5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNzowMS45Nl0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC44NV3kuIDkuKrlpJzmmZoKWzAwOjAyLjk4XQpbMDA6MTguMzBd5LiN566h5aaC5L2V77yM6YO95bey57uP6K+05b6X5aSq5aSaClswMDoyNi40Ml3kuLrkuobpgb/lhY3lsLTlsKzlj6rog73otbDlh7rmiL/pl7QKWzAwOjM0LjE4Xei6sui/h+aLkOinkueahOawtOWdkeW8gOWni+aVsOi1t+i3r+eBrwpbMDA6NDIuMzld5oqK6Ieq5bex5pWw5Lmx5LqG5bCx6L2s6L+H5LqG5aS0ClswMDo0NS43Nl0KWzAwOjQ5LjQ1XeS9oOivtOWcqOi/meagt+S4gOS4quWknOaZmgpbMDA6NTguNDBd5L2g5bqU6K+l5Y675oqK6Lev54Gv5aWJ54yu57uZ5LuWClswMTowNS40N13kvaDor7TlnKjov5nmoLfkuIDkuKrlpJzmmZoKWzAxOjE0LjQ3XeS9oOimgeaKiuiHquW3seeMrue7meS7lgpbMDE6MTcuODddClswMTo0Ni4wNl3ljrvku5blpojnmoTku4DkuYjlpKnmsJTkuI3lpKnmsJQKWzAxOjU0LjMxXeWPquimgeiDveWkn+eci+ingeS9oOWwseS4jeeul+eZvea0uwpbMDI6MDIuMDJd5Y+N5q2j5bey57uP5byg5byA5LqG6IW/ClswMjoxMC4zNF3lvoDlk6rkuKrmlrnlkJHotbDpg73kvJrmnInmsLTlnZEKWzAyOjE0LjcxXQpbMDI6MTcuNDJd5L2g6K+05Zyo6L+Z5qC35LiA5Liq5aSc5pmaClswMjoyNi40MF3po47lkLnmlq3kuobnnInmr5vkuZ/kuI3kvJrmhJ/liLDlr5LlhrcKWzAyOjMzLjYxXeS9oOivtOWcqOi/meagt+S4gOS4quWknOaZmgpbMDI6NDIuNDNd5oC75oOz6ISx5YWJ6KKc5a2Q5YOP5LuO5YmN5LiA5qC3ClswMzoxMy40Nl3kvaDor7TlnKjov5nmoLfkuIDkuKrlpJzmmZoKWzAzOjIyLjQ5XeWwseeul+aMluepuuW/g+aAneS5n+S4jeS8mueci+W+l+Wkqui/nApbMDM6MjkuNjRd5L2g6K+05Zyo6L+Z5qC35LiA5Liq5aSc5pmaClswMzozOC41MF3ot6/nga/kvJrmm7/miJHku6zmgJ3ogIPlpJzmmZoKWzAzOjQxLjk2XQpbMDM6NDUuMzld5L2g6K+05Zyo6L+Z5qC35LiA5Liq5aSc5pmaClswMzo1NC40OF3orqnmiJHku6zmia3otbflsYHogqHnm7jkupLmi6XmirEKWzA0OjAxLjQxXeS9oOivtOWcqOi/meagt+S4gOS4quWknOaZmgpbMDQ6MTAuMzdd6K6p5oiR5Lus5omt6LW35bGB6IKh55u45LqS5oul5oqxCg==" 98 | }, 99 | { 100 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 101 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!584:/死人-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 102 | "title": "死人-洗心革面(Live)", 103 | "artist": "李志", 104 | "lyric": "W3RpOiDmrbvkurot5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNTo0NS4wN10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC42Ml3mrbvkuroKWzAwOjA1LjM1XQpbMDA6MzUuMDdd5oiR5Lus5piv5LiA5bqn5qGlClswMDo0My4wM13ooqvkurrmi4bkuobloqkKWzAwOjUwLjY1XeS9oOS4gOi3g+iAjOi1t++8jOa6tui/m+i/meawtOmHjApbMDA6NTguNzRd5a+75om+55yf55u45ZKM56eY5a+GClswMTowNi43MV3lv4/mgpTlkKfnvLrlvrfnmoTkuroKWzAxOjE1LjA4XeWIq+aAquaIkeaKiuaJgOaciemDveaAque9quS6juS9oApbMDE6MjIuODdd6LCB6K6p5L2g5rKJ6buY77yM5LiN5oeC5b6X6KGo5ryUClswMTozMC41MV3osIHorqnmiJHkuI7nlJ/mh6blvLEKWzAxOjM4LjkzXeaIkeS7rOaYr+S4ieS4qum7keeCuQpbMDE6NDcuMThd6L+e5oiQ5LiA56KX6Z2iClswMTo1NC42Ml3miJHliqrlipvorqHnrpfvvIzmgI7moLfmnIDlpKcKWzAyOjAyLjYxXeWNtOmdouS4tOabtOWkp+eahOWkluWbtApbMDI6NDMuMTFd5oiR5Lus5piv5Lik5qC555S157q/ClswMjo1MS4wOV3ov57mjqXkuoblj5jljovlmagKWzAyOjU4Ljk4XeWPquacieeBq+iKse+8jOiDveivgeaYjuWtmOWcqApbMDM6MDcuMDFd5a2Y5Zyo5oqK5L2g5oiR5Ye756m/ClswMzoxNC4wOF3nh4Png6flkKfvvIzliLrmv4DnmoTlvILlkbMKWzAzOjIyLjkwXemjnuWQkeabtOi/nOWkhOeahOW8guWRswpbMDM6MzAuNzld5LiL6Z2i55qE57u/6Imy5ZKM5LiK6Z2i55qE6JOd6ImyClswMzozOC45NV3pgqPmmK/puJ/nmoTnqbrpl7QKWzAzOjQ3LjA0XeaIkeS7rOaYr+Wbm+S4quS6ugpbMDM6NTQuOTRd5LiA5Liq5oCV5pel5Ye6ClswNDowMi45NF3kuIDkuKrlnKjljJfmlrnmmI/mmI/msonmsokKWzA0OjExLjA4XeS4gOS4quWcqOWNl+aWueWQg+iNlOaenQpbMDQ6MTkuMDJd5LiA5Liq5Lyq6KOF5oiQ6KW/6L6555qE5LqRClswNDoyNy4xMF3msqHmnInml7bpl7TmiZPpurvlsIYKWzA0OjM0Ljk4XeS4gOS4quS8quijheaIkOilv+i+ueeahOS6kQpbMDQ6NDMuMDdd5rKh5pyJ5pe26Ze05omT6bq75bCGClswNDo1MS43OV0=" 105 | }, 106 | { 107 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 108 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!570:/路-洗新革面.mp3?authkey=AIi2BPhsvSW-Bd0", 109 | "title": "路-洗心革面(Live)", 110 | "artist": "李志", 111 | "lyric": "W3RpOiDot68t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwMzozNS4wN10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC42N13ot68KWzAwOjAwLjk2XQpbMDA6MDIuMTdd6Iqx5YS/5Zyo6Lev5LiK562J552A5oiRClswMDowNy4zMl3nh5XlrZDmi6XmirHnnYDnqb/ooYwKWzAwOjEwLjkxXeacieS6m+aipuS8mueUn+mVvwpbMDA6MTMuNzFdClswMDoxNS4yMl3lsLHlg4/lnKjnqpflj7DvvIznnKnmmZXnmoTlhYnnur8KWzAwOjIyLjMwXeiDjOW9semHjOeahOS9oO+8jOaYr+S9jumfs+i/nui/ngpbMDA6MjcuMjBdClswMDozMS44MF3kuIDpmLXpo47mjqDov4fmiJHnmoTlv4MKWzAwOjM3LjYwXeWSjOS9oOmBpei/nOeahOW/g+aDhQpbMDA6NDEuMjRd5rmW6Z2i5aaC5q2k5bmz6Z2ZClswMDo0NS42MV3lsLHlg4/lnKjlpKnnqbrvvIznlLvlh7rkvaDnmoTohLgKWzAwOjUyLjU4XeaXtumXtOWDj+eOu+eSg++8jOWIuueXm+aIkeWPjOecvApbMDA6NTkuNDBdClswMToyNS4wMl3orqnmiJHku6znu6fnu63vvIzotormnaXotorpgaXov5wKWzAxOjMxLjkzXeeUqOaAneW/teaKiuWbnuW/hu+8jOaOqOWQkem7keaalwpbMDE6MzkuOTJdClswMTo0NS40Nl3kuIDpmLXpo47mjqDov4fmiJHnmoTlv4MKWzAxOjUxLjg2XeWSjOS9oOmBpei/nOeahOW/g+aDhQpbMDE6NTUuNzVd5oiR55yL552A5oiR6Ieq5bexClswMTo1OS41MV3miJHnnIvnnYDmiJHoh6rlt7EKWzAyOjAzLjQyXeS7v+S9m+WPiOeci+ingeS9oApbMDI6MDcuNTFd5oiR55yL552A5oiR6Ieq5bexClswMjoxMS41MF3ku7/kvZvlj4jnnIvop4HkvaAKWzAyOjE0LjQ1XQ==" 112 | }, 113 | { 114 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 115 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!585:/方式-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 116 | "title": "方式-洗心革面(Live)", 117 | "artist": "李志", 118 | "lyric": "W3RpOiDmlrnlvI8t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoyOS45OV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS41Nl3mlrnlvI8KWzAwOjA1LjM1XQpbMDA6NDcuOTRd5oiR5Y+q5pyJ5Zyo552h552A55qE5pe25YCZ5omN6IO95oSf6KeJ6L+Y5rS7552AClswMDo1NS4wMF3mgLvmmK/lnKjkvaDkuI3lnKjnmoTml7blgJnliIfogqTkuYvnl5voiKzniLHkvaAKWzAxOjA3LjMzXeWmguaenOaYjuWkqeaNouS4gOenjeaWueW8j+mCo+aYr+S7gOS5iApbMDE6MTcuNjFd5aaC5p6c5pa55byP6Kej5LiN5byA6LCc5Zui5Y+I5piv5LuA5LmIClswMToyNy41M10KWzAxOjI4LjI2XeaIkeecn+eahOeci+ingeW+ruW8seeahOWFieWcqOWJjemdouayoeaciemql+S9oApbMDE6MzcuNTRd6L+Z5piv5oiR5Z2a5L+h5oKy5Ymn55qE6LW35rqQ6ICM5oKy5Ymn5Lmf5Y+v5Lul5b+r5LmQClswMTo0OC4xNF3ov5nnp43nirbmgIHlhbblrp7kuIDnm7TpmpDnuqblrZjlnKjmsqHmnInpqpfkvaAKWzAxOjU3LjkyXeWwseeul+aYr+WwhuadpeS5n+aYr+WtmOWcqOWug+aYr+eUn+a0u+eahOacrOa6kApbMDI6MDcuOTNdClswMjowOS43MV3miJHlj6rmnInlnKjnnaHnnYDnmoTml7blgJnlgYfoo4Xlj4jmrbvkuoblh6DmrKEKWzAyOjE4LjgwXeiAjOS9oOS9k+S8muS4jeWIsOeIse+8jOe6v+adoeiIrOeahOaEn+WumApbMDI6MjcuNjVdClswMjoyOS4wMV3ku5bku6zljZbmjonniZvlkozlsI/puqbvvIzlvKDlmLTlkbzlkLjnqbrmsJQKWzAyOjM5LjQxXeeZveWktOe/gemjnui/h+aLluaLieacuu+8jOeUn+mUiOWcsOeliOaxggpbMDI6NDguMzFd" 119 | }, 120 | { 121 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 122 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!575:/你好明天-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 123 | "title": "你好明天-洗心革面(Live)", 124 | "artist": "李志", 125 | "lyric": "W3RpOiDkvaDlpb3mmI7lpKkt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNToxOS41Nl0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC45MV3kvaDlpb3mmI7lpKkKWzAwOjAzLjYxXQpbMDI6MDMuMTld5L2g5aW95Yy755SfClswMjowNy45NF3kvaDog73kuI3og73miormiJHmnYDkuoYKWzAyOjEzLjI2XeaIkeeahOiDuOWPowpbMDI6MTcuOTZd5aW95YOP6KKr5LuW5Lus5aC15L2P5LqGClswMjoyMy40OF3mjo/kuobljYrlpKnku4DkuYjpg73msqHmnIkKWzAyOjI4LjQ4XeS9huiDveaEn+inieW/g+i3s+WKoOW/qwpbMDI6MzMuNzld56qB5Y+R5aWH5oOz5Y675LiA5Liq5Zyw5pa5ClswMjozOS4zMl3liLDkuobkuYvlkI7lj4jmg7Plm57mnaUKWzAyOjQzLjgwXQpbMDI6NDYuOTZd5L2g5aW95YWI55SfClswMjo1MS42Ml3kvaDog73kuI3og73pl63kuIroh63lmLQKWzAyOjU3LjAzXemCo+S6m+S6i+aDhQpbMDM6MDEuOTNd5ZKM5oiR5rKh5Y2K5q+b6ZKx5YWz57O7ClswMzowNy4xN13or7TmnaXor7Tljrvlhajku5blpojlup/or50KWzAzOjEyLjMzXeaIkeWPquaDs+mZquedgOWbsOmavuWPkeWRhgpbMDM6MTcuMzdd5aSc5pma5aW95Z2P5piv5aSc5pma55qE5LqLClswMzoyMi44OF3oi7nmnpzng4LkuoblsLHor6XmiZTmjokKWzAzOjI3LjgzXQpbMDM6MzUuOTBd5Lmx5LqG5Lmx5ZCnClswMzo0MC44N13kubHns5/ns5/nmoTmnInlpLTmnInohLgKWzAzOjQ2LjA3XeWIq+ivtOWBnOatogpbMDM6NTEuMjNd5ZOq5pyJ5LuA5LmI6YeN5paw5byA5aeLClswMzo1Ni4zOF3kuIDlnZfpnaLljIXphY3kuIDmna/lkpbllaEKWzA0OjAxLjQ5Xeivl+aDheeUu+aEj+S4gOa7qeeLl+WxjgpbMDQ6MDYuNjVd5oCO5LmI5rKh5pyJ55+z5aS05o6J5LiL5p2lClswNDoxMS44Ml3orqnmiJHmrbvkuo7kuIDlnLrmhI/lpJYKWzA0OjE4LjI4XQpbMDQ6NDguMjNd5L2g5aW95piO5aSpClswNDo1NS43N13kvaDlpb3nlJ/mtLsKWzA1OjAzLjk3XeS9oOWlveaYjuWkqQpbMDU6MTEuMjdd5L2g5aW9IDIwMTgKWzA1OjE3LjE5XQ==" 126 | }, 127 | { 128 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 129 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!586:/杭州-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 130 | "title": "杭州-洗心革面(Live)", 131 | "artist": "李志", 132 | "lyric": "W3RpOiDmna3lt54t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwMzoyOC45OV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC45OV3mna3lt54KWzAwOjAzLjk1XQpbMDA6MzQuNjFd5bCx5YOP5piv5LiA5Zy65oiY5LqJIOeOsOWcqOmcgOimgeWkp+mbqOa1h+eBreeQhuaApwpbMDA6MzkuMzRd6LCB5Lmf5peg5rOV6YCD6ISxIOaIluaYr+WHj+WwkeS8pOS6oQpbMDA6NDUuOTZd6buE5qW86YeM5pyJ5Liq55S35Lq65Zyo5by56ZKi55C0IOi6q+i+ueeahOWwkeWls+WBt+aDhQpbMDA6NTAuODBd5LiA5p2v6ZW/5bKb5LiL6IKaIOi9rOi6q+i3s+i/m+ilv+a5lgpbMDA6NTYuOTNd5om+5Lmf5om+5LiN5Yiw5Lmd5YWt5bm055qE5Zue5b+GClswMTowNS4wMF3lv5jkuZ/lv5jkuI3kuobmrabmnpfpl6jnmoTlm57lv4YKWzAxOjEyLjI0XeS4uuS9leWcqOaFjOS5seS4reWGsui/m+i/meWfjuW4guaKiuS4gOWIh+aJk+S5sQpbMDE6MTkuOTld5piv5pyI5LquIOaYr+a4heaziSDmmK/liY3lubTnmoTnirnosasKWzAxOjI2LjIyXQpbMDE6NTIuNjNd6ZSZ6L+H5piv5LiA5Liq6ZSZ6K+vIOWvu+aJvuaYr+S4gOS4qumUmeivrwpbMDE6NTYuMjFd6YeN5aGR5piv5LiA5Liq6ZSZ6K+vIOmGkuS6huaJjeWPkeeOsOayoeaciemAgOi3rwpbMDI6MDQuMDdd5o6P5Ye65L2g5bem5omL55qE5omL5p6q5Y+z5omL55qE6I+c5YiA5Lit6Ze055qE5Ye25ZmoClswMjoxMC45OF3lo67ng4jnmoTlkJHmiJHlvIDngq4KWzAyOjE1LjQwXeeBsOmjnueDn+eBreeahOaYr+aIkeeahOeBtemtggpbMDI6MjMuMTJd6JeV5pat5Lid6L+e55qE5piv6L+Z5bqn5Z+O5rGgClswMjozMC4yNl3lrrbpqo/msYLmsYLkvaDvvIzlnKjnvo7kuL3nmoTkuYnkuYznrYnmiJEKWzAyOjM4LjEyXeS4uum7keWrgiDkuLrmoYPoirEg5Li66YKj55uG54Kt54GrClswMjo0NS41MV3orqnmiJHmn6XkuIDkuIvosLfmrYzlnLDlm77ljJfku5HmgI7kuYjotbAKWzAyOjUyLjg2XeWOu+eci+S9oCDljrvniLHkvaAg5YaN5oKE5oKE56a75Y67" 133 | }, 134 | { 135 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 136 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!588:/不多-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 137 | "title": "不多-洗心革面(Live)", 138 | "artist": "李志", 139 | "lyric": "W3RpOiDkuI3lpJot5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwMzozOS4wMV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC41Ml3kuI3lpJoKWzAwOjA1LjMwXQpbMDA6MzMuNzFd5aSa5aSa5L2g5LiN6KaB5ZOtIOmVv+Wkp+S9oOWwseS8mua4healmgpbMDA6MzguNDZd6L+Z5LiW55WM5rKh5pyJ5Lq6IOWvueS9oOecn+eahOWcqOS5jgpbMDA6NDQuNDNd5aSa5aSa5L2g5LiN6KaB5oCVIOaIkeS4jeS8mumAvOS9oOWtpuWQieS7lgpbMDA6NDguODhd5L2g5piv5L2g5oiR5piv5oiRIOWQhOacieWQhOeahOaDs+azlQpbMDA6NTQuMjJd5LiN5LmF5Lul5ZCO55qE5p+Q5aSpIOaIkeWwsei/meagt+eahOiAgeS6hgpbMDA6NTkuMjNd5L2g5LiN55So6KOF5L2c5aSa5LmI55qE6Zq+6L+HClswMTowNC4zN13kvaDmmK/kvaDmiJHmmK/miJEg6LCB6YO96Zq+5YWN5Lya5a2k54usClswMTowOS41NF3kvaDmmK/kvaDmiJHmmK/miJEg6LCB6YO96Zq+5YWN5Lya5a+C5a+eClswMToxNC43N10KWzAxOjE4LjgxXeWkmuWkmuS9oOWIq+mXruaIkSDnlJ/mtLvliLDlupXmmK/ku4DkuYgKWzAxOjIzLjY2XeS7luS7rOS6uuexu+ayoemBk+eQhiDmiJHkuI3mh4LnmoTlpKrlpJoKWzAxOjI5LjA2XeWkmuWkmuS9oOWIq+Wus+aAlSDlpoLmnpzkvaDnnJ/nmoTniLHkuIrku5YKWzAxOjM0LjAyXeeUqOecn+W/g+eUqOecn+aDhSDliKvnrqHku6XlkI7nmoTnu5PmnpwKWzAxOjQwLjAyXeW/heeEtuaciemCo+S5iOS4gOWkqSDkvaDlsLHnqoHnhLbnprvlvIDmiJEKWzAxOjQ0LjYxXeS9oOS4jeimgeijheS9nOWkmuS5iOeahOect+aBiwpbMDE6NDkuNTdd5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpwpbMDE6NTQuNzld5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpwpbMDE6NTkuODhdClswMjo0NC4zOF3kuZ/orrjkuI3kuYXnmoTmn5DlpKkg5oiR56qB54S25bCx56a75byA5L2gClswMjo0OS4wN13kvaDkuI3opoHoo4XkvZzlpJrkuYjnmoTnnLfmgYsKWzAyOjUzLjI0XQpbMDM6MDEuNjld5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpwpbMDM6MDkuMjhd5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpwpbMDM6MTYuNDhd5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpwpbMDM6MjQuMjJd5L2g6LWw5ZCn5L2g56yR5ZCnIOS9oOaJvuWvu+S9oOiHquW3seWQpw==" 140 | }, 141 | { 142 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 143 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!574:/被禁忌的游戏-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 144 | "title": "被禁忌的游戏-洗心革面(Live)", 145 | "artist": "李志", 146 | "lyric": "W3RpOiDooqvnpoHlv4znmoTmuLjmiI8t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNTozMS4yM10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC44M13ooqvnpoHlv4znmoTmuLjmiI8KWzAwOjAzLjcwXQpbMDE6MTYuMTVd5rKJ6buY55qE5L2gIOmYs+WFieiQp+eRn+eahOagkeaelwpbMDE6MjMuMTdd6YKj5Lqb5L2g54ix55qE5Lq6IOa4qeaflOW+l+mCo+S5iOaflOi9rwpbMDE6MjkuMzRdClswMTozMC45MV3ml6Dnn6XnmoTmiJEg5piv6JC95Y+26JC95a+e5Y+I6JC96a2EClswMTozOC45MV3nnIvlvoDlt53mtYHnmoTkurrnvqQg56m/6LaK5rKJ6buY55qE546w5ZyoClswMTo0NC45MV0KWzAxOjQ2LjY3XeWRvOWVuOiAjOi/h+eahOmdkuaYpSDmsonpu5jkuI3or63nmoTkvaAKWzAxOjU0LjE4XeWNs+S9v+e7meaIkeS4queBv+eDguaYjuWkqSDorqnmiJHlv4/mgpTnmoTkvaAKWzAyOjAxLjUxXQpbMDI6MDIuMzNd6L+Z6KKr56aB5b+M55qE5ri45oiPIOaXqeW3suW/mOiusOeahOWygeaciApbMDI6MDkuOThd6L+Z6KKr56aB5b+M55qE5ri45oiPIOS4gOWmguaXouW+gOeahOWygeaciApbMDI6MTcuMTBdClswMjo0OS43Nl3pmo/po47po5jojaHnmoTmiJHku6wg6buR5aSc6YeM5a+75om+5LiA54K554K55qyi5oSJClswMjo1Ny42OF3lho3mrKHpnaLlr7nov5nmmKXoibIg5aSx6JC955qE5LiN55+l5omA5LulClswMzowMy4wMl0KWzAzOjA0LjQyXeaal+iHquWPueaBr+WPiOaal+iHquS8pOW/gyDmuLjmiI/lt7LlpoLmraTpmYznlJ8KWzAzOjEyLjQ4Xeeci+W+gOW3nea1geeahOS6uue+pCDnqb/otormsonpu5jnmoTnjrDlnKgKWzAzOjE5LjE4XQpbMDM6MjAuMzdd5ZG85ZW46ICM6L+H55qE6Z2S5pilIOayiem7mOS4jeivreeahOS9oApbMDM6MjguMTBd5Y2z5L2/57uZ5oiR5Liq54G/54OC5piO5aSpIOiuqeaIkeW/j+aClOeahOS9oApbMDM6MzQuMjNdClswMzozNS44Nl3ov5nooqvnpoHlv4znmoTmuLjmiI8g5pep5bey5b+Y6K6w5LqG5bKB5pyIClswMzo0My42NV3ov5nooqvnpoHlv4znmoTmuLjmiI8g5LiA5aaC5pei5b6A55qE5bKB5pyIClswMzo1MC4zOF0=" 147 | }, 148 | { 149 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 150 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!571:/哦吼-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 151 | "title": "哦吼-洗心革面(Live)", 152 | "artist": "李志", 153 | "lyric": "W3RpOiDlk6blkLwt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoyOS42NF0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS4xOF3lk6blkLwKWzAwOjA1LjA5XQpbMDA6MjQuMDdd5Y+R5Ye65LqG5pyA5ZCO55qE5aOw6Z+z6L+r5YiH56a75byAClswMDozMi4xMl3ljbPkvb/mnInku4DkuYjkuovmg4Xov5jmsqHmnInlgZrlrowKWzAwOjQwLjEzXeayoeacieiwgeWcqOS5juiwgemaj+WQjueahOmdouWvuQpbMDA6NDguMjNd5piv55ay5oOr5piv55ay5YCm5oOv5oCn55qE5L2gClswMDo1NS45M13lgrvph4zlgrvmsJTnmoTlnLDpk4EKWzAxOjAwLjE5XeWGsuWHuuS6humrmOaetuahpQpbMDE6MDQuMzld6L2m5aS05Zyo5aSV6Ziz6KGw6ICBClswMTowOC4xNF3lubPmt6Hlvpflg4/kuIDlj6rnjKsKWzAxOjE0LjIyXeWYvyDlk44g5Zi/IOWTjgpbMDE6MjIuMzhd5Zi/IOWTjiDlmL8g5ZOOClswMTozMC42N13nlJjolJfku4DkuYjml7blgJnmiY3og73kuIrluIIKWzAxOjM4Ljc5XeiHqueUseWViuawkeS4u+WViuWTpuWQvApbMDI6MTQuMjhd5Y+R5Ye65LqG5pyA5ZCO55qE5aOw6Z+z6L+r5YiH56a75byAClswMjoyMS4xMF3ljbPkvb/mnInku4DkuYjkuovmg4Xov5jmsqHmnInlgZrlrowKWzAyOjI4LjAxXeayoeacieiwgeWcqOS5juiwgemaj+WQjueahOmdouWvuQpbMDI6MzQuNzNd5piv55ay5oOr5piv55ay5YCm5oOv5oCn55qE5L2gClswMjo0MS44OV3kvaDnmoTpl67popjmmK/mhJrooKIKWzAyOjQ1LjA1XeWfuuWboOmHjOmVv+a7oemHjuiNiQpbMDI6NDguNTBd6I+c5Zy66YeM5q+P5LiA5Liq5Lq6ClswMjo1MS44N13mjJHnnYDnm7jlkIznmoTpkrvnn7MKWzAyOjU3LjIzXeWYvyDlk44g5Zi/IOWTjgpbMDM6MDQuNjRd5Zi/IOWTjiDlmL8g5ZOOClswMzoxMC44OV3lgZzlnKjov5nph4zkvJrkuI3kvJrotLTnvZrljZUKWzAzOjE3LjY5XeW/q+S4gOeCueWwkeS4gOeCueWTpuWQvApbMDM6MjUuMThd5Zi/IOWTjiDlmL8g5ZOOClswMzozMS40N13lmL8g5ZOOIOWYvyDlk44KWzAzOjM4LjMwXeaAu+WcqOasouS5kOeahOaXtuWAmeWxj+S9j+awlApbMDM6NDUuMTBd5b+954S26Ze05oSf6KeJ5Yiw5ZOm5ZC8ClswMzo1MC44MF0=" 154 | }, 155 | { 156 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 157 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!560:/黑色信封-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 158 | "title": "黑色信封-洗心革面(Live)", 159 | "artist": "李志", 160 | "lyric": "W3RpOiDpu5HoibLkv6HlsIEt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNDoyOS45OF0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC44MF3pu5HoibLkv6HlsIEKWzAwOjA1LjIwXQpbMDA6NDAuMDJd5LiA5aSp5pma5LiK5oiR55qE5LiA5Liq5pyL5Y+L5oKE5oKE55qE5p2l55yL5oiRClswMDo0OS45OV3ku5bnmoTnnLznnZvlg4/lpJbpnaLnmoTmnIjkuq7mmK/lv6fpg4HnmoQKWzAwOjU5Ljc1XeS7luaKk+i1t+aIkeahjOS4iueahOmCo+S4quiLueaenOi9u+i9u+eahOWSrOS6huS4gOWPowpbMDE6MDkuMzZd5LuO5LiK6KGj55qE5Y+j6KKL6YeM5o6P5Ye65LiA5Liq5L+h5bCB5a+55oiR6K+0ClswMToxOC44N13ku5bor7Tov5nkuJbnlYzmmK/kuI3mmK/miJHku6znmoQKWzAxOjIzLjU1XeaIkeW6lOivpeepv+S7gOS5iOWQg+S7gOS5iApbMDE6MjguMThd5aaC5p6c5rKh5pyJ5Lq655yL552A5oiRClswMTozMi41Nl3pgqPor6XlpJrlv6vkuZAKWzAxOjM2LjQwXQpbMDE6MzguNjZd5LuW6K+06L+Z5LiW55WM5LiN6K+l5piv5oiR5Lus55qEClswMTo0My4wN13niLjniLjlkozlpojlpojkuZ/kuI3or6XmnInnmoQKWzAxOjQ3LjgwXeaIkeWPr+aYr+S4queUt+S6uuS4uuS7gOS5iOaJk+S4jei1t+eyvuelngpbMDE6NTUuMDFdClswMjo0NC4wN13kuIDkupvlpKnlsLHlg4/ov4fljrvpgqPmoLflubPmt6HnmoTlsLHov4fljrvkuoYKWzAyOjU0LjEzXeWcqOWQjOagt+eahOS4gOS4quWknOaZmumCo+S4quaci+WPi+aJk+adpeeUteivnQpbMDM6MDQuMzVd5LuW6K+05LuW5Zyo5LiA5Liq6ZmM55Sf55qE5Zyw5pa55LiA5Liq5Lq65ZSx552A5q2MClswMzoxNC4xNF3miJHnnIvnnYDku5bnlZnkuIvnmoTpgqPkuKrkv6HlsIHmg7Potbfku5bor7TnmoTor50KWzAzOjIzLjMwXeS7luivtOi/meS4lueVjOaYr+S4jeaYr+aIkeS7rOeahApbMDM6MjcuOTJd5oiR5bqU6K+l56m/5LuA5LmI5ZCD5LuA5LmIClswMzozMi42MF3lpoLmnpzmsqHmnInkurrnnIvnnYDmiJEKWzAzOjM2LjU5XemCo+ivpeWkmuW/q+S5kApbMDM6NDIuNjZd5LuW6K+06L+Z5LiW55WM5LiN6K+l5piv5oiR5Lus55qEClswMzo0Ny4xN13niLjniLjlkozlpojlpojkuZ/kuI3or6XmnInnmoQKWzAzOjUwLjg1XQpbMDM6NTEuNTZd5oiR5Y+v5piv5Liq55S35Lq65Li65LuA5LmI5omT5LiN6LW357K+56WeClswMzo1OS42M10=" 161 | }, 162 | { 163 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 164 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!572:/寻找-忽然-热河-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 165 | "title": "寻找-忽然-热河-洗心革面(Live)", 166 | "artist": "李志", 167 | "lyric": "W3RpOiDlr7vmib4t5b+954S2LeeDreaysy3mtJflv4PpnanpnaJdClthcjog5p2O5b+XXQpbYWw6IOa0l+W/g+mdqemdol0KW2J5OiDlpKnprYJdClt0b29sOiDmrYzor43mu5rliqjlp6wgaHR0cHM6Ly9scmMtbWFrZXIuZ2l0aHViLmlvXQpbbGVuZ3RoOiAxMzo0OS43OF0KWzAwOjE4LjM2XeWvu+aJvgpbMDA6MjUuNDBdClswMDozNS43Ml3miJHlnKjmgbblv4PnmoTkuJbnlYzph4zvvIzlr7vmib7kuIDkuKrlg4/kvaDnmoTkuroKWzAwOjQzLjQ1XeWcqOavj+S4quaDs+S9oOeahOWkj+WkqemHjO+8jOetieWPpuS4gOenjeaEn+aDhQpbMDA6NTEuNjhd5oiR5Zyo5aSx6LSl55qE55Sf5rS76YeM77yM5a+75om+5LiA5Liq54ix5oiR55qE5Lq6ClswMDo1OS40Ml3miJHnmoTmgrLkvKTvvIzmtarmvKvlkozlubvmg7PvvIzkuI3lr7nlpbnor7TotbcKWzAxOjA3Ljk1XeaIkeWGjeS5n+S4jeS8muaKiuiHquW3se+8jOaEmuigoueahOS6pOe7mei/h+WOuwpbMDE6MTUuNjFd5oiR55qE55CG5oOz5ZKM5oiR55qE5oOz5rOV77yM5LuO5q2k55u46ZqU5LqG5LiH6YeMClswMToyMy45MV3miJHmlbTlpJzmlbTlpJzlnLDlpLHnnKDvvIzkuI3mmK/kuLrkuoblkozosIHlho3nm7jop4EKWzAxOjMxLjUyXeabvue7j+eIseS9oOeahOavj+S4gOadoeihl++8jOaYr+aIkeaWsOmynOeUn+a0u+eahOi1t+eCuQpbMDI6MDkuNzRd5oiR5Zyo6ZmM55Sf55qE5oSf5Yqo6YeM77yM5a+75om+5LiA5Liq5YOP5L2g55qE5Lq6ClswMjoxNy40Nl3lsLHnrpflg4/ov4fljrvkuIDmoLfooqvor6/op6PvvIzkuI3lv6vkuZDlj4jlpoLkvZUKWzAyOjIzLjAxXQpbMDI6MjUuOTBd5oiR5Zyo5aSx6LSl55qE55Sf5rS76YeM77yM5a+75om+5LiA5Liq54ix5oiR55qE5Lq6ClswMjozMy42M13lpbnnmoTlloToia/vvIznlJzonJzlkozpmLPlhYnvvIzpmarkvLTmiJHoh6rlt7EKWzAyOjQyLjQ5XeaIkeWGjeS5n+S4jeS8muaKiuiHquW3se+8jOW9u+W6leeahOS6pOe7meS4gOS4quS6ugpbMDI6NDkuNzNd5oiR55qE55Sf5rS75ZKM5oiR55qE6buR5aSc77yM5LiA5YiG5LiA56eS55qE5pat6KOCClswMjo1Ny45NV3miJHkuIDlpKnkuIDlpKnlnLDlj5HlkYbvvIzkuI3mmK/kuLrkuobphZ3phb/kupvku4DkuYgKWzAzOjA1Ljc3Xeabvue7j+eIseS9oOeahOiiq+S7luS7rOavgeeBre+8jOi/mOacieS7gOS5iOS4jeiDveWOu+aLkue7nQpbMDM6MTQuMDBd5oiR5YaN5Lmf5LiN5Lya5oqK6Ieq5bex77yM5b275bqV55qE5Lqk57uZ5LiA5Liq5Lq6ClswMzoyMi4wMF3miJHnmoTnkIbmg7PlsLHlg4/ov5npu5HlpJzvvIzkuIDliIbkuIDnp5LnmoTmlq3oo4IKWzAzOjMwLjAxXeaIkeS4gOWkqeS4gOWkqeWcsOWPkeWRhu+8jOS4jeaYr+S4uuS6humFnemFv+S6m+S7gOS5iApbMDM6MzcuNzBd55yf5oOF5pep5bey57uP6KKr5LuW5Lus5q+B54Gt77yM6L+Y5pyJ5LuA5LmI5LiN6IO95Y675ouS57udClswMzo0NS40Ml0KWzAzOjUwLjUxXQpbMDM6NTcuODdd5b+954S2ClswMzo1OS4xMV0KWzA0OjMyLjExXeW/veeEtuWwsea1geWHuuazquadpe+8jOW/veeEtuaDs+imgeWQrOWIsOWlueeahOWjsOmfswpbMDQ6NDEuNjVd6ICM5oiR5Y205LuA5LmI6K+d6YO96K+05LiN5Ye65p2lClswNDo0Ny4zMl0KWzA0OjQ4LjA2XeaYr+iwgeWcqOa4qeaaluS9oO+8jOacieiwgeS8muiuqeaIkeinieW+l+i/meWknOaZmui/mOacieacn+ebvApbMDQ6NTkuODRd5oiR5bCx5Lya6Lef552A5a6D5Y676L+c6KGMClswNTowMy43N10KWzA1OjIwLjAzXeWPr+aYr+S9oOWcqOWTqumHjO+8jOWPr+aYr+aYjuWkqemGkuadpeeahOesrOS4gOiEuOmYs+WFiQpbMDU6MjkuNDdd5piv5ZCm77yM5Lya5YOP5qKm6YeM5LiA5qC35piO5LquClswNTozNC45M10KWzA1OjM1Ljg3XeW5u+aDs+acneilv+eahOeUn+a0uwpbMDU6NDAuNDdd5bm75oOz552A5L2g6KKr54Gv5YWJ5Lyk5oSf5LqG5a+C5a+eClswNTo0NS41M13mnIDlkI7vvIzmiJHkuIDkuKrkurrotorotbDotorlraTljZUKWzA1OjUxLjIyXQpbMDU6NTIuMDJd5bm75oOz5pyd6KW/55qE55Sf5rS7ClswNTo1Ni4yM13lubvmg7PnnYDkvaDooqvlrrPmgJXlrprmoLzkuobop5LokL0KWzA2OjAxLjU0XeacgOWQju+8jOaIkeS4gOS4quS6uui2iui1sOi2iuWtpOWNlQpbMDY6MDcuODhdClswNjowOC41OF3lrrPmgJXmnJ3opb/nmoTnlJ/mtLsKWzA2OjEyLjA2XeWus+aAleedgOS9oOiiq+eBr+WFieS8pOaEn+S6huWvguWvngpbMDY6MTcuNDld5pyA5ZCO77yM5oiR5Lus5bCx6LaK6LWw6LaK5a2k5Y2VClswNjoyNS4zOF0KWzA2OjMxLjQ3XQpbMDY6NTMuNjRd54Ot5rKzClswNzowNy40N10KWzA3OjIwLjU5XeeDreays+i3r+WwseWDjyDlhavljYHlubTku6PnmoTph5HlnZvljr8KWzA3OjI4LjYyXeaip+ahkOWeg+WcvueBsOWwmApbMDc6MzEuMzZd5ZKM5ZCE5byP5ZCE5qC355qE5p2C6LSn5bqXClswNzozNi41NF3mr4/lpKnpg73mnInlnKgKWzA3OjQ0LjM2XeWcqOWkqem7keWJjeepv+S4iuavm+ihowpbMDc6NDcuMzFd54K55LiA5qC554OfClswNzo1Mi4zNF3ng63msrPot6/mnInkuIDlrrYKWzA3OjU0LjY4XeW8gOS6huWlveWkmuW5tOeahOeQhuWPkeW6lwpbMDg6MDAuMjdd5LiN566h5Ymq5LuA5LmI5qC355qE5Y+R5Z6LClswODowMy4yOF3kvaDlj6ropoHku5jkupTlnZfpkrEKWzA4OjA4LjU0XeiAgeadv+WSjOWlueeahOWmueWmueWdkOWcqOakheWtkOS4igpbMDg6MTIuMDVd5a+5552A6ZWc5a2Q5LiA6KiA5LiN5Y+RClswODoxNi4zNl3ku5bku6znmoTogIHlrrblnKjouqvlkI4KWzA4OjE4LjcyXeWcqOWyuOi+ueWcqOWuieW+veWFqOakkuWOvwpbMDg6MjQuMDhd5rKh5pyJ5Lq65Zyo54Ot5rKz6Lev6LCI5oGL54ixClswODozMi4wN13mgLvmnInkurrlnKjlpKnkuq7ml7bkvKTmhJ8KWzA4OjM5LjU5XeWmguaenOW5tOi9u+aXtuS9oOayoeadpei/h+eDreays+i3rwpbMDg6NDcuNjFd6YKj5L2g546w5Zyo55qE55Sf5rS75piv5LiN5piv5b6I5bm456aPClswOToyOC41Nl3nuqrlv7XnopHml4HmnInkuIDlrrbnoLTml6fnmoTnlLXlvbHpmaIKWzA5OjM2LjQwXeW+gOWMl+i1sOS6lOeZvuexs+WwseaYr+WNl+S6rOeBq+i9puilv+ermQpbMDk6NDQuNTdd5q+P5aSp6YO95pyJ5aSW5Zyw5Lq6ClswOTo0Ni4yNV3lnKjnm7Tnur/lkozmm7Lnur/kuYvpl7Tov7fot68KWzA5OjUyLjQwXeawlOWWmOWYmOWYmOecvOazquaooeezigpbMDk6NTQuNzFd5aWU6LeR6LeM5YCS5aWU6LeRClsxMDowMC41MF3np4vmnpfpvpnomb7mjaLkuobmlrDnmoTlnLDmlrkKWzEwOjAzLjA2XTMy6Lev6L+Y5piv56m/6L+H5oy55rGf6ZeoClsxMDowOC40Ml3pq5jmnrbmoaXmi4bkuobkv67kuobmlrDnmoTpmqfpgZMKWzEwOjEwLjQ0Xei1sOadpei1sOWOu+i1sOS4jeWHuuaIkeeahOebkOS7k+ahpQpbMTA6MTYuNTNd5p2l5Yiw5Z+O5biC5bey57uP5YWr55m+5Lmd5Y2B5YWt5aSpClsxMDoxOS4yNF3ng63msrPot6/kuIDnm7TmmK/nm7jlkIznmoTlrrnpopwKWzEwOjI0LjQ4XeWBtuWwlOacieW5suWHgOeahOa9mOilv+i3r+i/hwpbMTA6MjcuMTFd5aW55LiN5Lya6K+05L2g5aW95YaN6KeBClsxMDozMi45OV3msqHmnInkurrlnKjng63msrPot6/osIjmgYvniLEKWzEwOjQwLjAyXeaAu+acieS6uuWcqOWkqem7keaXtuS8pOaEnwpbMTA6NDcuNDZd5aaC5p6c5bm06L275pe25L2g5p2l6L+H54Ot5rKz6LevClsxMDo1NS41Nl3pgqPkvaDnjrDlnKjmmK/kuI3mmK/lt7Lnu4/ooqvku5bku6zmt7nmsqEKWzExOjA0LjEzXeayoeacieaWsOeahOiho+acjeiDveiuqeS9oOeIseaBiwpbMTE6MTIuMTBd5oC75pyJ5LiA56eN5aSp5rCU6K6p5oiR5oCA5b+1ClsxMToxOS44OF3phpLmnaXmiJbogIXlkIPppbHlj4jmmK/kuIDlubQKWzExOjI3Ljg1XeebuOmBh+eEtuWQjuWIhuWIq+WwseWcqOS4gOWkqQpbMTE6MzUuOTdd" 168 | }, 169 | { 170 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 171 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!587:/大象-洗心革面.m4a?authkey=AIi2BPhsvSW-Bd0", 172 | "title": "大象-洗心革面(Live)", 173 | "artist": "李志", 174 | "lyric": "W3RpOiDlpKfosaEt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNjowOS45N10KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS4xMF3lpKfosaEKWzAwOjAzLjQyXQpbMDI6MjUuMzhd55So6YKj5Y+q57y66KeS55qE6Lqr5L2T5Y675YG36KKt55y85YmN6L+Z5Y+q5Y2I552h55qE5aSn6LGhClswMjo0OS4zMl3lho3lgYfoo4XlubbmsqHmnInlj5HnjrDljprlrp7nmoTnmq7ogqTog73po57liLDmoJHmnp0KWzAzOjEwLjMwXeWug+S7rOeQhuino+eahOeZveWkqeWwseaYr+atpOWIu+aZg+iNoeeahOa1t+W4guicg+alvApbMDM6MTYuMjhd5Y2H6IW+55qE56m65rCU6YeM5rKh5pyJ57u/6I2J5ZKM5Yia5Yia5a2m5Lmg6aOe57+U55qE6bifClswMzo0Ni40N13llaTphZLkuI3or6XmnInnnLzms6rkuI3or6XmnInpopzoibLlpJzmmZrkuZ/kuI3lubPmlbQKWzA0OjEwLjM2XeWjsOmfs+S4jeivpeaYr+e+juWlveiwgeWPiOS8muS7i+aEj+WPquaYr+ihqOa8lOe8heaAgOaAqOW/tQpbMDQ6MzIuMjdd546v5Y2r5bel5Lq65LiN5Zad5ZWk6YWS56u5562+5peg5rOV57un57ut5YuD6LW3ClswNDozNy4zOV3ogq7ohI/mtojlpLHlnKjngavnhLDlkozllL7mtrLkuK3noLTnoo7lkZDllornu5nlpKnkuq7nkIbnlLEKWzA0OjQzLjM2XeeqgeeqgemXquWFieeahOWFrOWFseaxvei9puWCrOecoOeWsuaDq+eahOemj+W7uuiAgeadvwpbMDQ6NDkuMjld5a2p5a2Q5Lus5Zyo5Y2D6YeM5LmL5aSW5qKm6KeB5LiA5Y+q55i46IW/55qE5aSn6LGhClswNDo1NS42OV0=" 175 | }, 176 | { 177 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 178 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!569:/门-尽头 洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 179 | "title": "门-尽头-洗心革面(Live)", 180 | "artist": "李志", 181 | "lyric": "W3RpOiDpl6gt5bC95aS0Lea0l+W/g+mdqemdol0KW2FyOiDmnY7lv5ddClthbDog5rSX5b+D6Z2p6Z2iXQpbYnk6IOWkqemtgl0KW2xlbmd0aDogMTE6MTguNjRdClt0b29sOiDmrYzor43mu5rliqjlp6wgaHR0cHM6Ly9scmMtbWFrZXIuZ2l0aHViLmlvXQpbMDA6MDAuOTZd6ZeoClswMDowNy42MF0KWzAwOjUzLjMwXeaAu+WcqOi/meenjeaXtuWAmQpbMDA6NTUuMzNd5oSf6KeJ6Ieq5bex5bey57uPIOmjnueahOWkqui/nApbMDE6MDEuNDld6Lev54Gv5YWo6YO954Gt5LqGClswMTowMi45M10KWzAxOjAzLjYzXeS4jeiDveegtOWdj+WIq+S6uueahOW5uOemjwpbMDE6MDkuMzJd5LuO5rKh6KeB6L+H55qE57uG6IOeClswMToxMi4wNV3nnaHooaPlkozooYzmmJ8KWzAxOjE3LjM4Xei/mOaciei2tOWcqOeOu+eSg+S4iueahOeBtemtggpbMDE6MjEuMzBdClswMToyNS43MF3lroPorqnmiJHnmoTlv4Plh4nkuoblj4jng63kuoYKWzAxOjMyLjM3XeWug+ivtOeUn+eUn+atu+atu+eahOeIseaBi+WPiOiDveWmguS9lQpbMDE6MzcuNzhdClswMTozOS43MF3nm7jkv6HlkKfvvIznm7jkv6HmiJHku6zmm77nu4/mgZDmg6fnmoTkuIDliIcKWzAxOjQ4LjIwXeebuOS/oeWQp++8jOmXqOW8gOS6hgpbMDE6NTMuODZd55u45L+h5ZCn77yM55u45L+h5oiR5Lus5pu+57uP5peg5aWI55qE5bKB5pyIClswMjowMi40OF3pl6jlvIDkuobvvIzlroPmnaXkuoYKWzAyOjA1Ljc5XQpbMDI6NDEuMzdd5pyJ5pe25qyj5Zac6Iul54uC77yM5pyJ5pe25oSf6KeJ5LiN5Yiw55Sf6ZW/ClswMjo0OS40MV3pu5Hmmpfph4znmoTnp5jlr4bvvIzkvaDlpKnnlJ/nmoTnvo7kuL0KWzAyOjU3LjkzXeWtpOeLrOadpeiHquiEhuW8seeahOaVj+aEnwpbMDM6MDUuOTRd5pWP5oSf5peg5rOV5oqK576O5Li955yL56m/ClswMzoxMC41NV0KWzAzOjExLjg1XeebuOS/oeWQp++8jOebuOS/oei9sOi9sOeDiOeDiOaYr+S9oOeahOacquadpQpbMDM6MjAuMTdd55u45L+h5ZCn77yM6Zeo5byA5LqGClswMzoyNS45MF3nm7jkv6HlkKfvvIznm7jkv6Hlj43lj43lpI3lpI3mmK/miJHku6zmg4XmgIAKWzAzOjMzLjkzXemXqOW8gOS6hu+8jOWug+adpeS6hgpbMDM6MzguNjldClswNDowOC45Ml0KWzA0OjUzLjUwXQpbMDU6MDMuMDVdClswNToyMC40OF0KWzA3OjA3LjA5XeWwveWktApbMDc6MTkuNDddClswODozOC4wMV3ot6/nmoTlsL3lpLTmmK/muZYKWzA4OjQ1Ljk0Xea5lueahOWwveWktOaYr+S9oApbMDg6NTMuOTZd5L2g55qE5bC95aS05pyJ5LiA5Liq5Lq655yL552A5oiRClswODo1OS4zNF0KWzA5OjAwLjY3XeivtOaYjuWkqSDmnInkurrkuIvokawKWzA5OjA5Ljc3XeeUn+eahOWwveWktOaYr+eIsQpbMDk6MTcuODNd54ix55qE5bC95aS05piv6Ii5ClswOToyNS44M13oiLnnmoTlsL3lpLTmnInkuIDkuKrkurrnnIvnnYDmiJEKWzA5OjMyLjkwXeivtOadpeWQpyDkuIDotbfkuIvokawKWzA5OjQxLjQzXeiOq+WQjeWFtuWmmeeahOaDhee7quS7juWxsemhtuS4iumjmOi/h+adpQpbMDk6NDkuMzVd6aOe5Lmf6aOe5LiN5Ye655qE5YyF5Zu05a+55oiR6K+0ClswOTo1NS44NF3kuIDotbfkuIvokawKWzA5OjU3LjM0XQpbMTA6MjkuNDNd6I6r5ZCN5YW25aaZ55qE5oOF57uq5LuO5bGx6aG25LiK6aOY6L+H5p2lClsxMDozNy40OF3po57kuZ/po57kuI3lh7rnmoTljIXlm7Tlr7nmiJHor7QKWzEwOjQ1LjI3Xeatu+S6oeWSjOaIkeeahOaipuaDs+abvue7j+WmguatpOeahOaOpei/kQpbMTA6NTMuMjdd5LiJ5Y2B5YWr5bm055qE5oyj6ISxIOiEseS4jeS6hgpbMTE6MDAuMDZd5aaC5L2V5piv5aW9ClsxMTowNC4xOF3lpoLkvZXmmK/lpb0KWzExOjA4LjEzXeWmguS9leaYr+WlvQpbMTE6MTIuMjNd5aaC5L2V5piv5aW9ClsxMToxMy45NF0=" 182 | }, 183 | { 184 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 185 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!564:/来了-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 186 | "title": "来了-洗心革面", 187 | "artist": "李志", 188 | "lyric": "W3RpOiDmnaXkuoYt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNTowMy4wNV0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMC43OF3mnaXkuoYKWzAwOjA2LjAyXQpbMDA6MTUuMjRd54ix5oOF5p2l5LqGClswMDoxOC41NV3lpbnnqb/ov4flpJzoibLmnaXnnIvmnJvkuIDkuKrkuroKWzAwOjIyLjM5XemCo+S4jeaYr+aIkSDmmK/miJHnmoTlhYTlvJ8KWzAwOjMwLjQ1XeWlueiDjOWvueedgOaIkeiEseS4i+a3i+a5v+eahOiho+acjQpbMDA6MzQuMThd5oiR55yL6KeB5aSW6Z2i5Lik5Y+q5Zac6bmK5Zyo5omT5p62ClswMDo0Mi41NV3miJHns7vntKfpnovluKblhrLov5vov5nlpJzoibIg5aSc6Imy5Zyo5ZSxIOWcqOWUsQpbMDA6NTIuMTZdClswMToxMS4yN13nkIbmg7PmnaXkuoYg5a6D5piv5Liq6KKr5q+N5Lqy6YGX5byD55qE5bCP5a2pClswMToxNy43OV3mnInkuIDlj4znu5Plrp7nmoTlpKfohb/ouabouabot7Pot7PliLDlpITkubHot5EKWzAxOjI2LjYwXeaIkeeahOWFhOW8n+abvue7j+mCo+S5iOeWr+eLgueahOeIseedgOWugyDot5/pmo/nnYDlroMKWzAxOjM4LjUzXeS4jeefpemBk+S7gOS5iOaXtuWAmeWFhOW8n+WBt+WBt+WTreazoyDopoHmipvlvIPlroMg5LqO5piv5bCx5ZSxClswMTo0Ny42M10KWzAyOjA3LjQyXeWRvei/kOadpeS6hiDlroPluKbnnYDlpKnlubPnu5nmr4/kuKrkurrnrpflkb0KWzAyOjE0LjU3XeaIkeeci+edgOWugyDnrJHkuoYg552h552A5LqGClswMjoyMy41OV3miJHmm77nu4/pgqPkuYjml6Dnn6Xnlq/ni4LnmoTphJnop4blroMg6K+F5ZKS5a6DClswMjozNC42NF3lpoLku4rmiJHot6rlgJLnnYDoi5vmsYLkuKrmnLrkvJog5a6D55yL552A5oiR56yR5LqGIOedoeedgOS6hgpbMDI6NDUuNDRd" 189 | }, 190 | { 191 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 192 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!577:/山阴路的夏天李志-洗心革面.mp3?authkey=AIi2BPhsvSW-Bd0", 193 | "title": "山阴路的夏天-洗心革面(Live)", 194 | "artist": "李志", 195 | "lyric": "W3RpOiDlsbHpmLTot6/nmoTlpI/lpKkt5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwNTo1My43Ml0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS4wOF3lsbHpmLTot6/nmoTlpI/lpKkKWzAwOjA4Ljc5XQpbMDA6MTQuNDNd6L+Z5qyh5L2g56a75byA5LqG5rKh5pyJ5YOP5Lul5YmN6YKj5qC36K+05YaN6KeB77yM5YaN6KeB5Lmf5LuW5aaI55qE5Y+q5piv5YaN6KeBClswMDoyNC45OV3miJHku6zkuYvpl7Tku47mnaXmsqHmnInmg7PosaHnmoTpgqPkuYjmjqXov5HvvIzlj6rmmK/kuKTmo7XmoJHnmoTot53nprsKWzAwOjM2LjYzXeS9oOaYr+WQpui/mOiusOW+l+WxsemYtOi3r+WFq+alvOeahOaIv+mXtO+8jOaIv+mXtOmHjOWUseatjOeahOaXpeaXpeWknOWknApbMDA6NDcuMzld6YKj5LmI54Ot55qE5aSP5aSp5L2g55yL552A5aSW6Z2i77yM55yL552A5L2g5Zyo5raI6YCd55qE5a656aKcClswMDo1OC45N13miJHlpJrkuYjmg7Plv7XkvaDotbDlnKjmiJHouqvovrnnmoTmoLflrZDvvIzmg7PotbfmnaXmiJHnmoTniLHlsLHkuI3og73lgZzmraIKWzAxOjA5LjY3XeWNl+S6rOeahOmbqOS4jeWBnOWcsOS4i+S4jeWBnOWcsOS4i++8jOWwseWDj+S9oOayiem7mOeahOWnlOWxiApbMDE6NDMuODRd5LiA6L2s55y85oiR5Lus55qE5Z+O5biC5Y+I5Yiw5LqG5aSP5aSp77yM5a+56Z2i6LWw5p2l55qE5Lq66YO955yv552A55y8ClswMTo1NC4zMF3kurrku6zkuI3mlaLor7Tor53kuI3mlaLlgZzkuIvohJrmraXvvIzlm6DkuLrlv4Pnl5vluLjluLjluKbmnaXljbHpmakKWzAyOjA1LjkxXeaIkeWkmuS5iOaDs+W/teS9oOi1sOWcqOaIkei6q+i+ueeahOagt+WtkO+8jOaDs+i1t+adpeaIkeeahOeIseWwseS4jeiDveWBnOatogpbMDI6MTYuNTld5Y2X5Lqs55qE6Zuo5LiN5YGc5Zyw5LiL5LiN5YGc5Zyw5LiL77yM5pyJ5Lqb5Lq65Y205rOo5a6a6KaB55u46YGHClswMjoyOC4xNV3kvaDmmK/kuIDniYflhYnojaPnmoTlj7blrZDokL3lnKjmiJHljZHotLHnmoTlv4MKWzAyOjM4Ljc2XeWDj+W+gOW4uOS4gOagt+aIkeS4uuiHquW3seeUn+awlOW5tuS4lOatjOWUsQpbMDI6NDQuODBd6YKj5LmI5LmP5Yqb77yM54ix5Lmf5ZC55LiN5Yqo55qE5Y+25a2QClswMjo0OS41OV0KWzAzOjM5Ljk1XTIwMTjlubTlt7Lnu4/ov4fljrvkuobvvIzmiJHlhrPlrprljrvmgIDlv7XlroMKWzAzOjUwLjgzXeS4jeeuoeWug+aYr+S4gOmmluivl++8jOi/mOaYr+S4gOWdqOeLl+WxjgpbMDM6NTUuOTZd5oiR5Yaz5a6a5Y675oCA5b+15a6DClswNDowMC42MF3miJHlhrPlrprku47mmI7lpKnotbfvvIzmiormr4/kuIDlpKkg6L+H55qE5YOPMjAxOOW5tOS4gOagtwpbMDQ6MTAuOThd5YOP5LiA6aaW6K+X77yM5oiW6ICFIOWDj+S4gOWdqOeLl+WxjgpbMDQ6MTcuMzJdClswNTowMS42OV0=" 196 | }, 197 | { 198 | "thumb": "https://media.webhcj.net/items/F85B50B58B003D55!590:/xxgm.jpg?authkey=AIi2BPhsvSW-Bd0", 199 | "url": "https://media.webhcj.net/items/F85B50B58B003D55!562:/你离开了南京从此没人和我说话.mp3?authkey=AIi2BPhsvSW-Bd0", 200 | "title": "你离开了南京从此没人和我说话-洗心革面(Live)", 201 | "artist": "李志", 202 | "lyric": "W3RpOiDkvaDnprvlvIDkuobljZfkuqzku47mraTmsqHkurrlkozmiJHor7Tor50t5rSX5b+D6Z2p6Z2iXQpbYXI6IOadjuW/l10KW2FsOiDmtJflv4PpnanpnaJdCltieTog5aSp6a2CXQpbbGVuZ3RoOiAwMzoyNi45NF0KW3Rvb2w6IOatjOivjea7muWKqOWnrCBodHRwczovL2xyYy1tYWtlci5naXRodWIuaW9dClswMDowMS41NF3kvaDnprvlvIDkuobljZfkuqzku47mraTmsqHkurrlkozmiJHor7Tor50KWzAwOjA3LjgzXQpbMDA6MTQuODFd57qv6Z+z5LmQ" 203 | } 204 | ] 205 | }, 206 | { 207 | "cover": "https://i.kfs.io/album/global/45834383,0v1/fit/500x500.jpg", 208 | "name": "李志 电声与管弦乐II(Live)", 209 | "issueDate": "2018-05-16", 210 | "songs": [ 211 | { 212 | "thumb": "https://i.kfs.io/album/global/45834383,0v1/fit/500x500.jpg", 213 | "url": "https://media.webhcj.net/1drv/aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbFU5QUl1MVVGdjRoQ2NESGZfeWVodzlRdHJi.flac", 214 | "title": "相信未来序曲", 215 | "artist": "李志", 216 | "lyric": "W3RpOiDnm7jkv6HmnKrmnaXluo/mm7JdClthcjog5p2O5b+XXQpbYWw6IOadjuW/lyDnlLXlo7DkuI7nrqHlvKbkuZBJSShMaXZlKV0KW2J5OiDlpKnprYJdClt0b29sOiDmrYzor43mu5rliqjlp6wgaHR0cHM6Ly9scmMtbWFrZXIuZ2l0aHViLmlvXQpbbGVuZ3RoOiAwNTowNi40NDNdClswMDowMC44MV0g55u45L+h5pyq5p2l5bqP5puyIC0g5p2O5b+XClswMDowMzowMF0g57qv6Z+z5LmQ" 217 | }, 218 | { 219 | "thumb": "https://i.kfs.io/album/global/45834383,0v1/fit/500x500.jpg", 220 | "url": "https://media.webhcj.net/1drv/aHR0cHM6Ly8xZHJ2Lm1zL3UvcyFBbFU5QUl1MVVGdjRoQ2c3Z2VGWFFaZVc0M0Jq.flac", 221 | "title": "一头偶像(相信未来版)", 222 | "artist": "李志", 223 | "lyric": "W3RpOiDkuIDlpLTlgbblg48gKOebuOS/oeacquadpeeJiCldClthcjog5p2O5b+XXQpbYWw6IOadjuW/lyDnlLXlo7DkuI7nrqHlvKbkuZBJSShMaXZlKV0KW2J5OiDlpKnprYJdClt0b29sOiDmrYzor43mu5rliqjlp6wgaHR0cHM6Ly9scmMtbWFrZXIuZ2l0aHViLmlvXQpbbGVuZ3RoOiAwNDo0OS4zOTddClswMDowMC44MTddIOS4gOWktOWBtuWDjyAo55u45L+h5pyq5p2l54mIKSAtIOadjuW/lwpbMDA6MDEuOTEwXSDor43vvJrmnY7lv5cKWzAwOjAyLjgxMl0g5puy77ya5p2O5b+XClswMDowMy44NTZdIOe8luabsu+8mumZiOS8n+a0i+iRsea1k+axpOS8pi/lvpDmoqfmoZAKWzAwOjA0LjY5Ml0g5Yi25L2c5Lq677ya6ZmI5Lyf5LymClswMDowNS42MDJdIOmfs+S5kOaAu+ebke+8mumZiOS8n+S8pgpbMDA6MDcuMDU0XSDpvJPvvJrkvZnotaPlroEKWzAwOjA3LjkyOV0g5ZCJ5LuW77ya6KKB6ZOuL+i1teawuOW6hgpbMDA6MDguNzE1XSDotJ3mlq/vvJrlvKDpm68KWzAwOjA5LjY2NV0g6ZSu55uY77ya6YOt5pix5qyjClswMDoxMC4zOTNdIOaJk+WHu+S5kO+8mumtj+aYnwpbMDA6MTEuMjAwXSDlj6PnkLTvvJrpmYjlso0KWzAwOjExLjk2M10g5Ly05ZSx77ya5pyx5qC85LmQL+mYv+eOm+Wmri/lvKDmgKHnhLYKWzAwOjEyLjg4OF0g566h5bym5LmQ77ya6Z2z5rW36Z+zP+euoeW8puS5kOWbogpbMDA6MTMuNjUwXSBQcm9ncmFt5bel56iL5pON5L2c77ya5p2O5aSp6ZuEClswMDoxNC44MTJdIFByb2dyYW3liLbkvZzvvJrpmYjkvJ/kvKYv5b6Q5qKn5qGQL+ael+aso+eRgApbMDA6MTUuODM5XSBQcm9ncmFt5b2V6Z+z77yaVFRM5b2V6Z+z5qOaClswMDoxNi41MTddIOW9lemfs+W4iO+8muWnnOWMl+eUny/njovnq7nmoLkKWzAwOjE3LjI1NF0g5re36Z+z5biI77ya5aec5YyX55SfClswMDoxOC4zNjJdIOavjeW4puW3peeoi+W4iO+8muWnnOWMl+eUnwpbMDA6MTkuNDgwXSDmt7fpn7Mv5q+N5bim5bel5L2c5a6k77yaUy5BLkflvZXpn7Pmo5oKWzAwOjIzLjg5OV0KWzAwOjU2LjY4Ml0g6L+Z5LiA5aSpIOS9oOiDveaOp+WItuS9oOeahOi6q+S9kwpbMDE6MDIuMjA2XSDnlKjnnaHnnKDmiorniZnnl5vlkozkvKTmhJ/mirnljrsKWzAxOjA4LjcxOV0g5riF5pmo5LqU54K5IOS9oOimgei1sOWHuuS9oOeahOaIv+mXtApbMDE6MTUuMDc5XSDkuIDlj6rmh7Xmh4LnmoTpurvpm4DmiorkvaDmkIXkubEKWzAxOjIyLjM2M10g5LiA5p2h6IW/IOS4gOWPquecvOedm+eejuS6hgpbMDE6MjcuOTM5XSDkuIDmoLnng5/nmoTnh4Png6forqnkvaDppb/kuoYKWzAxOjM0LjI0OF0g6IO95Y675ZOq6YeMIOivpeWOu+WTqumHjApbMDE6NDAuNTQ5XSDplJnkubHnmoTohJrmraXku7/kvZvlg4/kuIDlj6rojYnni5cKWzAxOjQ3LjA3MV0g5LuW5Lus55yL5L2gIOS7luS7rOeci+edgOS8n+Wkp+eahOS9oApbMDE6NTMuNDM2XSDohLHnprvml7bku6PnmoTnnLznpZ7lg4/kuIDluYXnlLsKWzAxOjU5Ljk2NF0g5LiN6IO95L6d5oGLIOWTquaAleWJjemdoumbvuawtOi/nue7tQpbMDI6MDYuMTQ1XSDor6XotbDkuIvljrsg6IO96aG26L+H5Y675LiN5piv5ZCXClswMjo1OC4zMDVdIOS4gOmYtemjjiDkuIDniYfmoJHlj7bpu4TkuoYKWzAzOjAzLjk4OF0g5LiA56KX6Z2i55qE5ZGz6YGT6K6p5L2g6aW/5LqGClswMzoxMC4wMDVdIOi9puadpei9puW+gCDlranlrZDku6znnIvotbfmnaXlvojlv5kKWzAzOjE3LjExNF0g5Y+95Y+95Zaz5Zaz55qE5aW95YOP5oqK5LiA5YiH5oul5pyJClswMzoyMy4zMDVdIOS7luS7rOeci+S9oCDku5bku6znnIvnnYDpmYznlJ/nmoTkvaAKWzAzOjI5LjQ1OV0g55Wl5bim5auM5byD55qE55y856We5YOP5LiA5bmF55S7ClswMzozNS45NTVdIOS4jeiDvemAl+eVmSDkvaDmmK/ku5bku6znnLzkuK3nmoTni5cKWzAzOjQxLjk2Ml0g5LiN6IO956C05Z2PIOS4jeiDvemHjeadpeS4jeaYr+WQlwpbMDM6NDguOTE0XSDku5bku6znnIvkvaAg5LuW5Lus55yL552A6ZmM55Sf55qE5L2gClswMzo1NS4wNTVdIOeVpeW4puWrjOW8g+eahOecvOelnuWDj+S4gOW5heeUuwpbMDQ6MDEuNTczXSDkuI3og73pgJfnlZkg5L2g5piv5Lq66Ze05bmz5Yeh55qE54uXClswNDowOC4xNjJdIOivpei1sOS4i+WOuyDog73pobbov4fljrvkuI3mmK/lkJc=" 224 | } 225 | ] 226 | }, 227 | { 228 | "cover": "https://i.kfs.io/album/global/45834418,0v1/fit/500x500.jpg", 229 | "name": "爵士樂與不插電新編12首", 230 | "issueDate": "2018-04-16", 231 | "songs": [ 232 | { 233 | "thumb": "", 234 | "url": "", 235 | "title": "", 236 | "artist": "", 237 | "lyric": "" 238 | } 239 | ] 240 | }, 241 | { 242 | "cover": "https://i.kfs.io/album/global/45832938,0v1/fit/500x500.jpg", 243 | "name": "李志、電聲與管弦樂", 244 | "issueDate": "2017-05-16", 245 | "songs": [ 246 | { 247 | "thumb": "", 248 | "url": "", 249 | "title": "", 250 | "artist": "", 251 | "lyric": "" 252 | } 253 | ] 254 | }, 255 | { 256 | "cover": "https://i.kfs.io/album/global/45832279,0v1/fit/500x500.jpg", 257 | "name": "在每一條傷心的應天大街上", 258 | "issueDate": "2016-11-20", 259 | "songs": [ 260 | { 261 | "thumb": "", 262 | "url": "", 263 | "title": "", 264 | "artist": "", 265 | "lyric": "" 266 | } 267 | ] 268 | }, 269 | { 270 | "cover": "https://i.kfs.io/album/global/45826116,0v1/fit/500x500.jpg", 271 | "name": "捌", 272 | "issueDate": "2016-10-18", 273 | "songs": [ 274 | { 275 | "thumb": "", 276 | "url": "", 277 | "title": "", 278 | "artist": "", 279 | "lyric": "" 280 | } 281 | ] 282 | }, 283 | { 284 | "cover": "https://i.kfs.io/album/global/45830532,0v1/fit/500x500.jpg", 285 | "name": "李志北京不插電現場", 286 | "issueDate": "2016-08-11", 287 | "songs": [ 288 | { 289 | "thumb": "", 290 | "url": "", 291 | "title": "", 292 | "artist": "", 293 | "lyric": "" 294 | } 295 | ] 296 | }, 297 | { 298 | "cover": "https://i.kfs.io/album/global/45827988,0v1/fit/500x500.jpg", 299 | "name": "動靜", 300 | "issueDate": "2016-03-14", 301 | "songs": [ 302 | { 303 | "thumb": "", 304 | "url": "", 305 | "title": "", 306 | "artist": "", 307 | "lyric": "" 308 | } 309 | ] 310 | }, 311 | { 312 | "cover": "https://i.kfs.io/album/global/45434848,0v1/fit/500x500.jpg", 313 | "name": "看見", 314 | "issueDate": "2015-06-27", 315 | "songs": [ 316 | { 317 | "thumb": "", 318 | "url": "", 319 | "title": "", 320 | "artist": "", 321 | "lyric": "" 322 | } 323 | ] 324 | }, 325 | { 326 | "cover": "https://i.kfs.io/album/global/45432442,0v1/fit/500x500.jpg", 327 | "name": "i/O", 328 | "issueDate": "2015-01-21", 329 | "songs": [ 330 | { 331 | "thumb": "", 332 | "url": "", 333 | "title": "", 334 | "artist": "", 335 | "lyric": "" 336 | } 337 | ] 338 | }, 339 | { 340 | "cover": "https://i.kfs.io/album/global/45438107,0v2/fit/500x500.jpg", 341 | "name": "1701", 342 | "issueDate": "2014-11-13", 343 | "songs": [ 344 | { 345 | "thumb": "", 346 | "url": "", 347 | "title": "", 348 | "artist": "", 349 | "lyric": "" 350 | } 351 | ] 352 | }, 353 | { 354 | "cover": "https://i.kfs.io/album/global/45437525,0v1/fit/500x500.jpg", 355 | "name": "勾三搭四", 356 | "issueDate": "2014-04-01", 357 | "songs": [ 358 | { 359 | "thumb": "", 360 | "url": "", 361 | "title": "", 362 | "artist": "", 363 | "lyric": "" 364 | } 365 | ] 366 | }, 367 | { 368 | "cover": "https://i.kfs.io/album/global/45435114,0v2/fit/500x500.jpg", 369 | "name": "108個關鍵字", 370 | "issueDate": "2012-12-31", 371 | "songs": [ 372 | { 373 | "thumb": "", 374 | "url": "", 375 | "title": "", 376 | "artist": "", 377 | "lyric": "" 378 | } 379 | ] 380 | }, 381 | { 382 | "cover": "https://i.kfs.io/album/global/45435121,0v1/fit/500x500.jpg", 383 | "name": "F", 384 | "issueDate": "2011-09-28", 385 | "songs": [ 386 | { 387 | "thumb": "", 388 | "url": "", 389 | "title": "", 390 | "artist": "", 391 | "lyric": "" 392 | } 393 | ] 394 | }, 395 | { 396 | "cover": "https://i.kfs.io/album/global/45437532,0v1/fit/500x500.jpg", 397 | "name": "你好,鄭州", 398 | "issueDate": "2010-09-01", 399 | "songs": [ 400 | { 401 | "thumb": "", 402 | "url": "", 403 | "title": "", 404 | "artist": "", 405 | "lyric": "" 406 | } 407 | ] 408 | }, 409 | { 410 | "cover": "https://i.kfs.io/album/global/45433578,0v1/fit/500x500.jpg", 411 | "name": "我愛南京", 412 | "issueDate": "2009-09-09", 413 | "songs": [ 414 | { 415 | "thumb": "", 416 | "url": "", 417 | "title": "", 418 | "artist": "", 419 | "lyric": "" 420 | } 421 | ] 422 | }, 423 | { 424 | "cover": "https://i.kfs.io/album/global/45151278,0v1/fit/500x500.jpg", 425 | "name": "工體東路沒有人", 426 | "issueDate": "2009-01-22", 427 | "songs": [ 428 | { 429 | "thumb": "", 430 | "url": "", 431 | "title": "", 432 | "artist": "", 433 | "lyric": "" 434 | } 435 | ] 436 | }, 437 | { 438 | "cover": "https://i.kfs.io/album/global/45436873,0v1/fit/500x500.jpg", 439 | "name": "這個世界會好嗎2015", 440 | "issueDate": "2006-11-06", 441 | "songs": [ 442 | { 443 | "thumb": "", 444 | "url": "", 445 | "title": "", 446 | "artist": "", 447 | "lyric": "" 448 | } 449 | ] 450 | }, 451 | { 452 | "cover": "https://i.kfs.io/album/global/45149879,0v1/fit/500x500.jpg", 453 | "name": "這個世界會好嗎", 454 | "issueDate": "2006-11-06", 455 | "songs": [ 456 | { 457 | "thumb": "", 458 | "url": "", 459 | "title": "", 460 | "artist": "", 461 | "lyric": "" 462 | } 463 | ] 464 | }, 465 | { 466 | "cover": "https://i.kfs.io/album/global/45835640,0v1/fit/500x500.jpg", 467 | "name": "梵高先生", 468 | "issueDate": "2005-12-01", 469 | "songs": [ 470 | { 471 | "thumb": "", 472 | "url": "", 473 | "title": "", 474 | "artist": "", 475 | "lyric": "" 476 | } 477 | ] 478 | }, 479 | { 480 | "cover": "https://i.kfs.io/album/global/45149196,0v1/fit/500x500.jpg", 481 | "name": "被禁忌的遊戲", 482 | "issueDate": "2004-12-01", 483 | "songs": [ 484 | { 485 | "thumb": "", 486 | "url": "", 487 | "title": "", 488 | "artist": "", 489 | "lyric": "" 490 | } 491 | ] 492 | } 493 | ] 494 | } 495 | -------------------------------------------------------------------------------- /src/assets/images/background-dark.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tian-Hun/biger-music/84f6a02f18048052909358b5cf6b98b6b99316ee/src/assets/images/background-dark.jpg -------------------------------------------------------------------------------- /src/assets/images/lizhi.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tian-Hun/biger-music/84f6a02f18048052909358b5cf6b98b6b99316ee/src/assets/images/lizhi.png -------------------------------------------------------------------------------- /src/browserslist: -------------------------------------------------------------------------------- 1 | # This file is currently used by autoprefixer to adjust CSS to support the below specified browsers 2 | # For additional information regarding the format and rule options, please see: 3 | # https://github.com/browserslist/browserslist#queries 4 | # 5 | # For IE 9-11 support, please remove 'not' from the last line of the file and adjust as needed 6 | 7 | > 0.5% 8 | last 2 versions 9 | Firefox ESR 10 | not dead 11 | not IE 9-11 -------------------------------------------------------------------------------- /src/environments/environment.prod.ts: -------------------------------------------------------------------------------- 1 | export const environment = { 2 | production: true 3 | }; 4 | -------------------------------------------------------------------------------- /src/environments/environment.ts: -------------------------------------------------------------------------------- 1 | // This file can be replaced during build by using the `fileReplacements` array. 2 | // `ng build --prod` replaces `environment.ts` with `environment.prod.ts`. 3 | // The list of file replacements can be found in `angular.json`. 4 | 5 | export const environment = { 6 | production: false 7 | }; 8 | 9 | /* 10 | * For easier debugging in development mode, you can import the following file 11 | * to ignore zone related error stack frames such as `zone.run`, `zoneDelegate.invokeTask`. 12 | * 13 | * This import should be commented out in production mode because it will have a negative impact 14 | * on performance if an error is thrown. 15 | */ 16 | // import 'zone.js/dist/zone-error'; // Included with Angular CLI. 17 | -------------------------------------------------------------------------------- /src/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Tian-Hun/biger-music/84f6a02f18048052909358b5cf6b98b6b99316ee/src/favicon.ico -------------------------------------------------------------------------------- /src/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | BigerMusic 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/karma.conf.js: -------------------------------------------------------------------------------- 1 | // Karma configuration file, see link for more information 2 | // https://karma-runner.github.io/1.0/config/configuration-file.html 3 | 4 | module.exports = function (config) { 5 | config.set({ 6 | basePath: '', 7 | frameworks: ['jasmine', '@angular-devkit/build-angular'], 8 | plugins: [ 9 | require('karma-jasmine'), 10 | require('karma-chrome-launcher'), 11 | require('karma-jasmine-html-reporter'), 12 | require('karma-coverage-istanbul-reporter'), 13 | require('@angular-devkit/build-angular/plugins/karma') 14 | ], 15 | client: { 16 | clearContext: false // leave Jasmine Spec Runner output visible in browser 17 | }, 18 | coverageIstanbulReporter: { 19 | dir: require('path').join(__dirname, '../coverage/biger-music'), 20 | reports: ['html', 'lcovonly', 'text-summary'], 21 | fixWebpackSourcePaths: true 22 | }, 23 | reporters: ['progress', 'kjhtml'], 24 | port: 9876, 25 | colors: true, 26 | logLevel: config.LOG_INFO, 27 | autoWatch: true, 28 | browsers: ['Chrome'], 29 | singleRun: false, 30 | restartOnFileChange: true 31 | }); 32 | }; 33 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { enableProdMode } from '@angular/core'; 2 | import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'; 3 | 4 | import { BigerMusicModule } from './app/biger-music.module'; 5 | import { environment } from './environments/environment'; 6 | 7 | if (environment.production) { 8 | enableProdMode(); 9 | } 10 | 11 | platformBrowserDynamic() 12 | .bootstrapModule(BigerMusicModule) 13 | .catch(err => console.error(err)); 14 | -------------------------------------------------------------------------------- /src/polyfills.ts: -------------------------------------------------------------------------------- 1 | /** 2 | * This file includes polyfills needed by Angular and is loaded before the app. 3 | * You can add your own extra polyfills to this file. 4 | * 5 | * This file is divided into 2 sections: 6 | * 1. Browser polyfills. These are applied before loading ZoneJS and are sorted by browsers. 7 | * 2. Application imports. Files imported after ZoneJS that should be loaded before your main 8 | * file. 9 | * 10 | * The current setup is for so-called "evergreen" browsers; the last versions of browsers that 11 | * automatically update themselves. This includes Safari >= 10, Chrome >= 55 (including Opera), 12 | * Edge >= 13 on the desktop, and iOS 10 and Chrome on mobile. 13 | * 14 | * Learn more in https://angular.io/guide/browser-support 15 | */ 16 | 17 | /*************************************************************************************************** 18 | * BROWSER POLYFILLS 19 | */ 20 | 21 | /** IE10 and IE11 requires the following for NgClass support on SVG elements */ 22 | // import 'classlist.js'; // Run `npm install --save classlist.js`. 23 | 24 | /** 25 | * Web Animations `@angular/platform-browser/animations` 26 | * Only required if AnimationBuilder is used within the application and using IE/Edge or Safari. 27 | * Standard animation support in Angular DOES NOT require any polyfills (as of Angular 6.0). 28 | */ 29 | // import 'web-animations-js'; // Run `npm install --save web-animations-js`. 30 | 31 | /** 32 | * By default, zone.js will patch all possible macroTask and DomEvents 33 | * user can disable parts of macroTask/DomEvents patch by setting following flags 34 | * because those flags need to be set before `zone.js` being loaded, and webpack 35 | * will put import in the top of bundle, so user need to create a separate file 36 | * in this directory (for example: zone-flags.ts), and put the following flags 37 | * into that file, and then add the following code before importing zone.js. 38 | * import './zone-flags.ts'; 39 | * 40 | * The flags allowed in zone-flags.ts are listed here. 41 | * 42 | * The following flags will work for all browsers. 43 | * 44 | * (window as any).__Zone_disable_requestAnimationFrame = true; // disable patch requestAnimationFrame 45 | * (window as any).__Zone_disable_on_property = true; // disable patch onProperty such as onclick 46 | * (window as any).__zone_symbol__UNPATCHED_EVENTS = ['scroll', 'mousemove']; // disable patch specified eventNames 47 | * 48 | * in IE/Edge developer tools, the addEventListener will also be wrapped by zone.js 49 | * with the following flag, it will bypass `zone.js` patch for IE/Edge 50 | * 51 | * (window as any).__Zone_enable_cross_context_check = true; 52 | * 53 | */ 54 | 55 | /*************************************************************************************************** 56 | * Zone JS is required by default for Angular itself. 57 | */ 58 | import 'zone.js/dist/zone'; // Included with Angular CLI. 59 | 60 | 61 | /*************************************************************************************************** 62 | * APPLICATION IMPORTS 63 | */ 64 | -------------------------------------------------------------------------------- /src/scss/_components.scss: -------------------------------------------------------------------------------- 1 | button.icon-button { 2 | background: none; 3 | border: none; 4 | line-height: 0; 5 | outline: none; 6 | cursor: pointer; 7 | 8 | .icon { 9 | fill: currentColor; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/scss/_variables.scss: -------------------------------------------------------------------------------- 1 | $color-bg: #F2D7D3; 2 | $color-light: #fff9e1; 3 | $color-black: #252120; 4 | $color-gray: rgb(68, 68, 68); 5 | $primary: #93110A; 6 | -------------------------------------------------------------------------------- /src/styles.scss: -------------------------------------------------------------------------------- 1 | // @import url('https://fonts.loli.net/css?family=Oswald:300,400,700'); 2 | 3 | @import "./scss/components"; 4 | 5 | i[class^="btn"] { 6 | font-size: 20px; 7 | margin-right: 30px; 8 | cursor: pointer; 9 | } 10 | 11 | * { 12 | box-sizing: border-box; 13 | } 14 | 15 | ul, li { 16 | list-style: none; 17 | padding: 0; 18 | } 19 | 20 | a { 21 | color: inherit; 22 | text-decoration: none; 23 | } 24 | 25 | body { 26 | margin: 0; 27 | font-family: 'Oswald', sans-serif; 28 | -webkit-font-smoothing: antialiased; 29 | -moz-osx-font-smoothing: grayscale; 30 | font-size: 1rem; 31 | overflow: hidden; 32 | width: 100vw; 33 | height: 100vh; 34 | background: url("./assets/images/background-dark.jpg") no-repeat center center; 35 | background-size: cover; 36 | } 37 | -------------------------------------------------------------------------------- /src/test.ts: -------------------------------------------------------------------------------- 1 | // This file is required by karma.conf.js and loads recursively all the .spec and framework files 2 | 3 | import 'zone.js/dist/zone-testing'; 4 | import { getTestBed } from '@angular/core/testing'; 5 | import { 6 | BrowserDynamicTestingModule, 7 | platformBrowserDynamicTesting 8 | } from '@angular/platform-browser-dynamic/testing'; 9 | 10 | declare const require: any; 11 | 12 | // First, initialize the Angular testing environment. 13 | getTestBed().initTestEnvironment( 14 | BrowserDynamicTestingModule, 15 | platformBrowserDynamicTesting() 16 | ); 17 | // Then we find all the tests. 18 | const context = require.context('./', true, /\.spec\.ts$/); 19 | // And load the modules. 20 | context.keys().map(context); 21 | -------------------------------------------------------------------------------- /src/tsconfig.app.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/app", 5 | "types": [] 6 | }, 7 | "exclude": [ 8 | "test.ts", 9 | "**/*.spec.ts" 10 | ] 11 | } 12 | -------------------------------------------------------------------------------- /src/tsconfig.spec.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tsconfig.json", 3 | "compilerOptions": { 4 | "outDir": "../out-tsc/spec", 5 | "types": [ 6 | "jasmine", 7 | "node" 8 | ] 9 | }, 10 | "files": [ 11 | "test.ts", 12 | "polyfills.ts" 13 | ], 14 | "include": [ 15 | "**/*.spec.ts", 16 | "**/*.d.ts" 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /src/tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "../tslint.json", 3 | "rules": { 4 | "directive-selector": [ 5 | true, 6 | "attribute", 7 | "app", 8 | "camelCase" 9 | ], 10 | "component-selector": [ 11 | true, 12 | "element", 13 | "biger", 14 | "kebab-case" 15 | ], 16 | "indent": [ 17 | true, 18 | "spaces", 19 | 4 20 | ], 21 | "prefer-inline-decorator": false, 22 | "no-implicit-dependencies": false, 23 | "only-arrow-functions": false, 24 | "no-invalid-this": false, 25 | "newline-per-chained-call": false 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compileOnSave": false, 3 | "compilerOptions": { 4 | "baseUrl": "./src", 5 | "outDir": "./dist/out-tsc", 6 | "sourceMap": true, 7 | "declaration": false, 8 | "module": "esnext", 9 | "moduleResolution": "node", 10 | "emitDecoratorMetadata": true, 11 | "experimentalDecorators": true, 12 | "importHelpers": true, 13 | "target": "es2015", 14 | "typeRoots": [ 15 | "node_modules/@types" 16 | ], 17 | "lib": [ 18 | "es2018", 19 | "dom" 20 | ], 21 | "paths": { 22 | "@core/*": [ 23 | "./app/core/*" 24 | ], 25 | "@shared/*": [ 26 | "./app/shared/*" 27 | ] 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /tslint.json: -------------------------------------------------------------------------------- 1 | { 2 | "rulesDirectory": [ 3 | "node_modules/codelyzer" 4 | ], 5 | "extends": "angular-tslint-rules", 6 | "rules": { 7 | "array-type": false, 8 | "arrow-parens": false, 9 | "deprecation": { 10 | "severity": "warn" 11 | }, 12 | "import-blacklist": [ 13 | true, 14 | "rxjs/Rx" 15 | ], 16 | "interface-name": false, 17 | "max-classes-per-file": false, 18 | "max-line-length": [ 19 | true, 20 | 140 21 | ], 22 | "member-access": false, 23 | "member-ordering": [ 24 | true, 25 | { 26 | "order": [ 27 | "static-field", 28 | "instance-field", 29 | "static-method", 30 | "instance-method" 31 | ] 32 | } 33 | ], 34 | "no-consecutive-blank-lines": false, 35 | "no-console": [ 36 | true, 37 | "debug", 38 | "info", 39 | "time", 40 | "timeEnd", 41 | "trace" 42 | ], 43 | "no-empty": false, 44 | "no-inferrable-types": [ 45 | true, 46 | "ignore-params" 47 | ], 48 | "no-non-null-assertion": true, 49 | "no-redundant-jsdoc": true, 50 | "no-switch-case-fall-through": true, 51 | "no-use-before-declare": true, 52 | "no-var-requires": false, 53 | "object-literal-key-quotes": [ 54 | true, 55 | "as-needed" 56 | ], 57 | "object-literal-sort-keys": false, 58 | "ordered-imports": false, 59 | "quotemark": [ 60 | true, 61 | "single" 62 | ], 63 | "trailing-comma": false, 64 | "no-output-on-prefix": true, 65 | "no-inputs-metadata-property": true, 66 | "no-outputs-metadata-property": true, 67 | "no-host-metadata-property": true, 68 | "no-input-rename": true, 69 | "no-output-rename": true, 70 | "use-lifecycle-interface": true, 71 | "use-pipe-transform-interface": true, 72 | "component-class-suffix": true, 73 | "directive-class-suffix": true 74 | } 75 | } 76 | --------------------------------------------------------------------------------