forked from fair/matrix-puppeteer-line
Syncable chat lists
This commit is contained in:
parent
1280916455
commit
cbe1fd7059
18
README.md
18
README.md
|
@ -1,4 +1,18 @@
|
||||||
# mautrix-line
|
# mautrix-line
|
||||||
A very hacky Matrix-LINE bridge based on running LINE's Chrome extension in Puppeteer
|
A very hacky Matrix-LINE bridge based on running LINE's Chrome extension in Puppeteer.
|
||||||
|
|
||||||
Matrix room: [`#mautrix-line:miscworks.net`](https://matrix.to/#/#matrix-line:miscworks.net)
|
Matrix room: [`#mautrix-line:miscworks.net`](https://matrix.to/#/#mautrix-line:miscworks.net)
|
||||||
|
|
||||||
|
## Missing features
|
||||||
|
### Missing from LINE
|
||||||
|
- typing notifications
|
||||||
|
- message edits
|
||||||
|
- formatted messages
|
||||||
|
|
||||||
|
### Missing from LINE on Chrome:
|
||||||
|
- message redaction (delete/unsend)
|
||||||
|
- replies
|
||||||
|
- voice messages
|
||||||
|
|
||||||
|
### Missing from mautrix-line
|
||||||
|
- TODO
|
||||||
|
|
|
@ -92,6 +92,7 @@ async def login_do(evt: CommandEvent, gen: AsyncGenerator[Tuple[str, str], None]
|
||||||
if not failure and evt.sender.command_status:
|
if not failure and evt.sender.command_status:
|
||||||
await evt.reply("Successfully logged in, now syncing")
|
await evt.reply("Successfully logged in, now syncing")
|
||||||
await evt.sender.sync()
|
await evt.sender.sync()
|
||||||
|
await evt.reply("Syncing complete")
|
||||||
# else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already
|
# else command was cancelled or failed. Don't post message about it, "cancel" command or failure did already
|
||||||
evt.sender.command_status = None
|
evt.sender.command_status = None
|
||||||
|
|
||||||
|
@ -107,12 +108,12 @@ async def login_qr(evt: CommandEvent) -> None:
|
||||||
help_text="Log into LINE via email/password",
|
help_text="Log into LINE via email/password",
|
||||||
help_args="<_email_> <_password_>")
|
help_args="<_email_> <_password_>")
|
||||||
async def login_email(evt: CommandEvent) -> None:
|
async def login_email(evt: CommandEvent) -> None:
|
||||||
|
await evt.az.intent.redact(evt.room_id, evt.event_id)
|
||||||
if len(evt.args) != 2:
|
if len(evt.args) != 2:
|
||||||
await evt.reply("Usage: `$cmdprefix+sp login <email> <password>`")
|
await evt.reply("Usage: `$cmdprefix+sp login <email> <password>`")
|
||||||
return
|
return
|
||||||
if not await login_prep(evt, "email"):
|
if not await login_prep(evt, "email"):
|
||||||
return
|
return
|
||||||
await evt.az.intent.redact(evt.room_id, evt.event_id)
|
|
||||||
gen = evt.sender.client.login(
|
gen = evt.sender.client.login(
|
||||||
evt.sender,
|
evt.sender,
|
||||||
login_data=dict(email=evt.args[0], password=evt.args[1]))
|
login_data=dict(email=evt.args[0], password=evt.args[1]))
|
||||||
|
|
|
@ -318,7 +318,7 @@ class Portal(DBPortal, BasePortal):
|
||||||
await self.main_intent.invite_user(self.mxid, source.mxid, check_cache=True)
|
await self.main_intent.invite_user(self.mxid, source.mxid, check_cache=True)
|
||||||
puppet = await p.Puppet.get_by_custom_mxid(source.mxid)
|
puppet = await p.Puppet.get_by_custom_mxid(source.mxid)
|
||||||
if puppet:
|
if puppet:
|
||||||
await puppet.intent.ensure_joined(self.mxid)
|
await puppet.az.intent.ensure_joined(self.mxid)
|
||||||
|
|
||||||
await self.update_info(info)
|
await self.update_info(info)
|
||||||
|
|
||||||
|
@ -395,7 +395,7 @@ class Portal(DBPortal, BasePortal):
|
||||||
puppet = await p.Puppet.get_by_custom_mxid(source.mxid)
|
puppet = await p.Puppet.get_by_custom_mxid(source.mxid)
|
||||||
if puppet:
|
if puppet:
|
||||||
try:
|
try:
|
||||||
await puppet.intent.join_room_by_id(self.mxid)
|
await puppet.az.intent.join_room_by_id(self.mxid)
|
||||||
except MatrixError:
|
except MatrixError:
|
||||||
self.log.debug("Failed to join custom puppet into newly created portal",
|
self.log.debug("Failed to join custom puppet into newly created portal",
|
||||||
exc_info=True)
|
exc_info=True)
|
||||||
|
|
|
@ -55,7 +55,6 @@ class User(DBUser, BaseUser):
|
||||||
self._metric_value = defaultdict(lambda: False)
|
self._metric_value = defaultdict(lambda: False)
|
||||||
self._connection_check_task = None
|
self._connection_check_task = None
|
||||||
self.client = None
|
self.client = None
|
||||||
self.intent = None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def init_cls(cls, bridge: 'MessagesBridge') -> None:
|
def init_cls(cls, bridge: 'MessagesBridge') -> None:
|
||||||
|
@ -84,7 +83,7 @@ class User(DBUser, BaseUser):
|
||||||
self.log.warning("Failed to log in with shared secret")
|
self.log.warning("Failed to log in with shared secret")
|
||||||
return
|
return
|
||||||
self.log.debug("Logged in with shared secret")
|
self.log.debug("Logged in with shared secret")
|
||||||
self.intent = self.az.intent.user(self.mxid, access_token)
|
#self.intent = self.az.intent.user(self.mxid, access_token)
|
||||||
except Exception:
|
except Exception:
|
||||||
self.log.exception("Error logging in with shared secret")
|
self.log.exception("Error logging in with shared secret")
|
||||||
|
|
||||||
|
|
|
@ -27,7 +27,7 @@ export default class MessagesPuppeteer {
|
||||||
static executablePath = undefined
|
static executablePath = undefined
|
||||||
static disableDebug = false
|
static disableDebug = false
|
||||||
static noSandbox = false
|
static noSandbox = false
|
||||||
//static viewport = { width: 1920, height: 1080 }
|
static viewport = { width: 960, height: 880 }
|
||||||
static url = undefined
|
static url = undefined
|
||||||
static extensionDir = 'extension_files'
|
static extensionDir = 'extension_files'
|
||||||
|
|
||||||
|
@ -231,16 +231,18 @@ export default class MessagesPuppeteer {
|
||||||
const text = messageSyncElement.innerText
|
const text = messageSyncElement.innerText
|
||||||
return text.startsWith("Syncing messages...")
|
return text.startsWith("Syncing messages...")
|
||||||
&& (text.endsWith("100%") || text.endsWith("NaN%"))
|
&& (text.endsWith("100%") || text.endsWith("NaN%"))
|
||||||
|
// TODO Sometimes it gets stuck at 99%...??
|
||||||
},
|
},
|
||||||
{},
|
{timeout: 10000}, // Assume 10 seconds is long enough
|
||||||
result)
|
result)
|
||||||
|
|
||||||
this.loginRunning = false
|
|
||||||
await this.startObserving()
|
|
||||||
this.log("Login complete")
|
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
this._sendLoginFailure(`Failed to sync: ${err}`)
|
//this._sendLoginFailure(`Failed to sync: ${err}`)
|
||||||
|
this.log("LINE's sync took too long, assume it's fine and carry on...")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.loginRunning = false
|
||||||
|
await this.startObserving()
|
||||||
|
this.log("Login complete")
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -452,7 +454,7 @@ export default class MessagesPuppeteer {
|
||||||
//await chatDetailArea.$(".MdTxtDesc02") || // 1:1 chat with custom title - get participant's real name
|
//await chatDetailArea.$(".MdTxtDesc02") || // 1:1 chat with custom title - get participant's real name
|
||||||
participants = [{
|
participants = [{
|
||||||
id: id, // the ID of a 1:1 chat is the other user's member ID
|
id: id, // the ID of a 1:1 chat is the other user's member ID
|
||||||
name: await participantElement.$eval(
|
name: await chatDetailArea.$eval(
|
||||||
"#_chat_contact_detail_view > a",
|
"#_chat_contact_detail_view > a",
|
||||||
element => element.innerText),
|
element => element.innerText),
|
||||||
}]
|
}]
|
||||||
|
@ -460,7 +462,11 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
|
|
||||||
this.log(`Found participants: ${participants}`)
|
this.log(`Found participants: ${participants}`)
|
||||||
return participants
|
return {
|
||||||
|
participants,
|
||||||
|
...await this.page.$eval(this._listItemSelector(id),
|
||||||
|
elem => window.__mautrixController.parseChatListItem(elem)),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async _sendMessageUnsafe(chatID, text) {
|
async _sendMessageUnsafe(chatID, text) {
|
||||||
|
@ -475,12 +481,14 @@ export default class MessagesPuppeteer {
|
||||||
}
|
}
|
||||||
|
|
||||||
async _getMessagesUnsafe(id, minID = 0) {
|
async _getMessagesUnsafe(id, minID = 0) {
|
||||||
|
/* TODO Also handle "decrypting" state
|
||||||
await this._switchChatUnsafe(id)
|
await this._switchChatUnsafe(id)
|
||||||
this.log("Waiting for messages to load")
|
this.log("Waiting for messages to load")
|
||||||
await this.page.waitFor("mws-message-wrapper")
|
await this.page.waitFor("mws-message-wrapper")
|
||||||
const messages = await this.page.$eval("mws-messages-list .content",
|
const messages = await this.page.$eval("mws-messages-list .content",
|
||||||
element => window.__mautrixController.parseMessageList(element))
|
element => window.__mautrixController.parseMessageList(element))
|
||||||
return messages.filter(msg => msg.id > minID && !this.sentMessageIDs.has(msg.id))
|
return messages.filter(msg => msg.id > minID && !this.sentMessageIDs.has(msg.id))
|
||||||
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
async _processChatListChangeUnsafe(id) {
|
async _processChatListChangeUnsafe(id) {
|
||||||
|
|
Loading…
Reference in New Issue