Compare commits
16 Commits
2646007c2a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
| 6ba33c5da1 | |||
| 4512b891f8 | |||
| 63af73b678 | |||
| b6ccd7747b | |||
| 9ce74da4ec | |||
| 14e417d72a | |||
| 6f0866df97 | |||
| 90583e7a93 | |||
| 57a3b80a33 | |||
| 740db5ce15 | |||
|
|
acae8c71fc | ||
|
|
56fcf1b959 | ||
|
|
740993b19a | ||
|
|
bb52003118 | ||
|
|
6d3d945398 | ||
|
|
ee86ef7130 |
10
.gitignore
vendored
10
.gitignore
vendored
@@ -1,10 +0,0 @@
|
|||||||
.DS_Store
|
|
||||||
*~
|
|
||||||
typogra
|
|
||||||
klasky
|
|
||||||
alas
|
|
||||||
ROY4L
|
|
||||||
directory
|
|
||||||
CarlWinslows
|
|
||||||
Coach
|
|
||||||
|
|
||||||
29
LICENSE
29
LICENSE
@@ -1,29 +0,0 @@
|
|||||||
Jollo LNT license
|
|
||||||
Version 1 - February 2015
|
|
||||||
|
|
||||||
Copyright, 2015. JOLLO NET NA.
|
|
||||||
The Jollo IRC Network. <https://jollo.org/>
|
|
||||||
|
|
||||||
Vu, fare wanderer, confronted with raw, programmatic instruction
|
|
||||||
dans la forme la plus pure. A hesitation, troubled to the terms
|
|
||||||
qui ce license affirme. Par un voyage du explorer le mechanisme
|
|
||||||
et ponder la fabrication. Voila! La remide: egress sans risque.
|
|
||||||
|
|
||||||
Sans trace (Leave No Trace) via sept principales:
|
|
||||||
|
|
||||||
0. Modifique language en advance. L'Apposer Jollo LNT license
|
|
||||||
with copies en distribuer.
|
|
||||||
|
|
||||||
1. Non responsible pour neglige programme du problematique.
|
|
||||||
|
|
||||||
2. Non sympathie pour neglige programme du problematique.
|
|
||||||
|
|
||||||
3. Non permission l'modifique under any circumstance.
|
|
||||||
|
|
||||||
4. Non permission distribution under any circumstance.
|
|
||||||
|
|
||||||
5. Respect les programmatic instructions.
|
|
||||||
|
|
||||||
6. Non interfere avec l'harmonie d'une amitie.
|
|
||||||
|
|
||||||
|
|
||||||
16
README.md
16
README.md
@@ -1,18 +1,18 @@
|
|||||||
ytmnd
|
ytmndd - ytmnd downloader
|
||||||
=====
|
=====
|
||||||
|
|
||||||
ytmnd scraper.
|
An updated ytmnd scraper based on [https://github.com/julescarbon/ytmnd](https://github.com/julescarbon/ytmnd)
|
||||||
|
|
||||||
`./ytmnd.py -u [username]`
|
`./ytmndd.py -u [username]`
|
||||||
|
|
||||||
`./ytmnd.py [domain]`
|
`./ytmndd.py [domain]`
|
||||||
|
|
||||||
serving
|
serving
|
||||||
-------
|
-------
|
||||||
|
|
||||||
this scraper will download the gif and mp3 from a ytmnd and write a file embedding these things in addition to zoom text (if any).
|
this scraper will download the gif and mp3 from a ytmnd and write a file embedding these things in addition to zoom text (if any).
|
||||||
|
|
||||||
the html files use the web audio api in an attempt to get seamless looping (oddly complicated). since they download binary data, they cannot be loaded from a `file://` url.. to view these files, put them online. alternatively, run `python -m SimpleHTTPServer 8000` from the directory and navigate to e.g. http://lvh.me:8000/
|
The downloaded files cannot be loaded from a `file://` url. In order to view these files, put them online or run a local server. For example, `python -m http.server` from the directory and got to [http://localhost:8000/](http://localhost:8000/).
|
||||||
|
|
||||||
options
|
options
|
||||||
-------
|
-------
|
||||||
@@ -25,9 +25,3 @@ options
|
|||||||
| `--json-only` | writes simplified json to a file |
|
| `--json-only` | writes simplified json to a file |
|
||||||
| `--no-web-audio` | uses the <audio> tag instead of web audio |
|
| `--no-web-audio` | uses the <audio> tag instead of web audio |
|
||||||
| `--print-json` | dumps raw json from ytmnd to stdout |
|
| `--print-json` | dumps raw json from ytmnd to stdout |
|
||||||
|
|
||||||
license
|
|
||||||
-------
|
|
||||||
|
|
||||||
_This software made available under the Jollo LNT License (Leave no trace)_
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
httplib2==0.9
|
requests>=2.31.0
|
||||||
simplejson==3.4.0
|
|
||||||
|
|||||||
25
ytmnd.js
25
ytmnd.js
@@ -1,25 +0,0 @@
|
|||||||
(function(){
|
|
||||||
var hasWebKit = ('webkitAudioContext' in window) && !('chrome' in window)
|
|
||||||
var context = new webkitAudioContext()
|
|
||||||
var request = new XMLHttpRequest()
|
|
||||||
var source
|
|
||||||
request.open('GET', url, true)
|
|
||||||
request.responseType = 'arraybuffer'
|
|
||||||
request.onload = function() {
|
|
||||||
context.decodeAudioData(request.response, function(response) {
|
|
||||||
(function loop(){
|
|
||||||
if (source) {
|
|
||||||
source.start(0)
|
|
||||||
setTimeout(loop, source.buffer.duration * 1000 - (source.buffer.duration < 2 ? 0 : 60) )
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
setTimeout(loop, 0)
|
|
||||||
}
|
|
||||||
source = context.createBufferSource()
|
|
||||||
source.connect(context.destination)
|
|
||||||
source.buffer = response
|
|
||||||
})()
|
|
||||||
}, function () { console.error('The request failed.') } )
|
|
||||||
}
|
|
||||||
request.send()
|
|
||||||
})()
|
|
||||||
293
ytmnd.py
293
ytmnd.py
@@ -1,293 +0,0 @@
|
|||||||
#!/usr/bin/python
|
|
||||||
|
|
||||||
import sys
|
|
||||||
import os
|
|
||||||
import os.path
|
|
||||||
import re
|
|
||||||
import time
|
|
||||||
import urllib2
|
|
||||||
import simplejson
|
|
||||||
from optparse import OptionParser
|
|
||||||
|
|
||||||
class YTMND:
|
|
||||||
|
|
||||||
def __init__ (self):
|
|
||||||
self.user_mode = False
|
|
||||||
self.media_only = False
|
|
||||||
self.html_only = False
|
|
||||||
self.json_only = False
|
|
||||||
self.no_web_audio = False
|
|
||||||
self.print_json = False
|
|
||||||
self.sleep = 5
|
|
||||||
|
|
||||||
# Scrapes sites from the profile page, then fetches them
|
|
||||||
def fetch_user(self, user):
|
|
||||||
if user == "":
|
|
||||||
print("expecting one ytmnd name, got "+str(sys.argv))
|
|
||||||
return
|
|
||||||
|
|
||||||
ytmnd_name = user
|
|
||||||
ytmnd_html = urllib2.urlopen("http://ytmnd.com/users/" + ytmnd_name + "/sites").readlines()
|
|
||||||
|
|
||||||
domains = []
|
|
||||||
|
|
||||||
for line in ytmnd_html:
|
|
||||||
if 'profile_link' in line:
|
|
||||||
expr = r"site_link\" href=\"http://(\S+).ytmn(d|sfw)?.com\""
|
|
||||||
domain = re.search(expr,line).group(1)
|
|
||||||
domains.append(domain)
|
|
||||||
|
|
||||||
if self.json_only:
|
|
||||||
if self.media_only:
|
|
||||||
os.system("mkdir -p %s" % user)
|
|
||||||
os.chdir(user)
|
|
||||||
parsed = []
|
|
||||||
for domain in domains:
|
|
||||||
parsed.append( self.fetch_ytmnd( domain ) )
|
|
||||||
if self.media_only:
|
|
||||||
os.chdir("..")
|
|
||||||
self.write_json(ytmnd_name, parsed)
|
|
||||||
|
|
||||||
else:
|
|
||||||
print ">> found %d domains" % len( domains )
|
|
||||||
os.system("mkdir -p %s" % user)
|
|
||||||
os.chdir(user)
|
|
||||||
if not self.no_web_audio:
|
|
||||||
self.copy_ytmnd_js()
|
|
||||||
for domain in domains:
|
|
||||||
self.fetch_ytmnd( domain )
|
|
||||||
os.chdir("..")
|
|
||||||
|
|
||||||
# Fetches a single subdomain
|
|
||||||
def fetch_ytmnd(self, domain):
|
|
||||||
|
|
||||||
if domain == "":
|
|
||||||
print("expecting one ytmnd name, got "+str(sys.argv))
|
|
||||||
return
|
|
||||||
|
|
||||||
if not self.print_json:
|
|
||||||
print "fetching %s" % domain
|
|
||||||
if not self.sleep:
|
|
||||||
time.sleep(self.sleep)
|
|
||||||
|
|
||||||
ytmnd_name = domain
|
|
||||||
ytmnd_html = urllib2.urlopen("http://" + domain + ".ytmnd.com").read()
|
|
||||||
expr = r"ytmnd.site_id = (\d+);"
|
|
||||||
ytmnd_id = re.search(expr,ytmnd_html).group(1)
|
|
||||||
ytmnd_info = simplejson.load(urllib2.urlopen("http://" + domain + ".ytmnd.com/info/" + ytmnd_id + "/json"))
|
|
||||||
|
|
||||||
if self.print_json:
|
|
||||||
print simplejson.dumps(ytmnd_info, sort_keys=True, indent=4 * ' ')
|
|
||||||
elif self.json_only:
|
|
||||||
if self.media_only:
|
|
||||||
self.fetch_media(ytmnd_info)
|
|
||||||
return self.parse_json(ytmnd_info)
|
|
||||||
elif self.media_only:
|
|
||||||
self.fetch_media(ytmnd_info)
|
|
||||||
elif self.html_only:
|
|
||||||
self.write_index(ytmnd_info)
|
|
||||||
else:
|
|
||||||
self.fetch_media(ytmnd_info)
|
|
||||||
self.write_index(ytmnd_info)
|
|
||||||
|
|
||||||
return ytmnd_info
|
|
||||||
|
|
||||||
# Fetches the gif and mp3 for a post
|
|
||||||
def fetch_media(self, ytmnd_info):
|
|
||||||
domain = ytmnd_info['site']['domain']
|
|
||||||
original_gif = ytmnd_info['site']['foreground']['url']
|
|
||||||
gif_type = original_gif.split(".")[-1]
|
|
||||||
original_wav = ytmnd_info['site']['sound']['url']
|
|
||||||
wav_type = ytmnd_info['site']['sound']['type']
|
|
||||||
|
|
||||||
if 'alternates' in ytmnd_info['site']['sound']:
|
|
||||||
key = ytmnd_info['site']['sound']['alternates'].keys()[0]
|
|
||||||
value = ytmnd_info['site']['sound']['alternates'][key]
|
|
||||||
if value['file_type'] != 'swf':
|
|
||||||
original_wav = value['file_url']
|
|
||||||
wav_type = ytmnd_info['site']['sound']['file_type']
|
|
||||||
|
|
||||||
os.system("wget --quiet -O %s %s" % (domain + "." + gif_type, original_gif))
|
|
||||||
os.system("wget --quiet -O %s %s" % (domain + "." + wav_type, original_wav))
|
|
||||||
|
|
||||||
# Writes an html file emulating the ytmnd format
|
|
||||||
def write_index(self, ytmnd_info):
|
|
||||||
|
|
||||||
# print simplejson.dumps(ytmnd_info)
|
|
||||||
domain = ytmnd_info['site']['domain']
|
|
||||||
bgcolor = ytmnd_info['site']['background']['color']
|
|
||||||
title = ytmnd_info['site']['description']
|
|
||||||
placement = ytmnd_info['site']['foreground']['placement']
|
|
||||||
|
|
||||||
original_gif = ytmnd_info['site']['foreground']['url']
|
|
||||||
gif_type = original_gif.split(".")[-1]
|
|
||||||
wav_type = ytmnd_info['site']['sound']['type']
|
|
||||||
|
|
||||||
if 'alternates' in ytmnd_info['site']['sound']:
|
|
||||||
key = ytmnd_info['site']['sound']['alternates'].keys()[0]
|
|
||||||
value = ytmnd_info['site']['sound']['alternates'][key]
|
|
||||||
if value['file_type'] != 'swf':
|
|
||||||
original_wav = value['file_url']
|
|
||||||
wav_type = ytmnd_info['site']['sound']['file_type']
|
|
||||||
|
|
||||||
fn = open(domain + ".html", 'w')
|
|
||||||
fn.write("<html>\n")
|
|
||||||
fn.write("<head>\n")
|
|
||||||
fn.write("<title>%s</title>\n" % title)
|
|
||||||
fn.write("<style>\n")
|
|
||||||
fn.write("*{margin:0;padding:0;width:100%;height:100%;}\n")
|
|
||||||
fn.write("body{font-size:12px;font-weight:normal;font-style:normal;overflow:hidden;")
|
|
||||||
fn.write("background-color:%s;" % bgcolor)
|
|
||||||
fn.write("background-image:url(%s.%s);" % (domain, gif_type))
|
|
||||||
if placement == "mc":
|
|
||||||
fn.write("background-position: center center; background-repeat: no-repeat;}")
|
|
||||||
elif placement == "tile":
|
|
||||||
fn.write("background-position: top left; background-repeat: repeat;}")
|
|
||||||
fn.write("\n")
|
|
||||||
fn.write("#zoom_text{position:absolute;left:0;top:0;width:1000px;z-index:10;text-align:center;font-family:Tahoma, sans-serif}")
|
|
||||||
fn.write("#zoom_text div{position:absolute;width:1000px}")
|
|
||||||
fn.write("</style>\n")
|
|
||||||
fn.write("</head>\n")
|
|
||||||
|
|
||||||
fn.write("<body>\n")
|
|
||||||
self.write_zoom_text(fn, ytmnd_info)
|
|
||||||
|
|
||||||
if self.no_web_audio:
|
|
||||||
fn.write("<audio src='%s.%s' loop autoplay>\n" % (domain, wav_type))
|
|
||||||
fn.write("</body>\n")
|
|
||||||
else:
|
|
||||||
fn.write("</body>\n")
|
|
||||||
fn.write("<script>var url = '%s.%s'</script>\n" % (domain, wav_type))
|
|
||||||
fn.write("<script src='ytmnd.js'></script>\n")
|
|
||||||
fn.write("<script type='application/json'>\n")
|
|
||||||
fn.write(simplejson.dumps(ytmnd_info, sort_keys=True, indent=4 * ' ') + "\n")
|
|
||||||
fn.write("</script>\n")
|
|
||||||
fn.write("</html>")
|
|
||||||
|
|
||||||
fn.close()
|
|
||||||
|
|
||||||
# print out the zoom text
|
|
||||||
def write_zoom_text (self, fn, ytmnd_info):
|
|
||||||
if 'zoom_text' not in ytmnd_info['site']:
|
|
||||||
return
|
|
||||||
|
|
||||||
zoom_text = ytmnd_info['site']['zoom_text']
|
|
||||||
|
|
||||||
fn.write('<div id="zoom_text">')
|
|
||||||
|
|
||||||
offset = 100
|
|
||||||
if "line_3" in zoom_text and len(zoom_text["line_3"]) > 0:
|
|
||||||
self.write_zoom_layers( fn, zoom_text['line_3'], offset, 500 )
|
|
||||||
offset += 50
|
|
||||||
if "line_2" in zoom_text and len(zoom_text["line_2"]) > 0:
|
|
||||||
self.write_zoom_layers( fn, zoom_text['line_2'], offset, 250 )
|
|
||||||
offset += 50
|
|
||||||
if "line_1" in zoom_text and len(zoom_text["line_1"]) > 0:
|
|
||||||
self.write_zoom_layers( fn, zoom_text['line_1'], offset, 0 )
|
|
||||||
|
|
||||||
fn.write('</div>')
|
|
||||||
|
|
||||||
# print the layers of zoom text
|
|
||||||
def write_zoom_layers (self, fn, text, offset, top):
|
|
||||||
for i in xrange(1, 51):
|
|
||||||
z_index = offset + i
|
|
||||||
row_left = i * 2
|
|
||||||
row_top = top + i
|
|
||||||
font_size = i * 2
|
|
||||||
if i == 50:
|
|
||||||
color = 0
|
|
||||||
else:
|
|
||||||
color = i * 4
|
|
||||||
|
|
||||||
fn.write("<div style='z-index: %d; left: %dpx; top: %dpx; color: rgb(%d, %d, %d); font-size: %dpt;'>%s</div>"
|
|
||||||
% (z_index, row_left, row_top, color, color, color, font_size, text))
|
|
||||||
|
|
||||||
# Copies the looping audio JS into place
|
|
||||||
def copy_ytmnd_js (self):
|
|
||||||
if not os.path.isfile("ytmnd.js"):
|
|
||||||
os.system("cp ../ytmnd.js .")
|
|
||||||
|
|
||||||
# Parses data we need out of JSON
|
|
||||||
def parse_json (self, ytmnd_info):
|
|
||||||
domain = ytmnd_info['site']['domain']
|
|
||||||
bgcolor = ytmnd_info['site']['background']['color']
|
|
||||||
title = ytmnd_info['site']['description']
|
|
||||||
placement = ytmnd_info['site']['foreground']['placement']
|
|
||||||
|
|
||||||
gif_type = ytmnd_info['site']['foreground']['url'].split(".")[-1]
|
|
||||||
wav_type = ytmnd_info['site']['sound']['type']
|
|
||||||
zoom_text = ytmnd_info['site']['zoom_text']
|
|
||||||
keywords = ytmnd_info['site']['keywords']
|
|
||||||
username = ytmnd_info['site']['user']['user_name']
|
|
||||||
sound_origin = ytmnd_info['site']['sound_origin']
|
|
||||||
image_origin = ytmnd_info['site']['fg_image_origin']
|
|
||||||
work_safe = ytmnd_info['site']['work_safe']
|
|
||||||
|
|
||||||
if len(zoom_text['line_1']) == 0:
|
|
||||||
zoom_text = ""
|
|
||||||
|
|
||||||
if 'alternates' in ytmnd_info['site']['sound']:
|
|
||||||
key = ytmnd_info['site']['sound']['alternates'].keys()[0]
|
|
||||||
value = ytmnd_info['site']['sound']['alternates'][key]
|
|
||||||
if value['file_type'] != 'swf':
|
|
||||||
wav_type = ytmnd_info['site']['sound']['file_type']
|
|
||||||
|
|
||||||
simplified_info = {
|
|
||||||
'domain': domain,
|
|
||||||
'title': title,
|
|
||||||
'username': username,
|
|
||||||
'work_safe': work_safe,
|
|
||||||
'bgcolor': bgcolor,
|
|
||||||
'placement': placement,
|
|
||||||
'zoom_text': zoom_text,
|
|
||||||
'image': domain + "." + gif_type,
|
|
||||||
'sound': domain + "." + wav_type,
|
|
||||||
'image_type': gif_type,
|
|
||||||
'sound_type': wav_type,
|
|
||||||
'image_origin': image_origin,
|
|
||||||
'sound_origin': sound_origin,
|
|
||||||
}
|
|
||||||
|
|
||||||
return simplified_info
|
|
||||||
|
|
||||||
# Writes site JSON to a file
|
|
||||||
def write_json (self, domain, data):
|
|
||||||
fn = open(domain + '.json', 'w')
|
|
||||||
fn.write( simplejson.dumps(data) )
|
|
||||||
fn.close()
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
|
|
||||||
parser = OptionParser()
|
|
||||||
|
|
||||||
parser.add_option("-u", "--user", action="store_true")
|
|
||||||
parser.add_option("-m", "--media-only", action="store_true")
|
|
||||||
parser.add_option("-f", "--html-only", action="store_true")
|
|
||||||
parser.add_option("-j", "--json-only", action="store_true")
|
|
||||||
parser.add_option("-w", "--no-web-audio", action="store_true")
|
|
||||||
parser.add_option("-p", "--print-json", action="store_true")
|
|
||||||
parser.add_option("-s", "--sleep", action="store", type="int", dest="sleep", default=5)
|
|
||||||
|
|
||||||
(options, args) = parser.parse_args()
|
|
||||||
|
|
||||||
if len(args) == 0:
|
|
||||||
parser.error("incorrect number of arguments")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
ytmnd = YTMND ()
|
|
||||||
ytmnd.user_mode = options.user
|
|
||||||
ytmnd.media_only = options.media_only
|
|
||||||
ytmnd.html_only = options.html_only
|
|
||||||
ytmnd.json_only = options.json_only
|
|
||||||
ytmnd.no_web_audio = options.no_web_audio
|
|
||||||
ytmnd.print_json = options.print_json
|
|
||||||
ytmnd.sleep = options.sleep
|
|
||||||
|
|
||||||
if options.user:
|
|
||||||
user = args[0]
|
|
||||||
ytmnd.fetch_user( user )
|
|
||||||
|
|
||||||
else:
|
|
||||||
name = args[0].replace("http://","").replace(".ytmnsfw.com","").replace(".ytmnd.com","").replace("/","")
|
|
||||||
ytmnd.fetch_ytmnd( name )
|
|
||||||
|
|
||||||
533
ytmndd.py
Executable file
533
ytmndd.py
Executable file
@@ -0,0 +1,533 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
import os.path
|
||||||
|
import re
|
||||||
|
import subprocess
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
from optparse import OptionParser
|
||||||
|
|
||||||
|
import requests
|
||||||
|
from requests.exceptions import RequestException
|
||||||
|
|
||||||
|
|
||||||
|
class YTMND:
|
||||||
|
def __init__(self):
|
||||||
|
self.user_mode = False
|
||||||
|
self.media_only = False
|
||||||
|
self.html_only = False
|
||||||
|
self.json_only = False
|
||||||
|
self.no_web_audio = False
|
||||||
|
self.print_json = False
|
||||||
|
self.sleep = 5
|
||||||
|
|
||||||
|
def fetch_user(self, user):
|
||||||
|
if user == "":
|
||||||
|
print("expecting one ytmnd name, got " + str(sys.argv))
|
||||||
|
return
|
||||||
|
|
||||||
|
ytmnd_name = user
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
"http://ytmnd.com/users/" + ytmnd_name + "/sites",
|
||||||
|
headers={"User-Agent": "Mozilla/5.0"},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
ytmnd_html = response.text.splitlines()
|
||||||
|
except RequestException as e:
|
||||||
|
print(f"Error fetching user page: {e}")
|
||||||
|
return
|
||||||
|
|
||||||
|
domains = []
|
||||||
|
|
||||||
|
for line in ytmnd_html:
|
||||||
|
if "profile_link" in line:
|
||||||
|
expr = r"site_link\" href=\"http://(\S+).ytmn(d|sfw)?.com\""
|
||||||
|
match = re.search(expr, line)
|
||||||
|
if match:
|
||||||
|
domain = match.group(1)
|
||||||
|
domains.append(domain)
|
||||||
|
|
||||||
|
if self.json_only:
|
||||||
|
if self.media_only:
|
||||||
|
os.makedirs(user, exist_ok=True)
|
||||||
|
os.chdir(user)
|
||||||
|
parsed = []
|
||||||
|
for domain in domains:
|
||||||
|
result = self.fetch_ytmnd(domain)
|
||||||
|
if result:
|
||||||
|
parsed.append(result)
|
||||||
|
if self.media_only:
|
||||||
|
os.chdir("..")
|
||||||
|
self.write_json(ytmnd_name, parsed)
|
||||||
|
|
||||||
|
else:
|
||||||
|
print(">> found %d domains" % len(domains))
|
||||||
|
os.makedirs(user, exist_ok=True)
|
||||||
|
os.chdir(user)
|
||||||
|
for domain in domains:
|
||||||
|
self.fetch_ytmnd(domain)
|
||||||
|
os.chdir("..")
|
||||||
|
|
||||||
|
def fetch_ytmnd(self, domain):
|
||||||
|
if domain == "":
|
||||||
|
print("expecting one ytmnd name, got " + str(sys.argv))
|
||||||
|
return None
|
||||||
|
|
||||||
|
if not self.print_json:
|
||||||
|
print("fetching %s" % domain)
|
||||||
|
if self.sleep:
|
||||||
|
time.sleep(self.sleep)
|
||||||
|
|
||||||
|
ytmnd_name = domain
|
||||||
|
try:
|
||||||
|
response = requests.get(
|
||||||
|
"http://" + domain + ".ytmnd.com", headers={"User-Agent": "Mozilla/5.0"}
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
ytmnd_html = response.text
|
||||||
|
|
||||||
|
expr = r"ytmnd.site_id = (\d+);"
|
||||||
|
match = re.search(expr, ytmnd_html)
|
||||||
|
if not match:
|
||||||
|
print(f"Could not find site_id for {domain}")
|
||||||
|
return None
|
||||||
|
ytmnd_id = match.group(1)
|
||||||
|
|
||||||
|
response = requests.get(
|
||||||
|
"http://" + domain + ".ytmnd.com/info/" + ytmnd_id + "/json",
|
||||||
|
headers={"User-Agent": "Mozilla/5.0"},
|
||||||
|
)
|
||||||
|
response.raise_for_status()
|
||||||
|
ytmnd_info = response.json()
|
||||||
|
|
||||||
|
except RequestException as e:
|
||||||
|
print(f"Error fetching {domain}: {e}")
|
||||||
|
return None
|
||||||
|
|
||||||
|
if self.print_json:
|
||||||
|
print(json.dumps(ytmnd_info, sort_keys=True, indent=4))
|
||||||
|
elif self.json_only:
|
||||||
|
if self.media_only:
|
||||||
|
self.fetch_media(ytmnd_info)
|
||||||
|
return self.parse_json(ytmnd_info)
|
||||||
|
elif self.media_only:
|
||||||
|
self.fetch_media(ytmnd_info)
|
||||||
|
elif self.html_only:
|
||||||
|
self.write_index(ytmnd_info)
|
||||||
|
else:
|
||||||
|
self.fetch_media(ytmnd_info)
|
||||||
|
self.write_index(ytmnd_info)
|
||||||
|
|
||||||
|
return ytmnd_info
|
||||||
|
|
||||||
|
def fetch_media(self, ytmnd_info):
|
||||||
|
domain = ytmnd_info["site"]["domain"]
|
||||||
|
original_gif = ytmnd_info["site"]["foreground"]["url"]
|
||||||
|
gif_type = original_gif.split(".")[-1]
|
||||||
|
original_wav = ytmnd_info["site"]["sound"]["url"]
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["type"]
|
||||||
|
|
||||||
|
if "alternates" in ytmnd_info["site"]["sound"]:
|
||||||
|
key = list(ytmnd_info["site"]["sound"]["alternates"].keys())[0]
|
||||||
|
value = ytmnd_info["site"]["sound"]["alternates"][key]
|
||||||
|
if value["file_type"] != "swf":
|
||||||
|
original_wav = value["file_url"]
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["file_type"]
|
||||||
|
|
||||||
|
try:
|
||||||
|
gif_response = requests.get(
|
||||||
|
original_gif, headers={"User-Agent": "Mozilla/5.0"}
|
||||||
|
)
|
||||||
|
gif_response.raise_for_status()
|
||||||
|
with open(f"{domain}.{gif_type}", "wb") as f:
|
||||||
|
f.write(gif_response.content)
|
||||||
|
except RequestException as e:
|
||||||
|
print(f"Error downloading gif: {e}")
|
||||||
|
|
||||||
|
try:
|
||||||
|
wav_response = requests.get(
|
||||||
|
original_wav, headers={"User-Agent": "Mozilla/5.0"}
|
||||||
|
)
|
||||||
|
wav_response.raise_for_status()
|
||||||
|
with open(f"{domain}.{wav_type}", "wb") as f:
|
||||||
|
f.write(wav_response.content)
|
||||||
|
except RequestException as e:
|
||||||
|
print(f"Error downloading audio: {e}")
|
||||||
|
|
||||||
|
def write_index(self, ytmnd_info):
|
||||||
|
domain = ytmnd_info["site"]["domain"]
|
||||||
|
bgcolor = ytmnd_info["site"]["background"]["color"]
|
||||||
|
title = ytmnd_info["site"]["description"]
|
||||||
|
placement = ytmnd_info["site"]["foreground"]["placement"]
|
||||||
|
|
||||||
|
original_gif = ytmnd_info["site"]["foreground"]["url"]
|
||||||
|
gif_type = original_gif.split(".")[-1]
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["type"]
|
||||||
|
|
||||||
|
if "alternates" in ytmnd_info["site"]["sound"]:
|
||||||
|
key = list(ytmnd_info["site"]["sound"]["alternates"].keys())[0]
|
||||||
|
value = ytmnd_info["site"]["sound"]["alternates"][key]
|
||||||
|
if value["file_type"] != "swf":
|
||||||
|
original_wav = value["file_url"]
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["file_type"]
|
||||||
|
|
||||||
|
with open(domain + ".html", "w", encoding="utf-8") as fn:
|
||||||
|
fn.write("<!DOCTYPE html>\n")
|
||||||
|
fn.write("<html>\n")
|
||||||
|
fn.write("<head>\n")
|
||||||
|
fn.write("<meta charset='utf-8'>\n")
|
||||||
|
fn.write(
|
||||||
|
"<meta name='viewport' content='width=device-width, initial-scale=1.0'>\n"
|
||||||
|
)
|
||||||
|
fn.write("<title>%s</title>\n" % title)
|
||||||
|
fn.write("<style>\n")
|
||||||
|
fn.write("*{margin:0;padding:0;width:100%;height:100%;}\n")
|
||||||
|
fn.write(
|
||||||
|
"body{font-size:12px;font-weight:normal;font-style:normal;overflow:hidden;"
|
||||||
|
)
|
||||||
|
fn.write("background-color:%s;" % bgcolor)
|
||||||
|
fn.write("background-image:url(%s.%s);" % (domain, gif_type))
|
||||||
|
if placement == "mc":
|
||||||
|
fn.write(
|
||||||
|
"background-position: center center; background-repeat: no-repeat;}"
|
||||||
|
)
|
||||||
|
elif placement == "tile":
|
||||||
|
fn.write("background-position: top left; background-repeat: repeat;}")
|
||||||
|
fn.write("\n")
|
||||||
|
fn.write(
|
||||||
|
"#zoom_text{position:absolute;left:0;top:0;width:1000px;z-index:10;text-align:center;font-family:Tahoma, sans-serif}\n"
|
||||||
|
)
|
||||||
|
fn.write("#zoom_text div{position:absolute;width:1000px}\n")
|
||||||
|
fn.write("@media (max-width: 768px) {\n")
|
||||||
|
fn.write(
|
||||||
|
" #zoom_text{left:50%;top:50%;margin-left:-500px;-webkit-transform:translate(0,-50%) scale(0.55);-ms-transform:translate(0,-50%) scale(0.55);transform:translate(0,-50%) scale(0.55);-webkit-transform-origin:center center;-ms-transform-origin:center center;transform-origin:center center;}\n"
|
||||||
|
)
|
||||||
|
fn.write("}\n")
|
||||||
|
fn.write("@media (max-width: 480px) {\n")
|
||||||
|
fn.write(
|
||||||
|
" #zoom_text{-webkit-transform:translate(0,-50%) scale(0.45);-ms-transform:translate(0,-50%) scale(0.45);transform:translate(0,-50%) scale(0.45);}\n"
|
||||||
|
)
|
||||||
|
fn.write("}\n")
|
||||||
|
fn.write(
|
||||||
|
"#unmute-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,0.9);display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;z-index:99999;cursor:pointer;}\n"
|
||||||
|
)
|
||||||
|
fn.write(
|
||||||
|
"#unmute-btn{width:80px;height:80px;background:rgba(255,255,255,0.1);border:2px solid rgba(255,255,255,0.3);border-radius:50%;display:-webkit-box;display:-webkit-flex;display:-ms-flexbox;display:flex;-webkit-box-align:center;-webkit-align-items:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-webkit-justify-content:center;-ms-flex-pack:center;justify-content:center;font-size:32px;color:rgba(255,255,255,0.9);-webkit-transition:all 0.3s ease;transition:all 0.3s ease;}\n"
|
||||||
|
)
|
||||||
|
fn.write(
|
||||||
|
"#unmute-btn:hover{background:rgba(255,255,255,0.2);border-color:rgba(255,255,255,0.5);-webkit-transform:scale(1.1);-ms-transform:scale(1.1);transform:scale(1.1);}\n"
|
||||||
|
)
|
||||||
|
fn.write("</style>\n")
|
||||||
|
fn.write("</head>\n")
|
||||||
|
|
||||||
|
fn.write("<body>\n")
|
||||||
|
|
||||||
|
fn.write('<div id="unmute-overlay">\n')
|
||||||
|
fn.write(' <div id="unmute-btn">▶</div>\n')
|
||||||
|
fn.write("</div>\n")
|
||||||
|
|
||||||
|
self.write_zoom_text(fn, ytmnd_info)
|
||||||
|
|
||||||
|
if self.no_web_audio:
|
||||||
|
fn.write("<audio src='%s.%s' loop autoplay>\n" % (domain, wav_type))
|
||||||
|
|
||||||
|
fn.write("</body>\n")
|
||||||
|
|
||||||
|
fn.write("<script>\n")
|
||||||
|
fn.write("(function() {\n")
|
||||||
|
fn.write(" var audioUrl = '%s.%s';\n" % (domain, wav_type))
|
||||||
|
fn.write(" var context = null;\n")
|
||||||
|
fn.write(" var source = null;\n")
|
||||||
|
fn.write(" var audioBuffer = null;\n")
|
||||||
|
fn.write(" var isPlaying = false;\n")
|
||||||
|
fn.write(" var fallbackAudio = null;\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function hasWebAudio() {\n")
|
||||||
|
fn.write(
|
||||||
|
" return ('AudioContext' in window) || ('webkitAudioContext' in window);\n"
|
||||||
|
)
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function createContext() {\n")
|
||||||
|
fn.write(" if ('AudioContext' in window) {\n")
|
||||||
|
fn.write(" return new AudioContext();\n")
|
||||||
|
fn.write(" } else if ('webkitAudioContext' in window) {\n")
|
||||||
|
fn.write(" return new webkitAudioContext();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" return null;\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function loadAudioWithXHR(callback, errorCallback) {\n")
|
||||||
|
fn.write(" var request = new XMLHttpRequest();\n")
|
||||||
|
fn.write(" request.open('GET', audioUrl, true);\n")
|
||||||
|
fn.write(" request.responseType = 'arraybuffer';\n")
|
||||||
|
fn.write(" request.onload = function() {\n")
|
||||||
|
fn.write(" if (request.status === 200) {\n")
|
||||||
|
fn.write(" callback(request.response);\n")
|
||||||
|
fn.write(" } else {\n")
|
||||||
|
fn.write(
|
||||||
|
" errorCallback('Request failed with status: ' + request.status);\n"
|
||||||
|
)
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" };\n")
|
||||||
|
fn.write(" request.onerror = function() {\n")
|
||||||
|
fn.write(" errorCallback('Network error');\n")
|
||||||
|
fn.write(" };\n")
|
||||||
|
fn.write(" request.send();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function loopAudio() {\n")
|
||||||
|
fn.write(" if (!isPlaying || !audioBuffer) return;\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" source = context.createBufferSource();\n")
|
||||||
|
fn.write(" source.connect(context.destination);\n")
|
||||||
|
fn.write(" source.buffer = audioBuffer;\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" try {\n")
|
||||||
|
fn.write(" if (source.start) {\n")
|
||||||
|
fn.write(" source.start(0);\n")
|
||||||
|
fn.write(" } else if (source.noteOn) {\n")
|
||||||
|
fn.write(" source.noteOn(0);\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" } catch(e) {\n")
|
||||||
|
fn.write(" console.error('Start error:', e);\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" var duration = audioBuffer.duration * 1000;\n")
|
||||||
|
fn.write(" var offset = audioBuffer.duration < 2 ? 0 : 60;\n")
|
||||||
|
fn.write(" setTimeout(loopAudio, duration - offset);\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function playWebAudio() {\n")
|
||||||
|
fn.write(" context = createContext();\n")
|
||||||
|
fn.write(" if (!context) {\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" return;\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" if (context.state === 'suspended') {\n")
|
||||||
|
fn.write(" try {\n")
|
||||||
|
fn.write(" context.resume();\n")
|
||||||
|
fn.write(" } catch(e) {\n")
|
||||||
|
fn.write(" console.error('Resume error:', e);\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" loadAudioWithXHR(\n")
|
||||||
|
fn.write(" function(arrayBuffer) {\n")
|
||||||
|
fn.write(" var decodeSuccess = function(buffer) {\n")
|
||||||
|
fn.write(" audioBuffer = buffer;\n")
|
||||||
|
fn.write(" isPlaying = true;\n")
|
||||||
|
fn.write(" setTimeout(loopAudio, 0);\n")
|
||||||
|
fn.write(" };\n")
|
||||||
|
fn.write(" var decodeError = function(error) {\n")
|
||||||
|
fn.write(" console.error('Decode error:', error);\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" };\n")
|
||||||
|
fn.write(" try {\n")
|
||||||
|
fn.write(
|
||||||
|
" context.decodeAudioData(arrayBuffer, decodeSuccess, decodeError);\n"
|
||||||
|
)
|
||||||
|
fn.write(" } catch(e) {\n")
|
||||||
|
fn.write(" console.error('decodeAudioData exception:', e);\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" },\n")
|
||||||
|
fn.write(" function(error) {\n")
|
||||||
|
fn.write(" console.error('Load error:', error);\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" );\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function fallbackToHTMLAudio() {\n")
|
||||||
|
fn.write(" try {\n")
|
||||||
|
fn.write(" fallbackAudio = new Audio(audioUrl);\n")
|
||||||
|
fn.write(" fallbackAudio.loop = true;\n")
|
||||||
|
fn.write(" var playPromise = fallbackAudio.play();\n")
|
||||||
|
fn.write(" if (playPromise && playPromise.catch) {\n")
|
||||||
|
fn.write(" playPromise.catch(function(error) {\n")
|
||||||
|
fn.write(" console.error('HTML5 audio play failed:', error);\n")
|
||||||
|
fn.write(" });\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" isPlaying = true;\n")
|
||||||
|
fn.write(" } catch(e) {\n")
|
||||||
|
fn.write(" console.error('Fallback audio failed:', e);\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" function startAudio() {\n")
|
||||||
|
fn.write(" var overlay = document.getElementById('unmute-overlay');\n")
|
||||||
|
fn.write(" if (overlay) {\n")
|
||||||
|
fn.write(" overlay.style.display = 'none';\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" if (hasWebAudio()) {\n")
|
||||||
|
fn.write(" try {\n")
|
||||||
|
fn.write(" playWebAudio();\n")
|
||||||
|
fn.write(" } catch(e) {\n")
|
||||||
|
fn.write(" console.error('Web Audio failed:', e);\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" } else {\n")
|
||||||
|
fn.write(" fallbackToHTMLAudio();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" var overlay = document.getElementById('unmute-overlay');\n")
|
||||||
|
fn.write(" if (overlay) {\n")
|
||||||
|
fn.write(" overlay.addEventListener('click', function(e) {\n")
|
||||||
|
fn.write(" e.preventDefault();\n")
|
||||||
|
fn.write(" startAudio();\n")
|
||||||
|
fn.write(" });\n")
|
||||||
|
fn.write(" overlay.addEventListener('touchend', function(e) {\n")
|
||||||
|
fn.write(" e.preventDefault();\n")
|
||||||
|
fn.write(" startAudio();\n")
|
||||||
|
fn.write(" });\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" \n")
|
||||||
|
fn.write(" document.addEventListener('keydown', function(e) {\n")
|
||||||
|
fn.write(" var modifierKeys = [16, 17, 18];\n")
|
||||||
|
fn.write(" if (modifierKeys.indexOf(e.keyCode) !== -1) {\n")
|
||||||
|
fn.write(" return;\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" if (overlay && overlay.style.display !== 'none') {\n")
|
||||||
|
fn.write(" startAudio();\n")
|
||||||
|
fn.write(" }\n")
|
||||||
|
fn.write(" });\n")
|
||||||
|
fn.write("})();\n")
|
||||||
|
fn.write("</script>\n")
|
||||||
|
|
||||||
|
fn.write("<script type='application/json' id='ytmnd-data'>\n")
|
||||||
|
fn.write(json.dumps(ytmnd_info, sort_keys=True, indent=2) + "\n")
|
||||||
|
fn.write("</script>\n")
|
||||||
|
|
||||||
|
fn.write("</html>")
|
||||||
|
|
||||||
|
def write_zoom_text(self, fn, ytmnd_info):
|
||||||
|
if "zoom_text" not in ytmnd_info["site"]:
|
||||||
|
return
|
||||||
|
|
||||||
|
zoom_text = ytmnd_info["site"]["zoom_text"]
|
||||||
|
|
||||||
|
fn.write('<div id="zoom_text">')
|
||||||
|
|
||||||
|
offset = 100
|
||||||
|
if "line_3" in zoom_text and len(zoom_text["line_3"]) > 0:
|
||||||
|
self.write_zoom_layers(fn, zoom_text["line_3"], offset, 269)
|
||||||
|
offset += 21
|
||||||
|
if "line_2" in zoom_text and len(zoom_text["line_2"]) > 0:
|
||||||
|
self.write_zoom_layers(fn, zoom_text["line_2"], offset, 135)
|
||||||
|
offset += 21
|
||||||
|
if "line_1" in zoom_text and len(zoom_text["line_1"]) > 0:
|
||||||
|
self.write_zoom_layers(fn, zoom_text["line_1"], offset, 1)
|
||||||
|
|
||||||
|
fn.write("</div>")
|
||||||
|
|
||||||
|
def write_zoom_layers(self, fn, text, offset, top):
|
||||||
|
for i in range(1, 22):
|
||||||
|
z_index = offset + i
|
||||||
|
row_left = i * 2
|
||||||
|
row_top = top + i
|
||||||
|
font_size = i * 2
|
||||||
|
if i == 21:
|
||||||
|
color = 0
|
||||||
|
else:
|
||||||
|
color = i * 4
|
||||||
|
|
||||||
|
fn.write(
|
||||||
|
"<div style='z-index: %d; left: %dpx; top: %dpx; color: rgb(%d, %d, %d); font-size: %dpt;'>%s</div>"
|
||||||
|
% (z_index, row_left, row_top, color, color, color, font_size, text)
|
||||||
|
)
|
||||||
|
|
||||||
|
def parse_json(self, ytmnd_info):
|
||||||
|
domain = ytmnd_info["site"]["domain"]
|
||||||
|
bgcolor = ytmnd_info["site"]["background"]["color"]
|
||||||
|
title = ytmnd_info["site"]["description"]
|
||||||
|
placement = ytmnd_info["site"]["foreground"]["placement"]
|
||||||
|
|
||||||
|
gif_type = ytmnd_info["site"]["foreground"]["url"].split(".")[-1]
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["type"]
|
||||||
|
zoom_text = ytmnd_info["site"]["zoom_text"]
|
||||||
|
keywords = ytmnd_info["site"]["keywords"]
|
||||||
|
username = ytmnd_info["site"]["user"]["user_name"]
|
||||||
|
sound_origin = ytmnd_info["site"]["sound_origin"]
|
||||||
|
image_origin = ytmnd_info["site"]["fg_image_origin"]
|
||||||
|
work_safe = ytmnd_info["site"]["work_safe"]
|
||||||
|
|
||||||
|
if len(zoom_text["line_1"]) == 0:
|
||||||
|
zoom_text = ""
|
||||||
|
|
||||||
|
if "alternates" in ytmnd_info["site"]["sound"]:
|
||||||
|
key = list(ytmnd_info["site"]["sound"]["alternates"].keys())[0]
|
||||||
|
value = ytmnd_info["site"]["sound"]["alternates"][key]
|
||||||
|
if value["file_type"] != "swf":
|
||||||
|
wav_type = ytmnd_info["site"]["sound"]["file_type"]
|
||||||
|
|
||||||
|
simplified_info = {
|
||||||
|
"domain": domain,
|
||||||
|
"title": title,
|
||||||
|
"username": username,
|
||||||
|
"work_safe": work_safe,
|
||||||
|
"bgcolor": bgcolor,
|
||||||
|
"placement": placement,
|
||||||
|
"zoom_text": zoom_text,
|
||||||
|
"image": domain + "." + gif_type,
|
||||||
|
"sound": domain + "." + wav_type,
|
||||||
|
"image_type": gif_type,
|
||||||
|
"sound_type": wav_type,
|
||||||
|
"image_origin": image_origin,
|
||||||
|
"sound_origin": sound_origin,
|
||||||
|
}
|
||||||
|
|
||||||
|
return simplified_info
|
||||||
|
|
||||||
|
def write_json(self, domain, data):
|
||||||
|
with open(domain + ".json", "w", encoding="utf-8") as fn:
|
||||||
|
fn.write(json.dumps(data))
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
parser = OptionParser()
|
||||||
|
|
||||||
|
parser.add_option("-u", "--user", action="store_true")
|
||||||
|
parser.add_option("-m", "--media-only", action="store_true")
|
||||||
|
parser.add_option("-f", "--html-only", action="store_true")
|
||||||
|
parser.add_option("-j", "--json-only", action="store_true")
|
||||||
|
parser.add_option("-w", "--no-web-audio", action="store_true")
|
||||||
|
parser.add_option("-p", "--print-json", action="store_true")
|
||||||
|
parser.add_option(
|
||||||
|
"-s", "--sleep", action="store", type="int", dest="sleep", default=5
|
||||||
|
)
|
||||||
|
|
||||||
|
(options, args) = parser.parse_args()
|
||||||
|
|
||||||
|
if len(args) == 0:
|
||||||
|
parser.error("incorrect number of arguments")
|
||||||
|
sys.exit(1)
|
||||||
|
|
||||||
|
ytmnd = YTMND()
|
||||||
|
ytmnd.user_mode = options.user
|
||||||
|
ytmnd.media_only = options.media_only
|
||||||
|
ytmnd.html_only = options.html_only
|
||||||
|
ytmnd.json_only = options.json_only
|
||||||
|
ytmnd.no_web_audio = options.no_web_audio
|
||||||
|
ytmnd.print_json = options.print_json
|
||||||
|
ytmnd.sleep = options.sleep
|
||||||
|
|
||||||
|
if options.user:
|
||||||
|
user = args[0]
|
||||||
|
ytmnd.fetch_user(user)
|
||||||
|
|
||||||
|
else:
|
||||||
|
name = (
|
||||||
|
args[0]
|
||||||
|
.replace("http://", "")
|
||||||
|
.replace(".ytmnsfw.com", "")
|
||||||
|
.replace(".ytmnd.com", "")
|
||||||
|
.replace("/", "")
|
||||||
|
)
|
||||||
|
ytmnd.fetch_ytmnd(name)
|
||||||
Reference in New Issue
Block a user