Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

API to create the info needed #19

Merged
merged 4 commits into from
Apr 4, 2023
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
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@
![PyPI - License](https://img.shields.io/pypi/l/marketwatch)
![PyPI - Downloads](https://img.shields.io/pypi/dm/marketwatch)
![GitHub last commit](https://img.shields.io/github/last-commit/antoinebou12/marketwatch)
[![Publish 📦 to PyPI](https://github.com/antoinebou12/marketwatch/actions/workflows/python-publish.yml/badge.svg?branch=main)](https://github.com/antoinebou12/marketwatch/actions/workflows/python-publish.yml)
[![Python Test and Build](https://github.com/antoinebou12/marketwatch/actions/workflows/python-test.yml/badge.svg)](https://github.com/antoinebou12/marketwatch/actions/workflows/python-test.yml)
![Coverage](https://raw.githubusercontent.com/antoinebou12/marketwatch/main/.github/badge/coverage.svg)

Expand Down
3 changes: 3 additions & 0 deletions api/.dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.dockerignore
Dockerfile
__pycache__
12 changes: 12 additions & 0 deletions api/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
# syntax=docker/dockerfile:1

FROM python:3.10.0

WORKDIR /api

COPY requirements.txt requirements.txt
RUN pip3 install -r requirements.txt --no-cache-dir

COPY api/ .

CMD ["unicorn", "marketwatch:app", "--bind", "0.0.0.0:5000", "--workers", "4", "--threads", "2"]
1 change: 1 addition & 0 deletions api/Procfile
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
web: uvicorn app.marketwatch:app --reload
Empty file added api/api/__init__.py
Empty file.
74 changes: 74 additions & 0 deletions api/api/app.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
"""Marketwatch API"""

import os
from fastapi import FastAPI, Request
from fastapi.responses import HTMLResponse, FileResponse
from fastapi.templating import Jinja2Templates

from marketwatch import MarketWatch


MARKETWATCH_USERNAME = os.environ.get("MARKETWATCH_USERNAME")
MARKETWATCH_PASSWORD = os.environ.get("MARKETWATCH_PASSWORD")
MARKETWATCH_GAME_ID = os.environ.get("MARKETWATCH_GAME_ID")

app = FastAPI()

templates = Jinja2Templates(directory="templates")


@app.get("/game/{game_id}", response_class=HTMLResponse)
async def game(request: Request, game_id: str = MARKETWATCH_GAME_ID):
"""
Get the current marketwatch data

:param request: The request object
:return: The marketwatch data
"""
mw = MarketWatch(MARKETWATCH_USERNAME, MARKETWATCH_PASSWORD)
data = mw.get_game(game_id=game_id)
return templates.TemplateResponse("game.html.j2", {"request": request, "data": data})

@app.get("/portfolio/{game_id}", response_class=HTMLResponse)
async def portfolio(request: Request, game_id: str = MARKETWATCH_GAME_ID):
"""
Get the current marketwatch data

:param request: The request object
:return: The marketwatch data
"""
mw = MarketWatch(MARKETWATCH_USERNAME, MARKETWATCH_PASSWORD)
data = mw.get_portfolio(game_id=game_id)
return templates.TemplateResponse("porfolio.html.j2", {"request": request, "data": data})

@app.get("/leaderboard/{game_id}", response_class=HTMLResponse)
async def leaderboard(request: Request, game_id: str = MARKETWATCH_GAME_ID):
"""
Get the current marketwatch data

:param request: The request object
:return: The marketwatch data
"""
mw = MarketWatch(MARKETWATCH_USERNAME, MARKETWATCH_PASSWORD)
data = mw.get_leaderboard(game_id=game_id)
return templates.TemplateResponse("leaderboard.html.j2", {"request": request, "data": data})


@app.get("/card/{game_id}", response_class=HTMLResponse)
async def card(request: Request, game_id: str = MARKETWATCH_GAME_ID):
"""
Get the current marketwatch data

:param request: The request object
:return: The marketwatch data
"""
mw = MarketWatch(MARKETWATCH_USERNAME, MARKETWATCH_PASSWORD)
game = mw.get_game(game_id=game_id)

return templates.TemplateResponse("card.html.j2", {"request": request, "data": game})



if __name__ == "__main__":
import uvicorn
uvicorn.run(app, host="0.0.0.0", port=5000)
32 changes: 32 additions & 0 deletions api/api/templates/card.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
<svg width="480" height="600" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">
<foreignObject width="480" height="600">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.7/tailwind.min.css">
<div xmlns="http://www.w3.org/1999/xhtml" class="container">
<div class="container mx-auto px-4 py-8 bg-gray-900">
<div class="bg-gray-800 rounded-lg shadow-lg p-6">
<h1 class="text-3xl font-bold text-white">{{ data.title }}</h1>
<p class="text-gray-400 mt-2">{{ data.time }}</p>
<p class="mt-4 mb-2"><a href="{{ data.url }}" class="text-blue-500 hover:text-blue-700">View game on MarketWatch</a></p>
<ul class="list-disc pl-4 text-white">
<li>Start date: {{ data.start_date }}</li>
<li>End date: {{ data.end_date }}</li>
<li>Number of players: {{ data.players }}</li>
<li>Game creator: {{ data.creator }}</li>
</ul>
<h2 class="text-xl font-bold text-white mt-6">Your current standings:</h2>
<ul class="list-disc pl-4 mt-2 text-white">
<li>Rank: {{ data.rank }}</li>
<li>Portfolio value: {{ data.portfolio_value }}</li>
<li>Gain percentage: {{ data.gain_percentage }}</li>
<li>Gain: {{ data.gain }}</li>
<li>Return: {{ data.return }}</li>
<li>Cash remaining: {{ data.cash_remaining }}</li>
<li>Buying power: {{ data.buying_power }}</li>
<li>Shorts reserve: {{ data.shorts_reserve }}</li>
<li>Cash borrowed: {{ data.cash_borrowed }}</li>
</ul>
</div>
</div>
</div>
</foreignObject>
</svg>
35 changes: 35 additions & 0 deletions api/api/templates/game.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<!DOCTYPE html>
<html>
<head>
<title>{{ data.title }}</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/tailwindcss/2.2.7/tailwind.min.css">
</head>
<body class="bg-gray-900">
<div class="container mx-auto px-4 py-8">
<div class="bg-gray-800 rounded-lg shadow-lg p-6">
<h1 class="text-3xl font-bold text-white">{{ data.title }}</h1>
<p class="text-gray-400 mt-2">{{ data.time }}</p>
<p class="mt-4 mb-2"><a href="{{ data.url }}" class="text-blue-500 hover:text-blue-700">View game on MarketWatch</a></p>
<ul class="list-disc pl-4 text-white">
<li>Start date: {{ data.start_date }}</li>
<li>End date: {{ data.end_date }}</li>
<li>Number of players: {{ data.players }}</li>
<li>Game creator: {{ data.creator }}</li>
</ul>
<h2 class="text-xl font-bold text-white mt-6">Your current standings:</h2>
<ul class="list-disc pl-4 mt-2 text-white">
<li>Rank: {{ data.rank }}</li>
<li>Portfolio value: {{ data.portfolio_value }}</li>
<li>Gain percentage: {{ data.gain_percentage }}</li>
<li>Gain: {{ data.gain }}</li>
<li>Return: {{ data.return }}</li>
<li>Cash remaining: {{ data.cash_remaining }}</li>
<li>Buying power: {{ data.buying_power }}</li>
<li>Shorts reserve: {{ data.shorts_reserve }}</li>
<li>Cash borrowed: {{ data.cash_borrowed }}</li>
</ul>
</div>

</div>
</body>
</html>
29 changes: 29 additions & 0 deletions api/api/templates/leaderboard.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<div class="bg-black rounded-lg overflow-hidden shadow-lg">
<div class="px-6 py-8">
<h1 class="text-3xl font-bold text-white">{{ data.game_id }} Leaderboard</h1>
<table class="table-auto w-full mt-8">
<thead>
<tr>
<th class="px-4 py-2 text-white">Rank</th>
<th class="px-4 py-2 text-white">Player</th>
<th class="px-4 py-2 text-white">Portfolio Value</th>
<th class="px-4 py-2 text-white">Gain Percentage</th>
<th class="px-4 py-2 text-white">Transactions</th>
<th class="px-4 py-2 text-white">Gain</th>
</tr>
</thead>
<tbody>
{% for player in data.players %}
<tr>
<td class="border px-4 py-2 text-white">{{ player.rank }}</td>
<td class="border px-4 py-2 text-white"><a href="{{ player.player_url }}" class="text-blue-500 hover:underline">{{ player.player }}</a></td>
<td class="border px-4 py-2 text-white">{{ player.portfolio_value }}</td>
<td class="border px-4 py-2 text-white">{{ player.gain_percentage }}</td>
<td class="border px-4 py-2 text-white">{{ player.transactions }}</td>
<td class="border px-4 py-2 text-white">{{ player.gain }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
40 changes: 40 additions & 0 deletions api/api/templates/portfolio.html.j2
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ data.game_id }} Leaderboard</title>
<!-- Include Tailwind CSS -->
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/tailwind.min.css" rel="stylesheet">
</head>
<body class="bg-gray-900">
<div class="container mx-auto px-4 py-8">
<div class="bg-gray-800 rounded-lg shadow-lg overflow-hidden">
<h1 class="text-3xl font-bold text-white bg-gray-900 px-4 py-2">{{ data.game_id }} Leaderboard</h1>
<table class="table-auto w-full mt-8">
<thead>
<tr>
<th class="px-4 py-2 text-white">Rank</th>
<th class="px-4 py-2 text-white">Player</th>
<th class="px-4 py-2 text-white">Portfolio Value</th>
<th class="px-4 py-2 text-white">Gain Percentage</th>
<th class="px-4 py-2 text-white">Transactions</th>
<th class="px-4 py-2 text-white">Gain</th>
</tr>
</thead>
<tbody>
{% for player in data.players %}
<tr>
<td class="border px-4 py-2">{{ player.rank }}</td>
<td class="border px-4 py-2"><a href="{{ player.player_url }}" class="text-blue-500 hover:underline">{{ player.player }}</a></td>
<td class="border px-4 py-2">{{ player.portfolio_value }}</td>
<td class="border px-4 py-2">{{ player.gain_percentage }}</td>
<td class="border px-4 py-2">{{ player.transactions }}</td>
<td class="border px-4 py-2">{{ player.gain }}</td>
</tr>
{% endfor %}
</tbody>
</table>
</div>
</div>
</body>
</html>
30 changes: 30 additions & 0 deletions api/app.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"name": "marketwatch",
"description": "Marketwatch is a web app that allows users to track their favorite stocks and view their performance over time.",
"scripts": {
"postdeploy": "gunicorn --workers=1 api.spotify:app"
},
"env": {
"MARKETWATCH_USERNAME": {
"required": true
},
"MARKETWATCH_PASSWORD": {
"required": true
},
"MARKETWATCH_GAME_ID": {
"required": true
}
},
"formation": {
"web": {
"quantity": 1
}
},
"addons": [],
"buildpacks": [
{
"url": "heroku/python"
}
],
"stack": "heroku-20"
}
10 changes: 10 additions & 0 deletions api/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
version: '3.8'
services:
spotify-readme:
build: .
ports:
- "5000:5000"
volumes:
- ./api:/api
volumes:
persistent:
5 changes: 5 additions & 0 deletions api/requirements.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fastapi
uvicorn
httpx
marketwatch
jinja2
71 changes: 71 additions & 0 deletions api/setup.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
# Deployment

## Environment variables

MARKETWATCH_USERNAME
MARKETWATCH_PASSWORD
MARKETWATCH_GAME_ID

## Deploy to Vercel

1. Fork this repository
2. Create a Vercel project and link it to your forked repository
3. Add the following environment variables in your Vercel project settings
4. Deploy the project

https://vercel.com/<YourName>/<ProjectName>/settings/environment-variables

## Deploy to Heroku

1. Create a Heroku application via the Heroku CLI or Heroku Dashboard
2. Connect the app with your GitHub repository and enable automatic builds
3. After the build is completed, start the Flask server by executing `heroku ps:scale web=1`
4. Alternatively, you can click the "Deploy to Heroku" button above to automatically start the deployment process
5. Add the following environment variables to your Heroku application:

[![Marketwatch](https://USER_NAME.vercel.app/api/marketwatch)](https://marketwatch.com/game/{ID})

## Run locally with Docker

1. Install Docker
2. Add the following environment variables
3. Open a terminal in the root folder of the repository and execute:

```bash
docker-compose up -d
```


4. Navigate to `http://localhost:5000/` in your web browser to access the service
5. To stop the service, execute:


```bash
docker-compose down
```


## Customization

### Hide the EQ bar

Remove the `#` in front of `contentBar` in line 81 of the current master to hide the EQ bar when you're not currently playing anything.

### Status String

Add a string saying either "Vibing to:" or "Last seen playing:".

### Change height

Change the `height` to `height + 40` (or whatever margin-top is set to).

### Theme Templates

If you want to change the widget theme, you can do so by changing the `current-theme` property in the `templates.json` file. The available themes are:

- light
- dark

If you wish to customize further, you can add your own customized `marketwatch.html.j2` file to the `templates` folder and add the theme and file name to the `templates` dictionary in the `templates.json` file.


8 changes: 8 additions & 0 deletions api/vercel.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"redirects": [
{
"source": "/",
"destination": "https://github.com/antoinebou12/marketwatch"
}
]
}
Loading