initial commit

This commit is contained in:
Tanishq Dubey 2022-07-31 14:44:25 -04:00
commit 8d6448a952
7 changed files with 467 additions and 0 deletions

160
.gitignore vendored Normal file
View File

@ -0,0 +1,160 @@
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class
# C extensions
*.so
# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST
# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec
# Installer logs
pip-log.txt
pip-delete-this-directory.txt
# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/
# Translations
*.mo
*.pot
# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal
# Flask stuff:
instance/
.webassets-cache
# Scrapy stuff:
.scrapy
# Sphinx documentation
docs/_build/
# PyBuilder
.pybuilder/
target/
# Jupyter Notebook
.ipynb_checkpoints
# IPython
profile_default/
ipython_config.py
# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version
# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock
# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock
# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/
# Celery stuff
celerybeat-schedule
celerybeat.pid
# SageMath parsed files
*.sage.py
# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/
# Spyder project settings
.spyderproject
.spyproject
# Rope project settings
.ropeproject
# mkdocs documentation
/site
# mypy
.mypy_cache/
.dmypy.json
dmypy.json
# Pyre type checker
.pyre/
# pytype static type analyzer
.pytype/
# Cython debug symbols
cython_debug/
# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

11
Dockerfile Normal file
View File

@ -0,0 +1,11 @@
FROM python:buster
WORKDIR /usr/src/app
COPY requirements.txt ./
RUN pip install --no-cache-dir -r requirements.txt
copy . .
CMD ["python", "./main.py"]

7
README.md Normal file
View File

@ -0,0 +1,7 @@
# IDC - InterDimensional Cable
> The Interdimensional Cable is a cable box invented by Rick that gives access to television shows across every dimension.
Interdimensional Cable is a format consisting of short video clips that are perceived to be alien. The subreddit /r/interdimensionalcable is where enjoyers of this format find and post such videos.
This app shuffles the top /r/interdimensionalcable posts of the week (refreshed every hour) and continously plays them on https://idc.dws.rip.

99
main.py Normal file
View File

@ -0,0 +1,99 @@
import json
import os.path
import random
import time
import requests
from flask import Flask, render_template
from flask_apscheduler import APScheduler
URL = "https://www.reddit.com/r/InterdimensionalCable/top.json?limit=100&t=week"
scheduler = APScheduler()
v = []
def getRedditData(url):
resp = requests.get(url)
text = resp.text
code = resp.status_code
while code == 429:
print("waiting for timeout to end ...")
time.sleep(2)
resp = requests.get(url)
text = resp.text
code = resp.status_code
data = json.loads(text)
token = data["data"]["after"]
ret = []
for post in data["data"]["children"]:
turl = post["data"]["url_overridden_by_dest"]
if "youtu.be" in turl:
turl = turl.replace("https://youtu.be/", "https://www.youtube.com/watch?v=")
if "m.youtube.com" in turl:
turl = turl.replace(
"https://m.youtube.com/embed", "https://www.youtube.com/watch?v="
)
turl = turl.replace("watch?v=", "embed/")
turl = turl + "?autoplay=1&enablejsapi=1"
ret.append(turl)
return ret, token
def doPages(numPages):
token = ""
vids = []
for i in range(numPages):
if i == 0:
v, t = getRedditData(URL)
vids = vids + v
token = t
time.sleep(2)
v, t = getRedditData(URL + f"&after={token}")
vids = vids + v
print(f"got page {i}...")
return vids
@scheduler.task("interval", id="do_job_1", minutes=60, misfire_grace_time=900)
def job1():
global v
doFetch = False
pexist = os.path.exists("temp.json")
if pexist:
print("temp.json exists")
sec = os.path.getmtime("temp.json")
now = time.time()
if now - sec > 600:
doFetch = True
else:
doFetch = True
if doFetch:
print("stale or no file, fetching...")
v = doPages(2)
with open("temp.json", "w") as f:
json.dump(v, f)
else:
print("fresh file, not fetching...")
with open("temp.json", "r") as f:
v = json.load(f)
app = Flask(__name__)
scheduler.init_app(app)
scheduler.start()
job1()
@app.route("/")
def hello_world():
global v
random.shuffle(v)
return render_template("index.html", vids=json.dumps(v))
if __name__ == "__main__":
app.run(host="0.0.0.0", port=8080)

3
requirements.txt Normal file
View File

@ -0,0 +1,3 @@
APScheduler==3.9.1
requests==2.26.0
Flask==2.0.3

BIN
static/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

187
templates/index.html Normal file
View File

@ -0,0 +1,187 @@
<!DOCTYPE html>
<html>
<head>
<title>InterdimensionalCable</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<script
src="https://code.jquery.com/jquery-2.2.4.min.js"
integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
crossorigin="anonymous"></script>
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
<style type="text/css">
body, html
{
margin: 0; padding: 0; height: 100%; overflow: hidden;
}
#content
{
position:absolute; left: 0; right: 0; bottom: 0; top: 0px;
}
#player
{
width: 100%;
height: 100%;
}
.hidden {
display: none;
}
.btn{
border-radius: 10px;
margin:1em;
padding:1em 2em;
transition:all 125ms ease;
text-transform:uppercase;
color:#fff;
font-weight:500;
border:1px solid #d1d1d1
}
.btn:active{ transform:scale(.9) }
.btn:focus{ outline:none }
.btn:active,
.btn:hover,
.btn:focus{ color:#fff }
.btn:active:focus,
.btn:active:hover{ outline:none }
.btn:active,
.btn:active:hover,
.btn:active:focus{ transform:scale(.9) }
.btn:focus{ transform:scale(1) }
.btn-danger {
background-color:#FF0000;
border:1px solid #FF0000;
box-shadow:0 2px 20px rgba(246,77,76,0.57)
}
.btn-danger:active{
box-shadow:0 2px 20px rgba(246,77,76,0.57)
}
.btn-danger:hover{
background-color:#ff2e2e;
border:1px solid #ff2e2e;
box-shadow:0 2px 20px rgba(246,77,76,0.67)
}
.btn-danger:active,
.btn-danger:focus,
.btn-danger:active:hover,
.btn-danger:active:focus{
border:1px solid #ff2e2e;
background-color:#ff2e2e
}
#buttonl {
z-index: 101;
position: absolute;
width: 50px;
height: 50px;
left: 3%;
top: 50%;
}
#buttonr {
z-index: 101;
position: absolute;
width: 50px;
height: 50px;
right: 3%;
top: 50%;
}
</style>
</head>
<body>
<script type="text/javascript">
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
var idx=0;
var justHidden = false;
var videos = {{vids|safe}};
var player;
function onYouTubeIframeAPIReady() {
player = new YT.Player('player', {
events: {
'onReady': function(){},
'onStateChange': onPlayerStateChange
}
});
}
function onPlayerStateChange(event) {
if (event.data == YT.PlayerState.ENDED) {
idx = idx + 1;
if (idx == videos.length) {
idx = 0;
}
$('#player').attr('src', videos[idx]);
player = new YT.Player('player', {
events: {
'onReady': function(){},
'onStateChange': onPlayerStateChange
}
});
}
}
$(document).ready(function() {
var j;
$('#player').attr('src', videos[idx]);
$(document).mousemove(function() {
if (!justHidden) {
justHidden = false;
clearTimeout(j);
$('.btn').removeClass('hidden');
j = setTimeout('hide();', 1000);
}
});
$('#buttonl').click(function(){
idx = idx - 1;
if (idx < 0) {
idx = videos.length - 1;
}
$('#player').attr('src', videos[idx]);
player = new YT.Player('player', {
events: {
'onReady': function(){},
'onStateChange': onPlayerStateChange
}
});
});
$('#buttonr').click(function(){
idx = idx + 1;
if (idx == videos.length) {
idx = 0;
}
$('#player').attr('src', videos[idx]);
player = new YT.Player('player', {
events: {
'onReady': function(){},
'onStateChange': onPlayerStateChange
}
});
});
});
function hide() {
$('.btn').addClass('hidden');
}
</script>
<div id="content">
<iframe
id="player"
src="https://www.youtube.com/embed/tgbNymZ7vqY?autoplay=1" frameborder="0" allow="autoplay">
</iframe>
<button id="buttonl" class="btn btn-danger hidden"><i class="fa fa-angle-left"></i></button>
<button id="buttonr" class="btn btn-danger hidden"><i class="fa fa-angle-right"></i></button>
</div>
</body>
</html>