├── style.css ├── README.md ├── layout_company.html ├── layout_project.html ├── credits.html ├── _template └── data.xml ├── data.xml ├── generate.py └── layout_common.html /style.css: -------------------------------------------------------------------------------- 1 | body { 2 | padding: 15px 0; 3 | font-family: "Trebuchet MS", Arial, Helvetica, sans-serif; 4 | font-size: 0.9em; 5 | line-height:1.6em; 6 | } 7 | 8 | img { 9 | width: 100%; 10 | } 11 | 12 | #navigation h1.nav-header { 13 | padding: 0 15px; 14 | margin-bottom: 0; 15 | } 16 | 17 | #navigation a.nav-header { 18 | padding: 5px 15px; 19 | font-weight: bold; 20 | } 21 | 22 | #navigation ul.uk-nav { 23 | padding: 15px 0; 24 | } 25 | 26 | #navigation p { 27 | padding-bottom: 10px; 28 | } 29 | 30 | #navigation li.language-select select { 31 | float: right; 32 | } 33 | 34 | #content h2 { 35 | font-family: Georgia, "Times New Roman", Times, serif; 36 | } 37 | 38 | #content img.header { 39 | margin-bottom: 20px; 40 | } 41 | 42 | #content ul { 43 | list-style-type: square; 44 | } 45 | 46 | #content li.done { 47 | color: #008000; 48 | text-decoration: line-through; 49 | } 50 | 51 | #content div.images div { 52 | padding-bottom: 25px; 53 | } 54 | 55 | #content p.images-text { 56 | margin-top: -15px; 57 | } 58 | 59 | #content .iframe-container { 60 | position: relative; 61 | /* Magic! Makes sure the container is high enough to show the entire iframe 62 | * Thanks to http://andmag.se/2011/11/responsive-embeds/ */ 63 | padding-bottom: 56.5%; 64 | } 65 | 66 | #content iframe { 67 | position: absolute; 68 | top: 0; 69 | left: 0; 70 | width: 100%; 71 | height: 100%; 72 | } 73 | 74 | @media (max-width: 767px) { 75 | h2 { 76 | margin-top: 25px; 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | dopresskit-static 2 | ================= 3 | 4 | dopresskit-static is a static version of the great [Rami Ismail's presskit()](https://github.com/ramiismail/dopresskit). 5 | 6 | If you don't wan't to rely on PHP you can use it with the same xml files & directory structure as the original presskit(). 7 | 8 | You can even **host it on dropbox** : [demo](https://dl.dropboxusercontent.com/u/8211966/presskit-static/index.html) 9 | 10 | # Features 11 | * Not PHP 12 | * More comprehensible source (thanks to python being python & the simple jinja syntax) 13 | * Hostable on dropbox or anywhere with a simple drag & drop 14 | * Compatible with the original presskit() xml files & directory structure 15 | * Each non-filled xml tags will hide the appropriate section in the generated page 16 | 17 | *Note : One thing you will lose from Vlambeer's version is the ability to make presskit requests through the server-side mail system.* 18 | 19 | # Getting started 20 | Go read the original [https://github.com/ramiismail/dopresskit](https://github.com/ramiismail/dopresskit) to see what presskit() is all about. 21 | 22 | ## Python environment 23 | It requires python 2.7 (2.6 probably works as well) and the jinja2 package. 24 | 25 | If you're on OSX/Linux you might already have a proper environment. 26 | 27 | * Download python [https://www.python.org/download/releases/2.7.7/](https://www.python.org/download/releases/2.7.7/) 28 | * Install the template engine **jinja2** with `easy_install jinja2` or `pip install jinja2` or even via the windows binary at [http://www.lfd.uci.edu/~gohlke/pythonlibs/#jinja2](http://www.lfd.uci.edu/~gohlke/pythonlibs/#jinja2) (`Jinja2‑2.7.3.win32‑py2.7.exe`) 29 | 30 | ## Generate your static files 31 | You should be able to compile a project as is with the default `data.xml`. 32 | 33 | * Run `python generate.py`, it will generate an `index.html` file at the root of your folder and in each of the project folders (by default, none). 34 | * Open `index.html` and it's done! 35 | * Edit the various `data.xml` files to your needs and run `python generate.py` again. 36 | 37 | If you want to add a project, copy the `_template` folder and rename it, re generate the html files and a project should show up in the *Projects* section of the page. 38 | 39 | *Note : A project folder will be ignored if its name is starting with an \_uppercase_, if containing any space and if not in lowercase. 'Super Crate Box' would have a folder named `super_crate_box` to be valid.* 40 | 41 | ## Google Analytics 42 | To add google analytics support simply add your *Tracker ID* as an argument like this `python generate.py UA-1234567-89` 43 | -------------------------------------------------------------------------------- /layout_company.html: -------------------------------------------------------------------------------- 1 | {% extends "layout_common.html" %} 2 | 3 | {% block title %}{{ company.title }}{% endblock %} 4 | {% block css_path %}"style.css"{% endblock %} 5 | {% block company_path %}""{% endblock %} 6 | {% block credit_path %}"credits.html"{% endblock %} 7 | {% block histories_history %} 8 | {% if company.histories|length > 0 %} 9 |
  • History
  • 10 | {% endif %} 11 | {% endblock %} 12 | {% block projects_features %} 13 | {% if get_projects()|length > 0 %}
  • Projects
  • {% endif %} 14 | {% endblock %} 15 | {% block images_screenshots %}
  • Images
  • {% endblock %} 16 | 17 | {% block header %} 18 | {% set url = company.website|clean_url %} 19 | {{ url }} 20 | {% endblock %} 21 | 22 | {% block foundingdate_releasedate %} 23 | {% if company.founding_date|length > 0 %} 24 |

    25 | Founding date:
    26 | {{ company.founding_date }} 27 |

    28 | {% endif %} 29 | {% endblock %} 30 | 31 | {% block companysite_gamesite %} 32 | {% if company.website|length > 0 %} 33 |

    34 | Website:
    35 | {% set url = company.website|clean_url %} 36 | {{ url }} 37 |

    38 | {% endif %} 39 | {% endblock %} 40 | 41 | {% block press_regularprice %} 42 | {% if company.press_contact|length > 0 %} 43 |

    44 | Press / Business Contact:
    45 | {{ company.press_contact }} 46 |

    47 | {% endif %} 48 | 49 | {% if company.socials|length > 0 %} 50 |

    51 | Social:
    52 | {% for social in company.socials.social %} 53 | {{ social.name }}
    54 | {% endfor %} 55 |

    56 | {% endif %} 57 | 58 | {% if get_projects()|length > 0 %} 59 |

    60 | Releases:
    61 | {% for project in get_projects() %} 62 | {{ project|replace("_", " ")|title }}
    63 | {% endfor %} 64 |

    65 | {% endif %} 66 | 67 |

    68 | {% if company.address|length > 0 %} 69 | Address:
    70 | {% for address in company.address.line %} 71 | {{ address }}
    72 | {% endfor %} 73 | {% endif %} 74 |

    75 | 76 | {% if company.phone|length > 0 %} 77 |

    78 | Phone:
    79 | {{ company.phone }} 80 |

    81 | {% endif %} 82 | {% endblock %} 83 | 84 | {% block historieprojects_historyfeatures %} 85 | {% if company.histories|length > 0 %} 86 |

    History

    87 | 88 | {% for history in company.histories.history %} 89 | {{ history.header }} 90 |

    {{ history.text }}

    91 | {% endfor %} 92 | {% endif %} 93 | 94 | {% if get_projects()|length > 0 %} 95 |

    Projects

    96 | 104 | {% endblock %} 105 | 106 | {% block credit_name %}Team & Repeating Collaborators{% endblock %} 107 | 108 | -------------------------------------------------------------------------------- /layout_project.html: -------------------------------------------------------------------------------- 1 | {% extends "layout_common.html" %} 2 | 3 | {% block title %}{{ project.title }}{% endblock %} 4 | {% block css_path %}"../style.css"{% endblock %} 5 | {% block company_path %}"../index.html"{% endblock %} 6 | {% block credit_path %}"../credits.html"{% endblock %} 7 | {% block histories_history %} 8 | {% if project.history|length > 0 %} 9 |
  • History
  • 10 | {% endif %} 11 | {% endblock %} 12 | {% block projects_features %} 13 | {% if project.features|length > 0 %}
  • Features
  • {% endif %} 14 | {% endblock %} 15 | {% block images_screenshots %}
  • Images
  • {% endblock %} 16 | {% block _navpreview %} 17 | {% if company.press_can_request_copy == 'TRUE' %}
  • Request Press Copy
  • {% endif %} 18 | {% endblock %} 19 | {% block _navabout %} 20 |
  • About {{ company.title }}
  • 21 | {% endblock %} 22 | 23 | {% block header %} 24 | press kit 25 | {% endblock %} 26 | 27 | {% block foundingdate_releasedate %} 28 | {% if project.release_date|length > 0 %} 29 |

    30 | Release date:
    31 | {{ project.release_date }} 32 |

    33 | {% endif %} 34 | 35 | {% if project.platforms|length > 0 %} 36 |

    37 | Platforms:
    38 | {% for platform in project.platforms.platform %} 39 | {{ platform.name }}
    40 | {% endfor %} 41 |

    42 | {% endif %} 43 | 44 | 45 | {% endblock %} 46 | 47 | {% block companysite_gamesite %} 48 | {% if project.website|length > 0 %} 49 |

    50 | Website:
    51 | {% set url = project.website|clean_url %} 52 | {{ url }} 53 |

    54 | {% endif %} 55 | {% endblock %} 56 | 57 | {% block press_regularprice %} 58 | {% if project.prices|length > 0 %} 59 |

    60 | Regular Price:
    61 | 62 | {% for price in project.prices.price %} 63 | 64 | {% endfor %} 65 |
    {{ price.currency }}{{ price.value }}
    66 |

    67 | {% endif %} 68 | {% endblock %} 69 | 70 | {% block historieprojects_historyfeatures %} 71 | {% if project.history|length > 0 %} 72 |

    History

    73 |

    {{ project.history }}

    74 | {% endif %} 75 | 76 | {% if project.features|length > 0 %} 77 |

    Features

    78 | 85 | {% endif %} 86 | {% endblock %} 87 | 88 | {% block _preview %} 89 | {% if company.press_can_request_copy == 'TRUE' %} 90 |

    Request Press Copy

    91 |

    Please send us an e-mail at {{ company.press_contact }} and we'll get back to you as soon as a press copy is available for you.

    92 |
    93 | {% endif %} 94 | {% endblock %} 95 | 96 | {% block _about %} 97 |

    About {{ company.title }}

    98 |

    Boilerplate
    99 | {{ company.description }} 100 |

    101 | 102 |

    More information
    103 | More information on {{ company.title }}, our logo & relevant media are available here. 104 |

    105 |
    106 | {% endblock %} 107 | 108 | {% block credit_name %}{{ project.title}} Credits{% endblock %} 109 | -------------------------------------------------------------------------------- /credits.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Thanks! 8 | 9 | 10 | 11 | 12 | 13 |
    14 |
    15 | 19 |
    20 |

    Short introduction by Vlambeer's Rami Ismail

    21 |

    Even though I'm still not quite sure what to call presskit() - be it a kit or a system or a framework or just a way for me to spend more time making games and less time doing repetitive chores, I ended up making this because I felt it would make a lot of lives a lot easier.

    22 |

    A good game is worth nothing if no-one plays it & to play a game one needs to know of it. The way I see it, developers & press both have the same goal: to bring great games to as many people as possible. For the press, finding out about a game but not having access to information & media for the game means that they still can't really write something about it. Developers want to spend their valuable time making games instead of press pages, resulting in that so many games that could've touched so many hearts didn't end up doing so.

    23 |

    I figured that something that is free for everyone, open and easy-to-use for both sides is the ultimate solution. Developers only have to spend an hour or so creating well-laid out press pages with everything the press needs to write to their hearts desire. Everyone wins.

    24 |

    But presskit() was only possible thanks to these fine folks!

    25 |
      26 |
    • Andreas Zecher - Made by Pixelate - for the original inspiration that made me create this kit.
    • 27 |
    • Jan Willem Nijman - Vlambeer - for starting Vlambeer with me, which eventually led to this thing.
    • 28 |
    • Russ Frushtick - Polygon - for general feedback from a press-person point-of-view.
    • 29 |
    • Martin Jonasson - grapefrukt - for challenging me to a race to see who could write the most efficient install script.
    • 30 |
    • Joram Wolters - JoramWolters.com - for his always sharp critique on game & web design and functionality.
    • 31 |
    • Jan Pieter van Seventer - Dutch Game Garden - for support & feedback.
    • 32 |
    • Philip Tibitoski - octodadgame.com - for inspiring me to make this publically available.
    • 33 |
    • Adriaan de Jongh - gameovenstudios.com - for distractions and meaningful Skype-conversations during presskit()s development.
    • 34 |
    • Remco Meeuwissen - dearon.com - for contributions to presskit() on Github.
    • 35 |
      36 |
    • The indie community at large for being amazing, open-minded, supportive, creative and interesting people.
    • 37 |
    • Friends, family & girlfriend for allowing & supporting me to do what I love to do, to pursue my dreams and to make games.
    • 38 |
    39 |
    40 |
    41 |
    42 | 43 | 44 | -------------------------------------------------------------------------------- /_template/data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Game Name 5 | 1 May, 2012 6 | http://www.gamesite.com/ 7 | TRUE 8 | 9 | 10 | 11 | PC / Mac 12 | http://www.gamesite.com/ 13 | 14 | 15 | Steam 16 | http://www.steampowered.com/ 17 | 18 | 19 | Apple App Store 20 | http://www.itunes.com/ 21 | 22 | 23 | 24 | 25 | 26 | USD 27 | $1.99 28 | 29 | 30 | EUR 31 | €1.59 32 | 33 | 34 | CAD 35 | $1.99 36 | 37 | 38 | GBP 39 | £1.29 40 | 41 | 42 | 43 | 44 | Hello. This is a short compilation of facts about the game. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 45 | 46 | 47 | 48 | Since we're an indie developer, we want a history to our game. This paragraph will explain this history in short. Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. 49 | 50 | 51 | 52 | Includes something really interesting about the game which players will love. 53 | This feature line is about the 8-bit pixels that are no doubt featuring in this game. 54 | Since it is unlikely that the audio isn't fucking amazing, say something about the audio, maybe? 55 | Make sure to stress that everything about this game is absolutely fabulous. 56 | Something to wrap up this 5-point feature list with a nice ring to it. 57 | 58 | 59 | 60 | 61 | Trailer 62 | 7jQbITg0MSk 63 | 23571681 64 | 65 | 66 | Gameplay Video 67 | 7jQbITg0MSk 68 | 23571681 69 | 70 | 71 | 72 | 73 | 74 | Winner in this highly relevant contest. 75 | Award Location, 20 October, 1989 76 | 77 | 78 | Nomination for this prestigious award. 79 | Award Ceremony, 4 December, 1991 80 | 81 | 82 | Winner in this highly relevant contest. 83 | Award Location, 20 October, 1989 84 | 85 | 86 | Nomination for this prestigious award. 87 | Award Ceremony, 4 December, 1991 88 | 89 | 90 | 91 | 92 | 93 | This is a rather insignificant quote by a highly important person. 94 | Person Name 95 | Website 96 | http:// 97 | 98 | 99 | An extremely positive quote from a rather insignificant person. Also great. 100 | Some Guy 101 | This Page Is Visited By 12 Visitors A Month 102 | http:// 103 | 104 | 105 | I pretend to love this game even though I do not actually understand it. 106 | Pretentious Bastard 107 | Artsy Page 108 | http:// 109 | 110 | 111 | HOLY SHIT SO AMAZING 112 | Caps Guy 113 | Angry Review 114 | http:// 115 | 116 | 117 | 118 | 119 | 120 | Original Soundtrack 121 | Available for free from 122 | http://somemusicsite.com/thislink 123 | 124 | 125 | Release Blog Post 126 | The blog-post through which this game was released is available at 127 | http://vlambeer.com/bloglink 128 | 129 | 130 | 131 | 132 | 133 | Rami Ismail 134 | Business & Development, Vlambeer 135 | 136 | 137 | Jan Willem Nijman 138 | Game Designer, Vlambeer 139 | 140 | 141 | John Doe 142 | Artist, Freelancer 143 | 144 | 145 | Oliver Twist 146 | www.olivertwist.com 147 | Artist, Freelancer 148 | 149 | 150 | Jane Doette 151 | www.olivertwist.com 152 | Music, Freelancer 153 | 154 | 155 | -------------------------------------------------------------------------------- /data.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Company Name 6 | September 1, 2010 7 | http://www.website.com 8 | Cityville, Metropolisland 9 | 10 | press-contact@company.com 11 | +00 (1) 22 33 44 55 66 12 |
    13 | Address Line 1 14 | Address Line 2 15 | Address Line 3 16 |
    17 | 18 | 19 | 20 | twitter.com/MyCompanyName 21 | twitter.com/MyCompanyName 22 | 23 | 24 | facebook.com/MyCompanyName 25 | facebook.com/MyCompanyName 26 | 27 | 28 | Skype 29 | callto:MySkypeName 30 | 31 | 32 | 33 | 34 | We're games studio and we make games. We're also capable of editing XML files. 35 | 36 | 37 | 38 | 39 |
    Early history
    40 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nam vel nisi dolor. Pellentesque vitae eros velit, quis venenatis orci. Phasellus elit urna, semper ut gravida et, porta non dui. Aliquam erat volutpat. Aenean porta volutpat imperdiet. Maecenas venenatis, tellus eget vehicula vulputate, augue erat elementum quam, tincidunt laoreet magna orci et mauris. Proin porttitor pharetra nisi, accumsan sollicitudin neque varius a. Aenean ut massa ipsum, id hendrerit lacus. Maecenas posuere egestas nunc at cursus. Etiam mollis libero vel eros pulvinar aliquam. Sed vitae turpis sed nibh venenatis dictum. Sed suscipit orci justo, at sagittis ante. Sed leo nisl, ultricies in fermentum id, aliquam id dolor. Ut laoreet, felis id posuere bibendum, arcu ipsum lacinia est, eu lobortis velit enim eget mi. In ullamcorper ullamcorper enim ut gravida. Vivamus rutrum lacus mollis risus malesuada iaculis. 41 |
    42 | 43 |
    After that
    44 | Lorem ipsum dolor sit amet, consectetur adipiscing elit. Cras sem dui, volutpat eu adipiscing sed, rutrum aliquam lacus. Proin sollicitudin consequat dolor id dignissim. Aliquam sem turpis, sagittis lobortis viverra eget, varius vitae nunc. Proin ac lacus porttitor dui sollicitudin elementum. Nulla ut hendrerit est. Fusce vitae arcu erat, vel molestie est. Proin et placerat justo. Proin placerat arcu massa, eu blandit leo. Cum sociis natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Nam eu lorem sed massa lobortis hendrerit vitae vel odio. Maecenas eget pulvinar tortor. Nunc vitae nisl ac odio bibendum luctus ac a leo. Suspendisse auctor elit et velit sagittis vehicula. Maecenas faucibus blandit rutrum. Duis et sem nibh. Vestibulum placerat elit et dui rhoncus accumsan. 45 |
    46 |
    47 | 48 | 49 | 50 | This video is nice 51 | 7jQbITg0MSk 52 | 53 | 54 | This one too 55 | 0CevOaYrYDA 56 | 12536488 57 | 58 | 59 | 60 | 61 | 62 | Winner in this highly relevant contest. 63 | Award Location, 20 October, 1989 64 | 65 | 66 | Nomination for this prestigious award. 67 | Award Ceremony, 4 December, 1991 68 | 69 | 70 | Winner in this highly relevant contest. 71 | Award Location, 20 October, 1989 72 | 73 | 74 | Nomination for this prestigious award. 75 | Award Ceremony, 4 December, 1991 76 | 77 | 78 | 79 | 80 | 81 | This is a rather insignificant quote by a highly important person. 82 | Person Name 83 | Website 84 | http://www.website.com/ 85 | 86 | 87 | An extremely positive quote from a rather insignificant person. Also great. 88 | Some Guy 89 | This Page Is Visited By 12 Visitors A Month 90 | http://geocities.blog.com/ 91 | 92 | 93 | I pretend to love this game even though I do not actually understand it. 94 | Pretentious Bastard 95 | Artsy Page 96 | http://art.tumblr.com/ 97 | 98 | 99 | HOLY SHIT SO AMAZING 100 | Caps Guy 101 | Angry Review 102 | http://thispage.net/angrytube 103 | 104 | 105 | 106 | TRUE 107 | monetize 111 | 112 | 113 | Company Link #1 114 | This link is a link that might be useful. You can check it out at 115 | http://somemusicsite.com/thislink 116 | 117 | 118 | 119 | 120 | 121 | John Doe 122 | Artist, Freelancer 123 | 124 | 125 | Oliver Twist 126 | www.olivertwist.com 127 | Artist, Freelancer 128 | 129 | 130 | Jane Doette 131 | www.olivertwist.com 132 | Music, Freelancer 133 | 134 | 135 | 136 | 137 | 138 | Inquiries 139 | rami@vlambeer.com 140 | 141 | 142 | Twitter 143 | http://twitter.com/MyCompanyName 144 | 145 | 146 | Facebook 147 | http://facebook.com/MyCompanyName 148 | 149 | 150 | Web 151 | MyCompanyWebsite.com 152 | 153 | 154 |
    -------------------------------------------------------------------------------- /generate.py: -------------------------------------------------------------------------------- 1 | import re 2 | import os.path 3 | import sys 4 | import urlparse 5 | import xml.sax.handler 6 | 7 | from jinja2 import Template, Environment, FileSystemLoader 8 | 9 | 10 | # CONVERTS XML TO PYTHON OBJECT REPRESENTATION 11 | # from http://code.activestate.com/recipes/534109-xml-to-python-data-structure/ 12 | def xml2obj(src): 13 | """ 14 | A simple function to converts XML data into native Python object. 15 | """ 16 | 17 | non_id_char = re.compile('[^_0-9a-zA-Z]') 18 | 19 | def _name_mangle(name): 20 | return non_id_char.sub('_', name) 21 | 22 | class DataNode(object): 23 | 24 | def __init__(self): 25 | self._attrs = {} # XML attributes and child elements 26 | self.data = None # child text data 27 | 28 | def __len__(self): 29 | # treat single element as a list of 1 30 | return 1 31 | 32 | def __getitem__(self, key): 33 | if isinstance(key, basestring): 34 | return self._attrs.get(key, None) 35 | else: 36 | return [self][key] 37 | 38 | def __contains__(self, name): 39 | return self._attrs.has_key(name) 40 | 41 | def __nonzero__(self): 42 | return bool(self._attrs or self.data) 43 | 44 | def __getattr__(self, name): 45 | if name.startswith('__'): 46 | # need to do this for Python special methods??? 47 | raise AttributeError(name) 48 | return self._attrs.get(name, None) 49 | 50 | def _add_xml_attr(self, name, value): 51 | if name in self._attrs: 52 | # multiple attribute of the same name are represented by a list 53 | children = self._attrs[name] 54 | if not isinstance(children, list): 55 | children = [children] 56 | self._attrs[name] = children 57 | children.append(value) 58 | else: 59 | self._attrs[name] = value 60 | 61 | def __str__(self): 62 | return self.data or '' 63 | 64 | def __repr__(self): 65 | items = sorted(self._attrs.items()) 66 | if self.data: 67 | items.append(('data', self.data)) 68 | return u'{%s}' % ', '.join([u'%s:%s' % (k, repr(v)) for k, v in items]) 69 | 70 | class TreeBuilder(xml.sax.handler.ContentHandler): 71 | 72 | def __init__(self): 73 | self.stack = [] 74 | self.root = DataNode() 75 | self.current = self.root 76 | self.text_parts = [] 77 | 78 | def startElement(self, name, attrs): 79 | self.stack.append((self.current, self.text_parts)) 80 | self.current = DataNode() 81 | self.text_parts = [] 82 | # xml attributes --> python attributes 83 | for k, v in attrs.items(): 84 | self.current._add_xml_attr("caca" + _name_mangle(k), v) 85 | 86 | def endElement(self, name): 87 | text = ''.join(self.text_parts).strip() 88 | if text: 89 | self.current.data = text 90 | if self.current._attrs: 91 | obj = self.current 92 | else: 93 | # a text only node is simply represented by the string 94 | obj = text or '' 95 | self.current, self.text_parts = self.stack.pop() 96 | self.current._add_xml_attr(_name_mangle(name), obj) 97 | 98 | def characters(self, content): 99 | self.text_parts.append(content) 100 | 101 | builder = TreeBuilder() 102 | if isinstance(src, basestring): 103 | xml.sax.parseString(src, builder) 104 | else: 105 | xml.sax.parse(src, builder) 106 | return builder.root._attrs.values()[0] 107 | 108 | 109 | # FUNCTIONS THAT JUST TALK 110 | def blabla_ga(): 111 | if ga is None: 112 | print ">>> Google analytics ID : Not found, skipping..." 113 | print " Use 'python generate.py " + \ 114 | "to activate google analytics" 115 | else: 116 | print "Google analytics : Enabled (ID: %s)" % (ga) 117 | 118 | 119 | def blabla_projects(): 120 | projects = get_projects() 121 | if len(projects) == 0: 122 | print ">>> No project found, skipping..." 123 | print " Duplicate the '_template' folder, rename it " + \ 124 | "and edit data.xml" 125 | print " The project folder name must be lowercase " + \ 126 | "and spaces by _underscores_." 127 | 128 | 129 | ############################################################### 130 | # ACTUAL PRESSKIT STUFF 131 | now_project = "." 132 | ga = sys.argv[1] if len(sys.argv) == 2 else None 133 | blabla_ga() 134 | 135 | 136 | # HELPERS 137 | def get_images(extensions, rejects=None): 138 | rejects = rejects or [] 139 | files, images_path = [], os.path.join(now_project, "images") 140 | try: 141 | os.mkdir(images_path) 142 | except OSError: # Images folder already exists 143 | pass 144 | for f in os.listdir(images_path): 145 | _, ext = os.path.splitext(f) 146 | ext = ext[1:] 147 | if ext in extensions and f not in rejects: 148 | files.append(f) 149 | 150 | return files 151 | 152 | 153 | def get_projects(): 154 | projects = [] 155 | for folder_name in os.listdir('.'): 156 | # FILTER OUT 157 | if os.path.isfile(folder_name): 158 | continue 159 | if ' ' in folder_name: 160 | continue 161 | if folder_name[0] == '_': 162 | continue 163 | if len([l for l in folder_name if l.isupper()]) > 0: 164 | continue 165 | 166 | # SEARCH FOR data.xml 167 | for f in os.listdir(folder_name): 168 | if f == "data.xml": 169 | projects.append(folder_name) 170 | return projects 171 | 172 | 173 | def file_exists(filepath): 174 | return os.path.isfile(os.path.join(now_project, filepath)) 175 | 176 | 177 | def filesize(filepath): 178 | return os.path.getsize(os.path.join(now_project, filepath)) 179 | 180 | 181 | def parse_url(url): 182 | if url[:7] != "http://" and url[:8] != "https://": 183 | url = "http://" + url 184 | return url 185 | 186 | def clean_url(url): 187 | if url.startswith("http://"): 188 | url = url[7:] 189 | if url.startswith("https://"): 190 | url = url[8:] 191 | if url.startswith("www."): 192 | url = url[4:] 193 | return url.rstrip('/') 194 | 195 | def get_site(url): 196 | parsed_url = urlparse.urlparse(url) 197 | if parsed_url.netloc == '' and parsed_url.scheme == '': 198 | parsed_url = urlparse.urlparse("//" + url) 199 | site = parsed_url.netloc 200 | if site.startswith("www."): 201 | site = site[4:] 202 | return site 203 | 204 | env = Environment(loader=FileSystemLoader("")) 205 | env.filters['clean_url'] = clean_url 206 | env.filters['get_site'] = get_site 207 | 208 | 209 | def do_compile(project_name, company_datas=None): 210 | global now_project 211 | now_project = project_name 212 | 213 | # CLEAN XML FROM DASHES 214 | def undash(match): 215 | return match.group().replace("-", "_") 216 | 217 | xml_datas = open(os.path.join(project_name, 'data.xml'), 'r') 218 | regex = re.compile('\<[^?!].*?\>') 219 | xml_datas = regex.sub(undash, xml_datas.read()) 220 | 221 | # PARSE 222 | xml_obj = xml2obj(xml_datas) 223 | 224 | # DETECT LAYOUT NAME 225 | if project_name == ".": 226 | layout_name = "layout_company.html" 227 | else: 228 | layout_name = "layout_project.html" 229 | 230 | if project_name == ".": 231 | company_datas = xml_obj 232 | 233 | # WRITE ON DISK 234 | t = env.get_template(layout_name) 235 | output = t.render( 236 | company=company_datas, project=xml_obj, common=xml_obj, 237 | file_exists=file_exists, filesize=filesize, 238 | get_images=get_images, get_projects=get_projects, google_analytics=ga, 239 | parse_url=parse_url) 240 | 241 | path = os.path.join(project_name, "index.html") 242 | with open(path, "wb") as fh: 243 | fh.write(output.encode('utf-8')) 244 | 245 | print ">>> generated : " + path 246 | return xml_obj 247 | 248 | 249 | # COMPILE COMPANY PAGE 250 | company_datas = do_compile(".") 251 | # COMPILE ALL PROJECT PAGES 252 | for project in get_projects(): 253 | do_compile(project, company_datas) 254 | blabla_projects() 255 | -------------------------------------------------------------------------------- /layout_common.html: -------------------------------------------------------------------------------- 1 | {% if file_exists("images/logo.zip") %} {% set logo_zip = true %} {% endif %} 2 | {% if file_exists("images/logo.png") %} {% set logo_png = true %} {% endif %} 3 | {% if file_exists("images/icon.png") %} {% set icon_png = true %} {% endif %} 4 | {% if logo_zip or logo_png or icon_png %} {% set logo = true %} {% endif %} 5 | {% set images = get_images(['png', 'jpg', 'gif'], ['logo.png', 'icon.png', 'header.png']) %} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{ common.title }} 14 | 15 | 16 | 17 | 18 | 19 |
    20 |
    21 | 43 |
    44 | 45 | {% if file_exists("images/header.png") %} 46 | 47 | {% endif %} 48 | 49 |
    50 |
    51 |

    Factsheet

    52 |

    53 | Developer:
    54 | {{ company.title }}
    55 | {% if company.based_in|length > 0 %} 56 | Based in {{ company.based_in }} 57 | {% endif %} 58 |

    59 | 60 | {% block foundingdate_releasedate %}{% endblock %} 61 | 62 | {% block companysite_gamesite %}{% endblock %} 63 | 64 | {% block press_regularprice %}{% endblock %} 65 | 66 |
    67 | 68 |
    69 | {% if common.description|length > 0 %} 70 |

    Description

    71 |

    {{ common.description }}

    72 | {% endif %} 73 | 74 | {% block historieprojects_historyfeatures %}{% endblock %} 75 |
    76 |
    77 | 78 |
    79 | 80 | {% if common.trailers|length > 0 %} 81 |

    Videos

    82 | {% for trailer in common.trailers.trailer %} 83 |

    {{ trailer.name }}  84 | 85 | {% if "youtube" in trailer %} 86 | YouTube 87 |

    88 | 89 |
    90 | {% endif %} 91 | 92 | {% if "vimeo" in trailer %} 93 | Vimeo 94 |
    95 | 96 |
    97 | {% endif %} 98 | 99 | {% if "mov" in trailer %} 100 | .mov 101 | {% endif %} 102 | 103 | {% if "mp4" in trailer %} 104 | .mp4 105 | {% endif %} 106 | 107 |

    108 | 109 | {% endfor %} 110 |
    111 | {% endif %} 112 | 113 | {% if file_exists("images/images.zip") or images|length > 0 %} 114 |

    Images

    115 | 116 | {% if file_exists("images/images.zip") %} 117 | {% set fsize = filesize("images/images.zip") %} 118 |
    download all screenshots & photos as .zip ({{ fsize|filesizeformat }})
    119 | {% endif %} 120 | 121 | 122 | {% if images|length > 0 %} 123 |
    124 | {% for image in images %} 125 |
    {{ image }}
    126 | {% endfor %} 127 |
    128 | {% endif %} 129 | 130 |
    131 |

    There are far more images available for {{ common.title }}, but these are the ones we felt would be most useful to you. If you have specific requests, please do contact us!

    132 | 133 |
    134 | {% endif %} 135 | 136 | {% if logo %} 137 | 138 | 139 | {% if logo_zip %} 140 | {% set fsize = filesize("images/logo.zip") %} 141 |
    download logo files as .zip ({{ fsize|filesizeformat }})
    142 | {% endif %} 143 | 144 |
    145 | 146 | {% if logo_png %} 147 |
    logo
    148 | {% endif %} 149 | 150 | {% if icon_png %} 151 |
    logo
    152 | {% endif %} 153 | 154 |
    155 |
    156 | {% endif %} 157 | 158 | 159 | {% if common.awards|length > 0 %} 160 |

    Awards & Recognition

    161 |
      162 | {% for award in common.awards.award %} 163 |
    • "{{ award.description }}" - {{ award.info }}
    • 164 | {% endfor %} 165 |
    166 |
    167 | {% endif %} 168 | 169 | {% if common.quotes|length > 0 %} 170 |

    Selected Articles

    171 |
      172 | {% for quote in common.quotes.quote %} 173 |
    • "{{ quote.description }}"
      - {{ quote.name }}, {{ quote.website }}
    • 174 | {% endfor %} 175 | 176 |
    177 |
    178 | {% endif %} 179 | 180 | {% block _preview %}{% endblock %} 181 | 182 | 183 | {% if common.additionals|length > 0 %} 184 | 185 | {% for additional in common.additionals.additional %} 186 |

    187 | {{ additional.title }}
    188 | {{ additional.description }} {{ additional.link|get_site }}. 189 |

    190 | {% endfor %} 191 | 192 |
    193 | {% endif %} 194 | 195 | {% block _about %}{% endblock %} 196 | 197 | {% if common.credits|length > 0 or company.contacts|length > 0 %} 198 |
    199 | {% if common.credits|length > 0 %} 200 |
    201 |

    {% block credit_name %}{% endblock %}

    202 | 203 | {% for credit in common.credits.credit %} 204 |

    205 | {{ credit.person }}
    206 | {% if "website" in credit and credit.website|length != 0 %} 207 | {{ credit.role }} 208 | {% else %} 209 | {{ credit.role }} 210 | {% endif %} 211 |

    212 | {% endfor %} 213 | 214 |
    215 | {% endif %} 216 | 217 | {% if company.contacts|length > 0 %} 218 |
    219 |

    Contact

    220 | 221 | {% for contact in company.contacts.contact %} 222 |

    223 | 224 | {% if not "link" in contact and contact.mail|length > 0 %} 225 | {{ contact.name }}
    {{ contact.mail }} 226 | {% endif %} 227 | 228 | {% if not "mail" in contact and contact.link|length > 0 %} 229 | {{ contact.name }}
    {{ contact.link|clean_url }} 230 | {% endif %} 231 |

    232 | {% endfor %} 233 | 234 |
    235 | {% endif %} 236 |
    237 |
    238 | {% endif %} 239 | 240 | 241 |

    presskit() by Rami Ismail (Vlambeer) - also thanks to these fine folks

    242 |
    243 |
    244 |
    245 | 246 | 247 | 248 | 249 | 250 | 261 | 262 | {% if google_analytics != none %} 263 | 272 | {% endif %} 273 | 274 | 275 | --------------------------------------------------------------------------------