Skip to content
This repository has been archived by the owner on Dec 12, 2020. It is now read-only.

Commit

Permalink
Merge branch 'master' into github-releases
Browse files Browse the repository at this point in the history
  • Loading branch information
Xerus committed Nov 9, 2018
2 parents e7c40b1 + 7fb3ec7 commit 106ad4c
Show file tree
Hide file tree
Showing 24 changed files with 384 additions and 253 deletions.
75 changes: 67 additions & 8 deletions Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,31 +6,55 @@ Browse, stream and download Monstercat Songs, powered by the Monstercat API and

## Usage

[Download](http://monsterutilities.bplaced.net/downloads?download)
[Download](http://monsterutilities.bplaced.net/downloads?download) or use the GitHub releases.

> This is a pre-Release, you may encounter bugs.
If you do, open an issue here or send feedback from inside the application.
The latter will automatically include logs, which reside in `TEMP/monsterutilities/logs`

To run it, you need to have Java 8 by Oracle installed on your computer.

Read the initial guide and follow the tooltips. Improved user-friendliness is in development ;)
Read the initial guide and follow the tooltips.
Improved user-friendliness is in development ;)

### Troubleshooting

#### connect.sid

For downloading and listening to the latest Track, your `connect.sid`
needs to be entered in the bottom of the Downloader. It is a cookie that
identifies your Monstercat Account. Here's how to obtain it:

1) Log in on [monstercat.com](https://monstercat.com) and ensure that you have a valid Monstercat Gold subscription
2) Go to your browser cookies and search for `connect.monstercat.com`
[Quick link for Chrome](chrome://settings/cookies/detail?site=connect.monstercat.com)
3) Find the content of `connect.sid`. It is a string starting with `s%3A` and has around 90 characters.
4) Copy that string into the `connect.sid` Textfield at the bottom of the Downloader.

#### Downloader

Sometimes, the cache runs into issues and that may contribute to issues in the Downloader.
Simply disable the cache, restart the application and enable it again.

> If you still have issues - no problem!
> Hit me up on [Discord](https://discord.gg/ZEusvHS) or send Feedback directly from the application!
## Screenshots

### Catalog

The Catalog provides an overview of all Tracks ever released on the label and extensive possibilities of filtering them.
The Catalog provides an overview of all Tracks ever released on the label and
extensive possibilities of filtering them.
> Tip: You can customize which columns to show by clicking on the `+` in the top right
![Catalog](assets/screenshots/catalog.png)
![Catalog filtering](assets/screenshots/filtering.png)

### Streaming

In case you missed it in the other Screenshots: There's a player on top that can stream any Monstercat track,
just like the website. Double-click on any piece in the Catalog or Downloader to load it into the Player!

In case you missed it in the other Screenshots:
There's a player on top that can stream any Monstercat track, just like the website.
Double-click on any piece in the Catalog or Downloader to load it into the Player!
![Player](assets/screenshots/player.png)

### Downloader
Expand All @@ -39,11 +63,46 @@ You have a Monstercat Gold membership? Great, because now you can download whate
![Downloader](assets/screenshots/downloader.png)
![Downloader](assets/screenshots/downloading.png)

### Configurable
### Customization

The application has multiple available skins and other options if the defaults don't suit your needs.
![Settings](assets/screenshots/settings.png)

## Development

Gradle is used for building the project.
[Gradle](https://gradle.org/) is used for building the project.

### Setup

If you want Gradle to use a JDK other than your system default,
create a `gradle.properties` file at the root of the project
with the following line:
```
org.gradle.java.home=/path/to/jdk
```

To fetch the Catalog and Genres, you need to create the file `src/resources/sheets-api-key`
and put an api key for Google Sheets into it.


### Important Tasks
Name | Action
--- | ---
`run` | runs the project right from source
`shadowJar` | Creates an executable jar with all libraries bundled in the root directory of the project
`runShadow` | Creates a shadowJar and runs it

Both run tasks can be run with the argument `-Dargs="--loglevel trace"`
to change the log level or pass other arguments to the application.

### Logging

Logging is done via slf4j wrapped by kotlin-logging and carried out by logback-classic.
A Logger can be created anywhere via `val logger = KotlinLogging.logger { }`
and will automatically pick up the context where it was instantiated.

The application runs with the WARN log level by default, however both run tasks
automatically pass arguments to run it at DEBUG.

The application also logs to a file in `TMP/monsterutilities/logs`,
the log level of which defaults to the lower of the console log level and DEBUG.
70 changes: 34 additions & 36 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import org.gradle.internal.os.OperatingSystem;
import com.github.jengelman.gradle.plugins.shadow.internal.JavaJarExec
import org.gradle.internal.os.OperatingSystem
import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.Coroutines
Expand All @@ -13,10 +14,10 @@ version = "dev" + commitNumber +
file("src/resources/version").writeText(version as String)

plugins {
kotlin("jvm") version "1.2.61"
kotlin("jvm") version "1.3.0"
application
id("com.github.johnrengelman.shadow") version "2.0.4"
id("com.github.ben-manes.versions") version "0.19.0"
id("com.github.ben-manes.versions") version "0.20.0"
id("com.github.breadmoirai.github-release") version "2.0.1"
}

Expand All @@ -37,50 +38,53 @@ application {
repositories {
jcenter()
maven("https://jitpack.io")
maven("http://maven.bluexin.be/repository/snapshots/")
maven("https://oss.jfrog.org/simple/libs-snapshot")
}

dependencies {
compile("com.github.Xerus2000", "util", "master-SNAPSHOT")
compile(kotlin("stdlib-jdk8"))
compile(kotlin("reflect"))
implementation(kotlin("reflect"))

compile("org.controlsfx", "controlsfx", "8.40.14")
implementation("com.github.Xerus2000.util", "javafx", "-SNAPSHOT")
implementation("org.controlsfx", "controlsfx", "8.40.+")

compile("be.bluexin", "drpc4k", "0.6-SNAPSHOT")
implementation("ch.qos.logback", "logback-classic", "1.2.+")
implementation("com.github.Bluexin", "drpc4k", "16b0c60")
implementation("org.apache.httpcomponents", "httpmime", "4.5.+")
implementation("com.google.apis", "google-api-services-sheets", "v4-rev551-1.25.0")

compile("org.apache.httpcomponents", "httpmime", "4.5.5")
compile("com.google.apis", "google-api-services-sheets", "v4-rev527-1.23.0")

testCompile("org.junit.jupiter", "junit-jupiter-api", "5.2.0")
testRuntimeOnly("org.junit.jupiter", "junit-jupiter-engine", "5.2.0")
val junitVersion = "5.3.1"
testCompile("org.junit.jupiter", "junit-jupiter-api", junitVersion)
testRuntimeOnly("org.junit.jupiter", "junit-jupiter-engine", junitVersion)
}

kotlin.experimental.coroutines = Coroutines.ENABLE
val jarFile
get() = "MonsterUtilities-$version.jar"
get() = "$name-$version.jar"

val MAIN = "_Main"
tasks {

getByName("runShadow").group = MAIN
getByName("startShadowScripts").group = "distribution"

"run"(JavaExec::class) {
group = MAIN
// Usage: gradle run -Dargs="FINE save"
args = System.getProperty("args", "").split(" ")
arrayOf(getByName<JavaExec>("run"), getByName<JavaExec>("runShadow")).forEach {
it.group = MAIN
it.args = System.getProperty("args", "--loglevel debug").split(" ")
}

"shadowJar"(ShadowJar::class) {
baseName = "MonsterUtilities"
val shadowJar by getting(ShadowJar::class) {
group = MAIN
classifier = ""
destinationDir = file(".")
doLast { file(jarFile).setExecutable(true) }
doFirst {
destinationDir.listFiles().forEach {
if (it.name.endsWith("jar"))
it.delete()
}
}
doLast {
outputs.files.singleFile.setExecutable(true)
}
}

create<Exec>("release") {
dependsOn("jar")
dependsOn(shadowJar)
group = MAIN
val path = file("../monsterutilities-extras/website/downloads/" + if (isUnstable) "unstable" else "latest")
val pathLatest = path.resolveSibling("latest") // TODO temporary workaround until real release
Expand All @@ -92,22 +96,16 @@ tasks {
val s = if (OperatingSystem.current().isWindows) "\\" else ""
commandLine("lftp", "-c", """set ftp:ssl-allow true; set ssl:verify-certificate no;
open -u ${properties["credentials.ftp"]} -e $s"
cd /www/downloads/files; put $jarFile;
cd /www/downloads; ${if (properties["noversion"] == null) "put $path; put $pathLatest;" else ""}
cd ./files; put $jarFile;
quit$s" monsterutilities.bplaced.net""".filter { it != '\t' && it != '\n' })
}

withType<KotlinCompile> {
kotlinOptions.jvmTarget = "1.8"
}

replace("jar", Delete::class).run {
group = MAIN
dependsOn("shadowJar")
setDelete(file(".").listFiles { f -> f.name.run { startsWith("MonsterUtilities-") && endsWith("jar") && this != jarFile } })
}

"test"(Test::class) {
withType<Test> {
useJUnitPlatform()
}

Expand All @@ -118,7 +116,7 @@ githubRelease {
setOwner("Xerus2000")
setReleaseAssets(jarFile)

setTagName(if(isUnstable) "dev$commitNumber" else version.toString())
setTagName(version.toString())
setBody(properties["m"]?.toString())
setReleaseName("Dev $commitNumber" + if (properties["n"] != null) " - ${properties["n"]}" else "")
setPrerelease(isUnstable)
Expand Down
1 change: 1 addition & 0 deletions settings.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
rootProject.name = "MonsterUtilities"
2 changes: 1 addition & 1 deletion src/archive/Downloader.kt
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ class DownloaderSwing : BasePanel() {
}

init {
launch {
GlobalScope.launch {
logger.fine("DownloadWorker started")

var limit = LIMIT.int
Expand Down
91 changes: 91 additions & 0 deletions src/main/xerus/monstercat/Logging.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
package xerus.monstercat

import ch.qos.logback.classic.Level
import ch.qos.logback.classic.LoggerContext
import ch.qos.logback.classic.encoder.PatternLayoutEncoder
import ch.qos.logback.classic.filter.ThresholdFilter
import ch.qos.logback.classic.spi.Configurator
import ch.qos.logback.classic.spi.ILoggingEvent
import ch.qos.logback.core.ConsoleAppender
import ch.qos.logback.core.FileAppender
import ch.qos.logback.core.spi.ContextAwareBase
import kotlinx.coroutines.GlobalScope
import kotlinx.coroutines.launch
import mu.KotlinLogging
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import xerus.ktutil.currentSeconds
import xerus.ktutil.getStackTraceString
import java.io.File

private val logDir: File
get() = cacheDir.resolve("logs").apply { mkdirs() }
private val logFile = logDir.resolve("log${currentSeconds()}.txt")
private var logLevel: Level = Level.WARN

internal fun initLogging(args: Array<String>) {
args.indexOf("--loglevel").takeIf { it > -1 }?.let {
logLevel = args.getOrNull(it + 1)?.let { Level.toLevel(it, null) } ?: run {
println("WARNING: Loglevel argument given without a valid value! Use one of {OFF, ERROR, WARN, INFO, DEBUG, TRACE, ALL}")
return@let
}
}
Thread.setDefaultUncaughtExceptionHandler { thread, ex ->
LoggerFactory.getLogger(Logger.ROOT_LOGGER_NAME).warn("Uncaught exception in $thread: ${ex.getStackTraceString()}")
}
val logger = KotlinLogging.logger { }
logger.info("Console loglevel: $logLevel")
logger.info("Logging to $logFile")
GlobalScope.launch {
val logs = logDir.listFiles()
if (logs.size > 10) {
logs.asSequence().sortedByDescending { it.name }.drop(5).filter {
val timestamp = it.nameWithoutExtension.substring(3).toIntOrNull()
?: return@filter true
timestamp + 200_000 < currentSeconds()
}.also {
val count = it.count()
if (count > 0)
logger.debug("Deleting $count old logs")
}.forEach { it.delete() }
}
}
}

internal class LogbackConfigurator : ContextAwareBase(), Configurator {

override fun configure(lc: LoggerContext) {

val encoder = PatternLayoutEncoder().apply {
context = lc
pattern = "%d{HH:mm:ss} [%-25.25thread] %-5level %-30logger{30} %msg%n"
start()
}

val consoleAppender = ConsoleAppender<ILoggingEvent>().apply {
name = "console"
context = lc
this.encoder = encoder
addFilter(ThresholdFilter().apply {
setLevel(logLevel.toString())
start()
})
start()
}

val fileAppender = FileAppender<ILoggingEvent>().apply {
name = "file"
file = logFile.toString()
context = lc
this.encoder = encoder
start()
}

val rootLogger = lc.getLogger(Logger.ROOT_LOGGER_NAME)
if (logLevel.levelInt < Level.DEBUG_INT)
rootLogger.level = logLevel
rootLogger.addAppender(consoleAppender)
rootLogger.addAppender(fileAppender)
}

}
Loading

0 comments on commit 106ad4c

Please sign in to comment.