GithubHelp home page GithubHelp logo

laterball's Introduction

banner

▶️ Laterball

This is the source for the Laterball football match watchability rating generator running at laterball.com

What is Laterball?

I like to watch replays of football games on demand, but hate having the score spoiled for me, so I always wanted to know which game is worth spending time watching without knowing the score.

So I built laterball.com ↠

It calculates watchability ratings for the latest EPL and Champions League games, without spoilers!

How does it work?

The Ktor server returns static HTML to the configured routes (one for each supported league and an about page). When a request is received, the server calculates the ratings for all matches within the past 7 days based on match statistics, events and odds. Match data is fetched from API-Football and cached to minimise API requests.

Twitter bot

A Twitter bot tweets the ratings for 4- and 5-star games (maximum one per kickoff time, maximum one every 4 hours) to @laterball

Hosting and deployment

(Deprecated) This repository contains a GitHub action for deploying to Google App Engine, provided the appropriate secrets are set in the repository. The required secrets are defined in the application.conf file. The action runs every time a new tag is pushed to main.

Future work

Better "Where to watch" links

Currently, clicking on the ↠ icon next to a match just Googles where to watch the match streaming on demand. Ideally, this would take the user to the official streaming provider for their local region.

User ratings

Crowdsourcing ratings could improve rating accuracy, and could be weighted against the statistically-determined ratings

Algorithm improvements

Accounting for:

  • xG
  • Relative league position/importance of match
  • Timing of goals (late winner etc)

Hosting

Laterball is currently hosted on a single Linode instance. It makes use of an in-memory cache to reduce DB roundtrips, and a Mongo database to persist data between restarts. If the application ever needs to support horizontal scaling, a more robust centralised caching mechanism would be required.

laterball's People

Contributors

y-a-n-n avatar

Stargazers

Jared avatar Tyson Ni avatar Arne Schrade avatar Sergio Castaño Sánchez avatar Dobrosław Żybort avatar Kai Weber avatar Michael Harris avatar

Watchers

 avatar  avatar

laterball's Issues

2022-07-30 21:21:32.046 [Thread-0] DEBUG i.n.u.internal.NativeLibraryLoader - Unable to load the library 'netty_transport_native_epoll_x86_64', trying other loading mechanism.

java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1124)
at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.netty.util.internal.NativeLibraryLoader$1.run(NativeLibraryLoader.java:371)
at java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.NativeLibraryLoader.loadLibraryByHelper(NativeLibraryLoader.java:363)
at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:341)
at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:136)
at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:250)
at io.netty.channel.epoll.Native.(Native.java:69)
at io.netty.channel.epoll.Epoll.(Epoll.java:39)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create(NettyApplicationEngine.kt:212)
at io.ktor.server.netty.NettyApplicationEngine$workerEventGroup$2.invoke(NettyApplicationEngine.kt:89)
at io.ktor.server.netty.NettyApplicationEngine$workerEventGroup$2.invoke(NettyApplicationEngine.kt:26)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.server.netty.NettyApplicationEngine.getWorkerEventGroup(NettyApplicationEngine.kt)
at io.ktor.server.netty.NettyApplicationEngine.access$getWorkerEventGroup$p(NettyApplicationEngine.kt:26)
at io.ktor.server.netty.NettyApplicationEngine$engineDispatcherWithShutdown$2.invoke(NettyApplicationEngine.kt:109)
at io.ktor.server.netty.NettyApplicationEngine$engineDispatcherWithShutdown$2.invoke(NettyApplicationEngine.kt:26)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.server.netty.NettyApplicationEngine.getEngineDispatcherWithShutdown(NettyApplicationEngine.kt)
at io.ktor.server.netty.NettyApplicationEngine.stop(NettyApplicationEngine.kt:167)
at io.ktor.server.engine.ApplicationEngineJvmKt.stop(ApplicationEngineJvm.kt:18)
at io.ktor.server.netty.EngineMain$main$1.invoke(EngineMain.kt:24)
at io.ktor.server.netty.EngineMain$main$1.invoke(EngineMain.kt:14)
at io.ktor.server.engine.ShutdownHook.run(ShutdownHook.kt:39)
2022-07-30 21:21:32.048 [Thread-0] DEBUG i.n.u.internal.NativeLibraryLoader - netty_transport_native_epoll_x86_64 cannot be loaded from java.library.path, now trying export to -Dio.netty.native.workdir: /tmp
java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1124)
at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38)
at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:351)
at io.netty.util.internal.NativeLibraryLoader.load(NativeLibraryLoader.java:136)
at io.netty.channel.epoll.Native.loadNativeLibrary(Native.java:250)
at io.netty.channel.epoll.Native.(Native.java:69)
at io.netty.channel.epoll.Epoll.(Epoll.java:39)
at io.ktor.server.netty.EventLoopGroupProxy$Companion.create(NettyApplicationEngine.kt:212)
at io.ktor.server.netty.NettyApplicationEngine$workerEventGroup$2.invoke(NettyApplicationEngine.kt:89)
at io.ktor.server.netty.NettyApplicationEngine$workerEventGroup$2.invoke(NettyApplicationEngine.kt:26)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.server.netty.NettyApplicationEngine.getWorkerEventGroup(NettyApplicationEngine.kt)
at io.ktor.server.netty.NettyApplicationEngine.access$getWorkerEventGroup$p(NettyApplicationEngine.kt:26)
at io.ktor.server.netty.NettyApplicationEngine$engineDispatcherWithShutdown$2.invoke(NettyApplicationEngine.kt:109)
at io.ktor.server.netty.NettyApplicationEngine$engineDispatcherWithShutdown$2.invoke(NettyApplicationEngine.kt:26)
at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
at io.ktor.server.netty.NettyApplicationEngine.getEngineDispatcherWithShutdown(NettyApplicationEngine.kt)
at io.ktor.server.netty.NettyApplicationEngine.stop(NettyApplicationEngine.kt:167)
at io.ktor.server.engine.ApplicationEngineJvmKt.stop(ApplicationEngineJvm.kt:18)
at io.ktor.server.netty.EngineMain$main$1.invoke(EngineMain.kt:24)
at io.ktor.server.netty.EngineMain$main$1.invoke(EngineMain.kt:14)
at io.ktor.server.engine.ShutdownHook.run(ShutdownHook.kt:39)
Suppressed: java.lang.UnsatisfiedLinkError: no netty_transport_native_epoll_x86_64 in java.library.path
at java.lang.ClassLoader.loadLibrary(ClassLoader.java:1860)
at java.lang.Runtime.loadLibrary0(Runtime.java:871)
at java.lang.System.loadLibrary(System.java:1124)
at io.netty.util.internal.NativeLibraryUtil.loadLibrary(NativeLibraryUtil.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at io.netty.util.internal.NativeLibraryLoader$1.run(NativeLibraryLoader.java:371)
at java.security.AccessController.doPrivileged(Native Method)
at io.netty.util.internal.NativeLibraryLoader.loadLibraryByHelper(NativeLibraryLoader.java:363)
at io.netty.util.internal.NativeLibraryLoader.loadLibrary(NativeLibraryLoader.java:341)
... 19 common frames omitted

ch.qos.logback.core.util.DynamicClassLoadingException: Failed to instantiate type com.google.cloud.logging.logback.LoggingAppender

Caused by: java.lang.ClassNotFoundException: com.google.cloud.logging.logback.LoggingAppender
at at java.net.URLClassLoader.findClass(URLClassLoader.java:387)
at at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
at at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:352)
at at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
at at ch.qos.logback.core.util.OptionHelper.instantiateByClassNameAndParameter(OptionHelper.java:56)
at ... 21 common frames omitted

Externalize league ID configuration

League IDs are currently hardcoded, meaning the app needs to be rebuild every season. These should be put somewhere external like an S3 bucket or a configuration file read upon request (not just at startup time)

Dockerize it

Create dockerfile and Github action to deploy as docker instance to linode

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.