mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Merge pull request #3880 from mikiher/rich-text-book-descriptionss
Support rich text book descriptions
This commit is contained in:
		
						commit
						a4d0f95ecc
					
				| @ -52,4 +52,17 @@ | ||||
|   text-indent: 0px !important; | ||||
|   text-align: start !important; | ||||
|   text-align-last: start !important; | ||||
| } | ||||
| } | ||||
| 
 | ||||
| .default-style.less-spacing p { | ||||
|   margin-block-start: 0; | ||||
| } | ||||
| 
 | ||||
| .default-style.less-spacing ul { | ||||
|   margin-block-start: 0; | ||||
| } | ||||
| 
 | ||||
| .default-style.less-spacing ol { | ||||
|   margin-block-start: 0; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -446,7 +446,7 @@ trix-editor .attachment__metadata .attachment__size { | ||||
| } | ||||
| 
 | ||||
| .trix-content { | ||||
|   line-height: 1.5; | ||||
|   line-height: inherit; | ||||
| } | ||||
| 
 | ||||
| .trix-content * { | ||||
| @ -455,6 +455,13 @@ trix-editor .attachment__metadata .attachment__size { | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .trix-content p { | ||||
|   box-sizing: border-box; | ||||
|   margin-top: 0; | ||||
|   margin-bottom: 0.5em; | ||||
|   padding: 0; | ||||
| } | ||||
| 
 | ||||
| .trix-content h1 { | ||||
|   font-size: 1.2em; | ||||
|   line-height: 1.2; | ||||
| @ -560,4 +567,4 @@ trix-editor .attachment__metadata .attachment__size { | ||||
| .trix-content .attachment-gallery.attachment-gallery--4 .attachment { | ||||
|   flex-basis: 50%; | ||||
|   max-width: 50%; | ||||
| } | ||||
| } | ||||
|  | ||||
| @ -24,7 +24,7 @@ | ||||
|           </div> | ||||
|         </div> | ||||
|         <div class="w-full max-h-12 overflow-hidden"> | ||||
|           <p class="text-gray-500 text-xs">{{ book.description }}</p> | ||||
|           <p class="text-gray-500 text-xs">{{ book.descriptionPlain }}</p> | ||||
|         </div> | ||||
|       </div> | ||||
|       <div v-else class="px-4 flex-grow"> | ||||
|  | ||||
| @ -94,9 +94,9 @@ | ||||
|         <div v-if="selectedMatchOrig.description" class="flex items-center py-2"> | ||||
|           <ui-checkbox v-model="selectedMatchUsage.description" checkbox-bg="bg" @input="checkboxToggled" /> | ||||
|           <div class="flex-grow ml-4"> | ||||
|             <ui-textarea-with-label v-model="selectedMatch.description" :rows="3" :disabled="!selectedMatchUsage.description" :label="$strings.LabelDescription" /> | ||||
|             <ui-rich-text-editor v-model="selectedMatch.description" :disabled="!selectedMatchUsage.description" :label="$strings.LabelDescription" /> | ||||
|             <p v-if="mediaMetadata.description" class="text-xs ml-1 text-white text-opacity-60"> | ||||
|               {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('description', mediaMetadata.description)">{{ mediaMetadata.description.substr(0, 100) + (mediaMetadata.description.length > 100 ? '...' : '') }}</a> | ||||
|               {{ $strings.LabelCurrently }} <a title="$strings.LabelClickToUseCurrentValue" class="cursor-pointer hover:underline" @click.stop="setMatchFieldValue('description', mediaMetadata.description)">{{ mediaMetadata.descriptionPlain.substr(0, 100) + (mediaMetadata.descriptionPlain.length > 100 ? '...' : '') }}</a> | ||||
|             </p> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
| @ -16,7 +16,7 @@ | ||||
|         </div> | ||||
|       </div> | ||||
|       <p dir="auto" class="text-lg font-semibold mb-6">{{ title }}</p> | ||||
|       <div v-if="description" dir="auto" class="default-style" v-html="description" /> | ||||
|       <div v-if="description" dir="auto" class="default-style less-spacing" v-html="description" /> | ||||
|       <p v-else class="mb-2">{{ $strings.MessageNoDescription }}</p> | ||||
| 
 | ||||
|       <div class="w-full h-px bg-white/5 my-4" /> | ||||
|  | ||||
| @ -1,9 +1,9 @@ | ||||
| <template> | ||||
|   <div class="default-style"> | ||||
|     <p v-if="label" class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': disabled }"> | ||||
|     <p v-if="label" class="px-1 text-sm font-semibold" :class="{ 'text-gray-400': disabled }" style="margin-top: 0; margin-bottom: 0.125em"> | ||||
|       {{ label }} | ||||
|     </p> | ||||
|     <ui-vue-trix v-model="content" :config="config" :disabled-editor="disabled" @trix-file-accept="trixFileAccept" /> | ||||
|     <ui-vue-trix ref="input" v-model="content" :disabled-editor="disabled" @trix-file-accept="trixFileAccept" /> | ||||
|   </div> | ||||
| </template> | ||||
| 
 | ||||
| @ -12,7 +12,10 @@ export default { | ||||
|   props: { | ||||
|     value: String, | ||||
|     label: String, | ||||
|     disabled: Boolean | ||||
|     disabled: { | ||||
|       type: Boolean, | ||||
|       default: false | ||||
|     } | ||||
|   }, | ||||
|   data() { | ||||
|     return {} | ||||
| @ -25,49 +28,19 @@ export default { | ||||
|       set(val) { | ||||
|         this.$emit('input', val) | ||||
|       } | ||||
|     }, | ||||
|     config() { | ||||
|       return { | ||||
|         toolbar: { | ||||
|           getDefaultHTML: () => `<div class="trix-button-row"> | ||||
|       <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools"> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" title="${this.$strings.LabelFontBold}" tabindex="-1">${this.$strings.LabelFontBold}</button> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" title="${this.$strings.LabelFontItalic}" tabindex="-1">${this.$strings.LabelFontItalic}</button> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" title="${this.$strings.LabelFontStrikethrough}" tabindex="-1">${this.$strings.LabelFontStrikethrough}</button> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" title="${this.$strings.LabelTextEditorLink}" tabindex="-1">${this.$strings.LabelTextEditorLink}</button> | ||||
|       </span> | ||||
|       <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools"> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" title="${this.$strings.LabelTextEditorBulletedList}" tabindex="-1">${this.$strings.LabelTextEditorBulletedList}</button> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" title="${this.$strings.LabelTextEditorNumberedList}" tabindex="-1">${this.$strings.LabelTextEditorNumberedList}</button> | ||||
|       </span> | ||||
| 
 | ||||
|       <span class="trix-button-group-spacer"></span> | ||||
|       <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools"> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" title="${this.$strings.LabelUndo}" tabindex="-1">${this.$strings.LabelUndo}</button> | ||||
|         <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" title="${this.$strings.LabelRedo}" tabindex="-1">${this.$strings.LabelRedo}</button> | ||||
|       </span> | ||||
|     </div> | ||||
|     <div class="trix-dialogs" data-trix-dialogs> | ||||
|       <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href"> | ||||
|         <div class="trix-dialog__link-fields"> | ||||
|           <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="" aria-label="URL" required data-trix-input> | ||||
|           <div class="trix-button-group"> | ||||
|             <input type="button" class="trix-button trix-button--dialog" value="${this.$strings.LabelTextEditorLink}" data-trix-method="setAttribute"> | ||||
|             <input type="button" class="trix-button trix-button--dialog" value="${this.$strings.LabelTextEditorUnlink}" data-trix-method="removeAttribute"> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </div>` | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   methods: { | ||||
|     trixFileAccept(e) { | ||||
|       e.preventDefault() | ||||
|     }, | ||||
|     blur() { | ||||
|       if (this.$refs.input && this.$refs.input.blur) { | ||||
|         this.$refs.input.blur() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   mounted() {}, | ||||
|   beforeDestroy() {} | ||||
| } | ||||
| </script> | ||||
| </script> | ||||
|  | ||||
| @ -1,6 +1,37 @@ | ||||
| <template> | ||||
|   <div> | ||||
|     <trix-editor :contenteditable="!disabledEditor" :class="['trix-content']" ref="trix" :input="computedId" :placeholder="placeholder" @trix-change="handleContentChange" @trix-initialize="handleInitialize" @trix-focus="processTrixFocus" @trix-blur="processTrixBlur" /> | ||||
|     <trix-toolbar :id="toolbarId"> | ||||
|       <div v-show="!disabledEditor" class="trix-button-row"> | ||||
|         <span class="trix-button-group trix-button-group--text-tools" data-trix-button-group="text-tools"> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-bold" data-trix-attribute="bold" data-trix-key="b" :title="$strings.LabelFontBold" tabindex="-1">{{ $strings.LabelFontBold }}</button> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-italic" data-trix-attribute="italic" data-trix-key="i" :title="$strings.LabelFontItalic" tabindex="-1">{{ $strings.LabelFontItalic }}</button> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-strike" data-trix-attribute="strike" :title="$strings.LabelFontStrikethrough" tabindex="-1">{{ $strings.LabelFontStrikethrough }}</button> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-link" data-trix-attribute="href" data-trix-action="link" data-trix-key="k" :title="$strings.LabelTextEditorLink" tabindex="-1">{{ $strings.LabelTextEditorLink }}</button> | ||||
|         </span> | ||||
|         <span class="trix-button-group trix-button-group--block-tools" data-trix-button-group="block-tools"> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-bullet-list" data-trix-attribute="bullet" :title="$strings.LabelTextEditorBulletedList" tabindex="-1">{{ $strings.LabelTextEditorBulletedList }}</button> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-number-list" data-trix-attribute="number" :title="$strings.LabelTextEditorNumberedList" tabindex="-1">{{ $strings.LabelTextEditorNumberedList }}</button> | ||||
|         </span> | ||||
| 
 | ||||
|         <span class="trix-button-group-spacer"></span> | ||||
|         <span class="trix-button-group trix-button-group--history-tools" data-trix-button-group="history-tools"> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-undo" data-trix-action="undo" data-trix-key="z" :title="$strings.LabelUndo" tabindex="-1">{{ $strings.LabelUndo }}</button> | ||||
|           <button type="button" class="trix-button trix-button--icon trix-button--icon-redo" data-trix-action="redo" data-trix-key="shift+z" :title="$strings.LabelRedo" tabindex="-1">{{ $strings.LabelRedo }}</button> | ||||
|         </span> | ||||
|       </div> | ||||
|       <div class="trix-dialogs" data-trix-dialogs> | ||||
|         <div class="trix-dialog trix-dialog--link" data-trix-dialog="href" data-trix-dialog-attribute="href"> | ||||
|           <div class="trix-dialog__link-fields"> | ||||
|             <input type="url" name="href" class="trix-input trix-input--dialog" placeholder="" aria-label="URL" required data-trix-input /> | ||||
|             <div class="trix-button-group"> | ||||
|               <input type="button" class="trix-button trix-button--dialog" :value="$strings.LabelTextEditorLink" data-trix-method="setAttribute" /> | ||||
|               <input type="button" class="trix-button trix-button--dialog" :value="$strings.LabelTextEditorUnlink" data-trix-method="removeAttribute" /> | ||||
|             </div> | ||||
|           </div> | ||||
|         </div> | ||||
|       </div> | ||||
|     </trix-toolbar> | ||||
|     <trix-editor :toolbar="toolbarId" :contenteditable="!disabledEditor" :class="['trix-content']" ref="trix" :input="computedId" :placeholder="placeholder" @trix-change="handleContentChange" @trix-initialize="handleInitialize" @trix-focus="processTrixFocus" @trix-blur="processTrixBlur" /> | ||||
|     <input type="hidden" :name="inputName" :id="computedId" :value="editorContent" /> | ||||
|   </div> | ||||
| </template> | ||||
| @ -14,6 +45,30 @@ | ||||
| import Trix from 'trix' | ||||
| import '@/assets/trix.css' | ||||
| 
 | ||||
| function enableBreakParagraphOnReturn() { | ||||
|   // Trix works with divs by default, we want paragraphs instead | ||||
|   Trix.config.blockAttributes.default.tagName = 'p' | ||||
|   // Enable break paragraph on Enter (Shift + Enter will still create a line break) | ||||
|   Trix.config.blockAttributes.default.breakOnReturn = true | ||||
| 
 | ||||
|   // Hack to fix buggy paragraph breaks | ||||
|   // Copied from https://github.com/basecamp/trix/issues/680#issuecomment-735742942 | ||||
|   Trix.Block.prototype.breaksOnReturn = function () { | ||||
|     const attr = this.getLastAttribute() | ||||
|     const config = Trix.getBlockConfig(attr ? attr : 'default') | ||||
|     return config ? config.breakOnReturn : false | ||||
|   } | ||||
|   Trix.LineBreakInsertion.prototype.shouldInsertBlockBreak = function () { | ||||
|     if (this.block.hasAttributes() && this.block.isListItem() && !this.block.isEmpty()) { | ||||
|       return this.startLocation.offset > 0 | ||||
|     } else { | ||||
|       return !this.shouldBreakFormattedBlock() ? this.breaksOnReturn : false | ||||
|     } | ||||
|   } | ||||
| } | ||||
| 
 | ||||
| enableBreakParagraphOnReturn() | ||||
| 
 | ||||
| export default { | ||||
|   name: 'vue-trix', | ||||
|   model: { | ||||
| @ -134,6 +189,9 @@ export default { | ||||
|      * Compute a random id of hidden input | ||||
|      * when it haven't been specified. | ||||
|      */ | ||||
|     toolbarId() { | ||||
|       return `trix-toolbar-${this.generateId}` | ||||
|     }, | ||||
|     generateId() { | ||||
|       return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, (c) => { | ||||
|         var r = (Math.random() * 16) | 0 | ||||
| @ -223,13 +281,17 @@ export default { | ||||
|     decorateDisabledEditor(editorState) { | ||||
|       /** Disable toolbar and editor by pointer events styling */ | ||||
|       if (editorState) { | ||||
|         this.$refs.trix.toolbarElement.style['pointer-events'] = 'none' | ||||
|         this.$refs.trix.disabled = true | ||||
|         this.$refs.trix.contentEditable = false | ||||
|         this.$refs.trix.style['background'] = '#e9ecef' | ||||
|         this.$refs.trix.style['pointer-events'] = 'none' | ||||
|         this.$refs.trix.style['background-color'] = '#444' | ||||
|         this.$refs.trix.style['color'] = '#bbb' | ||||
|       } else { | ||||
|         this.$refs.trix.toolbarElement.style['pointer-events'] = 'unset' | ||||
|         this.$refs.trix.disabled = false | ||||
|         this.$refs.trix.contentEditable = true | ||||
|         this.$refs.trix.style['pointer-events'] = 'unset' | ||||
|         this.$refs.trix.style['background'] = 'transparent' | ||||
|         this.$refs.trix.style['background-color'] = '' | ||||
|         this.$refs.trix.style['color'] = '' | ||||
|       } | ||||
|     }, | ||||
|     overrideConfig(config) { | ||||
| @ -250,32 +312,15 @@ export default { | ||||
|       } | ||||
|       return target | ||||
|     }, | ||||
|     enableBreakParagraphOnReturn() { | ||||
|       // Trix works with divs by default, we want paragraphs instead | ||||
|       Trix.config.blockAttributes.default.tagName = 'p' | ||||
|       // Enable break paragraph on Enter (Shift + Enter will still create a line break) | ||||
|       Trix.config.blockAttributes.default.breakOnReturn = true | ||||
| 
 | ||||
|       // Hack to fix buggy paragraph breaks | ||||
|       // Copied from https://github.com/basecamp/trix/issues/680#issuecomment-735742942 | ||||
|       Trix.Block.prototype.breaksOnReturn = function () { | ||||
|         const attr = this.getLastAttribute() | ||||
|         const config = Trix.getBlockConfig(attr ? attr : 'default') | ||||
|         return config ? config.breakOnReturn : false | ||||
|       } | ||||
|       Trix.LineBreakInsertion.prototype.shouldInsertBlockBreak = function () { | ||||
|         if (this.block.hasAttributes() && this.block.isListItem() && !this.block.isEmpty()) { | ||||
|           return this.startLocation.offset > 0 | ||||
|         } else { | ||||
|           return !this.shouldBreakFormattedBlock() ? this.breaksOnReturn : false | ||||
|         } | ||||
|     blur() { | ||||
|       if (this.$refs.trix && this.$refs.trix.blur) { | ||||
|         this.$refs.trix.blur() | ||||
|       } | ||||
|     } | ||||
|   }, | ||||
|   mounted() { | ||||
|     /** Override editor configuration */ | ||||
|     this.overrideConfig(this.config) | ||||
|     this.enableBreakParagraphOnReturn() | ||||
|     /** Check if editor read-only mode is required */ | ||||
|     this.decorateDisabledEditor(this.disabledEditor) | ||||
|     this.$nextTick(() => { | ||||
| @ -305,4 +350,12 @@ export default { | ||||
| .trix_container .trix-content { | ||||
|   background-color: white; | ||||
| } | ||||
| trix-editor { | ||||
|   max-height: calc(4 * 1lh); | ||||
|   overflow-y: auto; | ||||
| } | ||||
| 
 | ||||
| trix-editor * { | ||||
|   pointer-events: inherit; | ||||
| } | ||||
| </style> | ||||
|  | ||||
| @ -26,7 +26,7 @@ | ||||
|         </div> | ||||
|       </div> | ||||
| 
 | ||||
|       <ui-textarea-with-label ref="descriptionInput" v-model="details.description" :rows="3" :label="$strings.LabelDescription" class="mt-2" @input="handleInputChange" /> | ||||
|       <ui-rich-text-editor ref="descriptionInput" v-model="details.description" :label="$strings.LabelDescription" class="mt-2" @input="handleInputChange" /> | ||||
| 
 | ||||
|       <div class="flex flex-wrap mt-2 -mx-1"> | ||||
|         <div class="w-full md:w-1/2 px-1"> | ||||
|  | ||||
| @ -123,7 +123,7 @@ | ||||
|           </div> | ||||
| 
 | ||||
|           <div class="my-4 w-full"> | ||||
|             <p ref="description" id="item-description" dir="auto" class="text-base text-gray-100 whitespace-pre-line mb-1" :class="{ 'show-full': showFullDescription }">{{ description }}</p> | ||||
|             <p ref="description" id="item-description" dir="auto" class="default-style less-spacing text-base text-gray-100 whitespace-pre-line mb-1" :class="{ 'show-full': showFullDescription }" v-html="description" /> | ||||
|             <button v-if="isDescriptionClamped" class="py-0.5 flex items-center text-slate-300 hover:text-white" @click="showFullDescription = !showFullDescription">{{ showFullDescription ? $strings.ButtonReadLess : $strings.ButtonReadMore }} <span class="material-symbols text-xl pl-1" v-html="showFullDescription ? 'expand_less' : ''" /></button> | ||||
|           </div> | ||||
| 
 | ||||
| @ -804,8 +804,7 @@ export default { | ||||
|   display: -webkit-box; | ||||
|   -webkit-box-orient: vertical; | ||||
|   -webkit-line-clamp: 4; | ||||
|   max-height: 6.25rem; | ||||
|   transition: all 0.3s ease-in-out; | ||||
|   max-height: calc(6 * 1lh); | ||||
| } | ||||
| #item-description.show-full { | ||||
|   -webkit-line-clamp: unset; | ||||
|  | ||||
| @ -8,6 +8,7 @@ const AudiobookCovers = require('../providers/AudiobookCovers') | ||||
| const CustomProviderAdapter = require('../providers/CustomProviderAdapter') | ||||
| const Logger = require('../Logger') | ||||
| const { levenshteinDistance, escapeRegExp } = require('../utils/index') | ||||
| const htmlSanitizer = require('../utils/htmlSanitizer') | ||||
| 
 | ||||
| class BookFinder { | ||||
|   #providerResponseTimeout = 30000 | ||||
| @ -463,6 +464,12 @@ class BookFinder { | ||||
|     } else { | ||||
|       books = await this.getGoogleBooksResults(title, author) | ||||
|     } | ||||
|     books.forEach((book) => { | ||||
|       if (book.description) { | ||||
|         book.description = htmlSanitizer.sanitize(book.description) | ||||
|         book.descriptionPlain = htmlSanitizer.stripAllTags(book.description) | ||||
|       } | ||||
|     }) | ||||
|     return books | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -2,6 +2,7 @@ const { DataTypes, Model } = require('sequelize') | ||||
| const Logger = require('../Logger') | ||||
| const { getTitlePrefixAtEnd, getTitleIgnorePrefix } = require('../utils') | ||||
| const parseNameString = require('../utils/parsers/parseNameString') | ||||
| const htmlSanitizer = require('../utils/htmlSanitizer') | ||||
| 
 | ||||
| /** | ||||
|  * @typedef EBookFileObject | ||||
| @ -579,6 +580,7 @@ class Book extends Model { | ||||
|     oldMetadataJSON.authorNameLF = this.authorNameLF | ||||
|     oldMetadataJSON.narratorName = (this.narrators || []).join(', ') | ||||
|     oldMetadataJSON.seriesName = this.seriesName | ||||
|     oldMetadataJSON.descriptionPlain = this.description ? htmlSanitizer.stripAllTags(this.description) : null | ||||
|     return oldMetadataJSON | ||||
|   } | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,4 @@ | ||||
| const axios = require('axios').default | ||||
| const htmlSanitizer = require('../utils/htmlSanitizer') | ||||
| const Logger = require('../Logger') | ||||
| const { isValidASIN } = require('../utils/index') | ||||
| 
 | ||||
| @ -68,7 +67,7 @@ class Audible { | ||||
|       narrator: narrators ? narrators.map(({ name }) => name).join(', ') : null, | ||||
|       publisher: publisherName, | ||||
|       publishedYear: releaseDate ? releaseDate.split('-')[0] : null, | ||||
|       description: summary ? htmlSanitizer.stripAllTags(summary) : null, | ||||
|       description: summary || null, | ||||
|       cover: image, | ||||
|       asin, | ||||
|       genres: genresFiltered.length ? genresFiltered : null, | ||||
|  | ||||
| @ -112,7 +112,7 @@ class iTunes { | ||||
|       artistId: data.artistId, | ||||
|       title: data.collectionName, | ||||
|       author, | ||||
|       description: htmlSanitizer.stripAllTags(data.description || ''), | ||||
|       description: data.description || null, | ||||
|       publishedYear: data.releaseDate ? data.releaseDate.split('-')[0] : null, | ||||
|       genres: data.primaryGenreName ? [data.primaryGenreName] : null, | ||||
|       cover: this.getCoverArtwork(data) | ||||
|  | ||||
| @ -1,11 +1,9 @@ | ||||
| const sanitizeHtml = require('../libs/sanitizeHtml') | ||||
| const { entities } = require("./htmlEntities"); | ||||
| const { entities } = require('./htmlEntities') | ||||
| 
 | ||||
| function sanitize(html) { | ||||
|   const sanitizerOptions = { | ||||
|     allowedTags: [ | ||||
|       'p', 'ol', 'ul', 'li', 'a', 'strong', 'em', 'del', 'br' | ||||
|     ], | ||||
|     allowedTags: ['p', 'ol', 'ul', 'li', 'a', 'strong', 'em', 'del', 'br', 'b', 'i'], | ||||
|     disallowedTagsMode: 'discard', | ||||
|     allowedAttributes: { | ||||
|       a: ['href', 'name', 'target'] | ||||
| @ -34,6 +32,6 @@ function decodeHTMLEntities(strToDecode) { | ||||
|     if (entity in entities) { | ||||
|       return entities[entity] | ||||
|     } | ||||
|     return entity; | ||||
|     return entity | ||||
|   }) | ||||
| } | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user