mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-12-19 18:29:37 +00:00
Merge 66fee7d39d into 626596b192
This commit is contained in:
commit
04790013c2
6 changed files with 110 additions and 8 deletions
|
|
@ -29,15 +29,18 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex flex-wrap">
|
||||
<div class="md:w-1/4 p-2">
|
||||
<div class="w-full md:w-1/4 p-2">
|
||||
<ui-dropdown :label="$strings.LabelPodcastType" v-model="podcast.type" :items="podcastTypes" small />
|
||||
</div>
|
||||
<div class="md:w-1/4 p-2">
|
||||
<div class="w-full md:w-1/4 p-2">
|
||||
<ui-text-input-with-label v-model="podcast.language" :label="$strings.LabelLanguage" />
|
||||
</div>
|
||||
<div class="md:w-1/4 px-2 pt-7">
|
||||
<div class="w-full md:w-1/4 px-2 pt-7">
|
||||
<ui-checkbox v-model="podcast.explicit" :label="$strings.LabelExplicit" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
||||
</div>
|
||||
<div class="w-full md:w-1/4 px-2 pt-7">
|
||||
<ui-checkbox v-model="podcast.isAuthenticatedFeed" :label="$strings.LabelAuthenticatedFeed" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-2 w-full">
|
||||
<ui-textarea-with-label v-model="podcast.description" :label="$strings.LabelDescription" :rows="3" />
|
||||
|
|
@ -96,6 +99,7 @@ export default {
|
|||
autoDownloadEpisodes: false,
|
||||
language: '',
|
||||
explicit: false,
|
||||
isAuthenticatedFeed: false,
|
||||
type: ''
|
||||
}
|
||||
}
|
||||
|
|
@ -194,6 +198,7 @@ export default {
|
|||
itunesArtistId: this.podcast.itunesArtistId,
|
||||
language: this.podcast.language,
|
||||
explicit: this.podcast.explicit,
|
||||
isAuthenticatedFeed: this.podcast.isAuthenticatedFeed,
|
||||
type: this.podcast.type
|
||||
},
|
||||
autoDownloadEpisodes: this.podcast.autoDownloadEpisodes
|
||||
|
|
@ -234,6 +239,7 @@ export default {
|
|||
this.podcast.type = this._podcastData.type || this.feedMetadata.type || 'episodic'
|
||||
|
||||
this.podcast.explicit = this._podcastData.explicit || this.feedMetadata.explicit === 'yes' || this.feedMetadata.explicit == 'true'
|
||||
this.podcast.isAuthenticatedFeed = this._podcastData.isAuthenticatedFeed || false
|
||||
if (this.folderItems[0]) {
|
||||
this.selectedFolderId = this.folderItems[0].value
|
||||
this.folderUpdated()
|
||||
|
|
|
|||
|
|
@ -34,8 +34,9 @@
|
|||
<ui-text-input-with-label ref="languageInput" v-model="details.language" :label="$strings.LabelLanguage" trim-whitespace @input="handleInputChange" />
|
||||
</div>
|
||||
<div class="grow px-1 pt-6">
|
||||
<div class="flex justify-center">
|
||||
<div class="flex justify-center space-x-4">
|
||||
<ui-checkbox v-model="details.explicit" :label="$strings.LabelExplicit" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" @input="handleInputChange" />
|
||||
<ui-checkbox v-model="details.isAuthenticatedFeed" :label="$strings.LabelAuthenticatedFeed" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" @input="handleInputChange" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -70,6 +71,7 @@ export default {
|
|||
itunesId: null,
|
||||
itunesArtistId: null,
|
||||
explicit: false,
|
||||
isAuthenticatedFeed: false,
|
||||
language: null,
|
||||
type: null
|
||||
},
|
||||
|
|
@ -241,6 +243,7 @@ export default {
|
|||
this.details.itunesArtistId = this.mediaMetadata.itunesArtistId || ''
|
||||
this.details.language = this.mediaMetadata.language || ''
|
||||
this.details.explicit = !!this.mediaMetadata.explicit
|
||||
this.details.isAuthenticatedFeed = !!this.mediaMetadata.isAuthenticatedFeed
|
||||
this.details.type = this.mediaMetadata.type || 'episodic'
|
||||
|
||||
this.newTags = [...(this.media.tags || [])]
|
||||
|
|
|
|||
|
|
@ -366,6 +366,7 @@
|
|||
"LabelExplicit": "Explicit",
|
||||
"LabelExplicitChecked": "Explicit (checked)",
|
||||
"LabelExplicitUnchecked": "Not Explicit (unchecked)",
|
||||
"LabelAuthenticatedFeed": "Authenticated Feed",
|
||||
"LabelExportOPML": "Export OPML",
|
||||
"LabelFeedURL": "Feed URL",
|
||||
"LabelFetchingMetadata": "Fetching Metadata",
|
||||
|
|
|
|||
68
server/migrations/v2.30.1-add-is-authenticated-feed.js
Normal file
68
server/migrations/v2.30.1-add-is-authenticated-feed.js
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/**
|
||||
* @typedef MigrationContext
|
||||
* @property {import('sequelize').QueryInterface} queryInterface - a suquelize QueryInterface object.
|
||||
* @property {import('../Logger')} logger - a Logger object.
|
||||
*
|
||||
* @typedef MigrationOptions
|
||||
* @property {MigrationContext} context - an object containing the migration context.
|
||||
*/
|
||||
|
||||
const migrationVersion = '2.30.1'
|
||||
const migrationName = `${migrationVersion}-add-is-authenticated-feed`
|
||||
const loggerPrefix = `[${migrationVersion} migration]`
|
||||
|
||||
/**
|
||||
* This upward migration adds the isAuthenticatedFeed column to the podcasts table.
|
||||
*
|
||||
* @param {MigrationOptions} options - an object containing the migration context.
|
||||
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
|
||||
*/
|
||||
async function up({ context: { queryInterface, logger } }) {
|
||||
// Upwards migration script
|
||||
logger.info(`${loggerPrefix} UPGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
const DataTypes = queryInterface.sequelize.Sequelize.DataTypes
|
||||
|
||||
// Check if column exists
|
||||
const tableDescription = await queryInterface.describeTable('podcasts')
|
||||
if (tableDescription.isAuthenticatedFeed) {
|
||||
logger.info(`${loggerPrefix} column "isAuthenticatedFeed" already exists in "podcasts" table`)
|
||||
} else {
|
||||
// Add column
|
||||
logger.info(`${loggerPrefix} adding column "isAuthenticatedFeed" to "podcasts" table`)
|
||||
await queryInterface.addColumn('podcasts', 'isAuthenticatedFeed', {
|
||||
type: DataTypes.BOOLEAN,
|
||||
defaultValue: false,
|
||||
allowNull: false
|
||||
})
|
||||
logger.info(`${loggerPrefix} added column "isAuthenticatedFeed" to "podcasts" table`)
|
||||
}
|
||||
|
||||
logger.info(`${loggerPrefix} UPGRADE COMPLETE: ${migrationName}`)
|
||||
}
|
||||
|
||||
/**
|
||||
* This downward migration removes the isAuthenticatedFeed column from the podcasts table.
|
||||
*
|
||||
* @param {MigrationOptions} options - an object containing the migration context.
|
||||
* @returns {Promise<void>} - A promise that resolves when the migration is complete.
|
||||
*/
|
||||
async function down({ context: { queryInterface, logger } }) {
|
||||
// Downwards migration script
|
||||
logger.info(`${loggerPrefix} DOWNGRADE BEGIN: ${migrationName}`)
|
||||
|
||||
// Check if column exists
|
||||
const tableDescription = await queryInterface.describeTable('podcasts')
|
||||
if (!tableDescription.isAuthenticatedFeed) {
|
||||
logger.info(`${loggerPrefix} column "isAuthenticatedFeed" does not exist in "podcasts" table`)
|
||||
} else {
|
||||
// Remove column
|
||||
logger.info(`${loggerPrefix} removing column "isAuthenticatedFeed" from "podcasts" table`)
|
||||
await queryInterface.removeColumn('podcasts', 'isAuthenticatedFeed')
|
||||
logger.info(`${loggerPrefix} removed column "isAuthenticatedFeed" from "podcasts" table`)
|
||||
}
|
||||
|
||||
logger.info(`${loggerPrefix} DOWNGRADE COMPLETE: ${migrationName}`)
|
||||
}
|
||||
|
||||
module.exports = { up, down }
|
||||
|
|
@ -44,6 +44,8 @@ class Podcast extends Model {
|
|||
/** @type {boolean} */
|
||||
this.explicit
|
||||
/** @type {boolean} */
|
||||
this.isAuthenticatedFeed
|
||||
/** @type {boolean} */
|
||||
this.autoDownloadEpisodes
|
||||
/** @type {string} */
|
||||
this.autoDownloadSchedule
|
||||
|
|
@ -104,6 +106,7 @@ class Podcast extends Model {
|
|||
language: typeof payload.metadata.language === 'string' ? payload.metadata.language : null,
|
||||
podcastType: typeof payload.metadata.type === 'string' ? payload.metadata.type : null,
|
||||
explicit: !!payload.metadata.explicit,
|
||||
isAuthenticatedFeed: !!payload.metadata.isAuthenticatedFeed,
|
||||
autoDownloadEpisodes: !!payload.autoDownloadEpisodes,
|
||||
autoDownloadSchedule: autoDownloadSchedule || global.ServerSettings.podcastEpisodeSchedule,
|
||||
lastEpisodeCheck: new Date(),
|
||||
|
|
@ -141,6 +144,7 @@ class Podcast extends Model {
|
|||
language: DataTypes.STRING,
|
||||
podcastType: DataTypes.STRING,
|
||||
explicit: DataTypes.BOOLEAN,
|
||||
isAuthenticatedFeed: DataTypes.BOOLEAN,
|
||||
|
||||
autoDownloadEpisodes: DataTypes.BOOLEAN,
|
||||
autoDownloadSchedule: DataTypes.STRING,
|
||||
|
|
@ -252,6 +256,11 @@ class Podcast extends Model {
|
|||
hasUpdates = true
|
||||
}
|
||||
|
||||
if (payload.metadata.isAuthenticatedFeed !== undefined && payload.metadata.isAuthenticatedFeed !== this.isAuthenticatedFeed) {
|
||||
this.isAuthenticatedFeed = !!payload.metadata.isAuthenticatedFeed
|
||||
hasUpdates = true
|
||||
}
|
||||
|
||||
if (Array.isArray(payload.metadata.genres) && !payload.metadata.genres.some((item) => typeof item !== 'string') && JSON.stringify(this.genres) !== JSON.stringify(payload.metadata.genres)) {
|
||||
this.genres = payload.metadata.genres
|
||||
this.changed('genres', true)
|
||||
|
|
@ -407,6 +416,7 @@ class Podcast extends Model {
|
|||
itunesId: this.itunesId,
|
||||
itunesArtistId: this.itunesArtistId,
|
||||
explicit: this.explicit,
|
||||
isAuthenticatedFeed: this.isAuthenticatedFeed,
|
||||
language: this.language,
|
||||
type: this.podcastType
|
||||
}
|
||||
|
|
|
|||
|
|
@ -108,19 +108,33 @@ module.exports.downloadPodcastEpisode = (podcastEpisodeDownload) => {
|
|||
// See: https://github.com/advplyr/audiobookshelf/issues/4401 (requires no iTMS user agent)
|
||||
const userAgents = ['audiobookshelf (+https://audiobookshelf.org; like iTMS)', 'audiobookshelf (+https://audiobookshelf.org)']
|
||||
|
||||
let refererHeader = null
|
||||
const feedURL = podcastEpisodeDownload.libraryItem?.media?.feedURL
|
||||
const isAuthenticatedFeed = podcastEpisodeDownload.libraryItem?.media?.isAuthenticatedFeed || false
|
||||
|
||||
if (feedURL && isAuthenticatedFeed) {
|
||||
refererHeader = feedURL
|
||||
}
|
||||
|
||||
let response = null
|
||||
let lastError = null
|
||||
|
||||
for (const userAgent of userAgents) {
|
||||
try {
|
||||
const headers = {
|
||||
Accept: '*/*',
|
||||
'User-Agent': userAgent
|
||||
}
|
||||
|
||||
if (refererHeader) {
|
||||
headers['Referer'] = refererHeader
|
||||
}
|
||||
|
||||
response = await axios({
|
||||
url: podcastEpisodeDownload.url,
|
||||
method: 'GET',
|
||||
responseType: 'stream',
|
||||
headers: {
|
||||
Accept: '*/*',
|
||||
'User-Agent': userAgent
|
||||
},
|
||||
headers,
|
||||
timeout: global.PodcastDownloadTimeout
|
||||
})
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue