commit b7dc2b2ce3c3e8206e28e38298e3c1fd3ecc6902 Author: j Date: Mon Jun 23 12:09:28 2014 +0200 turkishcine.ma config diff --git a/config.jsonc b/config.jsonc new file mode 100644 index 0000000..0ba9871 --- /dev/null +++ b/config.jsonc @@ -0,0 +1,913 @@ +/* + turkishcine.ma Settings + + You can edit this file. +*/ + +{ + "annotations": { + "showUsers": true + }, + "cantPlay": { + "icon": "NoCopyright", + "link": "/rights", + "text": "This movie is still under copyright." + }, + /* + Capabilities are per user level. + They can either be general: + {level: true} means a user of that level has the capability) + or related to items: + {level: x} means a user of that level has the capability + for items of a rights level up to and including x + */ + "capabilities": { + "canAddItems": {"researcher": true, "staff": true, "admin": true}, + "canDownloadVideo": {"guest": -1, "member": -1, "researcher": 3, "staff": 3, "admin": 3}, + "canEditAnnotations": {"staff": true, "admin": true}, + "canEditDocuments": {"researcher": true, "staff": true, "admin": true}, + "canEditEvents": {"researcher": true, "staff": true, "admin": true}, + "canEditFeaturedEdits": {"researcher": true, "staff": true, "admin": true}, + "canEditFeaturedLists": {"researcher": true, "staff": true, "admin": true}, + "canEditFeaturedTexts": {"researcher": true, "staff": true, "admin": true}, + "canEditMedia": {"researcher": true, "staff": true, "admin": true}, + "canEditMetadata": {"researcher": true, "staff": true, "admin": true}, + "canEditPlaces": {"researcher": true, "staff": true, "admin": true}, + "canEditRightsLevel": {"researcher": true, "staff": true, "admin": true}, + "canEditSitePages": {"staff": true, "admin": true}, + "canEditUsers": {"staff": true, "admin": true}, + "canImportAnnotations": {"researcher": true, "staff": true, "admin": true}, + "canManageDocuments": {"member": true, "researcher": true, "staff": true, "admin": true}, + "canManagePlacesAndEvents": {"member": true, "researcher": true, "staff": true, "admin": true}, + "canManageTitlesAndNames": {"member": true, "researcher": true, "staff": true, "admin": true}, + "canManageUsers": {"staff": true, "admin": true}, + "canPlayClips": {"guest": 3, "member": 3, "researcher": 3, "staff": 3, "admin": 3}, + "canPlayVideo": {"guest": 1, "member": 1, "researcher": 3, "staff": 3, "admin": 3}, + "canReadText": {"guest": 0, "member": 0, "researcher": 1, "staff": 1, "admin": 1}, + "canRemoveItems": {"staff": true, "admin": true}, + "canSeeAccessed": {"researcher": true, "staff": true, "admin": true}, + "canSeeDebugMenu": {"researcher": true, "staff": true, "admin": true}, + "canSeeExtraItemViews": {"researcher": true, "staff": true, "admin": true}, + "canSeeMedia": {"researcher": true, "staff": true, "admin": true}, + "canSeeItem": {"guest": 3, "member": 3, "researcher": 3, "staff": 3, "admin": 3}, + "canSeeSize": {"researcher": true, "staff": true, "admin": true}, + "canSeeSoftwareVersion": {"researcher": true, "staff": true, "admin": true}, + "canSendMail": {"staff": true, "admin": true} + }, + /* + clipKeys are the properties that clips can be sorted by. + If sortOperator is not specified, it will be + for strings and - for numbers. + */ + "clipKeys": [ + {"id": "text", "title": "Text", "type": "string"}, + {"id": "position", "title": "Position", "type": "float", "sortOperator": "+"}, + {"id": "duration", "title": "Duration", "type": "float"}, + {"id": "hue", "title": "Hue", "type": "float", "sortOperator": "+"}, + {"id": "saturation", "title": "Saturation", "type": "float"}, + {"id": "lightness", "title": "Lightness", "type": "float"}, + {"id": "volume", "title": "Volume", "type": "float"} + ], + /* + clipLayers is the ordered list of public layers that will appear as the + text of clips. Excluding a layer from this list means it will not be + included in find annotations. + */ + "clipLayers": ["subtitles", "keywords", "notes"], + "flags": false, + "help": [ + {"id": "help", "title": "Help"}, + {"id": "accounts", "title": "Accounts"}, + {"id": "navigation", "title": "Navigation"}, + {"id": "views", "title": "Views"}, + {"id": "timelines", "title": "Timelines"}, + {"id": "clips", "title": "Clips"}, + {"id": "maps", "title": "Maps"}, + {"id": "calendars", "title": "Calendars"}, + {"id": "find", "title": "Find"}, + {"id": "filters", "title": "Filters"}, + {"id": "lists", "title": "Lists"}, + {"id": "player", "title": "Player"}, + {"id": "editor", "title": "Editor"}, + {"id": "documents", "title": "Documents"}, + {"id": "edits", "title": "Edits"}, + {"id": "texts", "title": "Texts"}, + {"id": "embeds", "title": "Embeds"} + ], + /* + An itemKey must have the following properties: + id: The id of the key (as known by the server) + title: The title of the key (as displayed by the client) + type: text, string, float, integer, or array of any of these + and can have any of the following properties: + autocomplete: If true, find element will autocomplete + autocompleteSort: Sort order of autocomplete suggestions + capability: A capability required to see this key + columnRequired: If true, the column can't be removed + columnWidth: Default column width in px + filter: If true, one can filter results by this key + find: If true, this key will appear as a find option + format: {type: "...", args: [...]}, for special formatting + (Ox.formatType(args) will be called) + secondaryId: If true, loading /value will redirect to the item + sort: If true, one can sort results by this key + sortOperator: sort operator (+, -), in case it differs from the + default for the key's type (+ for strings, - for numbers) + sortType: special sort type (title, person) + value: {key: "...", type: "..."}, for keys that are derived + from other keys (like number of actors), or "capability" + */ + "itemKeys": [ + { + "id": "*", + "title": "All", + "type": "text", + "find": true + }, + { + "id": "title", + "title": "Title", + "type": "string", + "additionalSort": [{"key": "year", "operator": "+"}, {"key": "director", "operator": "+"}], + "autocomplete": true, + "autocompleteSort": [{"key": "year", "operator": "+"}], + "columnRequired": true, + "columnWidth": 180, + "find": true, + "sort": true, + "sortType": "title" + }, + { + "id": "director", + "title": "Director", + "type": ["string"], + "additionalSort": [{"key": "year", "operator": "+"}, {"key": "title", "operator": "-"}], + "autocomplete": true, + "columnRequired": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "country", + "title": "Country", + "type": ["string"], + "autocomplete": true, + "columnWidth": 120, + "find": true, + "sort": true + }, + { + "id": "year", + "title": "Year", + "type": "year", + "additionalSort": [{"key": "director", "operator": "+"}, {"key": "title", "operator": "+"}], + "autocomplete": true, + "columnWidth": 60, + "filter": true, + "find": true, + "sort": true, + "sortOperator": "+" + }, + { + "id": "language", + "title": "Language", + "type": ["string"], + "autocomplete": true, + "columnWidth": 120, + "filter": true, + "find": true, + "sort": true + }, + { + "id": "runtime", + "title": "Runtime", + "type": "time", + "columnWidth": 60, + "format": {"type": "duration", "args": [0, "short"]}, + "sort": true + }, + { + "id": "color", + "title": "Color", + "type": ["string"], + "columnWidth": 120, + "filter": true, + "find": true, + "sort": true + }, + { + "id": "sound", + "title": "Sound", + "type": ["string"], + "columnWidth": 120, + "filter": true, + "find": true, + "sort": true + }, + { + "id": "productionCompany", + "title": "Studio", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "description": true, + "filter": true, + "find": true, + "sort": true + }, + { + "id": "producer", + "title": "Producer", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "codirector", + "title": "Co-Director", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "writer", + "title": "Writer", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "cinematographer", + "title": "Cinematographer", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "editor", + "title": "Editor", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "composer", + "title": "Composer", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "lyricist", + "title": "Lyricist", + "type": ["string"], + "autocomplete": true, + "columnWidth": 180, + "filter": true, + "find": true, + "sort": true, + "sortType": "person" + }, + { + "id": "actor", + "title": "Cast", + "type": ["string"], + "autocomplete": true, + "filter": true, + "find": true, + "sortType": "person" + }, + { + "id": "numberofactors", + "title": "Number of Actors", + "type": "integer", + "columnWidth": 60, + "sort": true, + "value": {"key": "actor", "type": "length"} + }, + { + "id": "name", + "title": "Name", + "type": ["string"], + "autocomplete": true, + "description": true, + "find": true + }, + { + "id": "genre", + "title": "Genre", + "type": ["string"], + "autocomplete": true, + "columnWidth": 120, + "filter": true, + "find": true, + "sort": true + }, + { + "id": "keyword", + "title": "Keyword", + "type": ["string"], + "autocomplete": true, + "filter": true, + "find": true + }, + { + "id": "summary", + "title": "Summary", + "type": "text", + "find": true + }, + { + "id": "id", + "title": "ID", + "type": "string", + "columnWidth": 90, + "sort": true + }, + { + "id": "encyclopedia", + "title": "Encyclopedia", + "type": "string", + "capability": "canEditMetadata" + }, + { + "id": "wiki", + "title": "Wiki", + "type": "string", + "capability": "canEditMetadata" + }, + { + "id": "imdbId", + "title": "IMDb ID", + "type": "string", + "columnWidth": 90, + "secondaryId": true, + "sort": true + }, + { + "id": "comments", + "title": "Comments", + "type": "text", + "capability": "canEditMetadata" + }, + { + "id": "annotations", + "title": "Annotations", + "type": "string", // fixme: not the best type for this magic key + "find": true + }, + { + "id": "keywords", + "title": "Keywords", + "type": "layer", + "find": true + }, + { + "id": "notes", + "title": "Notes", + "type": "layer", + "find": true + }, + { + "id": "subtitles", + "title": "Subtitles", + "type": "layer", + "find": true + }, + { + "id": "duration", + "title": "Duration", + "type": "time", + "columnWidth": 90, + "format": {"type": "duration", "args": []}, + "sort": true + }, + { + "id": "resolution", + "title": "Resolution", + "type": ["integer"], + "capability": "canSeeMedia", + "columnWidth": 90, + "format": {"type": "resolution", "args": ["px"]}, + "sort": true + }, + { + "id": "aspectratio", + "title": "Aspect Ratio", + "type": "float", + "columnWidth": 90, + "format": {"type": "unit", "args": [":1", 3]}, + "sort": true + }, + { + "id": "pixels", + "title": "Pixels", + "type": "integer", + "capability": "canSeeMedia", + "columnWidth": 90, + "format": {"type": "value", "args": ["px"]}, + "sort": true + }, + { + "id": "hue", + "title": "Hue", + "type": "float", + "columnWidth": 90, + "format": {"type": "color", "args": ["hue"]}, + "sort": true, + "sortOperator": "+" + }, + { + "id": "saturation", + "title": "Saturation", + "type": "float", + "columnWidth": 90, + "format": {"type": "color", "args": ["saturation"]}, + "sort": true + }, + { + "id": "lightness", + "title": "Lightness", + "type": "float", + "columnWidth": 90, + "format": {"type": "color", "args": ["lightness"]}, + "sort": true + }, + { + "id": "volume", + "title": "Volume", + "type": "float", + "columnWidth": 60, + "format": {"type": "color", "args": ["lightness"]}, + "sort": true + }, + { + "id": "numberofcuts", + "title": "Number of Cuts", + "type": "integer", + "columnWidth": 60, + "format": {"type": "number", "args": []}, + "sort": true, + "value": {"key": "cuts", "type": "length"} + }, + { + "id": "cutsperminute", + "title": "Cuts per Minute", + "type": "float", + "columnWidth": 60, + "format": {"type": "number", "args": [3]}, + "sort": true, + "value": {"key": "cuts", "type": "lengthperminute"} + }, + { + "id": "words", + "title": "Number of Words", + "type": "integer", + "columnWidth": 60, + "format": {"type": "number", "args": []}, + "sort": true, + "value": {"layer": "subtitles", "type": "words"} + }, + { + "id": "wordsperminute", + "title": "Words per Minute", + "type": "float", + "columnWidth": 60, + "format": {"type": "number", "args": [3]}, + "sort": true, + "value": {"layer": "subtitles", "type": "wordsperminute"} + }, + { + "id": "numberofdocuments", + "title": "Number of Documents", + "type": "integer", + "columnWidth": 60, + "format": {"type": "number", "args": []}, + "sort": true, + "value": {"key": "documents", "type": "length"} + }, + { + "id": "size", + "title": "Size", + "type": "integer", + "capability": "canSeeSize", + "columnWidth": 60, + "format": {"type": "value", "args": ["B"]}, + "sort": true + }, + { + "id": "bitrate", + "title": "Bitrate", + "type": "integer", + "capability": "canSeeMedia", + "columnWidth": 60, + "format": {"type": "value", "args": ["bps"]}, + "sort": true + }, + { + "id": "parts", + "title": "Number of Parts", + "type": "integer", + "capability": "canSeeMedia", + "columnWidth": 60, + "sort": true + }, + { + "id": "numberoffiles", + "title": "Number of Files", + "type": "integer", + "capability": "canSeeMedia", + "columnWidth": 60, + "sort": true, + "value": {"key": "files", "type": "length"} + }, + { + "id": "filename", + "title": "Filename", + "type": ["string"], + "capability": "canSeeMedia" + }, + { + "id": "created", + "title": "Date Created", + "type": "date", + "columnWidth": 150, + "format": {"type": "date", "args": ["%Y-%m-%d %H:%M:%S"]}, + "sort": true + }, + { + "id": "modified", + "title": "Last Modified", + "type": "date", + "columnWidth": 150, + "format": {"type": "date", "args": ["%Y-%m-%d %H:%M:%S"]}, + "sort": true + }, + { + "id": "accessed", + "title": "Last Accessed", + "type": "date", + "capability": "canSeeAccessed", + "columnWidth": 150, + "format": {"type": "date", "args": ["%Y-%m-%d %H:%M:%S"]}, + "sort": true + }, + { + "id": "timesaccessed", + "title": "Times Accessed", + "type": "integer", + "capability": "canSeeAccessed", + "columnWidth": 60, + "format": {"type": "number", "args": []}, + "sort": true + }, + { + "id": "rightslevel", + "title": "Rights Level", + "type": "enum", + "columnWidth": 90, + "format": {"type": "ColorLevel", "args": [ + ["Public", "Out of Copyright", "Under Copyright", "Private"] + ]}, + "sort": true, + "sortOperator": "+", + "values": ["Public", "Out of Copyright", "Under Copyright", "Private", "Unknown"] + }, + { + "id": "canplayvideo", + "title": "Can Play Video", + "type": "boolean", + "value": "capability" + }, + { + "id": "canplayclips", + "title": "Can Play Clips", + "type": "boolean", + "value": "capability" + }, + { + "id": "random", + "title": "Random", + "type": "integer", + "sort": true + } + ], + /* + itemName specifies how items are being referred to. + Anything excessively long may cause layout errors. + */ + "itemName": { + "singular": "Movie", + "plural": "Movies" + }, + "itemRequiresVideo": false, + "itemViews": [ + {"id": "info", "title": "Info"}, + {"id": "documents", "title": "Documents"}, + {"id": "player", "title": "Player"}, + {"id": "editor", "title": "Editor"}, + {"id": "timeline", "title": "Timeline"}, + {"id": "clips", "title": "Clips"}, + {"id": "map", "title": "Map"}, + {"id": "calendar", "title": "Calendar"}, + {"id": "data", "title": "Data"}, + {"id": "media", "title": "Media"} + ], + "language": "en", + "languages": ["ar", "el", "en", "hi"], + // fixme: should be renamed to annotationLayers + "layers": [ + { + "id": "keywords", + "title": "Keywords", + "canAddAnnotations": {"member": true, "researcher": true, "staff": true, "admin": true}, + "hasEvents": true, + "hasPlaces": true, + "item": "Keyword", + "overlap": true, + "type": "string" + }, + { + "id": "notes", + "title": "Notes", + "canAddAnnotations": {"member": true, "researcher": true, "staff": true, "admin": true}, + "hasEvents": true, + "hasPlaces": true, + "item": "Note", + "overlap": true, + "showInfo": true, + "type": "text" + }, + { + "id": "subtitles", + "title": "Subtitles", + "canAddAnnotations": {"researcher": true, "staff": true, "admin": true}, + "hasEvents": true, + "hasPlaces": true, + "isSubtitles": true, + "item": "Subtitle", + "type": "text" + } + ], + "listViews": [ + {"id": "list", "title": "as List"}, + {"id": "grid", "title": "as Grid"}, + {"id": "timelines", "title": "with Timelines"}, + {"id": "clips", "title": "with Clips"}, + {"id": "clip", "title": "as Clips"}, + //{"id": "video", "title": "as Videos"}, + {"id": "map", "title": "on Map"}, + {"id": "calendar", "title": "on Calendar"} + ], + "media": { + "importPosters": false, + "importFrames": false + }, + "menuExtras": [ + "user", + //"locale", + "reload" + ], + "personalLists": [ + {"title": "Favorites"}, + {"title": "Black & White Films", "query": {"conditions": [{"key": "color", "value": "Black and White", "operator": "=="}], "operator": "&"}}, + {"title": "Silent Films", "query": {"conditions": [{"key": "language", "value": "None", "operator": "=="}, {"key": "sound", "value": "Silent", "operator": "=="}], "operator": "|"}} + ], + "posters": { + "ratio": 0.6875 + }, + "rightsLevel": {"member": 3, "researcher": 3, "staff": 3, "admin": 3}, + "rightsLevels": [ + {"name": "Public", "color": [128, 255, 128]}, + {"name": "Out of Copyright", "color": [212, 255, 128]}, + {"name": "Under Copyright", "color": [255, 212, 128]}, + {"name": "Private", "color": [255, 128, 128]} + ], + "sendReferrer": true, + "site": { + "description": "turkishcine.ma - A Project by Pad.ma", + // FIXME: "from" and "to" would be more intuitive as keys here + "email": { + // E-mail address in contact form (to) + "contact": "turkishcine.ma@turkishcine.ma", + "footer": "-- \nturkishcine.ma - https://turkishcine.ma", + "prefix": "turkishcine.ma News -", + // E-mail address uses by the system (from) + "system": "system@turkishcine.ma" + }, + "folderdepth": 4, + "https": true, + "id": "turkishcinema", + "name": "turkishcine.ma", + "url": "turkishcine.ma", + "videoprefix": "" + }, + "sitePages": [ + {"id": "about", "title": "About"}, + {"id": "news", "title": "News"}, + {"id": "faq", "title": "Frequently Asked Questions"}, + {"id": "terms", "title": "Terms of Service"}, + {"id": "copyrights", "title": "Copyrights"}, + {"id": "contact", "title": "Contact"} + ], + "sites": [ + {"name": "Pad.ma", "url": "pad.ma", "https": true}, + {"name": "OxDB", "url": "0xdb.org", "https": true} + ], + "textRightsLevels": [ + {"name": "Public", "color": [128, 255, 128]}, + {"name": "Private", "color": [255, 128, 128]} + ], + "themes": ["oxlight", "oxmedium", "oxdark"], + "timelines": [ + {"id": "antialias", "title": "Anti-Alias"}, + {"id": "slitscan", "title": "Slit-Scan"}, + {"id": "keyframes", "title": "Keyframes"}, + {"id": "audio", "title": "Waveform"} + ], + "totals": [ + {"id": "items"}, + {"id": "runtime"}, + {"id": "files", "admin": true}, + {"id": "duration", "admin": true}, + {"id": "size", "admin": true}, + {"id": "pixels"} + ], + "tv": { + "showLogo": false + }, + "user": { + "level": "guest", + "newsletter": true, + "ui": { + "annotationsCalendarSize": 128, + "annotationsMapSize": 128, + "annotationsRange": "all", + "annotationsSize": 256, + "annotationsSort": "position", + "calendarFind": "", + "calendarSelection": "", + "clipColumns": 2, + "columns": { + "Colors": { + "columns": ["title", "director", "country", "year", "hue", "saturation", "brightness"], + "columnWidth": {} + } + }, + "document": "", + "documents": {}, + "documentSize": 256, + "documentsSelection": {}, + "documentsSort": [{"key": "name", "operator": "+"}], + "documentsView": "grid", + "edit": "", + "edits": {}, + "editSelection": [], + "editSort": [ + {"key": "index", "operator": "+"}, + {"key": "year", "operator": "+"}, + {"key": "director", "operator": "+"}, + {"key": "title", "operator": "+"}, + {"key": "position", "operator": "+"}, + {"key": "duration", "operator": "+"} + ], + "editView": "list", + "embedSize": 256, + "filters": [ + {"id": "director", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "year", "sort": [{"key": "name", "operator": "+"}]}, + {"id": "language", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "productionCompany", "sort": [{"key": "items", "operator": "-"}]}, + {"id": "actor", "sort": [{"key": "items", "operator": "-"}]} + ], + "filtersSize": 176, + "find": {"conditions": [], "operator": "&"}, + "followPlayer": true, + "help": "", + "icons": "posters", + "infoIconSize": 256, + "item": "", + "itemFind": "", + "itemSort": [{"key": "position", "operator": "+"}], + "itemView": "info", + "listColumns": ["title", "director", "year", "language", "runtime", "productionCompany"], + "listColumnWidth": {}, + "listSelection": [], + "listSort": [ + {"key": "year", "operator": "+"}, + {"key": "director", "operator": "+"}, + {"key": "title", "operator": "+"} + ], + "listView": "grid", + "lists": {}, + "locale": "en", + "mapFind": "", + "mapSelection": "", + "onload": "", + "page": "", + "part": { + "api": "", + "documents": "", + "faq": "", + "help": "", + "news": "", + "preferences": "", + "tv": "" + }, + "section": "items", + "sequenceMode": "shape", + "sequenceSort": [{"key": "director", "operator": "+"}], + "showAdvancedEmbedOptions": false, + "showAnnotations": true, + "showAnnotationsCalendar": true, + "showAnnotationsMap": true, + "showBrowser": true, + "showCalendarControls": true, // fixme: should be false + "showClips": true, + "showDocument": true, + "showFilters": true, + "showIconBrowser": false, + "showInfo": true, + "showLayers": { + "keywords": true, + "notes": true, + "subtitles": true + }, + "showMapControls": false, + "showMapLabels": false, + "showFolder": { + "edits": { + "personal": true, + "favorite": true, + "featured": true + }, + "items": { + "personal": true, + "favorite": true, + "featured": true, + "volumes": true + }, + "texts": { + "personal": true, + "favorite": true, + "featured": true + } + }, + "showReflections": true, + "showSidebar": true, + "showSitePosters": false, + "showTimeline": true, + "sidebarSize": 256, + "text": "", + "texts": {}, + "theme": "oxmedium", + "updateAdvancedFindResults": false, + "videoLoop": false, + "videoMuted": false, + "videoPoints": {}, + "videoResolution": 240, + "videoScale": "fit", + "videoSize": "small", + "videoSubtitles": true, + "videoTimeline": "slitscan", + "videoView": "player", + "videoVolume": 1 + }, + "username": "", + "volumes": [] + }, + // fixme: this should include colors + "userLevels": ["guest", "member", "researcher", "staff", "admin"], + "video": { + "torrent": false, + "formats": ["webm", "mp4"], + "previewRatio": 1.375, + "resolutions": [240, 480] + } +} diff --git a/install.py b/install.py new file mode 100755 index 0000000..8ba9ae1 --- /dev/null +++ b/install.py @@ -0,0 +1,56 @@ +#!/usr/bin/python + +import os +from os.path import join, abspath, basename, dirname + +name = 'turkishcinema' +base = abspath(dirname(__file__)) +os.chdir(base) + +for root, folders, files in os.walk(join(base, 'static')): + for f in files: + src = join(root, f) + target = src.replace(base, '/srv/pandora') + rel_src = os.path.relpath(src, dirname(target)) + if os.path.exists(target): + os.unlink(target) + os.symlink(rel_src, target) + +overwrite = ( + ('home', 'indiancinema'), + ('infoView', 'indiancinema'), +) + +os.chdir('/srv/pandora/static/js') +for filename, sitename in overwrite: + src = '%s.%s.js' % (filename, sitename) + target = '%s.%s.js' % (filename, name) + if os.path.exists(target): + os.unlink(target) + os.symlink(src, target) + +os.chdir(base) +src = join(base, 'config.jsonc') +target = '/srv/pandora/pandora/config.%s.jsonc' % name +rel_src = os.path.relpath(src, dirname(target)) +if os.path.exists(target): + os.unlink(target) +os.symlink(rel_src, target) +t = '/srv/pandora/pandora/config.jsonc' +if os.path.exists(t): + os.unlink(t) +os.symlink(basename(target), t) + +for root, folders, files in os.walk(join(base, 'scripts')): + for f in files: + src = join(root, f) + target = src.replace(base, '/srv/pandora') + rel_src = os.path.relpath(src, dirname(target)) + if os.path.exists(target): + os.unlink(target) + os.symlink(rel_src, target) + +#todo +#custom python module etc +#local_settings.py? + diff --git a/scripts/poster.py b/scripts/poster.py new file mode 100755 index 0000000..38040c5 --- /dev/null +++ b/scripts/poster.py @@ -0,0 +1,226 @@ +#!/usr/bin/python +# -*- coding: utf-8 -*- +# vi:si:et:sw=4:sts=4:ts=4 +from __future__ import division +import os + +root_dir = os.path.normpath(os.path.abspath(os.path.join(os.path.dirname(__file__), '..'))) + +# using virtualenv's activate_this.py to reorder sys.path +activate_this = os.path.join(root_dir, 'bin', 'activate_this.py') +execfile(activate_this, dict(__file__=activate_this)) + +import Image +import ImageDraw +import json +from optparse import OptionParser +import ox +from ox.image import getRGB, drawText, wrapText +import sys + +static_root = os.path.join(os.path.dirname(__file__), 'data') + +def render_poster(data, poster): + + title = ox.decode_html(data.get('title', '')) + director = ox.decode_html(u', '.join(data.get('director', []))) + year = str(data.get('year', '')) + frame = data.get('frame') + timeline = data.get('timeline') + + poster_width = 704 + poster_height = 1024 + frame_height = 512 + frame_ratio = poster_width / frame_height + timeline_height = 64 + text_margin = 16 + text_width = poster_width - 2 * text_margin + poster_image = Image.new('RGB', (poster_width, poster_height)) + draw = ImageDraw.Draw(poster_image) + font_file = os.path.join(static_root, 'SourceSansProSemibold.ttf') + font_size = {'cinema': 111, 'director': 32, 'title': 48, 'year': 426} + font_lightness = {'cinema': 0.7, 'director': 0.8, 'title': 0.8, 'year': 0.6} + poster_lightness = {'image': 0.2, 'text': 0.4} + + if year: + hue = int(year) % 100 / 100 * 360 + saturation = 1 + else: + hue = 0 + saturation = 0 + + # background + draw.rectangle( + [(0, frame_height), (poster_width, poster_height - timeline_height)], + fill=getRGB((hue, saturation, poster_lightness['text'])) + ) + + # year + if year: + drawText( + poster_image, + (-93, poster_height - timeline_height - font_size['year'] + 6), + year, + font_file, + font_size['year'], + getRGB((hue, saturation, font_lightness['year'])) + ) + + # cinema + for y in [-1, 1]: + for x in [-1, 1]: + drawText( + poster_image, + (-10 + x, poster_height - timeline_height - font_size['cinema'] + 1 + y), + 'turkishcine.ma', + font_file, + font_size['cinema'], + getRGB((hue, saturation, poster_lightness['text'])) + ) + drawText( + poster_image, + (-10, poster_height - timeline_height - font_size['cinema'] + 1), + 'turkishcine.ma', + font_file, + font_size['cinema'], + getRGB((hue, saturation, font_lightness['cinema'])) + ) + + # director and title + offset_top = frame_height + text_margin + if not director: + title_max_lines = 8 + else: + title_max_lines = min(len(wrapText( + title, + text_width, + 0, + font_file, + font_size['title'] + )), 7) + director_max_lines = 11 - int((title_max_lines * 3 - 1) / 2) + + # director + if director: + lines = wrapText( + director, + text_width, + director_max_lines, + font_file, + font_size['director'] + ) + for line in lines: + for y in [-1, 1]: + for x in [-1, 1]: + drawText( + poster_image, + (text_margin + x, offset_top + y), + line, + font_file, + font_size['director'], + getRGB((hue, saturation, poster_lightness['text'])) + ) + size = drawText( + poster_image, + (text_margin, offset_top), + line, + font_file, + font_size['director'], + getRGB((hue, saturation, font_lightness['director'])) + ) + offset_top += font_size['director'] + 2 + offset_top += size[1] - font_size['director'] - 2 + + # title + lines = wrapText( + title, + text_width, + title_max_lines, + font_file, + font_size['title'] + ) + for line in lines: + for y in [-1, 1]: + for x in [-1, 1]: + drawText( + poster_image, + (text_margin + x, offset_top + y), + line, + font_file, + font_size['title'], + getRGB((hue, saturation, poster_lightness['text'])) + ) + drawText( + poster_image, + (text_margin, offset_top), + line, + font_file, + font_size['title'], + getRGB((hue, saturation, font_lightness['title'])) + ) + offset_top += font_size['title'] + 3 + + # frame + if frame: + frame_image = Image.open(frame) + frame_image_ratio = frame_image.size[0] / frame_image.size[1] + if frame_ratio < frame_image_ratio: + frame_image = frame_image.resize( + (int(frame_height * frame_image_ratio), frame_height), + Image.ANTIALIAS + ) + left = int((frame_image.size[0] - poster_width) / 2) + frame_image = frame_image.crop( + (left, 0, left + poster_width, frame_height) + ) + else: + frame_image = frame_image.resize( + (poster_width, int(poster_width / frame_image_ratio)), + Image.ANTIALIAS + ) + top = int((frame_image.size[1] - frame_height) / 2) + frame_image = frame_image.crop( + (0, top, poster_width, top + frame_height) + ) + poster_image.paste(frame_image, (0, 0)) + else: + draw.rectangle( + [(0, 0), (poster_width, frame_height)], + fill=getRGB((hue, saturation, poster_lightness['image'])) + ) + + # timeline + if timeline: + timeline_image = Image.open(timeline) + timeline_image = timeline_image.resize( + (poster_width, timeline_height), + Image.ANTIALIAS + ) + poster_image.paste(timeline_image, (0, poster_height - timeline_height)) + else: + draw.rectangle( + [(0, poster_height - timeline_height), (poster_width, poster_height)], + fill=getRGB((hue, saturation, poster_lightness['image'])) + ) + + poster_image.save(poster, quality=100) + +def main(): + parser = OptionParser() + parser.add_option('-d', '--data', dest='data', help='json file with metadata', default=None) + parser.add_option('-p', '--poster', dest='poster', help='Poster (image file to be written)') + (options, args) = parser.parse_args() + if None in (options.data, options.poster): + parser.print_help() + sys.exit() + + if options.data == '-': + data = json.load(sys.stdin) + else: + with open(options.data) as f: + data = json.load(f) + + render_poster(data, options.poster) + +if __name__ == "__main__": + main() diff --git a/static/png/icon.turkishcinema.png b/static/png/icon.turkishcinema.png new file mode 100644 index 0000000..034c9d4 Binary files /dev/null and b/static/png/icon.turkishcinema.png differ diff --git a/static/png/logo.turkishcinema.png b/static/png/logo.turkishcinema.png new file mode 100644 index 0000000..c120ad8 Binary files /dev/null and b/static/png/logo.turkishcinema.png differ