Script copie audio .m3u

  • Auteur de la discussion knightdead
  • Date de début

knightdead

Expert
Bonjour tout le monde !
Voilà le truc, j'ai une playlist enregistrée au format m3u avec près de 15000 musiques dedans et j'aurais aimé savoir si vous connaissiez un programme ou si quelqu'un pourrait m'en coder un petit me permettant de copier toutes ces musiques (donc classées chacune avec leur chemin absolu) vers un autre fichier, en gardant la hiérarchie de fichier si possible.

Je vous remercie d'avance !
 

VaderFR

Grand Maître
je tâcherais de faire un .exe alors (en Pascal, Java ou C...)
 

VaderFR

Grand Maître
je fait ça asap.
j'ai déjà réfléchi à la conception du bouzin : 3 passes, la première pour déterminer la taille totale des fichiers/taille libre sur la cible, deuxième pour déterminer la plus petite racine des fichiers à copier, et la 3eme pour faire la copie.

comme j'ai un peu la flemme de faire un code complexe à compiler ensuite, je vais voir si c'est pas faisable avec un .bat tout simple.
 

zeb

Modérateur
Salut,

Le modérateur est de retour !
Et il n'aime pas du tout cette petite histoire de programme à la demande. :fou:
Si le topic n'est pas encore fermé, c'est pour vous donner l'occasion de revoir votre copie, messieurs.
 

VaderFR

Grand Maître
1) concernant la "revue de copie"
-> ça me permet d'apprendre des trucs et ça rend lui service, ce qui est pas un mal pour les 2
-> vu que c'est un forum d'entraide et pas une échoppe à programmes sur demande, je mettrais le code (commenté/expliqué) du script sur le forum, dès fois que ça pourrait aider des gens, qui auraient les mêmes problématiques.

2) concernant le programme
- j'ai quasiment fini la phase 1, à savoir la somme des tailles des fichiers listés dans la playlist afin de prévoir la taille nécessaire sur la destination. Il ne me reste que la fonction déterminant la taille dispo (libre) par rapport à la taille requise calculée.
ça n'a pas été sans mal, les scripts ne se comportant pas comme ils auraient dû, avec des variables initialisées dans un if mais qui ne s'affichaient pas avec la bonne valeur, sauf quand l'affichage de la valeur se faisait en dehors du if, et 2/3 co******* du même acabit. je le dit et redit : W$, c'est nul !
Autant en shell unix j'aurais fait ça les doigts dans le nez, avec un code aussi simple (variables normalisées, tout ça) que puissant (appel aux fonctions unix extérieures et récupération du résultat dans le programme), autant là,, en script DOS, les fonctions sont limitées et le code est illisible.
 

zeb

Modérateur
:sarcastic:

Linux powaaaaaa !
\
[:zeb:3]

Si même le modo s'y met !
 

VaderFR

Grand Maître
- j'aurais une question toutefois : as tu des "&" dans le nom d'un de tes fichiers musicaux ?

Si oui, il faudra que je me débrouille pour les neutraliser car batch les interprétera comme une commande.

sinon, la phase 1 est finie, il liste les fichiers musicaux, additionne leurs tailles, et calcule la taille disponible sur le lecteur destination.


- Autre question, tes fichiers musicaux ont ils une racine commune (un répertoire de musique racine en commun) et sont ils sur un même lecteur ?

sinon, ça risque de ne pas marcher.
 

VaderFR

Grand Maître
...donc j'en déduit que non.

par conséquent, je ne me casserais ps la tête pour gérer les caractères spéciaux.

Voici le code de la phase 1.

Tout d'abord, comme tout script batch, j'enlève l'affichage et j'initialise quelques variables

Code:
@echo off
set /A grandeur=1024
set /A size=0
set /A sizek=0
set /A sizem=0
set /A sizetempm=0
set /A sizetempg=0
set /A tropk=0
set /A troptk=0
set /A troptm=0
set /A sizet=0
set /A sizetm=0
set /A sizetg=0
set /A sizetk=0
set /A tfreek=0
set /A tfreem=0
set /A tfreeg=0
set /A tropfk=0
set /A tropfm=0
set /A phaseok=0

Parmi ces variables, les 2 principales, fournies au lancement..pour le moment.
Plus tard je ferais un script avec des demandes de saisie utilisateur, mais pour le développement ça va vachement plus vite de rappeler la même commande que d'avoir à taper à chaque fois nom de fichier playlist et destination.

Code:
rem %1 est le 1er paramètre fourni au script = fichier playlist à traiter
rem si %1 absent, nul ou vide, message erreur et stop OU set /P
rem si /P échoue... ?
set fichier=%1
rem %2 est le deuxième paramètre = destination
set destination=%2
echo /!\ =========================================================== /!\
echo Il ne doit pas y avoir de "&" dans un nom de fichier son ! 
echo /!\ =========================================================== /!\

ces variables sont déclarées dès le début afin de pouvoir les utiliser dans des fonctions différentes.
pas sûr que ce soit vraiment utile en batch, mais dans le doute ...

Ensuite, il faut lire le fichier.
Là, y'a 3 syntaxes possible pour la boucle
Code:
rem  ===== BOUCLE 1 =====
rem for /f "delims=" %%a in (%fichier%) do (
rem  ===== BOUCLE 2 =====
rem for /f "delims=" %%a in ('type %fichier%') do (
rem  ===== BOUCLE 3 =====
rem for /f "delims=" %%a in ('type %fichier%)) do (

la boucle type 1 ne marche pas. la boucle 2 marche bien, je m'en contenterais donc...pour l'instant.

La fonction principale
Code:
for /f "delims=" %%a in ('type %fichier%') do (
	call :traiter1 "%%a"
)
echo Taille totale requise : %sizetg% Go %sizetm% Mo %sizetk% Ko
rem on enleve les "
set destination=%destination:"=%
call:taillelibre "%destination%"
echo Espace disponible : %tfreeg% Go %tfreem% Mo %tfreek% Ko
if %tfreeg% GTR %sizetg% (
	echo tout baigne !
	set /A phaseok=1
) else (
	if %tfreeg% == %sizetg% (
		if %tfreem% GTR %sizetm% (
			echo tout baigne !
			set /A phaseok=1
		) else (
			if %tfreem% == %sizetm% (
				if %tfreek% GTR %sizetk% (
					echo tout baigne !
					set /A phaseok=1
				) else (
					if %tfreek% == %sizetk% (
						trop juste !
					) else (
						pas assez de place
					)
				)
			) else (
				echo pas assez de place
			)
		)
	) else (
		echo pas assez de place
	)
)
goto:eof

On appelle la fonction de traitement n°1 de fichier afin de récupérer la taille de chaque fichier de musique listé, puis on appelle la fonction de recherche de la taille libre sur le périphérique destination.

1ère fonction, le traitement ligne par ligne, qui va appeler une sous-fonction pour récupérer la taille du fichier dont il est question sur la ligne traitée.

Code:
:traiter1
	set ligne=%1
	rem on enleve les "" fournis a l'appel
	set ligne=%ligne:"=%
set /A size=0
	set /A sizek=0
	set /A sizem=0
	set /A sizetempm=0
	set /A sizetempg=0
	set /A tropk=0
	set /A troptk=0
	set /A troptm=0
call:size_file "%ligne%"
rem la taille du fichier en Ko
	set /A sizek=size/grandeur
	if %sizek% GEQ %grandeur% (
	        set /A sizem=sizek/grandeur
	)else (
		set /A sizem=0
	)
	if %sizek% GEQ %grandeur% (
		set /A tropk=sizem*grandeur
		set /A sizek=sizek-tropk
	)
	set /A sizetm=sizetm+sizem
	set /A sizetk=sizetk+sizek
	if %sizetk% GEQ %grandeur% (
		set /A sizetempm=sizetk/grandeur
	)
	if %sizetk% GEQ %grandeur% (
		set /A troptk=sizetempm*grandeur
		set /A sizetk=sizetk-troptk
		set /A sizetm=sizetm+sizetempm
	) 
	if %sizetm% GEQ %grandeur% (
		set /A sizetempg=sizetm/grandeur
	)
	if %sizetm% GEQ %grandeur% (
		set /A troptm=sizetempg*grandeur
		set /A sizetm=sizetm-troptm
		set /A sizetg=sizetg+sizetempg
	)
	goto :eof

et la sous-fonction appelée, qui récupère la taille du fichier listé sur une ligne de la playlist, en octets.
Code:
:size_file
	set ligne=%1
	rem on enleve les "" fournis a l'appel
	set ligne=%ligne:"=%
	set premiercar=%ligne:~0,1%
	rem si ligne commence par # on ignore
	if NOT "%premiercar%" == "#" (
		set size=%~z1
	) else (
		set size=0
	)
	goto:eof

et maintenant la fonction de calcul de la taille libre sur la destination.
son résultat étant sur plusieurs lignes (taille libre, taille totale et taille libre disponible (?) en octets, une sous-fonction est appelée pour décortiquer tout ça.
Code:
:taillelibre
	set cible=%1
	set /A tfree=0
	set /A tfreek=0
	set /A tfreem=0
	set /A tfreeg=0
	for /f "delims=" %%A in ('fsutil volume diskfree %cible%') do (
		call:calcultaillelibre "%%A"
		set /A tfree=tfree+tfreek
	)
	set /A tfreek=tfree
	if %tfreek% GEQ %grandeur% (
		set /A tfreem=tfreek/grandeur
	) else (
		set tfreem=0
	)
	if %tfreek% GEQ %grandeur% (
	       set /A tropfk=tfreem*grandeur
		set /A tfreek=tfreek-tropfk
	)
	if %tfreem% GEQ %grandeur% (
		set /A tfreeg=tfreem/grandeur
	) else (
		set tfreeg=0
	)
	if %tfreem% GEQ %grandeur% (
		set /A tropfm=tfreeg*grandeur
		set /A tfreem=tfreem-tropfm
	)
	goto:eof

les blocs "if" successifs sont dus à une incrémentation tardive des variables.

la sous fonction qui décortique le résultat sur plusieurs lignes, en octets, pour renvoyer un résultat dans 3 variables, en Ko, Mo, Go.
Code:
:calcultaillelibre
	set lignel=%1
	set diskfree=%lignel%
	rem on enleve les "" fournis a l'appel
	set lignel=%lignel:"=%
	set diskfree=%diskfree:"=%
	rem taille libre en Ko
	set diskfree=%diskfree:~43,-3%
	set /A tfreek=%diskfree%
	if NOT "%lignel:libres=%" == "%lignel%" (
		if "%lignel:disponibles=%" == "%lignel%" (
		) else (
			set /A tfreek=0
		)
	) else (
		set /A tfreek=0
	)
	goto:eof


je me met à la phase 2, à savoir trouver la plus petite racine commune aux fichiers, pour ensuite la recréer sur la destination (avec un xcopy par exemple).

j'ai déjà l'algorithme en tête, restera plus que la syntaxe, à la llimite.
 

knightdead

Expert
Excusez moi de ma réponse tardive (vacances :D), non mes musiques ne contiennent pas de caractères spéciaux, et oui elles sont sur la même partition.

Merci de vous investir autant pour m'aider, c'est vraiment sympa !
 

VaderFR

Grand Maître
rebonjour,

phase 2 finie, je détermine le répertoire commun aux musiques.

par contre, je ne tolère qu'une profondeur de 26 répertoire maximum.

normalement ça devrait être bon, mais si tu as un répertoire racine de musique qui est perdu dans un coin paumé de ton DD, dans un répertoire qui est dans un autre....et ainsi de suite 26 fois, ça posera problème. (j'en doute un peu)

il ne me reste plus que la partie "copie" ce qui devrait être assez rapide.

voici donc le code correspondant.

La fonction principale est donc modifiée.
après
Code:
set destination=%destination:"=%
call:taillelibre "%destination%"
echo Espace disponible : %tfreeg% Go %tfreem% Mo %tfreek% Ko
if %tfreeg% GTR %sizetg% (
	echo tout baigne !
	set /A phaseok=1
) else (
	if %tfreeg% == %sizetg% (
		if %tfreem% GTR %sizetm% (
			echo tout baigne !
			set /A phaseok=1
		) else (
			if %tfreem% == %sizetm% (
				if %tfreek% GTR %sizetk% (
					echo tout baigne !
					set /A phaseok=1
				) else (
					if %tfreek% == %sizetk% (
						echo trop juste !
						goto:eof
					) else (
						pas assez de place
						goto:eof
					)
				)
			) else (
				echo pas assez de place
				goto:eof
			)
		)
	) else (
		echo pas assez de place
		goto:eof
	)
)

je rajoute la phase 2
Code:
if %phaseok% == 1 (
setlocal enableDelayedExpansion
rem	for /L %%J in (1,1,26) do set !tab[%%J]!="nul"
	echo === Phase II : trouver la ra
	for /f "eol=# delims=" %%a in ('type %fichier%') do (
		call :traiter2 "%%a"
		set /A nligne=%nligne%+1
	)
	echo racine = 
	for /L %%J in (1,1,!tab[0]!) do (
		if NOT "!tab[%%J]!" == "" (
				echo !tab[%%J]!
		)
	)
	echo sur le lecteur %lecteur%
	if !tab[0]! GTR %zero% (
		set /A phaseok=2
		echo Pas de souci, racine trouvee, on continue
	) else (
		echo Probleme pour la racine, indice : %ntab%, tableau : !tab[0]!
		goto:eof
	)
	endlocal
)
if %phaseok% == 2 (
	echo === Phase III : copie ===
)
goto:eof

et donc la (seule) fonction traiter2, puisque j'ai réussi à tout mettre dans une seule fonction, grâce notamment au setlocale EnabledExpansion (utilisant un tableau, j'avais pas vraiment le choix), qui permet aux variables de bien être incrémentées (ce qui dans la phase 1 m'avait obligé à faire des tas d'appels et sous fonctions et boucles if autrement inutiles)

Code:
rem =========================== traitement 2 ===========================
:traiter2
	set ligne=%1
	rem on enleve les "" fournis a l'appel
	set ligne=%ligne:"=%
	set premiercar=%ligne:~0,1%
	rem lecteur = 1ere lettre
	if %lecteur% == 0 (
		set lecteur=%premiercar%
	)
	rem on commence par 4eme caractère C:\xxxxx\yyyyyy\zzzzzz.mp3
	set lignec=%ligne:~3%
	set chemin=%lignec%
	rem delimiteur du FOR = \, empiler dans tableau
	for /f "tokens=1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26* delims=\" %%a in ("%chemin%") do (
		if %nligne% == 0 (
			rem pour 1ère ligne : on empile et pi c'est tout
			rem si %%a non nul, mettre dans case 1, si %%b non nul, mettre dans case 2...
			if NOT "%%a" == "" set tab[1]=%%s
			if NOT "%%b" == "" set tab[2]=%%b
			if NOT "%%c" == "" set tab[3]=%%c
			if NOT "%%d" == "" set tab[4]=%%d
			if NOT "%%e" == "" set tab[5]=%%e
			if NOT "%%f" == "" set tab[6]=%%f
			if NOT "%%g" == "" set tab[7]=%%g
			if NOT "%%h" == "" set tab[8]=%%h
			if NOT "%%i" == "" set tab[9]=%%i
			if NOT "%%j" == "" set tab[10]=%%j
			if NOT "%%k" == "" set tab[11]=%%k
			if NOT "%%l" == "" set tab[12]=%%l
			if NOT "%%m" == "" set tab[13]=%%m
			if NOT "%%n" == "" set tab[14]=%%n
			if NOT "%%o" == "" set tab[15]=%%o
			if NOT "%%p" == "" set tab[16]=%%p
			if NOT "%%q" == "" set tab[17]=%%q
			if NOT "%%r" == "" set tab[18]=%%r
			if NOT "%%s" == "" set tab[19]=%%s
			if NOT "%%t" == "" set tab[20]=%%t
			if NOT "%%u" == "" set tab[21]=%%u
			if NOT "%%v" == "" set tab[22]=%%v
			if NOT "%%w" == "" set tab[23]=%%w
			if NOT "%%x" == "" set tab[24]=%%x
			if NOT "%%y" == "" set tab[25]=%%y
			if NOT "%%z" == "" set tab[26]=%%z
		) else (
			rem après 1ere ligne
			rem si %%a  présent dans tableau on continue, si %%a est nouveau on ne l'empile pas, si case 1 différent de %%a on efface case 1 et suivante et on met id dernière case à 0
			rem l'inclusion de 26 boucles if/else semble faire planter le script "rem inattendu"
			if NOT "!tab[26]!" == "%%z" set /A ntab=25
			if NOT "!tab[25]!" == "%%y" set /A ntab=24
			if NOT "!tab[24]!" == "%%x" set /A ntab=23
			if NOT "!tab[23]!" == "%%w" set /A ntab=22
			if NOT "!tab[22]!" == "%%v" set /A ntab=21
			if NOT "!tab[21]!" == "%%u" set /A ntab=20
			if NOT "!tab[20]!" == "%%t" set /A ntab=19
			if NOT "!tab[19]!" == "%%s" set /A ntab=18
			if NOT "!tab[18]!" == "%%r" set /A ntab=17
			if NOT "!tab[17]!" == "%%q" set /A ntab=16
			if NOT "!tab[16]!" == "%%p" set /A ntab=15
			if NOT "!tab[15]!" == "%%o" set /A ntab=14
			if NOT "!tab[14]!" == "%%n" set /A ntab=13
			if NOT "!tab[13]!" == "%%m" set /A ntab=12
			if NOT "!tab[12]!" == "%%l" set /A ntab=11
			if NOT "!tab[11]!" == "%%k" set /A ntab=10
			if NOT "!tab[10]!" == "%%j" set /A ntab=9
			if NOT "!tab[9]!" == "%%i" set /A ntab=8
			if NOT "!tab[8]!" == "%%h" set /A ntab=7
			if NOT "!tab[7]!" == "%%g" set /A ntab=6
			if NOT "!tab[6]!" == "%%f" set /A ntab=5			
			if NOT "!tab[5]!" == "%%e" set /A ntab=4
			if NOT "!tab[4]!" == "%%d" set /A ntab=3
			if NOT "!tab[3]!" == "%%c" set /A ntab=2
			if NOT "!tab[2]!" == "%%b" set /A ntab=1
			if NOT "!tab[1]!" == "%%a" set /A ntab=0
		) 
	)
	set /A indice=%ntab%
	set tab[0]=%ntab%
	goto:eof

pour lire la chaîne de caractères (la ligne) et en extraire les branches de l'arborescence, le mieux est d'utiliser une boucle for, mais comme le script batch.... donc pour récupérer dans des variables différentes, il faut les nommer, vu que le batch ne fonctionne pas comme le reste des langages.

je le dit et redit : le batch et scripting DOS, c'est [de] la merde.
en bash/shel unix ce serait les doigts dans le nez. gestion de tableaux indexés, boucle for et while, syntaxe standard..

ah oui, j'ai aussi modifié les fonctions de la phase 1, ce qui est plus sûr et plus performant.
 

zeb

Modérateur
le batch et scripting DOS, c'est [de] la merde.
Microsoft, bien qu'inconscient de cet état de fait, a par ailleurs créé le VBScript pour faire "à la manière de" ce qui existe et qui fonctionne ailleurs. Aussi, ce langage remplace-t-il avantageusement le batch et scripting DOS.
;)

Pour l'exercice (c'est un exercice, hein ?) peux-tu nous proposer une version bash ?

:D :D :D
 

VaderFR

Grand Maître
évidemment que je ferais un script sh, ne serait-ce que pour permettre aux gens de comparer entre les deux.

je ferais ça dès que j'aurais fini le script batch W$ (en espérant qu'il fonctionne pour W$ 6.1) mais ça devrait être piece of cake
 

VaderFR

Grand Maître
bon, bah pour ce qui est du script batch, en théorie j'ai fini..


en théorie, parce que :
- comme j'utilise le delayedexpansion, il faut utiliser des "!" pour afficher la bonne valeur d'une variable, et donc comme en batch il est impossible d'échapper les caractères spéciaux (ce qui se faisait déjà sous Unix bien avant que n'arrive DOS), il ne supporte pas les "!" dans un nom de fichier
- comme c'est du batch, il ne supporte pas les caractères accentués dans le nom des fichiers/dossiers. (en revanche les "~" et les espaces, aucun problème), et le plus bizarre c'est que la même commande tapée direct sous DOS pose aucun problème. mais la gestion des accents en batch...

à part ça, ça va, il copie l'arborescence, pi les fichiers de la liste, un par un.

si ça te convient, je peux donc release une bêta, en envoyant les messages d'erreur dans un fichier log, à la rigueur..

je vais quand même essayer une solution avec un fichier temporaire.

je vais d'ores et déjà m'attaquer au script bash unix/linux.
 

VaderFR

Grand Maître
c'est marrant, mais je dirais pas ça.

pour moi, c'est du gros bricolage avec un système d'exploitation vite fait mal fait (QDOS = DOS) complètement naze, qui respecte aucune norme ni aucun standard, qui est largement à la ramasse par rapport à des OS plus anciens....

un script sh de sauvegarde totale+incrémentielle tar déportée par flux compressé gz sur connexion ssh, avec dates et envoi de mail, ça c'est de l'art.

question de point de vue.

 
Vous devez vous inscrire ou vous connecter pour répondre ici.
Derniers messages publiés
Statistiques globales
Discussions
730 098
Messages
6 717 098
Membres
1 586 287
Dernier membre
lucilleguffey
Partager cette page
Haut