-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit b25a100
Showing
137 changed files
with
14,199 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
photod-frontend/node_modules/ | ||
photod-backend/env/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
photod-frontend/node_modules/ | ||
|
||
photod-backend/env/ | ||
photod-backend/cache/ | ||
photod-backend/data/ | ||
photod-backend/photod/settings/local.py |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
Add celery | ||
select items | ||
|
||
|
||
|
||
classify colors -> remove GPL |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,28 @@ | ||
#!/usr/bin/env python | ||
import os | ||
import sys | ||
|
||
if __name__ == "__main__": | ||
# Set the default settings file | ||
os.environ.setdefault( | ||
"DJANGO_SETTINGS_MODULE", "photod.settings.local") | ||
|
||
# Load the Django environment. | ||
try: | ||
from django.core.management import execute_from_command_line | ||
except ImportError: | ||
# The above import may fail for some other reason. Ensure that the | ||
# issue is really that Django is missing to avoid masking other | ||
# exceptions on Python 2. | ||
try: | ||
import django # noqa | ||
except ImportError: | ||
raise ImportError( | ||
"Couldn't import Django. Are you sure it's installed and " | ||
"available on your PYTHONPATH environment variable? Did you " | ||
"forget to activate a virtual environment?" | ||
) | ||
raise | ||
|
||
# Run the command. | ||
execute_from_command_line(sys.argv) |
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,154 @@ | ||
from django.urls import reverse | ||
|
||
from photod.core import models | ||
from photod.web.views import thumbnail, image, filmstrip | ||
|
||
from graphene_django.filter import DjangoFilterConnectionField | ||
from graphene_django import DjangoObjectType | ||
|
||
from graphene import relay | ||
|
||
from graphql_relay.node.node import from_global_id | ||
|
||
import graphene | ||
import django_filters | ||
|
||
|
||
class MediaFileFilter(django_filters.FilterSet): | ||
class Meta: | ||
model = models.MediaFile | ||
fields = ["directory_id", "directory", "tag"] | ||
|
||
tag = django_filters.CharFilter(name='tags', method='filter_tag') | ||
|
||
def filter_tag(self, queryset, name, value): | ||
return queryset.filter(tags__label__iexact=value) | ||
|
||
|
||
class ThumbnailFilter(django_filters.FilterSet): | ||
class Meta: | ||
model = models.Thumbnail | ||
fields = ["width", "height", "min_width", "min_height"] | ||
|
||
min_width = django_filters.NumberFilter(name='width', lookup_expr='gte') | ||
min_height = django_filters.NumberFilter(name='height', lookup_expr='gte') | ||
|
||
|
||
class FilmstripFilter(django_filters.FilterSet): | ||
class Meta: | ||
model = models.Filmstrip | ||
fields = ["width", "height", "min_width", "min_height"] | ||
|
||
min_width = django_filters.NumberFilter(name='width', lookup_expr='gte') | ||
min_height = django_filters.NumberFilter(name='height', lookup_expr='gte') | ||
|
||
|
||
class Tag(DjangoObjectType): | ||
class Meta: | ||
model = models.Tag | ||
interfaces = (relay.Node, ) | ||
filter_fields = ['label'] | ||
|
||
|
||
class Face(DjangoObjectType): | ||
class Meta: | ||
model = models.Face | ||
interfaces = (relay.Node, ) | ||
|
||
|
||
class Person(DjangoObjectType): | ||
class Meta: | ||
model = models.Person | ||
interfaces = (relay.Node, ) | ||
|
||
|
||
class Album(DjangoObjectType): | ||
class Meta: | ||
model = models.Album | ||
interfaces = (relay.Node, ) | ||
|
||
|
||
class Directory(DjangoObjectType): | ||
class Meta: | ||
model = models.Directory | ||
interfaces = (relay.Node, ) | ||
|
||
children_count = graphene.Int() | ||
media_files_count = graphene.Int() | ||
|
||
def resolve_children_count(self, args, context, info): | ||
return self.get_children_count() | ||
|
||
def resolve_media_files_count(self, args, context, info): | ||
return self.media_files.all().count() | ||
|
||
|
||
class Thumbnail(DjangoObjectType): | ||
class Meta: | ||
model = models.Thumbnail | ||
interfaces = (relay.Node, ) | ||
|
||
url = graphene.String() | ||
|
||
def resolve_url(self, args, context, info): | ||
return reverse(thumbnail, args=[self.media_file_id, self.id]) | ||
|
||
|
||
class Filmstrip(DjangoObjectType): | ||
class Meta: | ||
model = models.Filmstrip | ||
interfaces = (relay.Node, ) | ||
|
||
url = graphene.String() | ||
|
||
def resolve_url(self, args, context, info): | ||
return reverse(filmstrip, args=[self.media_file_id, self.id]) | ||
|
||
|
||
class Palette(DjangoObjectType): | ||
class Meta: | ||
model = models.Palette | ||
interfaces = (relay.Node, ) | ||
|
||
|
||
class MediaFile(DjangoObjectType): | ||
class Meta: | ||
model = models.MediaFile | ||
interfaces = (relay.Node, ) | ||
|
||
thumbnails = DjangoFilterConnectionField( | ||
Thumbnail, filterset_class=ThumbnailFilter) | ||
filmstrips = DjangoFilterConnectionField( | ||
Filmstrip, filterset_class=FilmstripFilter) | ||
|
||
url = graphene.String() | ||
|
||
def resolve_url(self, args, context, info): | ||
return reverse(image, args=[self.id]) | ||
|
||
|
||
class Query(graphene.ObjectType): | ||
node = relay.Node.Field() | ||
|
||
media_files = DjangoFilterConnectionField( | ||
MediaFile, filterset_class=MediaFileFilter) | ||
|
||
tags = DjangoFilterConnectionField(Tag) | ||
faces = DjangoFilterConnectionField(Face) | ||
persons = DjangoFilterConnectionField(Person) | ||
|
||
albums = DjangoFilterConnectionField(Album) | ||
directories = DjangoFilterConnectionField( | ||
Directory, parent_id=graphene.ID()) | ||
|
||
def resolve_directories(self, args, context, info): | ||
parent_id = args.get('parent_id') | ||
|
||
if parent_id: | ||
_, parent_id = from_global_id(parent_id) | ||
|
||
return models.Directory.objects.get(id=parent_id).get_children() | ||
|
||
return models.Directory.get_root_nodes() | ||
|
||
schema = graphene.Schema(query=Query) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
from django.conf.urls import url | ||
from django.conf import settings | ||
|
||
from django.views.decorators.csrf import csrf_exempt | ||
|
||
from graphene_django.views import GraphQLView | ||
|
||
|
||
urlpatterns = [ | ||
url(r'^graphql', csrf_exempt( | ||
GraphQLView.as_view(graphiql=settings.DEBUG) | ||
)), | ||
] |
Empty file.
Binary file not shown.
Empty file.
Binary file added
BIN
+166 Bytes
photod-backend/photod/cli/management/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Empty file.
Binary file added
BIN
+175 Bytes
photod-backend/photod/cli/management/commands/__pycache__/__init__.cpython-36.pyc
Binary file not shown.
Binary file added
BIN
+895 Bytes
photod-backend/photod/cli/management/commands/__pycache__/clean.cpython-36.pyc
Binary file not shown.
Binary file added
BIN
+2.52 KB
photod-backend/photod/cli/management/commands/__pycache__/enroll.cpython-36.pyc
Binary file not shown.
Binary file added
BIN
+802 Bytes
photod-backend/photod/cli/management/commands/__pycache__/process.cpython-36.pyc
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
from django.core.management.base import BaseCommand | ||
|
||
from photod.core.models import MediaFile | ||
|
||
import os | ||
|
||
|
||
class Command(BaseCommand): | ||
help = 'Clean all media files that do not exist.' | ||
|
||
def handle(self, *args, **options): | ||
cleanup = [] | ||
|
||
# Collect all media files that do not exist anymore. | ||
for media_file in MediaFile.objects.all(): | ||
if not os.path.isfile(media_file.path): | ||
cleanup.append(media_file.id) | ||
|
||
self.stdout.write(self.style.WARNING( | ||
'Media file "%s" does not exist.' % media_file.path)) | ||
|
||
# Perform the cleanup. | ||
MediaFile.objects.filter(id__in=cleanup).delete() |
120 changes: 120 additions & 0 deletions
120
photod-backend/photod/cli/management/commands/enroll.py
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,120 @@ | ||
from django.core.management.base import BaseCommand | ||
|
||
from photod.core.models import MediaFile | ||
|
||
import hashlib | ||
import magic | ||
import glob | ||
import os | ||
|
||
|
||
class Command(BaseCommand): | ||
help = 'Enroll a directory of media files' | ||
|
||
def add_arguments(self, parser): | ||
parser.add_argument('directories', nargs='+', type=str) | ||
|
||
def scan(self, directories): | ||
""" | ||
Scan the directories, and yield each file found. | ||
""" | ||
|
||
for directory in directories: | ||
search_path = os.path.join(directory, "**/*") | ||
|
||
for file_path in glob.iglob(search_path, recursive=True): | ||
if os.path.isfile(file_path): | ||
yield file_path | ||
|
||
def enroll(self, file_path): | ||
""" | ||
Enroll a file. | ||
""" | ||
|
||
# Ensure the file exists. | ||
if not os.path.isfile(file_path): | ||
return False | ||
|
||
# Retrieve mime type. | ||
mime_type = magic.from_file(file_path, mime=True) | ||
|
||
if not mime_type: | ||
return False | ||
|
||
# Calculate hash of file. | ||
hash_instance = hashlib.sha256() | ||
|
||
with open(file_path, "rb") as fp: | ||
while True: | ||
data = fp.read(hash_instance.block_size) | ||
|
||
if not data: | ||
break | ||
|
||
hash_instance.update(data) | ||
|
||
digest = hash_instance.hexdigest() | ||
|
||
return MediaFile(path=file_path, mime_type=mime_type, digest=digest) | ||
|
||
def get_or_create(self, media_file): | ||
""" | ||
Try to find an existing media file in the database, or insert one if it | ||
does not exist. | ||
If the media file already exist, but the path (or digest) does not | ||
match, it is updated. | ||
""" | ||
|
||
# Try to find it using all information. | ||
try: | ||
return MediaFile.objects.get( | ||
path=media_file.path, | ||
digest=media_file.digest, | ||
mime_type=media_file.mime_type | ||
) | ||
except MediaFile.DoesNotExist: | ||
pass | ||
|
||
# Fall back on path and mime type (e.g. file updated). | ||
try: | ||
new_media_file = MediaFile.objects.get( | ||
path=media_file.path, | ||
mime_type=media_file.mime_type | ||
) | ||
|
||
new_media_file.digest = media_file.digest | ||
|
||
return new_media_file.save() | ||
except MediaFile.DoesNotExist: | ||
pass | ||
|
||
# Last, fall back on mime type and digest (e.g. file moved). | ||
try: | ||
new_media_file = MediaFile.objects.get( | ||
digest=media_file.digest, | ||
mime_type=media_file.mime_type | ||
) | ||
|
||
new_media_file.path = media_file.path | ||
|
||
return new_media_file.save() | ||
except MediaFile.DoesNotExist: | ||
pass | ||
|
||
# It did not exist, so create one. | ||
return media_file.save() | ||
|
||
def handle(self, *args, **options): | ||
for file_path in self.scan(options['directories']): | ||
media_file = self.enroll(file_path) | ||
|
||
if not media_file: | ||
self.stdout.write(self.style.WARNING( | ||
'Unable to enroll "%s".' % file_path)) | ||
continue | ||
|
||
self.get_or_create(media_file) | ||
|
||
self.stdout.write(self.style.SUCCESS( | ||
'Enrolled "%s".' % file_path)) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
from django.core.management.base import BaseCommand | ||
|
||
from photod.core.models import MediaFile | ||
from photod.core.steps import Step | ||
|
||
|
||
class Command(BaseCommand): | ||
help = 'Process all media files and apply all steps.' | ||
|
||
def handle(self, *args, **options): | ||
for media_file in MediaFile.objects.all(): | ||
for step in Step.iter_pipeline(): | ||
if step.process(media_file, {}): | ||
media_file.save() |
Empty file.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
from django.contrib import admin | ||
|
||
from .models import MediaFile | ||
|
||
admin.site.register(MediaFile) |
Oops, something went wrong.