kompisn90 / Livejasmin, Add button for saving chatlog

// ==UserScript==
// @name            Livejasmin, Add button for saving chatlog
// @description     Adds a button to the top left of the page that, when pressed, alerts the current contents of the chat window.
// @version         2
// @license         MIT
// @copyright       2018, kompisn90 (https://openuserjs.org/users/kompisn90)
// @include         https://*.livejasmin.com/*
// @include         https://*.jasmin.com/*
// @include         https://livejasmin.com/*
// @include         https://jasmin.com/*
// @exclude         https://www.livejasmin.com/en/member/favourite/get-favourite-list
// @require         https://cdn.jsdelivr.net/npm/vue/dist/vue.js
// @grant           GM.setValue
// @grant           GM.getValue
// ==/UserScript==

const getModelName = url => {
  let splits = [
    'html5/',
    'chat/'
  ]
  return url.split(splits.find(split => url.indexOf(split) > -1))[1]
}

const main = async () => {
  let modelName = getModelName(window.location.href)
  
  if (!modelName) {
    return
  }
  
  if (!models.includes(modelName)) {
    models.push(modelName)
    GM.setValue('models', JSON.stringify(models))
  }
  
  let storedLog = await GM.getValue(modelName, '')
  
  storedLog = storedLog.split('\n')
    
  let newLog = getNewLog();

  let completeLog = concatenate(storedLog, newLog, 5)
  
  console.log(completeLog)

  return await storeLog(modelName, completeLog)
}

const getNewLog = () => {
  return Array.from(document.querySelectorAll('ul.chat_flow li')).map(m => m.textContent.trim())
}

const storeLog = async (model, log) => {
  return await GM.setValue(model, log.join('\n'))
}

const concatenate = (arr1, arr2) => {
    if (arr2.filter(line => line === arr1[arr1.length - 1]).length > 0) {
        arr2.reverse()
        let arr2index = arr2.length - arr2.findIndex(line => line === arr1[arr1.length - 1])
        arr2.reverse()

        let perfectMatch = true
        let appendIndex = arr1.length
        for (let i = 1; i <= arr1.length; i++) {
            if (arr1[arr1.length - i] === arr2[arr2index - i] && perfectMatch) {
                appendIndex = arr1.length - i
            } else {
                perfectMatch = false
            }
        }
        return arr1.slice(0, appendIndex).concat(arr2)
    }
    return arr1.concat(arr2)
}

var settingsCounterTimeout = 0
const whenSettings = cb => {
	let settings = document.querySelector('#ext-gen33')
  if (!settings && settingsCounterTimeout < 100) {
    settingsCounterTimeout++
    setTimeout(() => whenSettings(cb), 100)
  } else {
    cb()
  }
}

const render = arr => {
	return '<pre>' + arr.join('\n') + '</pre>'
}

const getChatlog = async () => {
	let models = await GM.getValue('models', '[]')
  return JSON.parse(models)
}

const style = /*html*/`
<style scoped>
#close {
    position: fixed;
    top: 0;
    right: 0;
    z-index: 99999;
}
.models {
    margin: 2em auto;
    text-align: center
}
.chat {
    width: 30vw;
    margin: 5em auto;
    color: rgb(123, 131, 141);
    padding: 2em;
    background-color: rgba(0, 0, 0, 0.8);
}

.chat li {
    margin-bottom: 5px;
}

.chat .model {
    color: #fc0;
}

.chat .user {
    color: white;
}

.chat .introduction {
    margin-top: 10px;
    border-top: 2px solid white;
    padding-top: 10px;
}
</style>
`

const template = /*html*/`
	<ul v-if="log.length === 0" class="models">
        <input v-model="search">
		<li v-for="model in models" :key="model" :key="model">
			<a href="javascript:void(0)" @click="showlog(model)">
				{{ model }}
			</a>
		</li>
	</ul>
    <ul v-else class="chat">
        <li v-for="(message, index) in log"
            :key="index"
            :class="{
                'model': message.toLowerCase().indexOf(selectedModel.toLowerCase()) === 0,
                'user': message.indexOf(user) === 0,
                'introduction': message.indexOf('Hi ') === 0,
            }">
                {{ message }}
            </li>
    </ul>
    <button id="close" @click="close">X</button>
`

var app

const showChatlog = async () => {
  const appWrapper = document.createElement('div')
  appWrapper.innerHTML = style
  
  const appEl = document.createElement('div')
  appEl.innerHTML = template
  appEl.id = 'theApp'
  appWrapper.appendChild(appEl)

  let log = await getChatlog()
  document.body.innerHTML = appWrapper.outerHTML

  app = new Vue({
        el: '#theApp',
        data: {
            modelList: log,
            selectedModel: '',
            log: [],
            search: '',
            user: 'Me : ',
        },
        methods: {
            async showlog (model) {
                this.selectedModel = model
                let log = await GM.getValue(model, JSON.stringify(this.log.join('\n')))
                log = log.split('\n')
                this.log = log
            },
            close () {
                this.log = []
                this.selectedModel = ''
            }
        },
        mounted () {
            console.log('hello world from vue')
        },
        computed: {
            models ()  {
                return this.modelList
                    .filter(name => name.toLowerCase().indexOf(this.search.toLowerCase()) > -1)
                    .sort((a, b) => a.localeCompare(b))
            }
        }
    })
}


whenSettings(() => {
	let settings = document.querySelector('#ext-gen33')
  let chatlog = settings.cloneNode(true)
  chatlog.id = ''
  chatlog.dataset.action = ''
  chatlog.children[0].href = 'javascript:void(0)'
  chatlog.children[0].innerHTML = 'Chatlog'
  chatlog.addEventListener('click', showChatlog)
  settings.parentNode.insertBefore(chatlog, settings.nextSibling)
})

let models = []

;(async () => {
  models = await GM.getValue('models', JSON.stringify(models))
  models = JSON.parse(models)
})();

let b = document.createElement('button')
b.innerHTML = 'Save chatlog'
b.style.position = 'fixed'
b.style.top = '0px'
b.style.left = '0px'
b.style.zIndex = '9999999'
document.body.appendChild(b)


b.addEventListener('click', async () => {
  main()
})

setInterval(async () => {
  main()
}, 30000)