Skip to content

Commit 205dadb

Browse files
committed
transformed into py8chan, basic proof of concept
1 parent 9c05c05 commit 205dadb

File tree

13 files changed

+263
-143
lines changed

13 files changed

+263
-143
lines changed

.vscode/settings.json

+8
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
// Place your settings in this file to overwrite default and user settings.
2+
{
3+
// Controls the rendering size of tabs in characters. Accepted values: "auto", 2, 4, 6, etc. If set to "auto", the value will be guessed when a file is opened.
4+
"editor.tabSize": "4",
5+
6+
// Controls if the editor will insert spaces for tabs. Accepted values: "auto", true, false. If set to "auto", the value will be guessed when a file is opened.
7+
"editor.insertSpaces": "true"
8+
}

README.rst

+15-66
Original file line numberDiff line numberDiff line change
@@ -1,46 +1,37 @@
1-
4chan Python Library
1+
8chan/vichan Python Library
22
====================
3-
The Bibliotheca Anonoma's **complete Python Wrapper for the 4chan API.**
3+
The Bibliotheca Anonoma's **complete Python Wrapper for the 8chan API.**
44
Uses requests, respects if-modified-since headers on updating threads.
55
Caches thread objects. Fun stuff.
66

7-
An absolute must if you want to interface with or scrape from 4chan,
8-
using a Python script.
9-
10-
`Hosted Documentation <http://basc-py4chan.readthedocs.org/en/latest/index.html>`_
7+
An absolute must if you want to interface with or scrape from 8chan or other vichan-based imageboards/textboards,
8+
using a Python script._
119

1210
`Github Repository <https://github.com/bibanon/BASC-py4chan>`_
1311

1412
You can install this library `straight from
15-
PyPi <https://pypi.python.org/pypi/BASC-py4chan>`_ with::
13+
PyPi <https://pypi.python.org/pypi/py8chan>`_ with::
1614

17-
pip install basc-py4chan
15+
pip install py8chan
1816

1917

2018
**Getting Help**
2119

2220
If you want help, or you have some trouble using this library, our primary IRC channel
2321
is `#bibanon on irc.rizon.net <http://qchat2.rizon.net/?channels=bibanon>`_. Simply head
2422
in there and talk to dan or antonizoon. Otherwise, you can put a issue on our `Github
25-
Issue Tracker <https://github.com/bibanon/BASC-py4chan>`_ and we'll respond as soon as
23+
Issue Tracker <https://github.com/bibanon/py8chan>`_ and we'll respond as soon as
2624
we can!
2725

2826
--------
2927

30-
Originally written by `Edgeworth <https://github.com/e000/py-4chan>`_, the library
31-
has been adopted and extended by `Bibliotheca Anonoma <https://github.com/bibanon>`_.
32-
33-
**Note:** If you're a developer that still uses Edgeworth's py-4chan, and don't
34-
want to change the function names, Bibliotheca Anonoma maintains an `up-to-date,
35-
API-compatible version of py-4chan here. <https://github.com/bibanon/py-4chan>`_
36-
3728
Usage
3829
-----
3930

4031
.. code:: python
4132
42-
import basc_py4chan
43-
b = basc_py4chan.Board('b')
33+
import py8chan
34+
b = py8chan.Board('b')
4435
thread = b.get_thread(423491034)
4536
4637
print(thread)
@@ -51,57 +42,15 @@ Usage
5142
# In a while...
5243
print("I fetched", thread.update(), "new replies.")
5344
54-
Documentation is located `here <http://basc-py4chan.readthedocs.org/en/latest/index.html>`_.
55-
56-
Extending this Library
57-
----------------------
45+
Documentation
46+
-------------
5847

59-
There are a wealth of other imageboard APIs that have adopted a similar structure to the 4chan API (such as 8chan/vichan, or 420chan).
60-
61-
So instead of writing a whole new class from scratch, you could inherit and override BASC-py4chan to support them. Here's how:
62-
63-
.. code:: python
48+
This library extends the classes of `BASC-py4chan <https://github.com/bibanon/BASC-py4chan>`_. For the most part, it inherits all functions and remains compatible. See the BASC-py4chan documentation for more info.
6449

65-
import basc_py4chan
66-
67-
class URL (basc_py4chan.URL):
68-
# see BASC-py4chan's `url.py` for an example of how to set up
69-
# the URLs.
70-
def __init__(self, https=False):
71-
# Your API URL Subdomains
72-
DOMAIN = { }
73-
74-
# Your API URL Templates
75-
TEMPLATE = { }
76-
77-
# Your API Listings
78-
LISTING = { }
79-
80-
# combine all dictionaries into self.URL dictionary
81-
self.URL = TEMPLATE
82-
self.URL.update({'domain': DOMAIN})
83-
self.URL.update({'listing': LISTING})
84-
85-
class Board(basc_py4chan.Board):
86-
# add your own overrides here, or leave it alone
87-
pass
88-
89-
class Thread(basc_py4chan.Threads):
90-
# add your own overrides here, or leave it alone
91-
pass
92-
93-
class Post(basc_py4chan.Post):
94-
# add your own overrides here, or leave it alone
95-
pass
96-
97-
# note that all classes must be in one file (we recommend
98-
# py?chan/__init__.py ), due to how python modules work
99-
100-
101-
From there, just override any methods in classes Board, Thread or Post as necessary.
102-
103-
Notice that if your imageboard's API does not support a certain feature in the 4chan API, `you should have the function raise an AttributeError. <http://stackoverflow.com/a/23126260>`_
50+
`BASC-py4chan Documentation <http://basc-py4chan.readthedocs.org/en/latest/index.html>`_
10451

52+
Notice that some functions are not implemented in the 8chan API. These functions will `raise an AttributeError when used. <http://stackoverflow.com/a/23126260>`_
53+
10554
License
10655
-------
10756

examples/example1.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
# credits to Anarov for improved example.py
2-
import basc_py4chan
2+
import py8chan
33

44

55
def main():
6-
v = basc_py4chan.Board('v')
6+
v = py8chan.Board('v')
77
thread = v.get_thread(152900882)
88
print(thread)
99
print('Sticky?', thread.sticky)

examples/example2.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# credits to Anarov for improved example.py
2-
import basc_py4chan
2+
import py8chan
33

44

55
def main():
@@ -10,7 +10,7 @@ def main():
1010
% sys.argv[0])
1111
return
1212

13-
board = basc_py4chan.Board(sys.argv[1])
13+
board = py8chan.Board(sys.argv[1])
1414
thread = board.get_thread(int(sys.argv[2]))
1515
for f in thread.files():
1616
print(f)

examples/example3.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
# credits to Anarov for improved example.py
2-
import basc_py4chan
2+
import py8chan
33

4-
b = basc_py4chan.Board('b')
4+
b = py8chan.Board('b')
55
threads = b.get_threads()
66
print("Got %i threads" % len(threads))
77
first_thread = threads[0]
File renamed without changes.

basc_py4chan/board.py py8chan/board.py

+18-15
Original file line numberDiff line numberDiff line change
@@ -189,18 +189,19 @@ def _request_threads(self, url):
189189

190190
return threads
191191

192-
def get_threads(self, page=1):
192+
# 8chan/vichan board pages actually start at 0, not 1!
193+
def get_threads(self, page=0):
193194
"""Returns all threads on a certain page.
194-
195+
195196
Gets a list of Thread objects for every thread on the given page. If a thread is
196197
already in our cache, the cached version is returned and thread.want_update is
197198
set to True on the specific thread object.
198-
199-
Pages on 4chan are indexed from 1 onwards.
200-
199+
200+
Pages on 8chan/vichan are indexed from 0 onwards. (not 1 as in modern 4chan: 4chan used to start from 0)
201+
201202
Args:
202203
page (int): Page to request threads for. Defaults to the first page.
203-
204+
204205
Returns:
205206
list of :mod:`basc_py4chan.Thread`: List of Thread objects representing the threads on the given page.
206207
"""
@@ -258,23 +259,25 @@ def clear_cache(self):
258259
def name(self):
259260
return self._board_name
260261

262+
# py8chan does not use thread titles, unlike BASC-py4chan
261263
@property
262264
def title(self):
263-
return self._get_metadata('title')
264-
265+
raise AttributeError( "'py8chan.Board' object has no attribute 'title'" )
266+
267+
# py8chan does not use worksafe tag, unlike BASC-py4chan
265268
@property
266269
def is_worksafe(self):
267-
if self._get_metadata('ws_board'):
268-
return True
269-
return False
270-
270+
raise AttributeError( "'py8chan.Board' object has no attribute 'is_worksafe'" )
271+
272+
# py8chan does not use page_count variable, unlike BASC-py4chan
271273
@property
272274
def page_count(self):
273-
return self._get_metadata('pages')
274-
275+
raise AttributeError( "'py8chan.Board' object has no attribute 'page_count'" )
276+
277+
# py8chan does not use threads_per_page variable, unlike BASC-py4chan
275278
@property
276279
def threads_per_page(self):
277-
return self._get_metadata('per_page')
280+
raise AttributeError( "'py8chan.Board' object has no attribute 'threads_per_page'" )
278281

279282
@property
280283
def https(self):

py8chan/file.py

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# brand new class to handle 8chan/vichan's multiple files per post
2+
# supersedes py4chan's file generators in Thread and Post
3+
4+
class File(object):
5+
""" Represents File objects and their thumbnails.
6+
7+
Constructor:
8+
post (py8chan.Post) - parent Post object.
9+
data (dict) - The extra_files dict from the 8chan API.
10+
11+
Attributes:
12+
file_md5 (string): MD5 hash of the file attached to this post.
13+
file_md5_hex (string): Hex-encoded MD5 hash of the file attached to this post.
14+
filename (string): Original name of the file attached to this post.
15+
file_url (string): URL of the file attached to this post.
16+
file_extension (string): Extension of the file attached to this post. Eg: ``png``, ``webm``, etc.
17+
file_size (int): Size of the file attached to this post.
18+
file_width (int): Width of the file attached to this post.
19+
file_height (int): Height of the file attached to this post.
20+
file_deleted (bool): Whether the file attached to this post was deleted after being posted.
21+
thumbnail_width (int): Width of the thumbnail attached to this post.
22+
thumbnail_height (int): Height of the thumbnail attached to this post.
23+
thumbnail_fname (string): Filename of the thumbnail attached to this post.
24+
thumbnail_url (string): URL of the thumbnail attached to this post.
25+
has_file (bool): Whether this post has a file attached to it.
26+
url (string): URL of this post.
27+
"""
28+
29+
def __init__(self, post, data):
30+
self._post = post
31+
self._data = data
32+
self._url = Url(board=self._post._thread._board.name, https=self._post._thread._board.https) # 8chan URL generator
33+
34+
@property
35+
def file_md5(self):
36+
if not self.has_file:
37+
return None
38+
39+
return self._data['md5'].decode('base64')
40+
41+
@property
42+
def file_md5_hex(self):
43+
if not self.has_file:
44+
return None
45+
46+
return self.file_md5.encode('hex')
47+
48+
@property
49+
def filename(self):
50+
if not self.has_file:
51+
return None
52+
53+
board = self._thread._board
54+
55+
return '%i%s' % (
56+
self._data['tim'],
57+
self._data['ext']
58+
)
59+
60+
@property
61+
def file_url(self):
62+
if not self.has_file:
63+
return None
64+
65+
board = self._thread._board
66+
return self._url.file_url(
67+
self._data['tim'],
68+
self._data['ext']
69+
)
70+
71+
@property
72+
def file_extension(self):
73+
return self._data.get('ext')
74+
75+
@property
76+
def file_size(self):
77+
return self._data.get('fsize')
78+
79+
@property
80+
def file_width(self):
81+
return self._data.get('w')
82+
83+
@property
84+
def file_height(self):
85+
return self._data.get('h')
86+
87+
@property
88+
def file_deleted(self):
89+
return self._data.get('filedeleted') == 1
90+
91+
@property
92+
def thumbnail_width(self):
93+
return self._data.get('tn_w')
94+
95+
@property
96+
def thumbnail_height(self):
97+
return self._data.get('tn_h')
98+
99+
@property
100+
def thumbnail_fname(self):
101+
if not self.has_file:
102+
return None
103+
104+
board = self._thread._board
105+
106+
return '%is.jpg' % (
107+
self._data['tim']
108+
)
109+
110+
@property
111+
def thumbnail_url(self):
112+
if not self.has_file:
113+
return None
114+
115+
board = self._thread._board
116+
return self._url.thumb_url(
117+
self._data['tim']
118+
)
119+
120+
def file_request(self):
121+
return self._thread._board._requests_session.get(self.file_url)
122+
123+
def thumbnail_request(self):
124+
return self._thread._board._requests_session.get(self.thumbnail_url)

0 commit comments

Comments
 (0)