gitpub-py 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,54 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+
4
+ <head>
5
+ <meta charset="UTF-8">
6
+ <meta name="viewport" content="width=device-width" />
7
+ <link rel="stylesheet" type="text/css" href="{{ inter_css }}">
8
+ <script src="{{ paged_js }}"></script>
9
+ <script src="{{ tree_js }}"></script>
10
+ <link rel="stylesheet" type="text/css" href="{{ custom_css }}">
11
+ <script src="{{ flow_js }}"></script>
12
+ <title>{{ folder_name }}</title>
13
+ </head>
14
+
15
+ <body>
16
+
17
+ {% if cover %}
18
+ <div id="cover">
19
+ {{ cover | safe }}
20
+ </div>
21
+ {% else %}
22
+ <div id="cover_page">
23
+ <h1>{{ folder_name }}</h1>
24
+ </div>
25
+ {% endif %}
26
+
27
+
28
+
29
+ <ul id="toc">
30
+ {% for item in toc %}
31
+ <li class="{{ item.class }}">
32
+ {% if item.href %}
33
+ <a href="{{ item.href }}">{{ item.text }}</a>
34
+ {% else %}
35
+ <span>{{ item.text }}</span>
36
+ {% endif %}
37
+ </li>
38
+ {% endfor %}
39
+ </ul>
40
+
41
+ <div id="all-meta">
42
+ {% for meta in meta_contents %}
43
+ {{ meta | safe }}
44
+ {% endfor %}
45
+ </div>
46
+
47
+ <div id="all-main">
48
+ {% for main in main_contents %}
49
+ {{ main | safe }}
50
+ {% endfor %}
51
+ </div>
52
+
53
+ </body>
54
+ </html>
@@ -0,0 +1,48 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en-US">
3
+ <head>
4
+ <meta charset="utf-8" />
5
+ <meta name="generator" content="pandoc" />
6
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
7
+ $if(date-meta)$
8
+ <meta name="dcterms.date" content="$date-meta$" />
9
+ $endif$
10
+ $if(keywords)$
11
+ <meta name="keywords" content="$for(keywords)$$keywords$$sep$, $endfor$" />
12
+ $endif$
13
+ $if(description-meta)$
14
+ <meta name="description" content="$description-meta$" />
15
+ $endif$
16
+ <title>$pagetitle$</title>
17
+ </head>
18
+
19
+ <body>
20
+
21
+ $if(references)$
22
+ <div class="metacontainer">
23
+ <span class="file-header meta-header"></span>
24
+ $for(references)$
25
+ <div class="metablock">
26
+ <p class="cm-date"><span>on</span> $references.status$</p>
27
+ <p class="cm-author">$references.publisher$ <span>said</span></p>
28
+ <p class="cm-message">$references.note$</p>
29
+ <p class="cm-div"><span>making</span> $references.division$ <span>changes to</span></p>
30
+ <ul>
31
+ $for(references.categories)$
32
+ <li class="cm-categories">$references.categories$</li>
33
+ $endfor$
34
+ </ul>
35
+ </div>
36
+ $endfor$
37
+ </div>
38
+ $endif$
39
+
40
+ <div class="maincontainer">
41
+ $if(og_title)$
42
+ <h1 class="file-header" id="$pagetitle$">$og_title$</h1>
43
+ $endif$
44
+ $body$
45
+ </div>
46
+
47
+ </body>
48
+ </html>
gitpub_py/gitpub.py ADDED
@@ -0,0 +1,310 @@
1
+ import subprocess
2
+ from pathlib import Path
3
+ import pathlib
4
+ import os
5
+ import glob
6
+ from pydriller import Repository
7
+ from bs4 import BeautifulSoup
8
+ from bs4 import Doctype
9
+ import yaml
10
+ from jinja2 import Environment, FileSystemLoader
11
+
12
+ def main():
13
+
14
+ # --------------------------------------
15
+ # ------------ user inputs -------------
16
+ # --------------------------------------
17
+
18
+ # ask user for path input
19
+ path_input = input("enter absolute path: ")
20
+ # test_path = '/Users/kimfilippa/Desktop/ma_thesis'
21
+
22
+ # ask user for filetype input (only .md and .html work so far)
23
+ filetype_input = input("enter filetypes with . separated by spaces: ")
24
+ filetypes = filetype_input.split(" ") # responds with a list like that ['.md', '.html']
25
+
26
+ # html cover file
27
+ cover_input = input("add custom cover? y / N ")
28
+ cover_file = ""
29
+ if cover_input.lower() == "y":
30
+ cover_path_input = input("enter cover file path (skip to use default): ")
31
+ if cover_path_input == "":
32
+ cover_file = "assets/templates/cover.html"
33
+ print("cover file not defined, using default at assets/templates/cover.html")
34
+ elif not(os.path.exists(cover_path_input)):
35
+ cover_file = "assets/templates/cover.html"
36
+ print("cover file not found, using default at assets/templates/cover.html")
37
+ elif not(cover_path_input.endswith('.html')):
38
+ cover_file = cover_path_input + ".html"
39
+ else:
40
+ cover_file = cover_path_input
41
+ else:
42
+ cover_file = ""
43
+
44
+
45
+ # custom css file
46
+ first_css_input = input("add stylesheet? y / N ")
47
+ custom_css = ""
48
+
49
+ if first_css_input.lower() == "y":
50
+ css_input = input("enter custom stylesheet path (skip to use default): ")
51
+ if css_input == '':
52
+ custom_css = 'assets/css/style.css'
53
+ print('stylesheet not defined, using default')
54
+ elif not(os.path.exists(css_input)):
55
+ custom_css = 'assets/css/style.css'
56
+ print('stylesheet not found, using default at')
57
+ elif not(css_input.endswith('.css')):
58
+ custom_css = css_input + ".css"
59
+ else:
60
+ custom_css = css_input
61
+ else:
62
+ custom_css = Path(__file__).parent / "assets" / "css" / "style.css" # this gives the right path, but it cant be rendered in the browser bc its local and absolute
63
+
64
+ # transform into relative path
65
+ rel_css_path = os.path.relpath(custom_css, start=os.curdir)
66
+
67
+ # custom template file
68
+ custom_temp = False # var false by default
69
+ first_temp_input = input("add custom template? y / N ")
70
+
71
+ if first_temp_input.lower() == "y":
72
+ temp_input = input("enter custom template filename (inside of templates/ dir at root): ")
73
+ temp_path = os.path.join('templates', temp_input)
74
+ print(temp_path)
75
+ if temp_input == '':
76
+ custom_temp = False
77
+ print('template not defined, using default')
78
+ elif not(os.path.exists(temp_path)):
79
+ custom_temp = False
80
+ print('template not found, using default')
81
+ elif not(temp_input.endswith('.html')):
82
+ custom_temp = True
83
+ custom_title = temp_input + ".html"
84
+ else:
85
+ custom_temp = True
86
+ custom_title = temp_input
87
+ else:
88
+ custom_temp = False
89
+
90
+ # make the template path for default temp:
91
+ template_dir = Path(__file__).parent / "assets" / "templates"
92
+ pandoc_temp_path = Path(__file__).parent / "assets" / "templates" / "template.html"
93
+
94
+
95
+ output_yaml = Path("yaml") # make output dir for individual html files
96
+ output_yaml.mkdir(exist_ok=True)
97
+
98
+
99
+ # ------------------------------------------
100
+ # ---------- gitpub ignore config ----------
101
+ # ------------------------------------------
102
+ #ignore_path = os.path.join(path_input, '.gitpubignore')
103
+ ignore_path = '.gitpubignore'
104
+ ignore_files = []
105
+
106
+ # make sure the gitpub ignore file exists and is not empty
107
+ if os.path.exists(ignore_path) and os.path.getsize(ignore_path) > 0:
108
+
109
+ # Read lines without newline characters
110
+ with open(ignore_path, 'r') as file:
111
+ ignore_files = [line.strip() for line in file]
112
+
113
+
114
+ # ------------------------------------------
115
+ # ------------ git log to file -------------
116
+ # ------------------------------------------
117
+
118
+ def git_to_file(file): # def defines the function, function name, function object
119
+ commit_list = [] # opens an empty list to which we will append the files commit blocks
120
+
121
+ for commit in Repository(path_input, filepath=file).traverse_commits():
122
+ # get all commits of file into a python dictionary
123
+ commit_block = {
124
+ "id": f"{commit.hash[:7]}",
125
+ "status": f"{commit.author_date}",
126
+ "publisher": f"{commit.author.name}",
127
+ "note": f"{commit.msg}",
128
+ "division": f"-{commit.deletions} +{commit.insertions}",
129
+ "categories": list(commit.branches)
130
+ }
131
+
132
+ commit_list.append(commit_block) # append the commit blocks to the list
133
+
134
+ # patch new filename using os (https://bobbyhadz.com/blog/python-remove-extension-from-filename)
135
+ new_path = pathlib.Path(file)
136
+ # set og filetitle in metadata var
137
+ og_title = {"og_title": f"{new_path.name}"}
138
+ yaml_file = os.path.join(os.getcwd(), output_yaml, new_path.stem + '.yaml' )
139
+
140
+ with open(yaml_file, 'w+') as yf:
141
+ yf.write("---\nreferences:\n" + yaml.dump(commit_list, sort_keys=False) + yaml.dump(og_title) + "\n---") # write yaml output to new file
142
+
143
+
144
+ # this needs to be done on every desired filetype:
145
+ # loop through all .md files and subdirectories
146
+ md_files = [p for p in Path(path_input).glob("**/*") if p.suffix in set(filetypes)]
147
+ for md_file in md_files:
148
+ if ignore_files:
149
+ if md_file.name in ignore_files:
150
+ continue
151
+
152
+ # Skip hidden directories or files inside them
153
+ if any(part.startswith('.') for part in md_file.parts):
154
+ continue
155
+
156
+ git_to_file(md_file) # run the above function on each .md file
157
+
158
+
159
+ # --------------------------------------
160
+ # ---------- render html files ---------
161
+ # --------------------------------------
162
+
163
+ output_dir = Path("html") # make output dir for individual html files
164
+ output_dir.mkdir(exist_ok=True)
165
+
166
+ # this can be done with .md and .html
167
+ # also, this is the same line as md_files make var to avoid redundancy?
168
+ all_mds = [p for p in Path(path_input).glob("**/*") if p.suffix in set(filetypes)]
169
+ for all_md in all_mds:
170
+ # Skip hidden directories or files inside them
171
+ if any(part.startswith('.') for part in all_md.parts):
172
+ continue
173
+
174
+ if ignore_files:
175
+ if all_md.name in ignore_files:
176
+ continue
177
+
178
+ # define output dir and output filename
179
+ h_output = output_dir / all_md.with_suffix('.html').name
180
+
181
+ # strip suffix and add .yaml using pathlib
182
+ all_clean = all_md.with_suffix('')
183
+ all_yaml = all_md.with_suffix('.yaml')
184
+ yaml_path = output_yaml / Path(all_yaml).name
185
+
186
+ # check if all_yaml exists (because excluded files dont have yaml and would throw an error)
187
+ if yaml_path.exists():
188
+ yaml_file = f'--metadata-file={str(yaml_path)}' # only add the yaml file if it exists (otherwise references error)
189
+ else:
190
+ yaml_file = ''
191
+
192
+
193
+ # run pandoc, citation argument is only passed when true: https://stackoverflow.com/a/61068722
194
+ subprocess.run(['pandoc', str(all_md), '-s', '--template', str(pandoc_temp_path), *([yaml_file] if yaml_file else []), '-o', str(h_output)])
195
+
196
+
197
+
198
+ # ----------------------------------------------------------------------
199
+ # ------------ patch html files together into one document -------------
200
+ # ----------------------------------------------------------------------
201
+ # for global filename: get user input path directory & extract the folder name from the path
202
+ folder_name = os.path.basename(path_input)
203
+
204
+ # create paths for js and interface.css files
205
+ interface_css = Path(__file__).parent / "assets" / "css" / "interface.css"
206
+ rel_interface_path = os.path.relpath(interface_css, start=os.curdir)
207
+
208
+ paged_js = Path(__file__).parent / "assets" / "js" / "paged-polyfill.js"
209
+ rel_paged_path = os.path.relpath(paged_js, start=os.curdir)
210
+
211
+ flow_js = Path(__file__).parent / "assets" / "js" / "parallel-flows.js"
212
+ rel_flow_path = os.path.relpath(flow_js, start=os.curdir)
213
+
214
+ tree_js = Path(__file__).parent / "assets" / "js" / "csstree.js"
215
+ rel_tree_path = os.path.relpath(tree_js, start=os.curdir)
216
+
217
+
218
+ # patch html files into one (beautifulsoup)
219
+
220
+ # sorts the files alphabetically (?)
221
+ sorted_files = sorted(output_dir.glob('*'))
222
+
223
+ # create conatiners for lists that will then be looped through with jinja template (document.html)
224
+ meta_contents = []
225
+ main_contents = []
226
+ body_parts = []
227
+ toc = []
228
+
229
+ # loop through sorted files
230
+ for file in sorted_files:
231
+
232
+ with open(file, 'r') as html_file:
233
+
234
+ soup = BeautifulSoup(html_file.read(), "html.parser")
235
+
236
+ # generate TOC (loop through h1 and h2)
237
+ for header in soup.find_all('h1', class_='file-header'):
238
+ # set the items attributes
239
+ toc_item = {
240
+ "class": "toc-heading",
241
+ "text": header.get_text(),
242
+ "href": "#" + header.get("id") if header.get("id") else None
243
+ }
244
+ # append to the toc container
245
+ toc.append(toc_item)
246
+
247
+ # collect metacontainer elements
248
+ meta_elements = soup.find_all(class_=["metablock", "meta-header"])
249
+ for meta in meta_elements:
250
+ meta_contents.append(str(meta))
251
+
252
+ # collect maincontainer elements
253
+ main = soup.find(class_="maincontainer")
254
+ if main:
255
+ for child in main.children:
256
+ main_contents.append(str(child))
257
+
258
+ # collect contents of body
259
+ body = soup.find("body")
260
+ if body:
261
+ for part in body.children:
262
+ body_parts.append(str(part))
263
+
264
+ # cover (intially set to none)
265
+ cover_html = None
266
+
267
+ if cover_file:
268
+ # open, parse and render it into a variable that we can get in jinja template
269
+ with open(cover_file, "r") as cover:
270
+ cover_soup = BeautifulSoup(cover.read(), "html.parser")
271
+ cover_html = str(cover_soup)
272
+
273
+ # set up jinja environment: (other than loading directly from a file, this allows includes, template inheritance ...)
274
+ if custom_temp == True:
275
+ custom_env = Environment(loader=FileSystemLoader("templates/"))
276
+ print(custom_env)
277
+ template = custom_env.get_template(custom_title)
278
+ else:
279
+ env = Environment(loader=FileSystemLoader(str(template_dir)))
280
+ template = env.get_template("document.html")
281
+
282
+ # render the html with passing the variables to jinja
283
+ final_html = template.render(
284
+ folder_name=folder_name,
285
+ custom_css=str(rel_css_path),
286
+ cover=cover_html,
287
+ toc=toc,
288
+ meta_contents=meta_contents,
289
+ main_contents=main_contents,
290
+ body_parts=body_parts,
291
+ inter_css=str(rel_interface_path),
292
+ paged_js=str(rel_paged_path),
293
+ flow_js=str(rel_flow_path),
294
+ tree_js=str(rel_tree_path)
295
+ )
296
+
297
+ # and write it to file
298
+ with open("gitpub.html", "w", encoding="utf-8") as f:
299
+ f.write(final_html)
300
+
301
+
302
+ # ------------------------------------------------------------------------
303
+ # ------------ optional: cleaning temp files and pagination -------------
304
+ # ------------------------------------------------------------------------
305
+
306
+ # empty the html dir
307
+ os.system('rm ./html/*')
308
+
309
+ # empty the yaml dir
310
+ os.system('rm ./yaml/*')
@@ -0,0 +1,74 @@
1
+ Metadata-Version: 2.4
2
+ Name: gitpub-py
3
+ Version: 1.0.0
4
+ Summary: A collaborative web to print tool based on the git version control software
5
+ Keywords: git,print,terminal,pdf,markdown,html
6
+ Author: Kim Kleinert
7
+ Author-email: Kim Kleinert <mail@kimkleinert.com>
8
+ License-Expression: LicenseRef-CC4R-1.0
9
+ License-File: LICENSE
10
+ Classifier: Programming Language :: Python :: 3
11
+ Classifier: Operating System :: MacOS
12
+ Classifier: Operating System :: POSIX :: Linux
13
+ Classifier: Programming Language :: Python
14
+ Classifier: Programming Language :: JavaScript
15
+ Classifier: Topic :: Artistic Software
16
+ Classifier: Topic :: Printing
17
+ Classifier: Topic :: Software Development :: Version Control :: Git
18
+ Classifier: Topic :: Text Processing :: Markup :: HTML
19
+ Requires-Dist: beautifulsoup4
20
+ Requires-Dist: jinja2
21
+ Requires-Dist: pydriller
22
+ Requires-Dist: pyyaml
23
+ Requires-Python: >=3.9
24
+ Project-URL: Homepage, https://gitpub.directory
25
+ Project-URL: Repository, https://gitlab.com/km_kt/gitpub
26
+ Description-Content-Type: text/markdown
27
+
28
+ # GitPub
29
+
30
+ GitPub creates a printable publication from a Git repositories text files, including file metadata.
31
+
32
+ ## Installing
33
+
34
+ to install, run `pip install gitpub-py`
35
+
36
+ ## Requirements
37
+
38
+ - pandoc (see [installing pandoc](https://pandoc.org/installing.html))
39
+ - python
40
+ - pip
41
+
42
+ ## Usage
43
+
44
+ 1. to use, run `make-gitpub`
45
+ 2. enter an absolute path to a local git repository
46
+ 3. enter filetypes that you want to include (supported are .md .html)
47
+ 4. for detailed description of further options see [repository](https://gitlab.com/km_kt/gitpub)
48
+ 5. preview the generated gitpub.html file in your browser
49
+ 6. press `cmd` + `p` to print or export to pdf
50
+
51
+ ## Environment
52
+
53
+ GitPub is inspired by and learning from many tools and communities that understand the use, modification and distribution of software as active part of creative, collaborative practices:
54
+
55
+ - [Creative Crowds](https://cc.practices.tools/)
56
+ - [Pre Post Print](https://prepostprint.org)
57
+ - [Experimental Publishing](https://xpub.nl/)
58
+ - [Constant](https://constantvzw.org/)
59
+ - [OSP](https://osp.kitchen/)
60
+ - [Hackers & Designers](https://hackersanddesigners.nl/)
61
+
62
+ GitPub uses:
63
+
64
+ - [Pandoc](https://pandoc.org/index.html) to convert documents (2006–2025 John MacFarlane)
65
+ - the [Jinja](jinja.palletsprojects.com/en/stable/) templating engine (2007 Pallets)
66
+ - the [PyDriller](https://github.com/ishepard/pydriller) framework to analyze git repositories (2018 Davide Spadini)
67
+ - [Paged.js](https://pagedjs.org/) to create a paginated pdf preview from an html document (Adam Hyde, maintained by julientaq, Fred Chasen and Gijs de Heij)
68
+ - [paralell-flows](https://pagedjs.org/posts/en/parallel-flows-within-paged.js/) (modfied) a paged.js plugin to define parallel layouts
69
+
70
+
71
+ ## License
72
+
73
+ Kim Kleinert, GitPub, 2026.
74
+ Copyleft with a difference: This is a collective work, you are invited to copy, distribute, and modify it under the terms of the [CC4r](https://constantvzw.org/wefts/cc4r.en.html).
@@ -0,0 +1,15 @@
1
+ gitpub_py/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
2
+ gitpub_py/assets/css/interface.css,sha256=mEaD6Bt4Xo5wli2MN40xkxrRdXuddpiAeREiQy5jE0A,4730
3
+ gitpub_py/assets/css/parallel-flow.css,sha256=5E0UzppgmVne9RsU83EENWMhYL1BuamsKpt_p4La-sc,5419
4
+ gitpub_py/assets/css/style.css,sha256=RlH0-afUvno_2E-x73TWGgJTiSwIMBh-6KxK9ETFC6k,6004
5
+ gitpub_py/assets/js/csstree.js,sha256=XLVu6H5MzdBvkOzKcmCtl-HMxNEdkc2ca4guYrAy8c0,421659
6
+ gitpub_py/assets/js/paged-polyfill.js,sha256=9Z82GAJBbHcNVJpkeVhkmvLPZgGZmSS8AOT1B9rVJp8,921702
7
+ gitpub_py/assets/js/parallel-flows.js,sha256=QcErlYjcFpZTkwsGDnfBWZJ-T5eYlnBAalMnR58h4-o,24215
8
+ gitpub_py/assets/templates/document.html,sha256=Q1k5Qf5yqh1cXbgQ8qj4CZXsOVhX60M55m4JSIgNC54,1063
9
+ gitpub_py/assets/templates/template.html,sha256=aZFmCeyL_tVqvHC4SmnR_DJdBIXkC_JyjFrj0fmAv4o,1367
10
+ gitpub_py/gitpub.py,sha256=uXZ2rtHvX6LdN3_JwttSMc2K9ZTjWL7EI76T9POG-lE,12145
11
+ gitpub_py-1.0.0.dist-info/licenses/LICENSE,sha256=0AZLHK2s9klYaH5MnvyvqxlcaezNkX1hInN_f2ZUnWM,13302
12
+ gitpub_py-1.0.0.dist-info/WHEEL,sha256=LlB9zUOn921TC3CC5yCeS6O5jsLlxqKqIpg_Zk6XXcQ,81
13
+ gitpub_py-1.0.0.dist-info/entry_points.txt,sha256=0wZpIoF0KoM1_lOFGeuwQgUWhz8BuR2DQVRNdEIbUgE,55
14
+ gitpub_py-1.0.0.dist-info/METADATA,sha256=La9H9uGQglhbCwh7g7T65x5YkmggCr66ohQ1nT-PoYI,2940
15
+ gitpub_py-1.0.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: uv 0.11.20
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ make-gitpub = gitpub_py.gitpub:main
3
+
@@ -0,0 +1,121 @@
1
+ Published version: https://constantvzw.org/wefts/cc4r.en.html
2
+ Castellano: https://pad.constantvzw.org/p/cc4r_en_castellano
3
+ Français: https://pads.domainepublic.net/p/cc4r
4
+
5
+
6
+
7
+ [ Copyleft Attitude with a difference ]
8
+
9
+ COLLECTIVE CONDITIONS FOR RE-USE (CC4r)
10
+ version 1.0
11
+
12
+ ============
13
+ REMINDER TO CURRENT AND FUTURE AUTHORS:
14
+ The authored work released under the CC4r was never yours to begin with. The CC4r considers authorship to be part of a collective cultural effort and rejects authorship as ownership derived from individual genius. This means to recognize that it is situated in social and historical conditions and that there may be reasons to refrain from release and re-use.
15
+ =============
16
+
17
+ PREAMBLE
18
+
19
+ The CC4r articulates conditions for re-using authored materials. This document is inspired by the principles of Free Culture – with a few differences. You are invited to copy, distribute, and transform the materials published under these conditions, and to take the implications of (re-)use into account.
20
+
21
+ The CC4r understands authorship as inherently collaborative and already-collective. It applies to hybrid practices such as human-machine collaborations and other-than-human contributions. The legal framework of copyright ties authorship firmly in property and individual human creation, and prevents more fluid modes of authorial becoming from flourishing. Free Culture and intersectional, feminist, anti-colonial work reminds us that there is no tabula rasa, no original or single author; that authorial practice exist within a web of references.
22
+
23
+ The CC4r favours re-use and generous access conditions. It considers hands-on circulation as a necessary and generative activation of current, historical and future authored materials. While you are free to (re-)use them, you are not free from taking the implications from (re-)use into account.
24
+
25
+ The CC4r troubles the binary approach that declares authored works either ‘open’ or ‘closed'. It tries to address how a universalist approach to openness such as the one that Free licenses maintain, has historically meant the appropriation of marginalised knowledges. It is concerned with the way Free Culture, Free Licenses and Open Access do not account for the complexity and porosity of knowledge practices and their circulation, nor for the power structures active around it. This includes extractive use by software giants and commercial on-line platforms that increasingly invest into and absorb Free Culture.
26
+
27
+ The CC4r asks CURRENT and FUTURE AUTHORS, as a collective, to care together for the implications of appropriation. To be attentive to the way re-use of materials might support or oppress others, even if this will never be easy to gauge. This implies to consider the collective conditions of authorship.
28
+
29
+ The CC4r asks you to be courageous with the use of materials that are being licensed under the CC4r. To discuss them, to doubt, to let go, to change your mind, to experiment with them, to give back to them and to take responsibility when things might go wrong.
30
+
31
+ Considering the Collective Conditions for (re-)use involves inclusive crediting and speculative practices for referencing and resourcing. To consider the circulation of materials on commercial platforms as participating in extractive data practices; platform capitalism appropriates and abuses collective authorial practice. To take into account that the defaults of openness and transparency have different consequences in different contexts. To consider the potential necessity for opacity when accessing and transmitting knowledge, especially when it involves materials that matter to marginalized communities.
32
+
33
+ This document was written in response to the Free Art License (FAL) in a process of coming to terms with the colonial structuring of knowledge production. It emerged out of concerns with the way Open Access and Free Culture ideologies by foregrounding openness and freedom as universal principles might replicate some of the problems with conventional copyright.
34
+
35
+ DEFINITIONS
36
+ -----------
37
+ « LEGAL AUTHOR » In the CC4r, LEGAL AUTHOR is used for the individual that is assigned as "author" by conventional copyright. Even if the authored work was never theirs to begin with, he or she is the only one that is legally permitted to license a work under a CC4r. This license is therefore not about liability, or legal implications. It cares about the ways copyright contributes to structural inequalities.
38
+ « CURRENT AUTHOR » can be used for individuals and collectives. It is the person, collective or other that was involved in generating the work created under a CC4r license. CURRENT and FUTURE AUTHOR are used to avoid designations that overly rely on concepts of 'originality' and insist on linear orders of creation.
39
+ « FUTURE AUTHOR » can be used for individuals and collectives. They want to use the work under CC4r license and are held to its conditions. All future authors are considered coauthors, or anauthors. They are anauthorized because this license provides them with an unauthorized authorization.
40
+ « LICENSE » due to its conditional character, this document might actually not qualify as a license. It is for sure not a Free Culture License. see also: UNIVERSALIST OPENNESS.
41
+ « (RE-)USE » the CC4r opted for bracketing "RE" out of necessity to mess up the time-space linearity of the original.
42
+ « OPEN <-> CLOSED » the CC4r operates like rotating doors... it is a swinging license, or a hinged license.
43
+ « UNIVERSALIST OPENNESS » the CC4r tries to propose an alternative to universalist openness. A coming to terms with the fact that universal openness is "safe" only for some.
44
+
45
+
46
+ 0. CONDITIONS
47
+
48
+ The invitation to (re-)use the work licenced under CC4r applies as long as the FUTURE AUTHOR is convinced that this does not contribute to oppressive arrangements of power, privilege and difference. These may be reasons to refrain from release and re-use.
49
+ If it feels paralyzing to decide whether or not these conditions apply, it might point at the need to find alternative ways to activate the work. In case of doubt, consult for example https://constantvzw.org/wefts/orientationspourcollaboration.en.html
50
+
51
+ 1. OBJECT
52
+ The aim of this license is to articulate collective conditions for re-use.
53
+
54
+ 2. SCOPE
55
+ The work licensed under the CC4r is reluctantly subject to copyright law. By applying CC4r, the legal author extends its rights and invites others to copy, distribute, and modify the work.
56
+
57
+ 2.1 INVITATION TO COPY (OR TO MAKE REPRODUCTIONS)
58
+ When the conditions under 0. apply, you are invited to copy this work, for whatever reason and with whatever technique.
59
+
60
+ 2.2 INVITATION TO DISTRIBUTE, TO PERFORM IN PUBLIC
61
+ As long as the conditions under 0. apply, you are invited to distribute copies of this work; modified or not, whatever the medium and the place, with or without any charge, provided that you:
62
+ - attach this license to each of the copies of this work or indicate where the license can be found.
63
+ - make an effort to account for the collective conditions of the work, for example what contributions were made to the modified work and by whom, or how the work could continue.
64
+ - specify where to access other versions of the work.
65
+
66
+ 2.3 INVITATION TO MODIFY
67
+ As long as the conditions under 0. apply, you are invited to make future works based on the current work, provided that you:
68
+ - observe all conditions in article 2.2 above, if you distribute future works;
69
+ - indicate that the work has been modified and, if possible, what kind of modifications have been made.
70
+ - distribute future works under the same license or any compatible license.
71
+
72
+ 3. INCORPORATION OF THE WORK
73
+ Incorporating this work into a larger work (i.e., database, anthology, compendium, etc.) is possible. If as a result of its incorporation, the work can no longer be accessed apart from its appearance within the larger work, incorporation can only happen under the condition that the larger work is as well subject to the CC4r or to a compatible license.
74
+
75
+ 4. COMPATIBILITY
76
+ A license is compatible with the CC4r provided that:
77
+ - it invites users to take the implications of their appropriation into account;
78
+ - it invites to copy, distribute, and modify copies of the work including for commercial purposes and without any other restrictions than those required by the other compatibility criteria;
79
+ - it ensures that the collective conditions under which the work was authored are attributed unless not desirable, and access to previous versions of the work is provided when possible;
80
+ - it recognizes the CC4r as compatible (reciprocity);
81
+ - it requires that changes made to the work will be subject to the same license or to a license which also meets these compatibility criteria.
82
+
83
+ 5. LEGAL FRAMEWORK
84
+ Because of the conditions mentioned under 0., this is not a Free License. It is reluctantly formulated within the framework of both the Belgian law and the Berne Convention for the Protection of Literary and Artistic Works.
85
+ “We recognize that private ownership over media, ideas, and technology is rooted in European conceptions of property and the history of colonialism from which they formed. These systems of privatization and monopolization, namely copyright and patent law, enforce the systems of punishment and reward which benefit a privileged minority at the cost of others’ creative expression, political discourse, and cultural survival. The private and public institutions, legal frameworks, and social values which uphold these systems are inseparable from broader forms of oppression. Indigenous people, people of color, queer people, trans people, and women are particularly exploited for their creative and cultural resources while hardly receiving any of the personal gains or legal protections for their work. We also recognize that the public domain has jointly functioned to compliment the private, as works in the public domain may be appropriated for use in proprietary works. Therefore, we use copyleft not only to circumvent the monopoly granted by copyright, but also to protect against that appropriation.” [Decolonial Media License https://freeculture.org/About/license]
86
+
87
+ 6. YOUR RESPONSIBILITIES
88
+ The invitation to use the work as defined by the CC4r (invitation to copy, distribute, modify) implies to take the implications of the appropriation of the materials into account.
89
+
90
+ 7. DURATION OF THE LICENSE
91
+ This license takes effect as of the moment that the FUTURE AUTHOR accepts the invitation of the CURRENT AUTHOR. The act of copying, distributing, or modifying the work constitutes a tacit agreement. This license will remain in effect for the duration of the copyright which is attached to the work. If you do not respect the terms of this license, the invitation that it confers is void.
92
+ If the legal status or legislation to which you are subject makes it impossible for you to respect the terms of this license, you may not make use of the rights which it confers.
93
+
94
+ 8. VARIOUS VERSIONS OF THE LICENSE
95
+ You are invited to reformulate this license by way of new, renamed versions. [link to license on gitlab]. You can of course make reproductions and distribute this license verbatim (without any changes).
96
+
97
+ USER GUIDE
98
+
99
+ – How to use the CC4r?
100
+ To apply the CC4r, you need to mention the following elements:
101
+ [Name of the legal author, title, date of the work. When applicable, names of authors of the common work and, if possible, where to find other versions of the work].
102
+ Copyleft with a difference: This is a collective work, you are invited to copy, distribute, and modify it under the terms of the CC4r [link to license].
103
+ Short version: Legal author=name, date of work (? ask SD). CC4r [link to license]
104
+
105
+ – Why use the CC4r?
106
+ 1. To remind yourself and others that you do not own authored works
107
+ 2. To not allow copyright to hinder works to evolve, to be extended, to be transformed
108
+ 3. To allow materials to circulate as much as they need to
109
+ 4. Because the CC4r offers a legal framework to disallow mis-appropriation by insisting on inclusive attribution. Nobody can take hold of the work as one’s exclusive possession.
110
+
111
+ – When to use the CC4r?
112
+ Any time you want to invite others to copy, distribute and transform authored works without exclusive appropriation but with considering the implications of (re-)use, you can use the CC4r. You can for example apply it to collective documentation, hybrid productions, artistic collaborations or educational projects.
113
+
114
+ – What kinds of works can be subject to the CC4r?
115
+ The Collective Conditions for re-use can be applied to digital as well as physical works.
116
+ You can choose to apply the CC4r for any text, picture, sound, gesture, or whatever material as long as you have legal author’s rights.
117
+
118
+ – Background of this license:
119
+ The CC4r was developed for the Constant worksession Unbound libraries (spring 2020) and followed from discussions during and contributions to the study day Authors of the future (Fall 2019). It is based on the Free Art License http://artlibre.org/licence/lal/en/ and inspired by other licensing projects such as The (Cooperative) Non-Violent Public License https://thufie.lain.haus/NPL.html and the Decolonial Media license https://freeculture.org/About/license.
120
+
121
+ Copyleft Attitude with a difference, 6 October 2020.