/* * Copyright (c) 2021 William Hubbard. All Rights Reserved. * * This module contains the browser addon that handles most of the logic for internet songs. When the :browser module is * built, this addon is added to the browser's list of extensions. Then, when it is run, the addon will start the * intermediary program. Then, it will receive commands from the interface through the intermediary application and * manipulate the browser state based on those commands. It will then send the results of those commands back through * the intermediary. The addon will also periodically shoot off updates to the browser. */ import org.apache.tools.ant.taskdefs.condition.Os import java.nio.file.Files import java.nio.file.Paths import java.nio.file.StandardCopyOption import java.util.stream.Stream configurations { /** * This configuration is used to export the packaged addon for installation into a browser. */ addonBuild { canBeConsumed = true canBeResolved = false } /** * The nativeApp configuration is used to import a native application that this addon will start when the browser * does. */ nativeApp.extendsFrom runtime } /** * Contains information on the extension being made */ interface ExtensionData { Property getName() Property getDescription() Property getId() } def extension = project.extensions.create('extension', ExtensionData) extension.name = "universalmusic" extension.description = "A link between the Universal Music Player and the web browser." extension.id = "universalmusic@regis.edu" /** * Creates an addon manifest that defines details for the native application that is run when the app starts. */ abstract class BuildManifest extends DefaultTask { @OutputFile final abstract RegularFileProperty manifests = project.objects.fileProperty() @TaskAction void join() { println "Making build directories!" String addonName = project.extension.name.get(), addonDescription = project.extension.description.get(), extensionId = project.extension.id.get() File manifest File startupScript for (Dependency dep : project.configurations.nativeApp.dependencies) { File binFiles = new File(dep.dependencyProject.installDist.outputs.getFiles().getSingleFile(), "bin") Stream files = Arrays.stream(binFiles.listFiles()) if (Os.isFamily(Os.FAMILY_WINDOWS)) { startupScript = files.filter(file -> file.getName().endsWith(".bat")).findFirst().get() } else if (Os.isFamily(Os.FAMILY_UNIX)) { startupScript = files.filter(file -> !file.getName().endsWith(".sh")).findFirst().get() } else { throw new RuntimeException("Unknown OS family") } manifests.get().asFile.text = "{\n" + " \"name\": \"$addonName\",\n" + " \"description\": \"$addonDescription\",\n" + " \"path\": \"" + startupScript.getAbsolutePath().replace("\\", "\\\\") + "\",\n" + " \"type\": \"stdio\",\n" + " \"allowed_extensions\": [\"$extensionId\"]\n" + "}" break } } } /** * Installs the addon manifest, adding registery keys on Windows and creating the appropriate files on Mac and Linux. */ abstract class InstallAddon extends DefaultTask { @InputFile @SkipWhenEmpty final abstract RegularFileProperty inputFile = project.objects.fileProperty() @TaskAction void join() { File file = inputFile.get().asFile if (Os.isFamily(Os.FAMILY_WINDOWS)) { String name = file.name.substring(0, file.name.lastIndexOf('.')) Process p = Runtime.getRuntime() .exec("REG DELETE HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /f ") p.waitFor() p = Runtime.getRuntime() .exec("REG ADD HKEY_CURRENT_USER\\SOFTWARE\\Mozilla\\NativeMessagingHosts\\${name} /ve /d \"" + file.getAbsolutePath() + "\" /f ") p.waitFor() } else if (Os.isFamily(Os.FAMILY_MAC)) { Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), "Library/Application Support/Mozilla/NativeMessagingHosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) } else if (Os.isFamily(Os.FAMILY_UNIX)) { Files.copy(file.toPath(), Paths.get(System.getProperty("user.home"), ".mozilla/native-messaging-hosts", file.getName()), StandardCopyOption.REPLACE_EXISTING) } } } dependencies { nativeApp project(path: ":addonInter", configuration: 'nativeBuild') } /** * Creates a build manifest that defines details for the native application defined by nativeApp dependencies that will * be run. */ tasks.register('buildManifest', BuildManifest) { manifests = new File(buildDir, "${extension.name.get()}.json") } /** * Registers the build manifest to the OS, allowing for the native application to run properly. * This task depends on buildManifest */ def installAddon = tasks.register('installAddon', InstallAddon) { inputFile = buildManifest.manifests } /** * Creates a packaged (albiet unsigned) Firefox addon from the src/main directory. * This task is finished by calling installAddon */ tasks.register('zipAddon', Zip) { dependsOn configurations.nativeApp archiveName = "${extension.id.get()}.xpi" destinationDir = file("$buildDir/lib") from("$projectDir/src/addon/javascript", "$projectDir/src/addon/resources") doLast { File profiles File extention if (Os.isFamily(Os.FAMILY_WINDOWS)) { profiles = new File(System.getenv("APPDATA"), "Mozilla\\Firefox\\Profiles") } else if (Os.isFamily(Os.FAMILY_MAC)) { profiles = new File(System.getProperty("user.home"), "Library/Application Support/Firefox/Profiles") } else if (Os.isFamily(Os.FAMILY_UNIX)) { profiles = new File(System.getProperty("user.home"), ".mozilla/firefox/") } for (File profile: profiles.listFiles()) { if (profile.isDirectory()) { extention = new File(profile, "extensions/${extension.id.get()}.xpi") if (extention.exists()) { copy { from(zipAddon.outputs) into extention.getParentFile() } } } } } } zipAddon.finalizedBy installAddon tasks.register("clean", Delete) { delete "$buildDir" followSymlinks = false } /* * Exports the packaged addon task. */ artifacts { addonBuild(zipAddon) }