Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ object Authors {
val Nyako = Author("nyakowint", 118437263754395652L)
val Juby210 = Author("Juby210", 324622488644616195L)
val LampDelivery = Author("LampDelivery", 650805815623680030L)
val Ty = Author("Ty", 487443883127472129L)
val miaaaa0a = Author("miaaaa0a", 435750383491481602L)
}

Expand Down
25 changes: 25 additions & 0 deletions plugins/CallTime/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
import com.aliucord.gradle.repo.Authors
import com.aliucord.gradle.repo.author

plugins {
id("com.aliucord.plugins-repo")
}

version = "1.0.3"
description = "A plugin that shows how long you have been in a VC for."

aliucord {
changelog.set("""
# Version 1.0.3
* Updated for new discord/aliucord version
# Version 1.0.2
* Fix a crash
* Fix seconds bugging out with long times
# Version 1.0.1
* Fix ending timer on mute/deafen
# Version 1.0.0
* Initial release
""".trimIndent())

author(Authors.Ty)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package tech.tyman.plugins.calltime

import android.content.Context
import com.aliucord.Utils
import com.aliucord.annotations.AliucordPlugin
import com.aliucord.api.PatcherAPI
import com.aliucord.entities.Plugin
import com.aliucord.patcher.Hook
import com.discord.gateway.io.OutgoingPayload
import com.discord.rtcconnection.RtcConnection
import com.discord.stores.StoreRtcConnection
import com.discord.utilities.streams.StreamContext
import com.discord.utilities.time.ClockFactory
import com.discord.utilities.voice.VoiceViewUtils
import com.discord.widgets.status.WidgetGlobalStatusIndicator
import com.discord.widgets.status.WidgetGlobalStatusIndicatorViewModel
import java.util.*
import java.util.concurrent.TimeUnit
import kotlin.concurrent.schedule

@AliucordPlugin
class CallTime : Plugin() {
private var vcConnectedTime: Long? = null
private var cachedVoiceState: OutgoingPayload.VoiceStateUpdate? = null
private val timer = Timer()
private var timerTask: TimerTask? = null
private val clock = ClockFactory.get()
private val elapsedTime: String
get() = run {
val vcConnectedTime = vcConnectedTime ?: return "00:00:00"
val duration = clock.currentTimeMillis() - vcConnectedTime
return String.format(
"%02d:%02d:%02d",
TimeUnit.MILLISECONDS.toHours(duration),
TimeUnit.MILLISECONDS.toMinutes(duration) % TimeUnit.HOURS.toMinutes(1),
TimeUnit.MILLISECONDS.toSeconds(duration) % TimeUnit.MINUTES.toSeconds(1)
)
}

override fun start(ctx: Context) {
patcher.patchConnectedText()
}

private fun PatcherAPI.patchConnectedText() {
val currentVoiceStateField = StoreRtcConnection::class.java.getDeclaredField("currentVoiceState").apply { isAccessible = true }
val setupIndicatorStatusMethod = WidgetGlobalStatusIndicator::class.java.getDeclaredMethod("setupIndicatorStatus", WidgetGlobalStatusIndicatorViewModel.ViewState.CallOngoing::class.java).apply { isAccessible = true }
val getConnectedTextMethod = VoiceViewUtils::class.java.getDeclaredMethod("getConnectedText", Context::class.java, RtcConnection.State::class.java, StreamContext::class.java, Boolean::class.javaPrimitiveType)

patch(setupIndicatorStatusMethod, Hook {
val widget = it.thisObject as WidgetGlobalStatusIndicator
timerTask?.cancel()
timerTask = timer.schedule(1000) {
widget.activity?.runOnUiThread {
widget.view ?: return@runOnUiThread
setupIndicatorStatusMethod.invoke(widget, it.args[0])
}
}
})

patch(StoreRtcConnection::class.java.getDeclaredMethod("onVoiceStateUpdated"), Hook {
val store = it.thisObject as StoreRtcConnection
val currentVoiceState = currentVoiceStateField[store] as OutgoingPayload.VoiceStateUpdate?
?: return@Hook
if (currentVoiceState.channelId != null && cachedVoiceState?.channelId != currentVoiceState.channelId) {
vcConnectedTime = clock.currentTimeMillis()
} else if (currentVoiceState.channelId == null && cachedVoiceState?.channelId != null) {
timerTask?.cancel()
timerTask = null
if (vcConnectedTime != null) Utils.showToast("Call ended. Elapsed time: $elapsedTime", true)
vcConnectedTime = null
}
cachedVoiceState = currentVoiceState
})
patch(getConnectedTextMethod, Hook {
it.result = "${it.result} ($elapsedTime)"
})

}

override fun stop(context: Context) {
patcher.unpatchAll()
}
}
26 changes: 26 additions & 0 deletions plugins/ReverseImageSearch/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import com.aliucord.gradle.repo.Authors
import com.aliucord.gradle.repo.author

plugins {
id("com.aliucord.plugins-repo")
}

version = "1.0.4"
description = "A plugin that adds a button for reverse image searching a sent image."

aliucord {
changelog.set("""
# Version 1.0.4
* Fix reverse searching not working on expired discord urls and images inside embeds (thanks Delphox)
# Version 1.0.3
* Replace google images search with google lens, as the old images URL no longer works (thanks Delphox)
# Version 1.0.2
* Fixed google images search (i love it when google)
# Version 1.0.1
* Fixed a bug where some images would not work when using google
# Version 1.0.0
* Initial release
""".trimIndent())

author(Authors.Ty)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package tech.tyman.plugins.reverseimagesearch

import android.annotation.SuppressLint
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.view.View
import android.widget.TextView
import androidx.core.content.res.ResourcesCompat
import com.aliucord.Utils
import com.aliucord.api.SettingsAPI
import com.aliucord.widgets.BottomSheet
import com.discord.widgets.media.WidgetMedia
import com.lytefast.flexinput.R

class EngineSheet(val url: String?) : BottomSheet() {
@SuppressLint("SetTextI18n")
override fun onViewCreated(view: View, bundle: Bundle?) {
super.onViewCreated(view, bundle)

val context = view.context
val textViews = Engine.values().mapNotNull {
if (it == Engine.ASK) return@mapNotNull null
TextView(context, null, 0, R.i.UiKit_Settings_Item_Icon).apply {
val iconDrawable = ResourcesCompat
.getDrawable(resources, R.e.ic_open_in_browser_white_24dp, null)
text = "Open in ${it.niceName}"
setCompoundDrawablesRelativeWithIntrinsicBounds(iconDrawable, null, null, null)
setOnClickListener { _ ->
val url = this@EngineSheet.url ?: return@setOnClickListener
val intent = Intent(Intent.ACTION_VIEW, it.getUrl(url))
startActivity(intent)
}
}
}
textViews.forEach {
linearLayout.addView(it)
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package tech.tyman.plugins.reverseimagesearch

import android.content.Context
import com.aliucord.annotations.AliucordPlugin
import com.aliucord.entities.Plugin
import androidx.appcompat.view.menu.ActionMenuItemView
import com.aliucord.Utils
import com.discord.widgets.media.WidgetMedia
import com.aliucord.patcher.after
import android.net.Uri
import android.content.Intent
import android.graphics.drawable.Drawable
import androidx.core.content.res.ResourcesCompat
import com.aliucord.Logger
import java.net.URLEncoder
import java.nio.charset.StandardCharsets

@AliucordPlugin
class ReverseImageSearch : Plugin() {
lateinit var pluginIcon: Drawable

init {
settingsTab = SettingsTab(SearchSettings::class.java).withArgs(settings)
needsResources = true
}

override fun load(ctx: Context) {
val res = resources!!

pluginIcon = ResourcesCompat.getDrawable(
res,
res.getIdentifier("ic_baseline_image_search_24", "drawable", "com.aliucord.plugins"),
null
)!!
}

override fun start(context: Context) {
val isVideoMethod = WidgetMedia::class.java.getDeclaredMethod("isVideo").apply {
isAccessible = true
}
patcher.after<WidgetMedia>("onViewBoundOrOnResume") {
if (isVideoMethod.invoke(this) as Boolean) return@after
val btnId = Utils.getResId("menu_media_browser", "id")
val btn = Utils.appActivity.findViewById<ActionMenuItemView>(btnId)
btn.setOnLongClickListener {
val url = mostRecentIntent.getStringExtra("INTENT_IMAGE_URL") ?: return@setOnLongClickListener false
if (settings.engine == Engine.ASK) {
EngineSheet(url)
.show(Utils.appActivity.supportFragmentManager, "Reverse Image Search")
} else {
val intent = Intent(Intent.ACTION_VIEW, settings.engine.getUrl(url))
startActivity(intent)
}
true
}
}
}

override fun stop(context: Context) {
patcher.unpatchAll()
}
}

@Suppress("unused")
enum class Engine(val urlTemplate: String?, val niceName: String) {
ASK(null, "Ask every time"),
GOOGLE("https://lens.google.com/uploadbyurl?url=%s", "Google Lens"),
TIN_EYE("https://www.tineye.com/search?url=%s", "TinEye"),
YANDEX("https://yandex.com/images/search?url=%s&rpt=imageview", "Yandex"),
BING("https://www.bing.com/images/search?q=imgurl:%s&view=detailv2&iss=sbi&FORM=IRSBIQ", "Bing"),
IQDB("https://iqdb.org/?url=%s", "IQDB"),
SAUCE_NAO("https://saucenao.com/search.php?url=%s", "SauceNAO");

fun getUrl(url: String): Uri {
val uri = Uri.parse(
urlTemplate?.format(
URLEncoder.encode(url, StandardCharsets.UTF_8.toString())
)
)

return uri
}

companion object {
fun fromOrdinal(ordinal: Int): Engine? {
return values().find { it.ordinal == ordinal }
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
package tech.tyman.plugins.reverseimagesearch

import android.annotation.SuppressLint
import android.view.View
import android.widget.RadioGroup
import android.widget.TextView
import com.aliucord.Utils
import com.aliucord.api.SettingsAPI
import com.aliucord.fragments.SettingsPage
import com.discord.utilities.color.ColorCompat
import com.discord.views.CheckedSetting
import com.discord.views.RadioManager
import com.lytefast.flexinput.R

var SettingsAPI.engine: Engine
get() = Engine.fromOrdinal(this.getInt("engine", Engine.ASK.ordinal)) ?: Engine.ASK
set(value) = this.setInt("engine", value.ordinal)

@SuppressLint("SetTextI18n")
class SearchSettings(private val settings: SettingsAPI) : SettingsPage() {
override fun onViewBound(view: View?) {
super.onViewBound(view)
setActionBarTitle("ReverseImageSearch")
val ctx = requireContext()

val radios = Engine.values().mapNotNull {
Utils.createCheckedSetting(ctx, CheckedSetting.ViewType.RADIO, it.niceName, null)
}
val radioManager = RadioManager(radios)
val radioGroup = RadioGroup(ctx)

radios.forEachIndexed { i, radio ->
radio.e {
settings.engine = Engine.fromOrdinal(i) ?: return@e
radioManager.a(radio)
}
radioGroup.addView(radio)
if (settings.engine.ordinal == i) radioManager.a(radio)
}

val helpText = TextView(ctx)
helpText.linksClickable = true
helpText.text =
"To reverse image search an image, open it and long press the \"Open in browser\" icon. " +
"Then, a reverse image search using then engine of your choice (you can choose this above)" +
"will open in a browser."
helpText.setTextColor(ColorCompat.getThemedColor(ctx, R.b.colorOnPrimary))

addView(radioGroup)
addView(helpText)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
<vector android:height="24dp" android:tint="#FFFFFF"
android:viewportHeight="24" android:viewportWidth="24"
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
<path android:fillColor="@android:color/white" android:pathData="M18,13v7L4,20L4,6h5.02c0.05,-0.71 0.22,-1.38 0.48,-2L4,4c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-5l-2,-2zM16.5,18h-11l2.75,-3.53 1.96,2.36 2.75,-3.54zM19.3,8.89c0.44,-0.7 0.7,-1.51 0.7,-2.39C20,4.01 17.99,2 15.5,2S11,4.01 11,6.5s2.01,4.5 4.49,4.5c0.88,0 1.7,-0.26 2.39,-0.7L21,13.42 22.42,12 19.3,8.89zM15.5,9C14.12,9 13,7.88 13,6.5S14.12,4 15.5,4 18,5.12 18,6.5 16.88,9 15.5,9z"/>
</vector>
23 changes: 23 additions & 0 deletions plugins/RoleColorContrast/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import com.aliucord.gradle.repo.Authors
import com.aliucord.gradle.repo.author

plugins {
id("com.aliucord.plugins-repo")
}

version = "1.1.0"
description = "A plugin to improve contrast between role colors and the background"

aliucord {
changelog.set("""
# Version 1.1.0
* Now supports names in the member list
* Fixed a possible issue when themer was not installed
* Contrast adjustments are now faster

# Version 1.0.0
* Initial release, supporting only names in chat
""".trimIndent())

author(Authors.Ty)
}
Loading