mirror of
https://github.com/advplyr/audiobookshelf.git
synced 2025-01-22 00:07:52 +01:00
Fix library check path and set provider, update podcast model and UI
This commit is contained in:
parent
deadc63dbb
commit
43bbfbfee3
@ -4,7 +4,6 @@
|
|||||||
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="backArrowPress">arrow_back</span>
|
<span class="material-icons text-3xl cursor-pointer hover:text-gray-300" @click="backArrowPress">arrow_back</span>
|
||||||
<p class="px-4 text-xl">{{ title }}</p>
|
<p class="px-4 text-xl">{{ title }}</p>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="!showDirectoryPicker" class="w-full h-full py-4">
|
<div v-if="!showDirectoryPicker" class="w-full h-full py-4">
|
||||||
<div class="flex flex-wrap md:flex-nowrap -mx-1">
|
<div class="flex flex-wrap md:flex-nowrap -mx-1">
|
||||||
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
<div class="w-2/5 md:w-72 px-1 py-1 md:py-0">
|
||||||
@ -202,7 +201,6 @@ export default {
|
|||||||
mediaType: this.mediaType,
|
mediaType: this.mediaType,
|
||||||
disableWatcher: this.disableWatcher
|
disableWatcher: this.disableWatcher
|
||||||
}
|
}
|
||||||
|
|
||||||
this.$emit('update:processing', true)
|
this.$emit('update:processing', true)
|
||||||
this.$axios
|
this.$axios
|
||||||
.$post('/api/libraries', newLibraryPayload)
|
.$post('/api/libraries', newLibraryPayload)
|
||||||
|
@ -10,26 +10,29 @@
|
|||||||
<div class="w-full md:w-1/2 p-4">
|
<div class="w-full md:w-1/2 p-4">
|
||||||
<p class="text-lg font-semibold mb-2">Details</p>
|
<p class="text-lg font-semibold mb-2">Details</p>
|
||||||
<div class="flex flex-wrap">
|
<div class="flex flex-wrap">
|
||||||
<div class="p-2 w-full">
|
<div v-if="podcast.imageUrl" class="p-1 w-full">
|
||||||
|
<img :src="podcast.imageUrl" class="h-16 w-16 object-contain" />
|
||||||
|
</div>
|
||||||
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.title" label="Title" />
|
<ui-text-input-with-label v-model="podcast.title" label="Title" />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.author" label="Author" />
|
<ui-text-input-with-label v-model="podcast.author" label="Author" />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.feedUrl" label="Feed URL" />
|
<ui-text-input-with-label v-model="podcast.feedUrl" label="Feed URL" readonly />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" label="Genres" />
|
<ui-multi-select v-model="podcast.genres" :items="podcast.genres" label="Genres" />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.releaseDate" label="Release Date" />
|
<ui-textarea-with-label v-model="podcast.description" label="Description" />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.itunesPageUrl" label="Page URL" />
|
<ui-dropdown v-model="selectedFolderId" :items="folderItems" :disabled="processing" label="Folder" @input="folderUpdated" />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-1 w-full">
|
||||||
<ui-text-input-with-label v-model="podcast.feedImageUrl" label="Feed Image URL" />
|
<ui-text-input-with-label v-model="fullPath" label="Podcast Path" readonly />
|
||||||
</div>
|
</div>
|
||||||
<div class="p-2 w-full">
|
<div class="p-2 w-full">
|
||||||
<ui-checkbox v-model="podcast.autoDownloadEpisodes" label="Auto Download Episodes" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
<ui-checkbox v-model="podcast.autoDownloadEpisodes" label="Auto Download Episodes" checkbox-bg="primary" border-color="gray-600" label-class="pl-2 text-base font-semibold" />
|
||||||
@ -39,14 +42,15 @@
|
|||||||
<div class="w-full md:w-1/2 p-4">
|
<div class="w-full md:w-1/2 p-4">
|
||||||
<p class="text-lg font-semibold mb-2">Episodes</p>
|
<p class="text-lg font-semibold mb-2">Episodes</p>
|
||||||
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
<div ref="episodeContainer" id="episodes-scroll" class="w-full overflow-x-hidden overflow-y-auto">
|
||||||
<div v-for="(episode, index) in episodes" :key="index" class="relative cursor-pointer" :class="index % 2 == 0 ? 'bg-primary bg-opacity-25 hover:bg-opacity-40' : 'bg-primary bg-opacity-5 hover:bg-opacity-25'" @click="toggleSelectEpisode(index)">
|
<div v-for="(episode, index) in episodes" :key="index" class="relative cursor-pointer" :class="selectedEpisodes[String(index)] ? 'bg-success bg-opacity-10' : index % 2 == 0 ? 'bg-primary bg-opacity-25 hover:bg-opacity-40' : 'bg-primary bg-opacity-5 hover:bg-opacity-25'" @click="toggleSelectEpisode(index)">
|
||||||
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
<div class="absolute top-0 left-0 h-full flex items-center p-2">
|
||||||
<ui-checkbox v-model="selectedEpisodes[String(index)]" small checkbox-bg="primary" border-color="gray-600" />
|
<ui-checkbox v-model="selectedEpisodes[String(index)]" small checkbox-bg="primary" border-color="gray-600" />
|
||||||
</div>
|
</div>
|
||||||
<div class="px-8 py-2">
|
<div class="px-8 py-2">
|
||||||
<p v-if="episode.episode" class="font-semibold text-gray-200">#{{ episode.episode }}</p>
|
<p v-if="episode.episode" class="font-semibold text-gray-200">#{{ episode.episode }}</p>
|
||||||
<p class="break-words">{{ episode.title }}</p>
|
<p class="break-words mb-1">{{ episode.title }}</p>
|
||||||
<p class="text-xs text-gray-300">Published {{ episode.pubDate || 'Unknown' }}</p>
|
<p v-if="episode.subtitle" class="break-words mb-1 text-sm text-gray-300 episode-subtitle">{{ episode.subtitle }}</p>
|
||||||
|
<p class="text-xs text-gray-300">Published {{ episode.publishedAt ? $dateDistanceFromNow(episode.publishedAt) : 'Unknown' }}</p>
|
||||||
<!-- <span class="material-icons cursor-pointer text-lg hover:text-success" @click="saveEpisode(episode)">save</span> -->
|
<!-- <span class="material-icons cursor-pointer text-lg hover:text-success" @click="saveEpisode(episode)">save</span> -->
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -62,6 +66,8 @@
|
|||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import Path from 'path'
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
props: {
|
props: {
|
||||||
value: Boolean,
|
value: Boolean,
|
||||||
@ -77,6 +83,8 @@ export default {
|
|||||||
data() {
|
data() {
|
||||||
return {
|
return {
|
||||||
processing: false,
|
processing: false,
|
||||||
|
selectedFolderId: null,
|
||||||
|
fullPath: null,
|
||||||
podcast: {
|
podcast: {
|
||||||
title: '',
|
title: '',
|
||||||
author: '',
|
author: '',
|
||||||
@ -115,11 +123,27 @@ export default {
|
|||||||
title() {
|
title() {
|
||||||
return this._podcastData.title
|
return this._podcastData.title
|
||||||
},
|
},
|
||||||
|
currentLibrary() {
|
||||||
|
return this.$store.getters['libraries/getCurrentLibrary']
|
||||||
|
},
|
||||||
|
folders() {
|
||||||
|
if (!this.currentLibrary) return []
|
||||||
|
return this.currentLibrary.folders || []
|
||||||
|
},
|
||||||
|
folderItems() {
|
||||||
|
return this.folders.map((fold) => {
|
||||||
|
return {
|
||||||
|
value: fold.id,
|
||||||
|
text: fold.fullPath
|
||||||
|
}
|
||||||
|
})
|
||||||
|
},
|
||||||
_podcastData() {
|
_podcastData() {
|
||||||
return this.podcastData || {}
|
return this.podcastData || {}
|
||||||
},
|
},
|
||||||
feedMetadata() {
|
feedMetadata() {
|
||||||
return this._podcastData.metadata || {}
|
if (!this.podcastFeedData) return {}
|
||||||
|
return this.podcastFeedData.metadata || {}
|
||||||
},
|
},
|
||||||
episodes() {
|
episodes() {
|
||||||
if (!this.podcastFeedData) return []
|
if (!this.podcastFeedData) return []
|
||||||
@ -135,9 +159,23 @@ export default {
|
|||||||
if (!this.episodesSelected.length) return 'Add Podcast'
|
if (!this.episodesSelected.length) return 'Add Podcast'
|
||||||
if (this.episodesSelected.length == 1) return 'Add Podcast & Download 1 Episode'
|
if (this.episodesSelected.length == 1) return 'Add Podcast & Download 1 Episode'
|
||||||
return `Add Podcast & Download ${this.episodesSelected.length} Episodes`
|
return `Add Podcast & Download ${this.episodesSelected.length} Episodes`
|
||||||
|
},
|
||||||
|
selectedFolder() {
|
||||||
|
return this.folders.find((f) => f.id === this.selectedFolderId)
|
||||||
|
},
|
||||||
|
selectedFolderPath() {
|
||||||
|
if (!this.selectedFolder) return ''
|
||||||
|
return this.selectedFolder.fullPath
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
|
folderUpdated() {
|
||||||
|
if (!this.selectedFolderPath || !this.podcast.title) {
|
||||||
|
this.fullPath = ''
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.fullPath = Path.join(this.selectedFolderPath, this.podcast.title)
|
||||||
|
},
|
||||||
toggleSelectEpisode(index) {
|
toggleSelectEpisode(index) {
|
||||||
this.selectedEpisodes[String(index)] = !this.selectedEpisodes[String(index)]
|
this.selectedEpisodes[String(index)] = !this.selectedEpisodes[String(index)]
|
||||||
},
|
},
|
||||||
@ -152,15 +190,21 @@ export default {
|
|||||||
this.podcast.releaseDate = this._podcastData.releaseDate || ''
|
this.podcast.releaseDate = this._podcastData.releaseDate || ''
|
||||||
this.podcast.genres = this._podcastData.genres || []
|
this.podcast.genres = this._podcastData.genres || []
|
||||||
this.podcast.feedUrl = this._podcastData.feedUrl
|
this.podcast.feedUrl = this._podcastData.feedUrl
|
||||||
this.podcast.feedImageUrl = this._podcastData.cover || ''
|
this.podcast.imageUrl = this._podcastData.cover || ''
|
||||||
this.podcast.itunesPageUrl = this._podcastData.pageUrl || ''
|
this.podcast.itunesPageUrl = this._podcastData.pageUrl || ''
|
||||||
this.podcast.itunesId = this._podcastData.id || ''
|
this.podcast.itunesId = this._podcastData.id || ''
|
||||||
this.podcast.itunesArtistId = this._podcastData.artistId || ''
|
this.podcast.itunesArtistId = this._podcastData.artistId || ''
|
||||||
|
this.podcast.language = this._podcastData.language || ''
|
||||||
this.podcast.autoDownloadEpisodes = false
|
this.podcast.autoDownloadEpisodes = false
|
||||||
|
|
||||||
for (let i = 0; i < this.episodes.length; i++) {
|
for (let i = 0; i < this.episodes.length; i++) {
|
||||||
this.$set(this.selectedEpisodes, String(i), false)
|
this.$set(this.selectedEpisodes, String(i), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (this.folderItems[0]) {
|
||||||
|
this.selectedFolderId = this.folderItems[0].value
|
||||||
|
this.folderUpdated()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -174,4 +218,14 @@ export default {
|
|||||||
#episodes-scroll {
|
#episodes-scroll {
|
||||||
max-height: calc(80vh - 200px);
|
max-height: calc(80vh - 200px);
|
||||||
}
|
}
|
||||||
|
.episode-subtitle {
|
||||||
|
word-break: break-word;
|
||||||
|
overflow: hidden;
|
||||||
|
text-overflow: ellipsis;
|
||||||
|
display: -webkit-box;
|
||||||
|
line-height: 16px; /* fallback */
|
||||||
|
max-height: 32px; /* fallback */
|
||||||
|
-webkit-line-clamp: 2; /* number of lines to show */
|
||||||
|
-webkit-box-orient: vertical;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
@ -3,7 +3,7 @@
|
|||||||
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">
|
<p class="px-1 text-sm font-semibold" :class="disabled ? 'text-gray-400' : ''">
|
||||||
{{ label }}<em v-if="note" class="font-normal text-xs pl-2">{{ note }}</em>
|
{{ label }}<em v-if="note" class="font-normal text-xs pl-2">{{ note }}</em>
|
||||||
</p>
|
</p>
|
||||||
<ui-text-input ref="input" v-model="inputValue" :disabled="disabled" :type="type" class="w-full" />
|
<ui-text-input ref="input" v-model="inputValue" :disabled="disabled" :readonly="readonly" :type="type" class="w-full" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
@ -17,6 +17,7 @@ export default {
|
|||||||
type: String,
|
type: String,
|
||||||
default: 'text'
|
default: 'text'
|
||||||
},
|
},
|
||||||
|
readonly: Boolean,
|
||||||
disabled: Boolean
|
disabled: Boolean
|
||||||
},
|
},
|
||||||
data() {
|
data() {
|
||||||
|
@ -19,6 +19,24 @@ class LibraryController {
|
|||||||
return res.status(500).send('Invalid request')
|
return res.status(500).send('Invalid request')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate folder paths exist or can be created & resolve rel paths
|
||||||
|
// returns 400 if a folder fails to access
|
||||||
|
newLibraryPayload.folders = newLibraryPayload.folders.map(f => {
|
||||||
|
f.fullPath = Path.resolve(f.fullPath)
|
||||||
|
return f
|
||||||
|
})
|
||||||
|
for (var folder of newLibraryPayload.folders) {
|
||||||
|
var success = await fs.ensureDir(folder.fullPath).then(() => true).catch((error) => {
|
||||||
|
Logger.error(`[LibraryController] Failed to ensure folder dir "${folder.fullPath}"`, error)
|
||||||
|
return false
|
||||||
|
})
|
||||||
|
if (!success) {
|
||||||
|
return res.status(400).send(`Invalid folder directory "${folder.fullPath}"`)
|
||||||
|
} else {
|
||||||
|
await filePerms.setDefault(folder.fullPath)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var library = new Library()
|
var library = new Library()
|
||||||
newLibraryPayload.displayOrder = this.db.libraries.length + 1
|
newLibraryPayload.displayOrder = this.db.libraries.length + 1
|
||||||
library.setData(newLibraryPayload)
|
library.setData(newLibraryPayload)
|
||||||
|
@ -88,6 +88,7 @@ class Library {
|
|||||||
this.displayOrder = data.displayOrder || 1
|
this.displayOrder = data.displayOrder || 1
|
||||||
this.icon = data.icon || 'database'
|
this.icon = data.icon || 'database'
|
||||||
this.mediaType = data.mediaType || 'book'
|
this.mediaType = data.mediaType || 'book'
|
||||||
|
this.provider = data.provider || 'google'
|
||||||
this.disableWatcher = !!data.disableWatcher
|
this.disableWatcher = !!data.disableWatcher
|
||||||
this.createdAt = Date.now()
|
this.createdAt = Date.now()
|
||||||
this.lastUpdate = Date.now()
|
this.lastUpdate = Date.now()
|
||||||
|
@ -8,6 +8,11 @@ class PodcastEpisode {
|
|||||||
this.podcastId = null
|
this.podcastId = null
|
||||||
this.episodeNumber = null
|
this.episodeNumber = null
|
||||||
|
|
||||||
|
this.title = null
|
||||||
|
this.description = null
|
||||||
|
this.enclosure = null
|
||||||
|
this.pubDate = null
|
||||||
|
|
||||||
this.audioFile = null
|
this.audioFile = null
|
||||||
this.addedAt = null
|
this.addedAt = null
|
||||||
this.updatedAt = null
|
this.updatedAt = null
|
||||||
@ -22,6 +27,10 @@ class PodcastEpisode {
|
|||||||
this.index = episode.index
|
this.index = episode.index
|
||||||
this.podcastId = episode.podcastId
|
this.podcastId = episode.podcastId
|
||||||
this.episodeNumber = episode.episodeNumber
|
this.episodeNumber = episode.episodeNumber
|
||||||
|
this.title = episode.title
|
||||||
|
this.description = episode.description
|
||||||
|
this.enclosure = episode.enclosure ? { ...episode.enclosure } : null
|
||||||
|
this.pubDate = episode.pubDate
|
||||||
this.audioFile = new AudioFile(episode.audioFile)
|
this.audioFile = new AudioFile(episode.audioFile)
|
||||||
this.addedAt = episode.addedAt
|
this.addedAt = episode.addedAt
|
||||||
this.updatedAt = episode.updatedAt
|
this.updatedAt = episode.updatedAt
|
||||||
@ -33,6 +42,10 @@ class PodcastEpisode {
|
|||||||
index: this.index,
|
index: this.index,
|
||||||
podcastId: this.podcastId,
|
podcastId: this.podcastId,
|
||||||
episodeNumber: this.episodeNumber,
|
episodeNumber: this.episodeNumber,
|
||||||
|
title: this.title,
|
||||||
|
description: this.description,
|
||||||
|
enclosure: this.enclosure ? { ...this.enclosure } : null,
|
||||||
|
pubDate: this.pubDate,
|
||||||
audioFile: this.audioFile.toJSON(),
|
audioFile: this.audioFile.toJSON(),
|
||||||
addedAt: this.addedAt,
|
addedAt: this.addedAt,
|
||||||
updatedAt: this.updatedAt
|
updatedAt: this.updatedAt
|
||||||
|
@ -6,11 +6,12 @@ class PodcastMetadata {
|
|||||||
this.releaseDate = null
|
this.releaseDate = null
|
||||||
this.genres = []
|
this.genres = []
|
||||||
this.feedUrl = null
|
this.feedUrl = null
|
||||||
this.feedImageUrl = null
|
this.imageUrl = null
|
||||||
this.itunesPageUrl = null
|
this.itunesPageUrl = null
|
||||||
this.itunesId = null
|
this.itunesId = null
|
||||||
this.itunesArtistId = null
|
this.itunesArtistId = null
|
||||||
this.explicit = false
|
this.explicit = false
|
||||||
|
this.language = null
|
||||||
|
|
||||||
if (metadata) {
|
if (metadata) {
|
||||||
this.construct(metadata)
|
this.construct(metadata)
|
||||||
@ -24,11 +25,12 @@ class PodcastMetadata {
|
|||||||
this.releaseDate = metadata.releaseDate
|
this.releaseDate = metadata.releaseDate
|
||||||
this.genres = [...metadata.genres]
|
this.genres = [...metadata.genres]
|
||||||
this.feedUrl = metadata.feedUrl
|
this.feedUrl = metadata.feedUrl
|
||||||
this.feedImageUrl = metadata.feedImageUrl
|
this.imageUrl = metadata.imageUrl
|
||||||
this.itunesPageUrl = metadata.itunesPageUrl
|
this.itunesPageUrl = metadata.itunesPageUrl
|
||||||
this.itunesId = metadata.itunesId
|
this.itunesId = metadata.itunesId
|
||||||
this.itunesArtistId = metadata.itunesArtistId
|
this.itunesArtistId = metadata.itunesArtistId
|
||||||
this.explicit = metadata.explicit
|
this.explicit = metadata.explicit
|
||||||
|
this.language = metadata.language || null
|
||||||
}
|
}
|
||||||
|
|
||||||
toJSON() {
|
toJSON() {
|
||||||
@ -39,11 +41,12 @@ class PodcastMetadata {
|
|||||||
releaseDate: this.releaseDate,
|
releaseDate: this.releaseDate,
|
||||||
genres: [...this.genres],
|
genres: [...this.genres],
|
||||||
feedUrl: this.feedUrl,
|
feedUrl: this.feedUrl,
|
||||||
feedImageUrl: this.feedImageUrl,
|
imageUrl: this.imageUrl,
|
||||||
itunesPageUrl: this.itunesPageUrl,
|
itunesPageUrl: this.itunesPageUrl,
|
||||||
itunesId: this.itunesId,
|
itunesId: this.itunesId,
|
||||||
itunesArtistId: this.itunesArtistId,
|
itunesArtistId: this.itunesArtistId,
|
||||||
explicit: this.explicit
|
explicit: this.explicit,
|
||||||
|
language: this.language
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,7 +57,7 @@ function extractEpisodeData(item) {
|
|||||||
Logger.error(`[podcastUtils] Invalid podcast episode data`)
|
Logger.error(`[podcastUtils] Invalid podcast episode data`)
|
||||||
return null
|
return null
|
||||||
}
|
}
|
||||||
var arrayFields = ['title', 'pubDate', 'description', 'itunes:episodeType', 'itunes:episode', 'itunes:author', 'itunes:duration', 'itunes:explicit']
|
var arrayFields = ['title', 'pubDate', 'description', 'itunes:episodeType', 'itunes:episode', 'itunes:author', 'itunes:duration', 'itunes:explicit', 'itunes:subtitle']
|
||||||
var episode = {
|
var episode = {
|
||||||
enclosure: {
|
enclosure: {
|
||||||
...item.enclosure[0]['$']
|
...item.enclosure[0]['$']
|
||||||
@ -70,12 +70,27 @@ function extractEpisodeData(item) {
|
|||||||
return episode
|
return episode
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function cleanEpisodeData(data) {
|
||||||
|
return {
|
||||||
|
title: data.title,
|
||||||
|
subtitle: data.subtitle || '',
|
||||||
|
description: data.description || '',
|
||||||
|
pubDate: data.pubDate || '',
|
||||||
|
episodeType: data.episodeType || '',
|
||||||
|
episode: data.episode || '',
|
||||||
|
author: data.author || '',
|
||||||
|
duration: data.duration || '',
|
||||||
|
explicit: data.explicit || '',
|
||||||
|
publishedAt: (new Date(data.pubDate)).valueOf()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function extractPodcastEpisodes(items) {
|
function extractPodcastEpisodes(items) {
|
||||||
var episodes = []
|
var episodes = []
|
||||||
items.forEach((item) => {
|
items.forEach((item) => {
|
||||||
var cleaned = extractEpisodeData(item)
|
var extracted = extractEpisodeData(item)
|
||||||
if (cleaned) {
|
if (extracted) {
|
||||||
episodes.push(cleaned)
|
episodes.push(cleanEpisodeData(extracted))
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
return episodes
|
return episodes
|
||||||
|
Loading…
Reference in New Issue
Block a user