{"id":34025029,"url":"https://github.com/louislang/sortmedia","last_synced_at":"2026-04-07T11:31:28.861Z","repository":{"id":36469529,"uuid":"225118074","full_name":"louislang/sortmedia","owner":"louislang","description":"Dedupe and sort photo and video files based on the date they were created.","archived":false,"fork":false,"pushed_at":"2024-07-30T19:38:06.000Z","size":2543,"stargazers_count":7,"open_issues_count":1,"forks_count":1,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-12-15T07:00:17.592Z","etag":null,"topics":["file-sorting","media-manager","photos","videos"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/louislang.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-12-01T06:40:32.000Z","updated_at":"2024-09-11T21:49:49.000Z","dependencies_parsed_at":"2024-07-30T23:33:06.194Z","dependency_job_id":null,"html_url":"https://github.com/louislang/sortmedia","commit_stats":{"total_commits":80,"total_committers":4,"mean_commits":20.0,"dds":0.25,"last_synced_commit":"6caca50564264268d2b2f46f3976022d086233a8"},"previous_names":[],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/louislang/sortmedia","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louislang%2Fsortmedia","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louislang%2Fsortmedia/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louislang%2Fsortmedia/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louislang%2Fsortmedia/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/louislang","download_url":"https://codeload.github.com/louislang/sortmedia/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/louislang%2Fsortmedia/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":31511545,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-04-07T03:10:19.677Z","status":"ssl_error","status_checked_at":"2026-04-07T03:10:13.982Z","response_time":105,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.5:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["file-sorting","media-manager","photos","videos"],"created_at":"2025-12-13T16:50:33.964Z","updated_at":"2026-04-07T11:31:28.856Z","avatar_url":"https://github.com/louislang.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# sortmedia\r\n![Actions Status](https://github.com/LouisLang/sortmedia/workflows/Python%20application/badge.svg)\r\n![MIT License Badge](https://img.shields.io/github/license/LouisLang/sortmedia) \r\n[![Coverage Status](https://coveralls.io/repos/github/LouisLang/sortmedia/badge.svg?branch=master)](https://coveralls.io/github/LouisLang/sortmedia?branch=master)\r\n[![GitHub issues](https://img.shields.io/github/issues/LouisLang/sortmedia)](https://github.com/LouisLang/sortmedia/issues)\r\n\r\nDedupe and sort images and video files based on their creation date. \r\n\r\n![Image of Sorted Files](https://github.com/LouisLang/sortmedia/blob/master/resources/demo.png)\r\n\r\n* Handles images and video files.\r\n* Support for `heic` files (common iOS format).\r\n* Supports excluding directories.\r\n* Removes duplicates based on file hash.\r\n* Organizes files into `year/month/day/files.ext`.\r\n\r\n## Installation\r\n`pip install sortmedia`\r\n\r\n## Command Line Usage\r\n### Sorting a directory of media files, *move* to destination directory.\r\nBasic usage - processing a directory of media files `foo` and moving them to the destination directory `bar`.\r\n\r\n`sortmedia foo bar`\r\n\r\n### Sorting a directory of media files, *copy* to destination directory.\r\nInstead of moving files (the default), copy the files leaving the source directory `foo` intact. \r\n\r\n`sortmedia -c foo bar`\r\n\r\nor \r\n\r\n`sortmedia --copy foo bar`\r\n\r\n### Exclude directory\r\nYou can list a set of directories that we should completely ignore. Assuming the following directory structure:\r\n\r\n```\r\nfoo/\r\n  ignoreMe/\r\n  ignoreMeToo/\r\n  img1.jpg\r\n  img2.png\r\n  ...\r\n```\r\n\r\n`sortmedia --exclude=foo/ignoreMe,foo/ignoreMeToo foo/ bar/`\r\n\r\n### Skip processing for a specified directory - but still move/copy.\r\nIf you have directories that are already sorted, that you'd like to skip processing but still move or copy you can mark them as \"no process\" directories. Assuming the following directory structure:\r\n\r\n```\r\nfoo/\r\n  alreadySorted/\r\n  img1.jpg\r\n  img2.png\r\n  ...\r\n```\r\n\r\n`sortmedia --noprocess=foo/alreadySorted/ foo/ bar/`\r\n\r\nThis will result in `alreadySorted/` being moved to `bar/` without analyzing the files under that directory.\r\n\r\n## Programmatic Usage\r\nThe primary interface into `sortmedia` is the `SortMedia` class. This class can be instantiated and used as follows:\r\n\r\n```\r\nfrom sortmedia.sort import SortMedia\r\nsort = SortMedia()\r\nsort.process('src/', 'dst/')\r\n```\r\n\r\nThis will process media in `src/` and move the files to `dst/`.\r\n\r\n### Copying instead of moving\r\nYou can set the sorter to `copy` rather than `move` (which is the default):\r\n\r\n```\r\nfrom sortmedia.sort import SortMedia\r\nsort = SortMedia(copy=True)\r\n```\r\n\r\n### Specifying directories to ignore\r\nLets say you have a directory of photos, `photos/`, with two directories you want to completely ignore: `ignoreMe` and `ignoreMeToo`.\r\n\r\n```\r\nfrom sortmedia.sort import SortMedia\r\nsort = SortMedia(excludes=['photos/ignoreMe', 'photos/ignoreMeToo'])\r\n```\r\n\r\n### Move/copy but do not process directory\r\nIn some instances you might have a directory of media (e.g. `photos/birthday-photos/`) that you want to move or copy to the destination directory without processing the files in the directory. You can achieve this by passing a list of directories in the `noprocess` parameter.\r\n\r\n```\r\nfrom sortmedia.sort import SortMedia\r\nsort = SortMedia(noprocess=['photos/birthday-photos/`])\r\n```\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flouislang%2Fsortmedia","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flouislang%2Fsortmedia","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flouislang%2Fsortmedia/lists"}