diff --git a/README.md b/README.md index 2de6099..6362c97 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,7 @@ This extension will add download buttons to: * Tracks that are contained in scrollable lists. When a download is initiated, it attempts to download a track in its uploaded format (i.e. highest quality) and will only -resort to the streamable 128kb mp3 version if no better quality is available. +resort to the streamable 128 kbps mp3 version if no better quality is available. Metadata information and cover art is automatically added to files in .mp3 format (in ID3v2.3). diff --git a/src/resources/options.html b/src/resources/options.html index 969cd03..6fe4a2b 100644 --- a/src/resources/options.html +++ b/src/resources/options.html @@ -5,19 +5,31 @@ ZoundCloud Options +
-
-
-
-
- - + +
diff --git a/src/ts/background/background-script.ts b/src/ts/background/background-script.ts index 7454600..f366fde 100644 --- a/src/ts/background/background-script.ts +++ b/src/ts/background/background-script.ts @@ -33,7 +33,7 @@ export class BackgroundScript implements IRunnable { ExtensionMessenger.onMessage$(RequestContentPageReloadMessage.TYPE) .pipe(takeUntil(this.onSuspend$)) .subscribe((args: IMessageHandlerArgs) => - ExtensionMessenger.sendToContentPage$(args.sender.tab.id, new ReloadContentPageMessage()) + ExtensionMessenger.sendToContentPage$(args.sender.tab.id, new ReloadContentPageMessage()), ); ExtensionMessenger.onMessage$(RequestDownloadMessage.TYPE) @@ -46,7 +46,7 @@ export class BackgroundScript implements IRunnable { ExtensionMessenger.onMessage$(LogToConsoleMessage.TYPE) .pipe(takeUntil(this.onSuspend$)) .subscribe((args: IMessageHandlerArgs) => - logger.log(`${args.message.message} (tabId: ${args.sender.tab.id})`, ...args.message.optionalParams) + logger.log(`${args.message.message} (tabId: ${args.sender.tab.id})`, ...args.message.optionalParams), ); logger.log('Loaded background script'); diff --git a/src/ts/background/sc-page-observables.ts b/src/ts/background/sc-page-observables.ts index 2be6726..76a14bf 100644 --- a/src/ts/background/sc-page-observables.ts +++ b/src/ts/background/sc-page-observables.ts @@ -10,8 +10,8 @@ const initialNavigationToScPage$: Observable = fromEventPattern((handler: (tabId: number) => void) => chrome.webNavigation.onDOMContentLoaded.addListener( (details: WebNavigationFramedCallbackDetails) => handler(details.tabId), - {url: [{hostEquals: SC_URL_HOST}]} - ) + {url: [{hostEquals: SC_URL_HOST}]}, + ), ); /** @@ -22,18 +22,18 @@ const navigateBetweenScPages$: Observable = fromEventPattern((handler: (tabId: number) => void) => chrome.webNavigation.onHistoryStateUpdated.addListener( (details: WebNavigationTransitionCallbackDetails) => handler(details.tabId), - {url: [{hostEquals: SC_URL_HOST}]} - ) + {url: [{hostEquals: SC_URL_HOST}]}, + ), ).pipe(debounceTime(20)); const tabExists$: (tabId: number) => Observable = (tabId: number) => bindCallback(chrome.tabs.get)(tabId).pipe( - map((tab: Tab) => !chrome.runtime.lastError && tab !== undefined) + map((tab: Tab) => !chrome.runtime.lastError && tab !== undefined), ); export const ScPageObservables = { goToSoundCloudPage$(): Observable { return merge(initialNavigationToScPage$, navigateBetweenScPages$) .pipe(concatFilter(tabExists$)); - } + }, }; diff --git a/src/ts/content/bootstrapper.ts b/src/ts/content/bootstrapper.ts index 907028e..024e70c 100644 --- a/src/ts/content/bootstrapper.ts +++ b/src/ts/content/bootstrapper.ts @@ -31,7 +31,7 @@ export const Bootstrapper = { .subscribe(() => contentPage.unload()); addIdTagToDOM(idTag); } - } + }, }; function idTagIsInDOM(): boolean { diff --git a/src/ts/content/injection/download-button-factory.ts b/src/ts/content/injection/download-button-factory.ts index a259f41..775c3ef 100644 --- a/src/ts/content/injection/download-button-factory.ts +++ b/src/ts/content/injection/download-button-factory.ts @@ -10,7 +10,7 @@ export const DownloadButtonFactory = { const dlButton = createDlButton(); addDlButtonBehavior(dlButton, onUnload$, resourceInfoUrl); return dlButton; - } + }, }; function createDlButton(): JQuery { diff --git a/src/ts/content/injection/injection-service.ts b/src/ts/content/injection/injection-service.ts index 904f92c..80c6509 100644 --- a/src/ts/content/injection/injection-service.ts +++ b/src/ts/content/injection/injection-service.ts @@ -8,5 +8,5 @@ export const InjectionService = { ListenEngagementInjectionService.injectDownloadButtons(onUnload$); ListItemInjectionService.injectDownloadButtons(onUnload$); UserInfoBarInjectionService.injectDownloadButtons(onUnload$); - } + }, }; diff --git a/src/ts/content/injection/injection-signal-factory.ts b/src/ts/content/injection/injection-signal-factory.ts index a9dcfa7..7b8918f 100644 --- a/src/ts/content/injection/injection-signal-factory.ts +++ b/src/ts/content/injection/injection-signal-factory.ts @@ -10,22 +10,22 @@ export const InjectionSignalFactory = { create$(selector: string): Observable> { return merge( elementExistOrAdded$(selector), - forcefullyInjectSignal$(selector) + forcefullyInjectSignal$(selector), ).pipe( map(toJQuery), - filter(hasNoDownloadButton) + filter(hasNoDownloadButton), ); - } + }, }; function forcefullyInjectSignal$(selector: string): Observable { return merge( ContentPageMessenger.onMessage$(ReloadContentPageMessage.TYPE).pipe( - switchMapTo(interval(200).pipe(take(20))) + switchMapTo(interval(200).pipe(take(20))), ), interval(1000), ).pipe( - switchMapTo(elementExist$(selector)) + switchMapTo(elementExist$(selector)), ); } diff --git a/src/ts/content/injection/list-item-injection-service.ts b/src/ts/content/injection/list-item-injection-service.ts index 41b1bac..a3aabd7 100644 --- a/src/ts/content/injection/list-item-injection-service.ts +++ b/src/ts/content/injection/list-item-injection-service.ts @@ -11,7 +11,7 @@ export const ListItemInjectionService = { InjectionSignalFactory.create$(selector) .pipe(takeUntil(onUnload$)) .subscribe(addToListItem.bind(null, onUnload$)); - } + }, }; function createDownloadButton(onUnload$: Observable, downloadInfoUrl: string): JQuery { diff --git a/src/ts/content/injection/listen-engagement-injection-service.ts b/src/ts/content/injection/listen-engagement-injection-service.ts index dff76d3..6ad6d4d 100644 --- a/src/ts/content/injection/listen-engagement-injection-service.ts +++ b/src/ts/content/injection/listen-engagement-injection-service.ts @@ -12,7 +12,7 @@ export const ListenEngagementInjectionService = { InjectionSignalFactory.create$(selector) .pipe(takeUntil(onUnload$)) .subscribe(addToListenEngagement.bind(null, onUnload$)); - } + }, }; function createDownloadButton(onUnload$: Observable): JQuery { diff --git a/src/ts/content/injection/user-info-bar-injection-service.ts b/src/ts/content/injection/user-info-bar-injection-service.ts index 5f0925b..b8da7dc 100644 --- a/src/ts/content/injection/user-info-bar-injection-service.ts +++ b/src/ts/content/injection/user-info-bar-injection-service.ts @@ -14,7 +14,7 @@ export const UserInfoBarInjectionService = { InjectionSignalFactory.create$(selector) .pipe(takeUntil(onUnload$)) .subscribe(addToUserInfoBar.bind(null, onUnload$)); - } + }, }; function createDownloadButton(onUnload$: Observable): JQuery { diff --git a/src/ts/download/download-service.ts b/src/ts/download/download-service.ts index fe936e8..188abb1 100644 --- a/src/ts/download/download-service.ts +++ b/src/ts/download/download-service.ts @@ -7,7 +7,7 @@ import { IResourceInfo, ITrackInfo, IUserInfo, - ResourceType + ResourceType, } from 'src/ts/download/resource/resource-info'; import {ResourceInfoService} from 'src/ts/download/resource/resource-info-service'; import {TrackDownloadService} from 'src/ts/download/track-download-service'; @@ -21,10 +21,10 @@ export const DownloadService = { .pipe(timeout(30000)) .subscribe( doDownload.bind(null, downloadResult$, resourceInfoUrl), - onError.bind(null, downloadResult$, resourceInfoUrl) + onError.bind(null, downloadResult$, resourceInfoUrl), ); return downloadResult$.asObservable(); - } + }, }; function doDownload(downloadResult$: AsyncSubject, diff --git a/src/ts/download/metadata/id3-metadata-service.ts b/src/ts/download/metadata/id3-metadata-service.ts index 3e53e1e..2520d0c 100644 --- a/src/ts/download/metadata/id3-metadata-service.ts +++ b/src/ts/download/metadata/id3-metadata-service.ts @@ -21,22 +21,22 @@ export const ID3MetadataService = { ...downloadInfo, downloadOptions: { ...downloadInfo.downloadOptions, - url - } + url, + }, } as any)), catchError((err: Error) => { logger.error(`Unable to fetch metadata for track ${downloadInfo.trackInfo.title}`, err); return of(downloadInfo); - }) + }), ); - } + }, }; function writeMetadata$(metadata: ITrackMetadata, arrayBuffer: ArrayBuffer): Observable { return of(ID3WriterService.createWriter(arrayBuffer)).pipe( map(withTextualMetadata.bind(null, metadata)), flatMap(withCoverArt$.bind(null, metadata)), - map(ID3WriterService.addTag) + map(ID3WriterService.addTag), ); } @@ -52,7 +52,7 @@ function withTextualMetadata(metadata: ITrackMetadata, writer: IID3Writer): IID3 ID3WriterService.setFrame(writer, 'WOAS', metadata.audio_source_url); ID3WriterService.setFrame(writer, 'COMM', { description: 'Soundcloud description', - text: metadata.description || '' + text: metadata.description || '', }); return writer; } @@ -69,12 +69,12 @@ function withCoverArt$(metadata: ITrackMetadata, writer: IID3Writer): Observable data: arrayBuffer, description: `Soundcloud artwork. Source: ${url}`, type: 3, - useUnicodeEncoding: false - }) + useUnicodeEncoding: false, + }), ), catchError((err: Error) => { logger.error(`Unable to fetch cover art for track ${metadata.title}`, err); return of(writer); - }) + }), ); } diff --git a/src/ts/download/metadata/metadata-adapter.ts b/src/ts/download/metadata/metadata-adapter.ts index 27954cc..f019d75 100644 --- a/src/ts/download/metadata/metadata-adapter.ts +++ b/src/ts/download/metadata/metadata-adapter.ts @@ -11,19 +11,19 @@ export const MetadataAdapter = { addMetadata$(downloadInfo: ITrackDownloadInfo): Observable { const fileExtension = downloadInfo.downloadOptions.filename.split('.').pop(); const metadata$ = of(TrackMetadataFactory.create(downloadInfo.trackInfo)).pipe( - flatMap(withUpdatedCoverArtUrl$) + flatMap(withUpdatedCoverArtUrl$), ); switch (fileExtension) { case 'mp3': return metadata$.pipe( flatMap((metadata: ITrackMetadata) => ID3MetadataService.addID3V2Metadata$(metadata, downloadInfo)), - tap((info: ITrackDownloadInfo) => logger.debug('Added mp3 metadata', info)) + tap((info: ITrackDownloadInfo) => logger.debug('Added mp3 metadata', info)), ); default: return of(downloadInfo); } - } + }, }; function withUpdatedCoverArtUrl$(metadata: ITrackMetadata): Observable { diff --git a/src/ts/download/metadata/track-metadata-factory.ts b/src/ts/download/metadata/track-metadata-factory.ts index d93ec80..d79087b 100644 --- a/src/ts/download/metadata/track-metadata-factory.ts +++ b/src/ts/download/metadata/track-metadata-factory.ts @@ -16,7 +16,7 @@ export const TrackMetadataFactory = { release_day: trackInfo.release_day, release_month: trackInfo.release_month, release_year: trackInfo.release_year, - title: (titleParts.length > 1) ? titleParts.slice(1).join(' - ') : trackInfo.title + title: (titleParts.length > 1) ? titleParts.slice(1).join(' - ') : trackInfo.title, }; - } + }, }; diff --git a/src/ts/download/playlist-download-service.ts b/src/ts/download/playlist-download-service.ts index 071c6d9..10ea4e1 100644 --- a/src/ts/download/playlist-download-service.ts +++ b/src/ts/download/playlist-download-service.ts @@ -9,14 +9,14 @@ export const PlaylistDownloadService = { const downloadLocation = getDownloadLocation(playlistInfo); logger.debug(`Downloading playlist to '${downloadLocation}'`, playlistInfo); const tracks = playlistInfo.tracks.map( - (trackInfo: ITrackInfo) => TrackDownloadService.download(trackInfo, downloadLocation) + (trackInfo: ITrackInfo) => TrackDownloadService.download(trackInfo, downloadLocation), ); return { kind: ResourceType.Playlist, playlistInfo, - tracks + tracks, }; - } + }, }; function getDownloadLocation(playlistInfo: IPlaylistInfo): string { diff --git a/src/ts/download/resource/resource-info-service.ts b/src/ts/download/resource/resource-info-service.ts index b971d2a..333acfe 100644 --- a/src/ts/download/resource/resource-info-service.ts +++ b/src/ts/download/resource/resource-info-service.ts @@ -12,7 +12,7 @@ export const ResourceInfoService = { }, getTrackInfoList$(url: string): Observable { return getResource$(url); - } + }, }; function getResource$(url: string): Observable { diff --git a/src/ts/download/resource/resource-info.ts b/src/ts/download/resource/resource-info.ts index e3966f8..9bb3374 100644 --- a/src/ts/download/resource/resource-info.ts +++ b/src/ts/download/resource/resource-info.ts @@ -1,7 +1,7 @@ export enum ResourceType { Track = 'track', Playlist = 'playlist', - User = 'user' + User = 'user', } export interface IResourceInfo { diff --git a/src/ts/download/track-download-info-factory.ts b/src/ts/download/track-download-info-factory.ts index a734478..62ea0b1 100644 --- a/src/ts/download/track-download-info-factory.ts +++ b/src/ts/download/track-download-info-factory.ts @@ -14,14 +14,14 @@ export const TrackDownloadInfoFactory = { create$(trackInfo: ITrackInfo, downloadLocation: string): Observable { return combineLatest( TrackDownloadMethodService.getDownloadMethodInfo$(trackInfo), - OptionsObservables.getOptions$() + OptionsObservables.getOptions$(), ).pipe( map(([downloadMethodInfo, options]) => { - trackInfo = options.cleanTrackTitle ? cleanTrackTitle(trackInfo) : trackInfo; + trackInfo = cleanTrackTitleIfEnabled(trackInfo, options); return toDownloadInfo(trackInfo, downloadMethodInfo, downloadLocation, options); - }) + }), ); - } + }, }; function toDownloadInfo(trackInfo: ITrackInfo, @@ -33,15 +33,20 @@ function toDownloadInfo(trackInfo: ITrackInfo, downloadMethod: downloadMethodInfo.downloadMethod, downloadOptions: getDownloadOptions(filePath, downloadMethodInfo.url, options), originalUrl: downloadMethodInfo.url, - trackInfo + trackInfo, }; } -function cleanTrackTitle(trackInfo: ITrackInfo): ITrackInfo { - const freeDlRegex = /[-_|/*!\s]*[\[(\s]*(buy\s?=\s?)?free[\s_]?(download|dl).*$/i; +function cleanTrackTitleIfEnabled(trackInfo: ITrackInfo, options: IOptions): ITrackInfo { + if (!options.cleanTrackTitle.enabled) { + return trackInfo; + } + const regex = new RegExp(options.cleanTrackTitle.pattern, 'i'); + const cleanedTitle = trackInfo.title.replace(regex, '').trim(); return { ...trackInfo, - title: trackInfo.title.replace(freeDlRegex, '') + // Don't use cleaned title if the pattern matched the entire title + title: cleanedTitle === '' ? trackInfo.title : cleanedTitle, }; } @@ -56,6 +61,6 @@ function getDownloadOptions(filePath: string, url: string, options: IOptions): D conflictAction: options.overwriteExistingFiles ? 'overwrite' : 'uniquify', filename: filePath, saveAs: false, - url + url, }; } diff --git a/src/ts/download/track-download-method-service.ts b/src/ts/download/track-download-method-service.ts index dd23907..3df762f 100644 --- a/src/ts/download/track-download-method-service.ts +++ b/src/ts/download/track-download-method-service.ts @@ -16,7 +16,7 @@ export const TrackDownloadMethodService = { return combineLatest( canUseDownloadUrlMethod$(trackInfo), canUseStreamUrlMethod$(trackInfo), - OptionsObservables.getOptions$() + OptionsObservables.getOptions$(), ).pipe( flatMap(([canUseDownloadUrlMethod, canUseStreamUrlMethod, options]) => { if (canUseDownloadUrlMethod && shouldUseDownloadUrlMethod(trackInfo, options)) { @@ -26,9 +26,9 @@ export const TrackDownloadMethodService = { } else { return useI1ApiMethod$(trackInfo); } - }) + }), ); - } + }, }; function canUseDownloadUrlMethod$(trackInfo: ITrackInfo): Observable { @@ -51,7 +51,7 @@ function useDownloadUrlMethod$(trackInfo: ITrackInfo): Observable logger.debug('Downloading track', downloadInfo)), flatMap(addMetadataIfEnabled$), - timeout(1800000) + timeout(1800000), ).subscribe( downloadTrack.bind(null, downloadMetadata$), onError.bind(null, downloadMetadata$, trackInfo), - () => logger.debug('Track download info stream completed', trackInfo) + () => logger.debug('Track download info stream completed', trackInfo), ); return { kind: ResourceType.Track, metadata$: downloadMetadata$.asObservable(), - trackInfo + trackInfo, }; - } + }, }; function addMetadataIfEnabled$(downloadInfo: ITrackDownloadInfo): Observable { return OptionsObservables.getOptions$().pipe( flatMap((options: IOptions) => - options.addMetadata ? MetadataAdapter.addMetadata$(downloadInfo) : of(downloadInfo) - ) + options.addMetadata ? MetadataAdapter.addMetadata$(downloadInfo) : of(downloadInfo), + ), ); } @@ -43,7 +43,7 @@ function downloadTrack(downloadMetadata$: AsyncSubject, if (downloadId !== undefined) { downloadMetadata$.next({ downloadId, - downloadInfo + downloadInfo, }); downloadMetadata$.complete(); } else { diff --git a/src/ts/download/user-download-service.ts b/src/ts/download/user-download-service.ts index 4ddf838..ae299e2 100644 --- a/src/ts/download/user-download-service.ts +++ b/src/ts/download/user-download-service.ts @@ -15,16 +15,16 @@ export const UserDownloadService = { ResourceInfoService.getTrackInfoList$(trackListInfoUrl).pipe( timeout(60000), map((tracks: ITrackInfo[]) => tracks.map( - (trackInfo: ITrackInfo) => TrackDownloadService.download(trackInfo, downloadLocation) + (trackInfo: ITrackInfo) => TrackDownloadService.download(trackInfo, downloadLocation), )), map((tracks: ITrackDownloadResult[]) => ({ kind: ResourceType.User, tracks, - userInfo - })) + userInfo, + })), ).subscribe(downloadResult$); return downloadResult$.asObservable(); - } + }, }; function getDownloadLocation(userInfo: IUserInfo): string { diff --git a/src/ts/messaging/messenger.ts b/src/ts/messaging/messenger.ts index a133060..0b6e58c 100644 --- a/src/ts/messaging/messenger.ts +++ b/src/ts/messaging/messenger.ts @@ -31,7 +31,7 @@ export abstract class BaseMessenger implements IMessenger { response$.pipe(first()).subscribe(sendResponse); return true; } - } + }, ); } else { @@ -40,7 +40,7 @@ export abstract class BaseMessenger implements IMessenger { if (message.type === messageType) { handlerArgs$.next({message, sender}); } - } + }, ); } diff --git a/src/ts/options/default-options.ts b/src/ts/options/default-options.ts new file mode 100644 index 0000000..42a43aa --- /dev/null +++ b/src/ts/options/default-options.ts @@ -0,0 +1,14 @@ +import {IOptions} from 'src/ts/options/option'; + +export const defaultOptions: IOptions = { + addMetadata: true, + alwaysDownloadMp3: true, + cleanTrackTitle: { + enabled: true, + pattern: + `[-―_|/*!\\s]*[{(【\\[\\s]*` + + `((click|hit|press)?\\s*['"]?buy['"]?(link|is|to|for|a|4|=|-|\\s)*)?` + + `((free[\\s_]?(download|dl))|((free|full)?[\\s_]?(download|dl)[\\s_]?link)).*$`, + }, + overwriteExistingFiles: false, +}; diff --git a/src/ts/options/option.ts b/src/ts/options/option.ts index 8eb9518..f4edd50 100644 --- a/src/ts/options/option.ts +++ b/src/ts/options/option.ts @@ -1,13 +1,11 @@ export interface IOptions { addMetadata: boolean; alwaysDownloadMp3: boolean; - cleanTrackTitle: boolean; + cleanTrackTitle: ICleanTrackTitleOption; overwriteExistingFiles: boolean; } -export const defaultOptions: IOptions = { - addMetadata: true, - alwaysDownloadMp3: true, - cleanTrackTitle: true, - overwriteExistingFiles: false -}; +export interface ICleanTrackTitleOption { + enabled: boolean; + pattern: string; +} diff --git a/src/ts/options/options-observables.ts b/src/ts/options/options-observables.ts index 95b74a6..fce3c42 100644 --- a/src/ts/options/options-observables.ts +++ b/src/ts/options/options-observables.ts @@ -1,8 +1,9 @@ import {bindCallback} from 'rxjs'; -import {defaultOptions, IOptions} from 'src/ts/options/option'; +import {defaultOptions} from 'src/ts/options/default-options'; +import {IOptions} from 'src/ts/options/option'; export const OptionsObservables = { getOptions$() { return bindCallback(chrome.storage.sync.get)(defaultOptions); - } + }, }; diff --git a/src/ts/options/options-script.ts b/src/ts/options/options-script.ts index 1ae5bdd..4401a31 100644 --- a/src/ts/options/options-script.ts +++ b/src/ts/options/options-script.ts @@ -1,12 +1,14 @@ import * as $ from 'jquery'; -import {defaultOptions, IOptions} from 'src/ts/options/option'; +import {defaultOptions} from 'src/ts/options/default-options'; +import {IOptions} from 'src/ts/options/option'; import {IRunnable} from 'src/ts/util/runnable'; export class OptionsScript implements IRunnable { public run(): void { restoreOptions(); $('#save-btn').on('click', saveOptions); - $('#reset-btn').on('click', resetToDefaults); + $('#defaults-btn').on('click', setToDefaults); + $('#clean-title-option').on('click', (event: any) => syncCleanTitlePatternInput(event.target.checked)); } } @@ -19,15 +21,20 @@ function saveOptions() { $('#confirm-msg').show().delay(1000).fadeOut(); } -function resetToDefaults() { +function setToDefaults() { setOptions(defaultOptions); - saveOptions(); +} + +function syncCleanTitlePatternInput(enabled: boolean) { + $('#clean-title-pattern').prop('disabled', !enabled); } function setOptions(options: IOptions) { $('#add-metadata-option').prop('checked', options.addMetadata); $('#always-mp3-option').prop('checked', options.alwaysDownloadMp3); - $('#clean-title-option').prop('checked', options.cleanTrackTitle); + $('#clean-title-option').prop('checked', options.cleanTrackTitle.enabled); + $('#clean-title-pattern').val(options.cleanTrackTitle.pattern); + syncCleanTitlePatternInput(options.cleanTrackTitle.enabled); $('#overwrite-option').prop('checked', options.overwriteExistingFiles); } @@ -35,7 +42,10 @@ function getOptions(): IOptions { return { addMetadata: $('#add-metadata-option').prop('checked'), alwaysDownloadMp3: $('#always-mp3-option').prop('checked'), - cleanTrackTitle: $('#clean-title-option').prop('checked'), - overwriteExistingFiles: $('#overwrite-option').prop('checked') + cleanTrackTitle: { + enabled: $('#clean-title-option').prop('checked'), + pattern: $('#clean-title-pattern').val().toString(), + }, + overwriteExistingFiles: $('#overwrite-option').prop('checked'), }; } diff --git a/src/ts/util/dom-observer.ts b/src/ts/util/dom-observer.ts index a19d98c..9d967dc 100644 --- a/src/ts/util/dom-observer.ts +++ b/src/ts/util/dom-observer.ts @@ -16,7 +16,7 @@ export function elementRemoved$(elem: Node): Observable { observeAllNodes(mutationObserver); return mutationObserver; }, - () => mutationObserver.disconnect() + () => mutationObserver.disconnect(), ); } @@ -37,7 +37,7 @@ export function elementAdded$(test: (node: Node) => boolean): Observable { observeAllNodes(mutationObserver); return mutationObserver; }, - () => mutationObserver.disconnect() + () => mutationObserver.disconnect(), ); } @@ -54,13 +54,13 @@ export function elementExist$(selector: string): Observable { export function elementExistOrAdded$(selector: string): Observable { return merge( elementExist$(selector), - elementAdded$((node: Node) => $(node).is(selector)) + elementAdded$((node: Node) => $(node).is(selector)), ); } function observeAllNodes(mutationObserver: MutationObserver) { mutationObserver.observe(document.body, { childList: true, - subtree: true + subtree: true, }); } diff --git a/src/ts/util/filename-service.ts b/src/ts/util/filename-service.ts index 8a592f8..ebc5516 100644 --- a/src/ts/util/filename-service.ts +++ b/src/ts/util/filename-service.ts @@ -5,5 +5,5 @@ export const FilenameService = { removeSpecialCharacters(name: string): string { return name.replace(/[<>:"|?*\/\\]/g, '_').replace(/~/g, '-'); - } + }, }; diff --git a/src/ts/util/rxjs-operators.ts b/src/ts/util/rxjs-operators.ts index 432d64e..97c9f19 100644 --- a/src/ts/util/rxjs-operators.ts +++ b/src/ts/util/rxjs-operators.ts @@ -5,7 +5,7 @@ export function concatFilter(predicate: (value: T) => Observable) { return concatMap((value: T) => predicate(value).pipe( filter(Boolean), - mapTo(value) - ) + mapTo(value), + ), ); } diff --git a/src/ts/util/url-service.ts b/src/ts/util/url-service.ts index bb57c35..4b6f74c 100644 --- a/src/ts/util/url-service.ts +++ b/src/ts/util/url-service.ts @@ -8,5 +8,5 @@ export const UrlService = { getCurrentUrl(): string { return document.location.href; - } + }, }; diff --git a/src/ts/util/xhr-service.ts b/src/ts/util/xhr-service.ts index 9750f9e..3d8ba7c 100644 --- a/src/ts/util/xhr-service.ts +++ b/src/ts/util/xhr-service.ts @@ -9,7 +9,7 @@ export const XhrService = { }, getJSON$(url: string): Observable { return getResponse$('json', url); - } + }, }; function getResponse$(responseType: XMLHttpRequestResponseType, url: string): Observable { diff --git a/test/ts/background/background-script.spec.ts b/test/ts/background/background-script.spec.ts index 799b03a..25e7de8 100644 --- a/test/ts/background/background-script.spec.ts +++ b/test/ts/background/background-script.spec.ts @@ -98,8 +98,8 @@ describe('background script', () => { it('should send a reload message when a request reload content page message is received', () => { const handlerArgs = { sender: { - tab: {id: 123} - } + tab: {id: 123}, + }, } as IMessageHandlerArgs; stubOnMessage$.withArgs(RequestContentPageReloadMessage.TYPE).returns(of(handlerArgs)); fixture.run(); @@ -128,8 +128,8 @@ describe('background script', () => { it('should download when a request download message is received', () => { const handlerArgs = { message: { - resourceInfoUrl: 'some-url' - } + resourceInfoUrl: 'some-url', + }, } as IMessageHandlerArgs; stubOnMessage$.withArgs(RequestDownloadMessage.TYPE).returns(of(handlerArgs)); fixture.run(); @@ -158,11 +158,11 @@ describe('background script', () => { const handlerArgs = { message: { message: 'some-message', - optionalParams: [1, 2] + optionalParams: [1, 2], }, sender: { - tab: {id: 123} - } + tab: {id: 123}, + }, } as IMessageHandlerArgs; stubOnMessage$.withArgs(LogToConsoleMessage.TYPE).returns(of(handlerArgs)); fixture.run(); diff --git a/test/ts/background/sc-page-observables.spec.ts b/test/ts/background/sc-page-observables.spec.ts index f8000d8..cf771fc 100644 --- a/test/ts/background/sc-page-observables.spec.ts +++ b/test/ts/background/sc-page-observables.spec.ts @@ -32,7 +32,7 @@ describe('sc page visited observables', () => { const invalidScUrls = [ 'https://not.soundcloud.com/', 'https://soundcloud.org/', - 'https://soundcloud.com.abc/' + 'https://soundcloud.com.abc/', ]; let stubOnCompleted: SinonStub; diff --git a/test/ts/content/injection/list-item-injection-service.spec.ts b/test/ts/content/injection/list-item-injection-service.spec.ts index 2159c2b..02585f3 100644 --- a/test/ts/content/injection/list-item-injection-service.spec.ts +++ b/test/ts/content/injection/list-item-injection-service.spec.ts @@ -85,7 +85,7 @@ describe('list item injection service', () => { const downloadButtons = getDownloadButtons(); $.each(downloadButtons, (_, button) => expect($(button)).to.have.$class('sc-button-small') - .and.to.have.$class(ZC_DL_BUTTON_SMALL_CLASS) + .and.to.have.$class(ZC_DL_BUTTON_SMALL_CLASS), ); }); @@ -100,7 +100,7 @@ describe('list item injection service', () => { fixture.injectDownloadButtons(onUnload$); expect(spyCreateDownloadButton).to.have.been.calledOnceWithExactly(onUnload$, expectedUrl); - } + }, ); // noinspection TypeScriptValidateJSTypes @@ -115,7 +115,7 @@ describe('list item injection service', () => { expect(downloadButton.length).to.be.equal(1); expect($.contains(buttonGroup[0], downloadButton[0])).to.be.true; - } + }, ); }); }); diff --git a/test/ts/download/metadata/id3-metadata-service.spec.ts b/test/ts/download/metadata/id3-metadata-service.spec.ts index 62a308c..829a09f 100644 --- a/test/ts/download/metadata/id3-metadata-service.spec.ts +++ b/test/ts/download/metadata/id3-metadata-service.spec.ts @@ -16,7 +16,7 @@ describe('id3 metadata service', () => { const fixture = ID3MetadataService; const downloadInfo = { downloadOptions: {url: 'download-options-url'}, - trackInfo: {title: 'track-title'} + trackInfo: {title: 'track-title'}, } as ITrackDownloadInfo; const writer = {foo: 'bar'} as IID3Writer; const metadataAddedURL = 'url-with-metadata-added'; @@ -75,7 +75,7 @@ describe('id3 metadata service', () => { expect(stubSetFrame).to.have.been.calledWithExactly(writer, 'WOAS', metadata.audio_source_url); expect(stubSetFrame).to.have.been.calledWithExactly(writer, 'COMM', { description: 'Soundcloud description', - text: metadata.description + text: metadata.description, }); expect(stubAddTag).to.have.been.calledWith(writer).calledAfter(stubSetFrame); }); @@ -86,7 +86,7 @@ describe('id3 metadata service', () => { expect(stubSetFrame).to.have.been.calledWithExactly(writer, 'COMM', { description: 'Soundcloud description', - text: '' + text: '', }); expect(stubAddTag).to.have.been.calledWith(writer).calledAfter(stubSetFrame); }); @@ -134,7 +134,7 @@ describe('id3 metadata service', () => { data: coverArtData, description: `Soundcloud artwork. Source: ${metadata.cover_url}`, type: 3, - useUnicodeEncoding: false + useUnicodeEncoding: false, }; stubGetArrayBuffer$.withArgs(metadata.cover_url).returns(of(coverArtData)); }); @@ -186,8 +186,8 @@ describe('id3 metadata service', () => { ...downloadInfo, downloadOptions: { ...downloadInfo.downloadOptions, - url - } + url, + }, }; expect(rx.next).to.have.been.calledOnceWithExactly(expectedDownloadInfo); expect(rx.error).to.not.have.been.called; @@ -208,7 +208,7 @@ describe('id3 metadata service', () => { release_month: 4, release_year: 2008, title: 'some-title', - ...overrides + ...overrides, }; } }); diff --git a/test/ts/download/metadata/track-metadata-factory.spec.ts b/test/ts/download/metadata/track-metadata-factory.spec.ts index 3d3a361..5ff5239 100644 --- a/test/ts/download/metadata/track-metadata-factory.spec.ts +++ b/test/ts/download/metadata/track-metadata-factory.spec.ts @@ -9,12 +9,12 @@ describe('track metadata factory', () => { it('should parse the artist and title from the track title ' + 'and convert all other fields correctly', () => { const trackInfo = createTrackInfo({ - title: 'a track-artist - a song-title - separated by a dash and spaces' + title: 'a track-artist - a song-title - separated by a dash and spaces', }); const actual = fixture.create(trackInfo); const expected = createExpectedMetadata({ albumArtist: 'a track-artist', - title: 'a song-title - separated by a dash and spaces' + title: 'a song-title - separated by a dash and spaces', }); expect(actual).to.deep.include(expected); }); @@ -50,9 +50,9 @@ describe('track metadata factory', () => { user: { kind: ResourceType.User, permalink_url: 'user-permalink-url', - username: 'user-username' + username: 'user-username', }, - ...overrides + ...overrides, }; } @@ -71,7 +71,7 @@ describe('track metadata factory', () => { release_month: trackInfo.release_month, release_year: trackInfo.release_year, title: trackInfo.title, - ...overrides + ...overrides, }; } }); diff --git a/test/ts/download/playlist-download-service.spec.ts b/test/ts/download/playlist-download-service.spec.ts index afc89a1..54939dc 100644 --- a/test/ts/download/playlist-download-service.spec.ts +++ b/test/ts/download/playlist-download-service.spec.ts @@ -18,8 +18,8 @@ describe('playlist download service', () => { title: 'some*playlist?with>special\\characters', tracks: [trackOneInfo, trackTwoInfo], user: { - username: 'some { expect(actual).to.be.deep.equal({ kind: ResourceType.Playlist, playlistInfo, - tracks: [trackOneDlResult, trackTwoDlResult] + tracks: [trackOneDlResult, trackTwoDlResult], }); }); }); diff --git a/test/ts/download/track-download-info-factory.spec.ts b/test/ts/download/track-download-info-factory.spec.ts index 94b2df7..f06d398 100644 --- a/test/ts/download/track-download-info-factory.spec.ts +++ b/test/ts/download/track-download-info-factory.spec.ts @@ -6,6 +6,8 @@ import {ITrackDownloadInfo} from 'src/ts/download/track-download-info'; import {TrackDownloadInfoFactory} from 'src/ts/download/track-download-info-factory'; import {ITrackDownloadMethodInfo, TrackDownloadMethod} from 'src/ts/download/track-download-method'; import {TrackDownloadMethodService} from 'src/ts/download/track-download-method-service'; +import {defaultOptions} from 'src/ts/options/default-options'; +import {IOptions} from 'src/ts/options/option'; import {OptionsObservables} from 'src/ts/options/options-observables'; import {configureChai, useRxTesting} from 'test/ts/test-initializers'; @@ -21,14 +23,19 @@ describe('track download info factory', () => { const downloadMethodInfo: ITrackDownloadMethodInfo = { downloadMethod: TrackDownloadMethod.DownloadUrlMethod, format: 'wav', - url: 'download-url' + url: 'download-url', }; + let options: IOptions; let stubGetOptions$: SinonStub; let stubGetDownloadMethodInfo$: SinonStub; - const options = {cleanTrackTitle: true, overwriteExistingFiles: false}; beforeEach(() => { + options = { + cleanTrackTitle: {...defaultOptions.cleanTrackTitle}, + overwriteExistingFiles: false, + } as IOptions; + stubGetOptions$ = stub(OptionsObservables, 'getOptions$'); stubGetOptions$.returns(of(options)); @@ -64,44 +71,70 @@ describe('track download info factory', () => { .calledWithMatch(match.has('trackInfo', trackInfo)); }); - context('cleaning the track info', () => { - const titleSuffixes = [ - ' - FREE DOWNLOAD [link in description]', - '|[FREE Download]', - '*** FREE DOWNLOAD ***', - ' // FREE_DL - Link In Description!!! //', - '_Free_Download', - ' (Free Download)', - ' [Buy = Free Download]', - '*BUY=FREE DOWNLOAD*', - ' BUY= Free Download', - '| free dl', + context('cleaning the track info with the default pattern', () => { + const trackTitles = [ + 'Alok & Sevenn - BYOB [ FREE DOWNLOAD ]', + 'Calvin Harris - Live At EDC Las Vegas 2014 FREE DOWNLOAD', + 'Analog Trip @ EDM Underground Sessions Vol021 Protonradio 10-1-2017 | Free Download: goo.gl/pgD3gr', + 'Strip That Down - Liam Payne ("Deep House" Lucas Levi Remix)*BUY = FREE DOWNLOAD*', + 'Alan Walker - Faded (Osias Trap Remix) [BUY = FREE DOWNLOAD]', + 'Bob Marley - Is This Love (Soke Remix) **FREE DOWNLOAD**', + 'Hip Hop Beats Instrumental - Hard Work |Free Download| (Standard Lease $24.95) (Instant Delivery)', + 'Tracy Chapman - Fast Car (Bauke Top Remix) (Buy=Free DL)', + `Taylor Swift & Zayn Malik - I Don't Wanna Live Forever (Toob's Moombahbaas Refix) (buy = free DL!)`, + 'All That Swag (Prod By. YaBoyJDub) *Wack Rap Tuesday* ["BUY" IS FREE DL!]', + `Jennifer Lopez - Ain't Your Mama (DEEJAYDANNY BOOTLEG)HIT BUY FOR FREE DOWNLOAD !`, + 'Dj Taj ~ Latch (Remix) {DOWNLOAD LINK IN DESCRIPTION}', + 'Dilbar Dilbar ― DJ Farrukh Squashup ― Download Link : hearthis.at/2167189/', + 'Snatch Ma Crops (full download link in description box)', + // negative cases + '[FREE_DL] Yuto.com City Light Remix SHIMPEI ×JIVA Nel MONDO', + '[Buy link = FREE DL!!!] Tororoudon - Hot Cocoa', + ]; + + const expectedTitles = [ + 'Alok & Sevenn - BYOB', + 'Calvin Harris - Live At EDC Las Vegas 2014', + 'Analog Trip @ EDM Underground Sessions Vol021 Protonradio 10-1-2017', + 'Strip That Down - Liam Payne ("Deep House" Lucas Levi Remix)', + 'Alan Walker - Faded (Osias Trap Remix)', + 'Bob Marley - Is This Love (Soke Remix)', + 'Hip Hop Beats Instrumental - Hard Work', + 'Tracy Chapman - Fast Car (Bauke Top Remix)', + `Taylor Swift & Zayn Malik - I Don't Wanna Live Forever (Toob's Moombahbaas Refix)`, + 'All That Swag (Prod By. YaBoyJDub) *Wack Rap Tuesday', + 'Jennifer Lopez - Ain\'t Your Mama (DEEJAYDANNY BOOTLEG)', + 'Dj Taj ~ Latch (Remix)', + 'Dilbar Dilbar ― DJ Farrukh Squashup', + 'Snatch Ma Crops', + // negative cases + '[FREE_DL] Yuto.com City Light Remix SHIMPEI ×JIVA Nel MONDO', + '[Buy link = FREE DL!!!] Tororoudon - Hot Cocoa', ]; beforeEach(() => { stubGetDownloadMethodInfo$.returns(of(downloadMethodInfo)); }); - // In test setup, clean track title option is enabled - forEach(titleSuffixes) - .it(`should remove '%s' from the end of the song title`, (suffix: string) => { - const newTrackInfo = {...trackInfo, title: `${trackInfo.title}${suffix}`}; + // In test setup, clean track titles option is enabled + forEach(trackTitles.map((t, i) => [t, expectedTitles[i]])) + .it(`should clean track title for '%s'`, (trackTitle: string, expected: string) => { + const newTrackInfo = {...trackInfo, title: trackTitle}; rx.subscribeTo(fixture.create$(newTrackInfo, downloadLocation)); const actual: ITrackDownloadInfo = rx.next.firstCall.args[0]; - expect(actual.trackInfo.title).to.be.equal(trackInfo.title); - expect(actual.downloadOptions.filename).not.to.contain(suffix); + expect(actual.trackInfo.title).to.be.equal(expected); + // expect(actual.downloadOptions.filename).to.contain(expected); }); - it('should not clean the track info when clean track title option is disabled', () => { - stubGetOptions$.returns(of({...options, cleanTrackTitle: false})); - const titleWithSuffix = trackInfo.title + titleSuffixes[0]; - const newTrackInfo = {...trackInfo, title: titleWithSuffix}; + it('should not clean the track title when clean track title option is disabled', () => { + stubGetOptions$.returns(of({cleanTrackTitle: {enabled: false}})); + const newTrackInfo = {...trackInfo, title: trackTitles[0]}; rx.subscribeTo(fixture.create$(newTrackInfo, downloadLocation)); const actual: ITrackDownloadInfo = rx.next.firstCall.args[0]; - expect(actual.trackInfo.title).to.be.equal(titleWithSuffix); - expect(actual.downloadOptions.filename).to.contain(titleSuffixes[0]); + expect(actual.trackInfo.title).to.be.equal(trackTitles[0]); + // expect(actual.downloadOptions.filename).to.contain(trackTitles[0]); }); }); diff --git a/test/ts/download/track-download-method-service.spec.ts b/test/ts/download/track-download-method-service.spec.ts index 6e82db3..48c474f 100644 --- a/test/ts/download/track-download-method-service.spec.ts +++ b/test/ts/download/track-download-method-service.spec.ts @@ -40,7 +40,7 @@ describe('track download method service', () => { trackInfo = { download_url: 'some-download-url', downloadable: true, - original_format: 'wav' + original_format: 'wav', } as ITrackInfo; }); @@ -107,7 +107,7 @@ describe('track download method service', () => { beforeEach(() => { trackInfo = { downloadable: false, - stream_url: 'some-stream-url' + stream_url: 'some-stream-url', } as ITrackInfo; }); @@ -163,7 +163,7 @@ describe('track download method service', () => { beforeEach(() => { trackInfo = { downloadable: false, - id: 123 + id: 123, } as ITrackInfo; stubGetJSON$.withArgs(expectedScI1ApiEndpoint()).returns(of({http_mp3_128_url: expectedDlUrl})); diff --git a/test/ts/download/track-download-service.spec.ts b/test/ts/download/track-download-service.spec.ts index 9f582b9..a477885 100644 --- a/test/ts/download/track-download-service.spec.ts +++ b/test/ts/download/track-download-service.spec.ts @@ -22,11 +22,11 @@ describe(`track download service`, () => { const downloadLocation = 'download-location'; const downloadInfo = { downloadOptions: {url: 'original-url'} as DownloadOptions, - trackInfo + trackInfo, } as ITrackDownloadInfo; const downloadInfoWithMetadata = { downloadOptions: {url: 'updated-options-url'} as DownloadOptions, - trackInfo + trackInfo, } as ITrackDownloadInfo; let stubGetOptions$: SinonStub; diff --git a/test/ts/download/user-download-service.spec.ts b/test/ts/download/user-download-service.spec.ts index 8d2a732..94c3055 100644 --- a/test/ts/download/user-download-service.spec.ts +++ b/test/ts/download/user-download-service.spec.ts @@ -19,7 +19,7 @@ describe('user download service', () => { const userInfo: IUserInfo = { kind: ResourceType.User, permalink_url: 'permalinkUrl', - username: 'some?username/with*special { expect(rx.next).to.have.been.calledOnceWithExactly({ kind: ResourceType.User, tracks: [trackOneDlResult, trackTwoDlResult], - userInfo + userInfo, }); expect(rx.complete).to.have.been.called; }); diff --git a/test/ts/options/default-options.spec.ts b/test/ts/options/default-options.spec.ts new file mode 100644 index 0000000..b7f5318 --- /dev/null +++ b/test/ts/options/default-options.spec.ts @@ -0,0 +1,21 @@ +import {defaultOptions} from 'src/ts/options/default-options'; +import {configureChai} from 'test/ts/test-initializers'; + +const expect = configureChai(); + +describe('the default options', () => { + it('should have the default settings', () => { + expect(defaultOptions).to.be.deep.equal({ + addMetadata: true, + alwaysDownloadMp3: true, + cleanTrackTitle: { + enabled: true, + pattern: + `[-―_|/*!\\s]*[{(【\\[\\s]*` + + `((click|hit|press)?\\s*['"]?buy['"]?(link|is|to|for|a|4|=|-|\\s)*)?` + + `((free[\\s_]?(download|dl))|((free|full)?[\\s_]?(download|dl)[\\s_]?link)).*$`, + }, + overwriteExistingFiles: false, + }); + }); +}); diff --git a/test/ts/options/options-observables.spec.ts b/test/ts/options/options-observables.spec.ts index 23bec8b..6884126 100644 --- a/test/ts/options/options-observables.spec.ts +++ b/test/ts/options/options-observables.spec.ts @@ -1,5 +1,5 @@ import {match, restore} from 'sinon'; -import {defaultOptions} from 'src/ts/options/option'; +import {defaultOptions} from 'src/ts/options/default-options'; import {OptionsObservables} from 'src/ts/options/options-observables'; import {configureChai, useRxTesting, useSinonChrome} from 'test/ts/test-initializers'; diff --git a/test/ts/options/options-script.spec.ts b/test/ts/options/options-script.spec.ts index c70779d..f23db6a 100644 --- a/test/ts/options/options-script.spec.ts +++ b/test/ts/options/options-script.spec.ts @@ -1,6 +1,7 @@ import * as $ from 'jquery'; -import {clock, restore, useFakeTimers} from 'sinon'; -import {defaultOptions, IOptions} from 'src/ts/options/option'; +import {clock, match, restore, useFakeTimers} from 'sinon'; +import {defaultOptions} from 'src/ts/options/default-options'; +import {IOptions} from 'src/ts/options/option'; import {OptionsScript} from 'src/ts/options/options-script'; import {configureChai, useSinonChrome} from 'test/ts/test-initializers'; @@ -13,18 +14,21 @@ describe('options script', () => { let fixture: OptionsScript; // values should differ from default options - const mockOptions: IOptions = { + const mockOptions: IOptions = Object.freeze({ addMetadata: false, alwaysDownloadMp3: true, - cleanTrackTitle: false, - overwriteExistingFiles: true - }; + cleanTrackTitle: { + enabled: false, + pattern: 'abcdefg', + }, + overwriteExistingFiles: true, + }); beforeEach(() => { useFakeTimers(); document.body.innerHTML = optionsHTML; - sinonChrome.storage.sync.get.yields(defaultOptions); + sinonChrome.storage.sync.get.withArgs(defaultOptions, match.any).yields(defaultOptions); fixture = new OptionsScript(); }); @@ -35,22 +39,35 @@ describe('options script', () => { context('when script is run', () => { it('should restore to the default options if there were no saved options', () => { fixture.run(); - verifyHTMLState({ - addMetadata: true, - alwaysDownloadMp3: true, - cleanTrackTitle: true, - overwriteExistingFiles: false - }); + verifyHTMLState(defaultOptions); }); it('should restore options from Chrome storage if there were saved options', () => { - sinonChrome.storage.sync.get.yields(mockOptions); + sinonChrome.storage.sync.get.withArgs(defaultOptions, match.any).yields(mockOptions); fixture.run(); verifyHTMLState(mockOptions); }); }); - context('when save button is clicked', () => { + context('when the clean title option checkbox is clicked', () => { + beforeEach(() => { + fixture.run(); + }); + + it('should enable the clean title pattern input when checkbox is checked', () => { + setHTMLState({...mockOptions, cleanTrackTitle: {enabled: false, pattern: ''}}); + $('#clean-title-option').trigger('click'); + expect($('#clean-title-pattern')).to.have.$prop('disabled', false); + }); + + it('should disable the clean title pattern input when checkbox is unchecked', () => { + setHTMLState({...mockOptions, cleanTrackTitle: {enabled: true, pattern: ''}}); + $('#clean-title-option').trigger('click'); + expect($('#clean-title-pattern')).to.have.$prop('disabled', true); + }); + }); + + context('when the save button is clicked', () => { beforeEach(() => { fixture.run(); }); @@ -66,25 +83,16 @@ describe('options script', () => { }); }); - context('when reset button is clicked', () => { + context('when the reset button is clicked', () => { beforeEach(() => { fixture.run(); setHTMLState(mockOptions); }); - it('should save default options to Chrome storage', () => { - $('#reset-btn').trigger('click'); - expect(sinonChrome.storage.sync.set).to.have.been.calledOnceWithExactly(defaultOptions); - }); - it('should set options on the page to reflect the default options', () => { - $('#reset-btn').trigger('click'); + $('#defaults-btn').trigger('click'); verifyHTMLState(defaultOptions); }); - - it('should show the confirmation message', () => { - testConfirmMsgWhenBtnIsClicked($('#reset-btn')); - }); }); function testConfirmMsgWhenBtnIsClicked(button: JQuery) { @@ -99,14 +107,18 @@ describe('options script', () => { function setHTMLState(options: IOptions) { $('#add-metadata-option').prop('checked', options.addMetadata); $('#always-mp3-option').prop('checked', options.alwaysDownloadMp3); - $('#clean-title-option').prop('checked', options.cleanTrackTitle); + $('#clean-title-option').prop('checked', options.cleanTrackTitle.enabled); + const cleanTitlePattern = $('#clean-title-pattern'); + cleanTitlePattern.val(options.cleanTrackTitle.pattern); + cleanTitlePattern.prop('disabled', !options.cleanTrackTitle.enabled); $('#overwrite-option').prop('checked', options.overwriteExistingFiles); } function verifyHTMLState(options: IOptions) { expect($('#add-metadata-option')).to.have.$prop('checked', options.addMetadata); expect($('#always-mp3-option')).to.have.$prop('checked', options.alwaysDownloadMp3); - expect($('#clean-title-option')).to.have.$prop('checked', options.cleanTrackTitle); + expect($('#clean-title-option')).to.have.$prop('checked', options.cleanTrackTitle.enabled); + expect($('#clean-title-pattern')).to.have.$val(options.cleanTrackTitle.pattern); expect($('#overwrite-option')).to.have.$prop('checked', options.overwriteExistingFiles); } }); diff --git a/test/ts/test-initializers.ts b/test/ts/test-initializers.ts index 6359e4c..0c9be07 100644 --- a/test/ts/test-initializers.ts +++ b/test/ts/test-initializers.ts @@ -48,7 +48,7 @@ export function useRxTesting(): IRxTestingWrapper { next: sandbox.spy(), subscribeTo(observable: Observable) { subscription = observable.subscribe(this); - } + }, }; afterEach('reset callbacks and unsubscribe', () => { diff --git a/tslint.json b/tslint.json index 4f47667..2b8acc8 100644 --- a/tslint.json +++ b/tslint.json @@ -16,8 +16,7 @@ "quotemark": [true, "single"], "ter-indent": [true, 2, { "SwitchCase": 1 - }], - "trailing-comma": false + }] }, "rulesDirectory": [ "node_modules/tslint-microsoft-contrib"