mirror of
https://github.com/jellyfin/jellyfin-chromecast.git
synced 2024-11-27 00:00:28 +00:00
chore: manual lint fix
This commit is contained in:
parent
a050080ca9
commit
27ff1feb93
@ -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
|
||||
|
134
.eslintrc.js
134
.eslintrc.js
@ -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']
|
||||
|
@ -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"
|
||||
|
@ -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(
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
|
||||
|
@ -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'
|
||||
});
|
||||
}
|
||||
|
@ -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 });
|
||||
|
@ -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);
|
||||
|
@ -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,
|
||||
|
@ -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' });
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,7 +1,7 @@
|
||||
module.exports = {
|
||||
syntax: 'css',
|
||||
extends: ['stylelint-config-standard', 'stylelint-config-prettier'],
|
||||
rules: {
|
||||
'at-rule-no-unknown': null
|
||||
}
|
||||
},
|
||||
syntax: 'css'
|
||||
};
|
||||
|
@ -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),
|
||||
|
Loading…
Reference in New Issue
Block a user