mirror of
				https://github.com/advplyr/audiobookshelf.git
				synced 2025-10-27 11:18:14 +01:00 
			
		
		
		
	Allow any utf-8 char in genre and tags, fix stream manager user undefined
This commit is contained in:
		
							parent
							
								
									d2a2f3ff6a
								
							
						
					
					
						commit
						e534d015be
					
				| @ -121,7 +121,6 @@ export default { | ||||
|       return _sel.text | ||||
|     }, | ||||
|     genres() { | ||||
|       // return this.$store.state.audiobooks.genres | ||||
|       return this.$store.getters['audiobooks/getGenresUsed'] | ||||
|     }, | ||||
|     tags() { | ||||
|  | ||||
| @ -75,7 +75,6 @@ export default { | ||||
|       } | ||||
| 
 | ||||
|       return this.items.filter((i) => { | ||||
|         // var normie = this.$snakeToNormal(i) | ||||
|         var iValue = String(i).toLowerCase() | ||||
|         return iValue.includes(this.currentSearch.toLowerCase()) | ||||
|       }) | ||||
| @ -170,7 +169,6 @@ export default { | ||||
|       }) | ||||
|     }, | ||||
|     insertNewItem(item) { | ||||
|       // var kebabItem = this.$normalToSnake(item) | ||||
|       this.selected.push(item) | ||||
|       this.$emit('input', this.selected) | ||||
|       this.textInput = null | ||||
| @ -183,7 +181,6 @@ export default { | ||||
|       if (!this.textInput) return | ||||
| 
 | ||||
|       var cleaned = this.textInput.toLowerCase().trim() | ||||
|       // var cleanedKebab = this.$normalToSnake(cleaned) | ||||
|       var matchesItem = this.items.find((i) => { | ||||
|         return i === cleaned | ||||
|       }) | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "audiobookshelf-client", | ||||
|   "version": "1.0.3", | ||||
|   "version": "1.0.4", | ||||
|   "description": "Audiobook manager and player", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|  | ||||
| @ -38,105 +38,13 @@ Vue.prototype.$secondsToTimestamp = (seconds) => { | ||||
|   return `${_hours}:${_minutes.toString().padStart(2, '0')}:${_seconds.toString().padStart(2, '0')}` | ||||
| } | ||||
| 
 | ||||
| Vue.prototype.$snakeToNormal = (snake) => { | ||||
|   if (!snake) { | ||||
|     return '' | ||||
|   } | ||||
|   return String(snake) | ||||
|     .split('_') | ||||
|     .map((t) => t.slice(0, 1).toUpperCase() + t.slice(1)) | ||||
|     .join(' ') | ||||
| } | ||||
| 
 | ||||
| Vue.prototype.$normalToSnake = (normie) => { | ||||
|   if (!normie) return '' | ||||
|   return normie | ||||
|     .trim() | ||||
|     .split(' ') | ||||
|     .map((t) => t.toLowerCase()) | ||||
|     .join('_') | ||||
| } | ||||
| 
 | ||||
| const encode = (text) => encodeURIComponent(Buffer.from(text).toString('base64')) | ||||
| Vue.prototype.$encode = encode | ||||
| const decode = (text) => Buffer.from(decodeURIComponent(text), 'base64').toString() | ||||
| Vue.prototype.$decode = decode | ||||
| 
 | ||||
| const availableChars = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" | ||||
| const getCharCode = (char) => availableChars.indexOf(char) | ||||
| const getCharFromCode = (code) => availableChars[Number(code)] || -1 | ||||
| const cleanChar = (char) => getCharCode(char) < 0 ? '?' : char | ||||
| 
 | ||||
| Vue.prototype.$cleanString = (str) => { | ||||
|   if (!str) return '' | ||||
| 
 | ||||
|   // No longer necessary to replace accented chars, full utf-8 charset is supported
 | ||||
|   // replace accented characters: https://stackoverflow.com/a/49901740/7431543
 | ||||
|   str = str.normalize('NFD').replace(/[\u0300-\u036f]/g, "") | ||||
| 
 | ||||
|   var cleaned = '' | ||||
|   for (let i = 0; i < str.length; i++) { | ||||
|     cleaned += cleanChar(str[i]) | ||||
|   } | ||||
|   return cleaned | ||||
| } | ||||
| 
 | ||||
| Vue.prototype.$stringToCode = (str) => { | ||||
|   if (!str) return '' | ||||
|   var numcode = [...str].map(s => { | ||||
|     return String(getCharCode(s)).padStart(2, '0') | ||||
|   }).join('') | ||||
|   return BigInt(numcode).toString(36) | ||||
| } | ||||
| 
 | ||||
| Vue.prototype.$codeToString = (code) => { | ||||
|   if (!code) return '' | ||||
|   var numcode = '' | ||||
|   try { | ||||
|     numcode = [...code].reduce((acc, curr) => { | ||||
|       return BigInt(parseInt(curr, 36)) + BigInt(36) * acc | ||||
|     }, 0n) | ||||
|   } catch (err) { | ||||
|     console.error('numcode fialed', code, err) | ||||
|   } | ||||
|   var numcodestr = String(numcode) | ||||
| 
 | ||||
|   var remainder = numcodestr.length % 2 | ||||
|   numcodestr = numcodestr.padStart(numcodestr.length - 1 + remainder, '0') | ||||
| 
 | ||||
|   var finalform = '' | ||||
|   var numChunks = Math.floor(numcodestr.length / 2) | ||||
|   var remaining = numcodestr | ||||
|   for (let i = 0; i < numChunks; i++) { | ||||
|     var chunk = remaining.slice(0, 2) | ||||
|     remaining = remaining.slice(2) | ||||
|     finalform += getCharFromCode(chunk) | ||||
|   } | ||||
|   return finalform | ||||
| } | ||||
| 
 | ||||
| function loadImageBlob(uri) { | ||||
|   return new Promise((resolve) => { | ||||
|     const img = document.createElement('img') | ||||
|     const c = document.createElement('canvas') | ||||
|     const ctx = c.getContext('2d') | ||||
|     img.onload = ({ target }) => { | ||||
|       c.width = target.naturalWidth | ||||
|       c.height = target.naturalHeight | ||||
|       ctx.drawImage(target, 0, 0) | ||||
|       c.toBlob((b) => resolve(b), 'image/jpeg', 0.75) | ||||
|     } | ||||
|     img.crossOrigin = '' | ||||
|     img.src = uri | ||||
|   }) | ||||
| } | ||||
| 
 | ||||
| Vue.prototype.$downloadImage = async (uri, name) => { | ||||
|   var blob = await loadImageBlob(uri) | ||||
|   const a = document.createElement('a') | ||||
|   a.href = URL.createObjectURL(blob) | ||||
|   a.target = '_blank' | ||||
|   a.download = name || 'fotosho-image' | ||||
|   a.click() | ||||
|   // str = str.normalize('NFD').replace(/[\u0300-\u036f]/g, "")
 | ||||
|   return str.trim() | ||||
| } | ||||
| 
 | ||||
| function isClickedOutsideEl(clickEvent, elToCheckOutside, ignoreSelectors = [], ignoreElems = []) { | ||||
| @ -195,6 +103,11 @@ Vue.prototype.$sanitizeFilename = (input, replacement = '') => { | ||||
|   return sanitized | ||||
| } | ||||
| 
 | ||||
| const encode = (text) => encodeURIComponent(Buffer.from(text).toString('base64')) | ||||
| Vue.prototype.$encode = encode | ||||
| const decode = (text) => Buffer.from(decodeURIComponent(text), 'base64').toString() | ||||
| Vue.prototype.$decode = decode | ||||
| 
 | ||||
| export { | ||||
|   encode, | ||||
|   decode | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
|   "name": "audiobookshelf", | ||||
|   "version": "1.0.3", | ||||
|   "version": "1.0.4", | ||||
|   "description": "Self-hosted audiobook server for managing and playing audiobooks.", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|  | ||||
| @ -122,7 +122,7 @@ class StreamManager { | ||||
|   streamUpdate(socket, { currentTime, streamId }) { | ||||
|     var client = socket.sheepClient | ||||
|     if (!client || !client.stream) { | ||||
|       Logger.error('No stream for client', client.user.id) | ||||
|       Logger.error('No stream for client', (client && client.user) ? client.user.id : 'No Client') | ||||
|       return | ||||
|     } | ||||
|     if (client.stream.id !== streamId) { | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user