1+ #!/usr/bin/env python3
2+
3+ import getopt
4+ import http .cookiejar
5+ import sys
6+ import urllib .parse
7+ import urllib .request
8+ from http .cookies import SimpleCookie
9+ from json import loads as json_loads
10+ from os import environ
11+
12+ _headers = {"Referer" : 'https://rentry.co' }
13+
14+
15+ class UrllibClient :
16+ """Simple HTTP Session Client, keeps cookies."""
17+
18+ def __init__ (self ):
19+ self .cookie_jar = http .cookiejar .CookieJar ()
20+ self .opener = urllib .request .build_opener (urllib .request .HTTPCookieProcessor (self .cookie_jar ))
21+ urllib .request .install_opener (self .opener )
22+
23+ def get (self , url , headers = {}):
24+ request = urllib .request .Request (url , headers = headers )
25+ return self ._request (request )
26+
27+ def post (self , url , data = None , headers = {}):
28+ postdata = urllib .parse .urlencode (data ).encode ()
29+ request = urllib .request .Request (url , postdata , headers )
30+ return self ._request (request )
31+
32+ def _request (self , request ):
33+ response = self .opener .open (request )
34+ response .status_code = response .getcode ()
35+ response .data = response .read ().decode ('utf-8' )
36+ return response
37+
38+
39+ def raw (url ):
40+ client = UrllibClient ()
41+ return json_loads (client .get ('https://rentry.co/api/raw/{}' .format (url )).data )
42+
43+
44+ def new (url , edit_code , text ):
45+ client , cookie = UrllibClient (), SimpleCookie ()
46+
47+ cookie .load (vars (client .get ('https://rentry.co' ))['headers' ]['Set-Cookie' ])
48+ csrftoken = cookie ['csrftoken' ].value
49+
50+ payload = {
51+ 'csrfmiddlewaretoken' : csrftoken ,
52+ 'url' : url ,
53+ 'edit_code' : edit_code ,
54+ 'text' : text
55+ }
56+
57+ return json_loads (client .post ('https://rentry.co/api/new' , payload , headers = _headers ).data )
58+
59+
60+ def edit (url , edit_code , text ):
61+ client , cookie = UrllibClient (), SimpleCookie ()
62+
63+ cookie .load (vars (client .get ('https://rentry.co' ))['headers' ]['Set-Cookie' ])
64+ csrftoken = cookie ['csrftoken' ].value
65+
66+ payload = {
67+ 'csrfmiddlewaretoken' : csrftoken ,
68+ 'edit_code' : edit_code ,
69+ 'text' : text
70+ }
71+
72+ return json_loads (client .post ('https://rentry.co/api/edit/{}' .format (url ), payload , headers = _headers ).data )
73+
74+
75+ def usage ():
76+ print ('''
77+ Usage: rentry {new | edit | raw} {-h | --help} {-u | --url} {-p | --edit-code} text
78+
79+ Commands:
80+ new create a new entry
81+ edit edit an existing entry
82+ raw get raw markdown text of an existing entry
83+
84+ Options:
85+ -h, --help show this help message and exit
86+ -u, --url URL url for the entry, random if not specified
87+ -p, --edit-code EDIT-CODE edit code for the entry, random if not specified
88+
89+ Examples:
90+ rentry new 'markdown text' # new entry with random url and edit code
91+ rentry new -p pw -u example 'text' # with custom edit code and url
92+ rentry edit -p pw -u example 'text' # edit the example entry
93+ cat FILE | rentry new # read from FILE and paste it to rentry
94+ cat FILE | rentry edit -p pw -u example # read from FILE and edit the example entry
95+ rentry raw -u example # get raw markdown text
96+ rentry raw -u https://rentry.co/example # -u accepts absolute and relative urls
97+ ''' )
98+
99+
100+ if __name__ == '__main__' :
101+ try :
102+ environ .pop ('POSIXLY_CORRECT' , None )
103+ opts , args = getopt .gnu_getopt (sys .argv [1 :], "hu:p:" , ["help" , "url=" , "edit-code=" ])
104+ except getopt .GetoptError as e :
105+ sys .exit ("error: {}" .format (e ))
106+
107+ command , url , edit_code , text = None , '' , '' , None
108+
109+ for o , a in opts :
110+ if o in ("-h" , "--help" ):
111+ usage ()
112+ sys .exit ()
113+ elif o in ("-u" , "--url" ):
114+ url = urllib .parse .urlparse (a ).path .strip ('/' )
115+ elif o in ("-p" , "--edit-code" ):
116+ edit_code = a
117+
118+ command = (args [0 :1 ] or [None ])[0 ]
119+ command or sys .exit (usage ())
120+ command in ['new' , 'edit' , 'raw' ] or sys .exit ('error: command must be new, edit or raw' )
121+
122+ text = (args [1 :2 ] or [None ])[0 ]
123+ if not text and command != 'raw' :
124+ text = sys .stdin .read ().strip ()
125+ text or sys .exit ('error: text is required' )
126+
127+ if command == 'new' :
128+ response = new (url , edit_code , text )
129+ if response ['status' ] != '200' :
130+ print ('error: {}' .format (response ['content' ]))
131+ try :
132+ for i in response ['errors' ].split ('.' ):
133+ i and print (i )
134+ sys .exit (1 )
135+ except :
136+ sys .exit (1 )
137+ else :
138+ print ('Url: {}\n Edit code: {}' .format (response ['url' ], response ['edit_code' ]))
139+
140+ elif command == 'edit' :
141+ url or sys .exit ('error: url is required' )
142+ edit_code or sys .exit ('error: edit code is required' )
143+
144+ response = edit (url , edit_code , text )
145+ if response ['status' ] != '200' :
146+ print ('error: {}' .format (response ['content' ]))
147+ try :
148+ for i in response ['errors' ].split ('.' ):
149+ i and print (i )
150+ sys .exit (1 )
151+ except :
152+ sys .exit (1 )
153+ else :
154+ print ('Ok' )
155+
156+ elif command == 'raw' :
157+ url or sys .exit ('error: url is required' )
158+ response = raw (url )
159+ if response ['status' ] != '200' :
160+ sys .exit ('error: {}' .format (response ['content' ]))
161+ print (response ['content' ])
0 commit comments