initial commit

pull/1/head
Kevin F 1 year ago
commit f895fe5348
  1. 4
      .gitignore
  2. 7
      CHANGELOG.md
  3. 2
      Makefile
  4. 66
      imgmine/__init__.py
  5. BIN
      imgmine/__pycache__/__init__.cpython-39.pyc
  6. BIN
      imgmine/__pycache__/config.cpython-39.pyc
  7. BIN
      imgmine/__pycache__/get.cpython-39.pyc
  8. 4
      imgmine/config.py
  9. 64
      imgmine/get.py
  10. 25
      imgmine/web/gallery.html
  11. 41
      imgmine/web/index.html
  12. 14
      imgmine/web/theme.css
  13. 3
      run.py
  14. 13
      run_tests.sh
  15. 7
      tests/test.py

4
.gitignore vendored

@ -0,0 +1,4 @@
venv/*
helloworld/__pycache__/*
testdata/*
.vscode/*

@ -0,0 +1,7 @@
# Changelog
This project uses Semantic Versioning
## 0.0.0
Initial release

@ -0,0 +1,2 @@
test:
./run_tests.sh

@ -0,0 +1,66 @@
from gevent import monkey
from gevent import sleep
monkey.patch_all()
from threading import Thread
from os import remove, mkdir, path
from shutil import rmtree
from glob import glob
from uuid import uuid4
from bottle import route, run
from bottle import static_file
from bottle import SimpleTemplate
from .get import get
from .config import IMAGE_CACHE, SINGLE_IMAGE_DELETE_AFTER_SECS, ALBUM_DELETE_AFTER_SECS, template_dir
def album(id):
req_id = str(uuid4())
req = IMAGE_CACHE
get("/a/" + id, req)
imgs = glob(req + "*")
for c, img in enumerate(imgs):
imgs[c] = img.replace(IMAGE_CACHE, '/')
with open(f'{template_dir}gallery.html', 'r') as img_view:
tpl = SimpleTemplate(img_view)
return tpl.render(imgs=imgs)
@route('/')
@route('')
def home():
return static_file("index.html", root=template_dir)
@route('/static/<file>')
def static(file=''):
return static_file(file, root=template_dir)
@route('/gallery/<id>')
def gallery(id=''):
return album(id)
@route('/a/<id>')
def gallery(id=''):
return album(id)
@route('/<img>')
def hello(img=''):
if not path.exists(IMAGE_CACHE + img):
get(img, IMAGE_CACHE)
return static_file(img, root=IMAGE_CACHE)
def start_server():
try:
rmtree(IMAGE_CACHE)
except FileNotFoundError:
pass
mkdir(IMAGE_CACHE)
run(server='gevent')

@ -0,0 +1,4 @@
IMAGE_CACHE = '/tmp/imgmine-imgur-images/'
SINGLE_IMAGE_DELETE_AFTER_SECS = 60
ALBUM_DELETE_AFTER_SECS = 120
template_dir = 'imgmine/web/'

@ -0,0 +1,64 @@
import sys
from shutil import rmtree
from os import remove
from threading import Thread
import requests
import bs4
from gevent import sleep
from .config import SINGLE_IMAGE_DELETE_AFTER_SECS, ALBUM_DELETE_AFTER_SECS
def delete_file(path):
sleep(SINGLE_IMAGE_DELETE_AFTER_SECS)
print('Erasing', path)
try:
remove(path)
except FileNotFoundError:
pass
def error(msg):
sys.stderr.write(msg + "\n")
sys.stderr.flush()
def get(url: str, write_dir: str, delete=True):
if not url.startswith('https://imgur.com/'):
url = 'https://imgur.com/' + url
found_url = ''
print('it not album', url)
album = False
if "gallery" in url:
url = url.replace("gallery", "a")
print('it album')
if "/a/" in url:
print('it album')
album = True
if not url.endswith("blog"):
url += "/layout/blog"
if not album:
print('getting img', url)
url = 'https://i.imgur.com/' + url.rsplit('/', 1)[-1].replace('jpeg', '').replace('jpg', '')
with open(f'{write_dir}/{url[-12:]}', 'wb') as img:
img.write(requests.get(url).content)
if delete:
Thread(target=delete_file, args=[f"{write_dir}/{url[-12:]}"]).start()
else:
print('Detecting album/gallery images', url)
soup = bs4.BeautifulSoup(requests.get(url).text, 'html.parser')
for count, el in enumerate(soup.select('.post-image meta[itemprop="contentUrl"]'), start=1):
try:
found_url = "https:" + el['content']
except KeyError:
error("Could not obtain url for detected image")
continue
print(f"Downloading image {count}: {found_url}")
print("Writing image", f"{write_dir}{found_url[-11:]}")
with open(f"{write_dir}{found_url[-11:]}", "wb") as f:
f.write(requests.get(found_url).content)
if delete:
Thread(target=delete_file, args=[f"{write_dir}{found_url[-11:]}"]).start()

@ -0,0 +1,25 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charself="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>imgmine - minimal & private imgur proxy</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📷</text></svg>">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body>
% for img in imgs:
<img src="{{img}}" loading="lazy">
<br>
% end
<footer>
<small>
This website does not claim ownership of any media.
<br>This service simply acts as a proxy to Imgur.com and does not store images aside from a temporary cache.
<br>Abusive images should be reported to imgur. This website does not create new images/comments.
</small>
</footer>
</body>
</html>

@ -0,0 +1,41 @@
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charself="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>imgmine - minimal & private imgur proxy</title>
<link rel="icon" href="data:image/svg+xml,<svg xmlns=%22http://www.w3.org/2000/svg%22 viewBox=%220 0 100 100%22><text y=%22.9em%22 font-size=%2290%22>📷</text></svg>">
<link rel="stylesheet" href="/static/theme.css">
</head>
<body>
<h1>
imgmine
</h1>
<hr>
<p>
A minimalist read-only Imgur proxy insipired by software like <a href="https://invidio.us/">Invidious</a>, <a href="https://nitter.net/">Nitter</a>, and <a href="https://bibliogram.art/">Bibliogram</a>.
</p>
<p>
This project was started because <a href="https://chaoswebs.net/">Kevin Froman</a> got fed up with Imgur breaking with Tor because of cow-dung JS.
</p>
<h2>Feature roadmap</h2>
<p>Features are in order of priority of most to least</p>
<ul>
<li><input type="checkbox" checked> Image proxying</li>
<li><input type="checkbox" checked> Gallery/album proxying</li>
<li><input type="checkbox"> Proper order of gallery posts</li>
<li><input type="checkbox"> Image description and author info</li>
<li><input type="checkbox"> GIFs/videos</li>
<li><input type="checkbox"> Comments... maybe</li>
</ul>
<footer>
<small>
This website does not claim ownership of any media.
<br>This service simply acts as a proxy to Imgur.com and does not store images aside from a temporary cache.
<br>Abusive images should be reported to imgur. This website does not create new images/comments.
</small>
</footer>
</body>
</html>

@ -0,0 +1,14 @@
body{
background-color: rgba(8, 6, 37, 0.781);
color: white;
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
margin-left: 5%;
}
a, a:visited {
color: white;
}
ul{
list-style-type: none;
}

@ -0,0 +1,3 @@
import imgmine
imgmine.start_server()

@ -0,0 +1,13 @@
#!/bin/bash
ran=0
SECONDS=0 ;
close () {
exit 10;
}
for f in tests/*.py; do
python3 "$f" || close # if needed
let "ran++"
done
echo "ran $ran test files successfully in $SECONDS seconds"
rm -f *.dat

@ -0,0 +1,7 @@
import unittest
class TestBasic(unittest.TestCase):
def test_basic(self):
self.assertTrue(True)
unittest.main()
Loading…
Cancel
Save