Skip to content

Commit

Permalink
v0.2-alpha update
Browse files Browse the repository at this point in the history
Various features added:
-size_limit added
-shuffle added
-log added (screen log only, file log planned)
localization module added. English and Portuguese supported. Auto localization also added (EN default)

Updated:
-delete_left_files updated to work with -size_limit
README.md updated

Improved:
Exception handling improved
Error messages improved
  • Loading branch information
redactedPenguin committed Feb 18, 2018
1 parent c7c539f commit 65a0df3
Show file tree
Hide file tree
Showing 4 changed files with 253 additions and 46 deletions.
51 changes: 33 additions & 18 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

## Português

`ffsmc` é uma ferramenta em linha de comando para encontrar e copiar músicas `.mp3` avaliadas com 5 estrelas em uma pasta e suas subpastas para uma outra pasta, útil para sincronizar apenas o melhor da sua biblioteca com seu smartphone, por exemplo, com menor capacidade de armazenamento. Uma vez que você já realizou a cópia uma vez e deseja atualizar, ele pode copiar apenas as músicas que estão faltando no destino, para agilizar o processo. E ainda, caso haja músicas cuja avaliação diminuiu na pasta de origem ou que foram apagadas de lá, você pode ordenar que elas sejam apagadas no destino também. Suporta apenas `.mp3` até o momento.
`ffsmc` é uma ferramenta em linha de comando para encontrar e copiar músicas `.mp3` avaliadas com 5 estrelas em uma pasta e suas subpastas para uma outra pasta, útil para sincronizar apenas o melhor da sua biblioteca com seu smartphone, por exemplo, com menor capacidade de armazenamento. Uma vez que você já realizou a cópia uma vez e deseja atualizar, ele pode copiar apenas as músicas que estão faltando no destino, para agilizar o processo. Caso haja músicas cuja avaliação diminuiu na pasta de origem ou que foram apagadas de lá, você pode ordenar que elas sejam apagadas no destino também. Ele também pode limitar a cópia de arquvos até um certo limite de tamanho e embaralhar os arquivos copiados, o que é útil para mudar o conjunto de arquivos a cada atualização. Suporta apenas `.mp3` até o momento.


## Meu caso de uso
Expand All @@ -14,20 +14,28 @@ Desenvolvi o `ffsmc` como uma forma de ajudar a organizar minha própria bibliot

## Utilização

* `ffsmc.exe -source "pasta_de_origem" -destination "pasta_destino" [-override_on_destination] [-delete_left_files]`
* Opções entre colchetes são opcionais
* O parâmetro após `-source` deve ser a pasta de origem
* O parâmetro após `-destination` deve ser a pasta destino
* `-override_on_destination` realiza a cópia de todos os arquivos, sobrescrevendo os que já estiverem na pasta destino. Caso não seja recebido, será feita a cópia apenas dos arquivos que estiverem faltando
* `-delete_left_files apaga` todos os arquivos da pasta destino que não forem encontrados na busca, ou que não tenham satisfeito às condições para seleção (possuir 5 estrelas de avaliação). Caso não seja recebido, eles serão ignorados
* Você deve utilizar a extensão `.exe` mesmo rodando em Linux. É uma peculiaridade da exportação standalone feita com o nuitka que mantive
* Note que, por enquanto, a única verificação de igualdade feita em `-override_on_destination` e `-delete_left_files` é baseada no nome do arquivo
**`ffsmc.exe -source "pasta_origem" -destination "pasta_destino" [opções]`**

Opções são:

* `-h`, mostra esta tela de ajuda.
* `-source "pasta_origem"`, define a pasta de origem na busca por músicas. `"pasta_origem"` é o caminho da pasta de origem e precisa estar logo após `-source`. O uso de aspas é recomendado.
* `-destination "pasta_destino"`, define a pasta destino para onde copiar as músicas. `"pasta_destino"` é o caminho para a pasta destino e deve estar logo após `-destination`. O uso de aspas é recomendado.
* `-override_on_destination`, copia todos os arquivos, sobrescrevendo aqueles que já estão no destino. Se não for recebido, será feita a cópia apenas dos arquivos faltando.
* `-delete_left_files`, exclui do destino todos os arquivos que não foram encontrados durante a busca, não cumprem os requisitos para seleção (possuir 5 estrelas de rating) ou que não foram copiados por conta do uso de `-size_limit`. Se não for recebido, eles serão ignorados.
* `-size_limit tamanho_em_megabytes`, copia arquivos até atingir `tamanho_em_megabytes`. Esta opção sozinha não apagará arquivos do destino a menos que `-delete_left_files` também seja usado.
* `-shuffle_file_list`, embaralha a lista de arquivos a copiar aleatoriamente. É útil em conjunto com `-size_limit` para ter um conjunto aleatório de músicas abaixo do tamanho limite definido.
* `-log`, mostra todos os arquivos sendo copiados ou apagados.

* Você deve utilizar a extensão `.exe` mesmo rodando em `Linux` . É uma peculiaridade da exportação standalone feita com o `nuitka` que mantive.
* Note que, por enquanto, a única verificação de igualdade feita em `-override_on_destination` e `-delete_left_files` é baseada no nome do arquivo.




## English

`ffsmc` is a command line tool to find and copy `.mp3` music rated as 5 stars from a folder and its subfolders and paste them to another folder, useful to synchronize only the best of your music library with your smartphone, for instance, with less storage capability. Once you already executed once and you want to update it, it can also copy/paste only the files that are not yet on destination to speedup the process. Also, if there are any music that was down-rated or deleted on the source folder, you can order it to delete them on destination too. Supports only `.mp3` at the moment.
`ffsmc` is a command line tool to find and copy `.mp3` music rated as 5 stars from a folder and its subfolders and paste them to another folder, useful to synchronize only the best of your music library with your smartphone, for instance, with less storage capability. Once you already executed once and you want to update it, it can also copy/paste only the files that are not yet on destination to speedup the process. Also, if there are any music that was down-rated or deleted on the source folder, you can order it to delete them on destination too. It can limit the copy of the files under certain size and shuffle the files copied, useful to change the music set each time it runs. Supports only `.mp3` at the moment.


## My use case
Expand All @@ -37,14 +45,21 @@ I developed `ffsmc` as a way to help me organize my own library but I believe it

## Utilization

* `ffsmc.exe -source "source_folder" -destination "destination_folder" [-override_on_destination] [-delete_left_files]`
* Options between brackets are optional
* The argument after `-source` must be the source folder
* The argument after `-destination` must be the destination folder
* `-override_on_destination` copy/paste all files, overwriting those already on destination. If it's not received, it will copy/paste only the files needed
* `-delete_left_files` deletes all the files on destination that wasn't found during the scan, or don't match the requisites to be selected (have a rating of 5 stars). If it's not received, they will be ignored
* You must use `.exe` extension even running on Linux. It is a peculiarity of standalone export using nuitka I kept
* Notice that, for now, the only equality check made in `-override_on_destination` and `-delete_left_files` is based on the file name
**`ffsmc.exe -source "source_folder" -destination "destination_folder" [options]`**

Options are:
* `-h`, shows this help screen.
* `-source "source_folder"`, sets the source folder to search for music. `"source_folder"` is the path of the source folder and must be right after `-source`. The use of quotes is recommended.
* `-destination "destination folder"`, sets the destination folder to copy music to. `"destination_folder"` is the path of the destination folder and must be right after `-destination`. The use of quotes is recommended.
* `-override_on_destination`, copy/paste all files, overwriting those already on destination. If it's not received, it will copy/paste only the files needed.
* `-delete_left_files`, deletes all the files on destination that wasn't found on the source during the scan, don't match the requisites to be selected (have 5 stars of rating) or was not copied due to use of `-size_limit`. If it's not received, they will be ignored.
* `-size_limit size_in_megabytes`, copy/paste files until the size reaches `size_in_megabytes`. This option alone won't erase any file left on destination unless `-delete_left_files` is also used.
* `-shuffle_file_list`, shuffles the list of files to copy them randomly. It is useful when used with `-size_limit` to have a random set of musics under the size limit defined.
* `-log`, shows all files being copied and deleted.

* You must use `.exe` extension even running on `Linux`. It is a peculiarity of standalone export using `nuitka` I kept.
* Notice that, for now, the only equality check made in `-override_on_destination` and `-delete_left_files` is based on the file name.



## [1Deterministic](https://github.com/1Deterministic), 2018
150 changes: 122 additions & 28 deletions ffsmc.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,15 @@
import sys
import shutil
import os.path
from os import walk
import logging
import locale
from os import walk
from random import shuffle

# project imports
import strings
import fileextension
import filedirsize
from audiotag import Tag

# this function returns a list of music files rated as 5 stars inside 'path' folder and its subfolders
Expand Down Expand Up @@ -37,74 +41,162 @@ def existing_files_list(path):
return filenames


#_______________________________________ Program starts here __________________________________________________#

################################################################################################################
################################################################################################################
######################################### Program starts here ##################################################
################################################################################################################
################################################################################################################

if __name__ == "__main__":
# ignores warnings from eyed3 (it throws A LOT of warnings :P)
logging.getLogger("eyed3").setLevel(logging.CRITICAL)


# getting system language
language = "en" # en is the default language
if locale.getdefaultlocale()[0][:2] in strings.msg: # if the current language is supported, then it is set
language = locale.getdefaultlocale()[0][:2]


# shows the help screen, if -h is received anywhere in the arguments
try:
if (sys.argv.index("-h")):
print(strings.msg[language]["help"])
sys.exit()

except SystemExit: # sys.exit also throws an exception, this catches it to properly close the program
os._exit(0)

except ValueError: # -h not received
pass


# getting and validating the folders
try:
if os.path.isdir(sys.argv[sys.argv.index("-source") + 1]) and os.path.isdir(
sys.argv[sys.argv.index("-destination") + 1]):
source_path = sys.argv[sys.argv.index("-source") + 1]
destination_path = sys.argv[sys.argv.index("-destination") + 1]
else:
print("Some of the paths received is not a folder.")

else: # some path received is not a folder
print(strings.msg[language]["invalid path"])
sys.exit()

except:
print("""Invalid arguments, must be:
ffsmc.exe -source "source_folder" -destination "destination_folder" [-override_on_destination] [-delete_left_files]
* Options between brackets are optional
* The argument after -source must be the source folder
* The argument after -destination must be the destination folder
* -override_on_destination copy/paste all files, overwriting those already on destination. If it's not received, it will copy/paste only the files needed
* -delete_left_files deletes all the files on destination that wasn't found on the source during the scan, or don't match the requisites to be selected (have a rating of 5 stars). If it's not received, they will be ignored
* You must use .exe extension even running on Linux. It is a peculiarity of standalone export using nuitka I kept
* Notice that, for now, the only equality check made in -override_on_destination and -delete_left_files is based on the file name
""")
except ValueError: # missing -source or -destination
print(strings.msg[language]["missing required arguments"])
sys.exit()

except IndexError: # missing path after -source or -destination
print(strings.msg[language]["missing folder path"])
sys.exit()

except SystemExit: # sys.exit()
os._exit(0)


# checking for the command to delete the left files
try:
if sys.argv.index("-delete_left_files"):
delete_left_files = True

except:
except ValueError: # -delete_left_files not received
delete_left_files = False


# checking for the command to override the files on destination
try:
if sys.argv.index("-override_on_destination"):
override_on_destination = True

except:
except ValueError: # -override_on_destination not received
override_on_destination = False


# checking for the command to limit destination folder size
try:
if sys.argv.index("-size_limit"):
if sys.argv[sys.argv.index("-size_limit") + 1].isdigit(): # must be a positive integer
size_limit = int(sys.argv[sys.argv.index("-size_limit") + 1])

else: # negative, not integer or not numerical value
print(strings.msg[language]["invalid size"])
sys.exit()

except ValueError: # -size_limit not received
size_limit = 0

except IndexError: # missing size after -size_limit
print(strings.msg[language]["missing size limit"])
sys.exit()

except SystemExit: # sys.exit()
os._exit(0)


# checking for the command to shuffle copied files order (will take effect if size_limit is used)
try:
if sys.argv.index("-shuffle_file_list"):
shuffle_file_list = True

except ValueError: # -shuffle_file_list not received
shuffle_file_list = False


# checking for the command to log copied and deleted files on the screen
try:
if sys.argv.index("-log"):
log = True

except ValueError: # -log not received
log = False


# removing the last slash or backslash from the paths, if they exist
if source_path.endswith('/') or source_path.endswith('\\'):
source_path = source_path[:-1]

if destination_path.endswith('/') or destination_path.endswith('\\'):
destination_path = destination_path[:-1]


# finds all 5-star rating musics in the given source folder
print("Scanning source folder...")
print(strings.msg[language]["scanning source"])
file_list = search(source_path)

# init a zero total size to increment when files are copied or skipped because they already exist (when -override_on_destination was not received)
total_size = 0.0

# shuffle file_list to randomize what is copied when size_limit is used
if shuffle_file_list: shuffle(file_list)

# copy-paste all files selected, if they're not yet in the output folder or if override_on_destination was received
if len(file_list) > 0: print("Copying new files:")
if len(file_list) > 0: print(strings.msg[language]["copying new files"])
for l in file_list:
if (not os.path.isfile(destination_path + "/" + os.path.basename(l))) or override_on_destination:
if (not os.path.isfile(destination_path + "/" + os.path.basename(l))) or override_on_destination: # file doesnt exist or will be overwrited
try:
print("\t" + l)
if log: print("\t" + l)
shutil.copy(l, destination_path)

except:
print(strings.msg[language]["error"] + l + strings.msg[language]["not copied"])
print(strings.msg[language]["safe exit"])
sys.exit()

if size_limit > 0: # size limited received
try:
total_size += filedirsize.get_file_size(destination_path + "/" + os.path.basename(l)) # update total size
if total_size > size_limit: # size limit exceeded
print(strings.msg[language]["size limit reached"])
file_list = file_list[:file_list.index(l)] # cut file_list to properly delete left files
break

except:
print("Error: file " + l + " was not copied.")
print("Exiting for safety.")
print(strings.msg[language]["error"] + strings.msg[language]["copied file not found"])
print(strings.msg[language]["safe exit"])
sys.exit()


# if delete_left_files was received, the files that are not 5-stars anymore will be removed
if delete_left_files:
# getting a list of files to delete in destination folder
Expand All @@ -114,13 +206,15 @@ def existing_files_list(path):
must_delete = destination_list - source_list

# removing the left files
if len(must_delete) > 0: print("Deleting left files:")
if len(must_delete) > 0: print(strings.msg[language]["deleting left files"])
for m in must_delete:
try:
print("\t" + m)
if log: print("\t" + m)
os.remove(destination_path + "/" + m)

except:
print("Error: file " + m + " was not deleted.")
print(strings.msg[language]["error"] + m + strings.msg[language]["not deleted"])


print("Done!")
sys.exit()
print(strings.msg[language]["done"])
sys.exit()
20 changes: 20 additions & 0 deletions filedirsize.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# general imports
import os

# this function returns the current size of a folder
def get_folder_size(path):
s = 0.0

for entry in os.scandir(path):
if entry.is_file():
s += entry.stat().st_size / 1024000 # transform from bynary bytes to decimal megabytes

elif entry.is_dir():
s += get_folder_size(path + "/" + entry.name)

return s

# this function returns the size of a file
def get_file_size(path):
return os.path.getsize(path) / 1024000 # transform from bynary bytes to decimal megabytes

Loading

0 comments on commit 65a0df3

Please sign in to comment.