NOTICE: By continued use of this site you understand and agree to the binding Terms of Service and Privacy Policy.
// ==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)