Just deleted about 400 bot accounts and a bunch of spam. To mitigate this in the future, we've enabled reCaptcha on signup. Let me know if someone got caught in the crossfire.

Commit 245a3556 authored by Rob Nelson's avatar Rob Nelson
Browse files

Initial commit

parents
*.pyc
*.bak
"""
4chan Site Plugin
"""
from pychan.plugins import BasePlugin
from site_4chan.handler_4chan import FourchanHandler
class FourChanPlugin(BasePlugin):
ID = 'b327f53e-63b6-44af-b1ca-3dfab48c1752'
NAME = '4chan Site Plugin'
AUTHORS = [
'nexisentertainment@gmail.com'
]
VERSION = '0.0.1-alpha'
def Load(self):
return [FourchanHandler]
4chan:
domains:
- boards.4chan.org
software: 4chan
delays:
site: 5
catalog: 30
thread: 30
\ No newline at end of file
swagger: '2.0'
info:
title: 4chan
# Y.M.D
version: 2018.09.05
description: An unofficial description of the endpoints available to developers
on 4chan, derived from 4chan's API repository on GitHub.
termsOfService: https://github.com/4chan/4chan-API
license:
name: MIT Opensource License
host: a.4cdn.org
schemes:
- https
- http
basePath: /
externalDocs:
description: Find out more about 4chan's API
url: https://github.com/4chan/4chan-API
definitions:
CatalogEntry:
$ref: definitions/CatalogEntry.yml
Board:
$ref: definitions/Board.yml
Post:
$ref: definitions/Post.yml
paths:
/{boardID}/{pageIdx}.json:
parameters:
- name: boardID
in: path
description: ID of the board.
required: true
type: string
pattern: ^[a-zA-Z0-9]+$
- name: pageIdx
in: path
required: true
minimum: 1
description: Page number, starting from 1
type: integer
get:
tags:
- boards
summary: Get threads on a board page.
description: Retrieves a list of thread IDs for a particular page on a particular board.
produces:
- application/json
responses:
404:
description: Board not found
200:
description: Board contents page
schema:
type: array
items:
type: object
properties:
page:
type: integer
description: index of the page.
example: 0
threads:
type: array
items:
$ref: definitions/CatalogEntry.yml
/{boardID}/catalog.json:
parameters:
- in: path
name: boardID
description: ID of the board.
required: true
type: string
pattern: ^[a-zA-Z0-9]+$
get:
tags:
- boards
summary: Get all threads on a board.
description: Presents all available threads on a given board.
produces:
- application/json
responses:
404:
description: Board does not exist.
200:
description: Paged thread list.
schema:
type: array
description: An array of pages.
items:
type: object
properties:
page:
type: integer
description: Index of the page.
threads:
type: array
items:
$ref: definitions/Post.yml
/{boardID}/threads.json:
parameters:
- in: path
name: boardID
description: ID of the board.
required: true
type: string
pattern: ^[a-zA-Z0-9]+$
get:
tags:
- boards
summary: Get all thread IDs and timestamps on a board.
description: Presents all available thread IDs and timestamps on a given board.
produces:
- application/json
responses:
404:
description: Board does not exist.
200:
description: Paged thread list.
schema:
type: array
description: An array of pages.
items:
type: object
description: Representation of a board page.
properties:
page:
type: integer
description: Index of the page.
threads:
type: array
items:
type: object
required:
- 'no'
- last_modified
properties:
'no':
type: integer
example: 7613594
description: Number of this post in each board. NOT unique
globally.
last_modified:
type: integer
description: Unix timestamp of the last change made to the
thread.
example: 1512937329
/{boardID}/thread/{threadID}.json:
parameters:
- in: path
name: boardID
description: ID of the board.
required: true
type: string
pattern: ^[a-zA-Z0-9]+$
- in: path
name: threadID
description: ID of the thread.
required: true
type: integer
get:
tags:
- threads
summary: Get all of the posts in a thread
description: Presents all available thread IDs and timestamps on a given board.
produces:
- application/json
responses:
404:
description: Board and/or thread does not exist.
200:
description: Paged thread list.
schema:
type: object
description: An object containing the post array.
required:
- posts
properties:
posts:
type: array
description: A list of all of the posts in the thread.
items:
$ref: definitions/Post.yml
/boards.json:
get:
tags:
- boards
summary: Get all of the boards currently hosted on 4chan.
description: A list of all boards present on 4chan.
produces:
- application/json
responses:
200:
description: Array of boards.
schema:
type: object
properties:
boards:
type: array
items:
$ref: definitions/Board.yml
troll_flags:
type: object
description: A key => name associative list of troll country codes.
title: Board
description: 4chan's representation of a board's settings.
type: object
required:
- board
- title
- per_page
- pages
- max_filesize
- max_comment_chars
- bump_limit
- image_limit
- cooldowns
- meta_description
properties:
board:
type: string
example: aco
description: Board ID
title:
type: string
example: Adult Cartoons
description: Name of the board in question
ws_board:
type: integer
example: 1
enum:
- 0
- 1
description: Work-safe board
per_page:
type: integer
example: 15
minimum: 0
description: Threads per page
pages:
type: integer
example: 10
minimum: 0
description: Number of pages
max_filesize:
type: integer
example: 4194304
minimum: 0
description: Maximum file size in, bytes.
max_webm_filesize:
type: integer
example: 3145728
minimum: 0
description: Maximum webm file size, in bytes.
max_comment_chars:
type: integer
example: 2000
minimum: 0
description: How many characters each post's comment is permitted to have.
max_webm_duration:
type: integer
example: 120
minimum: 0
description: How many seconds each webm is permitted to last.
bump_limit:
type: integer
example: 300
minimum: 0
description: Bump (reply) limit
image_limit:
type: integer
example: 250
minimum: 0
description: Image limit
cooldowns:
type: object
description: Various cooldowns implemented on the board
properties:
threads:
type: integer
example: 600
description: How many seconds must pass before you can post a new thread.
replies:
type: integer
example: 60
description: How many seconds must pass before you can post a new reply.
images:
type: integer
example: 30
description: How many seconds must pass before you can post a new image.
meta_description:
type: string
example: "\u0026quot;\/aco\/ - Adult Cartoons\u0026quot; is 4chan's imageboard for posting western-styled adult cartoon artwork.",
description: Meta description tag for SEO
is_archived:
type: integer
example: 1
enum:
- 0
- 1
description: Whether the board can archive threads or not.
custom_spoilers:
type: integer
example: 1
minimum: 0
maximum: 10
description: Custom spoilers are enabled when this is greater than 0. The actual value is used to select a specific set of spoiler images.
spoilers:
type: integer
example: 1
enum:
- 0
- 1
description: Spoilers are enabled when this is greater than 0.
user_ids:
type: integer
enum:
- 0
- 1
example: 1
description: Whether user IDs are enabled
country_flags:
type: integer
enum:
- 0
- 1
example: 1
description: Whether country flags are enabled
title: Catalog Entry
description: A simple object that just contains the first and last post of the thread.
type: object
required:
- posts
properties:
posts:
type: array
items:
$ref: ../definitions/Post.yml
title: Post
description: A post as seen in a catalog endpoint.
type: object
required:
- 'no'
- time
- last_modified
- resto
properties:
'no':
type: integer
example: 9001
description: Number of this post in each board. NOT unique globally.
resto:
type: integer
example: 0
description: Reply To
sticky:
type: integer
example: 1
description: Stickied thread
closed:
type: integer
example: 1
description: Locked thread
archived:
type: integer
example: 1
description: Archived thread
archived_on:
type: integer
example: 1344571233
description: UNIX timestamp of when the thread was archived.
now:
type: string
example: 08/08/12(Wed)01:11
description: MM/DD/YY(Day)HH:MM (:SS on some boards), EST/EDT timezone
time:
type: integer
example: 1344570123
description: UNIX timestamp
name:
type: string
example: moot
description: Name of the user
trip:
type: string
example: "!Ep8pui8Vw2"
description: text (format: !tripcode!!securetripcode)
id:
type: string
example: Admin
description: ID
capcode:
type: string
example: admin
description: Capcode
country:
type: string
example: XX
description: Country code
country_name:
type: string
example: Unknown
description: Country name
sub:
type: string
example: This is a subject
description: Subject
com:
type: string
example: This is a comment
description: Comment
tim:
type: integer
example: 1344402680740
description: Renamed filename
filename:
type: string
example: OPisa
description: Original filename
ext:
type: string
example: .jpg
description: File extension
fsize:
type: integer
example: 2500
description: File size
md5:
type: string
example: NOetrLVnES3jUn1x5ZPVAg==
description: File MD5
w:
type: integer
example: 500
description: Image width
h:
type: integer
example: 500
description: Image height
tn_w:
type: integer
example: 250
description: Thumbnail width
tn_h:
type: integer
example: 250
description: Thumbnail height
filedeleted:
type: integer
example: 0
description: File deleted?
spoiler:
type: integer
example: 0
description: Spoiler image?
custom_spoiler:
type: integer
example: 3
description: Custom spoilers?
omitted_posts:
type: integer
example: 33
description: replies omitted
omitted_images:
type: integer
example: 21
description: image replies omitted
replies:
type: integer
example: 231
description: replies total
images:
type: integer
example: 132
description: images total
bumplimit:
type: integer
example: 0
description: Bump limit met?
imagelimit:
type: integer
example: 1
description: Image limit met?
capcode_replies:
type: object
additionalProperties: true
example: {"admin":[1234,1267]}
description: Capcode user replies
last_modified:
type: integer
example: 1344571233
description: Time when last modified
tag:
type: string
example: Loop
description: Thread tag
semantic_url:
type: string
example: daily-programming-thread
description: Thread URL slug
since4pass:
type: integer
example: 2016
description: Year 4chan Pass bought
import json
import os
from collections import OrderedDict
import yaml
def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
class OrderedLoader(Loader):
pass
def construct_mapping(loader, node):
loader.flatten_mapping(node)
return object_pairs_hook(loader.construct_pairs(node))
OrderedLoader.add_constructor(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
construct_mapping)
return yaml.load(stream, OrderedLoader)
def ordered_dump(data, stream=None, Dumper=yaml.Dumper, **kwds):
class OrderedDumper(Dumper):
pass
def _dict_representer(dumper, data):
return dumper.represent_mapping(
yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
data.items())
OrderedDumper.add_representer(OrderedDict, _dict_representer)
return yaml.dump(data, stream, OrderedDumper, **kwds)