chore: manual lint fix

This commit is contained in:
Fernando Fernández 2021-05-13 12:56:50 +02:00
parent a050080ca9
commit 27ff1feb93
14 changed files with 261 additions and 261 deletions

View File

@ -1,9 +1,9 @@
root = true
[*]
charset = utf-8
end_of_line = lf
indent_style = space
indent_size = 4
end_of_line = lf
charset = utf-8
trim_trailing_whitespace = true
insert_final_newline = true
trim_trailing_whitespace = true

View File

@ -16,97 +16,97 @@ module.exports = {
'plugin:import/warnings',
'plugin:import/typescript'
],
overrides: [
{
env: {
browser: true,
es6: true,
node: false
},
files: ['.js', '.ts'],
globals: {
$scope: 'writable',
cast: 'readonly',
PRODUCTION: 'readonly'
}
}
],
plugins: ['prettier', 'promise', 'import', 'jsdoc'],
root: true,
rules: {
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'@typescript-eslint/prefer-ts-expect-error': 'error',
curly: 'error',
'padding-line-between-statements': [
'error',
// Always require blank lines after directives (like 'use-strict'), except between directives
{ blankLine: 'always', next: '*', prev: 'directive' },
{ blankLine: 'any', prev: 'directive', next: 'directive' },
// Always require blank lines after import, except between imports
{ blankLine: 'always', prev: 'import', next: '*' },
{ blankLine: 'any', prev: 'import', next: 'import' },
// Always require blank lines before and after every sequence of variable declarations and export
{
blankLine: 'always',
prev: '*',
next: ['const', 'let', 'var', 'export']
},
{
blankLine: 'always',
prev: ['const', 'let', 'var', 'export'],
next: '*'
},
{
blankLine: 'any',
prev: ['const', 'let', 'var', 'export'],
next: ['const', 'let', 'var', 'export']
},
// Always require blank lines before and after class declaration, if, do/while, switch, try
{
blankLine: 'always',
prev: '*',
next: ['if', 'class', 'for', 'do', 'while', 'switch', 'try']
},
{
blankLine: 'always',
prev: ['if', 'class', 'for', 'do', 'while', 'switch', 'try'],
next: '*'
},
// Always require blank lines before return statements
{ blankLine: 'always', prev: '*', next: 'return' }
],
'import/newline-after-import': 'error',
'import/order': 'error',
'jsdoc/require-hyphen-before-param-description': 'error',
'jsdoc/check-indentation': 'error',
'jsdoc/check-param-names': 'error',
'jsdoc/check-property-names': 'error',
'jsdoc/check-syntax': 'error',
'jsdoc/check-tag-names': 'error',
'jsdoc/no-types': 'error',
'jsdoc/require-description': 'warn',
'jsdoc/require-param-description': 'warn',
'jsdoc/require-hyphen-before-param-description': 'error',
'jsdoc/require-jsdoc': 'error',
'jsdoc/require-param-description': 'warn',
//TypeScript and IntelliSense already provides us information about the function typings while hovering and
// eslint-jsdoc doesn't detect a mismatch between what's declared in the function and what's declared in
// JSDOC.
'jsdoc/require-param-type': 'off',
'jsdoc/require-returns-type': 'off',
'jsdoc/check-indentation': 'error',
'jsdoc/check-syntax': 'error',
'jsdoc/check-param-names': 'error',
'jsdoc/check-property-names': 'error',
'jsdoc/check-tag-names': 'error',
'jsdoc/no-types': 'error',
'jsdoc/valid-types': 'off',
'padding-line-between-statements': [
'error',
// Always require blank lines after directives (like 'use-strict'), except between directives
{ blankLine: 'always', next: '*', prev: 'directive' },
{ blankLine: 'any', next: 'directive', prev: 'directive' },
// Always require blank lines after import, except between imports
{ blankLine: 'always', next: '*', prev: 'import' },
{ blankLine: 'any', next: 'import', prev: 'import' },
// Always require blank lines before and after every sequence of variable declarations and export
{
blankLine: 'always',
next: ['const', 'let', 'var', 'export'],
prev: '*'
},
{
blankLine: 'always',
next: '*',
prev: ['const', 'let', 'var', 'export']
},
{
blankLine: 'any',
next: ['const', 'let', 'var', 'export'],
prev: ['const', 'let', 'var', 'export']
},
// Always require blank lines before and after class declaration, if, do/while, switch, try
{
blankLine: 'always',
next: ['if', 'class', 'for', 'do', 'while', 'switch', 'try'],
prev: '*'
},
{
blankLine: 'always',
next: '*',
prev: ['if', 'class', 'for', 'do', 'while', 'switch', 'try']
},
// Always require blank lines before return statements
{ blankLine: 'always', next: 'return', prev: '*' }
],
'prefer-arrow-callback': 'error',
'prefer-template': 'error',
'promise/no-nesting': 'error',
'promise/no-return-in-finally': 'error',
'promise/prefer-await-to-callbacks': 'error',
'promise/prefer-await-to-then': 'error',
'@typescript-eslint/explicit-function-return-type': 'error',
'@typescript-eslint/prefer-ts-expect-error': 'error',
'@typescript-eslint/no-unused-vars': 'error',
'prefer-arrow-callback': 'error',
'prefer-template': 'error',
'sort-keys': [
'error',
'asc',
{ caseSensitive: true, natural: false, minKeys: 2 }
{ caseSensitive: false, minKeys: 2, natural: true }
],
'sort-vars': 'error'
},
overrides: [
{
files: ['.js', '.ts'],
env: {
node: false,
browser: true,
es6: true
},
globals: {
cast: 'readonly',
PRODUCTION: 'readonly',
$scope: 'writable'
}
}
],
settings: {
'import/parsers': {
'@typescript-eslint/parser': ['.ts', '.tsx']

View File

@ -76,7 +76,7 @@
"lint:code": "eslint --ext .ts,.js,.json .",
"lint:css": "stylelint **/*.css",
"prepare": "npm run build:production",
"prettier": "prettier --write .",
"prettier": "prettier --check .",
"start": "TS_NODE_PROJECT=\"tsconfig-webpack.json\" webpack serve --config webpack.config.ts",
"test": "jest --passWithNoTests",
"watch": "TS_NODE_PROJECT=\"tsconfig-webpack.json\" webpack --config webpack.config.ts --watch"

View File

@ -27,29 +27,29 @@ export abstract class CommandHandler {
private static playerManager: framework.PlayerManager;
private static playbackManager: playbackManager;
private static supportedCommands: SupportedCommands = {
DisplayContent: CommandHandler.displayContentHandler,
Identify: CommandHandler.IdentifyHandler,
InstantMix: CommandHandler.instantMixHandler,
Mute: CommandHandler.MuteHandler,
NextTrack: CommandHandler.nextTrackHandler,
Pause: CommandHandler.PauseHandler,
PlayLast: CommandHandler.playLastHandler,
PlayNext: CommandHandler.playNextHandler,
PlayNow: CommandHandler.playNowHandler,
PlayLast: CommandHandler.playLastHandler,
Shuffle: CommandHandler.shuffleHandler,
InstantMix: CommandHandler.instantMixHandler,
DisplayContent: CommandHandler.displayContentHandler,
NextTrack: CommandHandler.nextTrackHandler,
PreviousTrack: CommandHandler.previousTrackHandler,
SetAudioStreamIndex: CommandHandler.setAudioStreamIndexHandler,
SetSubtitleStreamIndex: CommandHandler.setSubtitleStreamIndexHandler,
VolumeUp: CommandHandler.VolumeUpHandler,
VolumeDown: CommandHandler.VolumeDownHandler,
ToggleMute: CommandHandler.ToggleMuteHandler,
Identify: CommandHandler.IdentifyHandler,
SetVolume: CommandHandler.SetVolumeHandler,
Seek: CommandHandler.SeekHandler,
Mute: CommandHandler.MuteHandler,
Unmute: CommandHandler.MuteHandler,
Stop: CommandHandler.StopHandler,
PlayPause: CommandHandler.PlayPauseHandler,
Pause: CommandHandler.PauseHandler,
PreviousTrack: CommandHandler.previousTrackHandler,
Seek: CommandHandler.SeekHandler,
SetAudioStreamIndex: CommandHandler.setAudioStreamIndexHandler,
SetRepeatMode: CommandHandler.SetRepeatModeHandler,
Unpause: CommandHandler.UnpauseHandler
SetSubtitleStreamIndex: CommandHandler.setSubtitleStreamIndexHandler,
SetVolume: CommandHandler.SetVolumeHandler,
Shuffle: CommandHandler.shuffleHandler,
Stop: CommandHandler.StopHandler,
ToggleMute: CommandHandler.ToggleMuteHandler,
Unmute: CommandHandler.MuteHandler,
Unpause: CommandHandler.UnpauseHandler,
VolumeDown: CommandHandler.VolumeDownHandler,
VolumeUp: CommandHandler.VolumeUpHandler
};
static configure(

View File

@ -55,9 +55,9 @@ function createProfileCondition(
): ProfileCondition {
return {
Condition,
IsRequired,
Property,
Value,
IsRequired
Value
};
}
@ -75,9 +75,9 @@ function getResponseProfiles(): Array<ResponseProfile> {
// This seems related to DLNA, it might not be needed?
return [
{
Type: DlnaProfileType.Video,
Container: 'm4v',
MimeType: 'video/mp4'
MimeType: 'video/mp4',
Type: DlnaProfileType.Video
}
];
}
@ -96,18 +96,18 @@ function getDirectPlayProfiles(): Array<DirectPlayProfile> {
for (const codec of vpxVideoCodecs) {
DirectPlayProfiles.push({
AudioCodec: webmAudioCodecs.join(','),
Container: 'webm',
Type: DlnaProfileType.Video,
AudioCodec: webmAudioCodecs.join(','),
VideoCodec: codec
});
}
DirectPlayProfiles.push({
AudioCodec: mp4AudioCodecs.join(','),
Container: 'mp4,m4v',
Type: DlnaProfileType.Video,
VideoCodec: mp4VideoCodecs.join(','),
AudioCodec: mp4AudioCodecs.join(',')
VideoCodec: mp4VideoCodecs.join(',')
});
}
@ -116,9 +116,9 @@ function getDirectPlayProfiles(): Array<DirectPlayProfile> {
for (const audioFormat of supportedAudio) {
if (audioFormat === 'mp3') {
DirectPlayProfiles.push({
AudioCodec: audioFormat,
Container: audioFormat,
Type: DlnaProfileType.Audio,
AudioCodec: audioFormat
Type: DlnaProfileType.Audio
});
} else if (audioFormat === 'webma') {
DirectPlayProfiles.push({
@ -135,8 +135,8 @@ function getDirectPlayProfiles(): Array<DirectPlayProfile> {
// aac also appears in the m4a and m4b container
if (audioFormat === 'aac') {
DirectPlayProfiles.push({
Container: 'm4a,m4b',
AudioCodec: audioFormat,
Container: 'm4a,m4b',
Type: DlnaProfileType.Audio
});
}
@ -152,7 +152,6 @@ function getCodecProfiles(): Array<CodecProfile> {
const CodecProfiles: Array<CodecProfile> = [];
const audioConditions: CodecProfile = {
Type: CodecType.Audio,
Codec: 'flac',
Conditions: [
createProfileCondition(
@ -165,7 +164,8 @@ function getCodecProfiles(): Array<CodecProfile> {
ProfileConditionType.LessThanEqual,
'24'
)
]
],
Type: CodecType.Audio
};
CodecProfiles.push(audioConditions);
@ -176,7 +176,6 @@ function getCodecProfiles(): Array<CodecProfile> {
}
const aacConditions: CodecProfile = {
Type: CodecType.VideoAudio,
Codec: 'aac',
Conditions: [
// Not sure what secondary audio means in this context. Multiple audio tracks?
@ -190,7 +189,8 @@ function getCodecProfiles(): Array<CodecProfile> {
ProfileConditionType.LessThanEqual,
'2'
)
]
],
Type: CodecType.VideoAudio
};
CodecProfiles.push(aacConditions);
@ -200,7 +200,6 @@ function getCodecProfiles(): Array<CodecProfile> {
const h26xProfile: string = getH26xProfileSupport(currentDeviceId);
const h26xConditions: CodecProfile = {
Type: CodecType.Video,
Codec: 'h264',
Conditions: [
createProfileCondition(
@ -224,13 +223,13 @@ function getCodecProfiles(): Array<CodecProfile> {
maxWidth.toString(),
true
)
]
],
Type: CodecType.Video
};
CodecProfiles.push(h26xConditions);
const videoConditions: CodecProfile = {
Type: CodecType.Video,
Conditions: [
createProfileCondition(
ProfileConditionValue.Width,
@ -238,20 +237,21 @@ function getCodecProfiles(): Array<CodecProfile> {
maxWidth.toString(),
true
)
]
],
Type: CodecType.Video
};
CodecProfiles.push(videoConditions);
const videoAudioConditions: CodecProfile = {
Type: CodecType.VideoAudio,
Conditions: [
createProfileCondition(
ProfileConditionValue.IsSecondaryAudio,
ProfileConditionType.Equals,
'false'
)
]
],
Type: CodecType.VideoAudio
};
CodecProfiles.push(videoAudioConditions);
@ -270,14 +270,14 @@ function getTranscodingProfiles(): Array<TranscodingProfile> {
if (profileOptions.enableHls !== false) {
TranscodingProfiles.push({
Container: 'ts',
Type: DlnaProfileType.Audio,
AudioCodec: hlsAudioCodecs.join(','),
BreakOnNonKeyFrames: false,
Container: 'ts',
Context: EncodingContext.Streaming,
Protocol: 'hls',
MaxAudioChannels: audioChannels.toString(),
MinSegments: 1,
BreakOnNonKeyFrames: false
Protocol: 'hls',
Type: DlnaProfileType.Audio
});
}
@ -286,12 +286,12 @@ function getTranscodingProfiles(): Array<TranscodingProfile> {
// audio only profiles here
for (const audioFormat of supportedAudio) {
TranscodingProfiles.push({
Container: audioFormat,
Type: DlnaProfileType.Audio,
AudioCodec: audioFormat,
Container: audioFormat,
Context: EncodingContext.Streaming,
MaxAudioChannels: audioChannels.toString(),
Protocol: 'http',
MaxAudioChannels: audioChannels.toString()
Type: DlnaProfileType.Audio
});
}
@ -308,29 +308,29 @@ function getTranscodingProfiles(): Array<TranscodingProfile> {
profileOptions.enableHls !== false
) {
TranscodingProfiles.push({
Container: 'ts',
Type: DlnaProfileType.Video,
AudioCodec: hlsAudioCodecs.join(','),
VideoCodec: hlsVideoCodecs.join(','),
BreakOnNonKeyFrames: false,
Container: 'ts',
Context: EncodingContext.Streaming,
Protocol: 'hls',
MaxAudioChannels: audioChannels.toString(),
MinSegments: 1,
BreakOnNonKeyFrames: false
Protocol: 'hls',
Type: DlnaProfileType.Video,
VideoCodec: hlsVideoCodecs.join(',')
});
}
if (hasVP8Support() || hasVP9Support()) {
TranscodingProfiles.push({
Container: 'webm',
Type: DlnaProfileType.Video,
AudioCodec: 'vorbis',
VideoCodec: 'vpx',
Container: 'webm',
Context: EncodingContext.Streaming,
Protocol: 'http',
// If audio transcoding is needed, limit channels to number of physical audio channels
// Trying to transcode to 5 channels when there are only 2 speakers generally does not sound good
MaxAudioChannels: audioChannels.toString()
MaxAudioChannels: audioChannels.toString(),
Protocol: 'http',
Type: DlnaProfileType.Video,
VideoCodec: 'vpx'
});
}
@ -370,8 +370,8 @@ export function getDeviceProfile(options: ProfileOptions): DeviceProfile {
// MaxStaticBitrate seems to be for offline sync only
const profile: DeviceProfile = {
MaxStreamingBitrate: options.bitrateSetting,
MaxStaticBitrate: options.bitrateSetting,
MaxStreamingBitrate: options.bitrateSetting,
MusicStreamingTranscodingBitrate: Math.min(
options.bitrateSetting,
192000

View File

@ -372,17 +372,17 @@ export abstract class DocumentManager {
private static async setRandomUserBackdrop(): Promise<void> {
const result = await JellyfinApi.authAjaxUser('Items', {
dataType: 'json',
type: 'GET',
query: {
SortBy: 'Random',
IncludeItemTypes: 'Movie,Series',
ImageTypes: 'Backdrop',
Recursive: true,
IncludeItemTypes: 'Movie,Series',
Limit: 1,
MaxOfficialRating: 'PG-13',
Recursive: true,
SortBy: 'Random'
// Although we're limiting to what the user has access to,
// not everyone will want to see adult backdrops rotating on their TV.
MaxOfficialRating: 'PG-13'
}
},
type: 'GET'
});
let src: string | null = null;

View File

@ -12,9 +12,9 @@ function getFetchPromise(request: any): Promise<Response> {
}
const fetchRequest: RequestInit = {
credentials: 'same-origin',
headers: headers,
method: request.type,
credentials: 'same-origin'
method: request.type
};
let contentType = request.contentType;

View File

@ -79,16 +79,16 @@ export function reportPlaybackStart(
broadcastToMessageBus({
//TODO: convert these to use a defined type in the type field
type: 'playbackstart',
data: getSenderReportingData($scope, reportingParams)
data: getSenderReportingData($scope, reportingParams),
type: 'playbackstart'
});
restartPingInterval($scope, reportingParams);
return JellyfinApi.authAjax('Sessions/Playing', {
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(reportingParams),
contentType: 'application/json'
type: 'POST'
});
}
@ -108,8 +108,8 @@ export function reportPlaybackProgress(
broadcastEventName = 'playbackprogress'
): Promise<void> {
broadcastToMessageBus({
type: broadcastEventName,
data: getSenderReportingData($scope, reportingParams)
data: getSenderReportingData($scope, reportingParams),
type: broadcastEventName
});
if (reportToServer === false) {
@ -120,9 +120,9 @@ export function reportPlaybackProgress(
lastTranscoderPing = new Date().getTime();
return JellyfinApi.authAjax('Sessions/Playing/Progress', {
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(reportingParams),
contentType: 'application/json'
type: 'POST'
});
}
@ -140,14 +140,14 @@ export function reportPlaybackStopped(
stopPingInterval();
broadcastToMessageBus({
type: 'playbackstop',
data: getSenderReportingData($scope, reportingParams)
data: getSenderReportingData($scope, reportingParams),
type: 'playbackstop'
});
return JellyfinApi.authAjax('Sessions/Playing/Stopped', {
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(reportingParams),
contentType: 'application/json'
type: 'POST'
});
}
@ -180,12 +180,12 @@ export function pingTranscoder(
return JellyfinApi.authAjax(
`Sessions/Playing/Ping?playSessionId=${reportingParams.PlaySessionId}`,
{
type: 'POST',
contentType: 'application/json',
data: JSON.stringify({
// jellyfin <= 10.6 wants it in the post data.
PlaySessionId: reportingParams.PlaySessionId
}),
contentType: 'application/json'
type: 'POST'
}
);
}
@ -276,9 +276,9 @@ export function getPlaybackInfo(
// TODO: PlayRequestQuery might not be the proper type for this
const query: PlayRequestQuery = {
UserId: JellyfinApi.userId ?? undefined,
MaxStreamingBitrate: maxBitrate,
StartTimeTicks: startPosition || 0,
MaxStreamingBitrate: maxBitrate
UserId: JellyfinApi.userId ?? undefined
};
if (audioStreamIndex != null) {
@ -298,11 +298,11 @@ export function getPlaybackInfo(
}
return JellyfinApi.authAjax(`Items/${item.Id}/PlaybackInfo`, {
query: query,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(postData),
contentType: 'application/json'
dataType: 'json',
query: query,
type: 'POST'
});
}
@ -332,11 +332,11 @@ export function getLiveStream(
};
const query: PlayRequestQuery = {
UserId: JellyfinApi.userId ?? undefined,
StartTimeTicks: startPosition || 0,
ItemId: item.Id,
MaxStreamingBitrate: maxBitrate,
PlaySessionId: playSessionId
PlaySessionId: playSessionId,
StartTimeTicks: startPosition || 0,
UserId: JellyfinApi.userId ?? undefined
};
if (audioStreamIndex != null) {
@ -348,11 +348,11 @@ export function getLiveStream(
}
return JellyfinApi.authAjax('LiveStreams/Open', {
query: query,
type: 'POST',
dataType: 'json',
contentType: 'application/json',
data: JSON.stringify(postData),
contentType: 'application/json'
dataType: 'json',
query: query,
type: 'POST'
});
}
@ -370,8 +370,8 @@ export async function getDownloadSpeed(byteSize: number): Promise<number> {
const now = new Date().getTime();
await JellyfinApi.authAjax(path, {
type: 'GET',
timeout: 5000
timeout: 5000,
type: 'GET'
});
const responseTimeSeconds = (new Date().getTime() - now) / 1000;
@ -418,7 +418,7 @@ export function stopActiveEncodings($scope: GlobalScope): Promise<void> {
}
return JellyfinApi.authAjax('Videos/ActiveEncodings', {
type: 'DELETE',
query: options
query: options,
type: 'DELETE'
});
}

View File

@ -110,8 +110,8 @@ export abstract class JellyfinApi {
}
const params = {
url: this.createUrl(path),
headers: this.getSecurityHeaders()
headers: this.getSecurityHeaders(),
url: this.createUrl(path)
};
return ajax({ ...params, ...args });
@ -132,8 +132,8 @@ export abstract class JellyfinApi {
}
const params = {
url: this.createUserUrl(path),
headers: this.getSecurityHeaders()
headers: this.getSecurityHeaders(),
url: this.createUserUrl(path)
};
return ajax({ ...params, ...args });

View File

@ -210,23 +210,23 @@ export async function reportDeviceCapabilities(): Promise<void> {
const maxBitrate = await getMaxBitrate();
const deviceProfile = getDeviceProfile({
enableHls: true,
bitrateSetting: maxBitrate
bitrateSetting: maxBitrate,
enableHls: true
});
const capabilities = {
DeviceProfile: deviceProfile,
PlayableMediaTypes: ['Audio', 'Video'],
SupportsPersistentIdentifier: false,
SupportsMediaControl: true,
DeviceProfile: deviceProfile
SupportsPersistentIdentifier: false
};
hasReportedCapabilities = true;
return JellyfinApi.authAjax('Sessions/Capabilities/Full', {
type: 'POST',
contentType: 'application/json',
data: JSON.stringify(capabilities),
contentType: 'application/json'
type: 'POST'
});
}
@ -243,9 +243,9 @@ export function processMessage(data: any): void {
console.log('Invalid message sent from sender. Sending error response');
broadcastToMessageBus({
type: 'error',
message:
'Missing one or more required params - command,options,userId,accessToken,serverAddress'
'Missing one or more required params - command,options,userId,accessToken,serverAddress',
type: 'error'
});
return;
@ -442,8 +442,8 @@ export async function changeStream(
const maxBitrate = await getMaxBitrate();
const deviceProfile = getDeviceProfile({
enableHls: true,
bitrateSetting: maxBitrate
bitrateSetting: maxBitrate,
enableHls: true
});
const audioStreamIndex =
params.AudioStreamIndex == null
@ -665,7 +665,7 @@ export function validatePlaybackInfoResult(result: any): boolean {
* @param error
*/
export function showPlaybackInfoErrorMessage(error: string): void {
broadcastToMessageBus({ type: 'playbackerror', message: error });
broadcastToMessageBus({ message: error, type: 'playbackerror' });
}
/**
@ -805,17 +805,17 @@ export function createMediaInformation(
mediaInfo.contentId = streamInfo.url;
mediaInfo.contentType = streamInfo.contentType;
mediaInfo.customData = {
startPositionTicks: streamInfo.startPositionTicks || 0,
itemId: item.Id,
mediaSourceId: streamInfo.mediaSource.Id,
audioStreamIndex: streamInfo.audioStreamIndex,
subtitleStreamIndex: streamInfo.subtitleStreamIndex,
playMethod: streamInfo.isStatic ? 'DirectStream' : 'Transcode',
runtimeTicks: streamInfo.mediaSource.RunTimeTicks,
liveStreamId: streamInfo.mediaSource.LiveStreamId,
canSeek: streamInfo.canSeek,
canClientSeek: streamInfo.canClientSeek,
playSessionId: playSessionId
canSeek: streamInfo.canSeek,
itemId: item.Id,
liveStreamId: streamInfo.mediaSource.LiveStreamId,
mediaSourceId: streamInfo.mediaSource.Id,
playMethod: streamInfo.isStatic ? 'DirectStream' : 'Transcode',
playSessionId: playSessionId,
runtimeTicks: streamInfo.mediaSource.RunTimeTicks,
startPositionTicks: streamInfo.startPositionTicks || 0,
subtitleStreamIndex: streamInfo.subtitleStreamIndex
};
mediaInfo.metadata = getMetadata(item);

View File

@ -133,8 +133,8 @@ export class playbackManager {
const maxBitrate = await getMaxBitrate();
const deviceProfile = getDeviceProfile({
enableHls: true,
bitrateSetting: maxBitrate
bitrateSetting: maxBitrate,
enableHls: true
});
const playbackInfo = await getPlaybackInfo(
item,

View File

@ -39,21 +39,21 @@ export function getReportingParams($scope: GlobalScope): PlaybackProgressInfo {
* those fields are always rounded.
*/
return {
PositionTicks: Math.round(getCurrentPositionTicks($scope)),
AudioStreamIndex: $scope.audioStreamIndex,
CanSeek: $scope.canSeek,
IsMuted: window.volume.muted,
IsPaused:
window.mediaManager.getPlayerState() ===
cast.framework.messages.PlayerState.PAUSED,
IsMuted: window.volume.muted,
AudioStreamIndex: $scope.audioStreamIndex,
SubtitleStreamIndex: $scope.subtitleStreamIndex,
VolumeLevel: Math.round(window.volume.level * 100),
ItemId: $scope.itemId,
MediaSourceId: $scope.mediaSourceId,
CanSeek: $scope.canSeek,
PlayMethod: $scope.playMethod,
LiveStreamId: $scope.liveStreamId,
MediaSourceId: $scope.mediaSourceId,
PlayMethod: $scope.playMethod,
PlaySessionId: $scope.playSessionId,
RepeatMode: window.repeatMode
PositionTicks: Math.round(getCurrentPositionTicks($scope)),
RepeatMode: window.repeatMode,
SubtitleStreamIndex: $scope.subtitleStreamIndex,
VolumeLevel: Math.round(window.volume.level * 100)
};
}
@ -96,8 +96,8 @@ export function getNextPlaybackItemInfo(): ItemIndex | null {
const item = playlist[newIndex];
return {
item: item,
index: newIndex
index: newIndex,
item: item
};
}
@ -451,17 +451,17 @@ export function createStreamInfo(
const canSeek = (mediaSource.RunTimeTicks || 0) > 0;
const info: any = {
url: mediaUrl,
mediaSource: mediaSource,
isStatic: isStatic,
contentType: contentType,
streamContainer: streamContainer,
canSeek: canSeek,
canClientSeek: isStatic || (canSeek && streamContainer == 'm3u8'),
audioStreamIndex: mediaSource.DefaultAudioStreamIndex,
subtitleStreamIndex: mediaSource.DefaultSubtitleStreamIndex,
canClientSeek: isStatic || (canSeek && streamContainer == 'm3u8'),
canSeek: canSeek,
contentType: contentType,
isStatic: isStatic,
mediaSource: mediaSource,
playerStartPositionTicks: playerStartPositionTicks,
startPositionTicks: startPosition
startPositionTicks: startPosition,
streamContainer: streamContainer,
subtitleStreamIndex: mediaSource.DefaultSubtitleStreamIndex,
url: mediaUrl
};
const subtitleStreams =
@ -546,12 +546,12 @@ export function getShuffleItems(
item: BaseItemDto
): Promise<BaseItemDtoQueryResult> {
const query: ItemQuery = {
UserId: userId,
Fields: requiredItemFields,
Limit: 50,
Filters: 'IsNotFolder',
Limit: 50,
Recursive: true,
SortBy: 'Random'
SortBy: 'Random',
UserId: userId
};
if (item.Type == 'MusicArtist') {
@ -582,9 +582,9 @@ export async function getInstantMixItems(
item: BaseItemDto
): Promise<BaseItemDtoQueryResult> {
const query: any = {
UserId: userId,
Fields: requiredItemFields,
Limit: 50
Limit: 50,
UserId: userId
};
let url: string | null = null;
@ -605,9 +605,9 @@ export async function getInstantMixItems(
if (url) {
return JellyfinApi.authAjax(url, {
dataType: 'json',
query: query,
type: 'GET',
dataType: 'json'
type: 'GET'
});
} else {
throw new Error(`InstantMix: Unknown item type: ${item.Type}`);
@ -634,8 +634,8 @@ export async function getItemsForPlayback(
const item = await JellyfinApi.authAjaxUser(
`Items/${query.Ids.split(',')[0]}`,
{
type: 'GET',
dataType: 'json'
dataType: 'json',
type: 'GET'
}
);
@ -645,9 +645,9 @@ export async function getItemsForPlayback(
};
} else {
return JellyfinApi.authAjaxUser('Items', {
dataType: 'json',
query: query,
type: 'GET',
dataType: 'json'
type: 'GET'
});
}
}
@ -670,9 +670,9 @@ export function getEpisodesForPlayback(
query.ExcludeLocationTypes = 'Virtual';
return JellyfinApi.authAjax(`Shows/${seriesId}/Episodes`, {
dataType: 'json',
query: query,
type: 'GET',
dataType: 'json'
type: 'GET'
});
}
@ -730,25 +730,25 @@ export async function translateRequestedItems(
return await getItemsForPlayback(userId, {
ArtistIds: firstItem.Id,
Filters: 'IsNotFolder',
MediaTypes: 'Audio',
Recursive: true,
SortBy: 'SortName',
MediaTypes: 'Audio'
SortBy: 'SortName'
});
} else if (firstItem.Type == 'MusicGenre') {
return await getItemsForPlayback(userId, {
Genres: firstItem.Name ?? undefined,
Filters: 'IsNotFolder',
Genres: firstItem.Name ?? undefined,
MediaTypes: 'Audio',
Recursive: true,
SortBy: 'SortName',
MediaTypes: 'Audio'
SortBy: 'SortName'
});
} else if (firstItem.IsFolder) {
return await getItemsForPlayback(userId, {
ParentId: firstItem.Id,
Filters: 'IsNotFolder',
MediaTypes: 'Audio,Video',
ParentId: firstItem.Id,
Recursive: true,
SortBy: 'SortName',
MediaTypes: 'Audio,Video'
SortBy: 'SortName'
});
} else if (smart && firstItem.Type == 'Episode' && items.length == 1) {
const user = await getUser();
@ -777,8 +777,8 @@ export async function translateRequestedItems(
userId,
episode.SeriesId,
{
IsVirtualUnaired: false,
IsMissing: false,
IsVirtualUnaired: false,
UserId: userId
}
);
@ -857,7 +857,7 @@ export function broadcastToMessageBus(message: BusMessage): void {
* Inform the cast sender that we couldn't connect
*/
export function broadcastConnectionErrorMessage(): void {
broadcastToMessageBus({ type: 'connectionerror', message: '' });
broadcastToMessageBus({ message: '', type: 'connectionerror' });
}
/**

View File

@ -1,7 +1,7 @@
module.exports = {
syntax: 'css',
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
rules: {
'at-rule-no-unknown': null
}
},
syntax: 'css'
};

View File

@ -12,22 +12,35 @@ import { version } from './package.json';
const common: webpack.Configuration = {
context: path.resolve(__dirname, 'src'),
entry: './app.ts',
module: {
rules: [
{ loader: 'html-loader', test: /\.html$/ },
{
test: /\.(png|svg|jpg|gif)$/,
use: 'file-loader'
},
{
loader: 'file-loader',
test: /\.(ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/
},
{ test: /\.css$/i, use: ['style-loader', 'css-loader'] },
{ loader: 'ts-loader', test: /\.tsx?$/ },
{ loader: 'source-map-loader', test: /\.js$/ }
]
},
output: {
filename: '[name].[fullhash].js',
path: path.resolve(__dirname, 'dist'),
publicPath: './'
},
resolve: {
extensions: ['.ts', '.js']
},
plugins: [
// @ts-expect-error - Typings mismatch between versions
new CleanWebpackPlugin(),
new HtmlWebpackPlugin({
favicon: 'favicon.ico',
filename: 'index.html',
template: 'index.html',
hash: false,
favicon: 'favicon.ico'
template: 'index.html'
}),
new ImageMinimizerPlugin({
minimizerOptions: {
@ -46,36 +59,23 @@ const common: webpack.Configuration = {
}
})
],
module: {
rules: [
{ test: /\.html$/, loader: 'html-loader' },
{
test: /\.(png|svg|jpg|gif)$/,
use: 'file-loader'
},
{
test: /\.(ttf|eot|woff(2)?)(\?[a-z0-9=&.]+)?$/,
loader: 'file-loader'
},
{ test: /\.css$/i, use: ['style-loader', 'css-loader'] },
{ test: /\.tsx?$/, loader: 'ts-loader' },
{ test: /\.js$/, loader: 'source-map-loader' }
]
resolve: {
extensions: ['.ts', '.js']
}
};
const development: webpack.Configuration = {
mode: 'development',
devtool: 'inline-source-map',
// @ts-expect-error - Typings mismatch between versions
devServer: {
contentBase: path.join(__dirname, 'dist'),
compress: true,
contentBase: path.join(__dirname, 'dist'),
port: process.env.RECEIVER_PORT
? Number.parseInt(process.env.RECEIVER_PORT, 10)
: 9000,
publicPath: '/'
},
devtool: 'inline-source-map',
mode: 'development',
plugins: [
new DefinePlugin({
PRODUCTION: JSON.stringify(false),