playlist_transfer 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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: []