playlist_transfer 0.0.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/README.md +49 -0
- data/bin/playlist_transfer +53 -0
- data/lib/playlist_transfer.rb +128 -0
- data/lib/playlist_transfer/extensions.rb +22 -0
- metadata +79 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1fd192fa3c2a686c5948da6ea5c719647d42725a
|
4
|
+
data.tar.gz: 831a032a4b71b801395246667b78b71ce7ab7fdb
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0427271e71200e98d78ff23f20442ea8750468e1213ab3bafa0a3d8b723b634e603ddf3f58480aa79df59c47f3837d82ff67cab32ef8af7b4fed26be7a1f47bd
|
7
|
+
data.tar.gz: a0acda4092de869b08d196f76001de6cf4489d9765c762ee608aa2ddc94ca1629e9fc34e391c50c17b22829be378c25a2f8c0b0c59186fb2aa11fbc78771d564
|
data/README.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# playlist_transfer
|
2
|
+
## About
|
3
|
+
Ruby script to transfer music defined by playlist from music library to another directory (typically mounted flashdrive) including directory structure from library.
|
4
|
+
|
5
|
+
By default, script converts all FLAC files from playlist to MP3 format
|
6
|
+
|
7
|
+
This is script I created to put files from my Banshee managed music library (mostly FLAC files, some MP3 files) to flashdrive
|
8
|
+
Flashdrive is used in my car radio, which reads only MP3 files and cannot read files with special characters in name.
|
9
|
+
|
10
|
+
It reads playlist file (m3u8) generated by some media player and transfers each song to destination directory, including directory structure.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
###Easy way:
|
14
|
+
If are using rubygems, just run:
|
15
|
+
|
16
|
+
<pre>gem install playlist_transfer</pre>
|
17
|
+
|
18
|
+
###Manually:
|
19
|
+
Or you can build it from github manually:
|
20
|
+
|
21
|
+
<pre>
|
22
|
+
git clone https://github.com/Kisuke-CZE/playlist_transfer.git
|
23
|
+
cd playlist_transfer
|
24
|
+
gem build playlist_transfer.gemspec
|
25
|
+
gem install playlist_transfer
|
26
|
+
</pre>
|
27
|
+
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
<pre>playlist_transfer if=INPUT_FILE out=OUTPUT_DIR [basedir=MUSIC_DIR] [OPTIONS]</pre>
|
31
|
+
|
32
|
+
**INPUT_FILE** - m3u8 playlist with songs you want to transfer
|
33
|
+
|
34
|
+
**OUTPUT_DIR** - output directory where to create file structure and copy files (usually some flashdrive)
|
35
|
+
|
36
|
+
**MUSIC_DIR** - Path to directory where is your whole music library located. Optional argument if INPUT_FILE is located in your MUSIC_DIR
|
37
|
+
|
38
|
+
### Options
|
39
|
+
Script has these options:
|
40
|
+
|
41
|
+
**--compatible** - transfer filenames and directory names to target without special characters
|
42
|
+
|
43
|
+
**--justcopy** - do not convert FLAC files to MP3
|
44
|
+
|
45
|
+
## Requirements
|
46
|
+
* flac binary installed
|
47
|
+
* lame binary installed
|
48
|
+
* installed gems: m3u8, activesupport
|
49
|
+
* whole music library in one directory :)
|
@@ -0,0 +1,53 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# encoding: UTF-8
|
3
|
+
|
4
|
+
# This is script I created to put files from my Banshee managed music library to flashdrive
|
5
|
+
# It reads M3U8 playlist (defined by if=PATH_TO_PLAYLIST) and transfers files to output directory (defined by out=PATH_TO_DIRECTORY) including directory structure (Directory structure is created as relative from basedir=MUSIC_DIR)
|
6
|
+
# If there is any FLAC file it converts it to MP3 file (you can disable conversion by parameter --justcopy). Any other files will be just copied.
|
7
|
+
# It can also remove any special characters from file and directory names in output path. You can do that adding parameter --compatible
|
8
|
+
require 'pathname'
|
9
|
+
require 'm3u8'
|
10
|
+
require 'playlist_transfer'
|
11
|
+
|
12
|
+
ARGV.each do |argument|
|
13
|
+
case argument
|
14
|
+
when /if=/
|
15
|
+
$input_file = Pathname.new($')
|
16
|
+
when /out=/
|
17
|
+
$output_dir = Pathname.new($')
|
18
|
+
when /basedir=/
|
19
|
+
$base_dir = Pathname.new($')
|
20
|
+
when /--compatible/
|
21
|
+
$compatible = true
|
22
|
+
when /--justcopy/
|
23
|
+
$justcopy = true
|
24
|
+
else
|
25
|
+
puts "Invalid argument #{argument}"
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
abort "Bad syntax.\nUsage: #{File.basename($0)} if=INPUT_FILE out=OUTPUT_DIR [basedir=MUSIC_DIR] [OPTIONS]
|
30
|
+
|
31
|
+
Available options:
|
32
|
+
--compatible = transfer filenames and directory names without special characters
|
33
|
+
--justcopy = do not convert FLAC files to MP3" unless $input_file && $output_dir
|
34
|
+
abort "Cannot read file #{$input_file.to_s} . Does it exist?" unless $input_file.expand_path.file? && $input_file.expand_path.readable?
|
35
|
+
|
36
|
+
# If basedir is not defined by input, set basedir to directory where playlist is located
|
37
|
+
$base_dir = $input_file.expand_path.dirname if $base_dir==nil
|
38
|
+
|
39
|
+
puts "Using input file: #{$input_file.to_s}"
|
40
|
+
puts "Output will be placed in: #{$output_dir.to_s}"
|
41
|
+
puts "Base directory to define relative paths: #{$base_dir.to_s}"
|
42
|
+
|
43
|
+
# Change workdir to directory where playlist is located. Usually playlist has paths to audio files defined as relative from its location in filesystem. If it has absolute paths, changing current workdir is not a problem.
|
44
|
+
Dir.chdir($input_file.expand_path.dirname)
|
45
|
+
playlist_file = File.open($input_file.expand_path)
|
46
|
+
playlist = M3u8::Playlist.read(playlist_file)
|
47
|
+
|
48
|
+
playlist.items.each do |item|
|
49
|
+
track_location = Pathname.new(item.segment)
|
50
|
+
track=MusicTrack.new(track_location,$base_dir)
|
51
|
+
track.transfer($output_dir, $compatible, $justcopy)
|
52
|
+
end
|
53
|
+
puts "Transfer complete."
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require 'pathname'
|
2
|
+
require 'tempfile'
|
3
|
+
require 'playlist_transfer/extensions'
|
4
|
+
|
5
|
+
# Class MusicTrack represents one audiofile (trackfile) in some "Music folder" (basedir).
|
6
|
+
# trackfile and basedir are Pathnames
|
7
|
+
class MusicTrack
|
8
|
+
# Class MusicTrack represents one audiofile (trackfile) in some "Music folder" (basedir).
|
9
|
+
def initialize(trackfile,basedir)
|
10
|
+
abort "File #{trackfile.expand_path} is not located in #{basedir.expand_path}" if !trackfile.expand_path.is_child?(basedir.expand_path)
|
11
|
+
@path = trackfile.expand_path
|
12
|
+
@basedir = basedir.expand_path
|
13
|
+
end
|
14
|
+
|
15
|
+
# Methods flactags and encode_flac are highly inspired by script from guy named Mathew who posted his script on github: https://gist.github.com/lpar/4645195
|
16
|
+
|
17
|
+
# Method get_tags returns an array with tags extracted from original FLAC file. Array has fields named as attributes from original file. Each field contains value of that attribute
|
18
|
+
def get_tags
|
19
|
+
tmpfile = Tempfile.new('flacdata')
|
20
|
+
system(
|
21
|
+
'metaflac',
|
22
|
+
"--export-tags-to=#{tmpfile.path}",
|
23
|
+
'--no-utf8-convert',
|
24
|
+
@path.to_s
|
25
|
+
)
|
26
|
+
data = tmpfile.open
|
27
|
+
tags = { 'title' => '', 'artist' => '', 'album' => '', 'date' => '', 'tracknumber' => '0' }
|
28
|
+
while line = data.gets
|
29
|
+
m = line.match(/^(\w+)=(.*)$/)
|
30
|
+
if m && m[2]
|
31
|
+
tags[m[1].downcase] = m[2]
|
32
|
+
end
|
33
|
+
end
|
34
|
+
return tags
|
35
|
+
end
|
36
|
+
|
37
|
+
# Method encode_flac transcodes FLAC file to MP3 file placed in output (which is passed as parameter).
|
38
|
+
# Parameter output should be Pathname
|
39
|
+
def encode_flac(outputfile)
|
40
|
+
wavtemp = Tempfile.new('wavfile')
|
41
|
+
info = self.get_tags
|
42
|
+
track = info['tracknumber'].gsub(/\D/,'')
|
43
|
+
system(
|
44
|
+
'flac',
|
45
|
+
'-s',
|
46
|
+
'-d',
|
47
|
+
'-f',
|
48
|
+
'-o',
|
49
|
+
wavtemp.path,
|
50
|
+
@path.to_s
|
51
|
+
)
|
52
|
+
system(
|
53
|
+
'lame',
|
54
|
+
'--silent',
|
55
|
+
'--replaygain-accurate',
|
56
|
+
'--preset', 'cbr', '320',
|
57
|
+
'-m', 's',
|
58
|
+
'-q', '0',
|
59
|
+
'--add-id3v2',
|
60
|
+
'--tt', info['title'],
|
61
|
+
'--ta', info['artist'],
|
62
|
+
'--tl', info['album'],
|
63
|
+
'--ty', info['date'],
|
64
|
+
'--tn', track,
|
65
|
+
'--tg', info['genre'] || 'Rock',
|
66
|
+
wavtemp.path,
|
67
|
+
outputfile.to_s
|
68
|
+
)
|
69
|
+
|
70
|
+
# If encoding process is interrupted (by pressinc Ctrl + C), remove probably incomplete file in destination.
|
71
|
+
rescue Interrupt
|
72
|
+
FileUtils.rm(mp3name) if mp3name.file?
|
73
|
+
abort "Interrupted when encoding #{mp3name}. Incomplete file removed from destination."
|
74
|
+
end
|
75
|
+
|
76
|
+
# Returns true if track type is FLAC. Identified by file extension.
|
77
|
+
def is_flac?
|
78
|
+
if @path.extname.downcase == ".flac"
|
79
|
+
return true
|
80
|
+
else
|
81
|
+
return false
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# This method transfers track file to destination (outfile parameter is Pathname). (When it is FLAC, it converts it to MP3 by default, other files will be just copied).
|
86
|
+
# You can specify that you do not want to convert FLAC to MP3 by adding second parameter (justcopy) with value "true".
|
87
|
+
# It also creates directory structure (relatively from basedir to track itself) in destination.
|
88
|
+
def filetransfer(outfile, justcopy = nil)
|
89
|
+
abort "File #{@path.to_s} does not exist." if !@path.file?
|
90
|
+
outfile = outfile.sub(/\.flac$/i, '.mp3') if !justcopy
|
91
|
+
# If file in destination already exists in destination, skip it, no need to tranfer it.
|
92
|
+
if !outfile.file?
|
93
|
+
puts "Transfering #{outfile.to_s}"
|
94
|
+
outfile.dirname.mkpath
|
95
|
+
if self.is_flac? && !justcopy
|
96
|
+
self.encode_flac(outfile)
|
97
|
+
else
|
98
|
+
FileUtils.cp(@path.realpath,outfile)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
puts "File #{outfile.to_s} already exists. Skipping..."
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Method to transfer file and it's directory structure to destination (output)
|
106
|
+
# You can specify you want to create directory srtucture in destination in "compatible" way. This means no spaces and special characters in filenames.
|
107
|
+
# If you do not want any conversion from FLAC to MP3, just set justcopy to true.
|
108
|
+
def transfer(output, compatible = nil, justcopy = nil)
|
109
|
+
abort "Can't write to #{output.to_s} or it is not directory." unless output.expand_path.directory? && output.expand_path.writable?
|
110
|
+
|
111
|
+
# Next 3 lines just creates complete destination path for transfered track (combining desired output directory, current track location, and basedir). It also removes special characters if necessary.
|
112
|
+
relative_path = @path.relative_path_from(@basedir)
|
113
|
+
relative_path = relative_path.no_special_chars if compatible
|
114
|
+
output_file = output.expand_path + relative_path
|
115
|
+
|
116
|
+
self.filetransfer(output_file, justcopy)
|
117
|
+
end
|
118
|
+
|
119
|
+
# Method to transfer file and it's structure in "compatible" way (file and it's directory structure with removed special characters) - just alias for transfer with proper parameters.
|
120
|
+
def transfer_compatible(output, justcopy = nil)
|
121
|
+
self.transfer(output, true, justcopy)
|
122
|
+
end
|
123
|
+
|
124
|
+
# Method to transfer file and it's structure without removing special characters or transcoding files to MP3 - just alias for transfer with proper parameters.
|
125
|
+
def just_copy(output)
|
126
|
+
self.transfer(output, nil, true)
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#Some enhancements to standard classes created to fit my needs
|
2
|
+
|
3
|
+
require 'active_support/inflector'
|
4
|
+
|
5
|
+
class Pathname
|
6
|
+
# Adds new method to Pathname, which removes accented characters from Pathname. Then removes spaces and any special characters (they are replaced by _). This method returns another Pathname.
|
7
|
+
def no_special_chars
|
8
|
+
transliterated=ActiveSupport::Inflector.transliterate(self.to_s)
|
9
|
+
return Pathname.new(transliterated.gsub!(/[^0-9A-Za-z\/.]/, '_'))
|
10
|
+
end
|
11
|
+
|
12
|
+
# Adds new method to Pathname, which can check if path itself is child of root (parameter, root is another Pathname)
|
13
|
+
# It is used in MusicTrack class to determine if track initialization is correct (if file is really located in defined directory)
|
14
|
+
def is_child?(root)
|
15
|
+
if self.to_s.size >= root.to_s.size
|
16
|
+
return self.to_s[0...root.to_s.size] == root.to_s && (self.to_s.size == root.to_s.size || self.to_s[root.to_s.size] == ?/ )
|
17
|
+
else
|
18
|
+
return false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,79 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: playlist_transfer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.2
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Kisuke
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-10-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: m3u8
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.6.9
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.6.9
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 5.0.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 5.0.0
|
41
|
+
description: Transfers your music (from m3u playlist) to destination folder (for example
|
42
|
+
USB drive). It can convert your FLAC files to MP3 files, or leave as is and just
|
43
|
+
copy files-
|
44
|
+
email: kisuke@kisuke.cz
|
45
|
+
executables:
|
46
|
+
- playlist_transfer
|
47
|
+
extensions: []
|
48
|
+
extra_rdoc_files: []
|
49
|
+
files:
|
50
|
+
- README.md
|
51
|
+
- bin/playlist_transfer
|
52
|
+
- lib/playlist_transfer.rb
|
53
|
+
- lib/playlist_transfer/extensions.rb
|
54
|
+
homepage: https://github.com/Kisuke-CZE/playlist_transfer
|
55
|
+
licenses:
|
56
|
+
- WTFPL
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.5.1
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Transfers music (defined by M3U playlist) from your music library to destination
|
78
|
+
folder - including directory structure
|
79
|
+
test_files: []
|