Skip to content

Commit

Permalink
make flairsToExclude dynamic, separate SubmissionParser from RedditSe…
Browse files Browse the repository at this point in the history
…rvice
  • Loading branch information
AndreasVolkmann committed May 21, 2018
1 parent 6fadd99 commit 0b8cc2f
Show file tree
Hide file tree
Showing 32 changed files with 246 additions and 175 deletions.
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,9 @@ apply plugin: 'kotlin'

task fatJar(type: Jar) {
manifest {
attributes 'Compile-Title': 'spotify-dynamic-reddit-playlist',
attributes 'Compile-Title': 'spottit',
'Compile-Version': version,
'Main-Class': 'me.avo.spotify.dynamic.reddit.playlist.MainKt'
'Main-Class': 'me.avo.spottit.MainKt'
}
baseName = project.name
from { configurations.compile.collect { it.isDirectory() ? it : zipTree(it) } }
Expand Down
12 changes: 12 additions & 0 deletions example_config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,15 @@ playlists:
subreddit: trance
sort: TOP
timePeriod: ALL

# When a reddit post has any of the following flairs, it will be excluded
flairsToExclude:
- Mix
- Liveset
- Radio
- Show
- Album
- Upcoming
- AMA
- Concluded
- RIP
2 changes: 1 addition & 1 deletion settings.gradle
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
rootProject.name = 'spotify-dynamic-reddit-playlist'
rootProject.name = 'spottit'

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
package me.avo.spotify.dynamic.reddit.playlist
package me.avo.spottit

import com.github.salomonbrys.kodein.instance
import me.avo.spotify.dynamic.reddit.playlist.config.Arguments
import me.avo.spotify.dynamic.reddit.playlist.config.kodein
import me.avo.spotify.dynamic.reddit.playlist.controller.DynamicPlaylistController
import me.avo.spottit.config.Arguments
import me.avo.spottit.config.kodein
import me.avo.spottit.controller.DynamicPlaylistController

fun main(args: Array<String>) {
val arguments = Arguments(args)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.config
package me.avo.spottit.config

import com.beust.jcommander.JCommander
import com.beust.jcommander.Parameter
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,14 @@
package me.avo.spotify.dynamic.reddit.playlist.config

import com.github.salomonbrys.kodein.*
import me.avo.spotify.dynamic.reddit.playlist.controller.DynamicPlaylistController
import me.avo.spotify.dynamic.reddit.playlist.model.Playlist
import me.avo.spotify.dynamic.reddit.playlist.service.*
package me.avo.spottit.config

import com.github.salomonbrys.kodein.Kodein
import com.github.salomonbrys.kodein.bind
import com.github.salomonbrys.kodein.instance
import com.github.salomonbrys.kodein.singleton
import me.avo.spottit.controller.DynamicPlaylistController
import me.avo.spottit.model.RedditCredentials
import me.avo.spottit.service.SpotifyAuthService
import me.avo.spottit.service.SpotifyService
import me.avo.spottit.service.SpotifyServiceImpl
import java.util.*

val kodein = Kodein {
Expand All @@ -17,7 +22,7 @@ val kodein = Kodein {
DynamicPlaylistController(
spotifyAuthService = instance(),
spotifyService = instance(),
redditServiceFactory = factory()
redditCredentials = instance()
)
}

Expand All @@ -33,12 +38,11 @@ val kodein = Kodein {
)
}

bind<RedditService>() with factory { playlist: Playlist ->
RedditServiceImpl(
bind<RedditCredentials>() with singleton {
RedditCredentials(
clientId = getProperty("reddit-clientId"),
clientSecret = getProperty("reddit-clientSecret"),
deviceName = getProperty("deviceName"),
playlist = playlist
deviceName = getProperty("deviceName")
)
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,24 @@
package me.avo.spotify.dynamic.reddit.playlist.controller
package me.avo.spottit.controller

import com.wrapper.spotify.model_objects.specification.Track
import me.avo.spotify.dynamic.reddit.playlist.config.kodein
import me.avo.spotify.dynamic.reddit.playlist.model.Playlist
import me.avo.spotify.dynamic.reddit.playlist.server.prepareServer
import me.avo.spotify.dynamic.reddit.playlist.service.RedditService
import me.avo.spotify.dynamic.reddit.playlist.service.SpotifyAuthService
import me.avo.spotify.dynamic.reddit.playlist.service.SpotifyService
import me.avo.spotify.dynamic.reddit.playlist.service.SpotifyServiceImpl
import me.avo.spotify.dynamic.reddit.playlist.util.YamlConfigReader
import me.avo.spotify.dynamic.reddit.playlist.util.openUrlInBrowser
import me.avo.spottit.config.kodein
import me.avo.spottit.model.Configuration
import me.avo.spottit.model.Playlist
import me.avo.spottit.model.RedditCredentials
import me.avo.spottit.server.prepareServer
import me.avo.spottit.service.RedditServiceImpl
import me.avo.spottit.service.SpotifyAuthService
import me.avo.spottit.service.SpotifyService
import me.avo.spottit.util.YamlConfigReader
import me.avo.spottit.util.openUrlInBrowser
import org.slf4j.LoggerFactory
import java.io.File
import java.util.concurrent.TimeUnit

class DynamicPlaylistController(
private val spotifyAuthService: SpotifyAuthService,
private val spotifyService: SpotifyService,
private val redditServiceFactory: (Playlist) -> RedditService
private val redditCredentials: RedditCredentials
) {

fun updatePlaylists(configPath: String) {
Expand All @@ -36,13 +37,15 @@ class DynamicPlaylistController(
server.stop(timeout, timeout, TimeUnit.SECONDS)
}

configuration.playlists.forEach(::processPlaylist)
configuration.playlists.forEach {
processPlaylist(configuration, it)
}
}

private fun processPlaylist(playlist: Playlist) {
private fun processPlaylist(configuration: Configuration, playlist: Playlist) {
logger.info("Processing playlist ${playlist.id}")
//val postFilter = playlist.postFilters.first()
val redditService = redditServiceFactory(playlist)
val redditService = RedditServiceImpl(playlist, configuration.flairsToExclude, redditCredentials)

val foundTracks = mutableListOf<Track>()

Expand Down
7 changes: 7 additions & 0 deletions src/main/kotlin/me/avo/spottit/model/Configuration.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package me.avo.spottit.model

data class Configuration(
val userId: String,
val playlists: List<Playlist>,
val flairsToExclude: List<String>
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.model
package me.avo.spottit.model

import net.dean.jraw.models.SubredditSort
import net.dean.jraw.models.TimePeriod
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.model
package me.avo.spottit.model

import net.dean.jraw.models.SubredditSort
import net.dean.jraw.models.TimePeriod
Expand Down
7 changes: 7 additions & 0 deletions src/main/kotlin/me/avo/spottit/model/RedditCredentials.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package me.avo.spottit.model

data class RedditCredentials(
val clientId: String,
val clientSecret: String,
val deviceName: String
)
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.model
package me.avo.spottit.model

data class RedditTrack(
val artist: String,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.server
package me.avo.spottit.server

import io.ktor.http.HttpStatusCode

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.server
package me.avo.spottit.server

import com.github.salomonbrys.kodein.Kodein
import com.github.salomonbrys.kodein.instance
Expand All @@ -8,7 +8,7 @@ import io.ktor.response.respond
import io.ktor.routing.Routing
import io.ktor.routing.get
import io.ktor.routing.route
import me.avo.spotify.dynamic.reddit.playlist.service.SpotifyAuthService
import me.avo.spottit.service.SpotifyAuthService

fun Routing.setup(kodein: Kodein) {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.server
package me.avo.spottit.server

import com.github.salomonbrys.kodein.Kodein
import freemarker.cache.ClassTemplateLoader
Expand All @@ -16,10 +16,13 @@ import io.ktor.server.engine.ApplicationEngine
import io.ktor.server.engine.ShutDownUrl
import io.ktor.server.engine.embeddedServer
import io.ktor.server.netty.Netty
import me.avo.spotify.dynamic.reddit.playlist.config.Dependency
import me.avo.spottit.config.Dependency
import org.slf4j.event.Level

fun prepareServer(kodein: Kodein): ApplicationEngine = embeddedServer(Netty, 5000, module = main(kodein))
fun prepareServer(kodein: Kodein): ApplicationEngine = embeddedServer(Netty, 5000, module = main(
kodein
)
)

fun main(kodein: Kodein): Application.() -> Unit = {
install(Routing) {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.server
package me.avo.spottit.server

import io.ktor.freemarker.FreeMarkerContent

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package me.avo.spotify.dynamic.reddit.playlist.service
package me.avo.spottit.service

import me.avo.spotify.dynamic.reddit.playlist.model.RedditTrack
import me.avo.spottit.model.RedditTrack

interface RedditService {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package me.avo.spotify.dynamic.reddit.playlist.service
package me.avo.spottit.service

import me.avo.spotify.dynamic.reddit.playlist.model.Playlist
import me.avo.spotify.dynamic.reddit.playlist.model.RedditTrack
import me.avo.spottit.model.Playlist
import me.avo.spottit.model.RedditCredentials
import me.avo.spottit.model.RedditTrack
import me.avo.spottit.util.SubmissionParser
import net.dean.jraw.http.OkHttpNetworkAdapter
import net.dean.jraw.http.UserAgent
import net.dean.jraw.models.Submission
Expand All @@ -15,23 +17,19 @@ import org.slf4j.LoggerFactory
import java.util.*

class RedditServiceImpl(
clientId: String,
clientSecret: String,
deviceName: String,
private val playlist: Playlist
private val playlist: Playlist,
private val flairsToExclude: List<String>,
redditCredentials: RedditCredentials
) : RedditService {

private val reddit by lazy {
val userAgent = UserAgent("bot", "me.avo.spotify.dynamic.reddit.playlist", "v0.1", "idajuul")
val (clientId, clientSecret, deviceName) = redditCredentials
val userAgent = UserAgent("bot", "me.avo.spottit", "v0.2", "idajuul")
val adapter = OkHttpNetworkAdapter(userAgent)
val credentials = Credentials.userless(clientId, clientSecret, UUID.fromString(deviceName))
OAuthHelper.automatic(adapter, credentials)
}

private lateinit var paginator: Paginator<Submission>

private var currentSize = 0

override var isDone = false
private set

Expand All @@ -49,41 +47,31 @@ class RedditServiceImpl(
}
page
.filterNot { it.isSelfPost }
.filterNot { it.linkFlairText in flairsToExclude } // TODO make dynamic
.filterNot { it.linkFlairText in flairsToExclude }
.mapTo(validPosts) { it }
}

if (paginator.pageNumber >= maxPage || currentSize >= playlist.maxSize) {
stop()
}

return validPosts.map(::submissionToRedditTrack)
return validPosts.map(::parse)
}

private fun submissionToRedditTrack(submission: Submission): RedditTrack {
val fixedTitle = submission.title.fixChars()
val extraInformation = fixedTitle.getExtraInformation()
val mix = fixedTitle.getMix()
val fullTitle = (extraInformation + mix).fold(fixedTitle) { acc, s -> acc.replace(s, "").trim() }
return RedditTrack(
artist = fullTitle.substringBefore("-").trim(),
title = fullTitle.substringAfter("-").trim(),
mix = mix.firstOrNull()?.removePrefixSuffix(),
extraInformation = (extraInformation + mix.drop(1)).map { it.removePrefixSuffix() },
flair = submission.linkFlairText
)
override fun update(amountTaken: Int) {
logger.info("Adding $amountTaken tracks")
currentSize += amountTaken
}

private lateinit var paginator: Paginator<Submission>

private var currentSize = 0

private fun stop() {
logger.info("Reddit pagination done")
isDone = true
}

override fun update(amountTaken: Int) {
logger.info("Adding $amountTaken tracks")
currentSize += amountTaken
}

private fun initializePaginator() {
if (!::paginator.isInitialized) {
val subreddit = reddit.subreddit(playlist.subreddit)
Expand All @@ -98,27 +86,9 @@ class RedditServiceImpl(

private val maxPage = 20

private val flairsToExclude = listOf("Mix", "Liveset", "Radio Show", "Album", "Upcoming AMA", "Concluded", "RIP")

private fun String.fixChars() = replace("&amp;", "&")

private fun String.getMix() = getEnclosedText("(", ")")

private fun String.getExtraInformation(): List<String> = getEnclosedText("[", "]")

private fun String.getEnclosedText(start: String, end: String) = Regex("\\$start.*?\\$end")
.findAll(this)
.map(MatchResult::value)
.toList()

private val prefixSuffixChars = listOf(
"(" to ")",
"[" to "]"
)

private fun String.removePrefixSuffix(): String =
prefixSuffixChars.fold(this) { acc, (prefix, suffix) -> acc.removeSurrounding(prefix, suffix) }

private val logger = LoggerFactory.getLogger(this::class.java)

private fun parse(submission: Submission): RedditTrack =
SubmissionParser.parse(submission.title, submission.linkFlairText)

}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package me.avo.spotify.dynamic.reddit.playlist.service
package me.avo.spottit.service

import com.wrapper.spotify.SpotifyApi
import com.wrapper.spotify.SpotifyHttpManager
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package me.avo.spotify.dynamic.reddit.playlist.service
package me.avo.spottit.service

import com.wrapper.spotify.model_objects.specification.Track
import me.avo.spotify.dynamic.reddit.playlist.model.RedditTrack
import me.avo.spottit.model.RedditTrack

interface SpotifyService {

Expand Down
Loading

0 comments on commit 0b8cc2f

Please sign in to comment.